From e79b40ee8f78a9669ed0b7b6def2a69ef7ab02fa Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Tue, 1 Nov 2016 15:28:17 -0700 Subject: 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: I3e03e7ec21ff6c49442c7a6e803a7200aac0b58d Task-number: QTBUG-56746 Reviewed-by: Gabriel de Dietrich --- src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm | 5 +++++ src/plugins/platforms/cocoa/qcocoaeventdispatcher.h | 2 ++ src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm | 13 +++++++++++++ src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm | 5 +++++ src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm | 5 +++++ src/plugins/platforms/cocoa/qcocoanativeinterface.h | 2 ++ src/plugins/platforms/cocoa/qcocoanativeinterface.mm | 6 ++++++ 7 files changed, 38 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm index 0319d4ca6d..7d12804d47 100644 --- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm @@ -45,6 +45,7 @@ #include "qcocoacolordialoghelper.h" #include "qcocoahelpers.h" +#include "qcocoaeventdispatcher.h" #import @@ -322,6 +323,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); diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h index 84880d51c5..70887c41c9 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -131,6 +131,8 @@ public: void interrupt(); void flush(); + static void clearCurrentThreadCocoaEventDispatcherInterruptFlag(); + friend void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher); }; diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index 5c27cf8059..d9c835d797 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -966,6 +966,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(QThread::currentThread()->eventDispatcher()); + if (!cocoaEventDispatcher) + return; + QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = + static_cast(QObjectPrivate::get(cocoaEventDispatcher)); + cocoaEventDispatcherPrivate->interrupt = false; +} + QCocoaEventDispatcher::~QCocoaEventDispatcher() { Q_D(QCocoaEventDispatcher); diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 4eb35f5495..c7191e4841 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -53,6 +53,7 @@ #include "qt_mac_p.h" #include "qcocoahelpers.h" #include "qcocoamenubar.h" +#include "qcocoaeventdispatcher.h" #include #include #include @@ -243,6 +244,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(); diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm index dc7dfb788f..d0b76861d8 100644 --- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm @@ -49,6 +49,7 @@ #include "qcocoafontdialoghelper.h" #include "qcocoahelpers.h" +#include "qcocoaeventdispatcher.h" #import @@ -319,6 +320,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); diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index 7065a364bf..b06fff1375 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -100,6 +100,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. diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 8562246817..a327750ffd 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -44,6 +44,7 @@ #include "qcocoahelpers.h" #include "qcocoaapplication.h" #include "qcocoaintegration.h" +#include "qcocoaeventdispatcher.h" #include #include @@ -194,6 +195,11 @@ QPixmap QCocoaNativeInterface::defaultBackgroundPixmapForQWizard() return QPixmap(); } +void QCocoaNativeInterface::clearCurrentThreadCocoaEventDispatcherInterruptFlag() +{ + QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag(); +} + void QCocoaNativeInterface::onAppFocusWindowChanged(QWindow *window) { Q_UNUSED(window); -- cgit v1.2.3 From d8857f21ac2640215177b9cb7bb681b74bc66068 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 22 Nov 2016 09:46:14 +0100 Subject: If there are no available sizes, then fallback to the requested size In a case like the SVG iconengine there is no available sizes implementation. However in that case we don't need to provide different sizes as we can have SVG scale it for us to the one requested. So it is assumed that with no available sizes implementation that the icon engine will take care of this for us. This ensures that SVG files can be used as icons inside the menu on macOS. Task-number: QTBUG-40225 Task-number: QTBUG-55932 Change-Id: If01ca582c4c07834e6de16652924e0b7e118c87c Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoahelpers.h | 2 +- src/plugins/platforms/cocoa/qcocoahelpers.mm | 7 +++++-- src/plugins/platforms/cocoa/qcocoamenuitem.mm | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index c2abe4e245..bbb37937d2 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -64,7 +64,7 @@ inline NSMutableArray *qt_mac_QStringListToNSMutableArray(const QStringList &qst NSImage *qt_mac_cgimage_to_nsimage(CGImageRef iamge); NSImage *qt_mac_create_nsimage(const QPixmap &pm); -NSImage *qt_mac_create_nsimage(const QIcon &icon); +NSImage *qt_mac_create_nsimage(const QIcon &icon, int defaultSize = 0); CGImageRef qt_mac_toCGImage(const QImage &qImage); CGImageRef qt_mac_toCGImageMask(const QImage &qImage); QImage qt_mac_toQImage(CGImageRef image); diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 058209da7e..cd73148752 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -152,13 +152,16 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm) return nsImage; } -NSImage *qt_mac_create_nsimage(const QIcon &icon) +NSImage *qt_mac_create_nsimage(const QIcon &icon, int defaultSize) { if (icon.isNull()) return nil; NSImage *nsImage = [[NSImage alloc] init]; - foreach (QSize size, icon.availableSizes()) { + QList availableSizes = icon.availableSizes(); + if (availableSizes.isEmpty() && defaultSize > 0) + availableSizes << QSize(defaultSize, defaultSize); + foreach (QSize size, availableSizes) { QPixmap pm = icon.pixmap(size); QImage image = pm.toImage(); CGImageRef cgImage = qt_mac_toCGImage(image); diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 2d4073956a..fa8eb22569 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -348,7 +348,7 @@ NSMenuItem *QCocoaMenuItem::sync() NSImage *img = nil; if (!m_icon.isNull()) { - img = qt_mac_create_nsimage(m_icon); + img = qt_mac_create_nsimage(m_icon, m_iconSize); [img setSize:NSMakeSize(m_iconSize, m_iconSize)]; } [m_native setImage:img]; -- cgit v1.2.3 From 389b4ec28b6bb402d3575ff9c648ef878257ea84 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 22 Nov 2016 15:45:36 +0100 Subject: Windows QPA: Do not send key events for mouse-synthesized app commands Sending key events in addition causes applications to respond twice to for example the back / forward extra mouse buttons. Suppress the keypress by checking on the device. This is in line with the other platforms, which do not send keypresses either. Native event filters will still be able to listen for WM_APPCOMMAND. Task-number: QTBUG-48117 Task-number: QTBUG-57198 Change-Id: I219e17244087663f06ab2c5a8cf4b880c3655700 Reviewed-by: Andy Shaw --- src/plugins/platforms/windows/qwindowskeymapper.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 60361e436d..a52ae7c2a9 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -861,6 +861,9 @@ bool QWindowsKeyMapper::translateKeyEvent(QWindow *widget, HWND hwnd, bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, const MSG &msg) { #if defined(WM_APPCOMMAND) + // QTBUG-57198, do not send mouse-synthesized commands as key events in addition + if (GET_DEVICE_LPARAM(msg.lParam) == FAPPCOMMAND_MOUSE) + return false; const int cmd = GET_APPCOMMAND_LPARAM(msg.lParam); const int dwKeys = GET_KEYSTATE_LPARAM(msg.lParam); int state = 0; -- cgit v1.2.3