macOS: Clear event dispatcher interrupt state
A pending interrupt of a QEventLoop may interfere with
native runModal calls, resulting in Cocoa's main event
loop to be stopped unexpectedly.
After commit 9ab60b9c
processEvents() no longer resets
the event dispatcher interrupt flag.
Add QCocoaEventDispatcher::clearCurrentThreadCocoa
EventDispatcherInterruptFlag(). Use it to clear the
interrupt state before calling runModal and variants.
Work around the inability to use platform API in
the print support code.
Change-Id: I52f26f99a63cbb46969db42f65b09a3c3119ad15
Task-number: QTBUG-56746
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@qt.io>
This commit is contained in:
parent
ffe72840a3
commit
ae8d3d69d6
@ -39,6 +39,7 @@
|
||||
#include <QtCore/qtimer.h>
|
||||
|
||||
#include "qcocoahelpers.h"
|
||||
#include "qcocoaeventdispatcher.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@ -318,6 +319,10 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
|
||||
// cleanup of modal sessions. Do this before showing the native dialog, otherwise it will
|
||||
// close down during the cleanup.
|
||||
qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
|
||||
|
||||
// Make sure we don't interrupt the runModalForWindow call.
|
||||
QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
|
||||
|
||||
[NSApp runModalForWindow:mColorPanel];
|
||||
mDialogIsExecuting = false;
|
||||
return (mResultCode == NSOKButton);
|
||||
|
@ -125,6 +125,8 @@ public:
|
||||
void interrupt();
|
||||
void flush();
|
||||
|
||||
static void clearCurrentThreadCocoaEventDispatcherInterruptFlag();
|
||||
|
||||
friend void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher);
|
||||
};
|
||||
|
||||
|
@ -960,6 +960,19 @@ void QCocoaEventDispatcher::interrupt()
|
||||
void QCocoaEventDispatcher::flush()
|
||||
{ }
|
||||
|
||||
// QTBUG-56746: The behavior of processEvents() has been changed to not clear
|
||||
// the interrupt flag. Use this function to clear it.
|
||||
void QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag()
|
||||
{
|
||||
QCocoaEventDispatcher *cocoaEventDispatcher =
|
||||
qobject_cast<QCocoaEventDispatcher *>(QThread::currentThread()->eventDispatcher());
|
||||
if (!cocoaEventDispatcher)
|
||||
return;
|
||||
QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate =
|
||||
static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
|
||||
cocoaEventDispatcherPrivate->interrupt = false;
|
||||
}
|
||||
|
||||
QCocoaEventDispatcher::~QCocoaEventDispatcher()
|
||||
{
|
||||
Q_D(QCocoaEventDispatcher);
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "qt_mac_p.h"
|
||||
#include "qcocoahelpers.h"
|
||||
#include "qcocoamenubar.h"
|
||||
#include "qcocoaeventdispatcher.h"
|
||||
#include <qregexp.h>
|
||||
#include <qbuffer.h>
|
||||
#include <qdebug.h>
|
||||
@ -235,6 +236,10 @@ static QString strippedText(QString s)
|
||||
// cleanup of modal sessions. Do this before showing the native dialog, otherwise it will
|
||||
// close down during the cleanup.
|
||||
qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
|
||||
|
||||
// Make sure we don't interrupt the runModal call below.
|
||||
QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
|
||||
|
||||
QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
|
||||
mReturnCode = [mSavePanel runModal];
|
||||
QCocoaMenuBar::resetKnownMenuItemsToQt();
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <private/qfontengine_coretext_p.h>
|
||||
|
||||
#include "qcocoahelpers.h"
|
||||
#include "qcocoaeventdispatcher.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
@ -313,6 +314,10 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
|
||||
// cleanup of modal sessions. Do this before showing the native dialog, otherwise it will
|
||||
// close down during the cleanup.
|
||||
qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
|
||||
|
||||
// Make sure we don't interrupt the runModalForWindow call.
|
||||
QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
|
||||
|
||||
[NSApp runModalForWindow:mFontPanel];
|
||||
mDialogIsExecuting = false;
|
||||
return (mResultCode == NSOKButton);
|
||||
|
@ -96,6 +96,8 @@ private:
|
||||
*/
|
||||
Q_INVOKABLE QPixmap defaultBackgroundPixmapForQWizard();
|
||||
|
||||
Q_INVOKABLE void clearCurrentThreadCocoaEventDispatcherInterruptFlag();
|
||||
|
||||
// QMacPastebardMime support. The mac pasteboard void pointers are
|
||||
// QMacPastebardMime instances from the cocoa plugin or qtmacextras
|
||||
// These two classes are kept in sync and can be casted between.
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "qcocoahelpers.h"
|
||||
#include "qcocoaapplication.h"
|
||||
#include "qcocoaintegration.h"
|
||||
#include "qcocoaeventdispatcher.h"
|
||||
|
||||
#include <qbytearray.h>
|
||||
#include <qwindow.h>
|
||||
@ -193,6 +194,11 @@ QPixmap QCocoaNativeInterface::defaultBackgroundPixmapForQWizard()
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
void QCocoaNativeInterface::clearCurrentThreadCocoaEventDispatcherInterruptFlag()
|
||||
{
|
||||
QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
|
||||
}
|
||||
|
||||
void QCocoaNativeInterface::onAppFocusWindowChanged(QWindow *window)
|
||||
{
|
||||
Q_UNUSED(window);
|
||||
|
@ -127,6 +127,11 @@ void QMacPageSetupDialogPrivate::openCocoaPageLayout(Qt::WindowModality modality
|
||||
QT_MANGLE_NAMESPACE(QCocoaPageLayoutDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QCocoaPageLayoutDelegate) alloc] initWithNSPrintInfo:printInfo];
|
||||
|
||||
if (modality == Qt::ApplicationModal) {
|
||||
|
||||
// Make sure we don't interrupt the runModalWithPrintInfo call.
|
||||
(void) QMetaObject::invokeMethod(qApp->platformNativeInterface(),
|
||||
"clearCurrentThreadCocoaEventDispatcherInterruptFlag");
|
||||
|
||||
int rval = [pageLayout runModalWithPrintInfo:printInfo];
|
||||
[delegate pageLayoutDidEnd:pageLayout returnCode:rval contextInfo:q];
|
||||
} else {
|
||||
|
@ -239,6 +239,11 @@ void QPrintDialogPrivate::openCocoaPrintPanel(Qt::WindowModality modality)
|
||||
if (modality == Qt::ApplicationModal || !q->parentWidget()) {
|
||||
if (modality == Qt::NonModal)
|
||||
qWarning("QPrintDialog is required to be modal on OS X");
|
||||
|
||||
// Make sure we don't interrupt the runModalWithPrintInfo call.
|
||||
(void) QMetaObject::invokeMethod(qApp->platformNativeInterface(),
|
||||
"clearCurrentThreadCocoaEventDispatcherInterruptFlag");
|
||||
|
||||
int rval = [printPanel runModalWithPrintInfo:printInfo];
|
||||
[delegate printPanelDidEnd:printPanel returnCode:rval contextInfo:q];
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user