Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qcocoaapplication.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (c) 2007-2008, Apple, Inc.
3// SPDX-License-Identifier: BSD-3-Clause
4// Qt-Security score:significant reason:default
5
6#include <AppKit/AppKit.h>
7
9
12#include "qcocoahelpers.h"
13#include "qcocoawindow.h"
14#include <qguiapplication.h>
15#include <qdebug.h>
16
17QT_USE_NAMESPACE
18
19static void qt_sendPostedMessage(NSEvent *event)
20{
21 // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5!
22 // That is why we need to split the address in two parts:
23 quint64 lower = [event data1];
24 quint64 upper = [event data2];
25 QCocoaPostMessageArgs *args = reinterpret_cast<QCocoaPostMessageArgs *>(lower | (upper << 32));
26 // Special case for convenience: if the argument is an NSNumber, we unbox it directly.
27 // Use NSValue instead if this behaviour is unwanted.
28 id a1 = ([args->arg1 isKindOfClass:[NSNumber class]]) ? (id)[args->arg1 longValue] : args->arg1;
29 id a2 = ([args->arg2 isKindOfClass:[NSNumber class]]) ? (id)[args->arg2 longValue] : args->arg2;
30 switch (args->argCount) {
31 case 0:
32 [args->target performSelector:args->selector];
33 break;
34 case 1:
35 [args->target performSelector:args->selector withObject:a1];
36 break;
37 case 3:
38 [args->target performSelector:args->selector withObject:a1 withObject:a2];
39 break;
40 }
41
42 delete args;
43}
44
45static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSEvent");
46
47static bool qt_filterEvent(NSEvent *event)
48{
49 if (qApp && qApp->eventDispatcher()->
50 filterNativeEvent(q_macLocalEventType, static_cast<void*>(event), nullptr))
51 return true;
52
53 if (event.type == NSEventTypeApplicationDefined) {
54 switch (static_cast<short>(event.subtype)) {
55 case QtCocoaEventSubTypePostMessage:
56 qt_sendPostedMessage(event);
57 return true;
58 default:
59 break;
60 }
61 }
62
63 return false;
64}
65
66static void qt_maybeSendKeyEquivalentUpEvent(NSEvent *event)
67{
68 // Cocoa is known for not sending key up events for key
69 // equivalents, regardless of whether it's an actual
70 // recognized key equivalent. We decide to force fate
71 // and forward the key event to the key (focus) window.
72 // However, non-Qt windows will not (and should not) get
73 // any special treatment, only QWindow-owned NSWindows.
74 if (event.type == NSEventTypeKeyUp && (event.modifierFlags & NSEventModifierFlagCommand)) {
75 NSWindow *targetWindow = event.window;
76 if ([targetWindow.class conformsToProtocol:@protocol(QNSWindowProtocol)])
77 [targetWindow sendEvent:event];
78 }
79}
80
81@implementation QNSApplication
82
83- (void)QT_MANGLE_NAMESPACE(qt_sendEvent_original):(NSEvent *)event
84{
85 Q_UNUSED(event);
86 // This method will only be used as a signature
87 // template for the method we add into NSApplication
88 // containing the original [NSApplication sendEvent:] implementation
89}
90
91- (void)QT_MANGLE_NAMESPACE(qt_sendEvent_replacement):(NSEvent *)event
92{
93 // This method (or its implementation to be precise) will
94 // be called instead of sendEvent if redirection occurs.
95 // 'self' will then be an instance of NSApplication
96 // (and not QNSApplication)
97 if (!qt_filterEvent(event)) {
98 [self QT_MANGLE_NAMESPACE(qt_sendEvent_original):event];
99 qt_maybeSendKeyEquivalentUpEvent(event);
100 }
101}
102
103- (void)sendEvent:(NSEvent *)event
104{
105 // This method will be called if
106 // no redirection occurs
107 if (!qt_filterEvent(event)) {
108 [super sendEvent:event];
109 qt_maybeSendKeyEquivalentUpEvent(event);
110 }
111}
112
113@end
114
115QT_BEGIN_NAMESPACE
116
117void qt_redirectNSApplicationSendEvent()
118{
119 if (QCoreApplication::testAttribute(Qt::AA_PluginApplication))
120 // In a plugin we cannot chain sendEvent hooks: a second plugin could
121 // store the implementation of the first, which during the program flow
122 // can be unloaded.
123 return;
124
125 if ([NSApp isMemberOfClass:[QNSApplication class]]) {
126 // No need to change implementation since Qt
127 // already controls a subclass of NSApplication
128 return;
129 }
130
131 // Change the implementation of [NSApplication sendEvent] to the
132 // implementation of qt_sendEvent_replacement found in QNSApplication.
133 // And keep the old implementation that gets overwritten inside a new
134 // method 'qt_sendEvent_original' that we add to NSApplication
135 qt_cocoa_change_implementation(
136 [NSApplication class],
137 @selector(sendEvent:),
138 [QNSApplication class],
139 @selector(QT_MANGLE_NAMESPACE(qt_sendEvent_replacement):),
140 @selector(QT_MANGLE_NAMESPACE(qt_sendEvent_original):));
141 }
142
144{
145 if (QCoreApplication::testAttribute(Qt::AA_PluginApplication))
146 return;
147
148
149 qt_cocoa_change_back_implementation([NSApplication class],
150 @selector(sendEvent:),
151 @selector(QT_MANGLE_NAMESPACE(qt_sendEvent_original):));
152}
153
154QT_END_NAMESPACE
static bool qt_filterEvent(NSEvent *event)
static QT_USE_NAMESPACE void qt_sendPostedMessage(NSEvent *event)
static const QByteArray q_macLocalEventType
static void qt_maybeSendKeyEquivalentUpEvent(NSEvent *event)
void qt_resetNSApplicationSendEvent()
#define qApp