1
/****************************************************************************
3
** Copyright (C) 2016 The Qt Company Ltd.
4
** Contact: https://www.qt.io/licensing/
6
** This file is part of the test suite of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and The Qt Company. For licensing terms
14
** and conditions see https://www.qt.io/terms-conditions. For further
15
** information use the contact form at https://www.qt.io/contact-us.
17
** GNU General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU
19
** General Public License version 3 as published by the Free Software
20
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21
** included in the packaging of this file. Please review the following
22
** information to ensure the GNU General Public License requirements will
23
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
27
****************************************************************************/
29
#include <QApplication>
31
#include <QMainWindow>
33
#include <QPlainTextEdit>
37
#include <QGridLayout>
38
#include <QVBoxLayout>
39
#include <QMessageBox>
41
#include <QPushButton>
47
// Compiles with Qt 4.8 and Qt 5.
49
class MainWindow : public QMainWindow
55
bool eventFilter(QObject *, QEvent *);
58
void showModalDialog();
59
void mouseGrabToggled(bool);
60
void delayedMouseGrab();
61
void grabMouseWindowToggled(bool);
62
void delayedMouseWindowGrab();
63
void keyboardGrabToggled(bool);
64
void grabKeyboardWindowToggled(bool);
65
void forceNativeWidgets();
68
void toggleMouseWidgetGrab(QWidget *w, bool on);
69
void toggleKeyboardWidgetGrab(QWidget *w, bool on);
71
int m_mouseEventCount;
72
int m_enterLeaveEventCount;
73
QPlainTextEdit *m_logEdit;
74
QCheckBox *m_grabMouseCheckBox;
75
QCheckBox *m_grabMouseWindowCheckBox;
76
QCheckBox *m_grabKeyboardCheckBox;
77
QCheckBox *m_grabKeyboardWindowCheckBox;
78
QPushButton *m_forceNativeButton;
80
QString m_lastMouseMoveEvent;
83
class ClickableLabel : public QLabel
87
explicit ClickableLabel(const QString &text, QWidget *parent = 0) : QLabel(text, parent) {}
93
void mousePressEvent(QMouseEvent *ev)
96
QLabel::mousePressEvent(ev);
100
static const char testCasesC[] =
101
"- Drag a scrollbar, move mouse out of the window. The scrollbar should still react.\n\n"
102
"- Press mouse inside window, move outside while pressing the button. Mouse events"
103
" should be reported until the button is released.\n\n"
104
"- 'Show modal dialog on press' opens a modal dialog on mouse press. This should not lock up.\n\n"
105
"- Check the 'Grab Mouse' box. Only the checkbox should then receive mouse move events.\n\n"
106
"- Open popup menu. Mouse events should all go to popup menu while it is visible.\n\n"
107
"- Click delayed grab and then open popup immediately. Wait for Grab checkbox to be marked. "
108
"Click on popup menu to close it. Mouse events should be going to Grab checkbox. "
109
"Click on Grab checkbox to clear it. UI should respond normally after that. \n\n"
112
MainWindow::MainWindow()
113
: m_mouseEventCount(0)
114
, m_enterLeaveEventCount(0)
115
, m_logEdit(new QPlainTextEdit(this))
116
, m_grabMouseCheckBox(new QCheckBox(QLatin1String("Grab Mouse")))
117
, m_grabMouseWindowCheckBox(new QCheckBox(QLatin1String("Grab Mouse Window Ctrl+W")))
118
, m_grabKeyboardCheckBox(new QCheckBox(QLatin1String("Grab Keyboard")))
119
, m_grabKeyboardWindowCheckBox(new QCheckBox(QLatin1String("Grab Keyboard Window")))
120
, m_forceNativeButton(new QPushButton(QLatin1String("Force native widgets")))
122
setObjectName(QLatin1String("MainWindow"));
123
setMinimumWidth(800);
124
setWindowTitle(QString::fromLatin1("Manual Grab Test %1").arg(QLatin1String(QT_VERSION_STR)));
126
QMenu *fileMenu = menuBar()->addMenu(QLatin1String("File"));
127
fileMenu->setObjectName("FileMenu");
128
QAction *quit = fileMenu->addAction(QLatin1String("Quit"));
129
quit->setShortcut(QKeySequence::Quit);
130
connect(quit, SIGNAL(triggered()), this, SLOT(close()));
132
QMenu *editMenu = menuBar()->addMenu(QLatin1String("Edit"));
133
editMenu->setObjectName("EditMenu");
134
QAction *clearLog = editMenu->addAction(QLatin1String("Clear Log"));
135
connect(clearLog, SIGNAL(triggered()), m_logEdit, SLOT(clear()));
137
QWidget *w = new QWidget(this);
138
w->setObjectName(QLatin1String("CentralWidget"));
139
QVBoxLayout *layout = new QVBoxLayout(w);
140
QPlainTextEdit *instructions = new QPlainTextEdit(this);
141
instructions->setObjectName(QLatin1String("InstructionsEdit"));
142
instructions->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
143
instructions->setPlainText(QLatin1String(testCasesC));
144
instructions->setReadOnly(true);
145
layout->addWidget(instructions);
148
QGridLayout *controlLayout = new QGridLayout;
149
layout->addLayout(controlLayout);
150
QPushButton *modalDialogButton = new QPushButton("Show modal dialog on release");
151
modalDialogButton->setObjectName(QLatin1String("ModalDialogButton"));
152
connect(modalDialogButton, SIGNAL(clicked()), this, SLOT(showModalDialog()));
153
controlLayout->addWidget(modalDialogButton, row, 0);
154
ClickableLabel *modalDialogLabel = new ClickableLabel("Show modal dialog on press");
155
modalDialogLabel->setObjectName(QLatin1String("ModalDialogLabel"));
156
controlLayout->addWidget(modalDialogLabel, row, 1);
157
connect(modalDialogLabel, SIGNAL(pressed()), this, SLOT(showModalDialog()));
160
m_grabMouseCheckBox->setObjectName(QLatin1String("GrabCheckBox"));
161
connect(m_grabMouseCheckBox, SIGNAL(toggled(bool)), this, SLOT(mouseGrabToggled(bool)));
162
controlLayout->addWidget(m_grabMouseCheckBox, row, 0);
163
QPushButton *delayedGrabButton = new QPushButton("Delayed grab");
164
delayedGrabButton->setObjectName(QLatin1String("DelayedGrabButton"));
165
connect(delayedGrabButton, SIGNAL(clicked()), this, SLOT(delayedMouseGrab()));
166
controlLayout->addWidget(delayedGrabButton, row, 1);
169
m_grabMouseWindowCheckBox->setObjectName(QLatin1String("GrabWindowCheckBox"));
170
m_grabMouseWindowCheckBox->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_W));
171
connect(m_grabMouseWindowCheckBox, SIGNAL(toggled(bool)), this, SLOT(grabMouseWindowToggled(bool)));
172
controlLayout->addWidget(m_grabMouseWindowCheckBox, row, 0);
173
QPushButton *delayedWindowGrabButton = new QPushButton("Delayed window grab");
174
delayedWindowGrabButton->setObjectName(QLatin1String("DelayedWindowGrabButton"));
175
connect(delayedWindowGrabButton, SIGNAL(clicked()), this, SLOT(delayedMouseWindowGrab()));
176
controlLayout->addWidget(delayedWindowGrabButton, row, 1);
179
m_grabKeyboardCheckBox->setObjectName(QLatin1String("GrabKeyboardBox"));
180
connect(m_grabKeyboardCheckBox, SIGNAL(toggled(bool)), this, SLOT(keyboardGrabToggled(bool)));
181
controlLayout->addWidget(m_grabKeyboardCheckBox, row, 0);
182
m_grabKeyboardWindowCheckBox->setObjectName(QLatin1String("GrabKeyboardWindowBox"));
183
connect(m_grabKeyboardWindowCheckBox, SIGNAL(toggled(bool)), this, SLOT(grabKeyboardWindowToggled(bool)));
184
controlLayout->addWidget(m_grabKeyboardWindowCheckBox, row, 1);
187
QComboBox *combo = new QComboBox;
188
combo->addItems(QStringList() << QLatin1String("Popup test 1") << QLatin1String("Popup test 2"));
189
controlLayout->addWidget(combo, row, 0);
191
QPushButton *popupMenuButton = new QPushButton("Popup menu");
192
popupMenuButton->setObjectName(QLatin1String("PopupMenuButton"));
193
QMenu *popupMenu = new QMenu(this);
194
popupMenu->setObjectName(QLatin1String("PopupMenu"));
195
popupMenu->addAction(tr("&First Item"));
196
popupMenu->addAction(tr("&Second Item"));
197
popupMenu->addAction(tr("&Third Item"));
198
popupMenu->addAction(tr("F&ourth Item"));
199
popupMenuButton->setMenu(popupMenu);
200
controlLayout->addWidget(popupMenuButton, row, 1);
203
m_forceNativeButton->setObjectName("ForceNativeWidgetsButton");
204
controlLayout->addWidget(m_forceNativeButton, row, 0);
205
connect(m_forceNativeButton, SIGNAL(clicked()), this, SLOT(forceNativeWidgets()));
208
QLineEdit *lineEdit = new QLineEdit(this);
209
lineEdit->setObjectName(QLatin1String("LineEdit"));
210
controlLayout->addWidget(lineEdit, row, 0, 1, 2);
212
m_logEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
213
m_logEdit->setObjectName(QLatin1String("LogEdit"));
214
layout->addWidget(m_logEdit);
217
qApp->installEventFilter(this);
220
bool MainWindow::eventFilter(QObject *o, QEvent *e)
222
if (o->isWidgetType()) {
224
case QEvent::Enter: {
226
QDebug debug(&message);
227
#if QT_VERSION >= 0x050000
228
const QEnterEvent *ee = static_cast<QEnterEvent *>(e);
229
debug.nospace() << '#' << m_enterLeaveEventCount++ << " Enter for " << o->objectName()
230
<< " at " << ee->localPos() << " global: " << ee->globalPos();
232
debug.nospace() << '#' << m_enterLeaveEventCount++ << " Enter for " << o->objectName();
234
m_logEdit->appendPlainText(message);
237
case QEvent::Leave: {
239
QDebug debug(&message);
240
debug.nospace() << '#' << m_enterLeaveEventCount++ << " Leave for " << o->objectName();
241
m_logEdit->appendPlainText(message);
244
case QEvent::MouseButtonPress:
245
case QEvent::MouseButtonRelease: {
246
const QMouseEvent *me = static_cast<QMouseEvent *>(e);
248
QDebug debug = QDebug(&message).nospace();
249
debug << '#' << m_mouseEventCount++ << ' ';
250
if (e->type() == QEvent::MouseButtonPress) {
251
if (me->buttons() & Qt::LeftButton)
252
debug << "Left button press";
253
if (me->buttons() & Qt::MiddleButton)
254
debug << "Middle button press";
255
if (me->buttons() & Qt::RightButton)
256
debug << "Right button press";
258
debug << "Button release";
260
debug << " on " << o->objectName() << " Mousegrabber " << QWidget::mouseGrabber();
261
m_logEdit->appendPlainText(message);
264
case QEvent::MouseMove: {
265
const QMouseEvent *me = static_cast<const QMouseEvent *>(e);
266
const QWidget *widgetUnderMouse = QApplication::widgetAt(me->globalPos());
268
QDebug d = QDebug(&message).nospace();
269
d << " Mouse move reported for " << o->objectName();
270
if (widgetUnderMouse) {
271
d << " over " << widgetUnderMouse;
275
d << " mouse grabber " << QWidget::mouseGrabber();
276
// Compress mouse move event logging.
277
if (message != m_lastMouseMoveEvent) {
278
m_lastMouseMoveEvent = message;
279
m_logEdit->appendPlainText(QString::fromLatin1("#%1 %2").arg(m_mouseEventCount++).arg(message));
283
case QEvent::KeyRelease:
284
case QEvent::KeyPress: {
285
const QKeyEvent *ke = static_cast<const QKeyEvent *>(e);
287
QDebug d = QDebug(&message).nospace();
288
d << (e->type() == QEvent::KeyPress ? "Key press" : "Key release")
289
<< ' ' << ke->text() << " on " << o << " key grabber " << QWidget::keyboardGrabber();
290
m_logEdit->appendPlainText(message);
297
return QMainWindow::eventFilter(o ,e);
300
void MainWindow::showModalDialog()
302
QMessageBox::information(this, QLatin1String("Information"), QLatin1String("Modal Dialog"));
305
void MainWindow::toggleMouseWidgetGrab(QWidget *w, bool on)
308
m_logEdit->appendPlainText(w->objectName() + QLatin1String(" grabbed mouse."));
312
m_logEdit->appendPlainText(w->objectName() + QLatin1String(" released mouse."));
316
void MainWindow::toggleKeyboardWidgetGrab(QWidget *w, bool on)
319
m_logEdit->appendPlainText(w->objectName() + QLatin1String(" grabbed keyboard."));
322
w->releaseKeyboard();
323
m_logEdit->appendPlainText(w->objectName() + QLatin1String(" released keyboard."));
327
void MainWindow::mouseGrabToggled(bool g)
329
toggleMouseWidgetGrab(m_grabMouseCheckBox, g);
332
void MainWindow::delayedMouseGrab()
334
QTimer::singleShot(2000, m_grabMouseCheckBox, SLOT(animateClick()));
337
void MainWindow::grabMouseWindowToggled(bool g)
339
toggleMouseWidgetGrab(this, g);
342
void MainWindow::delayedMouseWindowGrab()
344
QTimer::singleShot(2000, m_grabMouseWindowCheckBox, SLOT(animateClick()));
347
void MainWindow::keyboardGrabToggled(bool g)
349
toggleKeyboardWidgetGrab(m_grabKeyboardCheckBox, g);
352
void MainWindow::grabKeyboardWindowToggled(bool g)
354
toggleKeyboardWidgetGrab(this, g);
357
void MainWindow::forceNativeWidgets()
359
const WId platformWid = m_forceNativeButton->winId();
360
#if QT_VERSION < 0x050000 && defined(Q_OS_WIN)
361
const quintptr wid = quintptr(platformWid); // HWND on Qt 4.8/Windows.
363
const WId wid = platformWid;
365
m_logEdit->appendPlainText(QString::fromLatin1("Created native widget %1").arg(wid));
366
m_forceNativeButton->setEnabled(false);
367
m_forceNativeButton->setText(QLatin1String("Native widgets created"));
370
int main(int argc, char *argv[])
372
QApplication a(argc, argv);