summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorJorgen Lind <jorgen.lind@digia.com>2014-04-03 13:11:59 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-04-16 09:30:32 +0200
commit50b8506eaccc3c9bc3d717b241193bc8be9708b0 (patch)
tree4d6114ce95bfccb99910a8d63b19a0afcd2960f0 /src/plugins
parent3536823c7f967b164f64a6bcfa64e4c5e3b8eb01 (diff)
XCB: fix that modal dialogs can go behind other process windows
Task-number: QTBUG-35302 Change-Id: I1ad7a66e530710d5338a15057254360dae676451 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com> Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp8
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp22
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp104
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h4
4 files changed, 93 insertions, 45 deletions
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 6462cb8d3e..f66859b72a 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -49,11 +49,11 @@
#include "qwindowsmime.h"
#include "qwindowsinputcontext.h"
#include "qwindowstabletsupport.h"
+#include <private/qguiapplication_p.h>
#ifndef QT_NO_ACCESSIBILITY
# include "accessible/qwindowsaccessibility.h"
#endif
#if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER)
-# include <private/qguiapplication_p.h>
# include <private/qsessionmanager_p.h>
# include "qwindowssessionmanager.h"
#endif
@@ -1025,6 +1025,12 @@ void QWindowsContext::handleFocusEvent(QtWindows::WindowsEventType et,
{
QWindow *nextActiveWindow = 0;
if (et == QtWindows::FocusInEvent) {
+ QWindow *topWindow = QWindowsWindow::topLevelOf(platformWindow->window());
+ QWindow *modalWindow = 0;
+ if (QGuiApplicationPrivate::instance()->isWindowBlocked(topWindow, &modalWindow) && topWindow != modalWindow) {
+ modalWindow->requestActivate();
+ return;
+ }
nextActiveWindow = platformWindow->window();
} else {
// Focus out: Is the next window known and different
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index ee9bf9936c..db06525508 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1016,17 +1016,17 @@ QWindow *QWindowsWindow::topLevelOf(QWindow *w)
while (QWindow *parent = w->parent())
w = parent;
- const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(w->handle());
-
- // In case the topmost parent is embedded, find next ancestor using native methods
- if (ww->isEmbedded(0)) {
- HWND parentHWND = GetAncestor(ww->handle(), GA_PARENT);
- const HWND desktopHwnd = GetDesktopWindow();
- const QWindowsContext *ctx = QWindowsContext::instance();
- while (parentHWND && parentHWND != desktopHwnd) {
- if (QWindowsWindow *ancestor = ctx->findPlatformWindow(parentHWND))
- return topLevelOf(ancestor->window());
- parentHWND = GetAncestor(parentHWND, GA_PARENT);
+ if (const QPlatformWindow *handle = w->handle()) {
+ const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(handle);
+ if (ww->isEmbedded(0)) {
+ HWND parentHWND = GetAncestor(ww->handle(), GA_PARENT);
+ const HWND desktopHwnd = GetDesktopWindow();
+ const QWindowsContext *ctx = QWindowsContext::instance();
+ while (parentHWND && parentHWND != desktopHwnd) {
+ if (QWindowsWindow *ancestor = ctx->findPlatformWindow(parentHWND))
+ return topLevelOf(ancestor->window());
+ parentHWND = GetAncestor(parentHWND, GA_PARENT);
+ }
}
}
return w;
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 193e75c1d6..dbffd577c1 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -485,7 +485,7 @@ QXcbWindow::~QXcbWindow()
void QXcbWindow::destroy()
{
if (connection()->focusWindow() == this)
- connection()->setFocusWindow(0);
+ doFocusOut();
if (m_syncCounter && m_usingSyncProtocol)
Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter));
@@ -671,6 +671,9 @@ void QXcbWindow::show()
Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
+ if (QGuiApplication::modalWindow() == window())
+ requestActivateWindow();
+
m_screen->windowShown(this);
connection()->sync();
@@ -694,6 +697,68 @@ void QXcbWindow::hide()
m_mapped = false;
}
+static QWindow *tlWindow(QWindow *window)
+{
+ if (window && window->parent())
+ return tlWindow(window->parent());
+ return window;
+}
+
+bool QXcbWindow::relayFocusToModalWindow() const
+{
+ QWindow *w = tlWindow(static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver());
+ QWindow *modal_window = 0;
+ if (QGuiApplicationPrivate::instance()->isWindowBlocked(w,&modal_window) && modal_window != w) {
+ modal_window->requestActivate();
+ connection()->flush();
+ return true;
+ }
+
+ return false;
+}
+
+void QXcbWindow::doFocusIn()
+{
+ if (relayFocusToModalWindow())
+ return;
+ QWindow *w = static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver();
+ connection()->setFocusWindow(static_cast<QXcbWindow *>(w->handle()));
+ QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason);
+}
+
+static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event)
+{
+ if (!event) {
+ // FocusIn event is not in the queue, proceed with FocusOut normally.
+ QWindowSystemInterface::handleWindowActivated(0, Qt::ActiveWindowFocusReason);
+ return true;
+ }
+ uint response_type = event->response_type & ~0x80;
+ if (response_type == XCB_FOCUS_IN)
+ return true;
+
+ /* We are also interested in XEMBED_FOCUS_IN events */
+ if (response_type == XCB_CLIENT_MESSAGE) {
+ xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event;
+ if (cme->type == connection->atom(QXcbAtom::_XEMBED)
+ && cme->data.data32[1] == XEMBED_FOCUS_IN)
+ return true;
+ }
+
+ return false;
+}
+
+void QXcbWindow::doFocusOut()
+{
+ if (relayFocusToModalWindow())
+ return;
+ connection()->setFocusWindow(0);
+ // Do not set the active window to 0 if there is a FocusIn coming.
+ // There is however no equivalent for XPutBackEvent so register a
+ // callback for QXcbConnection instead.
+ connection()->addPeekFunc(focusInPeeker);
+}
+
struct QtMotifWmHints {
quint32 flags, functions, decorations;
qint32 input_mode;
@@ -1514,6 +1579,8 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
QWindowSystemInterface::handleCloseEvent(window());
} else if (event->data.data32[0] == atom(QXcbAtom::WM_TAKE_FOCUS)) {
connection()->setTime(event->data.data32[1]);
+ relayFocusToModalWindow();
+ return;
} else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) {
if (event->window == m_screen->root())
return;
@@ -1549,8 +1616,7 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
} else if (event->type == atom(QXcbAtom::_XEMBED)) {
handleXEmbedMessage(event);
} else if (event->type == atom(QXcbAtom::_NET_ACTIVE_WINDOW)) {
- connection()->setFocusWindow(this);
- QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason);
+ doFocusIn();
} else if (event->type == atom(QXcbAtom::MANAGER)
|| event->type == atom(QXcbAtom::_NET_WM_STATE)
|| event->type == atom(QXcbAtom::WM_CHANGE_STATE)) {
@@ -1865,41 +1931,13 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *)
{
- QWindow *w = window();
- w = static_cast<QWindowPrivate *>(QObjectPrivate::get(w))->eventReceiver();
- connection()->setFocusWindow(static_cast<QXcbWindow *>(w->handle()));
- QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason);
+ doFocusIn();
}
-static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event)
-{
- if (!event) {
- // FocusIn event is not in the queue, proceed with FocusOut normally.
- QWindowSystemInterface::handleWindowActivated(0, Qt::ActiveWindowFocusReason);
- return true;
- }
- uint response_type = event->response_type & ~0x80;
- if (response_type == XCB_FOCUS_IN)
- return true;
-
- /* We are also interested in XEMBED_FOCUS_IN events */
- if (response_type == XCB_CLIENT_MESSAGE) {
- xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event;
- if (cme->type == connection->atom(QXcbAtom::_XEMBED)
- && cme->data.data32[1] == XEMBED_FOCUS_IN)
- return true;
- }
-
- return false;
-}
void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
{
- connection()->setFocusWindow(0);
- // Do not set the active window to 0 if there is a FocusIn coming.
- // There is however no equivalent for XPutBackEvent so register a
- // callback for QXcbConnection instead.
- connection()->addPeekFunc(focusInPeeker);
+ doFocusOut();
}
void QXcbWindow::updateSyncRequestCounter()
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index a90ad7b5ed..12d17023fb 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -176,6 +176,10 @@ private:
void show();
void hide();
+ bool relayFocusToModalWindow() const;
+ void doFocusIn();
+ void doFocusOut();
+
QXcbScreen *m_screen;
xcb_window_t m_window;