QWidget *qt_mouseGrb = 0;
static QWidget *keyboardGrb = 0;
+static inline QWindow *grabberWindow(const QWidget *w)
+{
+ QWindow *window = w->windowHandle();
+ if (!window)
+ if (const QWidget *nativeParent = w->nativeParentWidget())
+ window = nativeParent->windowHandle();
+ return window;
+}
+
void QWidget::grabMouse()
{
if (qt_mouseGrb)
qt_mouseGrb->releaseMouse();
- if (windowHandle())
- windowHandle()->setMouseGrabEnabled(true);
+ if (QWindow *window = grabberWindow(this))
+ window->setMouseGrabEnabled(true);
qt_mouseGrb = this;
qt_pressGrab = 0;
void QWidget::grabMouse(const QCursor &cursor)
{
Q_UNUSED(cursor);
-
- if (qt_mouseGrb)
- qt_mouseGrb->releaseMouse();
-
- if (windowHandle())
- windowHandle()->setMouseGrabEnabled(true);
-
- qt_mouseGrb = this;
- qt_pressGrab = 0;
+ grabMouse();
}
#endif
// 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;
+ QWindow *window = grabberWindow(q);
+ return window ? window->setMouseGrabEnabled(grab) : false;
}
void QWidget::releaseMouse()
{
if (qt_mouseGrb == this) {
- if (windowHandle())
- windowHandle()->setMouseGrabEnabled(false);
+ if (QWindow *window = grabberWindow(this))
+ window->setMouseGrabEnabled(false);
qt_mouseGrb = 0;
}
}
{
if (keyboardGrb)
keyboardGrb->releaseKeyboard();
- if (windowHandle())
- windowHandle()->setKeyboardGrabEnabled(true);
+ if (QWindow *window = grabberWindow(this))
+ window->setKeyboardGrabEnabled(true);
keyboardGrb = this;
}
// 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;
+ QWindow *window = grabberWindow(q);
+ return window ? window->setKeyboardGrabEnabled(grab) : false;
}
void QWidget::releaseKeyboard()
{
if (keyboardGrb == this) {
- if (windowHandle())
- windowHandle()->setKeyboardGrabEnabled(false);
+ if (QWindow *window = grabberWindow(this))
+ window->setKeyboardGrabEnabled(false);
keyboardGrb = 0;
}
}
void nativeChildFocus();
void grab();
+ void grabMouse();
void touchEventSynthesizedMouseEvent();
}
}
+/* grabMouse() tests whether mouse grab for a widget without window handle works.
+ * It creates a top level widget with another nested widget inside. The inner widget grabs
+ * the mouse and a series of mouse presses moving over the top level's window is simulated.
+ * Only the inner widget should receive events. */
+
+static inline QString mouseEventLogEntry(const QString &objectName, QEvent::Type t, const QPoint &p, Qt::MouseButtons b)
+{
+ QString result;
+ QDebug(&result).nospace() << objectName << " Mouse event " << t << " at " << p << " buttons " << b;
+ return result;
+}
+
+class GrabLoggerWidget : public QWidget {
+public:
+ explicit GrabLoggerWidget(QStringList *log, QWidget *parent = 0) : QWidget(parent), m_log(log) {}
+
+protected:
+ bool event(QEvent *e)
+ {
+ switch (e->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonRelease: {
+ QMouseEvent *me = static_cast<QMouseEvent *>(e);
+ m_log->push_back(mouseEventLogEntry(objectName(), me->type(), me->pos(), me->buttons()));
+ me->accept();
+ return true;
+ }
+ default:
+ break;
+ }
+ return QWidget::event(e);
+ }
+private:
+ QStringList *m_log;
+};
+
+void tst_QWidget::grabMouse()
+{
+ QStringList log;
+ GrabLoggerWidget w(&log);
+ w.setObjectName(QLatin1String("tst_qwidget_grabMouse"));
+ w.setWindowTitle(w.objectName());
+ QLayout *layout = new QVBoxLayout(&w);
+ layout->setMargin(50);
+ GrabLoggerWidget *grabber = new GrabLoggerWidget(&log, &w);
+ const QString grabberObjectName = QLatin1String("tst_qwidget_grabMouse_grabber");
+ grabber->setObjectName(grabberObjectName);
+ grabber->setMinimumSize(100, 100);
+ layout->addWidget(grabber);
+ w.show();
+ qApp->setActiveWindow(&w);
+ QVERIFY(QTest::qWaitForWindowActive(&w));
+
+ QStringList expectedLog;
+ grabber->grabMouse();
+ QPoint mousePos = QPoint(w.width() / 2, 10);
+ const int step = w.height() / 5;
+ for ( ; mousePos.y() < w.height() ; mousePos.ry() += step) {
+ QTest::mouseClick(w.windowHandle(), Qt::LeftButton, 0, mousePos);
+ // Events should go to the grabber child using its coordinates.
+ const QPoint expectedPos = grabber->mapFromParent(mousePos);
+ expectedLog.push_back(mouseEventLogEntry(grabberObjectName, QEvent::MouseButtonPress, expectedPos, Qt::LeftButton));
+ expectedLog.push_back(mouseEventLogEntry(grabberObjectName, QEvent::MouseButtonRelease, expectedPos, Qt::NoButton));
+ }
+ grabber->releaseMouse();
+ QCOMPARE(log, expectedLog);
+}
+
class TouchMouseWidget : public QWidget {
public:
explicit TouchMouseWidget(QWidget *parent = 0)