diff options
author | Friedemann Kleint <Friedemann.Kleint@theqtcompany.com> | 2015-12-21 15:06:40 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@theqtcompany.com> | 2016-02-25 07:17:43 +0000 |
commit | 28ee76fd0b9ce59291341c8a9937a6c98fcb926d (patch) | |
tree | cd385d6a5b771c7e88639e05cef1630bba7458e3 /src | |
parent | 97965a0908b8fbf7f01d0880410929a4ea61b48d (diff) |
QtPlatformHeaders/Windows: Add function to set window activation behavior.
The Windows OS by default does not activate windows when the calling
process is not active; only the taskbar entry is flashed as not to
distract the user.
Nevertheless, for some use cases, it is desirable to activate the window
also in the inactive state.
Introduce an enumeration specifying the behavior to QtPlatformHeaders
and employ a workaround using the Win32 API AttachThreadInput() to attach
to other processes while setting the foreground window to achieve
the AlwaysActivateWindow behavior.
Task-number: QTBUG-14062
Task-number: QTBUG-37435
Change-Id: I79cb6cd3fab29d55b5d3db7f9af01bbaa5096a37
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/gui/doc/qtgui.qdocconf | 1 | ||||
-rw-r--r-- | src/gui/kernel/qwindow.cpp | 2 | ||||
-rw-r--r-- | src/platformheaders/doc/qtplatformheaders.qdocconf | 1 | ||||
-rw-r--r-- | src/platformheaders/windowsfunctions/qwindowswindowfunctions.h | 15 | ||||
-rw-r--r-- | src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc | 49 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowsnativeinterface.cpp | 5 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowsnativeinterface.h | 9 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowswindow.cpp | 23 | ||||
-rw-r--r-- | src/widgets/doc/qtwidgets.qdocconf | 2 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 2 |
10 files changed, 106 insertions, 3 deletions
diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf index e34347b801..027d2663de 100644 --- a/src/gui/doc/qtgui.qdocconf +++ b/src/gui/doc/qtgui.qdocconf @@ -33,6 +33,7 @@ depends += \ qtmultimedia \ qtnetwork \ qtopengl \ + qtplatformheaders \ qtsvg \ qtqml \ qtquick \ diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 44fa88e7cf..c5c4f901e0 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1002,7 +1002,7 @@ QRegion QWindow::mask() const /*! Requests the window to be activated, i.e. receive keyboard focus. - \sa isActive(), QGuiApplication::focusWindow() + \sa isActive(), QGuiApplication::focusWindow(), QWindowsWindowFunctions::setWindowActivationBehavior() */ void QWindow::requestActivate() { diff --git a/src/platformheaders/doc/qtplatformheaders.qdocconf b/src/platformheaders/doc/qtplatformheaders.qdocconf index fc8a9d8731..989df524e6 100644 --- a/src/platformheaders/doc/qtplatformheaders.qdocconf +++ b/src/platformheaders/doc/qtplatformheaders.qdocconf @@ -27,6 +27,7 @@ qhp.QtPlatformHeaders.subprojects.classes.sortPages = true depends += \ qtcore \ qtgui \ + qtwidgets \ qtdoc headerdirs += .. diff --git a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h index 2b1efcdd6d..d0826bdb50 100644 --- a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h +++ b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h @@ -57,6 +57,11 @@ public: Q_DECLARE_FLAGS(TouchWindowTouchTypes, TouchWindowTouchType) + enum WindowActivationBehavior { + DefaultActivateWindow, + AlwaysActivateWindow + }; + typedef void (*SetTouchWindowTouchType)(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchType); static const QByteArray setTouchWindowTouchTypeIdentifier() { return QByteArrayLiteral("WindowsSetTouchWindowTouchType"); } @@ -75,6 +80,16 @@ public: if (func) func(window, border); } + + typedef void (*SetWindowActivationBehaviorType)(WindowActivationBehavior); + static const QByteArray setWindowActivationBehaviorIdentifier() { return QByteArrayLiteral("WindowsSetWindowActivationBehavior"); } + + static void setWindowActivationBehavior(WindowActivationBehavior behavior) + { + SetWindowActivationBehaviorType func = reinterpret_cast<SetWindowActivationBehaviorType>(QGuiApplication::platformFunction(setWindowActivationBehaviorIdentifier())); + if (func) + func(behavior); + } }; Q_DECLARE_OPERATORS_FOR_FLAGS(QWindowsWindowFunctions::TouchWindowTouchTypes) diff --git a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc index d6b8764e7b..196f9f22ce 100644 --- a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc +++ b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc @@ -95,3 +95,52 @@ See also \l [QtDoc] {Fullscreen OpenGL Based Windows} */ + +/*! + \enum QWindowsWindowFunctions::WindowActivationBehavior + + This enum specifies the behavior of QWidget::activateWindow() and + QWindow::requestActivate(). + + \value DefaultActivateWindow The window is activated according to the default + behavior of the Windows operating system. This means the window will not + be activated in some circumstances (most notably when the calling process + is not the active process); only the taskbar entry will be flashed. + \value AlwaysActivateWindow The window is always activated, even when the + calling process is not the active process. + + \sa QWidget::activateWindow(), QWindow::requestActivate() + \since 5.7 +*/ + +/*! + \typedef QWindowsWindowFunctions::SetWindowActivationBehaviorType + + This is the typedef for the function returned by QGuiApplication::platformFunction() + when passed setWindowActivationBehaviorIdentifier(). + + \sa QWidget::activateWindow(), QWindow::requestActivate() + \since 5.7 +*/ + +/*! + \fn QByteArray setWindowActivationBehaviorIdentifier() + + This function returns a bytearray that can be used to query + QGuiApplication::platformFunction() to retrieve the SetWindowActivationBehaviorType + function. + + \sa QWidget::activateWindow(), QWindow::requestActivate() + \since 5.7 +*/ + +/*! + \fn void QWindowsWindowFunctions::setWindowActivationBehavior(WindowActivationBehavior behavior) + + This is a convenience function that can be used directly instead of resolving + the function pointer. \a behavior will be relayed to the function retrieved + by QGuiApplication. + + \sa QWidget::activateWindow(), QWindow::requestActivate() + \since 5.7 +*/ diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index ac7c22fb7e..babca35149 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -84,6 +84,9 @@ static int resourceType(const QByteArray &key) return int(result - names); } +QWindowsWindowFunctions::WindowActivationBehavior QWindowsNativeInterface::m_windowActivationBehavior = + QWindowsWindowFunctions::DefaultActivateWindow; + void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window) { if (!window || !window->handle()) { @@ -253,6 +256,8 @@ QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &fun return QFunctionPointer(QWindowsWindow::setTouchWindowTouchTypeStatic); else if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier()) return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenStatic); + else if (function == QWindowsWindowFunctions::setWindowActivationBehaviorIdentifier()) + return QFunctionPointer(QWindowsNativeInterface::setWindowActivationBehavior); return Q_NULLPTR; } diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h index 3a0d3398d9..9fc43ddcce 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.h +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h @@ -42,6 +42,7 @@ #include <QtGui/qfont.h> #include <QtGui/qpa/qplatformnativeinterface.h> +#include <QtPlatformHeaders/qwindowswindowfunctions.h> QT_BEGIN_NAMESPACE @@ -96,7 +97,15 @@ public: QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const Q_DECL_OVERRIDE; void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) Q_DECL_OVERRIDE; + static QWindowsWindowFunctions::WindowActivationBehavior windowActivationBehavior() + { return QWindowsNativeInterface::m_windowActivationBehavior; } + static void setWindowActivationBehavior(QWindowsWindowFunctions::WindowActivationBehavior b) + { QWindowsNativeInterface::m_windowActivationBehavior = b; } + QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; + +private: + static QWindowsWindowFunctions::WindowActivationBehavior m_windowActivationBehavior; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 4c503a2c48..c1a047e276 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -43,6 +43,7 @@ #include "qwindowsdrag.h" #include "qwindowsscreen.h" #include "qwindowsintegration.h" +#include "qwindowsnativeinterface.h" #include "qwindowsopenglcontext.h" #ifdef QT_NO_CURSOR # include "qwindowscursor.h" @@ -2083,8 +2084,30 @@ void QWindowsWindow::requestActivateWindow() // 'Active' state handling is based in focus since it needs to work for // child windows as well. if (m_data.hwnd) { +#ifndef Q_OS_WINCE + const DWORD currentThread = GetCurrentThreadId(); + bool attached = false; + DWORD foregroundThread = 0; + + // QTBUG-14062, QTBUG-37435: Windows normally only flashes the taskbar entry + // when activating windows of inactive applications. Attach to the input of the + // currently active window while setting the foreground window to always activate + // the window when desired. + if (QGuiApplication::applicationState() != Qt::ApplicationActive + && QWindowsNativeInterface::windowActivationBehavior() == QWindowsWindowFunctions::AlwaysActivateWindow) { + if (const HWND foregroundWindow = GetForegroundWindow()) { + foregroundThread = GetWindowThreadProcessId(foregroundWindow, NULL); + if (foregroundThread && foregroundThread != currentThread) + attached = AttachThreadInput(foregroundThread, currentThread, TRUE) == TRUE; + } + } +#endif // !Q_OS_WINCE SetForegroundWindow(m_data.hwnd); SetFocus(m_data.hwnd); +#ifndef Q_OS_WINCE + if (attached) + AttachThreadInput(foregroundThread, currentThread, FALSE); +#endif // !Q_OS_WINCE } } diff --git a/src/widgets/doc/qtwidgets.qdocconf b/src/widgets/doc/qtwidgets.qdocconf index 8160396ca2..75bbb99579 100644 --- a/src/widgets/doc/qtwidgets.qdocconf +++ b/src/widgets/doc/qtwidgets.qdocconf @@ -26,7 +26,7 @@ qhp.QtWidgets.subprojects.classes.sortPages = true tagfile = ../../../doc/qtwidgets/qtwidgets.tags -depends += qtcore qtgui qtdoc qtsql qtdesigner qtquick qmake qtsvg +depends += qtcore qtgui qtdoc qtsql qtdesigner qtquick qmake qtplatformheaders qtsvg headerdirs += .. diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 7e2e02b58e..de832d667d 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -12689,7 +12689,7 @@ QWidget *QWidget::keyboardGrabber() does not allow an application to interrupt what the user is currently doing in another application. - \sa isActiveWindow(), window(), show() + \sa isActiveWindow(), window(), show(), QWindowsWindowFunctions::setWindowActivationBehavior() */ void QWidget::activateWindow() { |