summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa/qnswindow.mm
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2019-02-13 12:52:33 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2019-02-18 22:57:53 +0000
commit7319c342c34f6bcc8f0322e9613c6296331f1487 (patch)
treeb3d8813db68bf127bc05727ef362592731272ee1 /src/plugins/platforms/cocoa/qnswindow.mm
parent6273b484b35479eb5788425c8d90acacdf239623 (diff)
macOS: Implement QNSWindow/QNSPanel mixin using preprocessor includes
We want to share the implementation between the two classes, but Objective-C doesn't natively have a mixin-feature. Instead of using dynamic super-calls at runtime (which worked fine, but added complexity), we now do the mixin at compile time using the preprocessor. The dynamic-super feature is left in, in case we need it in other areas in the future. Change-Id: I95dfa7f18cba86cc518e963dd018944ef113ac06 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'src/plugins/platforms/cocoa/qnswindow.mm')
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm170
1 files changed, 75 insertions, 95 deletions
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index 28a9fa8607..3a1a04f887 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -37,6 +37,8 @@
**
****************************************************************************/
+#if !defined(QNSWINDOW_PROTOCOL_IMPLMENTATION)
+
#include "qnswindow.h"
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
@@ -89,36 +91,79 @@ static bool isMouseEvent(NSEvent *ev)
}
@end
-#define super USE_qt_objcDynamicSuper_INSTEAD
-
@implementation QNSWindow
+#define QNSWINDOW_PROTOCOL_IMPLMENTATION 1
+#include "qnswindow.mm"
+#undef QNSWINDOW_PROTOCOL_IMPLMENTATION
-+ (void)load
++ (void)applicationActivationChanged:(NSNotification*)notification
{
- 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);
+ const id sender = self;
+ NSEnumerator<NSWindow*> *windowEnumerator = nullptr;
+ NSApplication *application = [NSApplication sharedApplication];
+
+ // Unfortunately there's no NSWindowListOrderedBackToFront,
+ // so we have to manually reverse the order using an array.
+ NSMutableArray<NSWindow *> *windows = [NSMutableArray<NSWindow *> new];
+ [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
+ usingBlock:^(NSWindow *window, BOOL *) {
+ // For some reason AppKit will give us nil-windows, skip those
+ if (!window)
+ return;
+
+ [windows addObject:window];
+ }
+ ];
+
+ windowEnumerator = windows.reverseObjectEnumerator;
+
+ 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());
}
- free(methods);
- }
- free(protocols);
+ // 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
+#define QNSWINDOW_PROTOCOL_IMPLMENTATION 1
+#include "qnswindow.mm"
+#undef QNSWINDOW_PROTOCOL_IMPLMENTATION
+@end
+
+#else // QNSWINDOW_PROTOCOL_IMPLMENTATION
+
+// The following methods are mixed in to the QNSWindow and QNSPanel classes via includes
+
- (QCocoaWindow *)platformWindow
{
return qnsview_cast(self.contentView).platformWindow;
@@ -126,7 +171,7 @@ static bool isMouseEvent(NSEvent *ev)
- (NSString *)description
{
- NSMutableString *description = [NSMutableString stringWithString:qt_objcDynamicSuper()];
+ NSMutableString *description = [NSMutableString stringWithString:[super description]];
#ifndef QT_NO_DEBUG_STREAM
QString contentViewDescription;
@@ -187,13 +232,13 @@ static bool isMouseEvent(NSEvent *ev)
}
}
- return qt_objcDynamicSuper();
+ return [super worksWhenModal];
}
- (BOOL)isOpaque
{
return self.platformWindow ?
- self.platformWindow->isOpaque() : qt_objcDynamicSuper();
+ self.platformWindow->isOpaque() : [super isOpaque];
}
/*!
@@ -209,7 +254,7 @@ static bool isMouseEvent(NSEvent *ev)
- (NSColor *)backgroundColor
{
return self.styleMask == NSWindowStyleMaskBorderless
- ? [NSColor clearColor] : qt_objcDynamicSuper();
+ ? [NSColor clearColor] : [super backgroundColor];
}
- (void)sendEvent:(NSEvent*)theEvent
@@ -234,7 +279,7 @@ static bool isMouseEvent(NSEvent *ev)
return;
}
- qt_objcDynamicSuper(theEvent);
+ [super sendEvent:theEvent];
if (!self.platformWindow)
return; // Platform window went away while processing event
@@ -256,77 +301,12 @@ static bool isMouseEvent(NSEvent *ev)
[self release];
}
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wobjc-missing-super-calls"
- (void)dealloc
{
qCDebug(lcQpaWindow) << "Deallocating" << self;
self.delegate = nil;
- qt_objcDynamicSuper();
+ [super dealloc];
}
-#pragma clang diagnostic pop
-+ (void)applicationActivationChanged:(NSNotification*)notification
-{
- const id sender = self;
- NSEnumerator<NSWindow*> *windowEnumerator = nullptr;
- NSApplication *application = [NSApplication sharedApplication];
-
- // Unfortunately there's no NSWindowListOrderedBackToFront,
- // so we have to manually reverse the order using an array.
- NSMutableArray<NSWindow *> *windows = [NSMutableArray<NSWindow *> new];
- [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
- usingBlock:^(NSWindow *window, BOOL *) {
- // For some reason AppKit will give us nil-windows, skip those
- if (!window)
- return;
-
- [windows addObject:window];
- }
- ];
-
- windowEnumerator = windows.reverseObjectEnumerator;
-
- 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
+#endif