Mac: Add support for WindowMasks platform capability
authorGabriel de Dietrich <gabriel.dedietrich@digia.com>
Wed, 24 Oct 2012 14:09:52 +0000 (16:09 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Thu, 1 Nov 2012 23:38:51 +0000 (00:38 +0100)
Also brings back a working QWidgetPrivate::setMask_sys().

Change-Id: Idde9eea15d28bb0299258df81322a5a3ff0b9493
Reviewed-by: Liang Qi <liang.qi@digia.com>
Reviewed-by: Jens Bache-Wiig <jens.bache-wiig@digia.com>
src/plugins/platforms/cocoa/qcocoaintegration.mm
src/plugins/platforms/cocoa/qcocoawindow.h
src/plugins/platforms/cocoa/qcocoawindow.mm
src/plugins/platforms/cocoa/qnsview.h
src/plugins/platforms/cocoa/qnsview.mm

index b069446..100dc19 100644 (file)
@@ -302,11 +302,14 @@ void QCocoaIntegration::updateScreens()
 bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const
 {
     switch (cap) {
-    case ThreadedPixmaps: return true;
-    case OpenGL : return true;
-    case ThreadedOpenGL : return true;
-    case BufferQueueingOpenGL: return true;
-    default: return QPlatformIntegration::hasCapability(cap);
+    case ThreadedPixmaps:
+    case OpenGL:
+    case ThreadedOpenGL:
+    case BufferQueueingOpenGL:
+    case WindowMasks:
+        return true;
+    default:
+        return QPlatformIntegration::hasCapability(cap);
     }
 }
 
index d5dbe58..db3a20c 100644 (file)
@@ -107,6 +107,7 @@ public:
     void lower();
     void propagateSizeHints();
     void setOpacity(qreal level);
+    void setMask(const QRegion &region);
     bool setKeyboardGrabEnabled(bool grab);
     bool setMouseGrabEnabled(bool grab);
     QMargins frameMargins() const;
index d6b4ee6..de6e7dc 100644 (file)
@@ -509,6 +509,16 @@ void QCocoaWindow::setOpacity(qreal level)
         [m_nsWindow setAlphaValue:level];
 }
 
+void QCocoaWindow::setMask(const QRegion &region)
+{
+    if (m_nsWindow) {
+        [m_nsWindow setOpaque:NO];
+        [m_nsWindow setBackgroundColor:[NSColor clearColor]];
+    }
+
+    [m_contentView setMaskRegion:&region];
+}
+
 bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
 {
     if (!m_nsWindow)
index 32e140f..246d311 100644 (file)
@@ -54,6 +54,8 @@ QT_END_NAMESPACE
 
 @interface QNSView : NSView <NSTextInputClient> {
     CGImageRef m_cgImage;
+    CGImageRef m_maskImage;
+    uchar *m_maskData;
     QWindow *m_window;
     QCocoaWindow *m_platformWindow;
     Qt::MouseButtons m_buttons;
@@ -68,6 +70,7 @@ QT_END_NAMESPACE
 - (id)initWithQWindow:(QWindow *)window platformWindow:(QCocoaWindow *) platformWindow;
 
 - (void)setImage:(QImage *)image;
+- (void)setMaskRegion:(const QRegion *)region;
 - (void)drawRect:(NSRect)dirtyRect;
 - (void)updateGeometry;
 - (void)windowNotification : (NSNotification *) windowNotification;
index 33d0fb4..d62913a 100644 (file)
@@ -75,6 +75,8 @@ static QTouchDevice *touchDevice = 0;
     self = [super initWithFrame : NSMakeRect(0,0, 300,300)];
     if (self) {
         m_cgImage = 0;
+        m_maskImage = 0;
+        m_maskData = 0;
         m_window = 0;
         m_buttons = Qt::NoButton;
         m_sendKeyEvent = false;
@@ -93,6 +95,10 @@ static QTouchDevice *touchDevice = 0;
 {
     CGImageRelease(m_cgImage);
     m_cgImage = 0;
+    CGImageRelease(m_maskImage);
+    m_maskImage = 0;
+    delete[] m_maskData;
+    m_maskData = 0;
     m_window = 0;
     [super dealloc];
 }
@@ -205,47 +211,86 @@ static QTouchDevice *touchDevice = 0;
     }
 }
 
-- (void) setImage:(QImage *)image
+static CGImageRef qt_mac_toCGImage(QImage *qImage, bool isMask, uchar **dataCopy)
 {
-    CGImageRelease(m_cgImage);
-
-    int width = image->width();
-    int height = image->height();
+    int width = qImage->width();
+    int height = qImage->height();
 
     if (width <= 0 || height <= 0) {
         qWarning() << Q_FUNC_INFO <<
             "setting invalid size" << width << "x" << height << "for qnsview image";
-        m_cgImage = 0;
-        return;
+        return 0;
     }
 
-    const uchar *imageData = image->bits();
-    int bitDepth = image->depth();
+    const uchar *imageData = qImage->bits();
+    if (dataCopy) {
+        delete[] *dataCopy;
+        *dataCopy = new uchar[qImage->byteCount()];
+        memcpy(*dataCopy, imageData, qImage->byteCount());
+    }
+    int bitDepth = qImage->depth();
     int colorBufferSize = 8;
-    int bytesPrLine = image->bytesPerLine();
-
-    CGColorSpaceRef cgColourSpaceRef = CGColorSpaceCreateDeviceRGB();
+    int bytesPrLine = qImage->bytesPerLine();
 
     CGDataProviderRef cgDataProviderRef = CGDataProviderCreateWithData(
                 NULL,
-                imageData,
-                image->byteCount(),
+                dataCopy ? *dataCopy : imageData,
+                qImage->byteCount(),
                 NULL);
 
-    m_cgImage = CGImageCreate(width,
-                              height,
-                              colorBufferSize,
-                              bitDepth,
-                              bytesPrLine,
-                              cgColourSpaceRef,
-                              kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
-                              cgDataProviderRef,
-                              NULL,
-                              false,
-                              kCGRenderingIntentDefault);
+    CGImageRef cgImage = 0;
+    if (isMask) {
+        cgImage = CGImageMaskCreate(width,
+                                    height,
+                                    colorBufferSize,
+                                    bitDepth,
+                                    bytesPrLine,
+                                    cgDataProviderRef,
+                                    NULL,
+                                    false);
+    } else {
+        CGColorSpaceRef cgColourSpaceRef = CGColorSpaceCreateDeviceRGB();
+        cgImage = CGImageCreate(width,
+                                height,
+                                colorBufferSize,
+                                bitDepth,
+                                bytesPrLine,
+                                cgColourSpaceRef,
+                                kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
+                                cgDataProviderRef,
+                                NULL,
+                                false,
+                                kCGRenderingIntentDefault);
+        CGColorSpaceRelease(cgColourSpaceRef);
+    }
+    return cgImage;
+}
 
-    CGColorSpaceRelease(cgColourSpaceRef);
+- (void) setImage:(QImage *)image
+{
+    CGImageRelease(m_cgImage);
+    m_cgImage = qt_mac_toCGImage(image, false, 0);
+}
+
+- (void) setMaskRegion:(const QRegion *)region
+{
+    if (m_maskImage)
+        CGImageRelease(m_maskImage);
+    if (region->isEmpty()) {
+        m_maskImage = 0;
+    }
 
+    const QRect &rect = qt_mac_toQRect([self frame]);
+    QImage maskImage(rect.size(), QImage::Format_RGB888);
+    maskImage.fill(Qt::white);
+    QPainter p(&maskImage);
+    p.setRenderHint(QPainter::Antialiasing);
+    p.setClipRegion(*region);
+    p.fillRect(rect, QBrush(Qt::black));
+    p.end();
+
+    maskImage = maskImage.convertToFormat(QImage::Format_Indexed8);
+    m_maskImage = qt_mac_toCGImage(&maskImage, true, &m_maskData);
 }
 
 - (void) drawRect:(NSRect)dirtyRect
@@ -263,13 +308,19 @@ static QTouchDevice *touchDevice = 0;
     CGContextTranslateCTM(cgContext, 0, dy);
     CGContextScaleCTM(cgContext, 1, -1);
 
+    CGImageRef subMask = 0;
+    if (m_maskImage) {
+        subMask = CGImageCreateWithImageInRect(m_maskImage, dirtyCGRect);
+        CGContextClipToMask(cgContext, dirtyCGRect, subMask);
+    }
+
     CGImageRef subImage = CGImageCreateWithImageInRect(m_cgImage, dirtyCGRect);
     CGContextDrawImage(cgContext,dirtyCGRect,subImage);
 
     CGContextRestoreGState(cgContext);
 
     CGImageRelease(subImage);
-
+    CGImageRelease(subMask);
 }
 
 - (BOOL) isFlipped