summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/dialogs/qnspanelproxy_mac.mm87
-rw-r--r--src/gui/kernel/kernel.pri6
-rw-r--r--src/gui/kernel/qapplication.h1
-rw-r--r--src/gui/kernel/qapplication_mac.mm42
-rw-r--r--src/gui/kernel/qcocoaapplication_mac.mm72
-rw-r--r--src/gui/kernel/qcocoaapplication_mac_p.h8
-rw-r--r--src/gui/kernel/qcocoasharedwindowmethods_mac_p.h11
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac.mm30
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac_p.h12
-rw-r--r--src/gui/widgets/qmenu_mac.mm3
10 files changed, 147 insertions, 125 deletions
diff --git a/src/gui/dialogs/qnspanelproxy_mac.mm b/src/gui/dialogs/qnspanelproxy_mac.mm
index 3229a4d..f01c035 100644
--- a/src/gui/dialogs/qnspanelproxy_mac.mm
+++ b/src/gui/dialogs/qnspanelproxy_mac.mm
@@ -42,6 +42,7 @@
#include <qdialogbuttonbox.h>
#if defined(Q_WS_MAC)
#include <private/qt_mac_p.h>
+#include <private/qcocoaintrospection_p.h>
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#import <objc/objc-class.h>
@@ -137,46 +138,6 @@ QT_USE_NAMESPACE
QT_BEGIN_NAMESPACE
-void macStartIntercept(SEL originalSel, SEL fakeSel, Class baseClass, Class proxyClass)
-{
-#ifndef QT_MAC_USE_COCOA
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
-#endif
- {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
- // The following code replaces the _implementation_ for the selector we want to hack
- // (originalSel) with the implementation found in proxyClass. Then it creates
- // a new 'backup' method inside baseClass containing the old, original,
- // implementation (fakeSel). You can let the proxy implementation of originalSel
- // call fakeSel if needed (similar approach to calling a super class implementation).
- // fakeSel must also be implemented in proxyClass, as the signature is used
- // as template for the method one we add into baseClass.
- // NB: You will typically never create any instances of proxyClass; we use it
- // only for stealing its contents and put it into baseClass.
- Method originalMethod = class_getInstanceMethod(baseClass, originalSel);
- Method newMethod = class_getInstanceMethod(proxyClass, originalSel);
- Method fakeMethod = class_getInstanceMethod(proxyClass, fakeSel);
-
- IMP originalImp = method_setImplementation(originalMethod, method_getImplementation(newMethod));
- class_addMethod(baseClass, fakeSel, originalImp, method_getTypeEncoding(fakeMethod));
-#endif
- }
-}
-
-void macStopIntercept(SEL originalSel, SEL fakeSel, Class baseClass, Class /* proxyClass */)
-{
-#ifndef QT_MAC_USE_COCOA
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
-#endif
- {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
- Method originalMethod = class_getInstanceMethod(baseClass, originalSel);
- Method fakeMethodInBaseClass = class_getInstanceMethod(baseClass, fakeSel);
- method_setImplementation(originalMethod, method_getImplementation(fakeMethodInBaseClass));
-#endif
- }
-}
-
/*
Intercept the NSColorPanel constructor if the shared
color panel doesn't exist yet. What's going on here is
@@ -188,12 +149,18 @@ void macStopIntercept(SEL originalSel, SEL fakeSel, Class baseClass, Class /* pr
*/
void macStartInterceptNSPanelCtor()
{
- macStartIntercept(@selector(initWithContentRect:styleMask:backing:defer:),
- @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:),
- [NSPanel class], [QNSPanelProxy class]);
- macStartIntercept(@selector(initWithContentRect:styleMask:backing:defer:screen:),
- @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:screen:),
- [NSPanel class], [QNSPanelProxy class]);
+ qt_cocoa_change_implementation(
+ [NSPanel class],
+ @selector(initWithContentRect:styleMask:backing:defer:),
+ [QNSPanelProxy class],
+ @selector(initWithContentRect:styleMask:backing:defer:),
+ @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:));
+ qt_cocoa_change_implementation(
+ [NSPanel class],
+ @selector(initWithContentRect:styleMask:backing:defer:screen:),
+ [QNSPanelProxy class],
+ @selector(initWithContentRect:styleMask:backing:defer:screen:),
+ @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:screen:));
}
/*
@@ -201,12 +168,14 @@ void macStartInterceptNSPanelCtor()
*/
void macStopInterceptNSPanelCtor()
{
- macStopIntercept(@selector(initWithContentRect:styleMask:backing:defer:screen:),
- @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:screen:),
- [NSPanel class], [QNSPanelProxy class]);
- macStopIntercept(@selector(initWithContentRect:styleMask:backing:defer:),
- @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:),
- [NSPanel class], [QNSPanelProxy class]);
+ qt_cocoa_change_back_implementation(
+ [NSPanel class],
+ @selector(initWithContentRect:styleMask:backing:defer:screen:),
+ @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:screen:));
+ qt_cocoa_change_back_implementation(
+ [NSPanel class],
+ @selector(initWithContentRect:styleMask:backing:defer:),
+ @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:));
}
/*
@@ -216,8 +185,12 @@ void macStopInterceptNSPanelCtor()
void macStartInterceptWindowTitle(QWidget *window)
{
currentWindow = window;
- macStartIntercept(@selector(setTitle:), @selector(qt_fakeSetTitle:),
- [NSWindow class], [QNSWindowProxy class]);
+ qt_cocoa_change_implementation(
+ [NSWindow class],
+ @selector(setTitle:),
+ [QNSWindowProxy class],
+ @selector(setTitle:),
+ @selector(qt_fakeSetTitle:));
}
/*
@@ -226,8 +199,10 @@ void macStartInterceptWindowTitle(QWidget *window)
void macStopInterceptWindowTitle()
{
currentWindow = 0;
- macStopIntercept(@selector(setTitle:), @selector(qt_fakeSetTitle:),
- [NSWindow class], [QNSWindowProxy class]);
+ qt_cocoa_change_back_implementation(
+ [NSWindow class],
+ @selector(setTitle:),
+ @selector(qt_fakeSetTitle:));
}
/*
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 6fd45ad..b6cc2ac 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -213,7 +213,8 @@ embedded {
qcocoaapplicationdelegate_mac_p.h \
qmacgesturerecognizer_mac_p.h \
qmultitouch_mac_p.h \
- qcocoasharedwindowmethods_mac_p.h
+ qcocoasharedwindowmethods_mac_p.h \
+ qcocoaintrospection_p.h
OBJECTIVE_SOURCES += \
kernel/qcursor_mac.mm \
@@ -233,7 +234,8 @@ embedded {
kernel/qeventdispatcher_mac.mm \
kernel/qcocoawindowcustomthemeframe_mac.mm \
kernel/qmacgesturerecognizer_mac.mm \
- kernel/qmultitouch_mac.mm
+ kernel/qmultitouch_mac.mm \
+ kernel/qcocoaintrospection_mac.mm
HEADERS += \
kernel/qt_cocoa_helpers_mac_p.h \
diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h
index c21b982..ebb329b 100644
--- a/src/gui/kernel/qapplication.h
+++ b/src/gui/kernel/qapplication.h
@@ -233,6 +233,7 @@ public:
#if defined(Q_WS_MAC)
virtual bool macEventFilter(EventHandlerCallRef, EventRef);
+ virtual bool macEventFilter(void *);
#endif
#if defined(Q_WS_X11)
virtual bool x11EventFilter(XEvent *);
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index 321492d..4cd14df 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -1246,6 +1246,8 @@ void qt_init(QApplicationPrivate *priv, int)
// Cocoa application delegate
#ifdef QT_MAC_USE_COCOA
NSApplication *cocoaApp = [QNSApplication sharedApplication];
+ qt_redirectNSApplicationSendEvent();
+
QMacCocoaAutoReleasePool pool;
NSObject *oldDelegate = [cocoaApp delegate];
QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate];
@@ -2611,7 +2613,7 @@ OSStatus QApplicationPrivate::globalAppleEventProcessor(const AppleEvent *ae, Ap
/*!
\fn bool QApplication::macEventFilter(EventHandlerCallRef caller, EventRef event)
- \warning This virtual function is only implemented under Mac OS X when against Carbon.
+ \warning This virtual function is only used under Mac OS X when Qt is based on Carbon.
If you create an application that inherits QApplication and reimplement
this function, you get direct access to all Carbon Events that Qt registers
@@ -2622,14 +2624,7 @@ OSStatus QApplicationPrivate::globalAppleEventProcessor(const AppleEvent *ae, Ap
Return false for normal event dispatching. The default
implementation returns false.
- Cocoa uses a different event system which means this function is NOT CALLED
- when building Qt against Cocoa. If you want similar functionality subclass
- NSApplication and reimplement the sendEvent: message to handle all the
- NSEvents. You also will need to to instantiate your custom NSApplication
- before creating a QApplication. See \l
- {http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/Reference/Reference.html}{Apple's
- NSApplication Reference} for more information.
-
+ \sa macEventFilter(void *nsevent)
*/
bool QApplication::macEventFilter(EventHandlerCallRef, EventRef)
{
@@ -2637,6 +2632,29 @@ bool QApplication::macEventFilter(EventHandlerCallRef, EventRef)
}
/*!
+ \fn bool QApplication::macEventFilter(void *nsevent)
+
+ \warning This virtual function is only used under Mac OS X when Qt is based on Cocoa.
+
+ If you create an application that inherits QApplication and reimplement
+ this function, you get direct access to all NSEvents that Qt receives
+ from Cocoa.
+ \a nsevent is of type NSEvent *:
+
+ NSEvent *e = static_cast<NSEvent *>(nsevent);
+
+ Return true if you want to stop the event from being processed.
+ Return false for normal event dispatching. The default
+ implementation returns false.
+
+ \sa macEventFilter(EventHandlerCallRef caller, EventRef event)
+*/
+bool QApplication::macEventFilter(void * /*NSEvent*/)
+{
+ return false;
+}
+
+/*!
\internal
*/
void QApplicationPrivate::openPopup(QWidget *popup)
@@ -3110,11 +3128,7 @@ void onApplicationChangedActivation( bool activated )
}
if (!app->activeWindow()) {
-#if QT_MAC_USE_COCOA
- OSWindowRef wp = [NSApp keyWindow];
-#else
- OSWindowRef wp = ActiveNonFloatingWindow();
-#endif
+ OSWindowRef wp = [NSApp keyWindow];
if (QWidget *tmp_w = qt_mac_find_window(wp))
app->setActiveWindow(tmp_w);
}
diff --git a/src/gui/kernel/qcocoaapplication_mac.mm b/src/gui/kernel/qcocoaapplication_mac.mm
index 4962863..5cd32a1 100644
--- a/src/gui/kernel/qcocoaapplication_mac.mm
+++ b/src/gui/kernel/qcocoaapplication_mac.mm
@@ -78,6 +78,7 @@
#include <private/qcocoaapplication_mac_p.h>
#include <private/qcocoaapplicationdelegate_mac_p.h>
#include <private/qt_cocoa_helpers_mac_p.h>
+#include <private/qcocoaintrospection_p.h>
QT_USE_NAMESPACE
@@ -116,12 +117,26 @@ QT_USE_NAMESPACE
quint64 lower = [event data1];
quint64 upper = [event data2];
QCocoaPostMessageArgs *args = reinterpret_cast<QCocoaPostMessageArgs *>(lower | (upper << 32));
- [args->target performSelector:args->selector];
+ switch (args->argCount) {
+ case 0:
+ [args->target performSelector:args->selector];
+ break;
+ case 1:
+ [args->target performSelector:args->selector withObject:args->arg1];
+ break;
+ case 3:
+ [args->target performSelector:args->selector withObject:args->arg1 withObject:args->arg2];
+ break;
+ }
+
delete args;
}
-- (BOOL)qt_sendEvent:(NSEvent *)event
+- (BOOL)qt_filterEvent:(NSEvent *)event
{
+ if (qApp->macEventFilter(event))
+ return true;
+
if ([event type] == NSApplicationDefined) {
switch ([event subtype]) {
case QtCocoaEventSubTypePostMessage:
@@ -138,20 +153,55 @@ QT_USE_NAMESPACE
@implementation QNSApplication
-// WARNING: If Qt did not create NSApplication (this can e.g.
-// happend if Qt is used as a plugin from a 3rd-party cocoa
-// application), QNSApplication::sendEvent will never be called.
-// SO DO NOT RELY ON THIS FUNCTION BEING AVAILABLE.
-// Plugin developers that _do_ control the NSApplication sub-class
-// implementation of the 3rd-party application can call qt_sendEvent
-// from the sub-class event handler (like we do here) to work around
-// any issues.
+- (void)qt_sendEvent_original:(NSEvent *)event
+{
+ Q_UNUSED(event);
+ // This method will only be used as a signature
+ // template for the method we add into NSApplication
+ // containing the original [NSApplication sendEvent:] implementation
+}
+
+- (void)qt_sendEvent_replacement:(NSEvent *)event
+{
+ // This method (or its implementation to be precise) will
+ // be called instead of sendEvent if redirection occurs.
+ // 'self' will then be an instance of NSApplication
+ // (and not QNSApplication)
+ if (![NSApp qt_filterEvent:event])
+ [self qt_sendEvent_original:event];
+}
+
- (void)sendEvent:(NSEvent *)event
{
- if (![self qt_sendEvent:event])
+ // This method will be called if
+ // no redirection occurs
+ if (![NSApp qt_filterEvent:event])
[super sendEvent:event];
}
@end
+QT_BEGIN_NAMESPACE
+
+void qt_redirectNSApplicationSendEvent()
+{
+ if ([NSApp isMemberOfClass:[QNSApplication class]]) {
+ // No need to change implementation since Qt
+ // already controls a subclass of NSApplication
+ return;
+ }
+
+ // Change the implementation of [NSApplication sendEvent] to the
+ // implementation of qt_sendEvent_replacement found in QNSApplication.
+ // And keep the old implementation that gets overwritten inside a new
+ // method 'qt_sendEvent_original' that we add to NSApplication
+ qt_cocoa_change_implementation(
+ [NSApplication class],
+ @selector(sendEvent:),
+ [QNSApplication class],
+ @selector(qt_sendEvent_replacement:),
+ @selector(qt_sendEvent_original:));
+ }
+
+QT_END_NAMESPACE
#endif
diff --git a/src/gui/kernel/qcocoaapplication_mac_p.h b/src/gui/kernel/qcocoaapplication_mac_p.h
index 5569feb..c89ff36 100644
--- a/src/gui/kernel/qcocoaapplication_mac_p.h
+++ b/src/gui/kernel/qcocoaapplication_mac_p.h
@@ -101,11 +101,17 @@ QT_FORWARD_DECLARE_CLASS(QApplicationPrivate)
- (int)QT_MANGLE_NAMESPACE(qt_validModesForFontPanel):(NSFontPanel *)fontPanel;
- (void)qt_sendPostedMessage:(NSEvent *)event;
-- (BOOL)qt_sendEvent:(NSEvent *)event;
+- (BOOL)qt_filterEvent:(NSEvent *)event;
@end
@interface QNSApplication : NSApplication {
}
@end
+QT_BEGIN_NAMESPACE
+
+void qt_redirectNSApplicationSendEvent();
+
+QT_END_NAMESPACE
+
#endif
diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
index 8652816..717cfa5 100644
--- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
+++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
@@ -149,17 +149,6 @@ QT_END_NAMESPACE
- (void)sendEvent:(NSEvent *)event
{
- if ([event type] == NSApplicationDefined) {
- switch ([event subtype]) {
- case QtCocoaEventSubTypePostMessage:
- [NSApp qt_sendPostedMessage:event];
- return;
- default:
- break;
- }
- return;
- }
-
QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self];
// Cocoa can hold onto the window after we've disavowed its knowledge. So,
// if we get sent an event afterwards just have it go through the super's
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm
index 8cef03c..cbfbf86 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac.mm
+++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm
@@ -1423,39 +1423,17 @@ void qt_cocoaChangeOverrideCursor(const QCursor &cursor)
[static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) set];
}
-// WARNING: If Qt did not create NSApplication (e.g. in case it is
-// used as a plugin), and at the same time, there is no window on
-// screen (or the window that the event is sendt to becomes hidden etc
-// before the event gets delivered), the message will not be performed.
-bool qt_cocoaPostMessage(id target, SEL selector)
+void qt_cocoaPostMessage(id target, SEL selector, int argCount, id arg1, id arg2)
{
- if (!target)
- return false;
-
- NSInteger windowNumber = 0;
- if (![NSApp isMemberOfClass:[QNSApplication class]]) {
- // INVARIANT: Cocoa is not using our NSApplication subclass. That means
- // we don't control the main event handler either. So target the event
- // for one of the windows on screen:
- NSWindow *nswin = [NSApp mainWindow];
- if (!nswin) {
- nswin = [NSApp keyWindow];
- if (!nswin)
- return false;
- }
- windowNumber = [nswin windowNumber];
- }
-
- // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5!
+ // WARNING: data1 and data2 is truncated to from 64-bit to 32-bit on OS 10.5!
// That is why we need to split the address in two parts:
- QCocoaPostMessageArgs *args = new QCocoaPostMessageArgs(target, selector);
+ QCocoaPostMessageArgs *args = new QCocoaPostMessageArgs(target, selector, argCount, arg1, arg2);
quint32 lower = quintptr(args);
quint32 upper = quintptr(args) >> 32;
NSEvent *e = [NSEvent otherEventWithType:NSApplicationDefined
- location:NSZeroPoint modifierFlags:0 timestamp:0 windowNumber:windowNumber
+ location:NSZeroPoint modifierFlags:0 timestamp:0 windowNumber:0
context:nil subtype:QtCocoaEventSubTypePostMessage data1:lower data2:upper];
[NSApp postEvent:e atStart:NO];
- return true;
}
#endif
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
index 5db121a..6b005ca 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h
+++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
@@ -198,17 +198,25 @@ class QCocoaPostMessageArgs {
public:
id target;
SEL selector;
- QCocoaPostMessageArgs(id target, SEL selector) : target(target), selector(selector)
+ int argCount;
+ id arg1;
+ id arg2;
+ QCocoaPostMessageArgs(id target, SEL selector, int argCount=0, id arg1=0, id arg2=0)
+ : target(target), selector(selector), argCount(argCount), arg1(arg1), arg2(arg2)
{
[target retain];
+ [arg1 retain];
+ [arg2 retain];
}
~QCocoaPostMessageArgs()
{
+ [arg2 release];
+ [arg1 release];
[target release];
}
};
-bool qt_cocoaPostMessage(id target, SEL selector);
+void qt_cocoaPostMessage(id target, SEL selector, int argCount=0, id arg1=0, id arg2=0);
#endif
#endif
diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm
index aaa113b..8016da9 100644
--- a/src/gui/widgets/qmenu_mac.mm
+++ b/src/gui/widgets/qmenu_mac.mm
@@ -2052,8 +2052,7 @@ bool QMenuBar::macUpdateMenuBar()
{
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
- if (!qt_cocoaPostMessage(getMenuLoader(), @selector(qtUpdateMenubar)))
- return QMenuBarPrivate::macUpdateMenuBarImmediatly();
+ qt_cocoaPostMessage(getMenuLoader(), @selector(qtUpdateMenubar));
return true;
#else
return QMenuBarPrivate::macUpdateMenuBarImmediatly();