/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "qcocoahelpers.h" #include #include #include #include #include #ifndef QT_NO_WIDGETS #include #endif #include #include @interface NSGraphicsContext (QtAdditions) + (NSGraphicsContext *)qt_graphicsContextWithCGContext:(CGContextRef)graphicsPort flipped:(BOOL)initialFlippedState; @end @implementation NSGraphicsContext (QtAdditions) + (NSGraphicsContext *)qt_graphicsContextWithCGContext:(CGContextRef)graphicsPort flipped:(BOOL)initialFlippedState { #if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10, __IPHONE_NA) if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10) return [self graphicsContextWithCGContext:graphicsPort flipped:initialFlippedState]; #endif return [self graphicsContextWithGraphicsPort:graphicsPort flipped:initialFlippedState]; } @end QT_BEGIN_NAMESPACE // // Conversion Functions // QStringList qt_mac_NSArrayToQStringList(void *nsarray) { QStringList result; NSArray *array = static_cast(nsarray); for (NSUInteger i=0; i<[array count]; ++i) result << QCFString::toQString([array objectAtIndex:i]); return result; } void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list) { NSMutableArray *result = [NSMutableArray arrayWithCapacity:list.size()]; for (int i=0; i(image); } // Creates a CGDataProvider with the data from the given image. // The data provider retains a copy of the image. CGDataProviderRef qt_mac_CGDataProvider(const QImage &image) { return CGDataProviderCreateWithData(new QImage(image), image.bits(), image.byteCount(), qt_mac_deleteImage); } CGImageRef qt_mac_toCGImage(const QImage &inImage) { if (inImage.isNull()) return 0; QImage image = inImage; uint cgflags = kCGImageAlphaNone; switch (image.format()) { case QImage::Format_ARGB32: cgflags = kCGImageAlphaFirst | kCGBitmapByteOrder32Host; break; case QImage::Format_RGB32: cgflags = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; break; case QImage::Format_RGB888: cgflags = kCGImageAlphaNone | kCGBitmapByteOrder32Big; break; case QImage::Format_RGBA8888_Premultiplied: cgflags = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big; break; case QImage::Format_RGBA8888: cgflags = kCGImageAlphaLast | kCGBitmapByteOrder32Big; break; case QImage::Format_RGBX8888: cgflags = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big; break; default: // Everything not recognized explicitly is converted to ARGB32_Premultiplied. image = inImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); // no break; case QImage::Format_ARGB32_Premultiplied: cgflags = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; break; } QCFType dataProvider = qt_mac_CGDataProvider(image); return CGImageCreate(image.width(), image.height(), 8, 32, image.bytesPerLine(), qt_mac_genericColorSpace(), cgflags, dataProvider, 0, false, kCGRenderingIntentDefault); } CGImageRef qt_mac_toCGImageMask(const QImage &image) { QCFType dataProvider = qt_mac_CGDataProvider(image); return CGImageMaskCreate(image.width(), image.height(), 8, image.depth(), image.bytesPerLine(), dataProvider, NULL, false); } NSImage *qt_mac_cgimage_to_nsimage(CGImageRef image) { NSImage *newImage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize]; return newImage; } NSImage *qt_mac_create_nsimage(const QPixmap &pm) { if (pm.isNull()) return 0; QImage image = pm.toImage(); CGImageRef cgImage = qt_mac_toCGImage(image); NSImage *nsImage = qt_mac_cgimage_to_nsimage(cgImage); CGImageRelease(cgImage); return nsImage; } NSImage *qt_mac_create_nsimage(const QIcon &icon) { if (icon.isNull()) return nil; NSImage *nsImage = [[NSImage alloc] init]; foreach (QSize size, icon.availableSizes()) { QPixmap pm = icon.pixmap(size); QImage image = pm.toImage(); CGImageRef cgImage = qt_mac_toCGImage(image); NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; [nsImage addRepresentation:imageRep]; [imageRep release]; CGImageRelease(cgImage); } return nsImage; } HIMutableShapeRef qt_mac_QRegionToHIMutableShape(const QRegion ®ion) { HIMutableShapeRef shape = HIShapeCreateMutable(); QVector rects = region.rects(); if (!rects.isEmpty()) { int n = rects.count(); const QRect *qt_r = rects.constData(); while (n--) { CGRect cgRect = CGRectMake(qt_r->x(), qt_r->y(), qt_r->width(), qt_r->height()); HIShapeUnionWithRect(shape, &cgRect); ++qt_r; } } return shape; } NSSize qt_mac_toNSSize(const QSize &qtSize) { return NSMakeSize(qtSize.width(), qtSize.height()); } NSRect qt_mac_toNSRect(const QRect &rect) { return NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); } QRect qt_mac_toQRect(const NSRect &rect) { return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); } QColor qt_mac_toQColor(const NSColor *color) { QColor qtColor; NSString *colorSpace = [color colorSpaceName]; if (colorSpace == NSDeviceCMYKColorSpace) { CGFloat cyan, magenta, yellow, black, alpha; [color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha]; qtColor.setCmykF(cyan, magenta, yellow, black, alpha); } else { NSColor *tmpColor; tmpColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; CGFloat red, green, blue, alpha; [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha]; qtColor.setRgbF(red, green, blue, alpha); } return qtColor; } QColor qt_mac_toQColor(CGColorRef color) { QColor qtColor; CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color)); const CGFloat *components = CGColorGetComponents(color); if (model == kCGColorSpaceModelRGB) { qtColor.setRgbF(components[0], components[1], components[2], components[3]); } else if (model == kCGColorSpaceModelCMYK) { qtColor.setCmykF(components[0], components[1], components[2], components[3]); } else if (model == kCGColorSpaceModelMonochrome) { qtColor.setRgbF(components[0], components[0], components[0], components[1]); } else { // Colorspace we can't deal with. qWarning("Qt: qt_mac_toQColor: cannot convert from colorspace model: %d", model); Q_ASSERT(false); } return qtColor; } QBrush qt_mac_toQBrush(CGColorRef color) { QBrush qtBrush; CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color)); if (model == kCGColorSpaceModelPattern) { // Colorspace we can't deal with; the color is drawn directly using a callback. qWarning("Qt: qt_mac_toQBrush: cannot convert from colorspace model: %d", model); Q_ASSERT(false); } else { qtBrush.setStyle(Qt::SolidPattern); qtBrush.setColor(qt_mac_toQColor(color)); } return qtBrush; } static bool qt_mac_isSystemColorOrInstance(const NSColor *color, NSString *colorNameComponent, NSString *className) { // We specifically do not want isKindOfClass: here if ([color.className isEqualToString:className]) // NSPatternColorSpace return true; if ([color.catalogNameComponent isEqualToString:@"System"] && [color.colorNameComponent isEqualToString:colorNameComponent] && [color.colorSpaceName isEqualToString:NSNamedColorSpace]) return true; return false; } QBrush qt_mac_toQBrush(const NSColor *color, QPalette::ColorGroup colorGroup) { QBrush qtBrush; // QTBUG-49773: This calls NSDrawMenuItemBackground to render a 1 by n gradient; could use HITheme if ([color.className isEqualToString:@"NSMenuItemHighlightColor"]) { qWarning("Qt: qt_mac_toQBrush: cannot convert from NSMenuItemHighlightColor"); return qtBrush; } // Not a catalog color or a manifestation of System.windowBackgroundColor; // only retrieved from NSWindow.backgroundColor directly if ([color.className isEqualToString:@"NSMetalPatternColor"]) { // NSTexturedBackgroundWindowMask, could theoretically handle this without private API by // creating a window with the appropriate properties and then calling NSWindow.backgroundColor.patternImage, // which returns a texture sized 1 by (window height, including frame), backed by a CGPattern // which follows the window key state... probably need to allow QBrush to store a function pointer // like CGPattern does qWarning("Qt: qt_mac_toQBrush: cannot convert from NSMetalPatternColor"); return qtBrush; } // No public API to get these colors/stops; // both accurately obtained through runtime object inspection on OS X 10.11 // (the NSColor object has NSGradient i-vars for both color groups) if (qt_mac_isSystemColorOrInstance(color, @"_sourceListBackgroundColor", @"NSSourceListBackgroundColor")) { QLinearGradient gradient; if (colorGroup == QPalette::Active) { gradient.setColorAt(0, QColor(233, 237, 242)); gradient.setColorAt(0.5, QColor(225, 229, 235)); gradient.setColorAt(1, QColor(209, 216, 224)); } else { gradient.setColorAt(0, QColor(248, 248, 248)); gradient.setColorAt(0.5, QColor(240, 240, 240)); gradient.setColorAt(1, QColor(235, 235, 235)); } return QBrush(gradient); } // A couple colors are special... they are actually instances of NSGradientPatternColor, which // override set/setFill/setStroke to instead initialize an internal color // ([NSColor colorWithCalibratedWhite:0.909804 alpha:1.000000]) while still returning the // ruled lines pattern image (from OS X 10.4) to the user from -[NSColor patternImage] // (and providing no public API to get the underlying color without this insanity) if (qt_mac_isSystemColorOrInstance(color, @"controlColor", @"NSGradientPatternColor") || qt_mac_isSystemColorOrInstance(color, @"windowBackgroundColor", @"NSGradientPatternColor")) { static QColor newColor; if (!newColor.isValid()) { #if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_8, __IPHONE_NA) if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { newColor = qt_mac_toQColor(color.CGColor); } else #endif { NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil pixelsWide:1 pixelsHigh:1 bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:4 bitsPerPixel:32]; [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]]; NSEraseRect(NSMakeRect(0, 0, 1, 1)); [color drawSwatchInRect:NSMakeRect(0, 0, 1, 1)]; [NSGraphicsContext restoreGraphicsState]; NSUInteger pixel[4]; [offscreenRep getPixel:pixel atX:0 y:0]; [offscreenRep release]; newColor = QColor(pixel[0], pixel[1], pixel[2], pixel[3]); } } qtBrush.setStyle(Qt::SolidPattern); qtBrush.setColor(newColor); return qtBrush; } if (NSColor *patternColor = [color colorUsingColorSpaceName:NSPatternColorSpace]) { NSImage *patternImage = patternColor.patternImage; const QSizeF sz(patternImage.size.width, patternImage.size.height); qtBrush.setTexture(qt_mac_toQPixmap(patternImage, sz)); // QTBUG-49774 } else { qtBrush.setStyle(Qt::SolidPattern); qtBrush.setColor(qt_mac_toQColor(color)); } return qtBrush; } struct dndenum_mapper { NSDragOperation mac_code; Qt::DropAction qt_code; bool Qt2Mac; }; static dndenum_mapper dnd_enums[] = { { NSDragOperationLink, Qt::LinkAction, true }, { NSDragOperationMove, Qt::MoveAction, true }, { NSDragOperationCopy, Qt::CopyAction, true }, { NSDragOperationGeneric, Qt::CopyAction, false }, { NSDragOperationEvery, Qt::ActionMask, false }, { NSDragOperationNone, Qt::IgnoreAction, false } }; NSDragOperation qt_mac_mapDropAction(Qt::DropAction action) { for (int i=0; dnd_enums[i].qt_code; i++) { if (dnd_enums[i].Qt2Mac && (action & dnd_enums[i].qt_code)) { return dnd_enums[i].mac_code; } } return NSDragOperationNone; } NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions) { NSDragOperation nsActions = NSDragOperationNone; for (int i=0; dnd_enums[i].qt_code; i++) { if (dnd_enums[i].Qt2Mac && (actions & dnd_enums[i].qt_code)) nsActions |= dnd_enums[i].mac_code; } return nsActions; } Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions) { Qt::DropAction action = Qt::IgnoreAction; for (int i=0; dnd_enums[i].mac_code; i++) { if (nsActions & dnd_enums[i].mac_code) return dnd_enums[i].qt_code; } return action; } Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions) { Qt::DropActions actions = Qt::IgnoreAction; for (int i=0; dnd_enums[i].mac_code; i++) { if (dnd_enums[i].mac_code == NSDragOperationEvery) continue; if (nsActions & dnd_enums[i].mac_code) actions |= dnd_enums[i].qt_code; } return actions; } // // Misc // // Sets the activation policy for this process to NSApplicationActivationPolicyRegular, // unless either LSUIElement or LSBackgroundOnly is set in the Info.plist. void qt_mac_transformProccessToForegroundApplication() { bool forceTransform = true; CFTypeRef value = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), CFSTR("LSUIElement")); if (value) { CFTypeID valueType = CFGetTypeID(value); // Officially it's supposed to be a string, a boolean makes sense, so we'll check. // A number less so, but OK. if (valueType == CFStringGetTypeID()) forceTransform = !(QCFString::toQString(static_cast(value)).toInt()); else if (valueType == CFBooleanGetTypeID()) forceTransform = !CFBooleanGetValue(static_cast(value)); else if (valueType == CFNumberGetTypeID()) { int valueAsInt; CFNumberGetValue(static_cast(value), kCFNumberIntType, &valueAsInt); forceTransform = !valueAsInt; } } if (forceTransform) { value = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), CFSTR("LSBackgroundOnly")); if (value) { CFTypeID valueType = CFGetTypeID(value); if (valueType == CFBooleanGetTypeID()) forceTransform = !CFBooleanGetValue(static_cast(value)); else if (valueType == CFStringGetTypeID()) forceTransform = !(QCFString::toQString(static_cast(value)).toInt()); else if (valueType == CFNumberGetTypeID()) { int valueAsInt; CFNumberGetValue(static_cast(value), kCFNumberIntType, &valueAsInt); forceTransform = !valueAsInt; } } } if (forceTransform) { [[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular]; } } static CGColorSpaceRef m_genericColorSpace = 0; static QHash m_displayColorSpaceHash; static bool m_postRoutineRegistered = false; CGColorSpaceRef qt_mac_genericColorSpace() { #if 0 if (!m_genericColorSpace) { if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); } else { m_genericColorSpace = CGColorSpaceCreateDeviceRGB(); } if (!m_postRoutineRegistered) { m_postRoutineRegistered = true; qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces); } } return m_genericColorSpace; #else // Just return the main display colorspace for the moment. return qt_mac_displayColorSpace(0); #endif } /* Ideally, we should pass the widget in here, and use CGGetDisplaysWithRect() etc. to support multiple displays correctly. */ CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget) { CGColorSpaceRef colorSpace; CGDirectDisplayID displayID; if (widget == 0) { displayID = CGMainDisplayID(); } else { displayID = CGMainDisplayID(); /* ### get correct display const QRect &qrect = widget->window()->geometry(); CGRect rect = CGRectMake(qrect.x(), qrect.y(), qrect.width(), qrect.height()); CGDisplayCount throwAway; CGDisplayErr dErr = CGGetDisplaysWithRect(rect, 1, &displayID, &throwAway); if (dErr != kCGErrorSuccess) return macDisplayColorSpace(0); // fall back on main display */ } if ((colorSpace = m_displayColorSpaceHash.value(displayID))) return colorSpace; colorSpace = CGDisplayCopyColorSpace(displayID); if (colorSpace == 0) colorSpace = CGColorSpaceCreateDeviceRGB(); m_displayColorSpaceHash.insert(displayID, colorSpace); if (!m_postRoutineRegistered) { m_postRoutineRegistered = true; void qt_mac_cleanUpMacColorSpaces(); qAddPostRoutine(qt_mac_cleanUpMacColorSpaces); } return colorSpace; } void qt_mac_cleanUpMacColorSpaces() { if (m_genericColorSpace) { CFRelease(m_genericColorSpace); m_genericColorSpace = 0; } QHash::const_iterator it = m_displayColorSpaceHash.constBegin(); while (it != m_displayColorSpaceHash.constEnd()) { if (it.value()) CFRelease(it.value()); ++it; } m_displayColorSpaceHash.clear(); } CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice) { #ifdef QT_NO_WIDGETS Q_UNUSED(paintDevice) return qt_mac_displayColorSpace(0); #else bool isWidget = (paintDevice->devType() == QInternal::Widget); return qt_mac_displayColorSpace(isWidget ? static_cast(paintDevice): 0); #endif } QString qt_mac_applicationName() { QString appName; CFTypeRef string = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), CFSTR("CFBundleName")); if (string) appName = QCFString::toQString(static_cast(string)); if (appName.isEmpty()) { QString arg0 = QGuiApplicationPrivate::instance()->appName(); if (arg0.contains("/")) { QStringList parts = arg0.split(QLatin1Char('/')); appName = parts.at(parts.count() - 1); } else { appName = arg0; } } return appName; } int qt_mac_mainScreenHeight() { QMacAutoReleasePool pool; NSArray *screens = [NSScreen screens]; if ([screens count] > 0) { // The first screen in the screens array is documented // to have the (0,0) origin. NSRect screenFrame = [[screens objectAtIndex: 0] frame]; return screenFrame.size.height; } return 0; } int qt_mac_flipYCoordinate(int y) { return qt_mac_mainScreenHeight() - y; } qreal qt_mac_flipYCoordinate(qreal y) { return qt_mac_mainScreenHeight() - y; } QPointF qt_mac_flipPoint(const NSPoint &p) { return QPointF(p.x, qt_mac_flipYCoordinate(p.y)); } NSPoint qt_mac_flipPoint(const QPoint &p) { return NSMakePoint(p.x(), qt_mac_flipYCoordinate(p.y())); } NSPoint qt_mac_flipPoint(const QPointF &p) { return NSMakePoint(p.x(), qt_mac_flipYCoordinate(p.y())); } NSRect qt_mac_flipRect(const QRect &rect) { int flippedY = qt_mac_flipYCoordinate(rect.y() + rect.height()); return NSMakeRect(rect.x(), flippedY, rect.width(), rect.height()); } OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage) { // Verbatim copy if HIViewDrawCGImage (as shown on Carbon-Dev) OSStatus err = noErr; require_action(inContext != NULL, InvalidContext, err = paramErr); require_action(inBounds != NULL, InvalidBounds, err = paramErr); require_action(inImage != NULL, InvalidImage, err = paramErr); CGContextSaveGState( inContext ); CGContextTranslateCTM (inContext, 0, inBounds->origin.y + CGRectGetMaxY(*inBounds)); CGContextScaleCTM(inContext, 1, -1); CGContextDrawImage(inContext, *inBounds, inImage); CGContextRestoreGState(inContext); InvalidImage: InvalidBounds: InvalidContext: return err; } Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum) { if (buttonNum == 0) return Qt::LeftButton; if (buttonNum == 1) return Qt::RightButton; if (buttonNum == 2) return Qt::MiddleButton; if (buttonNum >= 3 && buttonNum <= 31) { // handle XButton1 and higher via logical shift return Qt::MouseButton(uint(Qt::MiddleButton) << (buttonNum - 3)); } // else error: buttonNum too high, or negative return Qt::NoButton; } bool qt_mac_execute_apple_script(const char *script, long script_len, AEDesc *ret) { OSStatus err; AEDesc scriptTextDesc; ComponentInstance theComponent = 0; OSAID scriptID = kOSANullScript, resultID = kOSANullScript; // set up locals to a known state AECreateDesc(typeNull, 0, 0, &scriptTextDesc); scriptID = kOSANullScript; resultID = kOSANullScript; // open the scripting component theComponent = OpenDefaultComponent(kOSAComponentType, typeAppleScript); if (!theComponent) { err = paramErr; goto bail; } // put the script text into an aedesc err = AECreateDesc(typeUTF8Text, script, script_len, &scriptTextDesc); if (err != noErr) goto bail; // compile the script err = OSACompile(theComponent, &scriptTextDesc, kOSAModeNull, &scriptID); if (err != noErr) goto bail; // run the script err = OSAExecute(theComponent, scriptID, kOSANullScript, kOSAModeNull, &resultID); // collect the results - if any if (ret) { AECreateDesc(typeNull, 0, 0, ret); if (err == errOSAScriptError) OSAScriptError(theComponent, kOSAErrorMessage, typeChar, ret); else if (err == noErr && resultID != kOSANullScript) OSADisplay(theComponent, resultID, typeChar, kOSAModeNull, ret); } bail: AEDisposeDesc(&scriptTextDesc); if (scriptID != kOSANullScript) OSADispose(theComponent, scriptID); if (resultID != kOSANullScript) OSADispose(theComponent, resultID); if (theComponent) CloseComponent(theComponent); return err == noErr; } bool qt_mac_execute_apple_script(const char *script, AEDesc *ret) { return qt_mac_execute_apple_script(script, qstrlen(script), ret); } bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret) { const QByteArray l = script.toUtf8(); return qt_mac_execute_apple_script(l.constData(), l.size(), ret); } QString qt_mac_removeAmpersandEscapes(QString s) { return QPlatformTheme::removeMnemonics(s).trimmed(); } /*! \internal Returns the CoreGraphics CGContextRef of the paint device. 0 is returned if it can't be obtained. It is the caller's responsibility to CGContextRelease the context when finished using it. \warning This function is only available on OS X. \warning This function is duplicated in qmacstyle_mac.mm */ CGContextRef qt_mac_cg_context(QPaintDevice *pdev) { // In Qt 5, QWidget and QPixmap (and QImage) paint devices are all QImages under the hood. QImage *image = 0; if (pdev->devType() == QInternal::Image) { image = static_cast(pdev); } else if (pdev->devType() == QInternal::Pixmap) { const QPixmap *pm = static_cast(pdev); QPlatformPixmap *data = const_cast(pm)->data_ptr().data(); if (data && data->classId() == QPlatformPixmap::RasterClass) { image = data->buffer(); } else { qDebug("qt_mac_cg_context: Unsupported pixmap class"); } } else if (pdev->devType() == QInternal::Widget) { // TODO test: image = static_cast(static_cast(pdev)->backingStore()->paintDevice()); qDebug("qt_mac_cg_context: not implemented: Widget class"); } if (!image) return 0; // Context type not supported. CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pdev); uint flags = kCGImageAlphaPremultipliedFirst; flags |= kCGBitmapByteOrder32Host; CGContextRef ret = 0; ret = CGBitmapContextCreate(image->bits(), image->width(), image->height(), 8, image->bytesPerLine(), colorspace, flags); CGContextTranslateCTM(ret, 0, image->height()); CGContextScaleCTM(ret, 1, -1); return ret; } QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size) { const NSSize pixmapSize = NSMakeSize(size.width(), size.height()); QPixmap pixmap(pixmapSize.width, pixmapSize.height); pixmap.fill(Qt::transparent); [image setSize:pixmapSize]; const NSRect iconRect = NSMakeRect(0, 0, pixmapSize.width, pixmapSize.height); QMacCGContext ctx(&pixmap); if (!ctx) return QPixmap(); NSGraphicsContext *gc = [NSGraphicsContext qt_graphicsContextWithCGContext:ctx flipped:YES]; if (!gc) return QPixmap(); [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:gc]; [image drawInRect:iconRect fromRect:iconRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil]; [NSGraphicsContext restoreGraphicsState]; return pixmap; } QImage qt_mac_toQImage(CGImageRef image) { const size_t w = CGImageGetWidth(image), h = CGImageGetHeight(image); QImage ret(w, h, QImage::Format_ARGB32_Premultiplied); ret.fill(Qt::transparent); CGRect rect = CGRectMake(0, 0, w, h); CGContextRef ctx = qt_mac_cg_context(&ret); qt_mac_drawCGImage(ctx, &rect, image); CGContextRelease(ctx); return ret; } QT_END_NAMESPACE