summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.p.agocs@nokia.com>2011-06-03 11:30:23 +0200
committerLaszlo Agocs <laszlo.p.agocs@nokia.com>2011-06-03 11:59:15 +0200
commit1f456b4cbb93e3fea699878d117900b703146213 (patch)
treece33b7dc746a1ef1b6a044fbcf742755c0c5744b
parent7d9fcaccb1e6e056336b9ad1f7f89afac4699aee (diff)
Add support for mouse and keyboard grab.
Reviewed-by: Samuel Rødal
-rw-r--r--src/gui/kernel/qplatformwindow_qpa.cpp14
-rw-r--r--src/gui/kernel/qplatformwindow_qpa.h4
-rw-r--r--src/gui/kernel/qwindow.cpp16
-rw-r--r--src/gui/kernel/qwindow.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp37
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h3
-rw-r--r--src/widgets/kernel/qapplication_qpa.cpp85
-rw-r--r--src/widgets/kernel/qwidget_p.h2
-rw-r--r--src/widgets/kernel/qwidget_qpa.cpp38
-rw-r--r--src/widgets/kernel/qwidgetwindow_qpa.cpp10
10 files changed, 173 insertions, 39 deletions
diff --git a/src/gui/kernel/qplatformwindow_qpa.cpp b/src/gui/kernel/qplatformwindow_qpa.cpp
index 7f07d0e6c7..fcf375fdad 100644
--- a/src/gui/kernel/qplatformwindow_qpa.cpp
+++ b/src/gui/kernel/qplatformwindow_qpa.cpp
@@ -212,6 +212,20 @@ QPlatformGLContext *QPlatformWindow::glContext() const
return 0;
}
+bool QPlatformWindow::setKeyboardGrabEnabled(bool grab)
+{
+ Q_UNUSED(grab);
+ qWarning("This plugin does not support grabbing the keyboard");
+ return false;
+}
+
+bool QPlatformWindow::setMouseGrabEnabled(bool grab)
+{
+ Q_UNUSED(grab);
+ qWarning("This plugin does not support grabbing the mouse");
+ return false;
+}
+
/*!
\class QPlatformWindow
\since 4.8
diff --git a/src/gui/kernel/qplatformwindow_qpa.h b/src/gui/kernel/qplatformwindow_qpa.h
index 2235d0f9be..7991e5e21c 100644
--- a/src/gui/kernel/qplatformwindow_qpa.h
+++ b/src/gui/kernel/qplatformwindow_qpa.h
@@ -88,6 +88,10 @@ public:
virtual void requestActivateWindow();
virtual QPlatformGLContext *glContext() const;
+
+ virtual bool setKeyboardGrabEnabled(bool grab);
+ virtual bool setMouseGrabEnabled(bool grab);
+
protected:
QScopedPointer<QPlatformWindowPrivate> d_ptr;
private:
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 1b65c4e5e2..fca8aaca46 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -427,6 +427,22 @@ QWindowSurface *QWindow::surface() const
return d->surface;
}
+bool QWindow::setKeyboardGrabEnabled(bool grab)
+{
+ Q_D(QWindow);
+ if (d->platformWindow)
+ return d->platformWindow->setKeyboardGrabEnabled(grab);
+ return false;
+}
+
+bool QWindow::setMouseGrabEnabled(bool grab)
+{
+ Q_D(QWindow);
+ if (d->platformWindow)
+ return d->platformWindow->setMouseGrabEnabled(grab);
+ return false;
+}
+
void QWindow::showMinimized()
{
qDebug() << "unimplemented:" << __FILE__ << __LINE__;
diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h
index 5b002a4791..d1c48484ab 100644
--- a/src/gui/kernel/qwindow.h
+++ b/src/gui/kernel/qwindow.h
@@ -144,6 +144,9 @@ public:
QPlatformWindow *handle() const;
QWindowSurface *surface() const;
+ bool setKeyboardGrabEnabled(bool grab);
+ bool setMouseGrabEnabled(bool grab);
+
public Q_SLOTS:
inline void show() { setVisible(true); }
inline void hide() { setVisible(false); }
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index fc888b8289..81822474a4 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -1094,3 +1094,40 @@ void QXcbWindow::updateSyncRequestCounter()
m_syncValue.hi = 0;
}
}
+
+bool QXcbWindow::setKeyboardGrabEnabled(bool grab)
+{
+ if (!grab) {
+ xcb_ungrab_keyboard(xcb_connection(), XCB_TIME_CURRENT_TIME);
+ return true;
+ }
+ xcb_grab_keyboard_cookie_t cookie = xcb_grab_keyboard(xcb_connection(), false,
+ m_window, XCB_TIME_CURRENT_TIME,
+ GrabModeAsync, GrabModeAsync);
+ xcb_generic_error_t *err;
+ xcb_grab_keyboard_reply_t *reply = xcb_grab_keyboard_reply(xcb_connection(), cookie, &err);
+ bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS);
+ free(reply);
+ free(err);
+ return result;
+}
+
+bool QXcbWindow::setMouseGrabEnabled(bool grab)
+{
+ if (!grab) {
+ xcb_ungrab_pointer(xcb_connection(), XCB_TIME_CURRENT_TIME);
+ return true;
+ }
+ xcb_grab_pointer_cookie_t cookie = xcb_grab_pointer(xcb_connection(), false, m_window,
+ (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
+ | EnterWindowMask | LeaveWindowMask | PointerMotionMask),
+ GrabModeAsync, GrabModeAsync,
+ XCB_WINDOW_NONE, XCB_CURSOR_NONE,
+ XCB_TIME_CURRENT_TIME);
+ xcb_generic_error_t *err;
+ xcb_grab_pointer_reply_t *reply = xcb_grab_pointer_reply(xcb_connection(), cookie, &err);
+ bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS);
+ free(reply);
+ free(err);
+ return result;
+}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 40d21f43da..57794fda07 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -76,6 +76,9 @@ public:
QPlatformGLContext *glContext() const;
+ bool setKeyboardGrabEnabled(bool grab);
+ bool setMouseGrabEnabled(bool grab);
+
xcb_window_t xcb_window() const { return m_window; }
uint depth() const { return m_depth; }
QImage::Format format() const { return m_format; }
diff --git a/src/widgets/kernel/qapplication_qpa.cpp b/src/widgets/kernel/qapplication_qpa.cpp
index ec67452543..65aca42cd3 100644
--- a/src/widgets/kernel/qapplication_qpa.cpp
+++ b/src/widgets/kernel/qapplication_qpa.cpp
@@ -71,8 +71,13 @@ QT_BEGIN_NAMESPACE
static QString appName;
static QString appFont;
+static bool popupGrabOk;
extern bool app_do_modal;
extern QWidgetList *qt_modal_stack;
+extern QWidget *qt_button_down;
+extern QWidget *qt_popup_down;
+extern bool qt_replay_popup_mouse_event;
+int openPopupCount = 0;
QString QApplicationPrivate::appName() const
{
@@ -160,6 +165,35 @@ void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous)
q->setActiveWindow(tlw);
}
+static void ungrabKeyboardForPopup(QWidget *popup)
+{
+ if (QWidget::keyboardGrabber())
+ qt_widget_private(QWidget::keyboardGrabber())->stealKeyboardGrab(true);
+ else
+ qt_widget_private(popup)->stealKeyboardGrab(false);
+}
+
+static void ungrabMouseForPopup(QWidget *popup)
+{
+ if (QWidget::mouseGrabber())
+ qt_widget_private(QWidget::mouseGrabber())->stealMouseGrab(true);
+ else
+ qt_widget_private(popup)->stealMouseGrab(false);
+}
+
+static void grabForPopup(QWidget *popup)
+{
+ Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
+ popupGrabOk = qt_widget_private(popup)->stealKeyboardGrab(true);
+ if (popupGrabOk) {
+ popupGrabOk = qt_widget_private(popup)->stealMouseGrab(true);
+ if (!popupGrabOk) {
+ // transfer grab back to the keyboard grabber if any
+ ungrabKeyboardForPopup(popup);
+ }
+ }
+}
+
void QApplicationPrivate::closePopup(QWidget *popup)
{
Q_Q(QApplication);
@@ -167,23 +201,34 @@ void QApplicationPrivate::closePopup(QWidget *popup)
return;
popupWidgets->removeAll(popup);
-//###
-// if (popup == qt_popup_down) {
-// qt_button_down = 0;
-// qt_popup_down = 0;
-// }
+ if (popup == qt_popup_down) {
+ qt_button_down = 0;
+ qt_popup_down = 0;
+ }
- if (QApplicationPrivate::popupWidgets->count() == 0) { // this was the last popup
+ if (QApplicationPrivate::popupWidgets->count() == 0) { // this was the last popup
delete QApplicationPrivate::popupWidgets;
QApplicationPrivate::popupWidgets = 0;
- //### replay mouse event?
-
- //### transfer/release mouse grab
+ if (popupGrabOk) {
+ popupGrabOk = false;
+
+ if (popup->geometry().contains(QPoint(QGuiApplicationPrivate::mousePressX,
+ QGuiApplicationPrivate::mousePressY))
+ || popup->testAttribute(Qt::WA_NoMouseReplay)) {
+ // mouse release event or inside
+ qt_replay_popup_mouse_event = false;
+ } else { // mouse press event
+ QGuiApplicationPrivate::mousePressTime -= 10000; // avoid double click
+ qt_replay_popup_mouse_event = true;
+ }
- //### transfer/release keyboard grab
+ // transfer grab back to mouse grabber if any, otherwise release the grab
+ ungrabMouseForPopup(popup);
- //give back focus
+ // transfer grab back to keyboard grabber if any, otherwise release the grab
+ ungrabKeyboardForPopup(popup);
+ }
if (active_window) {
if (QWidget *fw = active_window->focusWidget()) {
@@ -198,31 +243,25 @@ void QApplicationPrivate::closePopup(QWidget *popup)
} else {
// A popup was closed, so the previous popup gets the focus.
-
QWidget* aw = QApplicationPrivate::popupWidgets->last();
if (QWidget *fw = aw->focusWidget())
fw->setFocus(Qt::PopupFocusReason);
- //### regrab the keyboard and mouse in case 'popup' lost the grab
-
-
+ if (QApplicationPrivate::popupWidgets->count() == 1) // grab mouse/keyboard
+ grabForPopup(aw);
}
}
-int openPopupCount = 0;
void QApplicationPrivate::openPopup(QWidget *popup)
{
openPopupCount++;
- if (!popupWidgets) { // create list
+ if (!popupWidgets) // create list
popupWidgets = new QWidgetList;
+ popupWidgets->append(popup); // add to end of list
- /* only grab if you are the first/parent popup */
- //#### ->grabMouse(popup,true);
- //#### ->grabKeyboard(popup,true);
- //### popupGrabOk = true;
- }
- popupWidgets->append(popup); // add to end of list
+ if (QApplicationPrivate::popupWidgets->count() == 1) // grab mouse/keyboard
+ grabForPopup(popup);
// popups are not focus-handled by the window system (the first
// popup grabbed the keyboard), so we have to do that manually: A
diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h
index 24047cbced..d39e318b36 100644
--- a/src/widgets/kernel/qwidget_p.h
+++ b/src/widgets/kernel/qwidget_p.h
@@ -901,6 +901,8 @@ public:
#elif defined(Q_WS_QPA) // <--------------------------------------------------------- QPA
void setMaxWindowState_helper();
void setFullScreenSize_helper();
+ bool stealKeyboardGrab(bool grab);
+ bool stealMouseGrab(bool grab);
#ifndef QT_NO_CURSOR
void updateCursor() const;
#endif
diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp
index b8a7cb5463..8764f633f1 100644
--- a/src/widgets/kernel/qwidget_qpa.cpp
+++ b/src/widgets/kernel/qwidget_qpa.cpp
@@ -338,8 +338,8 @@ void QWidget::grabMouse()
if (qt_mouseGrb)
qt_mouseGrb->releaseMouse();
- // XXX
- //qwsDisplay()->grabMouse(this,true);
+ if (windowHandle())
+ windowHandle()->setMouseGrabEnabled(true);
qt_mouseGrb = this;
qt_pressGrab = 0;
@@ -353,19 +353,27 @@ void QWidget::grabMouse(const QCursor &cursor)
if (qt_mouseGrb)
qt_mouseGrb->releaseMouse();
- // XXX
- //qwsDisplay()->grabMouse(this,true);
- //qwsDisplay()->selectCursor(this, cursor.handle());
+ if (windowHandle())
+ windowHandle()->setMouseGrabEnabled(true);
+
qt_mouseGrb = this;
qt_pressGrab = 0;
}
#endif
+bool QWidgetPrivate::stealMouseGrab(bool grab)
+{
+ // This is like a combination of grab/releaseMouse() but with error checking
+ // and it has no effect on the result of mouseGrabber().
+ Q_Q(QWidget);
+ return q->windowHandle() ? q->windowHandle()->setMouseGrabEnabled(grab) : false;
+}
+
void QWidget::releaseMouse()
{
if (qt_mouseGrb == this) {
- // XXX
- //qwsDisplay()->grabMouse(this,false);
+ if (windowHandle())
+ windowHandle()->setMouseGrabEnabled(false);
qt_mouseGrb = 0;
}
}
@@ -374,16 +382,24 @@ void QWidget::grabKeyboard()
{
if (keyboardGrb)
keyboardGrb->releaseKeyboard();
- // XXX
- //qwsDisplay()->grabKeyboard(this, true);
+ if (windowHandle())
+ windowHandle()->setKeyboardGrabEnabled(true);
keyboardGrb = this;
}
+bool QWidgetPrivate::stealKeyboardGrab(bool grab)
+{
+ // This is like a combination of grab/releaseKeyboard() but with error
+ // checking and it has no effect on the result of keyboardGrabber().
+ Q_Q(QWidget);
+ return q->windowHandle() ? q->windowHandle()->setKeyboardGrabEnabled(grab) : false;
+}
+
void QWidget::releaseKeyboard()
{
if (keyboardGrb == this) {
- // XXX
- //qwsDisplay()->grabKeyboard(this, false);
+ if (windowHandle())
+ windowHandle()->setKeyboardGrabEnabled(false);
keyboardGrb = 0;
}
}
diff --git a/src/widgets/kernel/qwidgetwindow_qpa.cpp b/src/widgets/kernel/qwidgetwindow_qpa.cpp
index 38156d30e0..dbb8112e43 100644
--- a/src/widgets/kernel/qwidgetwindow_qpa.cpp
+++ b/src/widgets/kernel/qwidgetwindow_qpa.cpp
@@ -49,9 +49,9 @@ QT_BEGIN_NAMESPACE
QWidget *qt_button_down = 0; // widget got last button-down
// popup control
-static QWidget *qt_popup_down = 0; // popup that contains the pressed widget
+QWidget *qt_popup_down = 0; // popup that contains the pressed widget
extern int openPopupCount;
-static bool replayPopupMouseEvent = false;
+bool qt_replay_popup_mouse_event = false;
extern bool qt_try_modal(QWidget *widget, QEvent::Type type);
QWidgetWindow::QWidgetWindow(QWidget *widget)
@@ -155,7 +155,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
if (popup->isEnabled()) {
// deliver event
- replayPopupMouseEvent = false;
+ qt_replay_popup_mouse_event = false;
QWidget *receiver = popup;
QPoint widgetPos = mapped;
if (qt_button_down)
@@ -181,10 +181,10 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
}
if (qApp->activePopupWidget() != activePopupWidget
- && replayPopupMouseEvent) {
+ && qt_replay_popup_mouse_event) {
if (m_widget->windowType() != Qt::Popup)
qt_button_down = 0;
- replayPopupMouseEvent = false;
+ qt_replay_popup_mouse_event = false;
} else if (event->type() == QEvent::MouseButtonPress
&& event->button() == Qt::RightButton
&& (openPopupCount == oldOpenPopupCount)) {