summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro10
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.h8
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm20
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm43
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.h8
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm227
-rw-r--r--src/plugins/platforms/cocoa/qcocoaclipboard.h8
-rw-r--r--src/plugins/platforms/cocoa/qcocoacolordialoghelper.h10
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm5
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm18
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.h22
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm26
-rw-r--r--src/plugins/platforms/cocoa/qcocoafontdialoghelper.h10
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.h15
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm114
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h153
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm73
-rw-r--r--src/plugins/platforms/cocoa/qcocoainputcontext.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoainputcontext.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h99
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm274
-rw-r--r--src/plugins/platforms/cocoa/qcocoakeymapper.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoakeymapper.mm19
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.h45
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm224
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.h11
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm7
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.h32
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm5
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoamimetypes.mm92
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.h8
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoansmenu.h86
-rw-r--r--src/plugins/platforms/cocoa/qcocoansmenu.mm296
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintdevice.h34
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintdevice.mm11
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintersupport.h10
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.h108
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.mm309
-rw-r--r--src/plugins/platforms/cocoa/qcocoaservices.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemsettings.mm103
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.h18
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.h24
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm13
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h205
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm1699
-rw-r--r--src/plugins/platforms/cocoa/qmultitouch_mac.mm22
-rw-r--r--src/plugins/platforms/cocoa/qmultitouch_mac_p.h2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h18
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm427
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.h81
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm331
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.mm28
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac.mm98
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac_p.h6
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac.mm2
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac_p.h4
63 files changed, 2894 insertions, 2675 deletions
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index 5a00e1b7ec..2694cb3607 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -2,16 +2,19 @@ TARGET = qcocoa
SOURCES += main.mm \
qcocoaintegration.mm \
+ qcocoascreen.mm \
qcocoatheme.mm \
qcocoabackingstore.mm \
qcocoawindow.mm \
qnsview.mm \
+ qnswindow.mm \
qnsviewaccessibility.mm \
qnswindowdelegate.mm \
qcocoanativeinterface.mm \
qcocoaeventdispatcher.mm \
qcocoaapplicationdelegate.mm \
qcocoaapplication.mm \
+ qcocoansmenu.mm \
qcocoamenu.mm \
qcocoamenuitem.mm \
qcocoamenubar.mm \
@@ -34,15 +37,18 @@ SOURCES += main.mm \
messages.cpp
HEADERS += qcocoaintegration.h \
+ qcocoascreen.h \
qcocoatheme.h \
qcocoabackingstore.h \
qcocoawindow.h \
qnsview.h \
+ qnswindow.h \
qnswindowdelegate.h \
qcocoanativeinterface.h \
qcocoaeventdispatcher.h \
qcocoaapplicationdelegate.h \
qcocoaapplication.h \
+ qcocoansmenu.h \
qcocoamenu.h \
qcocoamenuitem.h \
qcocoamenubar.h \
@@ -72,12 +78,12 @@ qtConfig(opengl.*) {
RESOURCES += qcocoaresources.qrc
-LIBS += -framework AppKit -framework Carbon -framework IOKit -lcups
+LIBS += -framework AppKit -framework Carbon -framework IOKit -framework QuartzCore -lcups
QT += \
core-private gui-private \
accessibility_support-private clipboard_support-private theme_support-private \
- fontdatabase_support-private graphics_support-private cgl_support-private
+ fontdatabase_support-private graphics_support-private
CONFIG += no_app_extension_api_only
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
index e7957276c2..e456364555 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
@@ -53,10 +53,10 @@ class QCocoaAccessibility : public QPlatformAccessibility
public:
QCocoaAccessibility();
~QCocoaAccessibility();
- void notifyAccessibilityUpdate(QAccessibleEvent *event) Q_DECL_OVERRIDE;
- void setRootObject(QObject *o) Q_DECL_OVERRIDE;
- void initialize() Q_DECL_OVERRIDE;
- void cleanup() Q_DECL_OVERRIDE;
+ void notifyAccessibilityUpdate(QAccessibleEvent *event) override;
+ void setRootObject(QObject *o) override;
+ void initialize() override;
+ void cleanup() override;
};
namespace QCocoaAccessible {
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index b15c486e9d..8b6dcb35a6 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -41,8 +41,6 @@
#include <QtGui/qaccessible.h>
#include <private/qcore_mac_p.h>
-#include <Carbon/Carbon.h>
-
QT_BEGIN_NAMESPACE
#ifndef QT_NO_ACCESSIBILITY
@@ -369,7 +367,7 @@ id getValueAttribute(QAccessibleInterface *interface)
QString text;
if (interface->state().passwordEdit) {
// return round password replacement chars
- text = QString(end, QChar(kBulletUnicode));
+ text = QString(end, QChar(0x2022));
} else {
// VoiceOver will read out the entire text string at once when returning
// text as a value. For large text edits the size of the returned string
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index 7e6bae127c..df2336d08b 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -40,6 +40,7 @@
#include "qcocoaaccessibility.h"
#include "qcocoahelpers.h"
#include "qcocoawindow.h"
+#include "qcocoascreen.h"
#include "private/qaccessiblecache_p.h"
#include <QtAccessibilitySupport/private/qaccessiblebridgeutils_p.h>
#include <QtGui/qaccessible.h>
@@ -298,9 +299,9 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
// We're in the same top level element as our parent.
return [[self parentElement] accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
} else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
- QPoint qtPosition = iface->rect().topLeft();
- QSize qtSize = iface->rect().size();
- return [NSValue valueWithPoint: NSMakePoint(qtPosition.x(), qt_mac_flipYCoordinate(qtPosition.y() + qtSize.height()))];
+ // The position in points of the element's lower-left corner in screen-relative coordinates
+ QPointF qtPosition = QRectF(iface->rect()).bottomLeft();
+ return [NSValue valueWithPoint:QCocoaScreen::mapToNative(qtPosition)];
} else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) {
QSize qtSize = iface->rect().size();
return [NSValue valueWithSize: NSMakeSize(qtSize.width(), qtSize.height())];
@@ -430,7 +431,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
if ([attribute isEqualToString: NSAccessibilityBoundsForRangeParameterizedAttribute]) {
NSRange range = [parameter rangeValue];
QRect firstRect = iface->textInterface()->characterRect(range.location);
- QRect rect;
+ QRectF rect;
if (range.length > 0) {
NSUInteger position = range.location + range.length - 1;
if (position > range.location && iface->textInterface()->text(position, position + 1) == QStringLiteral("\n"))
@@ -441,15 +442,14 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
rect = firstRect;
rect.setWidth(1);
}
- return [NSValue valueWithRect: NSMakeRect((CGFloat) rect.x(),(CGFloat) qt_mac_flipYCoordinate(rect.y() + rect.height()), rect.width(), rect.height())];
+ return [NSValue valueWithRect:QCocoaScreen::mapToNative(rect)];
}
if ([attribute isEqualToString: NSAccessibilityAttributedStringForRangeParameterizedAttribute]) {
NSRange range = [parameter rangeValue];
QString text = iface->textInterface()->text(range.location, range.location + range.length);
return [[NSAttributedString alloc] initWithString:text.toNSString()];
} else if ([attribute isEqualToString: NSAccessibilityRangeForPositionParameterizedAttribute]) {
- NSPoint nsPoint = [parameter pointValue];
- QPoint point(static_cast<int>(nsPoint.x), static_cast<int>(qt_mac_flipYCoordinate(nsPoint.y)));
+ QPoint point = QCocoaScreen::mapFromNative([parameter pointValue]).toPoint();
int offset = iface->textInterface()->offsetAtPoint(point);
return [NSValue valueWithRange:NSMakeRange(static_cast<NSUInteger>(offset), 1)];
} else if ([attribute isEqualToString: NSAccessibilityStyleRangeForIndexParameterizedAttribute]) {
@@ -566,8 +566,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return NSAccessibilityUnignoredAncestor(self);
}
- int y = qt_mac_flipYCoordinate(point.y);
- QAccessibleInterface *childInterface = iface->childAt(point.x, y);
+ QPointF screenPoint = QCocoaScreen::mapFromNative(point);
+ QAccessibleInterface *childInterface = iface->childAt(screenPoint.x(), screenPoint.y());
// No child found, meaning we hit this element.
if (!childInterface || !childInterface->isValid())
return NSAccessibilityUnignoredAncestor(self);
@@ -575,7 +575,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
// find the deepest child at the point
QAccessibleInterface *childOfChildInterface = 0;
do {
- childOfChildInterface = childInterface->childAt(point.x, y);
+ childOfChildInterface = childInterface->childAt(screenPoint.x(), screenPoint.y());
if (childOfChildInterface && childOfChildInterface->isValid())
childInterface = childOfChildInterface;
} while (childOfChildInterface && childOfChildInterface->isValid());
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 03148c769b..a94e0dc517 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -86,16 +86,21 @@
QT_USE_NAMESPACE
-QT_BEGIN_NAMESPACE
-static QCocoaApplicationDelegate *sharedCocoaApplicationDelegate = nil;
+@implementation QCocoaApplicationDelegate
-static void cleanupCocoaApplicationDelegate()
++ (instancetype)sharedDelegate
{
- [sharedCocoaApplicationDelegate release];
+ static QCocoaApplicationDelegate *shared = nil;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ shared = [[self alloc] init];
+ atexit_b(^{
+ [shared release];
+ shared = nil;
+ });
+ });
+ return shared;
}
-QT_END_NAMESPACE
-
-@implementation QCocoaApplicationDelegate
- (id)init
{
@@ -120,7 +125,6 @@ QT_END_NAMESPACE
- (void)dealloc
{
- sharedCocoaApplicationDelegate = nil;
[dockMenu release];
if (reflectionDelegate) {
[[NSApplication sharedApplication] setDelegate:reflectionDelegate];
@@ -131,27 +135,6 @@ QT_END_NAMESPACE
[super dealloc];
}
-+ (id)allocWithZone:(NSZone *)zone
-{
- @synchronized(self) {
- if (sharedCocoaApplicationDelegate == nil) {
- sharedCocoaApplicationDelegate = [super allocWithZone:zone];
- qAddPostRoutine(cleanupCocoaApplicationDelegate);
- return sharedCocoaApplicationDelegate;
- }
- }
- return nil;
-}
-
-+ (QCocoaApplicationDelegate *)sharedDelegate
-{
- @synchronized(self) {
- if (sharedCocoaApplicationDelegate == nil)
- [[self alloc] init];
- }
- return [[sharedCocoaApplicationDelegate retain] autorelease];
-}
-
- (void)setDockMenu:(NSMenu*)newMenu
{
[newMenu retain];
@@ -284,7 +267,7 @@ QT_END_NAMESPACE
inLaunch = false;
if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) {
- if (QSysInfo::macVersion() >= QSysInfo::MV_10_12) {
+ if (__builtin_available(macOS 10.12, *)) {
// Move the application window to front to avoid launching behind the terminal.
// Ignoring other apps is necessary (we must ignore the terminal), but makes
// Qt apps play slightly less nice with other apps when lanching from Finder
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
index 5ed455fd71..b4cd506513 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h
@@ -42,6 +42,8 @@
#include <QtGraphicsSupport/private/qrasterbackingstore_p.h>
+#include <private/qcore_mac_p.h>
+
QT_BEGIN_NAMESPACE
class QCocoaBackingStore : public QRasterBackingStore
@@ -50,10 +52,12 @@ public:
QCocoaBackingStore(QWindow *window);
~QCocoaBackingStore();
- void flush(QWindow *, const QRegion &, const QPoint &) Q_DECL_OVERRIDE;
+ void flush(QWindow *, const QRegion &, const QPoint &) override;
private:
- QImage::Format format() const Q_DECL_OVERRIDE;
+ bool windowHasUnifiedToolbar() const;
+ QImage::Format format() const override;
+ void redrawRoundedBottomCorners(CGRect) const;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 1d7ad772dc..57a03905ab 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -44,6 +44,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcCocoaBackingStore, "qt.qpa.cocoa.backingstore");
+
QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
: QRasterBackingStore(window)
{
@@ -51,26 +53,239 @@ QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
QCocoaBackingStore::~QCocoaBackingStore()
{
- if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle()))
- [qnsview_cast(cocoaWindow->view()) clearBackingStore:this];
+}
+
+bool QCocoaBackingStore::windowHasUnifiedToolbar() const
+{
+ Q_ASSERT(window()->handle());
+ return static_cast<QCocoaWindow *>(window()->handle())->m_drawContentBorderGradient;
}
QImage::Format QCocoaBackingStore::format() const
{
- QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle());
- if (cocoaWindow && cocoaWindow->m_drawContentBorderGradient)
+ if (windowHasUnifiedToolbar())
return QImage::Format_ARGB32_Premultiplied;
return QRasterBackingStore::format();
}
+#if !QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12)
+static const NSCompositingOperation NSCompositingOperationCopy = NSCompositeCopy;
+static const NSCompositingOperation NSCompositingOperationSourceOver = NSCompositeSourceOver;
+#endif
+
+/*!
+ Flushes the given \a region from the specified \a window onto the
+ screen.
+
+ The \a window is the top level window represented by this backingstore,
+ or a non-transient child of that window.
+
+ If the \a window is a child window, the \a region will be in child window
+ coordinates, and the \a offset will be the child window's offset in relation
+ to the backingstore's top level window.
+*/
void QCocoaBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
if (m_image.isNull())
return;
- if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()))
- [qnsview_cast(cocoaWindow->view()) flushBackingStore:this region:region offset:offset];
+ // Use local pool so that any stale image references are cleaned up after flushing
+ QMacAutoReleasePool pool;
+
+ const QWindow *topLevelWindow = this->window();
+
+ Q_ASSERT(topLevelWindow->handle() && window->handle());
+ Q_ASSERT(!topLevelWindow->handle()->isForeignWindow() && !window->handle()->isForeignWindow());
+
+ QNSView *topLevelView = qnsview_cast(static_cast<QCocoaWindow *>(topLevelWindow->handle())->view());
+ QNSView *view = qnsview_cast(static_cast<QCocoaWindow *>(window->handle())->view());
+
+ if (lcCocoaBackingStore().isDebugEnabled()) {
+ QString targetViewDescription;
+ if (view != topLevelView) {
+ QDebug targetDebug(&targetViewDescription);
+ targetDebug << "onto" << topLevelView << "at" << offset;
+ }
+ qCDebug(lcCocoaBackingStore) << "Flushing" << region << "of" << view << qPrintable(targetViewDescription);
+ }
+
+ // Prevent potentially costly color conversion by assigning the display color space
+ // to the backingstore image. This does not copy the underlying image data.
+ CGColorSpaceRef displayColorSpace = view.window.screen.colorSpace.CGColorSpace;
+ QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace(
+ QCFType<CGImageRef>(m_image.toCGImage()), displayColorSpace);
+
+ if (view.layer) {
+ // In layer-backed mode, locking focus on a view does not give the right
+ // view transformation, and doesn't give us a graphics context to render
+ // via when drawing outside of the display cycle. Instead we tell AppKit
+ // that we want to update the layer's content, via [NSView wantsUpdateLayer],
+ // which result in AppKit not creating a backingstore for each layer, and
+ // we then directly set the layer's backingstore (content) to our backingstore,
+ // masked to the part of the subview that is relevant.
+ // FIXME: Figure out if there's a way to do partial updates
+ view.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage);
+ if (view != topLevelView) {
+ view.layer.contentsRect = CGRectApplyAffineTransform(
+ [view convertRect:view.bounds toView:topLevelView],
+ // The contentsRect is in unit coordinate system
+ CGAffineTransformMakeScale(1.0 / m_image.width(), 1.0 / m_image.height()));
+ }
+ return;
+ }
+
+ // Normally a NSView is drawn via drawRect, as part of the display cycle in the
+ // main runloop, via setNeedsDisplay and friends. AppKit will lock focus on each
+ // individual view, starting with the top level and then traversing any subviews,
+ // calling drawRect for each of them. This pull model results in expose events
+ // sent to Qt, which result in drawing to the backingstore and flushing it.
+ // Qt may also decide to paint and flush the backingstore via e.g. timers,
+ // or other events such as mouse events, in which case we're in a push model.
+ // If there is no focused view, it means we're in the latter case, and need
+ // to manually flush the NSWindow after drawing to its graphic context.
+ const bool drawingOutsideOfDisplayCycle = ![NSView focusView];
+
+ // We also need to ensure the flushed view has focus, so that the graphics
+ // context is set up correctly (coordinate system, clipping, etc). Outside
+ // of the normal display cycle there is no focused view, as explained above,
+ // so we have to handle it manually. There's also a corner case inside the
+ // normal display cycle due to way QWidgetBackingStore composits native child
+ // widgets, where we'll get a flush of a native child during the drawRect of
+ // its parent/ancestor, and the parent/ancestor being the one locked by AppKit.
+ // In this case we also need to lock and unlock focus manually.
+ const bool shouldHandleViewLockManually = [NSView focusView] != view;
+ if (shouldHandleViewLockManually && ![view lockFocusIfCanDraw]) {
+ qWarning() << "failed to lock focus of" << view;
+ return;
+ }
+
+ const qreal devicePixelRatio = m_image.devicePixelRatio();
+
+ // If the flushed window is a content view, and not in unified toolbar mode,
+ // we can get away with copying the backingstore instead of blending.
+ const NSCompositingOperation compositingOperation = static_cast<QCocoaWindow *>(
+ window->handle())->isContentView() && !windowHasUnifiedToolbar() ?
+ NSCompositingOperationCopy : NSCompositingOperationSourceOver;
+
+#ifdef QT_DEBUG
+ static bool debugBackingStoreFlush = [[NSUserDefaults standardUserDefaults]
+ boolForKey:@"QtCocoaDebugBackingStoreFlush"];
+#endif
+
+ // -------------------------------------------------------------------------
+
+ // The current contexts is typically a NSWindowGraphicsContext, but can be
+ // NSBitmapGraphicsContext e.g. when debugging the view hierarchy in Xcode.
+ // If we need to distinguish things here in the future, we can use e.g.
+ // [NSGraphicsContext drawingToScreen], or the attributes of the context.
+ NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
+ Q_ASSERT_X(graphicsContext, "QCocoaBackingStore",
+ "Focusing the view should give us a current graphics context");
+
+ // Create temporary image to use for blitting, without copying image data
+ NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease];
+
+ QRegion clippedRegion = region;
+ for (QWindow *w = window; w; w = w->parent()) {
+ if (!w->mask().isEmpty()) {
+ clippedRegion &= w == window ? w->mask()
+ : w->mask().translated(window->mapFromGlobal(w->mapToGlobal(QPoint(0, 0))));
+ }
+ }
+
+ for (const QRect &viewLocalRect : clippedRegion) {
+ QPoint backingStoreOffset = viewLocalRect.topLeft() + offset;
+ QRect backingStoreRect(backingStoreOffset * devicePixelRatio, viewLocalRect.size() * devicePixelRatio);
+ if (graphicsContext.flipped) // Flip backingStoreRect to match graphics context
+ backingStoreRect.moveTop(m_image.height() - (backingStoreRect.y() + backingStoreRect.height()));
+
+ CGRect viewRect = viewLocalRect.toCGRect();
+
+ if (windowHasUnifiedToolbar())
+ NSDrawWindowBackground(viewRect);
+
+ [backingStoreImage drawInRect:viewRect fromRect:backingStoreRect.toCGRect()
+ operation:compositingOperation fraction:1.0 respectFlipped:YES hints:nil];
+
+#ifdef QT_DEBUG
+ if (Q_UNLIKELY(debugBackingStoreFlush)) {
+ [[NSColor colorWithCalibratedRed:drand48() green:drand48() blue:drand48() alpha:0.3] set];
+ [NSBezierPath fillRect:viewRect];
+
+ if (drawingOutsideOfDisplayCycle) {
+ [[[NSColor magentaColor] colorWithAlphaComponent:0.5] set];
+ [NSBezierPath strokeLineFromPoint:viewLocalRect.topLeft().toCGPoint()
+ toPoint:viewLocalRect.bottomRight().toCGPoint()];
+ }
+ }
+#endif
+ }
+
+ QCocoaWindow *topLevelCocoaWindow = static_cast<QCocoaWindow *>(topLevelWindow->handle());
+ if (Q_UNLIKELY(topLevelCocoaWindow->m_needsInvalidateShadow)) {
+ [topLevelView.window invalidateShadow];
+ topLevelCocoaWindow->m_needsInvalidateShadow = false;
+ }
+
+ // -------------------------------------------------------------------------
+
+ if (shouldHandleViewLockManually)
+ [view unlockFocus];
+
+ if (drawingOutsideOfDisplayCycle) {
+ redrawRoundedBottomCorners([view convertRect:region.boundingRect().toCGRect() toView:nil]);
+ [view.window flushWindow];
+ }
+}
+
+/*
+ When drawing outside of the display cycle, which Qt Widget does a lot,
+ we end up drawing over the NSThemeFrame, losing the rounded corners of
+ windows in the process.
+
+ To work around this, until we've enabled updates via setNeedsDisplay and/or
+ enabled layer-backed views, we ask the NSWindow to redraw the bottom corners
+ if they intersect with the flushed region.
+
+ This is the same logic used internally by e.g [NSView displayIfNeeded],
+ [NSRulerView _scrollToMatchContentView], and [NSClipView _immediateScrollToPoint:],
+ as well as the workaround used by WebKit to fix a similar bug:
+
+ https://trac.webkit.org/changeset/85376/webkit
+*/
+void QCocoaBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const
+{
+#if !defined(QT_APPLE_NO_PRIVATE_APIS)
+ Q_ASSERT(this->window()->handle());
+ NSWindow *window = static_cast<QCocoaWindow *>(this->window()->handle())->nativeWindow();
+
+ static SEL intersectBottomCornersWithRect = NSSelectorFromString(
+ [NSString stringWithFormat:@"_%s%s:", "intersectBottomCorners", "WithRect"]);
+ if (NSMethodSignature *signature = [window methodSignatureForSelector:intersectBottomCornersWithRect]) {
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
+ invocation.target = window;
+ invocation.selector = intersectBottomCornersWithRect;
+ [invocation setArgument:&windowRect atIndex:2];
+ [invocation invoke];
+
+ NSRect cornerOverlap = NSZeroRect;
+ [invocation getReturnValue:&cornerOverlap];
+ if (!NSIsEmptyRect(cornerOverlap)) {
+ static SEL maskRoundedBottomCorners = NSSelectorFromString(
+ [NSString stringWithFormat:@"_%s%s:", "maskRounded", "BottomCorners"]);
+ if ((signature = [window methodSignatureForSelector:maskRoundedBottomCorners])) {
+ invocation = [NSInvocation invocationWithMethodSignature:signature];
+ invocation.target = window;
+ invocation.selector = maskRoundedBottomCorners;
+ [invocation setArgument:&cornerOverlap atIndex:2];
+ [invocation invoke];
+ }
+ }
+ }
+#else
+ Q_UNUSED(windowRect);
+#endif
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaclipboard.h b/src/plugins/platforms/cocoa/qcocoaclipboard.h
index cab2cfaa91..a78d8f4187 100644
--- a/src/plugins/platforms/cocoa/qcocoaclipboard.h
+++ b/src/plugins/platforms/cocoa/qcocoaclipboard.h
@@ -56,10 +56,10 @@ class QCocoaClipboard : public QObject, public QPlatformClipboard
public:
QCocoaClipboard();
- QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE;
- void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE;
- bool supportsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE;
- bool ownsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE;
+ QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
+ void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) override;
+ bool supportsMode(QClipboard::Mode mode) const override;
+ bool ownsMode(QClipboard::Mode mode) const override;
private Q_SLOTS:
void handleApplicationStateChanged(Qt::ApplicationState state);
diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h
index 133efd6db8..01ac7e181d 100644
--- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h
+++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h
@@ -55,12 +55,12 @@ public:
QCocoaColorDialogHelper();
~QCocoaColorDialogHelper();
- void exec() Q_DECL_OVERRIDE;
- bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) Q_DECL_OVERRIDE;
- void hide() Q_DECL_OVERRIDE;
+ void exec() override;
+ bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override;
+ void hide() override;
- void setCurrentColor(const QColor&) Q_DECL_OVERRIDE;
- QColor currentColor() const Q_DECL_OVERRIDE;
+ void setCurrentColor(const QColor&) override;
+ QColor currentColor() const override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.h b/src/plugins/platforms/cocoa/qcocoacursor.h
index d1586660a4..58b9ef2151 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.h
+++ b/src/plugins/platforms/cocoa/qcocoacursor.h
@@ -53,9 +53,9 @@ public:
QCocoaCursor();
~QCocoaCursor();
- void changeCursor(QCursor *cursor, QWindow *window) Q_DECL_OVERRIDE;
- QPoint pos() const Q_DECL_OVERRIDE;
- void setPos(const QPoint &position) Q_DECL_OVERRIDE;
+ void changeCursor(QCursor *cursor, QWindow *window) override;
+ QPoint pos() const override;
+ void setPos(const QPoint &position) override;
private:
QHash<Qt::CursorShape, NSCursor *> m_cursors;
NSCursor *convertCursor(QCursor *cursor);
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index 99a136d384..c021128e4c 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -39,6 +39,7 @@
#include "qcocoacursor.h"
#include "qcocoawindow.h"
+#include "qcocoascreen.h"
#include "qcocoahelpers.h"
#include <QtGui/private/qcoregraphics_p.h>
@@ -70,7 +71,7 @@ void QCocoaCursor::changeCursor(QCursor *cursor, QWindow *window)
QPoint QCocoaCursor::pos() const
{
- return qt_mac_flipPoint([NSEvent mouseLocation]).toPoint();
+ return QCocoaScreen::mapFromNative([NSEvent mouseLocation]).toPoint();
}
void QCocoaCursor::setPos(const QPoint &position)
@@ -86,7 +87,7 @@ void QCocoaCursor::setPos(const QPoint &position)
NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
{
- if (cursor == Q_NULLPTR)
+ if (cursor == nullptr)
return 0;
const Qt::CursorShape newShape = cursor->shape();
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.h b/src/plugins/platforms/cocoa/qcocoadrag.h
index 9ebb090989..dc0cc17dfb 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.h
+++ b/src/plugins/platforms/cocoa/qcocoadrag.h
@@ -55,11 +55,11 @@ public:
QCocoaDrag();
~QCocoaDrag();
- QMimeData *platformDropData() Q_DECL_OVERRIDE;
- Qt::DropAction drag(QDrag *m_drag) Q_DECL_OVERRIDE;
+ QMimeData *dragMimeData();
+ Qt::DropAction drag(QDrag *m_drag) override;
Qt::DropAction defaultAction(Qt::DropActions possibleActions,
- Qt::KeyboardModifiers modifiers) const Q_DECL_OVERRIDE;
+ Qt::KeyboardModifiers modifiers) const override;
/**
* to meet NSView dragImage:at guarantees, we need to record the original
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm
index c71e80d191..e1f36b47a1 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.mm
+++ b/src/plugins/platforms/cocoa/qcocoadrag.mm
@@ -68,7 +68,7 @@ void QCocoaDrag::setLastMouseEvent(NSEvent *event, NSView *view)
m_lastView = view;
}
-QMimeData *QCocoaDrag::platformDropData()
+QMimeData *QCocoaDrag::dragMimeData()
{
if (m_drag)
return m_drag->mimeData();
@@ -188,7 +188,7 @@ QPixmap QCocoaDrag::dragPixmap(QDrag *drag, QPoint &hotSpot) const
if (s.length() > dragImageMaxChars)
s = s.left(dragImageMaxChars -3) + QChar(0x2026);
if (!s.isEmpty()) {
- const int width = fm.width(s);
+ const int width = fm.horizontalAdvance(s);
const int height = fm.height();
if (width > 0 && height > 0) {
qreal dpr = 1.0;
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index 70887c41c9..2ffc1395ba 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -177,8 +177,6 @@ public:
void maybeCancelWaitForMoreEvents();
void ensureNSAppInitialized();
- void removeQueuedUserInputEvents(int nsWinNumber);
-
QCFSocketNotifier cfSocketNotifier;
QList<void *> queuedUserInputEvents; // NSEvent *
CFRunLoopSourceRef postedEventsSource;
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index b22f1b1f54..bf9ba4eccf 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -86,7 +86,6 @@
#include <qdebug.h>
#include <AppKit/AppKit.h>
-#include <Carbon/Carbon.h>
QT_BEGIN_NAMESPACE
@@ -285,7 +284,7 @@ bool QCocoaEventDispatcher::hasPendingEvents()
{
extern uint qGlobalPostedEventsCount();
extern bool qt_is_gui_used; //qapplication.cpp
- return qGlobalPostedEventsCount() || (qt_is_gui_used && GetNumEventsInQueue(GetMainEventQueue()));
+ return qGlobalPostedEventsCount() || (qt_is_gui_used && !CFRunLoopIsWaiting(CFRunLoopGetMain()));
}
static bool IsMouseOrKeyEvent( NSEvent* event )
@@ -900,21 +899,6 @@ void QCocoaEventDispatcherPrivate::processPostedEvents()
}
}
-void QCocoaEventDispatcherPrivate::removeQueuedUserInputEvents(int nsWinNumber)
-{
- if (nsWinNumber) {
- int eventIndex = queuedUserInputEvents.size();
-
- while (--eventIndex >= 0) {
- NSEvent * nsevent = static_cast<NSEvent *>(queuedUserInputEvents.at(eventIndex));
- if ([nsevent windowNumber] == nsWinNumber) {
- queuedUserInputEvents.removeAt(eventIndex);
- [nsevent release];
- }
- }
- }
-}
-
void QCocoaEventDispatcherPrivate::firstLoopEntry(CFRunLoopObserverRef ref,
CFRunLoopActivity activity,
void *info)
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h
index f5ba1dc22e..2ddda14289 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h
@@ -59,19 +59,19 @@ public:
QCocoaFileDialogHelper();
virtual ~QCocoaFileDialogHelper();
- void exec() Q_DECL_OVERRIDE;
+ void exec() override;
- bool defaultNameFilterDisables() const Q_DECL_OVERRIDE;
+ bool defaultNameFilterDisables() const override;
- bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) Q_DECL_OVERRIDE;
- void hide() Q_DECL_OVERRIDE;
- void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE;
- QUrl directory() const Q_DECL_OVERRIDE;
- void selectFile(const QUrl &filename) Q_DECL_OVERRIDE;
- QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE;
- void setFilter() Q_DECL_OVERRIDE;
- void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE;
- QString selectedNameFilter() const Q_DECL_OVERRIDE;
+ bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override;
+ void hide() override;
+ void setDirectory(const QUrl &directory) override;
+ QUrl directory() const override;
+ void selectFile(const QUrl &filename) override;
+ QList<QUrl> selectedFiles() const override;
+ void setFilter() override;
+ void selectNameFilter(const QString &filter) override;
+ QString selectedNameFilter() const override;
public:
bool showCocoaFilePanel(Qt::WindowModality windowModality, QWindow *parent);
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index c1c7903766..94f2125bad 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -63,7 +63,8 @@
#include <qsysinfo.h>
#include <qoperatingsystemversion.h>
#include <qglobal.h>
-#include <QDir>
+#include <qdir.h>
+#include <qregularexpression.h>
#include <qpa/qplatformnativeinterface.h>
@@ -161,11 +162,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate);
// resetting our mCurrentDir, set the delegate
// here to make sure it gets the correct value.
[mSavePanel setDelegate:self];
-
-#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_11)
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXElCapitan)
- mOpenPanel.accessoryViewDisclosed = YES;
-#endif
+ mOpenPanel.accessoryViewDisclosed = YES;
if (mOptions->isLabelExplicitlySet(QFileDialogOptions::Accept))
[mSavePanel setPrompt:[self strip:options->labelText(QFileDialogOptions::Accept)]];
@@ -197,7 +194,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate);
static QString strippedText(QString s)
{
- s.remove( QString::fromLatin1("...") );
+ s.remove(QLatin1String("..."));
return QPlatformTheme::removeMnemonics(s).trimmed();
}
@@ -231,7 +228,7 @@ static QString strippedText(QString s)
[mOpenPanel beginWithCompletionHandler:^(NSInteger result){
mReturnCode = result;
if (mHelper)
- mHelper->QNSOpenSavePanelDelegate_panelClosed(result == NSOKButton);
+ mHelper->QNSOpenSavePanelDelegate_panelClosed(result == NSModalResponseOK);
}];
}
}
@@ -260,12 +257,12 @@ static QString strippedText(QString s)
QCocoaMenuBar::resetKnownMenuItemsToQt();
QAbstractEventDispatcher::instance()->interrupt();
- return (mReturnCode == NSOKButton);
+ return (mReturnCode == NSModalResponseOK);
}
- (QPlatformDialogHelper::DialogCode)dialogResultCode
{
- return (mReturnCode == NSOKButton) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected;
+ return (mReturnCode == NSModalResponseOK) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected;
}
- (void)showWindowModalSheet:(QWindow *)parent
@@ -286,7 +283,7 @@ static QString strippedText(QString s)
[mSavePanel beginSheetModalForWindow:nsparent completionHandler:^(NSInteger result){
mReturnCode = result;
if (mHelper)
- mHelper->QNSOpenSavePanelDelegate_panelClosed(result == NSOKButton);
+ mHelper->QNSOpenSavePanelDelegate_panelClosed(result == NSModalResponseOK);
}];
}
@@ -513,9 +510,10 @@ static QString strippedText(QString s)
- (QString)removeExtensions:(const QString &)filter
{
- QRegExp regExp(QString::fromLatin1(QPlatformFileDialogHelper::filterRegExp));
- if (regExp.indexIn(filter) != -1)
- return regExp.cap(1).trimmed();
+ QRegularExpression regExp(QString::fromLatin1(QPlatformFileDialogHelper::filterRegExp));
+ QRegularExpressionMatch match = regExp.match(filter);
+ if (match.hasMatch())
+ return match.captured(1).trimmed();
return filter;
}
diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h
index c3fad7cfd6..14f12f2d76 100644
--- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h
+++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h
@@ -54,13 +54,13 @@ public:
QCocoaFontDialogHelper();
~QCocoaFontDialogHelper();
- void exec() Q_DECL_OVERRIDE;
+ void exec() override;
- bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) Q_DECL_OVERRIDE;
- void hide() Q_DECL_OVERRIDE;
+ bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override;
+ void hide() override;
- void setCurrentFont(const QFont &) Q_DECL_OVERRIDE;
- QFont currentFont() const Q_DECL_OVERRIDE;
+ void setCurrentFont(const QFont &) override;
+ QFont currentFont() const override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h
index 1a66cec0e3..0530aa8201 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.h
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h
@@ -55,22 +55,22 @@ public:
QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, const QVariant &nativeHandle);
~QCocoaGLContext();
- QSurfaceFormat format() const Q_DECL_OVERRIDE;
+ QSurfaceFormat format() const override;
- void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE;
+ void swapBuffers(QPlatformSurface *surface) override;
- bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE;
- void doneCurrent() Q_DECL_OVERRIDE;
+ bool makeCurrent(QPlatformSurface *surface) override;
+ void doneCurrent() override;
- QFunctionPointer getProcAddress(const char *procName) Q_DECL_OVERRIDE;
+ QFunctionPointer getProcAddress(const char *procName) override;
void update();
static NSOpenGLPixelFormat *createNSOpenGLPixelFormat(const QSurfaceFormat &format);
NSOpenGLContext *nsOpenGLContext() const;
- bool isSharing() const Q_DECL_OVERRIDE;
- bool isValid() const Q_DECL_OVERRIDE;
+ bool isSharing() const override;
+ bool isValid() const override;
void windowWasHidden();
@@ -84,6 +84,7 @@ private:
NSOpenGLContext *m_shareContext;
QSurfaceFormat m_format;
QPointer<QWindow> m_currentWindow;
+ bool m_didCheckForSoftwareContext;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index 9e688f4d1b..b656025ec7 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -42,7 +42,6 @@
#include "qcocoahelpers.h"
#include <qdebug.h>
#include <QtCore/private/qcore_mac_p.h>
-#include <QtCglSupport/private/cglconvenience_p.h>
#include <QtPlatformHeaders/qcocoanativecontext.h>
#include <dlfcn.h>
@@ -122,7 +121,8 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo
const QVariant &nativeHandle)
: m_context(nil),
m_shareContext(nil),
- m_format(format)
+ m_format(format),
+ m_didCheckForSoftwareContext(false)
{
if (!nativeHandle.isNull()) {
if (!nativeHandle.canConvert<QCocoaNativeContext>()) {
@@ -153,9 +153,32 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo
QMacAutoReleasePool pool; // For the SG Canvas render thread
- // create native context for the requested pixel format and share
- NSOpenGLPixelFormat *pixelFormat = static_cast <NSOpenGLPixelFormat *>(qcgl_createNSOpenGLPixelFormat(m_format));
m_shareContext = share ? static_cast<QCocoaGLContext *>(share)->nsOpenGLContext() : nil;
+
+ if (m_shareContext) {
+ // Allow sharing between 3.2 Core and 4.1 Core profile versions in
+ // cases where NSOpenGLContext creates a 4.1 context where a 3.2
+ // context was requested. Due to the semantics of QSurfaceFormat
+ // this 4.1 version can find its way onto the format for the new
+ // context, even though it was at no point requested by the user.
+ GLint shareContextRequestedProfile;
+ [m_shareContext.pixelFormat getValues:&shareContextRequestedProfile
+ forAttribute:NSOpenGLPFAOpenGLProfile forVirtualScreen:0];
+ auto shareContextActualProfile = share->format().version();
+
+ if (shareContextRequestedProfile == NSOpenGLProfileVersion3_2Core &&
+ shareContextActualProfile >= qMakePair(4, 1)) {
+
+ // There is a mismatch, downgrade requested format to make the
+ // NSOpenGLPFAOpenGLProfile attributes match. (NSOpenGLContext will
+ // fail to create a new context if there is a mismatch).
+ if (m_format.version() >= qMakePair(4, 1))
+ m_format.setVersion(3, 2);
+ }
+ }
+
+ // create native context for the requested pixel format and share
+ NSOpenGLPixelFormat *pixelFormat = createNSOpenGLPixelFormat(m_format);
m_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:m_shareContext];
// retry without sharing on context creation failure.
@@ -202,7 +225,6 @@ QVariant QCocoaGLContext::nativeHandle() const
return QVariant::fromValue<QCocoaNativeContext>(QCocoaNativeContext(m_context));
}
-// Match up with createNSOpenGLPixelFormat!
QSurfaceFormat QCocoaGLContext::format() const
{
return m_format;
@@ -220,6 +242,9 @@ void QCocoaGLContext::windowWasHidden()
void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
{
+ if (surface->surface()->surfaceClass() == QSurface::Offscreen)
+ return; // Nothing to do
+
QWindow *window = static_cast<QCocoaWindow *>(surface)->window();
setActiveWindow(window);
@@ -231,11 +256,29 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
Q_ASSERT(surface->surface()->supportsOpenGL());
QMacAutoReleasePool pool;
+ [m_context makeCurrentContext];
+
+ if (surface->surface()->surfaceClass() == QSurface::Offscreen)
+ return true;
QWindow *window = static_cast<QCocoaWindow *>(surface)->window();
setActiveWindow(window);
- [m_context makeCurrentContext];
+ // Disable high-resolution surfaces when using the software renderer, which has the
+ // problem that the system silently falls back to a to using a low-resolution buffer
+ // when a high-resolution buffer is requested. This is not detectable using the NSWindow
+ // convertSizeToBacking and backingScaleFactor APIs. A typical result of this is that Qt
+ // will display a quarter of the window content when running in a virtual machine.
+ if (!m_didCheckForSoftwareContext) {
+ m_didCheckForSoftwareContext = true;
+
+ const GLubyte* renderer = glGetString(GL_RENDERER);
+ if (qstrcmp((const char *)renderer, "Apple Software Renderer") == 0) {
+ NSView *view = static_cast<QCocoaWindow *>(surface)->m_view;
+ [view setWantsBestResolutionOpenGLSurface:NO];
+ }
+ }
+
update();
return true;
}
@@ -362,7 +405,64 @@ void QCocoaGLContext::update()
NSOpenGLPixelFormat *QCocoaGLContext::createNSOpenGLPixelFormat(const QSurfaceFormat &format)
{
- return static_cast<NSOpenGLPixelFormat *>(qcgl_createNSOpenGLPixelFormat(format));
+ QVector<NSOpenGLPixelFormatAttribute> attrs;
+
+ if (format.swapBehavior() == QSurfaceFormat::DoubleBuffer
+ || format.swapBehavior() == QSurfaceFormat::DefaultSwapBehavior)
+ attrs.append(NSOpenGLPFADoubleBuffer);
+ else if (format.swapBehavior() == QSurfaceFormat::TripleBuffer)
+ attrs.append(NSOpenGLPFATripleBuffer);
+
+
+ // Select OpenGL profile
+ attrs << NSOpenGLPFAOpenGLProfile;
+ if (format.profile() == QSurfaceFormat::CoreProfile) {
+ if (format.version() >= qMakePair(4, 1))
+ attrs << NSOpenGLProfileVersion4_1Core;
+ else if (format.version() >= qMakePair(3, 2))
+ attrs << NSOpenGLProfileVersion3_2Core;
+ else
+ attrs << NSOpenGLProfileVersionLegacy;
+ } else {
+ attrs << NSOpenGLProfileVersionLegacy;
+ }
+
+ if (format.depthBufferSize() > 0)
+ attrs << NSOpenGLPFADepthSize << format.depthBufferSize();
+ if (format.stencilBufferSize() > 0)
+ attrs << NSOpenGLPFAStencilSize << format.stencilBufferSize();
+ if (format.alphaBufferSize() > 0)
+ attrs << NSOpenGLPFAAlphaSize << format.alphaBufferSize();
+ if ((format.redBufferSize() > 0) &&
+ (format.greenBufferSize() > 0) &&
+ (format.blueBufferSize() > 0)) {
+ const int colorSize = format.redBufferSize() +
+ format.greenBufferSize() +
+ format.blueBufferSize();
+ attrs << NSOpenGLPFAColorSize << colorSize << NSOpenGLPFAMinimumPolicy;
+ }
+
+ if (format.samples() > 0) {
+ attrs << NSOpenGLPFAMultisample
+ << NSOpenGLPFASampleBuffers << (NSOpenGLPixelFormatAttribute) 1
+ << NSOpenGLPFASamples << (NSOpenGLPixelFormatAttribute) format.samples();
+ }
+
+ if (format.stereo())
+ attrs << NSOpenGLPFAStereo;
+
+ attrs << NSOpenGLPFAAllowOfflineRenderers;
+
+ QByteArray useLayer = qgetenv("QT_MAC_WANTS_LAYER");
+ if (!useLayer.isEmpty() && useLayer.toInt() > 0) {
+ // Disable the software rendering fallback. This makes compositing
+ // OpenGL and raster NSViews using Core Animation layers possible.
+ attrs << NSOpenGLPFANoRecovery;
+ }
+
+ attrs << 0;
+
+ return [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs.constData()];
}
NSOpenGLContext *QCocoaGLContext::nsOpenGLContext() const
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 0cf9cc0aff..84632c1487 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -55,11 +55,16 @@
#include <QtGui/qpalette.h>
#include <QtGui/qscreen.h>
+#include <objc/runtime.h>
+#include <objc/message.h>
+
Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSView));
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaWindow)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaDrawing)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaMouse)
class QPixmap;
class QString;
@@ -82,13 +87,8 @@ QT_MANGLE_NAMESPACE(QNSView) *qnsview_cast(NSView *view);
void qt_mac_transformProccessToForegroundApplication();
QString qt_mac_applicationName();
-int qt_mac_flipYCoordinate(int y);
-qreal qt_mac_flipYCoordinate(qreal y);
-QPointF qt_mac_flipPoint(const NSPoint &p);
-NSPoint qt_mac_flipPoint(const QPoint &p);
-NSPoint qt_mac_flipPoint(const QPointF &p);
-
-NSRect qt_mac_flipRect(const QRect &rect);
+QPointF qt_mac_flip(const QPointF &pos, const QRectF &reference);
+QRectF qt_mac_flip(const QRectF &rect, const QRectF &reference);
Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum);
@@ -191,5 +191,144 @@ QT_END_NAMESPACE
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSPanelContentsWrapper);
+// -------------------------------------------------------------------------
+
+// QAppleRefCounted expects the retain function to return the object
+io_object_t q_IOObjectRetain(io_object_t obj);
+// QAppleRefCounted expects the release function to return void
+void q_IOObjectRelease(io_object_t obj);
+
+template <typename T>
+class QIOType : public QAppleRefCounted<T, io_object_t, q_IOObjectRetain, q_IOObjectRelease>
+{
+ using QAppleRefCounted<T, io_object_t, q_IOObjectRetain, q_IOObjectRelease>::QAppleRefCounted;
+};
+
+// -------------------------------------------------------------------------
+
+// Depending on the ABI of the platform, we may need to use objc_msgSendSuper_stret:
+// - http://www.sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html
+// - https://lists.apple.com/archives/cocoa-dev/2008/Feb/msg02338.html
+template <typename T>
+struct objc_msgsend_requires_stret
+{ static const bool value =
+#if defined(Q_PROCESSOR_X86)
+ // Any return value larger than two registers on i386/x86_64
+ sizeof(T) > sizeof(void*) * 2;
+#elif defined(Q_PROCESSOR_ARM_32)
+ // Any return value larger than a single register on arm
+ sizeof(T) > sizeof(void*);
+#elif defined(Q_PROCESSOR_ARM_64)
+ // Stret not used on arm64
+ false;
+#endif
+};
+
+template <>
+struct objc_msgsend_requires_stret<void>
+{ static const bool value = false; };
+
+template <typename ReturnType, typename... Args>
+ReturnType qt_msgSendSuper(id receiver, SEL selector, Args... args)
+{
+ static_assert(!objc_msgsend_requires_stret<ReturnType>::value,
+ "The given return type requires stret on this platform");
+
+ typedef ReturnType (*SuperFn)(objc_super *, SEL, Args...);
+ SuperFn superFn = reinterpret_cast<SuperFn>(objc_msgSendSuper);
+ objc_super sup = { receiver, [receiver superclass] };
+ return superFn(&sup, selector, args...);
+}
+
+template <typename ReturnType, typename... Args>
+ReturnType qt_msgSendSuper_stret(id receiver, SEL selector, Args... args)
+{
+ static_assert(objc_msgsend_requires_stret<ReturnType>::value,
+ "The given return type does not use stret on this platform");
+
+ typedef void (*SuperStretFn)(ReturnType *, objc_super *, SEL, Args...);
+ SuperStretFn superStretFn = reinterpret_cast<SuperStretFn>(objc_msgSendSuper_stret);
+
+ objc_super sup = { receiver, [receiver superclass] };
+ ReturnType ret;
+ superStretFn(&ret, &sup, selector, args...);
+ return ret;
+}
+
+template<typename... Args>
+class QSendSuperHelper {
+public:
+ QSendSuperHelper(id receiver, SEL sel, Args... args)
+ : m_receiver(receiver), m_selector(sel), m_args(std::make_tuple(args...)), m_sent(false)
+ {
+ }
+
+ ~QSendSuperHelper()
+ {
+ if (!m_sent)
+ msgSendSuper<void>(m_args);
+ }
+
+ template <typename ReturnType>
+ operator ReturnType()
+ {
+#if defined(QT_DEBUG)
+ Method method = class_getInstanceMethod(object_getClass(m_receiver), m_selector);
+ char returnTypeEncoding[256];
+ method_getReturnType(method, returnTypeEncoding, sizeof(returnTypeEncoding));
+ NSUInteger alignedReturnTypeSize = 0;
+ NSGetSizeAndAlignment(returnTypeEncoding, nullptr, &alignedReturnTypeSize);
+ Q_ASSERT(alignedReturnTypeSize == sizeof(ReturnType));
+#endif
+ m_sent = true;
+ return msgSendSuper<ReturnType>(m_args);
+ }
+
+private:
+ template <std::size_t... Ts>
+ struct index {};
+
+ template <std::size_t N, std::size_t... Ts>
+ struct gen_seq : gen_seq<N - 1, N - 1, Ts...> {};
+
+ template <std::size_t... Ts>
+ struct gen_seq<0, Ts...> : index<Ts...> {};
+
+ template <typename ReturnType, bool V>
+ using if_requires_stret = typename std::enable_if<objc_msgsend_requires_stret<ReturnType>::value == V, ReturnType>::type;
+
+ template <typename ReturnType, std::size_t... Is>
+ if_requires_stret<ReturnType, false> msgSendSuper(std::tuple<Args...>& args, index<Is...>)
+ {
+ return qt_msgSendSuper<ReturnType>(m_receiver, m_selector, std::get<Is>(args)...);
+ }
+
+ template <typename ReturnType, std::size_t... Is>
+ if_requires_stret<ReturnType, true> msgSendSuper(std::tuple<Args...>& args, index<Is...>)
+ {
+ return qt_msgSendSuper_stret<ReturnType>(m_receiver, m_selector, std::get<Is>(args)...);
+ }
+
+ template <typename ReturnType>
+ ReturnType msgSendSuper(std::tuple<Args...>& args)
+ {
+ return msgSendSuper<ReturnType>(args, gen_seq<sizeof...(Args)>{});
+ }
+
+ id m_receiver;
+ SEL m_selector;
+ std::tuple<Args...> m_args;
+ bool m_sent;
+};
+
+template<typename... Args>
+QSendSuperHelper<Args...> qt_objcDynamicSuperHelper(id receiver, SEL selector, Args... args)
+{
+ return QSendSuperHelper<Args...>(receiver, selector, args...);
+}
+
+// Same as calling super, but the super_class field resolved at runtime instead of compile time
+#define qt_objcDynamicSuper(...) qt_objcDynamicSuperHelper(self, _cmd, ##__VA_ARGS__)
+
#endif //QCOCOAHELPERS_H
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index c3efe158c7..b729c7f4c0 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -55,11 +55,11 @@
#include <algorithm>
-#include <Carbon/Carbon.h>
-
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaCocoaWindow, "qt.qpa.cocoa.window");
+Q_LOGGING_CATEGORY(lcQpaCocoaDrawing, "qt.qpa.cocoa.drawing");
+Q_LOGGING_CATEGORY(lcQpaCocoaMouse, "qt.qpa.cocoa.mouse");
//
// Conversion Functions
@@ -234,50 +234,37 @@ QString qt_mac_applicationName()
return appName;
}
-int qt_mac_primaryScreenHeight()
-{
- 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 and is designated the primary screen.
- NSRect screenFrame = [[screens objectAtIndex: 0] frame];
- return screenFrame.size.height;
- }
- return 0;
-}
+// -------------------------------------------------------------------------
-int qt_mac_flipYCoordinate(int y)
-{
- return qt_mac_primaryScreenHeight() - y;
-}
+/*!
+ \fn QPointF qt_mac_flip(const QPointF &pos, const QRectF &reference)
+ \fn QRectF qt_mac_flip(const QRectF &rect, const QRectF &reference)
-qreal qt_mac_flipYCoordinate(qreal y)
-{
- return qt_mac_primaryScreenHeight() - y;
-}
+ Flips the Y coordinate of the point/rect between quadrant I and IV.
-QPointF qt_mac_flipPoint(const NSPoint &p)
-{
- return QPointF(p.x, qt_mac_flipYCoordinate(p.y));
-}
+ The native coordinate system on macOS uses quadrant I, with origin
+ in bottom left, and Qt uses quadrant IV, with origin in top left.
-NSPoint qt_mac_flipPoint(const QPoint &p)
-{
- return NSMakePoint(p.x(), qt_mac_flipYCoordinate(p.y()));
-}
+ By flipping the Y coordinate, we can map the point/rect between
+ the two coordinate systems.
-NSPoint qt_mac_flipPoint(const QPointF &p)
+ The flip is always in relation to a reference rectangle, e.g.
+ the frame of the parent view, or the screen geometry. In the
+ latter case the specialized QCocoaScreen::mapFrom/To functions
+ should be used instead.
+*/
+QPointF qt_mac_flip(const QPointF &pos, const QRectF &reference)
{
- return NSMakePoint(p.x(), qt_mac_flipYCoordinate(p.y()));
+ return QPointF(pos.x(), reference.height() - pos.y());
}
-NSRect qt_mac_flipRect(const QRect &rect)
+QRectF qt_mac_flip(const QRectF &rect, const QRectF &reference)
{
- int flippedY = qt_mac_flipYCoordinate(rect.y() + rect.height());
- return NSMakeRect(rect.x(), flippedY, rect.width(), rect.height());
+ return QRectF(qt_mac_flip(rect.bottomLeft(), reference), rect.size());
}
+// -------------------------------------------------------------------------
+
Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
{
if (buttonNum >= 0 && buttonNum <= 31)
@@ -407,6 +394,22 @@ QT_END_NAMESPACE
self.panelContents.needsDisplay = YES;
self.needsDisplay = YES;
+ [super layout];
+}
+
+// -------------------------------------------------------------------------
+
+io_object_t q_IOObjectRetain(io_object_t obj)
+{
+ kern_return_t ret = IOObjectRetain(obj);
+ Q_ASSERT(!ret);
+ return obj;
+}
+
+void q_IOObjectRelease(io_object_t obj)
+{
+ kern_return_t ret = IOObjectRelease(obj);
+ Q_ASSERT(!ret);
}
@end
diff --git a/src/plugins/platforms/cocoa/qcocoainputcontext.h b/src/plugins/platforms/cocoa/qcocoainputcontext.h
index a248ca0d8d..7190ba0de8 100644
--- a/src/plugins/platforms/cocoa/qcocoainputcontext.h
+++ b/src/plugins/platforms/cocoa/qcocoainputcontext.h
@@ -53,11 +53,11 @@ public:
explicit QCocoaInputContext();
~QCocoaInputContext();
- bool isValid() const Q_DECL_OVERRIDE { return true; }
+ bool isValid() const override { return true; }
- void reset() Q_DECL_OVERRIDE;
+ void reset() override;
- QLocale locale() const Q_DECL_OVERRIDE { return m_locale; }
+ QLocale locale() const override { return m_locale; }
void updateLocale();
private Q_SLOTS:
diff --git a/src/plugins/platforms/cocoa/qcocoainputcontext.mm b/src/plugins/platforms/cocoa/qcocoainputcontext.mm
index 9221099a57..d0baea5b36 100644
--- a/src/plugins/platforms/cocoa/qcocoainputcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoainputcontext.mm
@@ -129,6 +129,8 @@ void QCocoaInputContext::focusObjectChanged(QObject *focusObject)
return;
QCocoaWindow *window = static_cast<QCocoaWindow *>(mWindow->handle());
+ if (!window)
+ return;
QNSView *view = qnsview_cast(window->view());
if (!view)
return;
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index ecdd20c4dc..301771fd53 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -58,60 +58,11 @@
QT_BEGIN_NAMESPACE
-class QCocoaScreen : public QPlatformScreen
-{
-public:
- QCocoaScreen(int screenIndex);
- ~QCocoaScreen();
-
- // ----------------------------------------------------
- // Virtual methods overridden from QPlatformScreen
- QPixmap grabWindow(WId window, int x, int y, int width, int height) const Q_DECL_OVERRIDE;
- QRect geometry() const Q_DECL_OVERRIDE { return m_geometry; }
- QRect availableGeometry() const Q_DECL_OVERRIDE { return m_availableGeometry; }
- int depth() const Q_DECL_OVERRIDE { return m_depth; }
- QImage::Format format() const Q_DECL_OVERRIDE { return m_format; }
- qreal devicePixelRatio() const Q_DECL_OVERRIDE;
- QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_physicalSize; }
- QDpi logicalDpi() const Q_DECL_OVERRIDE { return m_logicalDpi; }
- qreal refreshRate() const Q_DECL_OVERRIDE { return m_refreshRate; }
- QString name() const Q_DECL_OVERRIDE { return m_name; }
- QPlatformCursor *cursor() const Q_DECL_OVERRIDE { return m_cursor; }
- QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE;
- QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE { return m_siblings; }
- QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const Q_DECL_OVERRIDE;
-
- // ----------------------------------------------------
- // Additional methods
- void setVirtualSiblings(const QList<QPlatformScreen *> &siblings) { m_siblings = siblings; }
- NSScreen *nativeScreen() const;
- void updateGeometry();
-
- QPointF mapToNative(const QPointF &pos) const { return flipCoordinate(pos); }
- QRectF mapToNative(const QRectF &rect) const { return flipCoordinate(rect); }
- QPointF mapFromNative(const QPointF &pos) const { return flipCoordinate(pos); }
- QRectF mapFromNative(const QRectF &rect) const { return flipCoordinate(rect); }
-
-private:
- QPointF flipCoordinate(const QPointF &pos) const;
- QRectF flipCoordinate(const QRectF &rect) const;
+class QCocoaScreen;
-public:
- int m_screenIndex;
- QRect m_geometry;
- QRect m_availableGeometry;
- QDpi m_logicalDpi;
- qreal m_refreshRate;
- int m_depth;
- QString m_name;
- QImage::Format m_format;
- QSizeF m_physicalSize;
- QCocoaCursor *m_cursor;
- QList<QPlatformScreen *> m_siblings;
-};
-
-class QCocoaIntegration : public QPlatformIntegration
+class QCocoaIntegration : public QObject, public QPlatformIntegration
{
+ Q_OBJECT
public:
enum Option {
UseFreeTypeFontEngine = 0x1
@@ -124,34 +75,35 @@ public:
static QCocoaIntegration *instance();
Options options() const;
- bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
- QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE;
- QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const Q_DECL_OVERRIDE;
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
+ QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override;
+ QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
#ifndef QT_NO_OPENGL
- QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE;
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
#endif
- QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const Q_DECL_OVERRIDE;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const override;
- QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE;
+ QAbstractEventDispatcher *createEventDispatcher() const override;
- QCoreTextFontDatabase *fontDatabase() const Q_DECL_OVERRIDE;
- QCocoaNativeInterface *nativeInterface() const Q_DECL_OVERRIDE;
- QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE;
+ QCoreTextFontDatabase *fontDatabase() const override;
+ QCocoaNativeInterface *nativeInterface() const override;
+ QPlatformInputContext *inputContext() const override;
#ifndef QT_NO_ACCESSIBILITY
- QCocoaAccessibility *accessibility() const Q_DECL_OVERRIDE;
+ QCocoaAccessibility *accessibility() const override;
#endif
#ifndef QT_NO_CLIPBOARD
- QCocoaClipboard *clipboard() const Q_DECL_OVERRIDE;
+ QCocoaClipboard *clipboard() const override;
#endif
- QCocoaDrag *drag() const Q_DECL_OVERRIDE;
+ QCocoaDrag *drag() const override;
- QStringList themeNames() const Q_DECL_OVERRIDE;
- QPlatformTheme *createPlatformTheme(const QString &name) const Q_DECL_OVERRIDE;
- QCocoaServices *services() const Q_DECL_OVERRIDE;
- QVariant styleHint(StyleHint hint) const Q_DECL_OVERRIDE;
+ QStringList themeNames() const override;
+ QPlatformTheme *createPlatformTheme(const QString &name) const override;
+ QCocoaServices *services() const override;
+ QVariant styleHint(StyleHint hint) const override;
- Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE;
- QList<int> possibleKeys(const QKeyEvent *event) const Q_DECL_OVERRIDE;
+ Qt::KeyboardModifiers queryKeyboardModifiers() const override;
+ QList<int> possibleKeys(const QKeyEvent *event) const override;
void updateScreens();
QCocoaScreen *screenForNSScreen(NSScreen *nsScreen);
@@ -165,9 +117,12 @@ public:
QCocoaWindow *activePopupWindow() const;
QList<QCocoaWindow *> *popupWindowStack();
- void setApplicationIcon(const QIcon &icon) const Q_DECL_OVERRIDE;
+ void setApplicationIcon(const QIcon &icon) const override;
+
+ void beep() const override;
- void beep() const Q_DECL_OVERRIDE;
+private Q_SLOTS:
+ void focusWindowChanged(QWindow *);
private:
static QCocoaIntegration *mInstance;
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index bac49cfad9..55b3805df3 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -51,10 +51,12 @@
#include "qcocoainputcontext.h"
#include "qcocoamimetypes.h"
#include "qcocoaaccessibility.h"
+#include "qcocoascreen.h"
#include <qpa/qplatforminputcontextfactory_p.h>
#include <qpa/qplatformaccessibility.h>
#include <qpa/qplatforminputcontextfactory_p.h>
+#include <qpa/qplatformoffscreensurface.h>
#include <QtCore/qcoreapplication.h>
#include <QtGui/private/qcoregraphics_p.h>
@@ -78,221 +80,6 @@ QT_BEGIN_NAMESPACE
class QCoreTextFontEngine;
class QFontEngineFT;
-QCocoaScreen::QCocoaScreen(int screenIndex)
- : QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0)
-{
- updateGeometry();
- m_cursor = new QCocoaCursor;
-}
-
-QCocoaScreen::~QCocoaScreen()
-{
- delete m_cursor;
-}
-
-NSScreen *QCocoaScreen::nativeScreen() const
-{
- NSArray *screens = [NSScreen screens];
-
- // Stale reference, screen configuration has changed
- if (m_screenIndex < 0 || (NSUInteger)m_screenIndex >= [screens count])
- return nil;
-
- return [screens objectAtIndex:m_screenIndex];
-}
-
-/*!
- Flips the Y coordinate of the point between quadrant I and IV.
-
- The native coordinate system on macOS uses quadrant I, with origin
- in bottom left, and Qt uses quadrant IV, with origin in top left.
-
- By flippig the Y coordinate, we can map the position between the
- two coordinate systems.
-*/
-QPointF QCocoaScreen::flipCoordinate(const QPointF &pos) const
-{
- return QPointF(pos.x(), m_geometry.height() - pos.y());
-}
-
-/*!
- Flips the Y coordinate of the rectangle between quadrant I and IV.
-
- The native coordinate system on macOS uses quadrant I, with origin
- in bottom left, and Qt uses quadrant IV, with origin in top left.
-
- By flippig the Y coordinate, we can map the rectangle between the
- two coordinate systems.
-*/
-QRectF QCocoaScreen::flipCoordinate(const QRectF &rect) const
-{
- return QRectF(flipCoordinate(rect.topLeft() + QPoint(0, rect.height())), rect.size());
-}
-
-void QCocoaScreen::updateGeometry()
-{
- NSScreen *nsScreen = nativeScreen();
- if (!nsScreen)
- return;
-
- // At this point the geometry is in native coordinates, but the size
- // is correct, which we take advantage of next when we map the native
- // coordinates to the Qt coordinate system.
- m_geometry = QRectF::fromCGRect(NSRectToCGRect(nsScreen.frame)).toRect();
- m_availableGeometry = QRectF::fromCGRect(NSRectToCGRect(nsScreen.visibleFrame)).toRect();
-
- // The reference screen for the geometry is always the primary screen, but since
- // we may be in the process of creating and registering the primary screen, we
- // must special-case that and assign it direcly.
- QCocoaScreen *primaryScreen = (nsScreen == [[NSScreen screens] firstObject]) ?
- this : static_cast<QCocoaScreen*>(QGuiApplication::primaryScreen()->handle());
-
- m_geometry = primaryScreen->mapFromNative(m_geometry).toRect();
- m_availableGeometry = primaryScreen->mapFromNative(m_availableGeometry).toRect();
-
- m_format = QImage::Format_RGB32;
- m_depth = NSBitsPerPixelFromDepth([nsScreen depth]);
-
- NSDictionary *devDesc = [nsScreen deviceDescription];
- CGDirectDisplayID dpy = [[devDesc objectForKey:@"NSScreenNumber"] unsignedIntValue];
- CGSize size = CGDisplayScreenSize(dpy);
- m_physicalSize = QSizeF(size.width, size.height);
- m_logicalDpi.first = 72;
- m_logicalDpi.second = 72;
- CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(dpy);
- float refresh = CGDisplayModeGetRefreshRate(displayMode);
- CGDisplayModeRelease(displayMode);
- if (refresh > 0)
- m_refreshRate = refresh;
-
- // Get m_name (brand/model of the monitor)
- NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(dpy), kIODisplayOnlyPreferredName);
- NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
- if ([localizedNames count] > 0)
- m_name = QString::fromUtf8([[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] UTF8String]);
- [deviceInfo release];
-
- QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
- QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), m_logicalDpi.first, m_logicalDpi.second);
- QWindowSystemInterface::handleScreenRefreshRateChange(screen(), m_refreshRate);
-}
-
-qreal QCocoaScreen::devicePixelRatio() const
-{
- QMacAutoReleasePool pool;
- NSScreen *nsScreen = nativeScreen();
- return qreal(nsScreen ? [nsScreen backingScaleFactor] : 1.0);
-}
-
-QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingTypeHint() const
-{
- QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint();
- if (type == QPlatformScreen::Subpixel_None) {
- // Every OSX machine has RGB pixels unless a peculiar or rotated non-Apple screen is attached
- type = QPlatformScreen::Subpixel_RGB;
- }
- return type;
-}
-
-QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const
-{
- NSPoint screenPoint = qt_mac_flipPoint(point);
-
- // Search (hit test) for the top-level window. [NSWidow windowNumberAtPoint:
- // belowWindowWithWindowNumber] may return windows that are not interesting
- // to Qt. The search iterates until a suitable window or no window is found.
- NSInteger topWindowNumber = 0;
- QWindow *window = 0;
- do {
- // Get the top-most window, below any previously rejected window.
- topWindowNumber = [NSWindow windowNumberAtPoint:screenPoint
- belowWindowWithWindowNumber:topWindowNumber];
-
- // Continue the search if the window does not belong to this process.
- NSWindow *nsWindow = [NSApp windowWithWindowNumber:topWindowNumber];
- if (nsWindow == 0)
- continue;
-
- // Continue the search if the window does not belong to Qt.
- if (![nsWindow conformsToProtocol:@protocol(QNSWindowProtocol)])
- continue;
-
- id<QNSWindowProtocol> proto = static_cast<id<QNSWindowProtocol> >(nsWindow);
- QCocoaWindow *cocoaWindow = proto.helper.platformWindow;
- if (!cocoaWindow)
- continue;
- window = cocoaWindow->window();
-
- // Continue the search if the window is not a top-level window.
- if (!window->isTopLevel())
- continue;
-
- // Stop searching. The current window is the correct window.
- break;
- } while (topWindowNumber > 0);
-
- return window;
-}
-
-QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height) const
-{
- // TODO window should be handled
- Q_UNUSED(window)
-
- const int maxDisplays = 128; // 128 displays should be enough for everyone.
- CGDirectDisplayID displays[maxDisplays];
- CGDisplayCount displayCount;
- CGRect cgRect;
-
- if (width < 0 || height < 0) {
- // get all displays
- cgRect = CGRectInfinite;
- } else {
- cgRect = CGRectMake(x, y, width, height);
- }
- const CGDisplayErr err = CGGetDisplaysWithRect(cgRect, maxDisplays, displays, &displayCount);
-
- if (err && displayCount == 0)
- return QPixmap();
-
- // calculate pixmap size
- QSize windowSize(width, height);
- if (width < 0 || height < 0) {
- QRect windowRect;
- for (uint i = 0; i < displayCount; ++i) {
- const CGRect cgRect = CGDisplayBounds(displays[i]);
- QRect qRect(cgRect.origin.x, cgRect.origin.y, cgRect.size.width, cgRect.size.height);
- windowRect = windowRect.united(qRect);
- }
- if (width < 0)
- windowSize.setWidth(windowRect.width());
- if (height < 0)
- windowSize.setHeight(windowRect.height());
- }
-
- QPixmap windowPixmap(windowSize * devicePixelRatio());
- windowPixmap.fill(Qt::transparent);
-
- for (uint i = 0; i < displayCount; ++i) {
- const CGRect bounds = CGDisplayBounds(displays[i]);
- int w = (width < 0 ? bounds.size.width : width) * devicePixelRatio();
- int h = (height < 0 ? bounds.size.height : height) * devicePixelRatio();
- QRect displayRect = QRect(x, y, w, h);
- displayRect = displayRect.translated(qRound(-bounds.origin.x), qRound(-bounds.origin.y));
- QCFType<CGImageRef> image = CGDisplayCreateImageForRect(displays[i],
- CGRectMake(displayRect.x(), displayRect.y(), displayRect.width(), displayRect.height()));
- QPixmap pix(w, h);
- pix.fill(Qt::transparent);
- CGRect rect = CGRectMake(0, 0, w, h);
- QMacCGContext ctx(&pix);
- qt_mac_drawCGImage(ctx, &rect, image);
-
- QPainter painter(&windowPixmap);
- painter.drawPixmap(0, 0, pix);
- }
- return windowPixmap;
-}
-
static QCocoaIntegration::Options parseOptions(const QStringList &paramList)
{
QCocoaIntegration::Options options;
@@ -355,7 +142,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
// Move the application window to front to make it take focus, also when launching
// from the terminal. On 10.12+ this call has been moved to applicationDidFinishLauching
// to work around issues with loss of focus at startup.
- if (QSysInfo::macVersion() < QSysInfo::MV_10_12) {
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSSierra) {
// Ignoring other apps is necessary (we must ignore the terminal), but makes
// Qt apps play slightly less nice with other apps when lanching from Finder
// (See the activateIgnoringOtherApps docs.)
@@ -392,6 +179,9 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
QMacInternalPasteboardMime::initializeMimeTypes();
QCocoaMimeTypes::initializeMimeTypes();
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
+
+ connect(qGuiApp, &QGuiApplication::focusWindowChanged,
+ this, &QCocoaIntegration::focusWindowChanged);
}
QCocoaIntegration::~QCocoaIntegration()
@@ -435,6 +225,8 @@ QCocoaIntegration::Options QCocoaIntegration::options() const
return mOptions;
}
+Q_LOGGING_CATEGORY(lcCocoaScreen, "qt.qpa.cocoa.screens");
+
/*!
\brief Synchronizes the screen list, adds new screens, removes deleted ones
*/
@@ -474,9 +266,11 @@ void QCocoaIntegration::updateScreens()
if (screen) {
remainingScreens.remove(screen);
screen->updateGeometry();
+ qCDebug(lcCocoaScreen) << "Updated properties of" << screen;
} else {
screen = new QCocoaScreen(i);
mScreens.append(screen);
+ qCDebug(lcCocoaScreen) << "Adding" << screen;
screenAdded(screen);
}
siblings << screen;
@@ -493,6 +287,7 @@ void QCocoaIntegration::updateScreens()
mScreens.removeOne(screen);
// Prevent stale references to NSScreen during destroy
screen->m_screenIndex = -1;
+ qCDebug(lcCocoaScreen) << "Removing" << screen;
destroyScreen(screen);
}
}
@@ -545,6 +340,24 @@ QPlatformWindow *QCocoaIntegration::createForeignWindow(QWindow *window, WId nat
return new QCocoaWindow(window, nativeHandle);
}
+class QCocoaOffscreenSurface : public QPlatformOffscreenSurface
+{
+public:
+ QCocoaOffscreenSurface(QOffscreenSurface *offscreenSurface) : QPlatformOffscreenSurface(offscreenSurface) {}
+
+ QSurfaceFormat format() const override
+ {
+ Q_ASSERT(offscreenSurface());
+ return offscreenSurface()->requestedFormat();
+ }
+ bool isValid() const override { return true; }
+};
+
+QPlatformOffscreenSurface *QCocoaIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
+{
+ return new QCocoaOffscreenSurface(surface);
+}
+
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
@@ -700,4 +513,33 @@ void QCocoaIntegration::beep() const
NSBeep();
}
+void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow)
+{
+ // Don't revert icon just because we lost focus
+ if (!focusWindow)
+ return;
+
+ static bool hasDefaultApplicationIcon = [](){
+ NSImage *genericApplicationIcon = [[NSWorkspace sharedWorkspace]
+ iconForFileType:NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];
+ NSImage *applicationIcon = [NSImage imageNamed:NSImageNameApplicationIcon];
+
+ NSRect rect = NSMakeRect(0, 0, 32, 32);
+ return [applicationIcon CGImageForProposedRect:&rect context:nil hints:nil]
+ == [genericApplicationIcon CGImageForProposedRect:&rect context:nil hints:nil];
+ }();
+
+ // Don't let the window icon override an explicit application icon set in the Info.plist
+ if (!hasDefaultApplicationIcon)
+ return;
+
+ // Or an explicit application icon set on QGuiApplication
+ if (!qGuiApp->windowIcon().isNull())
+ return;
+
+ setApplicationIcon(focusWindow->icon());
+}
+
+#include "moc_qcocoaintegration.cpp"
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.h b/src/plugins/platforms/cocoa/qcocoakeymapper.h
index 4ba615efeb..a75e275077 100644
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.h
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.h
@@ -91,8 +91,6 @@ public:
private:
QCFType<TISInputSourceRef> currentInputSource;
- QLocale keyboardInputLocale;
- Qt::LayoutDirection keyboardInputDirection;
enum { NullMode, UnicodeMode, OtherMode } keyboard_mode;
union {
const UCKeyboardLayout *unicode;
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
index 1ef7f11011..80140505d1 100644
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
@@ -72,14 +72,6 @@ static const Qt::KeyboardModifiers ModsTbl[] = {
bool qt_mac_eat_unicode_key = false;
-Q_GUI_EXPORT void qt_mac_secure_keyboard(bool b)
-{
- static bool secure = false;
- if (b != secure){
- b ? EnableSecureEventInput() : DisableSecureEventInput();
- secure = b;
- }
-}
/* key maps */
struct qt_mac_enum_mapper
@@ -384,18 +376,7 @@ bool QCocoaKeyMapper::updateKeyboard()
}
currentInputSource = source;
keyboard_dead = 0;
- CFStringRef iso639Code;
- CFArrayRef array = static_cast<CFArrayRef>(TISGetInputSourceProperty(currentInputSource, kTISPropertyInputSourceLanguages));
- iso639Code = static_cast<CFStringRef>(CFArrayGetValueAtIndex(array, 0)); // Actually a RFC3066bis, but it's close enough
-
- if (iso639Code) {
- keyboardInputLocale = QLocale(QString::fromCFString(iso639Code));
- keyboardInputDirection = keyboardInputLocale.textDirection();
- } else {
- keyboardInputLocale = QLocale::c();
- keyboardInputDirection = Qt::LeftToRight;
- }
return true;
}
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h
index 7baaf971f4..2b4cf0ef98 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.h
+++ b/src/plugins/platforms/cocoa/qcocoamenu.h
@@ -45,6 +45,8 @@
#include <qpa/qplatformmenu.h>
#include "qcocoamenuitem.h"
+Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaNSMenu));
+
QT_BEGIN_NAMESPACE
class QCocoaMenuBar;
@@ -55,37 +57,31 @@ public:
QCocoaMenu();
~QCocoaMenu();
- void setTag(quintptr tag) Q_DECL_OVERRIDE
- { m_tag = tag; }
- quintptr tag() const Q_DECL_OVERRIDE
- { return m_tag; }
-
- void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) Q_DECL_OVERRIDE;
- void removeMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE;
- void syncMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE;
- void setEnabled(bool enabled) Q_DECL_OVERRIDE;
- bool isEnabled() const Q_DECL_OVERRIDE;
- void setVisible(bool visible) Q_DECL_OVERRIDE;
- void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) Q_DECL_OVERRIDE;
- void dismiss() Q_DECL_OVERRIDE;
+ void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) override;
+ void removeMenuItem(QPlatformMenuItem *menuItem) override;
+ void syncMenuItem(QPlatformMenuItem *menuItem) override;
+ void setEnabled(bool enabled) override;
+ bool isEnabled() const override;
+ void setVisible(bool visible) override;
+ void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) override;
+ void dismiss() override;
- void syncSeparatorsCollapsible(bool enable) Q_DECL_OVERRIDE;
+ void syncSeparatorsCollapsible(bool enable) override;
void propagateEnabledState(bool enabled);
- void setIcon(const QIcon &icon) Q_DECL_OVERRIDE { Q_UNUSED(icon) }
+ void setIcon(const QIcon &icon) override { Q_UNUSED(icon) }
- void setText(const QString &text) Q_DECL_OVERRIDE;
- void setMinimumWidth(int width) Q_DECL_OVERRIDE;
- void setFont(const QFont &font) Q_DECL_OVERRIDE;
+ void setText(const QString &text) override;
+ void setMinimumWidth(int width) override;
+ void setFont(const QFont &font) override;
- inline NSMenu *nsMenu() const
- { return m_nativeMenu; }
+ NSMenu *nsMenu() const;
inline bool isVisible() const { return m_visible; }
- QPlatformMenuItem *menuItemAt(int position) const Q_DECL_OVERRIDE;
- QPlatformMenuItem *menuItemForTag(quintptr tag) const Q_DECL_OVERRIDE;
+ QPlatformMenuItem *menuItemAt(int position) const override;
+ QPlatformMenuItem *menuItemForTag(quintptr tag) const override;
QList<QCocoaMenuItem *> items() const;
QList<QCocoaMenuItem *> merged() const;
@@ -96,7 +92,7 @@ public:
bool isOpen() const;
void setIsOpen(bool isOpen);
- void timerEvent(QTimerEvent *e) Q_DECL_OVERRIDE;
+ void timerEvent(QTimerEvent *e) override;
void syncMenuItem_helper(QPlatformMenuItem *menuItem, bool menubarUpdate);
@@ -106,9 +102,8 @@ private:
void scheduleUpdate();
QList<QCocoaMenuItem *> m_menuItems;
- NSMenu *m_nativeMenu;
+ QT_MANGLE_NAMESPACE(QCocoaNSMenu) *m_nativeMenu;
NSMenuItem *m_attachedItem;
- quintptr m_tag;
int m_updateTimer;
bool m_enabled:1;
bool m_parentEnabled:1;
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index e41c70b8ca..b3c2d5ae90 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -38,229 +38,22 @@
****************************************************************************/
#include "qcocoamenu.h"
+#include "qcocoansmenu.h"
#include "qcocoahelpers.h"
#include <QtCore/QtDebug>
-#include <QtCore/qmetaobject.h>
-#include <QtCore/private/qthread_p.h>
-#include <QtGui/private/qguiapplication_p.h>
#include "qcocoaapplication.h"
#include "qcocoaintegration.h"
#include "qcocoamenuloader.h"
#include "qcocoamenubar.h"
#include "qcocoawindow.h"
-#import "qnsview.h"
-
-QT_BEGIN_NAMESPACE
-
-NSString *qt_mac_removePrivateUnicode(NSString* string)
-{
- int len = [string length];
- if (len) {
- QVarLengthArray <unichar, 10> characters(len);
- bool changed = false;
- for (int i = 0; i<len; i++) {
- characters[i] = [string characterAtIndex:i];
- // check if they belong to key codes in private unicode range
- // currently we need to handle only the NSDeleteFunctionKey
- if (characters[i] == NSDeleteFunctionKey) {
- characters[i] = NSDeleteCharacter;
- changed = true;
- }
- }
- if (changed)
- return [NSString stringWithCharacters:characters.data() length:len];
- }
- return string;
-}
-
-QT_END_NAMESPACE
-
-@interface QT_MANGLE_NAMESPACE(QCocoaMenuDelegate) : NSObject <NSMenuDelegate> {
- QCocoaMenu *m_menu;
-}
-
-- (id) initWithMenu:(QCocoaMenu*) m;
-- (NSMenuItem *)findItem:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier;
-
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate);
-
-@implementation QCocoaMenuDelegate
-
-- (id) initWithMenu:(QCocoaMenu*) m
-{
- if ((self = [super init]))
- m_menu = m;
-
- return self;
-}
-
-- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
-{
- Q_ASSERT(m_menu->nsMenu() == menu);
- return menu.numberOfItems;
-}
-
-- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
-{
- Q_UNUSED(index);
- Q_ASSERT(m_menu->nsMenu() == menu);
- if (shouldCancel) {
- // TODO detach all submenus
- return NO;
- }
-
- QCocoaMenuItem *menuItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
- if (m_menu->items().contains(menuItem)) {
- if (QCocoaMenu *itemSubmenu = menuItem->menu())
- itemSubmenu->setAttachedItem(item);
- }
- return YES;
-}
-
-- (void)menu:(NSMenu*)menu willHighlightItem:(NSMenuItem*)item
-{
- Q_UNUSED(menu);
- if (item && [item tag]) {
- QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]);
- cocoaItem->hovered();
- }
-}
-
-- (void) menuWillOpen:(NSMenu*)m
-{
- Q_UNUSED(m);
- m_menu->setIsOpen(true);
- emit m_menu->aboutToShow();
-}
-
-- (void) menuDidClose:(NSMenu*)m
-{
- Q_UNUSED(m);
- m_menu->setIsOpen(false);
- // wrong, but it's the best we can do
- emit m_menu->aboutToHide();
-}
-
-- (void) itemFired:(NSMenuItem*) item
-{
- QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]);
- // Menu-holding items also get a target to play nicely
- // with NSMenuValidation but should not trigger.
- if (cocoaItem->menu())
- return;
- QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
- QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
- static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
- activatedSignal.invoke(cocoaItem, Qt::QueuedConnection);
-}
-
-- (BOOL)validateMenuItem:(NSMenuItem*)menuItem
-{
- QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>(menuItem.tag);
- // Menu-holding items are always enabled, as it's conventional in Cocoa
- if (!cocoaItem || cocoaItem->menu())
- return YES;
-
- return cocoaItem->isEnabled();
-}
-
-- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action
-{
- /*
- Check if the menu actually has a keysequence defined for this key event.
- If it does, then we will first send the key sequence to the QWidget that has focus
- since (in Qt's eyes) it needs to a chance at the key event first (QEvent::ShortcutOverride).
- If the widget accepts the key event, we then return YES, but set the target and action to be nil,
- which means that the action should not be triggered, and instead dispatch the event ourselves.
- In every other case we return NO, which means that Cocoa can do as it pleases
- (i.e., fire the menu action).
- */
-
- // Change the private unicode keys to the ones used in setting the "Key Equivalents"
- NSString *characters = qt_mac_removePrivateUnicode([event characters]);
- // Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ...
- const NSUInteger mask = NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask;
- if (NSMenuItem *menuItem = [self findItem:menu forKey:characters forModifiers:([event modifierFlags] & mask)]) {
- if (!menuItem.target) {
- // This item was modified by QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder
- // and it looks like we're running a modal session for NSOpenPanel/NSSavePanel.
- // QCocoaFileDialogHelper is actually the only place we use this and we run NSOpenPanel modal
- // (modal sheet, window modal, application modal).
- // Whatever the current first responder is, let's give it a chance
- // and do not touch the Qt's focusObject (which is different from some native view
- // having a focus inside NSSave/OpenPanel.
- *target = nil;
- *action = menuItem.action;
- return YES;
- }
-
- QObject *object = qApp->focusObject();
- if (object) {
- QChar ch;
- int keyCode;
- ulong nativeModifiers = [event modifierFlags];
- Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers];
- NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers];
- NSString *characters = [event characters];
-
- if ([charactersIgnoringModifiers length] > 0) { // convert the first character into a key code
- if ((modifiers & Qt::ControlModifier) && ([characters length] != 0)) {
- ch = QChar([characters characterAtIndex:0]);
- } else {
- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
- }
- keyCode = qt_mac_cocoaKey2QtKey(ch);
- } else {
- // might be a dead key
- ch = QChar::ReplacementCharacter;
- keyCode = Qt::Key_unknown;
- }
-
- QKeyEvent accel_ev(QEvent::ShortcutOverride, (keyCode & (~Qt::KeyboardModifierMask)),
- Qt::KeyboardModifiers(modifiers & Qt::KeyboardModifierMask));
- accel_ev.ignore();
- QCoreApplication::sendEvent(object, &accel_ev);
- if (accel_ev.isAccepted()) {
- [[NSApp keyWindow] sendEvent: event];
- *target = nil;
- *action = nil;
- return YES;
- }
- }
- }
- return NO;
-}
-
-- (NSMenuItem *)findItem:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier
-{
- for (NSMenuItem *item in [menu itemArray]) {
- if (![item isEnabled] || [item isHidden] || [item isSeparatorItem])
- continue;
- if ([item hasSubmenu]) {
- if (NSMenuItem *nested = [self findItem:[item submenu] forKey:key forModifiers:modifier])
- return nested;
- }
-
- NSString *menuKey = [item keyEquivalent];
- if (menuKey
- && NSOrderedSame == [menuKey compare:key]
- && modifier == [item keyEquivalentModifierMask])
- return item;
- }
- return nil;
-}
-
-@end
+#include "qcocoascreen.h"
QT_BEGIN_NAMESPACE
QCocoaMenu::QCocoaMenu() :
m_attachedItem(0),
- m_tag(0),
m_updateTimer(0),
m_enabled(true),
m_parentEnabled(true),
@@ -269,9 +62,7 @@ QCocoaMenu::QCocoaMenu() :
{
QMacAutoReleasePool pool;
- m_nativeMenu = [[NSMenu alloc] initWithTitle:@"Untitled"];
- [m_nativeMenu setAutoenablesItems:YES];
- m_nativeMenu.delegate = [[QCocoaMenuDelegate alloc] initWithMenu:this];
+ m_nativeMenu = [[QCocoaNSMenu alloc] initWithQPAMenu:this];
}
QCocoaMenu::~QCocoaMenu()
@@ -281,10 +72,6 @@ QCocoaMenu::~QCocoaMenu()
item->setMenuParent(0);
}
- QMacAutoReleasePool pool;
- NSObject *delegate = m_nativeMenu.delegate;
- m_nativeMenu.delegate = nil;
- [delegate release];
[m_nativeMenu release];
}
@@ -309,6 +96,11 @@ void QCocoaMenu::setFont(const QFont &font)
}
}
+NSMenu *QCocoaMenu::nsMenu() const
+{
+ return static_cast<NSMenu *>(m_nativeMenu);
+}
+
void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before)
{
QMacAutoReleasePool pool;
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h
index a4ee531e91..6f3aca3a51 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.h
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.h
@@ -56,11 +56,11 @@ public:
QCocoaMenuBar();
~QCocoaMenuBar();
- void insertMenu(QPlatformMenu *menu, QPlatformMenu* before) Q_DECL_OVERRIDE;
- void removeMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE;
- void syncMenu(QPlatformMenu *menuItem) Q_DECL_OVERRIDE;
- void handleReparent(QWindow *newParentWindow) Q_DECL_OVERRIDE;
- QPlatformMenu *menuForTag(quintptr tag) const Q_DECL_OVERRIDE;
+ void insertMenu(QPlatformMenu *menu, QPlatformMenu* before) override;
+ void removeMenu(QPlatformMenu *menu) override;
+ void syncMenu(QPlatformMenu *menuItem) override;
+ void handleReparent(QWindow *newParentWindow) override;
+ QPlatformMenu *menuForTag(quintptr tag) const override;
inline NSMenu *nsMenu() const
{ return m_nativeMenu; }
@@ -71,6 +71,7 @@ public:
QList<QCocoaMenuItem*> merged() const;
NSMenuItem *itemForRole(QPlatformMenuItem::MenuRole r);
+ QCocoaWindow *cocoaWindow() const;
void syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate);
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index a4cd465dae..8091d00bda 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -449,7 +449,12 @@ NSMenuItem *QCocoaMenuBar::itemForRole(QPlatformMenuItem::MenuRole r)
foreach (QCocoaMenuItem *i, m->items())
if (i->effectiveRole() == r)
return i->nsItem();
- return Q_NULLPTR;
+ return nullptr;
+}
+
+QCocoaWindow *QCocoaMenuBar::cocoaWindow() const
+{
+ return m_window.data();
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h
index 23f788687c..2b598ee3a0 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h
@@ -78,27 +78,22 @@ public:
QCocoaMenuItem();
~QCocoaMenuItem();
- void setTag(quintptr tag) Q_DECL_OVERRIDE
- { m_tag = tag; }
- quintptr tag() const Q_DECL_OVERRIDE
- { return m_tag; }
-
- void setText(const QString &text) Q_DECL_OVERRIDE;
- void setIcon(const QIcon &icon) Q_DECL_OVERRIDE;
- void setMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE;
- void setVisible(bool isVisible) Q_DECL_OVERRIDE;
- void setIsSeparator(bool isSeparator) Q_DECL_OVERRIDE;
- void setFont(const QFont &font) Q_DECL_OVERRIDE;
- void setRole(MenuRole role) Q_DECL_OVERRIDE;
+ void setText(const QString &text) override;
+ void setIcon(const QIcon &icon) override;
+ void setMenu(QPlatformMenu *menu) override;
+ void setVisible(bool isVisible) override;
+ void setIsSeparator(bool isSeparator) override;
+ void setFont(const QFont &font) override;
+ void setRole(MenuRole role) override;
#ifndef QT_NO_SHORTCUT
- void setShortcut(const QKeySequence& shortcut) Q_DECL_OVERRIDE;
+ void setShortcut(const QKeySequence& shortcut) override;
#endif
- void setCheckable(bool checkable) Q_DECL_OVERRIDE { Q_UNUSED(checkable) }
- void setChecked(bool isChecked) Q_DECL_OVERRIDE;
- void setEnabled(bool isEnabled) Q_DECL_OVERRIDE;
- void setIconSize(int size) Q_DECL_OVERRIDE;
+ void setCheckable(bool checkable) override { Q_UNUSED(checkable) }
+ void setChecked(bool isChecked) override;
+ void setEnabled(bool isEnabled) override;
+ void setIconSize(int size) override;
- void setNativeContents(WId item) Q_DECL_OVERRIDE;
+ void setNativeContents(WId item) override;
inline QString text() const { return m_text; }
inline NSMenuItem * nsItem() { return m_native; }
@@ -129,7 +124,6 @@ private:
#ifndef QT_NO_SHORTCUT
QKeySequence m_shortcut;
#endif
- quintptr m_tag;
int m_iconSize;
bool m_textSynced:1;
bool m_isVisible:1;
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index 394e0fb8e4..f8f9648822 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -49,6 +49,7 @@
#include "qcocoaapplication.h" // for custom application category
#include "qcocoamenuloader.h"
#include <QtGui/private/qcoregraphics_p.h>
+#include <QtCore/qregularexpression.h>
#include <QtCore/QDebug>
@@ -95,7 +96,6 @@ QCocoaMenuItem::QCocoaMenuItem() :
m_itemView(nil),
m_menu(NULL),
m_role(NoRole),
- m_tag(0),
m_iconSize(16),
m_textSynced(false),
m_isVisible(true),
@@ -262,7 +262,8 @@ NSMenuItem *QCocoaMenuItem::sync()
m_detectedRole = detectMenuRole(m_text);
switch (m_detectedRole) {
case QPlatformMenuItem::AboutRole:
- if (m_text.indexOf(QRegExp(QString::fromLatin1("qt$"), Qt::CaseInsensitive)) == -1)
+ if (m_text.indexOf(QRegularExpression(QString::fromLatin1("qt$"),
+ QRegularExpression::CaseInsensitiveOption)) == -1)
mergeItem = [loader aboutMenuItem];
else
mergeItem = [loader aboutQtMenuItem];
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
index b986833f6d..cd597da71c 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
@@ -57,8 +57,12 @@
static QCocoaMenuLoader *shared = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
- shared = [[self alloc] init];
- });
+ shared = [[self alloc] init];
+ atexit_b(^{
+ [shared release];
+ shared = nil;
+ });
+ });
return shared;
}
diff --git a/src/plugins/platforms/cocoa/qcocoamimetypes.mm b/src/plugins/platforms/cocoa/qcocoamimetypes.mm
index 093f86da6e..f7662a92a4 100644
--- a/src/plugins/platforms/cocoa/qcocoamimetypes.mm
+++ b/src/plugins/platforms/cocoa/qcocoamimetypes.mm
@@ -105,101 +105,9 @@ QList<QByteArray> QMacPasteboardMimeTraditionalMacPlainText::convertFromMime(con
return ret;
}
-class QMacPasteboardMimeTiff : public QMacInternalPasteboardMime {
-public:
- QMacPasteboardMimeTiff() : QMacInternalPasteboardMime(MIME_ALL) { }
- QString convertorName();
-
- QString flavorFor(const QString &mime);
- QString mimeFor(QString flav);
- bool canConvert(const QString &mime, QString flav);
- QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
- QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
-};
-
-QString QMacPasteboardMimeTiff::convertorName()
-{
- return QLatin1String("Tiff");
-}
-
-QString QMacPasteboardMimeTiff::flavorFor(const QString &mime)
-{
- if (mime.startsWith(QLatin1String("application/x-qt-image")))
- return QLatin1String("public.tiff");
- return QString();
-}
-
-QString QMacPasteboardMimeTiff::mimeFor(QString flav)
-{
- if (flav == QLatin1String("public.tiff"))
- return QLatin1String("application/x-qt-image");
- return QString();
-}
-
-bool QMacPasteboardMimeTiff::canConvert(const QString &mime, QString flav)
-{
- return flav == QLatin1String("public.tiff") && mime == QLatin1String("application/x-qt-image");
-}
-
-QVariant QMacPasteboardMimeTiff::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
-{
- if (data.count() > 1)
- qWarning("QMacPasteboardMimeTiff: Cannot handle multiple member data");
- QVariant ret;
- if (!canConvert(mime, flav))
- return ret;
- const QByteArray &a = data.first();
- QCFType<CGImageRef> image;
- QCFType<CFDataRef> tiffData = CFDataCreateWithBytesNoCopy(0,
- reinterpret_cast<const UInt8 *>(a.constData()),
- a.size(), kCFAllocatorNull);
- QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithData(tiffData, 0);
- image = CGImageSourceCreateImageAtIndex(imageSource, 0, 0);
- if (image != 0)
- ret = QVariant(qt_mac_toQImage(image));
- return ret;
-}
-
-QList<QByteArray> QMacPasteboardMimeTiff::convertFromMime(const QString &mime, QVariant variant, QString flav)
-{
- QList<QByteArray> ret;
- if (!canConvert(mime, flav))
- return ret;
-
- QImage img = qvariant_cast<QImage>(variant);
- QCFType<CGImageRef> cgimage = qt_mac_toCGImage(img);
-
- QCFType<CFMutableDataRef> data = CFDataCreateMutable(0, 0);
- QCFType<CGImageDestinationRef> imageDestination = CGImageDestinationCreateWithData(data, kUTTypeTIFF, 1, 0);
- if (imageDestination != 0) {
- CFTypeRef keys[2];
- QCFType<CFTypeRef> values[2];
- QCFType<CFDictionaryRef> options;
- keys[0] = kCGImagePropertyPixelWidth;
- keys[1] = kCGImagePropertyPixelHeight;
- int width = img.width();
- int height = img.height();
- values[0] = CFNumberCreate(0, kCFNumberIntType, &width);
- values[1] = CFNumberCreate(0, kCFNumberIntType, &height);
- options = CFDictionaryCreate(0, reinterpret_cast<const void **>(keys),
- reinterpret_cast<const void **>(values), 2,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- CGImageDestinationAddImage(imageDestination, cgimage, options);
- CGImageDestinationFinalize(imageDestination);
- }
- QByteArray ar(CFDataGetLength(data), 0);
- CFDataGetBytes(data,
- CFRangeMake(0, ar.size()),
- reinterpret_cast<UInt8 *>(ar.data()));
- ret.append(ar);
- return ret;
-}
-
void QCocoaMimeTypes::initializeMimeTypes()
{
new QMacPasteboardMimeTraditionalMacPlainText;
- new QMacPasteboardMimeTiff;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h
index 26fbe3e4bc..c78f1d5a7f 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h
@@ -60,18 +60,18 @@ public:
QCocoaNativeInterface();
#ifndef QT_NO_OPENGL
- void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) Q_DECL_OVERRIDE;
+ void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) override;
#endif
- void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) Q_DECL_OVERRIDE;
+ void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) override;
- NativeResourceForIntegrationFunction nativeResourceFunctionForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE;
+ NativeResourceForIntegrationFunction nativeResourceFunctionForIntegration(const QByteArray &resource) override;
#ifndef QT_NO_OPENGL
static void *cglContextForContext(QOpenGLContext *context);
static void *nsOpenGLContextForContext(QOpenGLContext* context);
#endif
- QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE;
+ QFunctionPointer platformFunction(const QByteArray &function) const override;
public Q_SLOTS:
void onAppFocusWindowChanged(QWindow *window);
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
index 5504c2427f..955b147bfd 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
@@ -103,7 +103,7 @@ void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceS
return static_cast<QCocoaWindow *>(window->handle())->currentContext()->nsOpenGLContext();
#endif
} else if (resourceString == "nswindow") {
- return static_cast<QCocoaWindow *>(window->handle())->m_nsWindow;
+ return static_cast<QCocoaWindow *>(window->handle())->nativeWindow();
}
return 0;
}
@@ -233,7 +233,7 @@ QFunctionPointer QCocoaNativeInterface::platformFunction(const QByteArray &funct
if (function == QCocoaWindowFunctions::bottomLeftClippedByNSWindowOffsetIdentifier())
return QFunctionPointer(QCocoaWindowFunctions::BottomLeftClippedByNSWindowOffset(QCocoaWindow::bottomLeftClippedByNSWindowOffsetStatic));
- return Q_NULLPTR;
+ return nullptr;
}
void QCocoaNativeInterface::addToMimeList(void *macPasteboardMime)
diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.h b/src/plugins/platforms/cocoa/qcocoansmenu.h
new file mode 100644
index 0000000000..8fb0a26f27
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qcocoansmenu.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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$
+**
+****************************************************************************/
+
+#ifndef QCOCOANSMENU_H
+#define QCOCOANSMENU_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#import <AppKit/AppKit.h>
+
+#include <QtCore/qpointer.h>
+#include <qcocoahelpers.h>
+
+QT_FORWARD_DECLARE_CLASS(QCocoaMenu);
+typedef QPointer<QCocoaMenu> QCocoaMenuPointer;
+
+
+@interface QT_MANGLE_NAMESPACE(QCocoaNSMenuDelegate) : NSObject <NSMenuDelegate>
+
++ (instancetype)sharedMenuDelegate;
+
+- (NSMenuItem *)findItemInMenu:(NSMenu *)menu
+ forKey:(NSString *)key
+ modifiers:(NSUInteger)modifiers;
+
+- (BOOL)validateMenuItem:(NSMenuItem *)item; // NSMenuValidation
+
+@end
+
+@interface QT_MANGLE_NAMESPACE(QCocoaNSMenu) : NSMenu
+
+@property (readonly, nonatomic) QCocoaMenuPointer qpaMenu;
+
+- (instancetype)initWithQPAMenu:(QCocoaMenu *)menu;
+
+@end
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaNSMenu);
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaNSMenuDelegate);
+
+#endif // QCOCOANSMENU_H
diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.mm b/src/plugins/platforms/cocoa/qcocoansmenu.mm
new file mode 100644
index 0000000000..996a4ff194
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qcocoansmenu.mm
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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$
+**
+****************************************************************************/
+
+#import "qcocoansmenu.h"
+#include "qcocoamenu.h"
+#include "qcocoamenuitem.h"
+#import "qnsview.h"
+
+#include <QtCore/qmetaobject.h>
+#include <QtCore/private/qthread_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+static NSString *qt_mac_removePrivateUnicode(NSString* string)
+{
+ int len = [string length];
+ if (len) {
+ QVarLengthArray <unichar, 10> characters(len);
+ bool changed = false;
+ for (int i = 0; i<len; i++) {
+ characters[i] = [string characterAtIndex:i];
+ // check if they belong to key codes in private unicode range
+ // currently we need to handle only the NSDeleteFunctionKey
+ if (characters[i] == NSDeleteFunctionKey) {
+ characters[i] = NSDeleteCharacter;
+ changed = true;
+ }
+ }
+ if (changed)
+ return [NSString stringWithCharacters:characters.data() length:len];
+ }
+ return string;
+}
+
+@implementation QCocoaNSMenu
+
+- (instancetype)initWithQPAMenu:(QCocoaMenu *)menu
+{
+ if ((self = [super initWithTitle:@"Untitled"])) {
+ _qpaMenu = menu;
+ self.autoenablesItems = YES;
+ self.delegate = [QCocoaNSMenuDelegate sharedMenuDelegate];
+ }
+
+ return self;
+}
+
+@end
+
+#define CHECK_MENU_CLASS(menu) Q_ASSERT([menu isMemberOfClass:[QCocoaNSMenu class]])
+
+@implementation QCocoaNSMenuDelegate
+
++ (instancetype)sharedMenuDelegate
+{
+ static QCocoaNSMenuDelegate *shared = nil;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ shared = [[self alloc] init];
+ atexit_b(^{
+ [shared release];
+ shared = nil;
+ });
+ });
+ return shared;
+}
+
+- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
+{
+ CHECK_MENU_CLASS(menu);
+ return menu.numberOfItems;
+}
+
+- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
+{
+ Q_UNUSED(index);
+ CHECK_MENU_CLASS(menu);
+
+ if (shouldCancel)
+ return NO;
+
+ const auto &qpaMenu = static_cast<QCocoaNSMenu *>(menu).qpaMenu;
+ if (qpaMenu.isNull())
+ return YES;
+
+ auto *menuItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
+ if (qpaMenu->items().contains(menuItem)) {
+ if (QCocoaMenu *itemSubmenu = menuItem->menu())
+ itemSubmenu->setAttachedItem(item);
+ }
+
+ return YES;
+}
+
+- (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item
+{
+ CHECK_MENU_CLASS(menu);
+ auto *qpaItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
+ if (qpaItem)
+ qpaItem->hovered();
+}
+
+- (void)menuWillOpen:(NSMenu *)menu
+{
+ CHECK_MENU_CLASS(menu);
+ const auto &qpaMenu = static_cast<QCocoaNSMenu *>(menu).qpaMenu;
+ if (qpaMenu.isNull())
+ return;
+
+ qpaMenu->setIsOpen(true);
+ emit qpaMenu->aboutToShow();
+}
+
+- (void)menuDidClose:(NSMenu *)menu
+{
+ CHECK_MENU_CLASS(menu);
+ const auto &qpaMenu = static_cast<QCocoaNSMenu *>(menu).qpaMenu;
+ if (qpaMenu.isNull())
+ return;
+
+ qpaMenu->setIsOpen(false);
+ // wrong, but it's the best we can do
+ emit qpaMenu->aboutToHide();
+}
+
+- (void)itemFired:(NSMenuItem *)item
+{
+ auto *qpaItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
+ // Menu-holding items also get a target to play nicely
+ // with NSMenuValidation but should not trigger.
+ if (!qpaItem || qpaItem->menu())
+ return;
+
+ QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
+ QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
+
+ static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
+ activatedSignal.invoke(qpaItem, Qt::QueuedConnection);
+}
+
+- (BOOL)validateMenuItem:(NSMenuItem*)item
+{
+ auto *qpaItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
+ // Menu-holding items are always enabled, as it's conventional in Cocoa
+ if (!qpaItem || qpaItem->menu())
+ return YES;
+
+ return qpaItem->isEnabled();
+}
+
+- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action
+{
+ /*
+ Check if the menu actually has a keysequence defined for this key event.
+ If it does, then we will first send the key sequence to the QWidget that has focus
+ since (in Qt's eyes) it needs to a chance at the key event first (QEvent::ShortcutOverride).
+ If the widget accepts the key event, we then return YES, but set the target and action to be nil,
+ which means that the action should not be triggered, and instead dispatch the event ourselves.
+ In every other case we return NO, which means that Cocoa can do as it pleases
+ (i.e., fire the menu action).
+ */
+
+ CHECK_MENU_CLASS(menu);
+
+ // Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ...
+ static const NSUInteger mask = NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask;
+
+ // Change the private unicode keys to the ones used in setting the "Key Equivalents"
+ NSString *characters = qt_mac_removePrivateUnicode(event.charactersIgnoringModifiers);
+ const auto modifiers = event.modifierFlags & mask;
+ NSMenuItem *keyEquivalentItem = [self findItemInMenu:menu
+ forKey:characters
+ modifiers:modifiers];
+ if (!keyEquivalentItem) {
+ // Maybe the modified character is what we're looking for after all
+ characters = qt_mac_removePrivateUnicode(event.characters);
+ keyEquivalentItem = [self findItemInMenu:menu
+ forKey:characters
+ modifiers:modifiers];
+ }
+
+ if (keyEquivalentItem) {
+ if (!keyEquivalentItem.target) {
+ // This item was modified by QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder
+ // and it looks like we're running a modal session for NSOpenPanel/NSSavePanel.
+ // QCocoaFileDialogHelper is actually the only place we use this and we run NSOpenPanel modal
+ // (modal sheet, window modal, application modal).
+ // Whatever the current first responder is, let's give it a chance
+ // and do not touch the Qt's focusObject (which is different from some native view
+ // having a focus inside NSSave/OpenPanel.
+ *target = nil;
+ *action = keyEquivalentItem.action;
+ return YES;
+ }
+
+ QObject *object = qApp->focusObject();
+ if (object) {
+ QChar ch;
+ int keyCode;
+ ulong nativeModifiers = [event modifierFlags];
+ Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers];
+ NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers];
+ NSString *characters = [event characters];
+
+ if ([charactersIgnoringModifiers length] > 0) { // convert the first character into a key code
+ if ((modifiers & Qt::ControlModifier) && ([characters length] != 0)) {
+ ch = QChar([characters characterAtIndex:0]);
+ } else {
+ ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
+ }
+ keyCode = qt_mac_cocoaKey2QtKey(ch);
+ } else {
+ // might be a dead key
+ ch = QChar::ReplacementCharacter;
+ keyCode = Qt::Key_unknown;
+ }
+
+ QKeyEvent accel_ev(QEvent::ShortcutOverride, (keyCode & (~Qt::KeyboardModifierMask)),
+ Qt::KeyboardModifiers(modifiers & Qt::KeyboardModifierMask));
+ accel_ev.ignore();
+ QCoreApplication::sendEvent(object, &accel_ev);
+ if (accel_ev.isAccepted()) {
+ [[NSApp keyWindow] sendEvent: event];
+ *target = nil;
+ *action = nil;
+ return YES;
+ }
+ }
+ }
+
+ return NO;
+}
+
+- (NSMenuItem *)findItemInMenu:(NSMenu *)menu
+ forKey:(NSString *)key
+ modifiers:(NSUInteger)modifiers
+{
+ // Find an item in 'menu' that has the same key equivalent as specified by
+ // 'key' and 'modifiers'. We ignore disabled, hidden and separator items.
+ // In a similar fashion, we don't need to recurse into submenus because their
+ // delegate will have [menuHasKeyEquivalent:...] invoked at some point.
+
+ for (NSMenuItem *item in menu.itemArray) {
+ if (!item.enabled || item.hidden || item.separatorItem)
+ continue;
+
+ if (item.hasSubmenu)
+ continue;
+
+ NSString *menuKey = item.keyEquivalent;
+ if (menuKey && NSOrderedSame == [menuKey compare:key]
+ && modifiers == item.keyEquivalentModifierMask)
+ return item;
+ }
+
+ return nil;
+}
+
+@end
+
+#undef CHECK_MENU_CLASS
diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.h b/src/plugins/platforms/cocoa/qcocoaprintdevice.h
index c726cca4e5..20b27f3286 100644
--- a/src/plugins/platforms/cocoa/qcocoaprintdevice.h
+++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.h
@@ -68,37 +68,37 @@ public:
explicit QCocoaPrintDevice(const QString &id);
virtual ~QCocoaPrintDevice();
- bool isValid() const Q_DECL_OVERRIDE;
- bool isDefault() const Q_DECL_OVERRIDE;
+ bool isValid() const override;
+ bool isDefault() const override;
- QPrint::DeviceState state() const Q_DECL_OVERRIDE;
+ QPrint::DeviceState state() const override;
- QPageSize defaultPageSize() const Q_DECL_OVERRIDE;
+ QPageSize defaultPageSize() const override;
QMarginsF printableMargins(const QPageSize &pageSize, QPageLayout::Orientation orientation,
- int resolution) const Q_DECL_OVERRIDE;
+ int resolution) const override;
- int defaultResolution() const Q_DECL_OVERRIDE;
+ int defaultResolution() const override;
- QPrint::InputSlot defaultInputSlot() const Q_DECL_OVERRIDE;
+ QPrint::InputSlot defaultInputSlot() const override;
- QPrint::OutputBin defaultOutputBin() const Q_DECL_OVERRIDE;
+ QPrint::OutputBin defaultOutputBin() const override;
- QPrint::DuplexMode defaultDuplexMode() const Q_DECL_OVERRIDE;
+ QPrint::DuplexMode defaultDuplexMode() const override;
- QPrint::ColorMode defaultColorMode() const Q_DECL_OVERRIDE;
+ QPrint::ColorMode defaultColorMode() const override;
PMPrinter macPrinter() const;
PMPaper macPaper(const QPageSize &pageSize) const;
protected:
- void loadPageSizes() const Q_DECL_OVERRIDE;
- void loadResolutions() const Q_DECL_OVERRIDE;
- void loadInputSlots() const Q_DECL_OVERRIDE;
- void loadOutputBins() const Q_DECL_OVERRIDE;
- void loadDuplexModes() const Q_DECL_OVERRIDE;
- void loadColorModes() const Q_DECL_OVERRIDE;
- void loadMimeTypes() const Q_DECL_OVERRIDE;
+ void loadPageSizes() const override;
+ void loadResolutions() const override;
+ void loadInputSlots() const override;
+ void loadOutputBins() const override;
+ void loadDuplexModes() const override;
+ void loadColorModes() const override;
+ void loadMimeTypes() const override;
private:
QPageSize createPageSize(const PMPaper &paper) const;
diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
index 39fcf285ed..bfe6cd09b6 100644
--- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
+++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
@@ -46,6 +46,15 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_PRINTER
+// The CUPS PPD APIs were deprecated in CUPS 1.6/macOS 10.8, but
+// as long as we're supporting RHEL 6, which still ships CUPS 1.4
+// we're not going to rewrite this, as we want to share the code
+// between macOS and Linux for the CUPS-bits. See discussion in
+// https://bugreports.qt.io/browse/QTBUG-56545
+#pragma message "Disabling CUPS PPD deprecation warnings. This should be fixed once we drop support for RHEL6 (QTBUG-56545)"
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
static QPrint::DuplexMode macToDuplexMode(const PMDuplexMode &mode)
{
if (mode == kPMDuplexTumble)
@@ -474,6 +483,8 @@ PMPaper QCocoaPrintDevice::macPaper(const QPageSize &pageSize) const
return paper;
}
+#pragma clang diagnostic pop
+
#endif // QT_NO_PRINTER
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaprintersupport.h b/src/plugins/platforms/cocoa/qcocoaprintersupport.h
index a07bf0ec1b..40a638207a 100644
--- a/src/plugins/platforms/cocoa/qcocoaprintersupport.h
+++ b/src/plugins/platforms/cocoa/qcocoaprintersupport.h
@@ -53,12 +53,12 @@ public:
QCocoaPrinterSupport();
~QCocoaPrinterSupport();
- QPrintEngine *createNativePrintEngine(QPrinter::PrinterMode printerMode, const QString &deviceId = QString()) Q_DECL_OVERRIDE;
- QPaintEngine *createPaintEngine(QPrintEngine *, QPrinter::PrinterMode printerMode) Q_DECL_OVERRIDE;
+ QPrintEngine *createNativePrintEngine(QPrinter::PrinterMode printerMode, const QString &deviceId = QString()) override;
+ QPaintEngine *createPaintEngine(QPrintEngine *, QPrinter::PrinterMode printerMode) override;
- QPrintDevice createPrintDevice(const QString &id) Q_DECL_OVERRIDE;
- QStringList availablePrintDeviceIds() const Q_DECL_OVERRIDE;
- QString defaultPrintDeviceId() const Q_DECL_OVERRIDE;
+ QPrintDevice createPrintDevice(const QString &id) override;
+ QStringList availablePrintDeviceIds() const override;
+ QString defaultPrintDeviceId() const override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h
new file mode 100644
index 0000000000..3d59c3de79
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qcocoascreen.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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$
+**
+****************************************************************************/
+
+#ifndef QCOCOASCREEN_H
+#define QCOCOASCREEN_H
+
+#include <AppKit/AppKit.h>
+
+#include "qcocoacursor.h"
+
+#include <qpa/qplatformintegration.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCocoaScreen : public QPlatformScreen
+{
+public:
+ QCocoaScreen(int screenIndex);
+ ~QCocoaScreen();
+
+ // ----------------------------------------------------
+ // Virtual methods overridden from QPlatformScreen
+ QPixmap grabWindow(WId window, int x, int y, int width, int height) const override;
+ QRect geometry() const override { return m_geometry; }
+ QRect availableGeometry() const override { return m_availableGeometry; }
+ int depth() const override { return m_depth; }
+ QImage::Format format() const override { return m_format; }
+ qreal devicePixelRatio() const override;
+ QSizeF physicalSize() const override { return m_physicalSize; }
+ QDpi logicalDpi() const override { return m_logicalDpi; }
+ qreal refreshRate() const override { return m_refreshRate; }
+ QString name() const override { return m_name; }
+ QPlatformCursor *cursor() const override { return m_cursor; }
+ QWindow *topLevelAt(const QPoint &point) const override;
+ QList<QPlatformScreen *> virtualSiblings() const override { return m_siblings; }
+ QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override;
+
+ // ----------------------------------------------------
+ // Additional methods
+ void setVirtualSiblings(const QList<QPlatformScreen *> &siblings) { m_siblings = siblings; }
+ NSScreen *nativeScreen() const;
+ void updateGeometry();
+
+ static QCocoaScreen *primaryScreen();
+
+ static CGPoint mapToNative(const QPointF &pos, QCocoaScreen *screen = QCocoaScreen::primaryScreen());
+ static CGRect mapToNative(const QRectF &rect, QCocoaScreen *screen = QCocoaScreen::primaryScreen());
+ static QPointF mapFromNative(CGPoint pos, QCocoaScreen *screen = QCocoaScreen::primaryScreen());
+ static QRectF mapFromNative(CGRect rect, QCocoaScreen *screen = QCocoaScreen::primaryScreen());
+
+public:
+ int m_screenIndex;
+ QRect m_geometry;
+ QRect m_availableGeometry;
+ QDpi m_logicalDpi;
+ qreal m_refreshRate;
+ int m_depth;
+ QString m_name;
+ QImage::Format m_format;
+ QSizeF m_physicalSize;
+ QCocoaCursor *m_cursor;
+ QList<QPlatformScreen *> m_siblings;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QCocoaScreen *screen);
+#endif
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm
new file mode 100644
index 0000000000..ed1b19cd53
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qcocoascreen.mm
@@ -0,0 +1,309 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "qcocoascreen.h"
+
+#include "qcocoawindow.h"
+#include "qcocoahelpers.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtGui/private/qcoregraphics_p.h>
+
+#include <IOKit/graphics/IOGraphicsLib.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCoreTextFontEngine;
+class QFontEngineFT;
+
+QCocoaScreen::QCocoaScreen(int screenIndex)
+ : QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0)
+{
+ updateGeometry();
+ m_cursor = new QCocoaCursor;
+}
+
+QCocoaScreen::~QCocoaScreen()
+{
+ delete m_cursor;
+}
+
+NSScreen *QCocoaScreen::nativeScreen() const
+{
+ NSArray *screens = [NSScreen screens];
+
+ // Stale reference, screen configuration has changed
+ if (m_screenIndex < 0 || (NSUInteger)m_screenIndex >= [screens count])
+ return nil;
+
+ return [screens objectAtIndex:m_screenIndex];
+}
+
+static QString displayName(CGDirectDisplayID displayID)
+{
+ QIOType<io_iterator_t> iterator;
+ if (IOServiceGetMatchingServices(kIOMasterPortDefault,
+ IOServiceMatching("IODisplayConnect"), &iterator))
+ return QString();
+
+ QIOType<io_service_t> display;
+ while ((display = IOIteratorNext(iterator)) != 0)
+ {
+ NSDictionary *info = [(__bridge NSDictionary*)IODisplayCreateInfoDictionary(
+ display, kIODisplayOnlyPreferredName) autorelease];
+
+ if ([[info objectForKey:@kDisplayVendorID] longValue] != CGDisplayVendorNumber(displayID))
+ continue;
+
+ if ([[info objectForKey:@kDisplayProductID] longValue] != CGDisplayModelNumber(displayID))
+ continue;
+
+ if ([[info objectForKey:@kDisplaySerialNumber] longValue] != CGDisplaySerialNumber(displayID))
+ continue;
+
+ NSDictionary *localizedNames = [info objectForKey:@kDisplayProductName];
+ if (![localizedNames count])
+ break; // Correct screen, but no name in dictionary
+
+ return QString::fromNSString([localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]]);
+ }
+
+ return QString();
+}
+
+void QCocoaScreen::updateGeometry()
+{
+ NSScreen *nsScreen = nativeScreen();
+ if (!nsScreen)
+ return;
+
+ // The reference screen for the geometry is always the primary screen
+ QRectF primaryScreenGeometry = QRectF::fromCGRect([[NSScreen screens] firstObject].frame);
+ m_geometry = qt_mac_flip(QRectF::fromCGRect(nsScreen.frame), primaryScreenGeometry).toRect();
+ m_availableGeometry = qt_mac_flip(QRectF::fromCGRect(nsScreen.visibleFrame), primaryScreenGeometry).toRect();
+
+ m_format = QImage::Format_RGB32;
+ m_depth = NSBitsPerPixelFromDepth([nsScreen depth]);
+
+ NSDictionary *devDesc = [nsScreen deviceDescription];
+ CGDirectDisplayID dpy = [[devDesc objectForKey:@"NSScreenNumber"] unsignedIntValue];
+ CGSize size = CGDisplayScreenSize(dpy);
+ m_physicalSize = QSizeF(size.width, size.height);
+ m_logicalDpi.first = 72;
+ m_logicalDpi.second = 72;
+ CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(dpy);
+ float refresh = CGDisplayModeGetRefreshRate(displayMode);
+ CGDisplayModeRelease(displayMode);
+ if (refresh > 0)
+ m_refreshRate = refresh;
+
+ m_name = displayName(dpy);
+
+ QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
+ QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), m_logicalDpi.first, m_logicalDpi.second);
+ QWindowSystemInterface::handleScreenRefreshRateChange(screen(), m_refreshRate);
+}
+
+qreal QCocoaScreen::devicePixelRatio() const
+{
+ QMacAutoReleasePool pool;
+ NSScreen *nsScreen = nativeScreen();
+ return qreal(nsScreen ? [nsScreen backingScaleFactor] : 1.0);
+}
+
+QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingTypeHint() const
+{
+ QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint();
+ if (type == QPlatformScreen::Subpixel_None) {
+ // Every OSX machine has RGB pixels unless a peculiar or rotated non-Apple screen is attached
+ type = QPlatformScreen::Subpixel_RGB;
+ }
+ return type;
+}
+
+QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const
+{
+ NSPoint screenPoint = mapToNative(point);
+
+ // Search (hit test) for the top-level window. [NSWidow windowNumberAtPoint:
+ // belowWindowWithWindowNumber] may return windows that are not interesting
+ // to Qt. The search iterates until a suitable window or no window is found.
+ NSInteger topWindowNumber = 0;
+ QWindow *window = 0;
+ do {
+ // Get the top-most window, below any previously rejected window.
+ topWindowNumber = [NSWindow windowNumberAtPoint:screenPoint
+ belowWindowWithWindowNumber:topWindowNumber];
+
+ // Continue the search if the window does not belong to this process.
+ NSWindow *nsWindow = [NSApp windowWithWindowNumber:topWindowNumber];
+ if (nsWindow == 0)
+ continue;
+
+ // Continue the search if the window does not belong to Qt.
+ if (![nsWindow conformsToProtocol:@protocol(QNSWindowProtocol)])
+ continue;
+
+ id<QNSWindowProtocol> proto = static_cast<id<QNSWindowProtocol> >(nsWindow);
+ QCocoaWindow *cocoaWindow = proto.platformWindow;
+ if (!cocoaWindow)
+ continue;
+ window = cocoaWindow->window();
+
+ // Continue the search if the window is not a top-level window.
+ if (!window->isTopLevel())
+ continue;
+
+ // Stop searching. The current window is the correct window.
+ break;
+ } while (topWindowNumber > 0);
+
+ return window;
+}
+
+QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height) const
+{
+ // TODO window should be handled
+ Q_UNUSED(window)
+
+ const int maxDisplays = 128; // 128 displays should be enough for everyone.
+ CGDirectDisplayID displays[maxDisplays];
+ CGDisplayCount displayCount;
+ CGRect cgRect;
+
+ if (width < 0 || height < 0) {
+ // get all displays
+ cgRect = CGRectInfinite;
+ } else {
+ cgRect = CGRectMake(x, y, width, height);
+ }
+ const CGDisplayErr err = CGGetDisplaysWithRect(cgRect, maxDisplays, displays, &displayCount);
+
+ if (err && displayCount == 0)
+ return QPixmap();
+
+ // calculate pixmap size
+ QSize windowSize(width, height);
+ if (width < 0 || height < 0) {
+ QRect windowRect;
+ for (uint i = 0; i < displayCount; ++i) {
+ const CGRect cgRect = CGDisplayBounds(displays[i]);
+ QRect qRect(cgRect.origin.x, cgRect.origin.y, cgRect.size.width, cgRect.size.height);
+ windowRect = windowRect.united(qRect);
+ }
+ if (width < 0)
+ windowSize.setWidth(windowRect.width());
+ if (height < 0)
+ windowSize.setHeight(windowRect.height());
+ }
+
+ QPixmap windowPixmap(windowSize * devicePixelRatio());
+ windowPixmap.fill(Qt::transparent);
+
+ for (uint i = 0; i < displayCount; ++i) {
+ const CGRect bounds = CGDisplayBounds(displays[i]);
+ int w = (width < 0 ? bounds.size.width : width) * devicePixelRatio();
+ int h = (height < 0 ? bounds.size.height : height) * devicePixelRatio();
+ QRect displayRect = QRect(x, y, w, h);
+ displayRect = displayRect.translated(qRound(-bounds.origin.x), qRound(-bounds.origin.y));
+ QCFType<CGImageRef> image = CGDisplayCreateImageForRect(displays[i],
+ CGRectMake(displayRect.x(), displayRect.y(), displayRect.width(), displayRect.height()));
+ QPixmap pix(w, h);
+ pix.fill(Qt::transparent);
+ CGRect rect = CGRectMake(0, 0, w, h);
+ QMacCGContext ctx(&pix);
+ qt_mac_drawCGImage(ctx, &rect, image);
+
+ QPainter painter(&windowPixmap);
+ painter.drawPixmap(0, 0, pix);
+ }
+ return windowPixmap;
+}
+
+/*!
+ The screen used as a reference for global window geometry
+*/
+QCocoaScreen *QCocoaScreen::primaryScreen()
+{
+ return static_cast<QCocoaScreen *>(QGuiApplication::primaryScreen()->handle());
+}
+
+CGPoint QCocoaScreen::mapToNative(const QPointF &pos, QCocoaScreen *screen)
+{
+ Q_ASSERT(screen);
+ return qt_mac_flip(pos, screen->geometry()).toCGPoint();
+}
+
+CGRect QCocoaScreen::mapToNative(const QRectF &rect, QCocoaScreen *screen)
+{
+ Q_ASSERT(screen);
+ return qt_mac_flip(rect, screen->geometry()).toCGRect();
+}
+
+QPointF QCocoaScreen::mapFromNative(CGPoint pos, QCocoaScreen *screen)
+{
+ Q_ASSERT(screen);
+ return qt_mac_flip(QPointF::fromCGPoint(pos), screen->geometry());
+}
+
+QRectF QCocoaScreen::mapFromNative(CGRect rect, QCocoaScreen *screen)
+{
+ Q_ASSERT(screen);
+ return qt_mac_flip(QRectF::fromCGRect(rect), screen->geometry());
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QCocoaScreen *screen)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QCocoaScreen(" << (const void *)screen;
+ if (screen) {
+ debug << ", index=" << screen->m_screenIndex;
+ debug << ", native=" << screen->nativeScreen();
+ debug << ", geometry=" << screen->geometry();
+ debug << ", dpr=" << screen->devicePixelRatio();
+ debug << ", name=" << screen->name();
+ }
+ debug << ')';
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaservices.h b/src/plugins/platforms/cocoa/qcocoaservices.h
index c2ceede0f0..62a8891f96 100644
--- a/src/plugins/platforms/cocoa/qcocoaservices.h
+++ b/src/plugins/platforms/cocoa/qcocoaservices.h
@@ -47,8 +47,8 @@ QT_BEGIN_NAMESPACE
class QCocoaServices : public QPlatformServices
{
public:
- bool openUrl(const QUrl &url) Q_DECL_OVERRIDE;
- bool openDocument(const QUrl &url) Q_DECL_OVERRIDE;
+ bool openUrl(const QUrl &url) override;
+ bool openDocument(const QUrl &url) override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
index 9ddad7fc7a..7c6f879b18 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -45,49 +45,8 @@
#include <QtGui/qfont.h>
#include <QtGui/private/qcoregraphics_p.h>
-#include <Carbon/Carbon.h>
-
QT_BEGIN_NAMESPACE
-QBrush qt_mac_brushForTheme(ThemeBrush brush)
-{
- QMacAutoReleasePool pool;
-
- QCFType<CGColorRef> cgClr = 0;
- HIThemeBrushCreateCGColor(brush, &cgClr);
- return qt_mac_toQBrush(cgClr);
-}
-
-QColor qt_mac_colorForThemeTextColor(ThemeTextColor themeColor)
-{
- // No GetThemeTextColor in 64-bit mode, use hardcoded values:
- switch (themeColor) {
- case kThemeTextColorAlertActive:
- case kThemeTextColorTabFrontActive:
- case kThemeTextColorBevelButtonActive:
- case kThemeTextColorListView:
- case kThemeTextColorPlacardActive:
- case kThemeTextColorPopupButtonActive:
- case kThemeTextColorPopupLabelActive:
- case kThemeTextColorPushButtonActive:
- return Qt::black;
- case kThemeTextColorAlertInactive:
- case kThemeTextColorDialogInactive:
- case kThemeTextColorPlacardInactive:
- case kThemeTextColorPopupButtonInactive:
- case kThemeTextColorPopupLabelInactive:
- case kThemeTextColorPushButtonInactive:
- case kThemeTextColorTabFrontInactive:
- case kThemeTextColorBevelButtonInactive:
- case kThemeTextColorMenuItemDisabled:
- return QColor(127, 127, 127, 255);
- case kThemeTextColorMenuItemSelected:
- return Qt::white;
- default:
- return QColor(0, 0, 0, 255); // ### TODO: Sample color like Qt 4.
- }
-}
-
QPalette * qt_mac_createSystemPalette()
{
QColor qc;
@@ -119,7 +78,7 @@ QPalette * qt_mac_createSystemPalette()
palette->setBrush(QPalette::Shadow, background.darker(170));
- qc = qt_mac_colorForThemeTextColor(kThemeTextColorDialogActive);
+ qc = qt_mac_toQColor([NSColor controlTextColor]);
palette->setColor(QPalette::Active, QPalette::Text, qc);
palette->setColor(QPalette::Active, QPalette::WindowText, qc);
palette->setColor(QPalette::Active, QPalette::HighlightedText, qc);
@@ -127,7 +86,7 @@ QPalette * qt_mac_createSystemPalette()
palette->setColor(QPalette::Inactive, QPalette::WindowText, qc);
palette->setColor(QPalette::Inactive, QPalette::HighlightedText, qc);
- qc = qt_mac_colorForThemeTextColor(kThemeTextColorDialogInactive);
+ qc = qt_mac_toQColor([NSColor disabledControlTextColor]);
palette->setColor(QPalette::Disabled, QPalette::Text, qc);
palette->setColor(QPalette::Disabled, QPalette::WindowText, qc);
palette->setColor(QPalette::Disabled, QPalette::HighlightedText, qc);
@@ -136,60 +95,66 @@ QPalette * qt_mac_createSystemPalette()
}
struct QMacPaletteMap {
- inline QMacPaletteMap(QPlatformTheme::Palette p, ThemeBrush a, ThemeBrush i) :
+ inline QMacPaletteMap(QPlatformTheme::Palette p, NSColor *a, NSColor *i) :
paletteRole(p), active(a), inactive(i) { }
QPlatformTheme::Palette paletteRole;
- ThemeBrush active, inactive;
+ NSColor *active, *inactive;
};
+#define MAC_PALETTE_ENTRY(pal, active, inactive) \
+ QMacPaletteMap(pal, [NSColor active], [NSColor inactive])
static QMacPaletteMap mac_widget_colors[] = {
- QMacPaletteMap(QPlatformTheme::ToolButtonPalette, kThemeTextColorBevelButtonActive, kThemeTextColorBevelButtonInactive),
- QMacPaletteMap(QPlatformTheme::ButtonPalette, kThemeTextColorPushButtonActive, kThemeTextColorPushButtonInactive),
- QMacPaletteMap(QPlatformTheme::HeaderPalette, kThemeTextColorPushButtonActive, kThemeTextColorPushButtonInactive),
- QMacPaletteMap(QPlatformTheme::ComboBoxPalette, kThemeTextColorPopupButtonActive, kThemeTextColorPopupButtonInactive),
- QMacPaletteMap(QPlatformTheme::ItemViewPalette, kThemeTextColorListView, kThemeTextColorDialogInactive),
- QMacPaletteMap(QPlatformTheme::MessageBoxLabelPalette, kThemeTextColorAlertActive, kThemeTextColorAlertInactive),
- QMacPaletteMap(QPlatformTheme::TabBarPalette, kThemeTextColorTabFrontActive, kThemeTextColorTabFrontInactive),
- QMacPaletteMap(QPlatformTheme::LabelPalette, kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive),
- QMacPaletteMap(QPlatformTheme::GroupBoxPalette, kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive),
- QMacPaletteMap(QPlatformTheme::MenuPalette, kThemeTextColorMenuItemActive, kThemeTextColorMenuItemDisabled),
- QMacPaletteMap(QPlatformTheme::MenuBarPalette, kThemeTextColorMenuItemActive, kThemeTextColorMenuItemDisabled),
- //### TODO: The zeros below gives white-on-black text.
- QMacPaletteMap(QPlatformTheme::TextEditPalette, 0, 0),
- QMacPaletteMap(QPlatformTheme::TextLineEditPalette, 0, 0),
- QMacPaletteMap(QPlatformTheme::NPalettes, 0, 0) };
+ MAC_PALETTE_ENTRY(QPlatformTheme::ToolButtonPalette, controlTextColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::ButtonPalette, controlTextColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::HeaderPalette, headerTextColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::ComboBoxPalette, controlTextColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::ItemViewPalette, textColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::MessageBoxLabelPalette, textColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::TabBarPalette, controlTextColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::LabelPalette, textColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::GroupBoxPalette, textColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::MenuPalette, controlTextColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::MenuBarPalette, controlTextColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::TextEditPalette, textColor, disabledControlTextColor),
+ MAC_PALETTE_ENTRY(QPlatformTheme::TextLineEditPalette, textColor, disabledControlTextColor)
+};
+#undef MAC_PALETTE_ENTRY
+
+static const int mac_widget_colors_count = sizeof(mac_widget_colors) / sizeof(mac_widget_colors[0]);
QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes()
{
QHash<QPlatformTheme::Palette, QPalette*> palettes;
QColor qc;
- for (int i = 0; mac_widget_colors[i].paletteRole != QPlatformTheme::NPalettes; i++) {
+ for (int i = 0; i < mac_widget_colors_count; i++) {
QPalette &pal = *qt_mac_createSystemPalette();
if (mac_widget_colors[i].active != 0) {
- qc = qt_mac_colorForThemeTextColor(mac_widget_colors[i].active);
+ qc = qt_mac_toQColor(mac_widget_colors[i].active);
pal.setColor(QPalette::Active, QPalette::Text, qc);
pal.setColor(QPalette::Inactive, QPalette::Text, qc);
pal.setColor(QPalette::Active, QPalette::WindowText, qc);
pal.setColor(QPalette::Inactive, QPalette::WindowText, qc);
pal.setColor(QPalette::Active, QPalette::HighlightedText, qc);
pal.setColor(QPalette::Inactive, QPalette::HighlightedText, qc);
- qc = qt_mac_colorForThemeTextColor(mac_widget_colors[i].inactive);
+ qc = qt_mac_toQColor(mac_widget_colors[i].inactive);
pal.setColor(QPalette::Disabled, QPalette::Text, qc);
pal.setColor(QPalette::Disabled, QPalette::WindowText, qc);
pal.setColor(QPalette::Disabled, QPalette::HighlightedText, qc);
}
if (mac_widget_colors[i].paletteRole == QPlatformTheme::MenuPalette
|| mac_widget_colors[i].paletteRole == QPlatformTheme::MenuBarPalette) {
- pal.setBrush(QPalette::Background, qt_mac_brushForTheme(kThemeBrushMenuBackground));
- qc = qt_mac_colorForThemeTextColor(kThemeTextColorMenuItemActive);
+ pal.setBrush(QPalette::Highlight, qt_mac_toQColor([NSColor selectedMenuItemColor]));
+ qc = qt_mac_toQColor([NSColor labelColor]);
pal.setBrush(QPalette::ButtonText, qc);
- qc = qt_mac_colorForThemeTextColor(kThemeTextColorMenuItemSelected);
+ pal.setBrush(QPalette::Text, qc);
+ qc = qt_mac_toQColor([NSColor selectedMenuItemTextColor]);
pal.setBrush(QPalette::HighlightedText, qc);
- qc = qt_mac_colorForThemeTextColor(kThemeTextColorMenuItemDisabled);
+ qc = qt_mac_toQColor([NSColor disabledControlTextColor]);
pal.setBrush(QPalette::Disabled, QPalette::Text, qc);
} else if ((mac_widget_colors[i].paletteRole == QPlatformTheme::ButtonPalette)
- || (mac_widget_colors[i].paletteRole == QPlatformTheme::HeaderPalette)) {
+ || (mac_widget_colors[i].paletteRole == QPlatformTheme::HeaderPalette)
+ || (mac_widget_colors[i].paletteRole == QPlatformTheme::TabBarPalette)) {
pal.setColor(QPalette::Disabled, QPalette::ButtonText,
pal.color(QPalette::Disabled, QPalette::Text));
pal.setColor(QPalette::Inactive, QPalette::ButtonText,
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
index d542a3cb8f..2f1a1e42a9 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
@@ -57,17 +57,17 @@ class Q_GUI_EXPORT QCocoaSystemTrayIcon : public QPlatformSystemTrayIcon
public:
QCocoaSystemTrayIcon() : m_sys(0) {}
- void init() Q_DECL_OVERRIDE;
- void cleanup() Q_DECL_OVERRIDE;
- void updateIcon(const QIcon &icon) Q_DECL_OVERRIDE;
- void updateToolTip(const QString &toolTip) Q_DECL_OVERRIDE;
- void updateMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE;
- QRect geometry() const Q_DECL_OVERRIDE;
+ void init() override;
+ void cleanup() override;
+ void updateIcon(const QIcon &icon) override;
+ void updateToolTip(const QString &toolTip) override;
+ void updateMenu(QPlatformMenu *menu) override;
+ QRect geometry() const override;
void showMessage(const QString &title, const QString &msg,
- const QIcon& icon, MessageIcon iconType, int secs) Q_DECL_OVERRIDE;
+ const QIcon& icon, MessageIcon iconType, int secs) override;
- bool isSystemTrayAvailable() const Q_DECL_OVERRIDE;
- bool supportsMessages() const Q_DECL_OVERRIDE;
+ bool isSystemTrayAvailable() const override;
+ bool supportsMessages() const override;
private:
QSystemTrayIconSys *m_sys;
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h
index 27c071a8cd..69eaf8db56 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.h
+++ b/src/plugins/platforms/cocoa/qcocoatheme.h
@@ -56,25 +56,25 @@ public:
void reset();
- QPlatformMenuItem* createPlatformMenuItem() const Q_DECL_OVERRIDE;
- QPlatformMenu* createPlatformMenu() const Q_DECL_OVERRIDE;
- QPlatformMenuBar* createPlatformMenuBar() const Q_DECL_OVERRIDE;
+ QPlatformMenuItem* createPlatformMenuItem() const override;
+ QPlatformMenu* createPlatformMenu() const override;
+ QPlatformMenuBar* createPlatformMenuBar() const override;
#ifndef QT_NO_SYSTEMTRAYICON
- QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const Q_DECL_OVERRIDE;
+ QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const override;
#endif
- bool usePlatformNativeDialog(DialogType dialogType) const Q_DECL_OVERRIDE;
- QPlatformDialogHelper *createPlatformDialogHelper(DialogType dialogType) const Q_DECL_OVERRIDE;
+ bool usePlatformNativeDialog(DialogType dialogType) const override;
+ QPlatformDialogHelper *createPlatformDialogHelper(DialogType dialogType) const override;
- const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE;
- const QFont *font(Font type = SystemFont) const Q_DECL_OVERRIDE;
- QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const Q_DECL_OVERRIDE;
+ const QPalette *palette(Palette type = SystemPalette) const override;
+ const QFont *font(Font type = SystemFont) const override;
+ QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override;
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions options = 0) const override;
- QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE;
- QString standardButtonText(int button) const Q_DECL_OVERRIDE;
- QKeySequence standardButtonShortcut(int button) const Q_DECL_OVERRIDE;
+ QVariant themeHint(ThemeHint hint) const override;
+ QString standardButtonText(int button) const override;
+ QKeySequence standardButtonShortcut(int button) const override;
static const char *name;
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index a1c1b379f7..93f0400916 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -55,6 +55,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/qpainter.h>
+#include <QtGui/qtextformat.h>
#include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
#include <QtThemeSupport/private/qabstractfileiconengine_p.h>
#include <qpa/qplatformdialoghelper.h>
@@ -97,7 +98,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaThemeNotificationReceiver);
{
Q_UNUSED(notification);
mPrivate->reset();
- QWindowSystemInterface::handleThemeChange(Q_NULLPTR);
+ QWindowSystemInterface::handleThemeChange(nullptr);
}
@end
@@ -126,7 +127,7 @@ QCocoaTheme::~QCocoaTheme()
void QCocoaTheme::reset()
{
delete m_systemPalette;
- m_systemPalette = Q_NULLPTR;
+ m_systemPalette = nullptr;
qDeleteAll(m_palettes);
m_palettes.clear();
}
@@ -274,7 +275,7 @@ QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
}
if (iconType != 0) {
QPixmap pixmap;
- IconRef icon = Q_NULLPTR;
+ IconRef icon = nullptr;
GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon);
if (icon) {
@@ -341,9 +342,13 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const
case IconPixmapSizes:
return QVariant::fromValue(QCocoaFileIconEngine::availableIconSizes());
case QPlatformTheme::PasswordMaskCharacter:
- return QVariant(QChar(kBulletUnicode));
+ return QVariant(QChar(0x2022));
case QPlatformTheme::UiEffects:
return QVariant(int(HoverEffect));
+ case QPlatformTheme::SpellCheckUnderlineStyle:
+ return QVariant(int(QTextCharFormat::DotLine));
+ case QPlatformTheme::UseFullScreenForPopupMenu:
+ return QVariant(bool([[NSApplication sharedApplication] presentationOptions] & NSApplicationPresentationFullScreen));
default:
break;
}
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index aa8fffdf7e..fb91c53a7a 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -50,82 +50,15 @@
#include "qcocoaglcontext.h"
#endif
#include "qnsview.h"
+#include "qnswindow.h"
#include "qt_mac_p.h"
-QT_FORWARD_DECLARE_CLASS(QCocoaWindow)
-
-@class QT_MANGLE_NAMESPACE(QNSWindowHelper);
-
-// @compatibility_alias doesn't work with protocols
-#define QNSWindowProtocol QT_MANGLE_NAMESPACE(QNSWindowProtocol)
-
-@protocol QNSWindowProtocol
-
-@property (nonatomic, readonly) QT_MANGLE_NAMESPACE(QNSWindowHelper) *helper;
-
-- (void)superSendEvent:(NSEvent *)theEvent;
-- (void)closeAndRelease;
-
-@end
-
-typedef NSWindow<QNSWindowProtocol> QCocoaNSWindow;
-
-@interface QT_MANGLE_NAMESPACE(QNSWindowHelper) : NSObject
-{
- QCocoaNSWindow *_window;
- QPointer<QCocoaWindow> _platformWindow;
- BOOL _grabbingMouse;
- BOOL _releaseOnMouseUp;
-}
-
-@property (nonatomic, readonly) QCocoaNSWindow *window;
-@property (nonatomic, readonly) QCocoaWindow *platformWindow;
-@property (nonatomic) BOOL grabbingMouse;
-@property (nonatomic) BOOL releaseOnMouseUp;
-
-- (id)initWithNSWindow:(QCocoaNSWindow *)window platformWindow:(QCocoaWindow *)platformWindow;
-- (void)handleWindowEvent:(NSEvent *)theEvent;
-- (void) clearWindow;
-
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindowHelper);
-
-@interface QT_MANGLE_NAMESPACE(QNSWindow) : NSWindow<QNSWindowProtocol>
-{
- QNSWindowHelper *_helper;
-}
-
-@property (nonatomic, readonly) QNSWindowHelper *helper;
-
-- (id)initWithContentRect:(NSRect)contentRect
- screen:(NSScreen*)screen
- styleMask:(NSUInteger)windowStyle
- qPlatformWindow:(QCocoaWindow *)qpw;
-
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindow);
-
-@interface QT_MANGLE_NAMESPACE(QNSPanel) : NSPanel<QNSWindowProtocol>
-{
- QNSWindowHelper *_helper;
-}
-
-@property (nonatomic, readonly) QNSWindowHelper *helper;
-
-- (id)initWithContentRect:(NSRect)contentRect
- screen:(NSScreen*)screen
- styleMask:(NSUInteger)windowStyle
- qPlatformWindow:(QCocoaWindow *)qpw;
-
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSPanel);
+QT_BEGIN_NAMESPACE
-@class QT_MANGLE_NAMESPACE(QNSWindowDelegate);
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+#endif
-QT_BEGIN_NAMESPACE
// QCocoaWindow
//
// QCocoaWindow is an NSView (not an NSWindow!) in the sense
@@ -162,50 +95,51 @@ public:
QCocoaWindow(QWindow *tlw, WId nativeHandle = 0);
~QCocoaWindow();
- void setGeometry(const QRect &rect) Q_DECL_OVERRIDE;
- QRect geometry() const Q_DECL_OVERRIDE;
+ void initialize() override;
+
+ void setGeometry(const QRect &rect) override;
+ QRect geometry() const override;
void setCocoaGeometry(const QRect &rect);
- void clipChildWindows();
- void clipWindow(const NSRect &clipRect);
- void show(bool becauseOfAncestor = false);
- void hide(bool becauseOfAncestor = false);
- void setVisible(bool visible) Q_DECL_OVERRIDE;
- void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE;
- void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE;
- void setWindowTitle(const QString &title) Q_DECL_OVERRIDE;
- void setWindowFilePath(const QString &filePath) Q_DECL_OVERRIDE;
- void setWindowIcon(const QIcon &icon) Q_DECL_OVERRIDE;
- void setAlertState(bool enabled) Q_DECL_OVERRIDE;
- bool isAlertState() const Q_DECL_OVERRIDE;
- void raise() Q_DECL_OVERRIDE;
- void lower() Q_DECL_OVERRIDE;
- bool isExposed() const Q_DECL_OVERRIDE;
+
+ void setVisible(bool visible) override;
+ void setWindowFlags(Qt::WindowFlags flags) override;
+ void setWindowState(Qt::WindowStates state) override;
+ void setWindowTitle(const QString &title) override;
+ void setWindowFilePath(const QString &filePath) override;
+ void setWindowIcon(const QIcon &icon) override;
+ void setAlertState(bool enabled) override;
+ bool isAlertState() const override;
+ void raise() override;
+ void lower() override;
+ bool isExposed() const override;
bool isOpaque() const;
- void propagateSizeHints() Q_DECL_OVERRIDE;
- void setOpacity(qreal level) Q_DECL_OVERRIDE;
- void setMask(const QRegion &region) Q_DECL_OVERRIDE;
- bool setKeyboardGrabEnabled(bool grab) Q_DECL_OVERRIDE;
- bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE;
- QMargins frameMargins() const Q_DECL_OVERRIDE;
- QSurfaceFormat format() const Q_DECL_OVERRIDE;
+ void propagateSizeHints() override;
+ void setOpacity(qreal level) override;
+ void setMask(const QRegion &region) override;
+ bool setKeyboardGrabEnabled(bool grab) override;
+ bool setMouseGrabEnabled(bool grab) override;
+ QMargins frameMargins() const override;
+ QSurfaceFormat format() const override;
- bool isForeignWindow() const Q_DECL_OVERRIDE;
+ bool isForeignWindow() const override;
- void requestActivateWindow() Q_DECL_OVERRIDE;
+ void requestUpdate() override;
+ void requestActivateWindow() override;
- WId winId() const Q_DECL_OVERRIDE;
- void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE;
+ WId winId() const override;
+ void setParent(const QPlatformWindow *window) override;
NSView *view() const;
NSWindow *nativeWindow() const;
void setEmbeddedInForeignView(bool subwindow);
+ Q_NOTIFICATION_HANDLER(NSViewFrameDidChangeNotification) void viewDidChangeFrame();
+ Q_NOTIFICATION_HANDLER(NSViewGlobalFrameDidChangeNotification) void viewDidChangeGlobalFrame();
+
Q_NOTIFICATION_HANDLER(NSWindowWillMoveNotification) void windowWillMove();
Q_NOTIFICATION_HANDLER(NSWindowDidMoveNotification) void windowDidMove();
Q_NOTIFICATION_HANDLER(NSWindowDidResizeNotification) void windowDidResize();
- Q_NOTIFICATION_HANDLER(NSViewFrameDidChangeNotification) void viewDidChangeFrame();
- Q_NOTIFICATION_HANDLER(NSViewGlobalFrameDidChangeNotification) void viewDidChangeGlobalFrame();
Q_NOTIFICATION_HANDLER(NSWindowDidEndLiveResizeNotification) void windowDidEndLiveResize();
Q_NOTIFICATION_HANDLER(NSWindowDidBecomeKeyNotification) void windowDidBecomeKey();
Q_NOTIFICATION_HANDLER(NSWindowDidResignKeyNotification) void windowDidResignKey();
@@ -215,8 +149,8 @@ public:
Q_NOTIFICATION_HANDLER(NSWindowDidEnterFullScreenNotification) void windowDidEnterFullScreen();
Q_NOTIFICATION_HANDLER(NSWindowWillExitFullScreenNotification) void windowWillExitFullScreen();
Q_NOTIFICATION_HANDLER(NSWindowDidExitFullScreenNotification) void windowDidExitFullScreen();
- Q_NOTIFICATION_HANDLER(NSWindowDidOrderOffScreenNotification) void windowDidOrderOffScreen();
Q_NOTIFICATION_HANDLER(NSWindowDidOrderOnScreenAndFinishAnimatingNotification) void windowDidOrderOnScreen();
+ Q_NOTIFICATION_HANDLER(NSWindowDidOrderOffScreenNotification) void windowDidOrderOffScreen();
Q_NOTIFICATION_HANDLER(NSWindowDidChangeOcclusionStateNotification) void windowDidChangeOcclusionState();
Q_NOTIFICATION_HANDLER(NSWindowDidChangeScreenNotification) void windowDidChangeScreen();
Q_NOTIFICATION_HANDLER(NSWindowWillCloseNotification) void windowWillClose();
@@ -224,11 +158,8 @@ public:
bool windowShouldClose();
bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const;
- void reportCurrentWindowState(bool unconditionally = false);
-
NSInteger windowLevel(Qt::WindowFlags flags);
NSUInteger windowStyleMask(Qt::WindowFlags flags);
- void setWindowShadow(Qt::WindowFlags flags);
void setWindowZoomButton(Qt::WindowFlags flags);
#ifndef QT_NO_OPENGL
@@ -236,17 +167,15 @@ public:
QCocoaGLContext *currentContext() const;
#endif
- bool setWindowModified(bool modified) Q_DECL_OVERRIDE;
+ bool setWindowModified(bool modified) override;
- void setFrameStrutEventsEnabled(bool enabled) Q_DECL_OVERRIDE;
- bool frameStrutEventsEnabled() const Q_DECL_OVERRIDE
+ void setFrameStrutEventsEnabled(bool enabled) override;
+ bool frameStrutEventsEnabled() const override
{ return m_frameStrutEventsEnabled; }
void setMenubar(QCocoaMenuBar *mb);
QCocoaMenuBar *menubar() const;
- NSCursor *effectiveWindowCursor() const;
- void applyEffectiveWindowCursor();
void setWindowCursor(NSCursor *cursor);
void registerTouch(bool enable);
@@ -255,14 +184,10 @@ public:
void setContentBorderAreaEnabled(quintptr identifier, bool enable);
void setContentBorderEnabled(bool enable);
bool testContentBorderAreaPosition(int position) const;
- void applyContentBorderThickness(NSWindow *window);
+ void applyContentBorderThickness(NSWindow *window = nullptr);
void updateNSToolbar();
- qreal devicePixelRatio() const Q_DECL_OVERRIDE;
- bool isWindowExposable();
- void exposeWindow();
- void obscureWindow();
- void updateExposedGeometry();
+ qreal devicePixelRatio() const override;
QWindow *childWindowAt(QPoint windowPoint);
bool shouldRefuseKeyWindowAndFirstResponder();
@@ -274,7 +199,6 @@ public:
ParentChanged = 0x1,
MissingWindow = 0x2,
WindowModalityChanged = 0x4,
- ChildNSWindowChanged = 0x8,
ContentViewChanged = 0x10,
PanelChanged = 0x20,
};
@@ -282,20 +206,11 @@ public:
Q_FLAG(RecreationReasons)
protected:
- bool isChildNSWindow() const;
- bool isContentView() const;
-
- void foreachChildNSWindow(void (^block)(QCocoaWindow *));
-
void recreateWindowIfNeeded();
- QCocoaNSWindow *createNSWindow(bool shouldBeChildNSWindow, bool shouldBePanel);
-
- QRect nativeWindowGeometry() const;
- void reinsertChildWindow(QCocoaWindow *child);
- void removeChildWindow(QCocoaWindow *child);
+ QCocoaNSWindow *createNSWindow(bool shouldBePanel);
Qt::WindowState windowState() const;
- void applyWindowState(Qt::WindowState newState);
+ void applyWindowState(Qt::WindowStates newState);
void toggleMaximized();
void toggleFullScreen();
bool isTransitioningToFullScreen() const;
@@ -305,24 +220,34 @@ public: // for QNSView
friend class QCocoaBackingStore;
friend class QCocoaNativeInterface;
+ bool isContentView() const;
+
bool alwaysShowToolWindow() const;
void removeMonitor();
+ enum HandleFlags {
+ NoHandleFlags = 0,
+ HandleUnconditionally = 1
+ };
+
+ void handleGeometryChange();
+ void handleWindowStateChanged(HandleFlags flags = NoHandleFlags);
+ void handleExposeEvent(const QRegion &region);
+
NSView *m_view;
QCocoaNSWindow *m_nsWindow;
- QPointer<QCocoaWindow> m_forwardWindow;
// TODO merge to one variable if possible
bool m_viewIsEmbedded; // true if the m_view is actually embedded in a "foreign" NSView hiearchy
bool m_viewIsToBeEmbedded; // true if the m_view is intended to be embedded in a "foreign" NSView hiearchy
Qt::WindowFlags m_windowFlags;
- Qt::WindowState m_lastReportedWindowState;
+ Qt::WindowStates m_lastReportedWindowState;
Qt::WindowModality m_windowModality;
QPointer<QWindow> m_enterLeaveTargetWindow;
bool m_windowUnderMouse;
- bool m_inConstructor;
+ bool m_initialized;
bool m_inSetVisible;
bool m_inSetGeometry;
bool m_inSetStyleMask;
@@ -330,18 +255,14 @@ public: // for QNSView
QCocoaGLContext *m_glContext;
#endif
QCocoaMenuBar *m_menubar;
- NSCursor *m_windowCursor;
+
+ bool m_needsInvalidateShadow;
bool m_hasModalSession;
bool m_frameStrutEventsEnabled;
- bool m_geometryUpdateExposeAllowed;
- bool m_isExposed;
- QRect m_exposedGeometry;
- qreal m_exposedDevicePixelRatio;
+ QRect m_exposedRect;
int m_registerTouchCount;
bool m_resizableTransientParent;
- bool m_hiddenByClipping;
- bool m_hiddenByAncestor;
static const int NoAlertRequest;
NSInteger m_alertRequest;
@@ -362,10 +283,12 @@ public: // for QNSView
};
QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower
QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false)
-
- bool m_hasWindowFilePath;
};
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QCocoaWindow *window);
+#endif
+
QT_END_NAMESPACE
#endif // QCOCOAWINDOW_H
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index aeeef55598..562872a300 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qcocoawindow.h"
#include "qcocoaintegration.h"
+#include "qcocoascreen.h"
#include "qnswindowdelegate.h"
#include "qcocoaeventdispatcher.h"
#ifndef QT_NO_OPENGL
@@ -46,6 +47,7 @@
#include "qcocoahelpers.h"
#include "qcocoanativeinterface.h"
#include "qnsview.h"
+#include "qnswindow.h"
#include <QtCore/qfileinfo.h>
#include <QtCore/private/qcore_mac_p.h>
#include <qwindow.h>
@@ -53,34 +55,22 @@
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformscreen.h>
#include <QtGui/private/qcoregraphics_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <AppKit/AppKit.h>
+#include <QuartzCore/QuartzCore.h>
#include <QDebug>
#include <vector>
+QT_BEGIN_NAMESPACE
+
enum {
defaultWindowWidth = 160,
defaultWindowHeight = 160
};
-static bool isMouseEvent(NSEvent *ev)
-{
- switch ([ev type]) {
- case NSLeftMouseDown:
- case NSLeftMouseUp:
- case NSRightMouseDown:
- case NSRightMouseUp:
- case NSMouseMoved:
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- return true;
- default:
- return false;
- }
-}
-
static void qt_closePopups()
{
while (QCocoaWindow *popup = QCocoaIntegration::instance()->popPopupWindow()) {
@@ -89,377 +79,7 @@ static void qt_closePopups()
}
}
-
-// @compatibility_alias doesn't work with categories or their methods
-#define FullScreenProperty QT_MANGLE_NAMESPACE(FullScreenProperty)
-#define qt_fullScreen QT_MANGLE_NAMESPACE(qt_fullScreen)
-
-@interface NSWindow (FullScreenProperty)
-@property(readonly) BOOL qt_fullScreen;
-@end
-
-@implementation NSWindow (FullScreenProperty)
-
-+ (void)load
-{
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- [center addObserverForName:NSWindowDidEnterFullScreenNotification object:nil queue:nil
- usingBlock:^(NSNotification *notification) {
- objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
- [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_RETAIN);
- }
- ];
- [center addObserverForName:NSWindowDidExitFullScreenNotification object:nil queue:nil
- usingBlock:^(NSNotification *notification) {
- objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
- nil, OBJC_ASSOCIATION_RETAIN);
- }
- ];
-}
-
-- (BOOL)qt_fullScreen
-{
- NSNumber *number = objc_getAssociatedObject(self, @selector(qt_fullScreen));
- return [number boolValue];
-}
-@end
-
-@implementation QNSWindowHelper
-
-@synthesize window = _window;
-@synthesize grabbingMouse = _grabbingMouse;
-@synthesize releaseOnMouseUp = _releaseOnMouseUp;
-
-- (QCocoaWindow *)platformWindow
-{
- return _platformWindow.data();
-}
-
-- (id)initWithNSWindow:(QCocoaNSWindow *)window platformWindow:(QCocoaWindow *)platformWindow
-{
- self = [super init];
- if (self) {
- _window = window;
- _platformWindow = platformWindow;
-
- _window.delegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:_platformWindow];
-
- // Prevent Cocoa from releasing the window on close. Qt
- // handles the close event asynchronously and we want to
- // make sure that m_nsWindow stays valid until the
- // QCocoaWindow is deleted by Qt.
- [_window setReleasedWhenClosed:NO];
- }
-
- return self;
-}
-
-- (void)handleWindowEvent:(NSEvent *)theEvent
-{
- QCocoaWindow *pw = self.platformWindow;
- if (pw && pw->m_forwardWindow) {
- if (theEvent.type == NSLeftMouseUp || theEvent.type == NSLeftMouseDragged) {
- QNSView *forwardView = qnsview_cast(pw->view());
- if (theEvent.type == NSLeftMouseUp) {
- [forwardView mouseUp:theEvent];
- pw->m_forwardWindow.clear();
- } else {
- [forwardView mouseDragged:theEvent];
- }
- }
- if (pw->window()->isTopLevel() && theEvent.type == NSLeftMouseDown) {
- pw->m_forwardWindow.clear();
- }
- }
-
- if (theEvent.type == NSLeftMouseDown) {
- self.grabbingMouse = YES;
- } else if (theEvent.type == NSLeftMouseUp) {
- self.grabbingMouse = NO;
- if (self.releaseOnMouseUp) {
- [self detachFromPlatformWindow];
- [self.window release];
- return;
- }
- }
-
- // The call to -[NSWindow sendEvent] may result in the window being deleted
- // (e.g., when closing the window by pressing the title bar close button).
- [self retain];
- [self.window superSendEvent:theEvent];
- bool windowStillAlive = self.window != nil; // We need to read before releasing
- [self release];
- if (!windowStillAlive)
- return;
-
- if (!self.window.delegate)
- return; // Already detached, pending NSAppKitDefined event
-
- if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) {
- NSPoint loc = [theEvent locationInWindow];
- NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]];
- NSRect contentFrame = [[self.window contentView] frame];
- if (NSMouseInRect(loc, windowFrame, NO) && !NSMouseInRect(loc, contentFrame, NO))
- [qnsview_cast(pw->view()) handleFrameStrutMouseEvent:theEvent];
- }
-}
-
-- (void)detachFromPlatformWindow
-{
- _platformWindow.clear();
- [self.window.delegate release];
- self.window.delegate = nil;
-}
-
-- (void)clearWindow
-{
- if (_window) {
- QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
- if (cocoaEventDispatcher) {
- QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
- cocoaEventDispatcherPrivate->removeQueuedUserInputEvents([_window windowNumber]);
- }
-
- _window = nil;
- }
-}
-
-- (void)dealloc
-{
- _window = nil;
- _platformWindow.clear();
- [super dealloc];
-}
-
-@end
-
-@implementation QNSWindow
-
-@synthesize helper = _helper;
-
-- (id)initWithContentRect:(NSRect)contentRect
- screen:(NSScreen*)screen
- styleMask:(NSUInteger)windowStyle
- qPlatformWindow:(QCocoaWindow *)qpw
-{
- self = [super initWithContentRect:contentRect
- styleMask:windowStyle
- backing:NSBackingStoreBuffered
- defer:NO screen:screen]; // Deferring window creation breaks OpenGL (the GL context is
- // set up before the window is shown and needs a proper window)
-
- if (self) {
- _helper = [[QNSWindowHelper alloc] initWithNSWindow:self platformWindow:qpw];
- }
- return self;
-}
-
-- (BOOL)canBecomeKeyWindow
-{
- // Prevent child NSWindows from becoming the key window in
- // order keep the active apperance of the top-level window.
- QCocoaWindow *pw = self.helper.platformWindow;
- if (!pw || !pw->window()->isTopLevel())
- return NO;
-
- if (pw->shouldRefuseKeyWindowAndFirstResponder())
- return NO;
-
- // The default implementation returns NO for title-bar less windows,
- // override and return yes here to make sure popup windows such as
- // the combobox popup can become the key window.
- return YES;
-}
-
-- (BOOL)canBecomeMainWindow
-{
- BOOL canBecomeMain = YES; // By default, windows can become the main window
-
- // Windows with a transient parent (such as combobox popup windows)
- // cannot become the main window:
- QCocoaWindow *pw = self.helper.platformWindow;
- if (!pw || !pw->window()->isTopLevel() || pw->window()->transientParent())
- canBecomeMain = NO;
-
- return canBecomeMain;
-}
-
-- (void) sendEvent: (NSEvent*) theEvent
-{
- [self.helper handleWindowEvent:theEvent];
-}
-
-- (void)superSendEvent:(NSEvent *)theEvent
-{
- [super sendEvent:theEvent];
-}
-
-- (void)closeAndRelease
-{
- qCDebug(lcQpaCocoaWindow) << "closeAndRelease" << self;
-
- [self close];
-
- if (self.helper.grabbingMouse) {
- self.helper.releaseOnMouseUp = YES;
- } else {
- [self.helper detachFromPlatformWindow];
- [self release];
- }
-}
-
-- (void)dealloc
-{
- [_helper clearWindow];
- [_helper release];
- _helper = nil;
- [super dealloc];
-}
-
-@end
-
-@implementation QNSPanel
-
-@synthesize helper = _helper;
-
-+ (void)applicationActivationChanged:(NSNotification*)notification
-{
- const id sender = self;
- NSEnumerator<NSWindow*> *windowEnumerator = nullptr;
- NSApplication *application = [NSApplication sharedApplication];
-
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12)
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSSierra) {
- // Unfortunately there's no NSWindowListOrderedBackToFront,
- // so we have to manually reverse the order using an array.
- NSMutableArray *windows = [[[NSMutableArray alloc] init] autorelease];
- [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
- usingBlock:^(NSWindow *window, BOOL *) {
- // For some reason AppKit will give us nil-windows, skip those
- if (!window)
- return;
-
- [(NSMutableArray*)windows addObject:window];
- }
- ];
-
- windowEnumerator = windows.reverseObjectEnumerator;
- } else
-#endif
- {
- // No way to get ordered list of windows, so fall back to unordered,
- // list, which typically corresponds to window creation order.
- windowEnumerator = application.windows.objectEnumerator;
- }
-
- for (NSWindow *window in windowEnumerator) {
- // We're meddling with normal and floating windows, so leave others alone
- if (!(window.level == NSNormalWindowLevel || window.level == NSFloatingWindowLevel))
- continue;
-
- // Windows that hide automatically will keep their NSFloatingWindowLevel,
- // and hence be on top of the window stack. We don't want to affect these
- // windows, as otherwise we might end up with key windows being ordered
- // behind these auto-hidden windows when activating the application by
- // clicking on a new tool window.
- if (window.hidesOnDeactivate)
- continue;
-
- if ([window conformsToProtocol:@protocol(QNSWindowProtocol)]) {
- QCocoaWindow *cocoaWindow = static_cast<id<QNSWindowProtocol>>(window).helper.platformWindow;
- window.level = notification.name == NSApplicationWillResignActiveNotification ?
- NSNormalWindowLevel : cocoaWindow->windowLevel(cocoaWindow->window()->flags());
- }
-
- // The documentation says that "when a window enters a new level, it’s ordered
- // in front of all its peers in that level", but that doesn't seem to be the
- // case in practice. To keep the order correct after meddling with the window
- // levels, we explicitly order each window to the front. Since we are iterating
- // the windows in back-to-front order, this is okey. The call also triggers AppKit
- // to re-evaluate the level in relation to windows from other applications,
- // working around an issue where our tool windows would stay on top of other
- // application windows if activation was transferred to another application by
- // clicking on it instead of via the application switcher or Dock. Finally, we
- // do this re-ordering for all windows (except auto-hiding ones), otherwise we would
- // end up triggering a bug in AppKit where the tool windows would disappear behind
- // the application window.
- [window orderFront:sender];
- }
-}
-
-- (id)initWithContentRect:(NSRect)contentRect
- screen:(NSScreen*)screen
- styleMask:(NSUInteger)windowStyle
- qPlatformWindow:(QCocoaWindow *)qpw
-{
- self = [super initWithContentRect:contentRect
- styleMask:windowStyle
- backing:NSBackingStoreBuffered
- defer:NO screen:screen]; // Deferring window creation breaks OpenGL (the GL context is
- // set up before the window is shown and needs a proper window)
-
- if (self) {
- _helper = [[QNSWindowHelper alloc] initWithNSWindow:self platformWindow:qpw];
-
- if (qpw->alwaysShowToolWindow()) {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
- [center addObserver:[self class] selector:@selector(applicationActivationChanged:)
- name:NSApplicationWillResignActiveNotification object:nil];
- [center addObserver:[self class] selector:@selector(applicationActivationChanged:)
- name:NSApplicationWillBecomeActiveNotification object:nil];
- });
- }
- }
- return self;
-}
-
-- (BOOL)canBecomeKeyWindow
-{
- QCocoaWindow *pw = self.helper.platformWindow;
- if (!pw)
- return NO;
-
- if (pw->shouldRefuseKeyWindowAndFirstResponder())
- return NO;
-
- // Only tool or dialog windows should become key:
- Qt::WindowType type = pw->window()->type();
- if (type == Qt::Tool || type == Qt::Dialog)
- return YES;
-
- return NO;
-}
-
-- (void) sendEvent: (NSEvent*) theEvent
-{
- [self.helper handleWindowEvent:theEvent];
-}
-
-- (void)superSendEvent:(NSEvent *)theEvent
-{
- [super sendEvent:theEvent];
-}
-
-- (void)closeAndRelease
-{
- qCDebug(lcQpaCocoaWindow) << "closeAndRelease" << self;
-
- [self.helper detachFromPlatformWindow];
- [self close];
- [self release];
-}
-
-- (void)dealloc
-{
- [_helper clearWindow];
- [_helper release];
- _helper = nil;
- [super dealloc];
-}
-
-@end
+Q_LOGGING_CATEGORY(lcCocoaNotifications, "qt.qpa.cocoa.notifications");
static void qRegisterNotificationCallbacks()
{
@@ -480,38 +100,43 @@ static void qRegisterNotificationCallbacks()
[center addObserverForName:notificationName.toNSString() object:nil queue:nil
usingBlock:^(NSNotification *notification) {
- NSView *view = nullptr;
+ QVarLengthArray<QCocoaWindow *, 32> cocoaWindows;
if ([notification.object isKindOfClass:[NSWindow class]]) {
- NSWindow *window = notification.object;
- // Only top level NSWindows should notify their QNSViews
- if (window.parentWindow)
- return;
-
- if (!window.contentView)
- return;
-
- view = window.contentView;
+ NSWindow *nsWindow = notification.object;
+ for (const QWindow *window : QGuiApplication::allWindows()) {
+ if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()))
+ if (cocoaWindow->nativeWindow() == nsWindow)
+ cocoaWindows += cocoaWindow;
+ }
} else if ([notification.object isKindOfClass:[NSView class]]) {
- view = notification.object;
+ if (QNSView *qnsView = qnsview_cast(notification.object))
+ cocoaWindows += qnsView.platformWindow;
} else {
- qCWarning(lcQpaCocoaWindow) << "Unhandled notifcation"
+ qCWarning(lcCocoaNotifications) << "Unhandled notifcation"
<< notification.name << "for" << notification.object;
return;
}
- Q_ASSERT(view);
- QCocoaWindow *cocoaWindow = nullptr;
- if (QNSView *qnsView = qnsview_cast(view))
- cocoaWindow = qnsView.platformWindow;
+ if (lcCocoaNotifications().isDebugEnabled()) {
+ if (cocoaWindows.isEmpty()) {
+ qCDebug(lcCocoaNotifications) << "Could not find forwarding target for" <<
+ qPrintable(notificationName) << "from" << notification.object;
+ } else {
+ QVector<QCocoaWindow *> debugWindows;
+ for (QCocoaWindow *cocoaWindow : cocoaWindows)
+ debugWindows += cocoaWindow;
+ qCDebug(lcCocoaNotifications) << "Forwarding" << qPrintable(notificationName) <<
+ "to" << debugWindows;
+ }
+ }
// FIXME: Could be a foreign window, look up by iterating top level QWindows
- if (!cocoaWindow)
- return;
-
- if (!method.invoke(cocoaWindow, Qt::DirectConnection)) {
- qCWarning(lcQpaCocoaWindow) << "Failed to invoke NSNotification callback for"
- << notification.name << "on" << cocoaWindow;
+ for (QCocoaWindow *cocoaWindow : cocoaWindows) {
+ if (!method.invoke(cocoaWindow, Qt::DirectConnection)) {
+ qCWarning(lcQpaCocoaWindow) << "Failed to invoke NSNotification callback for"
+ << notification.name << "on" << cocoaWindow;
+ }
}
}];
}
@@ -520,8 +145,8 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterNotificationCallbacks)
const int QCocoaWindow::NoAlertRequest = -1;
-QCocoaWindow::QCocoaWindow(QWindow *tlw, WId nativeHandle)
- : QPlatformWindow(tlw)
+QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
+ : QPlatformWindow(win)
, m_view(nil)
, m_nsWindow(0)
, m_viewIsEmbedded(false)
@@ -529,7 +154,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw, WId nativeHandle)
, m_lastReportedWindowState(Qt::WindowNoState)
, m_windowModality(Qt::NonModal)
, m_windowUnderMouse(false)
- , m_inConstructor(true)
+ , m_initialized(false)
, m_inSetVisible(false)
, m_inSetGeometry(false)
, m_inSetStyleMask(false)
@@ -537,42 +162,45 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw, WId nativeHandle)
, m_glContext(0)
#endif
, m_menubar(0)
- , m_windowCursor(0)
+ , m_needsInvalidateShadow(false)
, m_hasModalSession(false)
, m_frameStrutEventsEnabled(false)
- , m_geometryUpdateExposeAllowed(false)
- , m_isExposed(false)
, m_registerTouchCount(0)
, m_resizableTransientParent(false)
- , m_hiddenByClipping(false)
- , m_hiddenByAncestor(false)
, m_alertRequest(NoAlertRequest)
, monitor(nil)
, m_drawContentBorderGradient(false)
, m_topContentBorderThickness(0)
, m_bottomContentBorderThickness(0)
- , m_hasWindowFilePath(false)
{
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::QCocoaWindow" << window();
- QMacAutoReleasePool pool;
-
if (nativeHandle) {
m_view = reinterpret_cast<NSView *>(nativeHandle);
[m_view retain];
- } else {
+ }
+}
+
+void QCocoaWindow::initialize()
+{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::initialize" << window();
+
+ QMacAutoReleasePool pool;
+
+ if (!m_view) {
m_view = [[QNSView alloc] initWithCocoaWindow:this];
// Enable high-dpi OpenGL for retina displays. Enabling has the side
// effect that Cocoa will start calling glViewport(0, 0, width, height),
// overriding any glViewport calls in application code. This is usually not a
// problem, except if the appilcation wants to have a "custom" viewport.
// (like the hellogl example)
- if (tlw->supportsOpenGL()) {
- BOOL enable = qt_mac_resolveOption(YES, tlw, "_q_mac_wantsBestResolutionOpenGLSurface",
+ if (window()->supportsOpenGL()) {
+ BOOL enable = qt_mac_resolveOption(YES, window(), "_q_mac_wantsBestResolutionOpenGLSurface",
"QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE");
[m_view setWantsBestResolutionOpenGLSurface:enable];
+ // See also QCocoaGLContext::makeCurrent for software renderer workarounds.
}
- BOOL enable = qt_mac_resolveOption(NO, tlw, "_q_mac_wantsLayer",
+ BOOL enable = qt_mac_resolveOption(NO, window(), "_q_mac_wantsLayer",
"QT_MAC_WANTS_LAYER");
[m_view setWantsLayer:enable];
}
@@ -580,10 +208,11 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw, WId nativeHandle)
setGeometry(initialGeometry(window(), windowGeometry(), defaultWindowWidth, defaultWindowHeight));
recreateWindowIfNeeded();
- tlw->setGeometry(geometry());
- if (tlw->isTopLevel())
- setWindowIcon(tlw->icon());
- m_inConstructor = false;
+ window()->setGeometry(geometry());
+ if (window()->isTopLevel())
+ setWindowIcon(window()->icon());
+
+ m_initialized = true;
}
QCocoaWindow::~QCocoaWindow()
@@ -593,10 +222,7 @@ QCocoaWindow::~QCocoaWindow()
QMacAutoReleasePool pool;
[m_nsWindow makeFirstResponder:nil];
[m_nsWindow setContentView:nil];
- [m_nsWindow.helper detachFromPlatformWindow];
- if (m_view.window.parentWindow)
- [m_view.window.parentWindow removeChildWindow:m_view.window];
- else if ([m_view superview])
+ if ([m_view superview])
[m_view removeFromSuperview];
removeMonitor();
@@ -612,13 +238,8 @@ QCocoaWindow::~QCocoaWindow()
QCocoaIntegration::instance()->popupWindowStack()->removeAll(this);
}
- foreachChildNSWindow(^(QCocoaWindow *childWindow) {
- [m_nsWindow removeChildWindow:childWindow->m_nsWindow];
- });
-
[m_view release];
[m_nsWindow release];
- [m_windowCursor release];
}
QSurfaceFormat QCocoaWindow::format() const
@@ -666,7 +287,7 @@ QRect QCocoaWindow::geometry() const
NSPoint windowPoint = [m_view convertPoint:NSMakePoint(0, 0) toView:nil];
NSRect screenRect = [[m_view window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
NSPoint screenPoint = screenRect.origin;
- QPoint position = qt_mac_flipPoint(screenPoint).toPoint();
+ QPoint position = QCocoaScreen::mapFromNative(screenPoint).toPoint();
QSize size = QRectF::fromCGRect(NSRectToCGRect([m_view bounds])).toRect().size();
return QRect(position, size);
}
@@ -679,134 +300,29 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setCocoaGeometry" << window() << rect;
QMacAutoReleasePool pool;
+ QPlatformWindow::setGeometry(rect);
+
if (m_viewIsEmbedded) {
if (!isForeignWindow()) {
[m_view setFrame:NSMakeRect(0, 0, rect.width(), rect.height())];
- } else {
- QPlatformWindow::setGeometry(rect);
}
return;
}
- if (isChildNSWindow()) {
- QPlatformWindow::setGeometry(rect);
- NSWindow *parentNSWindow = m_view.window.parentWindow;
- NSRect parentWindowFrame = [parentNSWindow contentRectForFrameRect:parentNSWindow.frame];
- clipWindow(parentWindowFrame);
-
- // call this here: updateGeometry in qnsview.mm is a no-op for this case
- QWindowSystemInterface::handleGeometryChange(window(), rect);
- QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
- } else if (m_nsWindow) {
- NSRect bounds = qt_mac_flipRect(rect);
- [m_nsWindow setFrame:[m_nsWindow frameRectForContentRect:bounds] display:YES animate:NO];
+ if (isContentView()) {
+ NSRect bounds = QCocoaScreen::mapToNative(rect);
+ [m_view.window setFrame:[m_view.window frameRectForContentRect:bounds] display:YES animate:NO];
} else {
[m_view setFrame:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
}
- if (isForeignWindow())
- QPlatformWindow::setGeometry(rect);
-
// will call QPlatformWindow::setGeometry(rect) during resize confirmation (see qnsview.mm)
}
-void QCocoaWindow::clipChildWindows()
-{
- foreachChildNSWindow(^(QCocoaWindow *childWindow) {
- childWindow->clipWindow(m_nsWindow.frame);
- });
-}
-
-void QCocoaWindow::clipWindow(const NSRect &clipRect)
-{
- if (!isChildNSWindow())
- return;
-
- NSRect clippedWindowRect = NSZeroRect;
- if (!NSIsEmptyRect(clipRect)) {
- NSRect windowFrame = qt_mac_flipRect(QRect(window()->mapToGlobal(QPoint(0, 0)), geometry().size()));
- clippedWindowRect = NSIntersectionRect(windowFrame, clipRect);
- // Clipping top/left offsets the content. Move it back.
- NSPoint contentViewOffset = NSMakePoint(qMax(CGFloat(0), NSMinX(clippedWindowRect) - NSMinX(windowFrame)),
- qMax(CGFloat(0), NSMaxY(windowFrame) - NSMaxY(clippedWindowRect)));
- [m_view setBoundsOrigin:contentViewOffset];
- }
-
- if (NSIsEmptyRect(clippedWindowRect)) {
- if (!m_hiddenByClipping) {
- // We dont call hide() here as we will recurse further down
- [m_nsWindow orderOut:nil];
- m_hiddenByClipping = true;
- }
- } else {
- [m_nsWindow setFrame:clippedWindowRect display:YES animate:NO];
- if (m_hiddenByClipping) {
- m_hiddenByClipping = false;
- if (!m_hiddenByAncestor) {
- [m_nsWindow orderFront:nil];
- static_cast<QCocoaWindow *>(QPlatformWindow::parent())->reinsertChildWindow(this);
- }
- }
- }
-
- // recurse
- foreachChildNSWindow(^(QCocoaWindow *childWindow) {
- childWindow->clipWindow(clippedWindowRect);
- });
-}
-
-void QCocoaWindow::hide(bool becauseOfAncestor)
-{
- bool visible = [m_nsWindow isVisible];
-
- if (!m_hiddenByAncestor && !visible) // Already explicitly hidden
- return;
- if (m_hiddenByAncestor && becauseOfAncestor) // Trying to hide some child again
- return;
-
- m_hiddenByAncestor = becauseOfAncestor;
-
- if (!visible) // Could have been clipped before
- return;
-
- foreachChildNSWindow(^(QCocoaWindow *childWindow) {
- childWindow->hide(true);
- });
-
- [m_nsWindow orderOut:nil];
-}
-
-void QCocoaWindow::show(bool becauseOfAncestor)
-{
- if ([m_nsWindow isVisible])
- return;
-
- if (m_view.window.parentWindow && !m_view.window.parentWindow.visible) {
- m_hiddenByAncestor = true; // Parent still hidden, don't show now
- } else if ((becauseOfAncestor == m_hiddenByAncestor) // Was NEITHER explicitly hidden
- && !m_hiddenByClipping) { // ... NOR clipped
- if (isChildNSWindow()) {
- m_hiddenByAncestor = false;
- setCocoaGeometry(windowGeometry());
- }
- if (!m_hiddenByClipping) { // setCocoaGeometry() can change the clipping status
- [m_nsWindow orderFront:nil];
- if (isChildNSWindow())
- static_cast<QCocoaWindow *>(QPlatformWindow::parent())->reinsertChildWindow(this);
- foreachChildNSWindow(^(QCocoaWindow *childWindow) {
- childWindow->show(true);
- });
- }
- }
-}
-
void QCocoaWindow::setVisible(bool visible)
{
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setVisible" << window() << visible;
- if (isChildNSWindow() && m_hiddenByClipping)
- return;
-
m_inSetVisible = true;
QMacAutoReleasePool pool;
@@ -818,6 +334,12 @@ void QCocoaWindow::setVisible(bool visible)
// We need to recreate if the modality has changed as the style mask will need updating
recreateWindowIfNeeded();
+ // We didn't send geometry changes during creation, as that would have confused
+ // Qt, which expects a show-event to be sent before any resize events. But now
+ // that the window is made visible, we know that the show-event has been sent
+ // so we can send the geometry change. FIXME: Get rid of this workaround.
+ handleGeometryChange();
+
// Register popup windows. The Cocoa platform plugin will forward mouse events
// to them and close them when needed.
if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip)
@@ -831,34 +353,28 @@ void QCocoaWindow::setVisible(bool visible)
if (window()->type() == Qt::Popup) {
// QTBUG-30266: a window should not be resizable while a transient popup is open
// Since this isn't a native popup, the window manager doesn't close the popup when you click outside
- NSUInteger parentStyleMask = [parentCocoaWindow->m_nsWindow styleMask];
+ NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
+ NSUInteger parentStyleMask = nativeParentWindow.styleMask;
if ((m_resizableTransientParent = (parentStyleMask & NSResizableWindowMask))
- && !([parentCocoaWindow->m_nsWindow styleMask] & NSFullScreenWindowMask))
- [parentCocoaWindow->m_nsWindow setStyleMask:parentStyleMask & ~NSResizableWindowMask];
+ && !(nativeParentWindow.styleMask & NSFullScreenWindowMask))
+ nativeParentWindow.styleMask &= ~NSResizableWindowMask;
}
}
- // This call is here to handle initial window show correctly:
- // - top-level windows need to have backing store content ready when the
- // window is shown, sendin the expose event here makes that more likely.
- // - QNSViews for child windows are initialy not hidden and won't get the
- // viewDidUnhide message.
- exposeWindow();
-
- if (m_nsWindow) {
+ if (isContentView()) {
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
// setWindowState might have been called while the window was hidden and
// will not change the NSWindow state in that case. Sync up here:
- applyWindowState(window()->windowState());
+ applyWindowState(window()->windowStates());
if (window()->windowState() != Qt::WindowMinimized) {
if ((window()->modality() == Qt::WindowModal
|| window()->type() == Qt::Sheet)
&& parentCocoaWindow) {
// show the window as a sheet
- [parentCocoaWindow->m_nsWindow beginSheet:m_nsWindow completionHandler:nil];
+ [parentCocoaWindow->nativeWindow() beginSheet:m_view.window completionHandler:nil];
} else if (window()->modality() != Qt::NonModal) {
// show the window as application modal
QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
@@ -866,32 +382,28 @@ void QCocoaWindow::setVisible(bool visible)
QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
cocoaEventDispatcherPrivate->beginModalSession(window());
m_hasModalSession = true;
- } else if ([m_nsWindow canBecomeKeyWindow]) {
+ } else if ([m_view.window canBecomeKeyWindow]) {
QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = 0;
if (cocoaEventDispatcher)
cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
if (cocoaEventDispatcherPrivate && cocoaEventDispatcherPrivate->cocoaModalSessionStack.isEmpty())
- [m_nsWindow makeKeyAndOrderFront:nil];
+ [m_view.window makeKeyAndOrderFront:nil];
else
- [m_nsWindow orderFront:nil];
-
- foreachChildNSWindow(^(QCocoaWindow *childWindow) {
- childWindow->show(true);
- });
+ [m_view.window orderFront:nil];
} else {
- show();
+ [m_view.window orderFront:nil];
}
// We want the events to properly reach the popup, dialog, and tool
if ((window()->type() == Qt::Popup || window()->type() == Qt::Dialog || window()->type() == Qt::Tool)
- && [m_nsWindow isKindOfClass:[NSPanel class]]) {
- [(NSPanel *)m_nsWindow setWorksWhenModal:YES];
+ && [m_view.window isKindOfClass:[NSPanel class]]) {
+ ((NSPanel *)m_view.window).worksWhenModal = YES;
if (!(parentCocoaWindow && window()->transientParent()->isActive()) && window()->type() == Qt::Popup) {
removeMonitor();
monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDownMask|NSMouseMovedMask handler:^(NSEvent *e) {
- QPointF localPoint = qt_mac_flipPoint([NSEvent mouseLocation]);
+ QPointF localPoint = QCocoaScreen::mapFromNative([NSEvent mouseLocation]);
QWindowSystemInterface::handleMouseEvent(window(), window()->mapFromGlobal(localPoint.toPoint()), localPoint,
cocoaButton2QtButton([e buttonNumber]));
}];
@@ -914,20 +426,21 @@ void QCocoaWindow::setVisible(bool visible)
QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = 0;
if (cocoaEventDispatcher)
cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
- if (m_nsWindow) {
+ if (isContentView()) {
if (m_hasModalSession) {
if (cocoaEventDispatcherPrivate)
cocoaEventDispatcherPrivate->endModalSession(window());
m_hasModalSession = false;
} else {
- if ([m_nsWindow isSheet]) {
+ if ([m_view.window isSheet]) {
Q_ASSERT_X(parentCocoaWindow, "QCocoaWindow", "Window modal dialog has no transient parent.");
- [parentCocoaWindow->m_nsWindow endSheet:m_nsWindow];
+ [parentCocoaWindow->nativeWindow() endSheet:m_view.window];
}
}
- hide();
- if (m_nsWindow == [NSApp keyWindow]
+ [m_view.window orderOut:nil];
+
+ if (m_view.window == [NSApp keyWindow]
&& !(cocoaEventDispatcherPrivate && cocoaEventDispatcherPrivate->currentModalSession())) {
// Probably because we call runModalSession: outside [NSApp run] in QCocoaEventDispatcher
// (e.g., when show()-ing a modal QDialog instead of exec()-ing it), it can happen that
@@ -946,10 +459,11 @@ void QCocoaWindow::setVisible(bool visible)
QCocoaIntegration::instance()->popupWindowStack()->removeAll(this);
if (parentCocoaWindow && window()->type() == Qt::Popup) {
+ NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
if (m_resizableTransientParent
- && !([parentCocoaWindow->m_nsWindow styleMask] & NSFullScreenWindowMask))
- // QTBUG-30266: a window should not be resizable while a transient popup is open
- [parentCocoaWindow->m_nsWindow setStyleMask:[parentCocoaWindow->m_nsWindow styleMask] | NSResizableWindowMask];
+ && !(nativeParentWindow.styleMask & NSFullScreenWindowMask))
+ // A window should not be resizable while a transient popup is open
+ nativeParentWindow.styleMask |= NSResizableWindowMask;
}
}
@@ -979,7 +493,7 @@ NSInteger QCocoaWindow::windowLevel(Qt::WindowFlags flags)
const QWindow * const transientParent = window()->transientParent();
const QCocoaWindow * const transientParentWindow = transientParent ? static_cast<QCocoaWindow *>(transientParent->handle()) : 0;
if (transientParentWindow)
- windowLevel = qMax([transientParentWindow->m_nsWindow level], windowLevel);
+ windowLevel = qMax([transientParentWindow->nativeWindow() level], windowLevel);
}
return windowLevel;
@@ -987,70 +501,46 @@ NSInteger QCocoaWindow::windowLevel(Qt::WindowFlags flags)
NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
{
- Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
- NSInteger styleMask = NSBorderlessWindowMask;
- if (flags & Qt::FramelessWindowHint)
- return styleMask;
- if ((type & Qt::Popup) == Qt::Popup) {
- if (!windowIsPopupType(type)) {
- styleMask = NSUtilityWindowMask | NSResizableWindowMask;
- if (!(flags & Qt::CustomizeWindowHint)) {
- styleMask |= NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask;
- } else {
- if (flags & Qt::WindowTitleHint)
- styleMask |= NSTitledWindowMask;
- if (flags & Qt::WindowCloseButtonHint)
- styleMask |= NSClosableWindowMask;
- if (flags & Qt::WindowMinimizeButtonHint)
- styleMask |= NSMiniaturizableWindowMask;
- }
- }
+ const Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
+ const bool frameless = (flags & Qt::FramelessWindowHint) || windowIsPopupType(type);
+
+ // Select base window type.
+ NSUInteger styleMask = frameless ? NSBorderlessWindowMask : NSResizableWindowMask;
+
+ if (frameless) {
+ // No further customizations for frameless since there are no window decorations.
+ } else if (flags & Qt::CustomizeWindowHint) {
+ if (flags & Qt::WindowTitleHint)
+ styleMask |= NSTitledWindowMask;
+ if (flags & Qt::WindowCloseButtonHint)
+ styleMask |= NSClosableWindowMask;
+ if (flags & Qt::WindowMinimizeButtonHint)
+ styleMask |= NSMiniaturizableWindowMask;
} else {
- if (type == Qt::Window && !(flags & Qt::CustomizeWindowHint)) {
- styleMask = (NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask);
- } else if (type == Qt::Dialog) {
- if (flags & Qt::CustomizeWindowHint) {
- if (flags & Qt::WindowMaximizeButtonHint)
- styleMask = NSResizableWindowMask;
- if (flags & Qt::WindowTitleHint)
- styleMask |= NSTitledWindowMask;
- if (flags & Qt::WindowCloseButtonHint)
- styleMask |= NSClosableWindowMask;
- if (flags & Qt::WindowMinimizeButtonHint)
- styleMask |= NSMiniaturizableWindowMask;
- } else {
- styleMask = NSResizableWindowMask | NSClosableWindowMask | NSTitledWindowMask;
- }
- } else {
- if (flags & Qt::WindowMaximizeButtonHint)
- styleMask |= NSResizableWindowMask;
- if (flags & Qt::WindowTitleHint)
- styleMask |= NSTitledWindowMask;
- if (flags & Qt::WindowCloseButtonHint)
- styleMask |= NSClosableWindowMask;
- if (flags & Qt::WindowMinimizeButtonHint)
- styleMask |= NSMiniaturizableWindowMask;
- }
+ styleMask |= NSClosableWindowMask | NSTitledWindowMask;
+
+ if (type != Qt::Dialog)
+ styleMask |= NSMiniaturizableWindowMask;
}
+ if (type == Qt::Tool)
+ styleMask |= NSUtilityWindowMask;
+
if (m_drawContentBorderGradient)
styleMask |= NSTexturedBackgroundWindowMask;
// Don't wipe fullscreen state
- if (m_nsWindow.styleMask & NSFullScreenWindowMask)
+ if (m_view.window.styleMask & NSFullScreenWindowMask)
styleMask |= NSFullScreenWindowMask;
return styleMask;
}
-void QCocoaWindow::setWindowShadow(Qt::WindowFlags flags)
-{
- bool keepShadow = !(flags & Qt::NoDropShadowWindowHint);
- [m_nsWindow setHasShadow:(keepShadow ? YES : NO)];
-}
-
void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags)
{
+ if (!isContentView())
+ return;
+
// Disable the zoom (maximize) button for fixed-sized windows and customized
// no-WindowMaximizeButtonHint windows. From a Qt perspective it migth be expected
// that the button would be removed in the latter case, but disabling it is more
@@ -1059,28 +549,27 @@ void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags)
&& windowMinimumSize() == windowMaximumSize());
bool customizeNoZoom = ((flags & Qt::CustomizeWindowHint)
&& !(flags & (Qt::WindowMaximizeButtonHint | Qt::WindowFullscreenButtonHint)));
- [[m_nsWindow standardWindowButton:NSWindowZoomButton] setEnabled:!(fixedSizeNoZoom || customizeNoZoom)];
+ [[m_view.window standardWindowButton:NSWindowZoomButton] setEnabled:!(fixedSizeNoZoom || customizeNoZoom)];
}
void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
{
- if (m_nsWindow && !isChildNSWindow()) {
- NSUInteger styleMask = windowStyleMask(flags);
- NSInteger level = this->windowLevel(flags);
- // While setting style mask we can have -updateGeometry calls on a content
+ if (isContentView()) {
+ // While setting style mask we can have handleGeometryChange calls on a content
// view with null geometry, reporting an invalid coordinates as a result.
m_inSetStyleMask = true;
- [m_nsWindow setStyleMask:styleMask];
+ m_view.window.styleMask = windowStyleMask(flags);
m_inSetStyleMask = false;
- [m_nsWindow setLevel:level];
- setWindowShadow(flags);
- if (!(flags & Qt::FramelessWindowHint)) {
+ m_view.window.level = this->windowLevel(flags);
+
+ m_view.window.hasShadow = !(flags & Qt::NoDropShadowWindowHint);
+
+ if (!(flags & Qt::FramelessWindowHint))
setWindowTitle(window()->title());
- }
Qt::WindowType type = window()->type();
if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) {
- NSWindowCollectionBehavior behavior = [m_nsWindow collectionBehavior];
+ NSWindowCollectionBehavior behavior = m_view.window.collectionBehavior;
if (flags & Qt::WindowFullscreenButtonHint) {
behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary;
@@ -1088,28 +577,26 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
behavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
}
- [m_nsWindow setCollectionBehavior:behavior];
+ m_view.window.collectionBehavior = behavior;
}
setWindowZoomButton(flags);
- }
- // Make window ignore mouse events if WindowTransparentForInput is set.
- // Note that ignoresMouseEvents has a special initial state where events
- // are ignored (passed through) based on window transparency, and that
- // setting the property to false does not return us to that state. Instead,
- // this makes the window capture all mouse events. Take care to only
- // set the property if needed. FIXME: recreate window if needed or find
- // some other way to implement WindowTransparentForInput.
- if (m_nsWindow) {
+ // Make window ignore mouse events if WindowTransparentForInput is set.
+ // Note that ignoresMouseEvents has a special initial state where events
+ // are ignored (passed through) based on window transparency, and that
+ // setting the property to false does not return us to that state. Instead,
+ // this makes the window capture all mouse events. Take care to only
+ // set the property if needed. FIXME: recreate window if needed or find
+ // some other way to implement WindowTransparentForInput.
bool ignoreMouse = flags & Qt::WindowTransparentForInput;
- if (m_nsWindow.ignoresMouseEvents != ignoreMouse)
- m_nsWindow.ignoresMouseEvents = ignoreMouse;
+ if (m_view.window.ignoresMouseEvents != ignoreMouse)
+ m_view.window.ignoresMouseEvents = ignoreMouse;
}
m_windowFlags = flags;
}
-void QCocoaWindow::setWindowState(Qt::WindowState state)
+void QCocoaWindow::setWindowState(Qt::WindowStates state)
{
if (window()->isVisible())
applyWindowState(state); // Window state set for hidden windows take effect when show() is called
@@ -1117,45 +604,54 @@ void QCocoaWindow::setWindowState(Qt::WindowState state)
void QCocoaWindow::setWindowTitle(const QString &title)
{
- QMacAutoReleasePool pool;
- if (!m_nsWindow)
+ if (!isContentView())
return;
- CFStringRef windowTitle = title.toCFString();
- [m_nsWindow setTitle: const_cast<NSString *>(reinterpret_cast<const NSString *>(windowTitle))];
- CFRelease(windowTitle);
+ QMacAutoReleasePool pool;
+ m_view.window.title = title.toNSString();
+
+ if (title.isEmpty() && !window()->filePath().isEmpty()) {
+ // Clearing the title should restore the default filename
+ setWindowFilePath(window()->filePath());
+ }
}
void QCocoaWindow::setWindowFilePath(const QString &filePath)
{
- QMacAutoReleasePool pool;
- if (!m_nsWindow)
+ if (!isContentView())
return;
- QFileInfo fi(filePath);
- [m_nsWindow setRepresentedFilename:fi.exists() ? filePath.toNSString() : @""];
- m_hasWindowFilePath = fi.exists();
+ QMacAutoReleasePool pool;
+
+ if (window()->title().isNull())
+ [m_view.window setTitleWithRepresentedFilename:filePath.toNSString()];
+ else
+ m_view.window.representedFilename = filePath.toNSString();
+
+ // Changing the file path may affect icon visibility
+ setWindowIcon(window()->icon());
}
void QCocoaWindow::setWindowIcon(const QIcon &icon)
{
- QMacAutoReleasePool pool;
+ if (!isContentView())
+ return;
- NSButton *iconButton = [m_nsWindow standardWindowButton:NSWindowDocumentIconButton];
- if (iconButton == nil) {
- if (icon.isNull())
- return;
- NSString *title = window()->title().toNSString();
- [m_nsWindow setRepresentedURL:[NSURL fileURLWithPath:title]];
- iconButton = [m_nsWindow standardWindowButton:NSWindowDocumentIconButton];
+ NSButton *iconButton = [m_view.window standardWindowButton:NSWindowDocumentIconButton];
+ if (!iconButton) {
+ // Window icons are only supported on macOS in combination with a document filePath
+ return;
}
+
+ QMacAutoReleasePool pool;
+
if (icon.isNull()) {
- [iconButton setImage:nil];
+ NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
+ [iconButton setImage:[workspace iconForFile:m_view.window.representedFilename]];
} else {
QPixmap pixmap = icon.pixmap(QSize(22, 22));
NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap));
- [iconButton setImage:image];
- [image release];
+ [iconButton setImage:[image autorelease]];
}
}
@@ -1179,34 +675,22 @@ void QCocoaWindow::raise()
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::raise" << window();
// ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm)
- if (!m_nsWindow)
+ if (!isContentView())
return;
- if (isChildNSWindow()) {
- if (m_hiddenByClipping)
- return;
- }
- if ([m_nsWindow isVisible]) {
- if (isChildNSWindow()) {
- // -[NSWindow orderFront:] doesn't work with attached windows.
- // The only solution is to remove and add the child window.
- // This will place it on top of all the other NSWindows.
- NSWindow *parentNSWindow = m_view.window.parentWindow;
- [parentNSWindow removeChildWindow:m_nsWindow];
- [parentNSWindow addChildWindow:m_nsWindow ordered:NSWindowAbove];
- } else {
- {
- // Clean up autoreleased temp objects from orderFront immediately.
- // Failure to do so has been observed to cause leaks also beyond any outer
- // autorelease pool (for example around a complete QWindow
- // construct-show-raise-hide-delete cyle), counter to expected autoreleasepool
- // behavior.
- QMacAutoReleasePool pool;
- [m_nsWindow orderFront: m_nsWindow];
- }
- static bool raiseProcess = qt_mac_resolveOption(true, "QT_MAC_SET_RAISE_PROCESS");
- if (raiseProcess) {
- [NSApp activateIgnoringOtherApps:YES];
- }
+
+ if (m_view.window.visible) {
+ {
+ // Clean up autoreleased temp objects from orderFront immediately.
+ // Failure to do so has been observed to cause leaks also beyond any outer
+ // autorelease pool (for example around a complete QWindow
+ // construct-show-raise-hide-delete cyle), counter to expected autoreleasepool
+ // behavior.
+ QMacAutoReleasePool pool;
+ [m_view.window orderFront:m_view.window];
+ }
+ static bool raiseProcess = qt_mac_resolveOption(true, "QT_MAC_SET_RAISE_PROCESS");
+ if (raiseProcess) {
+ [NSApp activateIgnoringOtherApps:YES];
}
}
}
@@ -1214,34 +698,16 @@ void QCocoaWindow::raise()
void QCocoaWindow::lower()
{
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::lower" << window();
- if (!m_nsWindow)
+ if (!isContentView())
return;
- if (isChildNSWindow()) {
- if (m_hiddenByClipping)
- return;
- }
- if ([m_nsWindow isVisible]) {
- if (isChildNSWindow()) {
- // -[NSWindow orderBack:] doesn't work with attached windows.
- // The only solution is to remove and add all the child windows except this one.
- // This will keep the current window at the bottom while adding the others on top of it,
- // hopefully in the same order (this is not documented anywhere in the Cocoa documentation).
- NSWindow *parentNSWindow = m_view.window.parentWindow;
- NSArray *children = [parentNSWindow.childWindows copy];
- for (NSWindow *child in children)
- if (m_nsWindow != child) {
- [parentNSWindow removeChildWindow:child];
- [parentNSWindow addChildWindow:child ordered:NSWindowAbove];
- }
- } else {
- [m_nsWindow orderBack: m_nsWindow];
- }
- }
+
+ if (m_view.window.visible)
+ [m_view.window orderBack:m_view.window];
}
bool QCocoaWindow::isExposed() const
{
- return m_isExposed;
+ return !m_exposedRect.isEmpty();
}
bool QCocoaWindow::isOpaque() const
@@ -1252,7 +718,7 @@ bool QCocoaWindow::isOpaque() const
bool translucent = window()->format().alphaBufferSize() > 0
|| window()->opacity() < 1
- || [qnsview_cast(m_view) hasMask]
+ || !window()->mask().isEmpty()
|| (surface()->supportsOpenGL() && openglSourfaceOrder == -1);
return !translucent;
}
@@ -1260,24 +726,24 @@ bool QCocoaWindow::isOpaque() const
void QCocoaWindow::propagateSizeHints()
{
QMacAutoReleasePool pool;
- if (!m_nsWindow)
+ if (!isContentView())
return;
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::propagateSizeHints" << window() << "\n"
- << " min/max" << windowMinimumSize() << windowMaximumSize()
- << "size increment" << windowSizeIncrement()
- << " basesize" << windowBaseSize()
- << " geometry" << windowGeometry();
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::propagateSizeHints" << window()
+ << "min:" << windowMinimumSize() << "max:" << windowMaximumSize()
+ << "increment:" << windowSizeIncrement()
+ << "base:" << windowBaseSize();
+
+ const NSWindow *window = m_view.window;
// Set the minimum content size.
- const QSize minimumSize = windowMinimumSize();
+ QSize minimumSize = windowMinimumSize();
if (!minimumSize.isValid()) // minimumSize is (-1, -1) when not set. Make that (0, 0) for Cocoa.
- [m_nsWindow setContentMinSize : NSMakeSize(0.0, 0.0)];
- [m_nsWindow setContentMinSize : NSMakeSize(minimumSize.width(), minimumSize.height())];
+ minimumSize = QSize(0, 0);
+ window.contentMinSize = NSSizeFromCGSize(minimumSize.toCGSize());
// Set the maximum content size.
- const QSize maximumSize = windowMaximumSize();
- [m_nsWindow setContentMaxSize : NSMakeSize(maximumSize.width(), maximumSize.height())];
+ window.contentMaxSize = NSSizeFromCGSize(windowMaximumSize().toCGSize());
// The window may end up with a fixed size; in this case the zoom button should be disabled.
setWindowZoomButton(m_windowFlags);
@@ -1287,42 +753,65 @@ void QCocoaWindow::propagateSizeHints()
QSize sizeIncrement = windowSizeIncrement();
if (sizeIncrement.isEmpty())
sizeIncrement = QSize(1, 1);
- [m_nsWindow setResizeIncrements:NSSizeFromCGSize(sizeIncrement.toCGSize())];
+ window.resizeIncrements = NSSizeFromCGSize(sizeIncrement.toCGSize());
QRect rect = geometry();
QSize baseSize = windowBaseSize();
- if (!baseSize.isNull() && baseSize.isValid()) {
- [m_nsWindow setFrame:NSMakeRect(rect.x(), rect.y(), baseSize.width(), baseSize.height()) display:YES];
- }
+ if (!baseSize.isNull() && baseSize.isValid())
+ [window setFrame:NSMakeRect(rect.x(), rect.y(), baseSize.width(), baseSize.height()) display:YES];
}
void QCocoaWindow::setOpacity(qreal level)
{
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setOpacity" << level;
- if (m_nsWindow) {
- [m_nsWindow setAlphaValue:level];
- [m_nsWindow setOpaque: isOpaque()];
- }
+ if (!isContentView())
+ return;
+
+ m_view.window.alphaValue = level;
}
void QCocoaWindow::setMask(const QRegion &region)
{
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setMask" << window() << region;
- if (m_nsWindow)
- [m_nsWindow setBackgroundColor:[NSColor clearColor]];
- [qnsview_cast(m_view) setMaskRegion:&region];
- [m_nsWindow setOpaque:isOpaque()];
+ if (m_view.layer) {
+ if (!region.isEmpty()) {
+ QCFType<CGMutablePathRef> maskPath = CGPathCreateMutable();
+ for (const QRect &r : region)
+ CGPathAddRect(maskPath, nullptr, r.toCGRect());
+ CAShapeLayer *maskLayer = [CAShapeLayer layer];
+ maskLayer.path = maskPath;
+ m_view.layer.mask = maskLayer;
+ } else {
+ m_view.layer.mask = nil;
+ }
+ }
+
+ if (isContentView()) {
+ // Setting the mask requires invalidating the NSWindow shadow, but that needs
+ // to happen after the backingstore has been redrawn, so that AppKit can pick
+ // up the new window shape based on the backingstore content. Doing a display
+ // directly here is not an option, as the window might not be exposed at this
+ // time, and so would not result in an updated backingstore.
+ m_needsInvalidateShadow = true;
+ [m_view setNeedsDisplay:YES];
+
+ // FIXME: [NSWindow invalidateShadow] has no effect when in layer-backed mode,
+ // so if the mask is changed after the initial mask is applied, it will not
+ // result in any visual change to the shadow. This is an Apple bug, and there
+ // may be ways to work around it, such as calling setFrame on the window to
+ // trigger some internal invalidation, but that needs more research.
+ }
}
bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
{
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setKeyboardGrabEnabled" << window() << grab;
- if (!m_nsWindow)
+ if (!isContentView())
return false;
- if (grab && ![m_nsWindow isKeyWindow])
- [m_nsWindow makeKeyWindow];
+ if (grab && ![m_view.window isKeyWindow])
+ [m_view.window makeKeyWindow];
return true;
}
@@ -1330,11 +819,11 @@ bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
bool QCocoaWindow::setMouseGrabEnabled(bool grab)
{
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setMouseGrabEnabled" << window() << grab;
- if (!m_nsWindow)
+ if (!isContentView())
return false;
- if (grab && ![m_nsWindow isKeyWindow])
- [m_nsWindow makeKeyWindow];
+ if (grab && ![m_view.window isKeyWindow])
+ [m_view.window makeKeyWindow];
return true;
}
@@ -1363,7 +852,7 @@ NSView *QCocoaWindow::view() const
NSWindow *QCocoaWindow::nativeWindow() const
{
- return m_nsWindow;
+ return m_view.window;
}
void QCocoaWindow::setEmbeddedInForeignView(bool embedded)
@@ -1374,8 +863,32 @@ void QCocoaWindow::setEmbeddedInForeignView(bool embedded)
m_nsWindow = 0;
}
+// ----------------------- NSView notifications -----------------------
+
+void QCocoaWindow::viewDidChangeFrame()
+{
+ handleGeometryChange();
+}
+
+/*!
+ Callback for NSViewGlobalFrameDidChangeNotification.
+
+ Posted whenever an NSView object that has attached surfaces (that is,
+ NSOpenGLContext objects) moves to a different screen, or other cases
+ where the NSOpenGLContext object needs to be updated.
+*/
+void QCocoaWindow::viewDidChangeGlobalFrame()
+{
+ [m_view setNeedsDisplay:YES];
+}
+
// ----------------------- NSWindow notifications -----------------------
+// Note: The following notifications are delivered to every QCocoaWindow
+// that is a child of the NSWindow that triggered the notification. Each
+// callback should make sure to filter out notifications if they do not
+// apply to that QCocoaWindow, e.g. if the window is not a content view.
+
void QCocoaWindow::windowWillMove()
{
// Close any open popups on window move
@@ -1384,54 +897,39 @@ void QCocoaWindow::windowWillMove()
void QCocoaWindow::windowDidMove()
{
- if (isChildNSWindow())
+ if (!isContentView())
return;
- [qnsview_cast(m_view) updateGeometry];
+ handleGeometryChange();
// Moving a window might bring it out of maximized state
- reportCurrentWindowState();
+ handleWindowStateChanged();
}
void QCocoaWindow::windowDidResize()
{
- if (!m_nsWindow)
+ if (!isContentView())
return;
- if (isChildNSWindow())
- return;
-
- clipChildWindows();
- [qnsview_cast(m_view) updateGeometry];
+ handleGeometryChange();
if (!m_view.inLiveResize)
- reportCurrentWindowState();
-}
-
-void QCocoaWindow::viewDidChangeFrame()
-{
- [qnsview_cast(m_view) updateGeometry];
-}
-
-/*!
- Callback for NSViewGlobalFrameDidChangeNotification.
-
- Posted whenever an NSView object that has attached surfaces (that is,
- NSOpenGLContext objects) moves to a different screen, or other cases
- where the NSOpenGLContext object needs to be updated.
-*/
-void QCocoaWindow::viewDidChangeGlobalFrame()
-{
- updateExposedGeometry();
+ handleWindowStateChanged();
}
void QCocoaWindow::windowDidEndLiveResize()
{
- reportCurrentWindowState();
+ if (!isContentView())
+ return;
+
+ handleWindowStateChanged();
}
void QCocoaWindow::windowDidBecomeKey()
{
+ if (!isContentView())
+ return;
+
if (isForeignWindow())
return;
@@ -1448,6 +946,9 @@ void QCocoaWindow::windowDidBecomeKey()
void QCocoaWindow::windowDidResignKey()
{
+ if (!isContentView())
+ return;
+
if (isForeignWindow())
return;
@@ -1464,43 +965,61 @@ void QCocoaWindow::windowDidResignKey()
void QCocoaWindow::windowDidMiniaturize()
{
- reportCurrentWindowState();
+ if (!isContentView())
+ return;
+
+ handleWindowStateChanged();
}
void QCocoaWindow::windowDidDeminiaturize()
{
- reportCurrentWindowState();
+ if (!isContentView())
+ return;
+
+ handleWindowStateChanged();
}
void QCocoaWindow::windowWillEnterFullScreen()
{
+ if (!isContentView())
+ return;
+
// The NSWindow needs to be resizable, otherwise we'll end up with
// the normal window geometry, centered in the middle of the screen
// on a black background. The styleMask will be reset below.
- m_nsWindow.styleMask |= NSResizableWindowMask;
+ m_view.window.styleMask |= NSResizableWindowMask;
}
void QCocoaWindow::windowDidEnterFullScreen()
{
- Q_ASSERT_X(m_nsWindow.qt_fullScreen, "QCocoaWindow",
+ if (!isContentView())
+ return;
+
+ Q_ASSERT_X(m_view.window.qt_fullScreen, "QCocoaWindow",
"FullScreen category processes window notifications first");
// Reset to original styleMask
setWindowFlags(m_windowFlags);
- reportCurrentWindowState();
+ handleWindowStateChanged();
}
void QCocoaWindow::windowWillExitFullScreen()
{
+ if (!isContentView())
+ return;
+
// The NSWindow needs to be resizable, otherwise we'll end up with
// a weird zoom animation. The styleMask will be reset below.
- m_nsWindow.styleMask |= NSResizableWindowMask;
+ m_view.window.styleMask |= NSResizableWindowMask;
}
void QCocoaWindow::windowDidExitFullScreen()
{
- Q_ASSERT_X(!m_nsWindow.qt_fullScreen, "QCocoaWindow",
+ if (!isContentView())
+ return;
+
+ Q_ASSERT_X(!m_view.window.qt_fullScreen, "QCocoaWindow",
"FullScreen category processes window notifications first");
// Reset to original styleMask
@@ -1509,7 +1028,7 @@ void QCocoaWindow::windowDidExitFullScreen()
Qt::WindowState requestedState = window()->windowState();
// Deliver update of QWindow state
- reportCurrentWindowState();
+ handleWindowStateChanged();
if (requestedState != windowState() && requestedState != Qt::WindowFullScreen) {
// We were only going out of full screen as an intermediate step before
@@ -1518,30 +1037,22 @@ void QCocoaWindow::windowDidExitFullScreen()
}
}
-void QCocoaWindow::windowDidOrderOffScreen()
+void QCocoaWindow::windowDidOrderOnScreen()
{
- obscureWindow();
+ [m_view setNeedsDisplay:YES];
}
-void QCocoaWindow::windowDidOrderOnScreen()
+void QCocoaWindow::windowDidOrderOffScreen()
{
- exposeWindow();
+ handleExposeEvent(QRegion());
}
void QCocoaWindow::windowDidChangeOcclusionState()
{
- // Several unit tests expect paint and/or expose events for windows that are
- // sometimes (unpredictably) occluded and some unit tests depend on QWindow::isExposed.
- // Don't send Expose/Obscure events when running under QTestLib.
- static const bool onTestLib = qt_mac_resolveOption(false, "QT_QTESTLIB_RUNNING");
- if (!onTestLib) {
- if ((NSUInteger)[m_view.window occlusionState] & NSWindowOcclusionStateVisible) {
- exposeWindow();
- } else {
- // Send Obscure events on window occlusion to stop animations.
- obscureWindow();
- }
- }
+ if (m_view.window.occlusionState & NSWindowOcclusionStateVisible)
+ [m_view setNeedsDisplay:YES];
+ else
+ handleExposeEvent(QRegion());
}
void QCocoaWindow::windowDidChangeScreen()
@@ -1551,8 +1062,6 @@ void QCocoaWindow::windowDidChangeScreen()
if (QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenForNSScreen(m_view.window.screen))
QWindowSystemInterface::handleWindowScreenChanged(window(), cocoaScreen->screen());
-
- updateExposedGeometry();
}
void QCocoaWindow::windowWillClose()
@@ -1577,6 +1086,111 @@ bool QCocoaWindow::windowShouldClose()
return accepted;
}
+// ----------------------------- QPA forwarding -----------------------------
+
+void QCocoaWindow::handleGeometryChange()
+{
+ // Prevent geometry change during initialization, as that will result
+ // in a resize event, and Qt expects those to come after the show event.
+ // FIXME: Remove once we've clarified the Qt behavior for this.
+ if (!m_initialized)
+ return;
+
+ // Don't send the geometry change if the QWindow is designated to be
+ // embedded in a foreign view hierarchy but has not actually been
+ // embedded yet - it's too early.
+ if (m_viewIsToBeEmbedded && !m_viewIsEmbedded)
+ return;
+
+ // It can happen that the current NSWindow is nil (if we are changing styleMask
+ // from/to borderless, and the content view is being re-parented), which results
+ // in invalid coordinates.
+ if (m_inSetStyleMask && !m_view.window)
+ return;
+
+ const bool isEmbedded = m_viewIsToBeEmbedded || m_viewIsEmbedded;
+
+ QRect newGeometry;
+ if (isContentView() && !isEmbedded) {
+ // Content views are positioned at (0, 0) in the window, so we resolve via the window
+ CGRect contentRect = [m_view.window contentRectForFrameRect:m_view.window.frame];
+
+ // The result above is in native screen coordinates, so remap to the Qt coordinate system
+ newGeometry = QCocoaScreen::mapFromNative(contentRect).toRect();
+ } else {
+ // QNSView has isFlipped set, so no need to remap the geometry
+ newGeometry = QRectF::fromCGRect(m_view.frame).toRect();
+ }
+
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleGeometryChange" << window()
+ << "current" << geometry() << "new" << newGeometry;
+
+ QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
+
+ // Guard against processing window system events during QWindow::setGeometry
+ // calls, which Qt and Qt applications do not expect.
+ if (!m_inSetGeometry)
+ QWindowSystemInterface::flushWindowSystemEvents();
+}
+
+void QCocoaWindow::handleExposeEvent(const QRegion &region)
+{
+ const QRect previouslyExposedRect = m_exposedRect;
+
+ // Ideally we'd implement isExposed() in terms of these properties,
+ // plus the occlusionState of the NSWindow, and let the expose event
+ // pull the exposed state out when needed. However, when the window
+ // is first shown we receive a drawRect call where the occlusionState
+ // of the window is still hidden, but we still want to prepare the
+ // window for display by issuing an expose event to Qt. To work around
+ // this we don't use the occlusionState directly, but instead base
+ // the exposed state on the region we get in, which in the case of
+ // a window being obscured is an empty region, and in the case of
+ // a drawRect call is a non-null region, even if occlusionState
+ // is still hidden. This ensures the window is prepared for display.
+ if (m_view.window.visible && m_view.window.screen
+ && !geometry().size().isEmpty() && !region.isEmpty()
+ && !m_view.hiddenOrHasHiddenAncestor) {
+ m_exposedRect = region.boundingRect();
+ } else {
+ m_exposedRect = QRect();
+ }
+
+ QWindowPrivate *windowPrivate = qt_window_private(window());
+ if (windowPrivate->updateRequestPending) {
+ // We can only deliver update request events when the window is exposed,
+ // and we also have to make sure we deliver any change to the exposed
+ // rect as a real expose event (including going from non-exposed to
+ // exposed). FIXME: Should this logic live in QGuiApplication?
+ if (isExposed() && m_exposedRect == previouslyExposedRect) {
+ qCDebug(lcQpaCocoaDrawing) << "QCocoaWindow::handleExposeEvent" << window() << region << "as update request";
+ windowPrivate->deliverUpdateRequest();
+ return;
+ } else {
+ // Since updateRequestPending is still set, we will issue a deferred setNeedsDisplay
+ // from drawRect and get back into this code on the next display cycle, delivering
+ // the pending update request.
+ }
+ }
+
+ qCDebug(lcQpaCocoaDrawing) << "QCocoaWindow::handleExposeEvent" << window() << region << "isExposed" << isExposed();
+ QWindowSystemInterface::handleExposeEvent<QWindowSystemInterface::SynchronousDelivery>(window(), region);
+}
+
+void QCocoaWindow::handleWindowStateChanged(HandleFlags flags)
+{
+ Qt::WindowState currentState = windowState();
+ if (!(flags & HandleUnconditionally) && currentState == m_lastReportedWindowState)
+ return;
+
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleWindowStateChanged" <<
+ m_lastReportedWindowState << "-->" << currentState;
+
+ QWindowSystemInterface::handleWindowStateChanged<QWindowSystemInterface::SynchronousDelivery>(
+ window(), currentState, m_lastReportedWindowState);
+ m_lastReportedWindowState = currentState;
+}
+
// --------------------------------------------------------------------------
bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const
@@ -1602,26 +1216,13 @@ QCocoaGLContext *QCocoaWindow::currentContext() const
#endif
/*!
- Checks if the window is a non-top level QWindow with a NSWindow.
-
- \sa _q_platform_MacUseNSWindow, QT_MAC_USE_NSWINDOW
-*/
-bool QCocoaWindow::isChildNSWindow() const
-{
- return m_view.window.parentWindow != nil;
-}
-
-/*!
Checks if the window is the content view of its immediate NSWindow.
Being the content view of a NSWindow means the QWindow is
the highest accessible NSView object in the window's view
hierarchy.
- This can only happen in two cases, either if the QWindow is
- itself a top level window, or if it's a child NSWindow.
-
- \sa isChildNSWindow
+ This is the case if the QWindow is a top level window.
*/
bool QCocoaWindow::isContentView() const
{
@@ -1629,33 +1230,16 @@ bool QCocoaWindow::isContentView() const
}
/*!
- Iterates child NSWindows that have a corresponding QCocoaWindow.
-*/
-void QCocoaWindow::foreachChildNSWindow(void (^block)(QCocoaWindow *))
-{
- NSArray *windows = m_view.window.childWindows;
- [windows enumerateObjectsUsingBlock:^(NSWindow *window, NSUInteger index, BOOL *stop) {
- Q_UNUSED(index);
- Q_UNUSED(stop);
- if (QNSView *view = qnsview_cast(window.contentView))
- block(view.platformWindow);
- }];
-}
-
-/*!
Recreates (or removes) the NSWindow for this QWindow, if needed.
- A QWindow may need a corresponding NSWindow, depending on whether
- or not it's a top level or not (or explicitly set to be a child
- NSWindow), whether it is a NSPanel or not, etc.
+ A QWindow may need a corresponding NSWindow/NSPanel, depending on
+ whether or not it's a top level or not, window flags, etc.
*/
void QCocoaWindow::recreateWindowIfNeeded()
{
QMacAutoReleasePool pool;
QPlatformWindow *parentWindow = QPlatformWindow::parent();
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::recreateWindowIfNeeded" << window()
- << "parent" << (parentWindow ? parentWindow->window() : 0);
RecreationReasons recreateReason = RecreationNotNeeded;
@@ -1673,79 +1257,56 @@ void QCocoaWindow::recreateWindowIfNeeded()
if (m_windowModality != window()->modality())
recreateReason |= WindowModalityChanged;
- const bool shouldBeChildNSWindow = parentWindow && qt_mac_resolveOption(NO,
- window(), "_q_platform_MacUseNSWindow", "QT_MAC_USE_NSWINDOW");
-
- if (isChildNSWindow() != shouldBeChildNSWindow)
- recreateReason |= ChildNSWindowChanged;
-
- const bool shouldBeContentView = (!parentWindow && !m_viewIsEmbedded) || shouldBeChildNSWindow;
+ const bool shouldBeContentView = !parentWindow && !(m_viewIsToBeEmbedded || m_viewIsEmbedded);
if (isContentView() != shouldBeContentView)
recreateReason |= ContentViewChanged;
Qt::WindowType type = window()->type();
const bool isPanel = isContentView() && [m_view.window isKindOfClass:[QNSPanel class]];
- const bool shouldBePanel = shouldBeContentView && !shouldBeChildNSWindow &&
+ const bool shouldBePanel = shouldBeContentView &&
((type & Qt::Popup) == Qt::Popup || (type & Qt::Dialog) == Qt::Dialog);
if (isPanel != shouldBePanel)
recreateReason |= PanelChanged;
- if (recreateReason == RecreationNotNeeded) {
- qCDebug(lcQpaCocoaWindow) << "No need to recreate NSWindow";
- return;
- }
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::recreateWindowIfNeeded" << window() << recreateReason;
- qCDebug(lcQpaCocoaWindow) << "Reconfiguring NSWindow due to" << recreateReason;
+ if (recreateReason == RecreationNotNeeded)
+ return;
QCocoaWindow *parentCocoaWindow = static_cast<QCocoaWindow *>(parentWindow);
- if (shouldBeChildNSWindow) {
- QWindow *parentQWindow = parentWindow->window();
- // Ensure that all parents in the hierarchy are also child NSWindows
- if (!parentQWindow->property("_q_platform_MacUseNSWindow").toBool()) {
- parentQWindow->setProperty("_q_platform_MacUseNSWindow", QVariant(true));
- parentCocoaWindow->recreateWindowIfNeeded();
- }
- }
-
// Remove current window (if any)
if ((isContentView() && !shouldBeContentView) || (recreateReason & PanelChanged)) {
- qCDebug(lcQpaCocoaWindow) << "Getting rid of existing window" << m_nsWindow;
- [m_nsWindow closeAndRelease];
- if (isChildNSWindow())
- [m_view.window.parentWindow removeChildWindow:m_view.window];
- if (isContentView()) {
- // We explicitly disassociate m_view from the window's contentView,
- // as AppKit does not automatically do this in response to removing
- // the view from the NSThemeFrame subview list, so we might end up
- // with a NSWindow contentView pointing to a deallocated NSView.
- m_view.window.contentView = nil;
+ if (m_nsWindow) {
+ qCDebug(lcQpaCocoaWindow) << "Getting rid of existing window" << m_nsWindow;
+ [m_nsWindow closeAndRelease];
+ if (isContentView()) {
+ // We explicitly disassociate m_view from the window's contentView,
+ // as AppKit does not automatically do this in response to removing
+ // the view from the NSThemeFrame subview list, so we might end up
+ // with a NSWindow contentView pointing to a deallocated NSView.
+ m_view.window.contentView = nil;
+ }
+ m_nsWindow = 0;
}
- m_nsWindow = 0;
}
if (shouldBeContentView) {
bool noPreviousWindow = m_nsWindow == 0;
+ QCocoaNSWindow *newWindow = nullptr;
if (noPreviousWindow)
- m_nsWindow = createNSWindow(shouldBeChildNSWindow, shouldBePanel);
-
- if (m_view.window.parentWindow) {
- if (!shouldBeChildNSWindow || (recreateReason & ParentChanged))
- [m_view.window.parentWindow removeChildWindow:m_view.window];
- m_forwardWindow = oldParentCocoaWindow;
- }
+ newWindow = createNSWindow(shouldBePanel);
// Move view to new NSWindow if needed
- if (m_nsWindow.contentView != m_view) {
- qCDebug(lcQpaCocoaWindow) << "Ensuring that view is content view for" << m_nsWindow;
+ if (newWindow) {
+ qCDebug(lcQpaCocoaWindow) << "Ensuring that" << m_view << "is content view for" << newWindow;
[m_view setPostsFrameChangedNotifications:NO];
- [m_view retain];
- if (m_view.superview) // m_view comes from another NSWindow
- [m_view removeFromSuperview];
- [m_nsWindow setContentView:m_view];
- [m_view release];
+ [newWindow setContentView:m_view];
[m_view setPostsFrameChangedNotifications:YES];
+
+ m_nsWindow = newWindow;
+ Q_ASSERT(m_view.window == m_nsWindow);
}
}
@@ -1756,21 +1317,10 @@ void QCocoaWindow::recreateWindowIfNeeded()
propagateSizeHints();
setWindowFlags(window()->flags());
setWindowTitle(window()->title());
+ setWindowFilePath(window()->filePath());
setWindowState(window()->windowState());
- } else if (shouldBeChildNSWindow) {
- if (!m_hiddenByClipping) {
- [parentCocoaWindow->m_nsWindow addChildWindow:m_nsWindow ordered:NSWindowAbove];
- parentCocoaWindow->reinsertChildWindow(this);
- }
-
- // Set properties after the window has been made a child NSWindow
- setCocoaGeometry(windowGeometry());
- setWindowFlags(window()->flags());
} else {
// Child windows have no NSWindow, link the NSViews instead.
- if ([m_view superview])
- [m_view removeFromSuperview];
-
[parentCocoaWindow->m_view addSubview:m_view];
QRect rect = windowGeometry();
// Prevent setting a (0,0) window size; causes opengl context
@@ -1786,29 +1336,18 @@ void QCocoaWindow::recreateWindowIfNeeded()
if (!qFuzzyCompare(opacity, qreal(1.0)))
setOpacity(opacity);
+ setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
+
// top-level QWindows may have an attached NSToolBar, call
// update function which will attach to the NSWindow.
if (!parentWindow)
updateNSToolbar();
}
-void QCocoaWindow::reinsertChildWindow(QCocoaWindow *child)
+void QCocoaWindow::requestUpdate()
{
- const QObjectList &childWindows = window()->children();
- int childIndex = childWindows.indexOf(child->window());
- Q_ASSERT(childIndex != -1);
-
- for (int i = childIndex; i < childWindows.size(); ++i) {
- QWindow *window = static_cast<QWindow *>(childWindows.at(i));
- QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
- if (!cocoaWindow)
- continue;
-
- NSWindow *nsChild = cocoaWindow->m_nsWindow;
- if (i != childIndex)
- [m_nsWindow removeChildWindow:nsChild];
- [m_nsWindow addChildWindow:nsChild ordered:NSWindowAbove];
- }
+ qCDebug(lcQpaCocoaDrawing) << "QCocoaWindow::requestUpdate" << window();
+ [m_view setNeedsDisplay:YES];
}
void QCocoaWindow::requestActivateWindow()
@@ -1818,10 +1357,8 @@ void QCocoaWindow::requestActivateWindow()
[window makeKeyWindow];
}
-QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBeChildNSWindow, bool shouldBePanel)
+QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
{
- qCDebug(lcQpaCocoaWindow) << "createNSWindow" << shouldBeChildNSWindow << shouldBePanel;
-
QMacAutoReleasePool pool;
QRect rect = geometry();
@@ -1841,7 +1378,7 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBeChildNSWindow, bool sh
rect.translate(-targetScreen->geometry().topLeft());
QCocoaScreen *cocoaScreen = static_cast<QCocoaScreen *>(targetScreen->handle());
- NSRect frame = NSRectFromCGRect(cocoaScreen->mapToNative(rect).toCGRect());
+ NSRect frame = QCocoaScreen::mapToNative(rect, cocoaScreen);
// Note: The macOS window manager has a bug, where if a screen is rotated, it will not allow
// a window to be created within the area of the screen that has a Y coordinate (I quadrant)
@@ -1853,44 +1390,58 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBeChildNSWindow, bool sh
// Create NSWindow
Class windowClass = shouldBePanel ? [QNSPanel class] : [QNSWindow class];
- NSUInteger styleMask = shouldBeChildNSWindow ? NSBorderlessWindowMask : windowStyleMask(flags);
- QCocoaNSWindow *window = [[windowClass alloc] initWithContentRect:frame
- screen:cocoaScreen->nativeScreen() styleMask:styleMask qPlatformWindow:this];
-
- window.restorable = NO;
- window.level = shouldBeChildNSWindow ? NSNormalWindowLevel : windowLevel(flags);
-
- if (!isOpaque()) {
- window.backgroundColor = [NSColor clearColor];
- window.opaque = NO;
+ QCocoaNSWindow *nsWindow = [[windowClass alloc] initWithContentRect:frame
+ styleMask:windowStyleMask(flags)
+ // Deferring window creation breaks OpenGL (the GL context is
+ // set up before the window is shown and needs a proper window)
+ backing:NSBackingStoreBuffered defer:NO
+ screen:cocoaScreen->nativeScreen()];
+
+ Q_ASSERT_X(nsWindow.screen == cocoaScreen->nativeScreen(), "QCocoaWindow",
+ "Resulting NSScreen should match the requested NSScreen");
+
+ nsWindow.delegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this];
+
+ // Prevent Cocoa from releasing the window on close. Qt
+ // handles the close event asynchronously and we want to
+ // make sure that NSWindow stays valid until the
+ // QCocoaWindow is deleted by Qt.
+ [nsWindow setReleasedWhenClosed:NO];
+
+ if (alwaysShowToolWindow()) {
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+ [center addObserver:[QNSWindow class] selector:@selector(applicationActivationChanged:)
+ name:NSApplicationWillResignActiveNotification object:nil];
+ [center addObserver:[QNSWindow class] selector:@selector(applicationActivationChanged:)
+ name:NSApplicationWillBecomeActiveNotification object:nil];
+ });
}
- Q_ASSERT(!(shouldBePanel && shouldBeChildNSWindow));
+ if (targetScreen != window()->screen())
+ QWindowSystemInterface::handleWindowScreenChanged(window(), targetScreen);
+
+ nsWindow.restorable = NO;
+ nsWindow.level = windowLevel(flags);
if (shouldBePanel) {
// Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set
- window.hidesOnDeactivate = ((type & Qt::Tool) == Qt::Tool) && !alwaysShowToolWindow();
+ nsWindow.hidesOnDeactivate = ((type & Qt::Tool) == Qt::Tool) && !alwaysShowToolWindow();
// Make popup windows show on the same desktop as the parent full-screen window
- window.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary;
+ nsWindow.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary;
if ((type & Qt::Popup) == Qt::Popup) {
- window.hasShadow = YES;
- window.animationBehavior = NSWindowAnimationBehaviorUtilityWindow;
+ nsWindow.hasShadow = YES;
+ nsWindow.animationBehavior = NSWindowAnimationBehaviorUtilityWindow;
}
- } else if (shouldBeChildNSWindow) {
- window.collectionBehavior =
- NSWindowCollectionBehaviorManaged
- | NSWindowCollectionBehaviorIgnoresCycle
- | NSWindowCollectionBehaviorFullScreenAuxiliary;
- window.hasShadow = NO;
- window.animationBehavior = NSWindowAnimationBehaviorNone;
}
// Persist modality so we can detect changes later on
m_windowModality = QPlatformWindow::window()->modality();
- applyContentBorderThickness(window);
+ applyContentBorderThickness(nsWindow);
// Prevent CoreGraphics RGB32 -> RGB64 backing store conversions on deep color
// displays by forcing 8-bit components, unless a deep color format has been
@@ -1903,11 +1454,11 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBeChildNSWindow, bool sh
surfaceFormat.blueBufferSize() > 8;
bool usesLayer = view().layer;
if (usesCoreGraphics && !usesDeepColor && !usesLayer) {
- [window setDynamicDepthLimit:NO];
- [window setDepthLimit:NSWindowDepthTwentyfourBitRGB];
+ [nsWindow setDynamicDepthLimit:NO];
+ [nsWindow setDepthLimit:NSWindowDepthTwentyfourBitRGB];
}
- return window;
+ return nsWindow;
}
bool QCocoaWindow::alwaysShowToolWindow() const
@@ -1923,19 +1474,6 @@ void QCocoaWindow::removeMonitor()
monitor = nil;
}
-// Returns the current global screen geometry for the nswindow associated with this window.
-QRect QCocoaWindow::nativeWindowGeometry() const
-{
- if (!m_nsWindow || isChildNSWindow())
- return geometry();
-
- NSRect rect = [m_nsWindow frame];
- QPlatformScreen *onScreen = QPlatformScreen::platformScreenForWindow(window());
- int flippedY = onScreen->geometry().height() - rect.origin.y - rect.size.height; // account for nswindow inverted y.
- QRect qRect = QRect(rect.origin.x, flippedY, rect.size.width, rect.size.height);
- return qRect;
-}
-
/*!
Applies the given state to the NSWindow, going in/out of minimize/zoomed/fullscreen
@@ -1943,13 +1481,15 @@ QRect QCocoaWindow::nativeWindowGeometry() const
updated yet, so window()->windowState() will reflect the previous state that was
reported to QtGui.
*/
-void QCocoaWindow::applyWindowState(Qt::WindowState newState)
+void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState)
{
- const Qt::WindowState currentState = windowState();
- if (newState == currentState)
+ if (!isContentView())
return;
- if (!m_nsWindow)
+ const Qt::WindowState currentState = windowState();
+ const Qt::WindowState newState = QWindowPrivate::effectiveState(requestedState);
+
+ if (newState == currentState)
return;
const NSSize contentSize = m_view.frame.size;
@@ -1957,23 +1497,25 @@ void QCocoaWindow::applyWindowState(Qt::WindowState newState)
// If content view width or height is 0 then the window animations will crash so
// do nothing. We report the current state back to reflect the failed operation.
qWarning("invalid window content view size, check your window geometry");
- reportCurrentWindowState(true);
+ handleWindowStateChanged(HandleUnconditionally);
return;
}
- if (m_nsWindow.styleMask & NSUtilityWindowMask) {
- // Utility panels cannot be fullscreen
- qWarning() << window()->type() << "windows can not be made full screen";
- reportCurrentWindowState(true);
+ const NSWindow *nsWindow = m_view.window;
+
+ if (nsWindow.styleMask & NSUtilityWindowMask
+ && newState & (Qt::WindowMinimized | Qt::WindowFullScreen)) {
+ qWarning() << window()->type() << "windows can not be made" << newState;
+ handleWindowStateChanged(HandleUnconditionally);
return;
}
- const id sender = m_nsWindow;
+ const id sender = nsWindow;
// First we need to exit states that can't transition directly to other states
switch (currentState) {
case Qt::WindowMinimized:
- [m_nsWindow deminiaturize:sender];
+ [nsWindow deminiaturize:sender];
Q_ASSERT_X(windowState() != Qt::WindowMinimized, "QCocoaWindow",
"[NSWindow deminiaturize:] is synchronous");
break;
@@ -1999,7 +1541,7 @@ void QCocoaWindow::applyWindowState(Qt::WindowState newState)
toggleMaximized();
break;
case Qt::WindowMinimized:
- [m_nsWindow miniaturize:sender];
+ [nsWindow miniaturize:sender];
break;
case Qt::WindowNoState:
if (windowState() == Qt::WindowMaximized)
@@ -2012,27 +1554,31 @@ void QCocoaWindow::applyWindowState(Qt::WindowState newState)
void QCocoaWindow::toggleMaximized()
{
+ const NSWindow *window = m_view.window;
+
// The NSWindow needs to be resizable, otherwise the window will
// not be possible to zoom back to non-zoomed state.
- const bool wasResizable = m_nsWindow.styleMask & NSResizableWindowMask;
- m_nsWindow.styleMask |= NSResizableWindowMask;
+ const bool wasResizable = window.styleMask & NSResizableWindowMask;
+ window.styleMask |= NSResizableWindowMask;
- const id sender = m_nsWindow;
- [m_nsWindow zoom:sender];
+ const id sender = window;
+ [window zoom:sender];
if (!wasResizable)
- m_nsWindow.styleMask &= ~NSResizableWindowMask;
+ window.styleMask &= ~NSResizableWindowMask;
}
void QCocoaWindow::toggleFullScreen()
{
+ const NSWindow *window = m_view.window;
+
// The window needs to have the correct collection behavior for the
// toggleFullScreen call to have an effect. The collection behavior
// will be reset in windowDidEnterFullScreen/windowDidLeaveFullScreen.
- m_nsWindow.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
+ window.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
- const id sender = m_nsWindow;
- [m_nsWindow toggleFullScreen:sender];
+ const id sender = window;
+ [window toggleFullScreen:sender];
}
bool QCocoaWindow::isTransitioningToFullScreen() const
@@ -2060,22 +1606,12 @@ Qt::WindowState QCocoaWindow::windowState() const
return Qt::WindowNoState;
}
-void QCocoaWindow::reportCurrentWindowState(bool unconditionally)
-{
- Qt::WindowState currentState = windowState();
- if (!unconditionally && currentState == m_lastReportedWindowState)
- return;
-
- QWindowSystemInterface::handleWindowStateChanged<QWindowSystemInterface::SynchronousDelivery>(
- window(), currentState, m_lastReportedWindowState);
- m_lastReportedWindowState = currentState;
-}
-
bool QCocoaWindow::setWindowModified(bool modified)
{
- if (!m_nsWindow)
+ if (!isContentView())
return false;
- [m_nsWindow setDocumentEdited:(modified?YES:NO)];
+
+ m_view.window.documentEdited = modified;
return true;
}
@@ -2089,51 +1625,19 @@ QCocoaMenuBar *QCocoaWindow::menubar() const
return m_menubar;
}
-// Finds the effective cursor for this window by walking up the
-// ancestor chain (including this window) until a set cursor is
-// found. Returns nil if there is not set cursor.
-NSCursor *QCocoaWindow::effectiveWindowCursor() const
-{
-
- if (m_windowCursor)
- return m_windowCursor;
- if (!QPlatformWindow::parent())
- return nil;
- return static_cast<QCocoaWindow *>(QPlatformWindow::parent())->effectiveWindowCursor();
-}
-
-// Applies the cursor as returned by effectiveWindowCursor(), handles
-// the special no-cursor-set case by setting the arrow cursor.
-void QCocoaWindow::applyEffectiveWindowCursor()
-{
- NSCursor *effectiveCursor = effectiveWindowCursor();
- if (effectiveCursor) {
- [effectiveCursor set];
- } else {
- // We wold like to _unset_ the cursor here; but there is no such
- // API. Fall back to setting the default arrow cursor.
- [[NSCursor arrowCursor] set];
- }
-}
-
void QCocoaWindow::setWindowCursor(NSCursor *cursor)
{
- if (m_windowCursor == cursor)
+ // Setting a cursor in a foreign view is not supported
+ if (isForeignWindow())
return;
- // Setting a cursor in a foregin view is not supported.
- if (isForeignWindow())
+ QNSView *view = qnsview_cast(m_view);
+ if (cursor == view.cursor)
return;
- [m_windowCursor release];
- m_windowCursor = cursor;
- [m_windowCursor retain];
+ view.cursor = cursor;
- // The installed view tracking area (see QNSView updateTrackingAreas) will
- // handle cursor updates on mouse enter/leave. Handle the case where the
- // mouse is on the this window by changing the cursor immediately.
- if (m_windowUnderMouse)
- applyEffectiveWindowCursor();
+ [m_view.window invalidateCursorRectsForView:m_view];
}
void QCocoaWindow::registerTouch(bool enable)
@@ -2152,35 +1656,38 @@ void QCocoaWindow::setContentBorderThickness(int topThickness, int bottomThickne
bool enable = (topThickness > 0 || bottomThickness > 0);
m_drawContentBorderGradient = enable;
- applyContentBorderThickness(m_nsWindow);
+ applyContentBorderThickness();
}
void QCocoaWindow::registerContentBorderArea(quintptr identifier, int upper, int lower)
{
m_contentBorderAreas.insert(identifier, BorderRange(identifier, upper, lower));
- applyContentBorderThickness(m_nsWindow);
+ applyContentBorderThickness();
}
void QCocoaWindow::setContentBorderAreaEnabled(quintptr identifier, bool enable)
{
m_enabledContentBorderAreas.insert(identifier, enable);
- applyContentBorderThickness(m_nsWindow);
+ applyContentBorderThickness();
}
void QCocoaWindow::setContentBorderEnabled(bool enable)
{
m_drawContentBorderGradient = enable;
- applyContentBorderThickness(m_nsWindow);
+ applyContentBorderThickness();
}
void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
{
+ if (!window && isContentView())
+ window = m_view.window;
+
if (!window)
return;
if (!m_drawContentBorderGradient) {
- [window setStyleMask:[window styleMask] & ~NSTexturedBackgroundWindowMask];
- [[[window contentView] superview] setNeedsDisplay:YES];
+ window.styleMask = window.styleMask & ~NSTexturedBackgroundWindowMask;
+ [window.contentView.superview setNeedsDisplay:YES];
window.titlebarAppearsTransparent = NO;
return;
}
@@ -2219,22 +1726,23 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
void QCocoaWindow::updateNSToolbar()
{
- if (!m_nsWindow)
+ if (!isContentView())
return;
NSToolbar *toolbar = QCocoaIntegration::instance()->toolbar(window());
+ const NSWindow *window = m_view.window;
- if ([m_nsWindow toolbar] == toolbar)
+ if (window.toolbar == toolbar)
return;
- [m_nsWindow setToolbar: toolbar];
- [m_nsWindow setShowsToolbarButton:YES];
+ window.toolbar = toolbar;
+ window.showsToolbarButton = YES;
}
bool QCocoaWindow::testContentBorderAreaPosition(int position) const
{
- return m_nsWindow && m_drawContentBorderGradient &&
- 0 <= position && position < [m_nsWindow contentBorderThicknessForEdge: NSMaxYEdge];
+ return isContentView() && m_drawContentBorderGradient &&
+ 0 <= position && position < [m_view.window contentBorderThicknessForEdge:NSMaxYEdge];
}
qreal QCocoaWindow::devicePixelRatio() const
@@ -2248,85 +1756,6 @@ qreal QCocoaWindow::devicePixelRatio() const
return backingSize.height;
}
-// Returns whether the window can be expose, which it can
-// if it is on screen and has a valid geometry.
-bool QCocoaWindow::isWindowExposable()
-{
- QSize size = geometry().size();
- bool validGeometry = (size.width() > 0 && size.height() > 0);
- bool validScreen = ([[m_view window] screen] != 0);
- bool nonHiddenSuperView = ![[m_view superview] isHidden];
- return (validGeometry && validScreen && nonHiddenSuperView);
-}
-
-// Exposes the window by posting an expose event to QWindowSystemInterface
-void QCocoaWindow::exposeWindow()
-{
- m_geometryUpdateExposeAllowed = true;
-
- if (!isWindowExposable())
- return;
-
- if (window()->isTopLevel()) {
- // Update the QWindow's screen property. This property is set
- // to QGuiApplication::primaryScreen() at QWindow construciton
- // time, and we won't get a NSWindowDidChangeScreenNotification
- // on show. The case where the window is initially displayed
- // on a non-primary screen needs special handling here.
- if (QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenForNSScreen(m_nsWindow.screen))
- window()->setScreen(cocoaScreen->screen());
- }
-
- if (!m_isExposed) {
- m_isExposed = true;
- m_exposedGeometry = geometry();
- m_exposedDevicePixelRatio = devicePixelRatio();
- QRect geometry(QPoint(0, 0), m_exposedGeometry.size());
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow: exposeWindow" << window() << geometry;
- QWindowSystemInterface::handleExposeEvent(window(), geometry);
- }
-}
-
-// Obscures the window by posting an empty expose event to QWindowSystemInterface
-void QCocoaWindow::obscureWindow()
-{
- if (m_isExposed) {
- m_geometryUpdateExposeAllowed = false;
- m_isExposed = false;
-
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::obscureWindow" << window();
- QWindowSystemInterface::handleExposeEvent(window(), QRegion());
- }
-}
-
-// Updates window geometry by posting an expose event to QWindowSystemInterface
-void QCocoaWindow::updateExposedGeometry()
-{
- // updateExposedGeometry is not allowed to send the initial expose. If you want
- // that call exposeWindow();
- if (!m_geometryUpdateExposeAllowed)
- return;
-
- // Do not send incorrect exposes in case the window is not even visible yet.
- // We might get here as a result of a resize() from QWidget's show(), for instance.
- if (!window()->isVisible())
- return;
-
- if (!isWindowExposable())
- return;
-
- if (m_exposedGeometry.size() == geometry().size() && m_exposedDevicePixelRatio == devicePixelRatio())
- return;
-
- m_isExposed = true;
- m_exposedGeometry = geometry();
- m_exposedDevicePixelRatio = devicePixelRatio();
-
- QRect geometry(QPoint(0, 0), m_exposedGeometry.size());
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::updateExposedGeometry" << window() << geometry;
- QWindowSystemInterface::handleExposeEvent(window(), geometry);
-}
-
QWindow *QCocoaWindow::childWindowAt(QPoint windowPoint)
{
QWindow *targetWindow = window();
@@ -2376,8 +1805,11 @@ QPoint QCocoaWindow::bottomLeftClippedByNSWindowOffset() const
QMargins QCocoaWindow::frameMargins() const
{
- NSRect frameW = [m_nsWindow frame];
- NSRect frameC = [m_nsWindow contentRectForFrameRect:frameW];
+ if (!isContentView())
+ return QMargins();
+
+ NSRect frameW = m_view.window.frame;
+ NSRect frameC = [m_view.window contentRectForFrameRect:frameW];
return QMargins(frameW.origin.x - frameC.origin.x,
(frameW.origin.y + frameW.size.height) - (frameC.origin.y + frameC.size.height),
@@ -2390,4 +1822,19 @@ void QCocoaWindow::setFrameStrutEventsEnabled(bool enabled)
m_frameStrutEventsEnabled = enabled;
}
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QCocoaWindow *window)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QCocoaWindow(" << (const void *)window;
+ if (window)
+ debug << ", window=" << window->window();
+ debug << ')';
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
#include "moc_qcocoawindow.cpp"
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac.mm b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
index f0ea3b1e66..9eca4d2d43 100644
--- a/src/plugins/platforms/cocoa/qmultitouch_mac.mm
+++ b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
@@ -39,10 +39,15 @@
#include "qmultitouch_mac_p.h"
#include "qcocoahelpers.h"
+#include "qcocoascreen.h"
+#include <private/qtouchdevice_p.h>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcInputDevices, "qt.qpa.input.devices")
+
QHash<qint64, QCocoaTouch*> QCocoaTouch::_currentTouches;
+QHash<quint64, QTouchDevice*> QCocoaTouch::_touchDevices;
QPointF QCocoaTouch::_screenReferencePos;
QPointF QCocoaTouch::_trackpadReferencePos;
int QCocoaTouch::_idAssignmentCount = 0;
@@ -79,7 +84,7 @@ void QCocoaTouch::updateTouchData(NSTouch *nstouch, NSTouchPhase phase)
if (_touchPoint.id == 0 && phase == NSTouchPhaseBegan) {
_trackpadReferencePos = qnpos;
- _screenReferencePos = qt_mac_flipPoint([NSEvent mouseLocation]);
+ _screenReferencePos = QCocoaScreen::mapFromNative([NSEvent mouseLocation]);
}
QPointF screenPos = _screenReferencePos;
@@ -209,4 +214,19 @@ QCocoaTouch::getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch)
return touchPoints.values();
}
+QTouchDevice *QCocoaTouch::getTouchDevice(QTouchDevice::DeviceType type, quint64 id)
+{
+ QTouchDevice *ret = _touchDevices.value(id);
+ if (!ret) {
+ ret = new QTouchDevice;
+ ret->setType(type);
+ ret->setCapabilities(QTouchDevice::Position | QTouchDevice::NormalizedPosition | QTouchDevice::MouseEmulation);
+ QWindowSystemInterface::registerTouchDevice(ret);
+ _touchDevices.insert(id, ret);
+ qCDebug(lcInputDevices) << "touch device" << id << "of type" << type
+ << "registered as Qt device" << QTouchDevicePrivate::get(ret)->id;
+ }
+ return ret;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac_p.h b/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
index 77af86c9c7..044bcd1882 100644
--- a/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
+++ b/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
@@ -66,8 +66,10 @@ class QCocoaTouch
public:
static QList<QWindowSystemInterface::TouchPoint> getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch);
static void setMouseInDraggingState(bool inDraggingState);
+ static QTouchDevice *getTouchDevice(QTouchDevice::DeviceType type, quint64 id);
private:
+ static QHash<quint64, QTouchDevice*> _touchDevices;
static QHash<qint64, QCocoaTouch*> _currentTouches;
static QPointF _screenReferencePos;
static QPointF _trackpadReferencePos;
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index 384f14ba3a..f8903725a6 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -51,19 +51,12 @@
QT_BEGIN_NAMESPACE
class QCocoaWindow;
-class QCocoaBackingStore;
class QCocoaGLContext;
QT_END_NAMESPACE
Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
@interface QT_MANGLE_NAMESPACE(QNSView) : NSView <NSTextInputClient> {
- QCocoaBackingStore* m_backingStore;
- QPoint m_backingStoreOffset;
- QRegion m_maskRegion;
- CGImageRef m_maskImage;
- uchar *m_maskData;
- bool m_shouldInvalidateWindowShadow;
QPointer<QCocoaWindow> m_platformWindow;
NSTrackingArea *m_trackingArea;
Qt::MouseButtons m_buttons;
@@ -73,6 +66,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
QPointer<QObject> m_composingFocusObject;
bool m_sendKeyEvent;
QStringList *currentCustomDragTypes;
+ bool m_dontOverrideCtrlLMB;
bool m_sendUpAsRightButton;
Qt::KeyboardModifiers currentWheelModifiers;
#ifndef QT_NO_OPENGL
@@ -89,28 +83,22 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
QSet<quint32> m_acceptedKeyDowns;
}
+@property (nonatomic, retain) NSCursor *cursor;
+
- (id)init;
- (id)initWithCocoaWindow:(QCocoaWindow *)platformWindow;
#ifndef QT_NO_OPENGL
- (void)setQCocoaGLContext:(QCocoaGLContext *)context;
#endif
-- (void)flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset;
-- (void)clearBackingStore:(QCocoaBackingStore *)backingStore;
-- (void)setMaskRegion:(const QRegion *)region;
-- (void)invalidateWindowShadowIfNeeded;
- (void)drawRect:(NSRect)dirtyRect;
-- (void)drawBackingStoreUsingCoreGraphics:(NSRect)dirtyRect;
-- (void)updateGeometry;
- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification;
- (void)viewDidHide;
-- (void)viewDidUnhide;
- (void)removeFromSuperview;
- (void)cancelComposingText;
- (BOOL)isFlipped;
- (BOOL)acceptsFirstResponder;
- (BOOL)becomeFirstResponder;
-- (BOOL)hasMask;
- (BOOL)isOpaque;
- (void)convertFromScreen:(NSPoint)mouseLocation toWindowPoint:(QPointF *)qtWindowPoint andScreenPoint:(QPointF *)qtScreenPoint;
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 78287b482c..216b2f1287 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -42,6 +42,7 @@
#include "qnsview.h"
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
+#include "qcocoascreen.h"
#include "qmultitouch_mac_p.h"
#include "qcocoadrag.h"
#include "qcocoainputcontext.h"
@@ -53,6 +54,7 @@
#include <QtCore/qsysinfo.h>
#include <private/qguiapplication_p.h>
#include <private/qcoregraphics_p.h>
+#include <private/qwindow_p.h>
#include "qcocoabackingstore.h"
#ifndef QT_NO_OPENGL
#include "qcocoaglcontext.h"
@@ -69,16 +71,6 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
#endif
Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
-static QTouchDevice *touchDevice = 0;
-
-static bool _q_dontOverrideCtrlLMB = false;
-
-@interface NSEvent (Qt_Compile_Leopard_DeviceDelta)
- - (CGFloat)deviceDeltaX;
- - (CGFloat)deviceDeltaY;
- - (CGFloat)deviceDeltaZ;
-@end
-
@interface QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) : NSObject
{
QNSView *view;
@@ -121,7 +113,7 @@ static bool _q_dontOverrideCtrlLMB = false;
- (void)cursorUpdate:(NSEvent *)theEvent
{
- [self cursorUpdate:theEvent];
+ [view cursorUpdate:theEvent];
}
@end
@@ -133,17 +125,9 @@ static bool _q_dontOverrideCtrlLMB = false;
@implementation QT_MANGLE_NAMESPACE(QNSView)
-+ (void)initialize
-{
- _q_dontOverrideCtrlLMB = qt_mac_resolveOption(false, "QT_MAC_DONT_OVERRIDE_CTRL_LMB");
-}
-
- (id) init
{
if (self = [super initWithFrame:NSZeroRect]) {
- m_backingStore = 0;
- m_maskImage = 0;
- m_shouldInvalidateWindowShadow = false;
m_buttons = Qt::NoButton;
m_acceptedMouseDowns = Qt::NoButton;
m_frameStrutButtons = Qt::NoButton;
@@ -153,6 +137,7 @@ static bool _q_dontOverrideCtrlLMB = false;
m_shouldSetGLContextinDrawRect = false;
#endif
currentCustomDragTypes = 0;
+ m_dontOverrideCtrlLMB = false;
m_sendUpAsRightButton = false;
m_inputSource = 0;
m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self];
@@ -160,28 +145,19 @@ static bool _q_dontOverrideCtrlLMB = false;
m_scrolling = false;
m_updatingDrag = false;
m_currentlyInterpretedKeyEvent = 0;
-
- if (!touchDevice) {
- touchDevice = new QTouchDevice;
- touchDevice->setType(QTouchDevice::TouchPad);
- touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::NormalizedPosition | QTouchDevice::MouseEmulation);
- QWindowSystemInterface::registerTouchDevice(touchDevice);
- }
-
m_isMenuView = false;
self.focusRingType = NSFocusRingTypeNone;
+ self.cursor = nil;
}
return self;
}
- (void)dealloc
{
- CGImageRelease(m_maskImage);
if (m_trackingArea) {
[self removeTrackingArea:m_trackingArea];
[m_trackingArea release];
}
- m_maskImage = 0;
[m_inputSource release];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[m_mouseMoveHelper release];
@@ -199,6 +175,7 @@ static bool _q_dontOverrideCtrlLMB = false;
m_platformWindow = platformWindow;
m_sendKeyEvent = false;
+ m_dontOverrideCtrlLMB = qt_mac_resolveOption(false, platformWindow->window(), "_q_platform_MacDontOverrideCtrlLMB", "QT_MAC_DONT_OVERRIDE_CTRL_LMB");
m_trackingArea = nil;
#ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR
@@ -226,6 +203,22 @@ static bool _q_dontOverrideCtrlLMB = false;
return self;
}
+- (NSString *)description
+{
+ NSMutableString *description = [NSMutableString stringWithString:[super description]];
+
+#ifndef QT_NO_DEBUG_STREAM
+ QString platformWindowDescription;
+ QDebug debug(&platformWindowDescription);
+ debug.nospace() << "; " << m_platformWindow << ">";
+
+ NSRange lastCharacter = [description rangeOfComposedCharacterSequenceAtIndex:description.length - 1];
+ [description replaceCharactersInRange:lastCharacter withString:platformWindowDescription.toNSString()];
+#endif
+
+ return description;
+}
+
#ifndef QT_NO_OPENGL
- (void) setQCocoaGLContext:(QCocoaGLContext *)context
{
@@ -249,18 +242,13 @@ static bool _q_dontOverrideCtrlLMB = false;
if ([self superview]) {
m_platformWindow->m_viewIsEmbedded = true;
QWindowSystemInterface::handleGeometryChange(m_platformWindow->window(), m_platformWindow->geometry());
- m_platformWindow->updateExposedGeometry();
+ [self setNeedsDisplay:YES];
QWindowSystemInterface::flushWindowSystemEvents();
} else {
m_platformWindow->m_viewIsEmbedded = false;
}
}
-- (void)viewDidMoveToWindow
-{
- m_backingStore = Q_NULLPTR;
-}
-
- (QWindow *)topLevelWindow
{
if (!m_platformWindow)
@@ -279,77 +267,6 @@ static bool _q_dontOverrideCtrlLMB = false;
return focusWindow;
}
-- (void)updateGeometry
-{
- if (!m_platformWindow)
- return;
-
- QRect geometry;
-
- if (self.window.parentWindow) {
- return;
-#if 0
- //geometry = QRectF::fromCGRect([self frame]).toRect();
- qDebug() << "nsview updateGeometry" << m_platformWindow->window();
- QRect screenRect = QRectF::fromCGRect([m_platformWindow->m_nsWindow convertRectToScreen:[self frame]]).toRect();
- qDebug() << "screenRect" << screenRect;
-
- screenRect.moveTop(qt_mac_flipYCoordinate(screenRect.y() + screenRect.height()));
- geometry = QRect(m_platformWindow->window()->parent()->mapFromGlobal(screenRect.topLeft()), screenRect.size());
- qDebug() << "geometry" << geometry;
-#endif
- //geometry = QRect(screenRect.origin.x, qt_mac_flipYCoordinate(screenRect.origin.y + screenRect.size.height), screenRect.size.width, screenRect.size.height);
- } else if (m_platformWindow->m_nsWindow) {
- // top level window, get window rect and flip y.
- NSRect rect = [self frame];
- NSRect windowRect = [[self window] frame];
- geometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height);
- } else if (m_platformWindow->m_viewIsToBeEmbedded) {
- // embedded child window, use the frame rect ### merge with case below
- geometry = QRectF::fromCGRect(NSRectToCGRect([self bounds])).toRect();
- } else {
- // child window, use the frame rect
- geometry = QRectF::fromCGRect(NSRectToCGRect([self frame])).toRect();
- }
-
- if (m_platformWindow->m_nsWindow && geometry == m_platformWindow->geometry())
- return;
-
- const bool isResize = geometry.size() != m_platformWindow->geometry().size();
-
- // It can happen that self.window is nil (if we are changing
- // styleMask from/to borderless and content view is being re-parented)
- // - this results in an invalid coordinates.
- if (m_platformWindow->m_inSetStyleMask && !self.window)
- return;
-
- qCDebug(lcQpaCocoaWindow) << "[QNSView udpateGeometry:]" << m_platformWindow->window()
- << "current" << m_platformWindow->geometry() << "new" << geometry;
-
- // Call setGeometry on QPlatformWindow. (not on QCocoaWindow,
- // doing that will initiate a geometry change it and possibly create
- // an infinite loop when this notification is triggered again.)
- m_platformWindow->QPlatformWindow::setGeometry(geometry);
-
- // Don't send the geometry change if the QWindow is designated to be
- // embedded in a foreign view hiearchy but has not actually been
- // embedded yet - it's too early.
- if (m_platformWindow->m_viewIsToBeEmbedded && !m_platformWindow->m_viewIsEmbedded)
- return;
-
- // Send a geometry change event to Qt, if it's ready to handle events
- if (!m_platformWindow->m_inConstructor) {
- QWindowSystemInterface::handleGeometryChange(m_platformWindow->window(), geometry);
- m_platformWindow->updateExposedGeometry();
- // Guard against processing window system events during QWindow::setGeometry
- // calles, which Qt and Qt applications do not excpect.
- if (!m_platformWindow->m_inSetGeometry)
- QWindowSystemInterface::flushWindowSystemEvents();
- else if (isResize)
- m_backingStore = 0;
- }
-}
-
- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification
{
Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification)
@@ -361,12 +278,13 @@ static bool _q_dontOverrideCtrlLMB = false;
- (void)viewDidHide
{
- m_platformWindow->obscureWindow();
-}
+ if (!m_platformWindow->isExposed())
+ return;
-- (void)viewDidUnhide
-{
- m_platformWindow->exposeWindow();
+ m_platformWindow->handleExposeEvent(QRegion());
+
+ // Note: setNeedsDisplay is automatically called for
+ // viewDidUnhide so no reason to override it here.
}
- (void)removeFromSuperview
@@ -375,35 +293,6 @@ static bool _q_dontOverrideCtrlLMB = false;
[super removeFromSuperview];
}
-- (void) flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset
-{
- qCDebug(lcQpaCocoaWindow) << "[QNSView flushBackingStore:]" << m_platformWindow->window() << region.rectCount() << region.boundingRect() << offset;
-
- m_backingStore = backingStore;
- m_backingStoreOffset = offset * m_backingStore->paintDevice()->devicePixelRatio();
-
- // Prevent buildup of NSDisplayCycle objects during setNeedsDisplayInRect, which
- // would normally be released as part of the root runloop's autorelease pool, but
- // can be kept alive during repeated painting which starve the root runloop.
- // FIXME: Move this to the event dispatcher, to cover more cases of starvation.
- // FIXME: Figure out if there's a way to detect and/or prevent runloop starvation.
- QMacAutoReleasePool pool;
-
- for (const QRect &rect : region)
- [self setNeedsDisplayInRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
-}
-
-- (void)clearBackingStore:(QCocoaBackingStore *)backingStore
-{
- if (backingStore == m_backingStore)
- m_backingStore = 0;
-}
-
-- (BOOL) hasMask
-{
- return !m_maskRegion.isEmpty();
-}
-
- (BOOL) isOpaque
{
if (!m_platformWindow)
@@ -411,49 +300,21 @@ static bool _q_dontOverrideCtrlLMB = false;
return m_platformWindow->isOpaque();
}
-- (void) setMaskRegion:(const QRegion *)region
-{
- m_shouldInvalidateWindowShadow = true;
- m_maskRegion = *region;
- if (m_maskImage)
- CGImageRelease(m_maskImage);
- if (region->isEmpty()) {
- m_maskImage = 0;
- return;
- }
-
- const QRect &rect = region->boundingRect();
- QImage tmp(rect.size(), QImage::Format_RGB32);
- tmp.fill(Qt::white);
- QPainter p(&tmp);
- p.setClipRegion(*region);
- p.fillRect(rect, Qt::black);
- p.end();
- QImage maskImage = QImage(rect.size(), QImage::Format_Indexed8);
- for (int y=0; y<rect.height(); ++y) {
- const uint *src = (const uint *) tmp.constScanLine(y);
- uchar *dst = maskImage.scanLine(y);
- for (int x=0; x<rect.width(); ++x) {
- dst[x] = src[x] & 0xff;
- }
- }
- m_maskImage = qt_mac_toCGImageMask(maskImage);
-}
-
-- (void)invalidateWindowShadowIfNeeded
-{
- if (m_shouldInvalidateWindowShadow && m_platformWindow->m_nsWindow) {
- [m_platformWindow->m_nsWindow invalidateShadow];
- m_shouldInvalidateWindowShadow = false;
- }
-}
-
- (void)drawRect:(NSRect)dirtyRect
{
+ Q_UNUSED(dirtyRect);
+
if (!m_platformWindow)
return;
- qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:]" << m_platformWindow->window() << QRectF::fromCGRect(NSRectToCGRect(dirtyRect));
+ QRegion exposedRegion;
+ const NSRect *dirtyRects;
+ NSInteger numDirtyRects;
+ [self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects];
+ for (int i = 0; i < numDirtyRects; ++i)
+ exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect();
+
+ qCDebug(lcQpaCocoaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
#ifndef QT_NO_OPENGL
if (m_glContext && m_shouldSetGLContextinDrawRect) {
@@ -462,85 +323,44 @@ static bool _q_dontOverrideCtrlLMB = false;
}
#endif
- if (m_platformWindow->m_drawContentBorderGradient)
- NSDrawWindowBackground(dirtyRect);
-
- if (m_backingStore)
- [self drawBackingStoreUsingCoreGraphics:dirtyRect];
+ m_platformWindow->handleExposeEvent(exposedRegion);
+
+ if (qt_window_private(m_platformWindow->window())->updateRequestPending) {
+ // A call to QWindow::requestUpdate was issued during the expose event, or we
+ // had to deliver a real expose event and still need to deliver the update.
+ // But AppKit will reset the needsDisplay state of the view after completing
+ // the current display cycle, so we need to defer the request to redisplay.
+ // FIXME: Perhaps this should be a trigger to enable CADisplayLink?
+ qCDebug(lcQpaCocoaDrawing) << "[QNSView drawRect:] issuing deferred setNeedsDisplay due to pending update request";
+ dispatch_async(dispatch_get_main_queue (), ^{
+ [self setNeedsDisplay:YES];
+ });
+ }
+}
- [self invalidateWindowShadowIfNeeded];
+- (BOOL)wantsUpdateLayer
+{
+ return YES;
}
-// Draws the backing store content to the QNSView using Core Graphics.
-// This function assumes that the QNSView is in a configuration that
-// supports Core Graphics, such as "classic" mode or layer mode with
-// the default layer.
-- (void)drawBackingStoreUsingCoreGraphics:(NSRect)dirtyRect
+- (void)updateLayer
{
- if (!m_backingStore)
+ if (!m_platformWindow)
return;
- // Calculate source and target rects. The target rect is the dirtyRect:
- CGRect dirtyWindowRect = NSRectToCGRect(dirtyRect);
-
- // The backing store source rect will be larger on retina displays.
- // Scale dirtyRect by the device pixel ratio:
- const qreal devicePixelRatio = m_backingStore->paintDevice()->devicePixelRatio();
- CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * devicePixelRatio,
- dirtyRect.origin.y * devicePixelRatio,
- dirtyRect.size.width * devicePixelRatio,
- dirtyRect.size.height * devicePixelRatio);
-
- NSGraphicsContext *nsGraphicsContext = [NSGraphicsContext currentContext];
- CGContextRef cgContext = (CGContextRef) [nsGraphicsContext graphicsPort];
-
- // Translate coordiate system from CoreGraphics (bottom-left) to NSView (top-left):
- CGContextSaveGState(cgContext);
- int dy = dirtyWindowRect.origin.y + CGRectGetMaxY(dirtyWindowRect);
-
- CGContextTranslateCTM(cgContext, 0, dy);
- CGContextScaleCTM(cgContext, 1, -1);
-
- // If a mask is set, modify the sub image accordingly:
- CGImageRef subMask = 0;
- if (m_maskImage) {
- subMask = CGImageCreateWithImageInRect(m_maskImage, dirtyWindowRect);
- CGContextClipToMask(cgContext, dirtyWindowRect, subMask);
- }
-
- // Clip out and draw the correct sub image from the (shared) backingstore:
- CGRect backingStoreRect = CGRectMake(
- dirtyBackingRect.origin.x + m_backingStoreOffset.x(),
- dirtyBackingRect.origin.y + m_backingStoreOffset.y(),
- dirtyBackingRect.size.width,
- dirtyBackingRect.size.height
- );
- CGImageRef bsCGImage = qt_mac_toCGImage(m_backingStore->toImage());
-
- // Prevent potentially costly color conversion by assiging the display
- // color space to the backingstore image.
- CGImageRef displayColorSpaceImage = CGImageCreateCopyWithColorSpace(bsCGImage,
- self.window.screen.colorSpace.CGColorSpace);
-
- CGImageRef cleanImg = CGImageCreateWithImageInRect(displayColorSpaceImage, backingStoreRect);
-
- // Optimization: Copy frame buffer content instead of blending for
- // top-level windows where Qt fills the entire window content area.
- // (But don't overpaint the title-bar gradient)
- if (m_platformWindow->m_nsWindow && !m_platformWindow->m_drawContentBorderGradient)
- CGContextSetBlendMode(cgContext, kCGBlendModeCopy);
+ qCDebug(lcQpaCocoaDrawing) << "[QNSView updateLayer]" << m_platformWindow->window();
- CGContextDrawImage(cgContext, dirtyWindowRect, cleanImg);
+ // FIXME: Find out if there's a way to resolve the dirty rect like in drawRect:
+ m_platformWindow->handleExposeEvent(QRectF::fromCGRect(self.bounds).toRect());
+}
- // Clean-up:
- CGContextRestoreGState(cgContext);
- CGImageRelease(cleanImg);
- CGImageRelease(subMask);
- CGImageRelease(bsCGImage);
- CGImageRelease(displayColorSpaceImage);
+- (void)viewDidChangeBackingProperties
+{
+ if (self.layer)
+ self.layer.contentsScale = self.window.backingScaleFactor;
}
-- (BOOL) isFlipped
+- (BOOL)isFlipped
{
return YES;
}
@@ -623,8 +443,7 @@ static bool _q_dontOverrideCtrlLMB = false;
nsWindowPoint = windowRect.origin; // NSWindow coordinates
NSPoint nsViewPoint = [self convertPoint: nsWindowPoint fromView: nil]; // NSView/QWindow coordinates
*qtWindowPoint = QPointF(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates
-
- *qtScreenPoint = QPointF(mouseLocation.x, qt_mac_flipYCoordinate(mouseLocation.y)); // Qt screen coordinates
+ *qtScreenPoint = QCocoaScreen::mapFromNative(mouseLocation);
}
- (void)resetMouseButtons
@@ -661,12 +480,6 @@ static bool _q_dontOverrideCtrlLMB = false;
QPointF qtWindowPoint;
QPointF qtScreenPoint;
QNSView *targetView = self;
- if (m_platformWindow && m_platformWindow->m_forwardWindow) {
- if (theEvent.type == NSLeftMouseDragged || theEvent.type == NSLeftMouseUp)
- targetView = qnsview_cast(m_platformWindow->m_forwardWindow->view());
- else
- m_platformWindow->m_forwardWindow.clear();
- }
if (!targetView.platformWindow)
return;
@@ -741,7 +554,7 @@ static bool _q_dontOverrideCtrlLMB = false;
NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil];
QPoint qtWindowPoint = QPoint(nsViewPoint.x, titleBarHeight + nsViewPoint.y);
NSPoint screenPoint = [window convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 0, 0)].origin;
- QPoint qtScreenPoint = QPoint(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y));
+ QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
ulong timestamp = [theEvent timestamp] * 1000;
QWindowSystemInterface::handleFrameStrutMouseEvent(m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint, m_frameStrutButtons);
@@ -760,7 +573,8 @@ static bool _q_dontOverrideCtrlLMB = false;
Q_UNUSED(qtScreenPoint);
// Maintain masked state for the button for use by MouseDragged and MouseUp.
- const bool masked = [self hasMask] && !m_maskRegion.contains(qtWindowPoint.toPoint());
+ QRegion mask = m_platformWindow->window()->mask();
+ const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
if (masked)
m_acceptedMouseDowns &= ~button;
else
@@ -832,7 +646,7 @@ static bool _q_dontOverrideCtrlLMB = false;
if (!popups->isEmpty()) {
// Check if the click is outside all popups.
bool inside = false;
- QPointF qtScreenPoint = qt_mac_flipPoint([self screenMousePoint:theEvent]);
+ QPointF qtScreenPoint = QCocoaScreen::mapFromNative([self screenMousePoint:theEvent]);
for (QList<QCocoaWindow *>::const_iterator it = popups->begin(); it != popups->end(); ++it) {
if ((*it)->geometry().contains(qtScreenPoint.toPoint())) {
inside = true;
@@ -858,8 +672,8 @@ static bool _q_dontOverrideCtrlLMB = false;
[self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
Q_UNUSED(qtScreenPoint);
- const bool masked = [self hasMask] && !m_maskRegion.contains(qtWindowPoint.toPoint());
-
+ QRegion mask = m_platformWindow->window()->mask();
+ const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
// Maintain masked state for the button for use by MouseDragged and Up.
if (masked)
m_acceptedMouseDowns &= ~Qt::LeftButton;
@@ -875,7 +689,8 @@ static bool _q_dontOverrideCtrlLMB = false;
if ([self hasMarkedText]) {
[[NSTextInputContext currentInputContext] handleEvent:theEvent];
} else {
- if (!_q_dontOverrideCtrlLMB && [QNSView convertKeyModifiers:[theEvent modifierFlags]] & Qt::MetaModifier) {
+ auto ctrlOrMetaModifier = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? Qt::ControlModifier : Qt::MetaModifier;
+ if (!m_dontOverrideCtrlLMB && [QNSView convertKeyModifiers:[theEvent modifierFlags]] & ctrlOrMetaModifier) {
m_buttons |= Qt::RightButton;
m_sendUpAsRightButton = true;
} else {
@@ -972,8 +787,16 @@ static bool _q_dontOverrideCtrlLMB = false;
- (void)cursorUpdate:(NSEvent *)theEvent
{
- Q_UNUSED(theEvent);
- m_platformWindow->applyEffectiveWindowCursor();
+ qCDebug(lcQpaCocoaMouse) << "[QNSView cursorUpdate:]" << self.cursor;
+
+ // Note: We do not get this callback when moving from a subview that
+ // uses the legacy cursorRect API, so the cursor is reset to the arrow
+ // cursor. See rdar://34183708
+
+ if (self.cursor)
+ [self.cursor set];
+ else
+ [super cursorUpdate:theEvent];
}
- (void)mouseMovedImpl:(NSEvent *)theEvent
@@ -994,7 +817,7 @@ static bool _q_dontOverrideCtrlLMB = false;
// the time of the leave. This is dificult to accomplish by
// handling mouseEnter and mouseLeave envents, since they are sent
// individually to different views.
- if (m_platformWindow->m_nsWindow && childWindow) {
+ if (m_platformWindow->isContentView() && childWindow) {
if (childWindow != m_platformWindow->m_enterLeaveTargetWindow) {
QWindowSystemInterface::handleEnterLeaveEvent(childWindow, m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
m_platformWindow->m_enterLeaveTargetWindow = childWindow;
@@ -1021,7 +844,7 @@ static bool _q_dontOverrideCtrlLMB = false;
return;
// Top-level windows generate enter events for sub-windows.
- if (!m_platformWindow->m_nsWindow)
+ if (!m_platformWindow->isContentView())
return;
QPointF windowPoint;
@@ -1043,7 +866,7 @@ static bool _q_dontOverrideCtrlLMB = false;
return;
// Top-level windows generate leave events for sub-windows.
- if (!m_platformWindow->m_nsWindow)
+ if (!m_platformWindow->isContentView())
return;
QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_enterLeaveTargetWindow);
@@ -1243,8 +1066,8 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points;
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, touchDevice, points);
+ qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
}
- (void)touchesMovedWithEvent:(NSEvent *)event
@@ -1254,8 +1077,8 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points;
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, touchDevice, points);
+ qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
}
- (void)touchesEndedWithEvent:(NSEvent *)event
@@ -1265,8 +1088,8 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points;
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, touchDevice, points);
+ qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
}
- (void)touchesCancelledWithEvent:(NSEvent *)event
@@ -1276,8 +1099,8 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points;
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, touchDevice, points);
+ qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
}
#ifndef QT_NO_GESTURES
@@ -1307,12 +1130,12 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
if ([self handleGestureAsBeginEnd:event])
return;
- qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification];
+ qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification] << "from device" << hex << [event deviceID];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), timestamp, Qt::ZoomNativeGesture,
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::ZoomNativeGesture,
[event magnification], windowPoint, screenPoint);
}
@@ -1322,12 +1145,12 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
return;
static bool zoomIn = true;
- qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn;
+ qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn << "from device" << hex << [event deviceID];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), timestamp, Qt::SmartZoomNativeGesture,
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::SmartZoomNativeGesture,
zoomIn ? 1.0f : 0.0f, windowPoint, screenPoint);
zoomIn = !zoomIn;
}
@@ -1344,7 +1167,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), timestamp, Qt::RotateNativeGesture,
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::RotateNativeGesture,
-[event rotation], windowPoint, screenPoint);
}
@@ -1353,7 +1176,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
if (!m_platformWindow)
return;
- qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY];
+ qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY] << "from device" << hex << [event deviceID];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
@@ -1369,7 +1192,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
else if ([event deltaY] == -1)
angle = 270.0f;
- QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), timestamp, Qt::SwipeNativeGesture,
+ QWindowSystemInterface::handleGestureEventWithRealValue(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::SwipeNativeGesture,
angle, windowPoint, screenPoint);
}
@@ -1382,8 +1205,8 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint;
- QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), timestamp, Qt::BeginNativeGesture,
+ qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::BeginNativeGesture,
windowPoint, screenPoint);
}
@@ -1392,12 +1215,12 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
if (!m_platformWindow)
return;
- qCDebug(lcQpaGestures) << "endGestureWithEvent";
+ qCDebug(lcQpaGestures) << "endGestureWithEvent" << "from device" << hex << [event deviceID];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), timestamp, Qt::EndNativeGesture,
+ QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::EndNativeGesture,
windowPoint, screenPoint);
}
#endif // QT_NO_GESTURES
@@ -1492,15 +1315,16 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
+ (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags
{
+ const bool dontSwapCtrlAndMeta = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
Qt::KeyboardModifiers qtMods =Qt::NoModifier;
if (modifierFlags & NSShiftKeyMask)
qtMods |= Qt::ShiftModifier;
if (modifierFlags & NSControlKeyMask)
- qtMods |= Qt::MetaModifier;
+ qtMods |= dontSwapCtrlAndMeta ? Qt::ControlModifier : Qt::MetaModifier;
if (modifierFlags & NSAlternateKeyMask)
qtMods |= Qt::AltModifier;
if (modifierFlags & NSCommandKeyMask)
- qtMods |= Qt::ControlModifier;
+ qtMods |= dontSwapCtrlAndMeta ? Qt::MetaModifier : Qt::ControlModifier;
if (modifierFlags & NSNumericPadKeyMask)
qtMods |= Qt::KeypadModifier;
return qtMods;
@@ -1533,7 +1357,8 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
// ALT+E to be used as a shortcut with an English keyboard even though
// pressing ALT+E will give a dead key while doing normal text input.
if ([characters length] != 0 || [charactersIgnoringModifiers length] != 0) {
- if (((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0))
+ auto ctrlOrMetaModifier = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) ? Qt::ControlModifier : Qt::MetaModifier;
+ if (((modifiers & ctrlOrMetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0))
ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
else if ([characters length] != 0)
ch = QChar([characters characterAtIndex:0]);
@@ -1682,10 +1507,17 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
if ((delta & mac_mask) == 0u)
continue;
+ Qt::Key qtCode = modifier_key_symbols[i].qt_code;
+ if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
+ if (qtCode == Qt::Key_Meta)
+ qtCode = Qt::Key_Control;
+ else if (qtCode == Qt::Key_Control)
+ qtCode = Qt::Key_Meta;
+ }
QWindowSystemInterface::handleKeyEvent(m_platformWindow->window(),
timestamp,
(lastKnownModifiers & mac_mask) ? QEvent::KeyRelease : QEvent::KeyPress,
- modifier_key_symbols[i].qt_code,
+ qtCode,
qmodifiers ^ [QNSView convertKeyModifiers:mac_mask]);
}
}
@@ -1917,14 +1749,8 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
// The returned rect is always based on the internal cursor.
QRect mr = qApp->inputMethod()->cursorRectangle().toRect();
- QPoint mp = m_platformWindow->window()->mapToGlobal(mr.bottomLeft());
-
- NSRect rect;
- rect.origin.x = mp.x();
- rect.origin.y = qt_mac_flipYCoordinate(mp.y());
- rect.size.width = mr.width();
- rect.size.height = mr.height();
- return rect;
+ mr.moveBottomLeft(m_platformWindow->window()->mapToGlobal(mr.bottomLeft()));
+ return QCocoaScreen::mapToNative(mr);
}
- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
@@ -2129,7 +1955,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
if (nativeDrag->currentDrag()) {
// The drag was started from within the application
- response = QWindowSystemInterface::handleDrag(target, nativeDrag->platformDropData(), mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
+ response = QWindowSystemInterface::handleDrag(target, nativeDrag->dragMimeData(), mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
[self updateCursorFromDragResponse:response drag:nativeDrag];
} else {
QCocoaDropData mimeData([sender draggingPasteboard]);
@@ -2173,7 +1999,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
if (nativeDrag->currentDrag()) {
// The drag was started from within the application
- response = QWindowSystemInterface::handleDrop(target, nativeDrag->platformDropData(), mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
+ response = QWindowSystemInterface::handleDrop(target, nativeDrag->dragMimeData(), mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
} else {
QCocoaDropData mimeData([sender draggingPasteboard]);
response = QWindowSystemInterface::handleDrop(target, &mimeData, mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
@@ -2210,8 +2036,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
NSPoint windowPoint = [self.window convertRectFromScreen:NSMakeRect(screenPoint.x, screenPoint.y, 1, 1)].origin;
NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil]; // NSView/QWindow coordinates
QPoint qtWindowPoint(nsViewPoint.x, nsViewPoint.y);
-
- QPoint qtScreenPoint = QPoint(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y));
+ QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
QWindowSystemInterface::handleMouseEvent(target, mapWindowCoordinates(m_platformWindow->window(), target, qtWindowPoint), qtScreenPoint, m_buttons);
}
diff --git a/src/plugins/platforms/cocoa/qnswindow.h b/src/plugins/platforms/cocoa/qnswindow.h
new file mode 100644
index 0000000000..ea690b69e3
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnswindow.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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$
+**
+****************************************************************************/
+
+#ifndef QNSWINDOW_H
+#define QNSWINDOW_H
+
+#include <qglobal.h>
+#include <QPointer>
+#include "qt_mac_p.h"
+
+#include <AppKit/AppKit.h>
+
+QT_FORWARD_DECLARE_CLASS(QCocoaWindow)
+
+// @compatibility_alias doesn't work with categories or their methods
+#define FullScreenProperty QT_MANGLE_NAMESPACE(FullScreenProperty)
+#define qt_fullScreen QT_MANGLE_NAMESPACE(qt_fullScreen)
+
+@interface NSWindow (FullScreenProperty)
+@property(readonly) BOOL qt_fullScreen;
+@end
+
+// @compatibility_alias doesn't work with protocols
+#define QNSWindowProtocol QT_MANGLE_NAMESPACE(QNSWindowProtocol)
+
+@protocol QNSWindowProtocol
+@optional
+- (BOOL)canBecomeKeyWindow;
+- (void)sendEvent:(NSEvent*)theEvent;
+- (void)closeAndRelease;
+- (void)dealloc;
+- (BOOL)isOpaque;
+- (NSColor *)backgroundColor;
+@property (nonatomic, readonly) QCocoaWindow *platformWindow;
+@end
+
+typedef NSWindow<QNSWindowProtocol> QCocoaNSWindow;
+
+@interface QT_MANGLE_NAMESPACE(QNSWindow) : NSWindow<QNSWindowProtocol> @end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindow);
+
+@interface QT_MANGLE_NAMESPACE(QNSPanel) : NSPanel<QNSWindowProtocol> @end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSPanel);
+
+#endif // QNSWINDOW_H
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
new file mode 100644
index 0000000000..cb13b7d184
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -0,0 +1,331 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "qnswindow.h"
+#include "qnswindowdelegate.h"
+#include "qcocoawindow.h"
+#include "qcocoahelpers.h"
+#include "qcocoaeventdispatcher.h"
+
+#include <qpa/qwindowsysteminterface.h>
+#include <qoperatingsystemversion.h>
+
+Q_LOGGING_CATEGORY(lcCocoaEvents, "qt.qpa.cocoa.events");
+
+static bool isMouseEvent(NSEvent *ev)
+{
+ switch ([ev type]) {
+ case NSLeftMouseDown:
+ case NSLeftMouseUp:
+ case NSRightMouseDown:
+ case NSRightMouseUp:
+ case NSMouseMoved:
+ case NSLeftMouseDragged:
+ case NSRightMouseDragged:
+ return true;
+ default:
+ return false;
+ }
+}
+
+@implementation NSWindow (FullScreenProperty)
+
++ (void)load
+{
+ NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+ [center addObserverForName:NSWindowDidEnterFullScreenNotification object:nil queue:nil
+ usingBlock:^(NSNotification *notification) {
+ objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
+ [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_RETAIN);
+ }
+ ];
+ [center addObserverForName:NSWindowDidExitFullScreenNotification object:nil queue:nil
+ usingBlock:^(NSNotification *notification) {
+ objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
+ nil, OBJC_ASSOCIATION_RETAIN);
+ }
+ ];
+}
+
+- (BOOL)qt_fullScreen
+{
+ NSNumber *number = objc_getAssociatedObject(self, @selector(qt_fullScreen));
+ return [number boolValue];
+}
+@end
+
+#define super USE_qt_objcDynamicSuper_INSTEAD
+
+@implementation QNSWindow
+
++ (void)load
+{
+ const Class windowClass = [self class];
+ const Class panelClass = [QNSPanel class];
+
+ unsigned int protocolCount;
+ Protocol **protocols = class_copyProtocolList(windowClass, &protocolCount);
+ for (unsigned int i = 0; i < protocolCount; ++i) {
+ Protocol *protocol = protocols[i];
+
+ unsigned int methodDescriptionsCount;
+ objc_method_description *methods = protocol_copyMethodDescriptionList(
+ protocol, NO, YES, &methodDescriptionsCount);
+
+ for (unsigned int j = 0; j < methodDescriptionsCount; ++j) {
+ objc_method_description method = methods[j];
+ class_addMethod(panelClass, method.name,
+ class_getMethodImplementation(windowClass, method.name),
+ method.types);
+ }
+ free(methods);
+ }
+
+ free(protocols);
+}
+
+- (QCocoaWindow *)platformWindow
+{
+ return qnsview_cast(self.contentView).platformWindow;
+}
+
+- (NSString *)description
+{
+ NSMutableString *description = [NSMutableString stringWithString:qt_objcDynamicSuper()];
+
+#ifndef QT_NO_DEBUG_STREAM
+ QString contentViewDescription;
+ QDebug debug(&contentViewDescription);
+ debug.nospace() << "; contentView=" << qnsview_cast(self.contentView) << ">";
+
+ NSRange lastCharacter = [description rangeOfComposedCharacterSequenceAtIndex:description.length - 1];
+ [description replaceCharactersInRange:lastCharacter withString:contentViewDescription.toNSString()];
+#endif
+
+ return description;
+}
+
+- (BOOL)canBecomeKeyWindow
+{
+ QCocoaWindow *pw = self.platformWindow;
+ if (!pw)
+ return NO;
+
+ if (pw->shouldRefuseKeyWindowAndFirstResponder())
+ return NO;
+
+ if ([self isKindOfClass:[QNSPanel class]]) {
+ // Only tool or dialog windows should become key:
+ Qt::WindowType type = pw->window()->type();
+ if (type == Qt::Tool || type == Qt::Dialog)
+ return YES;
+
+ return NO;
+ } else {
+ // The default implementation returns NO for title-bar less windows,
+ // override and return yes here to make sure popup windows such as
+ // the combobox popup can become the key window.
+ return YES;
+ }
+}
+
+- (BOOL)canBecomeMainWindow
+{
+ BOOL canBecomeMain = YES; // By default, windows can become the main window
+
+ // Windows with a transient parent (such as combobox popup windows)
+ // cannot become the main window:
+ QCocoaWindow *pw = self.platformWindow;
+ if (!pw || pw->window()->transientParent())
+ canBecomeMain = NO;
+
+ return canBecomeMain;
+}
+
+- (BOOL)isOpaque
+{
+ return self.platformWindow ?
+ self.platformWindow->isOpaque() : qt_objcDynamicSuper();
+}
+
+/*!
+ Borderless windows need a transparent background
+
+ Technically windows with NSTexturedBackgroundWindowMask (such
+ as windows with unified toolbars) need to draw the textured
+ background of the NSWindow, and can't have a transparent
+ background, but as NSBorderlessWindowMask is 0, you can't
+ have a window with NSTexturedBackgroundWindowMask that is
+ also borderless.
+*/
+- (NSColor *)backgroundColor
+{
+ return self.styleMask == NSBorderlessWindowMask
+ ? [NSColor clearColor] : qt_objcDynamicSuper();
+}
+
+- (void)sendEvent:(NSEvent*)theEvent
+{
+ qCDebug(lcCocoaEvents) << "Sending" << theEvent << "to" << self;
+
+ // We might get events for a NSWindow after the corresponding platform
+ // window has been deleted, as the NSWindow can outlive the QCocoaWindow
+ // e.g. if being retained by other parts of AppKit, or in an auto-release
+ // pool. We guard against this in QNSView as well, as not all callbacks
+ // come via events, but if they do there's no point in propagating them.
+ if (!self.platformWindow)
+ return;
+
+ // Prevent deallocation of this NSWindow during event delivery, as we
+ // have logic further below that depends on the window being alive.
+ [[self retain] autorelease];
+
+ const char *eventType = object_getClassName(theEvent);
+ if (QWindowSystemInterface::handleNativeEvent(self.platformWindow->window(),
+ QByteArray::fromRawData(eventType, qstrlen(eventType)), theEvent, nullptr)) {
+ return;
+ }
+
+ qt_objcDynamicSuper(theEvent);
+
+ if (!self.platformWindow)
+ return; // Platform window went away while processing event
+
+ QCocoaWindow *pw = self.platformWindow;
+ if (pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) {
+ NSPoint loc = [theEvent locationInWindow];
+ NSRect windowFrame = [self convertRectFromScreen:self.frame];
+ NSRect contentFrame = self.contentView.frame;
+ if (NSMouseInRect(loc, windowFrame, NO) && !NSMouseInRect(loc, contentFrame, NO))
+ [qnsview_cast(pw->view()) handleFrameStrutMouseEvent:theEvent];
+ }
+}
+
+- (void)closeAndRelease
+{
+ qCDebug(lcQpaCocoaWindow) << "closeAndRelease" << self;
+
+ [self.delegate release];
+ self.delegate = nil;
+
+ [self close];
+ [self release];
+}
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wobjc-missing-super-calls"
+- (void)dealloc
+{
+ qCDebug(lcQpaCocoaWindow) << "dealloc" << self;
+ qt_objcDynamicSuper();
+}
+#pragma clang diagnostic pop
+
++ (void)applicationActivationChanged:(NSNotification*)notification
+{
+ const id sender = self;
+ NSEnumerator<NSWindow*> *windowEnumerator = nullptr;
+ NSApplication *application = [NSApplication sharedApplication];
+
+#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12)
+ if (__builtin_available(macOS 10.12, *)) {
+ // Unfortunately there's no NSWindowListOrderedBackToFront,
+ // so we have to manually reverse the order using an array.
+ NSMutableArray *windows = [[[NSMutableArray alloc] init] autorelease];
+ [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
+ usingBlock:^(NSWindow *window, BOOL *) {
+ // For some reason AppKit will give us nil-windows, skip those
+ if (!window)
+ return;
+
+ [(NSMutableArray*)windows addObject:window];
+ }
+ ];
+
+ windowEnumerator = windows.reverseObjectEnumerator;
+ } else
+#endif
+ {
+ // No way to get ordered list of windows, so fall back to unordered,
+ // list, which typically corresponds to window creation order.
+ windowEnumerator = application.windows.objectEnumerator;
+ }
+
+ for (NSWindow *window in windowEnumerator) {
+ // We're meddling with normal and floating windows, so leave others alone
+ if (!(window.level == NSNormalWindowLevel || window.level == NSFloatingWindowLevel))
+ continue;
+
+ // Windows that hide automatically will keep their NSFloatingWindowLevel,
+ // and hence be on top of the window stack. We don't want to affect these
+ // windows, as otherwise we might end up with key windows being ordered
+ // behind these auto-hidden windows when activating the application by
+ // clicking on a new tool window.
+ if (window.hidesOnDeactivate)
+ continue;
+
+ if ([window conformsToProtocol:@protocol(QNSWindowProtocol)]) {
+ QCocoaWindow *cocoaWindow = static_cast<QCocoaNSWindow *>(window).platformWindow;
+ window.level = notification.name == NSApplicationWillResignActiveNotification ?
+ NSNormalWindowLevel : cocoaWindow->windowLevel(cocoaWindow->window()->flags());
+ }
+
+ // The documentation says that "when a window enters a new level, it’s ordered
+ // in front of all its peers in that level", but that doesn't seem to be the
+ // case in practice. To keep the order correct after meddling with the window
+ // levels, we explicitly order each window to the front. Since we are iterating
+ // the windows in back-to-front order, this is okey. The call also triggers AppKit
+ // to re-evaluate the level in relation to windows from other applications,
+ // working around an issue where our tool windows would stay on top of other
+ // application windows if activation was transferred to another application by
+ // clicking on it instead of via the application switcher or Dock. Finally, we
+ // do this re-ordering for all windows (except auto-hiding ones), otherwise we would
+ // end up triggering a bug in AppKit where the tool windows would disappear behind
+ // the application window.
+ [window orderFront:sender];
+ }
+}
+
+@end
+
+@implementation QNSPanel
+// Implementation shared with QNSWindow, see +[QNSWindow load] above
+@end
+
+#undef super
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
index 1224d138d9..6e5623d679 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
@@ -44,6 +44,8 @@
#include <qpa/qplatformscreen.h>
#include <qpa/qwindowsysteminterface.h>
+static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*"));
+
@implementation QNSWindowDelegate
- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow
@@ -78,27 +80,14 @@
return NSRectFromCGRect(m_cocoaWindow->screen()->availableGeometry().toCGRect());
}
-#if QT_MACOS_DEPLOYMENT_TARGET_BELOW(__MAC_10_11)
-/*
- AppKit on OS X 10.10 wrongly calls windowWillUseStandardFrame:defaultFrame
- from -[NSWindow _frameForFullScreenMode] when going into fullscreen, resulting
- in black bars on top and bottom of the window. By implementing the following
- method, AppKit will choose that instead, and resolve the right fullscreen
- geometry.
-*/
-- (NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize
-{
- Q_UNUSED(proposedSize);
- Q_ASSERT(window == m_cocoaWindow->nativeWindow());
- return NSSizeFromCGSize(m_cocoaWindow->screen()->geometry().size().toCGSize());
-}
-#endif
-
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu
{
Q_UNUSED(window);
Q_UNUSED(menu);
- return m_cocoaWindow && m_cocoaWindow->m_hasWindowFilePath;
+
+ // Only pop up document path if the filename is non-empty. We allow whitespace, to
+ // allow faking a window icon by setting the file path to a single space character.
+ return !whitespaceRegex.exactMatch(m_cocoaWindow->window()->filePath());
}
- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard
@@ -107,6 +96,9 @@
Q_UNUSED(event);
Q_UNUSED(dragImageLocation);
Q_UNUSED(pasteboard);
- return m_cocoaWindow && m_cocoaWindow->m_hasWindowFilePath;
+
+ // Only allow drag if the filename is non-empty. We allow whitespace, to
+ // allow faking a window icon by setting the file path to a single space.
+ return !whitespaceRegex.exactMatch(m_cocoaWindow->window()->filePath());
}
@end
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
index 7e241e3ae6..3f363b62d5 100644
--- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
@@ -108,7 +108,7 @@ CGAffineTransform qt_mac_convert_transform_to_cg(const QTransform &t) {
return CGAffineTransformMake(t.m11(), t.m12(), t.m21(), t.m22(), t.dx(), t.dy());
}
-inline static QCFType<CGColorRef> cgColorForQColor(const QColor &col, QPaintDevice *pdev)
+inline static QCFType<CGColorRef> cgColorForQColor(const QColor &col)
{
CGFloat components[] = {
qt_mac_convert_color_to_cg(col.red()),
@@ -116,7 +116,8 @@ inline static QCFType<CGColorRef> cgColorForQColor(const QColor &col, QPaintDevi
qt_mac_convert_color_to_cg(col.blue()),
qt_mac_convert_color_to_cg(col.alpha())
};
- return CGColorCreate(qt_mac_colorSpaceForDeviceType(pdev), components);
+ QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
+ return CGColorCreate(colorSpace, components);
}
// There's architectural problems with using native gradients
@@ -239,81 +240,6 @@ static CGMutablePathRef qt_mac_compose_path(const QPainterPath &p, float off=0)
return ret;
}
-CGColorSpaceRef QCoreGraphicsPaintEngine::m_genericColorSpace = 0;
-QHash<CGDirectDisplayID, CGColorSpaceRef> QCoreGraphicsPaintEngine::m_displayColorSpaceHash;
-bool QCoreGraphicsPaintEngine::m_postRoutineRegistered = false;
-
-CGColorSpaceRef QCoreGraphicsPaintEngine::macGenericColorSpace()
-{
-#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 macDisplayColorSpace();
-#endif
-}
-
-/*
- Ideally, we should pass the widget in here, and use CGGetDisplaysWithRect() etc.
- to support multiple displays correctly.
-*/
-CGColorSpaceRef QCoreGraphicsPaintEngine::macDisplayColorSpace(const QWidget *widget)
-{
- CGColorSpaceRef colorSpace;
-
- CGDirectDisplayID displayID;
- if (widget == 0) {
- displayID = CGMainDisplayID();
- } else {
- 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;
- qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces);
- }
- return colorSpace;
-}
-
-void QCoreGraphicsPaintEngine::cleanUpMacColorSpaces()
-{
- if (m_genericColorSpace) {
- CFRelease(m_genericColorSpace);
- m_genericColorSpace = 0;
- }
- QHash<CGDirectDisplayID, CGColorSpaceRef>::const_iterator it = m_displayColorSpaceHash.constBegin();
- while (it != m_displayColorSpaceHash.constEnd()) {
- if (it.value())
- CFRelease(it.value());
- ++it;
- }
- m_displayColorSpaceHash.clear();
-}
-
//pattern handling (tiling)
#if 1
# define QMACPATTERN_MASK_MULTIPLIER 32
@@ -377,7 +303,7 @@ static void qt_mac_draw_pattern(void *info, CGContextRef c)
QPixmap pm(w*QMACPATTERN_MASK_MULTIPLIER, h*QMACPATTERN_MASK_MULTIPLIER);
pm.fill(c0);
QMacCGContext pm_ctx(&pm);
- CGContextSetFillColorWithColor(c, cgColorForQColor(c1, pat->pdev));
+ CGContextSetFillColorWithColor(c, cgColorForQColor(c1));
CGRect rect = CGRectMake(0, 0, w, h);
for (int x = 0; x < QMACPATTERN_MASK_MULTIPLIER; ++x) {
rect.origin.x = x * w;
@@ -409,7 +335,7 @@ static void qt_mac_draw_pattern(void *info, CGContextRef c)
bool needRestore = false;
if (CGImageIsMask(pat->image)) {
CGContextSaveGState(c);
- CGContextSetFillColorWithColor(c, cgColorForQColor(pat->foreground, pat->pdev));
+ CGContextSetFillColorWithColor(c, cgColorForQColor(pat->foreground));
}
CGRect rect = CGRectMake(0, 0, w, h);
qt_mac_drawCGImage(c, &rect, pat->image);
@@ -871,7 +797,7 @@ void QCoreGraphicsPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, co
d->saveGraphicsState();
const QColor &col = d->current.pen.color();
- CGContextSetFillColorWithColor(d->hd, cgColorForQColor(col, d->pdev));
+ CGContextSetFillColorWithColor(d->hd, cgColorForQColor(col));
image = qt_mac_create_imagemask(pm, sr);
} else if (differentSize) {
QCFType<CGImageRef> img = qt_mac_toCGImage(pm.toImage());
@@ -1233,7 +1159,7 @@ QCoreGraphicsPaintEnginePrivate::setStrokePen(const QPen &pen)
CGContextSetLineDash(hd, pen.dashOffset() * cglinewidth, linedashes.data(), linedashes.size());
// color
- CGContextSetStrokeColorWithColor(hd, cgColorForQColor(pen.color(), pdev));
+ CGContextSetStrokeColorWithColor(hd, cgColorForQColor(pen.color()));
}
// Add our own patterns here to deal with the fact that the coordinate system
@@ -1276,7 +1202,7 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
CGFunctionRef fill_func = CGFunctionCreate(reinterpret_cast<void *>(&current.brush),
1, domain, 4, 0, &callbacks);
- CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pdev);
+ CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB)
if (bs == Qt::LinearGradientPattern) {
const QLinearGradient *linearGrad = static_cast<const QLinearGradient *>(grad);
const QPointF start(linearGrad->start());
@@ -1315,7 +1241,7 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
components[0] = qt_mac_convert_color_to_cg(col.red());
components[1] = qt_mac_convert_color_to_cg(col.green());
components[2] = qt_mac_convert_color_to_cg(col.blue());
- base_colorspace = QCoreGraphicsPaintEngine::macGenericColorSpace();
+ base_colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
}
} else {
qpattern->as_mask = true;
@@ -1325,7 +1251,7 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
components[0] = qt_mac_convert_color_to_cg(col.red());
components[1] = qt_mac_convert_color_to_cg(col.green());
components[2] = qt_mac_convert_color_to_cg(col.blue());
- base_colorspace = QCoreGraphicsPaintEngine::macGenericColorSpace();
+ base_colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
}
int width = qpattern->width(), height = qpattern->height();
qpattern->foreground = current.brush.color();
@@ -1346,10 +1272,12 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
!base_colorspace, &callbks);
CGContextSetFillPattern(hd, fill_pattern, components);
+
CGPatternRelease(fill_pattern);
+ CGColorSpaceRelease(base_colorspace);
CGColorSpaceRelease(fill_colorspace);
} else if (bs != Qt::NoBrush) {
- CGContextSetFillColorWithColor(hd, cgColorForQColor(current.brush.color(), pdev));
+ CGContextSetFillColorWithColor(hd, cgColorForQColor(current.brush.color()));
}
}
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h b/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
index 57d985c399..c9519ac827 100644
--- a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
+++ b/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
@@ -73,8 +73,6 @@ public:
bool begin(QPaintDevice *pdev);
bool end();
- static CGColorSpaceRef macGenericColorSpace();
- static CGColorSpaceRef macDisplayColorSpace(const QWidget *widget = 0);
void updateState(const QPaintEngineState &state);
@@ -126,10 +124,6 @@ protected:
QCoreGraphicsPaintEngine(QPaintEnginePrivate &dptr);
private:
- static bool m_postRoutineRegistered;
- static CGColorSpaceRef m_genericColorSpace;
- static QHash<CGDirectDisplayID, CGColorSpaceRef> m_displayColorSpaceHash;
- static void cleanUpMacColorSpaces();
Q_DISABLE_COPY(QCoreGraphicsPaintEngine)
};
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm
index c39af870d4..b3d48c1ec3 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm
@@ -247,7 +247,7 @@ void QMacPrintEnginePrivate::initialize()
QList<int> resolutions = m_printDevice->supportedResolutions();
if (!resolutions.isEmpty() && mode != QPrinter::ScreenResolution) {
- qSort(resolutions);
+ std::sort(resolutions.begin(), resolutions.end());
if (resolutions.count() > 1 && mode == QPrinter::HighResolution)
resolution.hRes = resolution.vRes = resolutions.last();
else
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
index 2d46a250d5..9514f3e691 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h
+++ b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
@@ -150,8 +150,8 @@ public:
PMPrintSession session() const { return static_cast<PMPrintSession>([printInfo PMPrintSession]); }
PMPrintSettings settings() const { return static_cast<PMPrintSettings>([printInfo PMPrintSettings]); }
- QPaintEngine *aggregateEngine() Q_DECL_OVERRIDE { return paintEngine; }
- Qt::HANDLE nativeHandle() Q_DECL_OVERRIDE { return q_func()->handle(); }
+ QPaintEngine *aggregateEngine() override { return paintEngine; }
+ Qt::HANDLE nativeHandle() override { return q_func()->handle(); }
};
QT_END_NAMESPACE