summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@nokia.com>2009-12-23 13:18:31 (GMT)
committerRichard Moe Gustavsen <richard.gustavsen@nokia.com>2010-01-04 08:03:50 (GMT)
commitec452c7f31ffe53dc28763a80d517288ac3c118d (patch)
tree8c0919ca8ee9b9c6f6e65086181304f43720b311 /src/gui/kernel
parent592dc5978e5109c6c7c378623817938779c869a0 (diff)
downloadQt-ec452c7f31ffe53dc28763a80d517288ac3c118d.zip
Qt-ec452c7f31ffe53dc28763a80d517288ac3c118d.tar.gz
Qt-ec452c7f31ffe53dc28763a80d517288ac3c118d.tar.bz2
Cocoa: app menu does now show before doing qApp::exec()
The reason is that we need to start [NSApplication run] before the menus get properly initialized. This patch will make the event dispatcher run nsapp once before spinning a modal session, if needed Task-number: QTBUG-6627
Diffstat (limited to 'src/gui/kernel')
-rw-r--r--src/gui/kernel/qeventdispatcher_mac.mm40
-rw-r--r--src/gui/kernel/qeventdispatcher_mac_p.h4
2 files changed, 28 insertions, 16 deletions
diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm
index 0b48dca..8d2218b 100644
--- a/src/gui/kernel/qeventdispatcher_mac.mm
+++ b/src/gui/kernel/qeventdispatcher_mac.mm
@@ -570,8 +570,8 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags)
// done from the application itself. And if processEvents is called
// manually (rather than from a QEventLoop), we cannot enter a tight
// loop and block this call, but instead we need to return after one flush:
- bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning];
- bool canExec_Qt = flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec;
+ const bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning];
+ const bool canExec_Qt = flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec;
if (canExec_Qt && canExec_3rdParty) {
// We can use exec-mode, meaning that we can stay in a tight loop until
@@ -596,9 +596,10 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags)
}
retVal = true;
} else {
+ // We cannot block the thread (and run in a tight loop).
+ // Instead we will process all current pending events and return.
+ d->ensureNSAppInitialized();
do {
- // We cannot block the thread (and run in a tight loop).
- // Instead we will process all current pending events and return.
bool releaseEvent = false;
if (!(flags & QEventLoop::ExcludeUserInputEvents)
@@ -746,20 +747,31 @@ bool QEventDispatcherMacPrivate::blockSendPostedEvents = false;
#ifdef QT_MAC_USE_COCOA
QStack<QCocoaModalSessionInfo> QEventDispatcherMacPrivate::cocoaModalSessionStack;
+bool QEventDispatcherMacPrivate::interrupt = false;
bool QEventDispatcherMacPrivate::currentExecIsNSAppRun = false;
bool QEventDispatcherMacPrivate::modalSessionsTemporarilyStopped = false;
bool QEventDispatcherMacPrivate::nsAppRunCalledByQt = false;
bool QEventDispatcherMacPrivate::cleanupModalSessionsNeeded = false;
NSModalSession QEventDispatcherMacPrivate::currentModalSessionCached = 0;
-void QEventDispatcherMacPrivate::flushCocoaEvents()
+void QEventDispatcherMacPrivate::ensureNSAppInitialized()
{
- while (NSEvent *event = [NSApp nextEventMatchingMask:0
- untilDate:nil
- inMode:NSDefaultRunLoopMode
- dequeue: YES]) {
- qt_mac_send_event(0, event, 0);
- }
+ // Some elements in Cocoa require NSApplication to be running before
+ // they get fully initialized, in particular the menu bar. This
+ // function is intended for cases where a dialog is told to execute before
+ // QApplication::exec is called, or the application spins the events loop
+ // manually rather than calling QApplication:exec.
+ // The function makes sure that NSApplication starts running, but stops
+ // it again as soon as the send posted events callback is called. That way
+ // we let Cocoa finish the initialization it seems to need. We'll only
+ // apply this trick at most once for any application, and we avoid doing it
+ // for the common case where main just starts QApplication::exec.
+ if (nsAppRunCalledByQt || [NSApp isRunning])
+ return;
+ nsAppRunCalledByQt = true;
+ QBoolBlocker block1(interrupt, true);
+ QBoolBlocker block2(currentExecIsNSAppRun, true);
+ [NSApp run];
}
void QEventDispatcherMacPrivate::temporarilyStopAllModalSessions()
@@ -811,6 +823,8 @@ NSModalSession QEventDispatcherMacPrivate::currentModalSession()
NSWindow *window = qt_mac_window_for(info.widget);
if (!window)
continue;
+
+ ensureNSAppInitialized();
QBoolBlocker block1(blockSendPostedEvents, true);
info.session = [NSApp beginModalSessionForWindow:window];
}
@@ -826,12 +840,11 @@ NSModalSession QEventDispatcherMacPrivate::currentModalSession()
// screen. To work around this, we block cocoa from changing the
// stacking order of the windows, and flush out the pending events
// (the block is used in QCocoaWindow and QCocoaPanel):
- modalSessionsTemporarilyStopped = false;
QBoolBlocker block1(blockSendPostedEvents, true);
QBoolBlocker block2(qt_blockCocoaSettingModalWindowLevel, true);
[NSApp runModalSession:currentModalSessionCached];
}
-
+ modalSessionsTemporarilyStopped = false;
return currentModalSessionCached;
}
@@ -935,7 +948,6 @@ void QEventDispatcherMacPrivate::endModalSession(QWidget *widget)
#endif
QEventDispatcherMacPrivate::QEventDispatcherMacPrivate()
- : interrupt(false)
{
}
diff --git a/src/gui/kernel/qeventdispatcher_mac_p.h b/src/gui/kernel/qeventdispatcher_mac_p.h
index 37ee2b1..205f564 100644
--- a/src/gui/kernel/qeventdispatcher_mac_p.h
+++ b/src/gui/kernel/qeventdispatcher_mac_p.h
@@ -184,7 +184,7 @@ public:
static void endModalSession(QWidget *widget);
static void cancelWaitForMoreEvents();
static void cleanupModalSessions();
- static void flushCocoaEvents();
+ static void ensureNSAppInitialized();
#endif
MacSocketHash macSockets;
@@ -194,7 +194,7 @@ public:
CFRunLoopObserverRef firstTimeObserver;
QAtomicInt serialNumber;
int lastSerial;
- bool interrupt;
+ static bool interrupt;
private:
static Boolean postedEventSourceEqualCallback(const void *info1, const void *info2);
static void postedEventsSourcePerformCallback(void *info);