From 30542304f19fe967b29f71c67cdcc782dc1fa1a8 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Wed, 24 Oct 2012 16:09:52 +0200 Subject: Mac: Add support for WindowMasks platform capability Also brings back a working QWidgetPrivate::setMask_sys(). Change-Id: Idde9eea15d28bb0299258df81322a5a3ff0b9493 Reviewed-by: Liang Qi Reviewed-by: Jens Bache-Wiig --- src/plugins/platforms/cocoa/qcocoaintegration.mm | 13 +-- src/plugins/platforms/cocoa/qcocoawindow.h | 1 + src/plugins/platforms/cocoa/qcocoawindow.mm | 10 +++ src/plugins/platforms/cocoa/qnsview.h | 3 + src/plugins/platforms/cocoa/qnsview.mm | 105 +++++++++++++++++------ 5 files changed, 100 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index b069446c50..100dc1962c 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -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); } } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index d5dbe58de9..db3a20c2be 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -107,6 +107,7 @@ public: void lower(); void propagateSizeHints(); void setOpacity(qreal level); + void setMask(const QRegion ®ion); bool setKeyboardGrabEnabled(bool grab); bool setMouseGrabEnabled(bool grab); QMargins frameMargins() const; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index d6b4ee68a9..de6e7dc43e 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -509,6 +509,16 @@ void QCocoaWindow::setOpacity(qreal level) [m_nsWindow setAlphaValue:level]; } +void QCocoaWindow::setMask(const QRegion ®ion) +{ + if (m_nsWindow) { + [m_nsWindow setOpaque:NO]; + [m_nsWindow setBackgroundColor:[NSColor clearColor]]; + } + + [m_contentView setMaskRegion:®ion]; +} + bool QCocoaWindow::setKeyboardGrabEnabled(bool grab) { if (!m_nsWindow) diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 32e140f9ff..246d311f7b 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -54,6 +54,8 @@ QT_END_NAMESPACE @interface QNSView : NSView { 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; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 33d0fb4bae..d62913a7af 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -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 -- cgit v1.2.3