QtBase  v6.3.1
tst_qwidget.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
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.
16 **
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.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "../../../shared/highdpi.h"
30 
31 #include <qboxlayout.h>
32 #include <qapplication.h>
33 #include <qbitmap.h>
34 #include <qdebug.h>
35 #include <qeventloop.h>
36 #include <qlabel.h>
37 #include <qlayout.h>
38 #include <qlineedit.h>
39 #include <qlistview.h>
40 #include <qmessagebox.h>
41 #include <qpainter.h>
42 #include <qpoint.h>
43 #include <qpushbutton.h>
44 #include <qstyle.h>
45 #include <qwidget.h>
46 #include <qstylefactory.h>
47 #include <private/qwidget_p.h>
48 #include <private/qwidgetrepaintmanager_p.h>
49 #include <private/qapplication_p.h>
50 #include <private/qhighdpiscaling_p.h>
51 #include <qcalendarwidget.h>
52 #include <qmainwindow.h>
53 #include <qdockwidget.h>
54 #include <qrandom.h>
55 #include <qsignalspy.h>
56 #include <qstylehints.h>
57 #include <qtoolbar.h>
58 #include <qtoolbutton.h>
59 #include <QtCore/qoperatingsystemversion.h>
60 #include <QtGui/qpaintengine.h>
61 #include <QtGui/qpainterpath.h>
62 #include <QtGui/qbackingstore.h>
63 #include <QtGui/qguiapplication.h>
64 #include <QtGui/qpa/qplatformwindow.h>
65 #include <QtGui/qscreen.h>
66 #include <qmenubar.h>
67 #include <qcompleter.h>
68 #include <qtableview.h>
69 #include <qtreewidget.h>
71 #include <qproxystyle.h>
72 #include <QtWidgets/QGraphicsView>
73 #include <QtWidgets/QGraphicsProxyWidget>
74 #include <QtGui/qwindow.h>
75 #include <qtimer.h>
76 #include <QtWidgets/QDoubleSpinBox>
77 
78 #if defined(Q_OS_MACOS)
79 #include "tst_qwidget_mac_helpers.h" // Abstract the ObjC stuff out so not everyone must run an ObjC++ compile.
80 #endif
81 
82 #include <QtTest/QTest>
83 #include <QtTest/private/qtesthelpers_p.h>
84 
85 using namespace QTestPrivate;
86 
87 #if defined(Q_OS_WIN)
88 # include <QtCore/qt_windows.h>
89 # include <QtGui/private/qguiapplication_p.h>
90 #include <qpa/qplatformnativeinterface.h>
91 #include <qpa/qplatformintegration.h>
92 
93 #include <algorithm>
94 
95 static HWND winHandleOf(const QWidget *w)
96 {
97  static QPlatformNativeInterface *nativeInterface
99  if (void *handle = nativeInterface->nativeResourceForWindow("handle", w->window()->windowHandle()))
100  return reinterpret_cast<HWND>(handle);
101  qWarning() << "Cannot obtain native handle for " << w;
102  return nullptr;
103 }
104 
105 # define Q_CHECK_PAINTEVENTS \
106  if (::SwitchDesktop(::GetThreadDesktop(::GetCurrentThreadId())) == 0) \
107  QSKIP("desktop is not visible, this test would fail");
108 
109 #else // Q_OS_WIN
110 # define Q_CHECK_PAINTEVENTS
111 #endif
112 
113 #ifdef Q_OS_MACOS
114 #include <Security/AuthSession.h>
115 bool macHasAccessToWindowsServer()
116 {
117  SecuritySessionId mySession;
118  SessionAttributeBits sessionInfo;
119  SessionGetInfo(callerSecuritySession, &mySession, &sessionInfo);
120  return (sessionInfo & sessionHasGraphicAccess);
121 }
122 #endif
123 
124 #if defined(Q_OS_WIN)
125 static inline void setWindowsAnimationsEnabled(bool enabled)
126 {
127  ANIMATIONINFO animation = { sizeof(ANIMATIONINFO), enabled };
128  SystemParametersInfo(SPI_SETANIMATION, 0, &animation, 0);
129 }
130 
131 static inline bool windowsAnimationsEnabled()
132 {
133  ANIMATIONINFO animation = { sizeof(ANIMATIONINFO), 0 };
134  SystemParametersInfo(SPI_GETANIMATION, 0, &animation, 0);
135  return animation.iMinAnimate;
136 }
137 #else // Q_OS_WIN
138 inline void setWindowsAnimationsEnabled(bool) {}
139 static inline bool windowsAnimationsEnabled() { return false; }
140 #endif // !Q_OS_WIN
141 
142 template <class T>
143 static QByteArray msgComparisonFailed(T v1, const char *op, T v2)
144 {
145  QString s;
146  QDebug(&s) << v1 << op << v2;
147  return s.toLocal8Bit();
148 }
149 
150 Q_LOGGING_CATEGORY(lcTests, "qt.widgets.tests")
151 
152 class tst_QWidget : public QObject
153 {
154  Q_OBJECT
155 
156 public:
157  tst_QWidget();
158  virtual ~tst_QWidget();
159 
160 public slots:
161  void initTestCase();
162  void cleanup();
163 private slots:
164  void addActionOverloads();
165  void getSetCheck();
166  void fontPropagation();
167  void fontPropagation2();
168  void fontPropagation3();
169  void fontPropagationDynamic();
170  void palettePropagation();
171  void palettePropagation2();
172  void palettePropagationDynamic();
173  void enabledPropagation();
174  void ignoreKeyEventsWhenDisabled_QTBUG27417();
175  void properTabHandlingWhenDisabled_QTBUG27417();
176 #if QT_CONFIG(draganddrop)
177  void acceptDropsPropagation();
178 #endif
179  void isEnabledTo();
180  void visible();
181  void visible_setWindowOpacity();
182  void isVisibleTo();
183  void isHidden();
184  void fonts();
185  void mapFromAndTo_data();
186  void mapFromAndTo();
187  void focusChainOnHide();
188  void focusChainOnReparent();
189  void defaultTabOrder();
190  void reverseTabOrder();
191  void tabOrderWithProxy();
192  void tabOrderWithProxyDisabled();
193  void tabOrderWithCompoundWidgets();
194  void tabOrderWithCompoundWidgetsNoFocusPolicy();
195  void tabOrderNoChange();
196  void tabOrderNoChange2();
197  void appFocusWidgetWithFocusProxyLater();
198  void appFocusWidgetWhenLosingFocusProxy();
199  void explicitTabOrderWithComplexWidget();
200  void explicitTabOrderWithSpinBox_QTBUG81097();
201 #if defined(Q_OS_WIN)
202  void activation();
203 #endif
204  void reparent();
205  void setScreen();
206  void windowState();
207  void showMaximized();
208  void showFullScreen();
209  void showMinimized();
210  void showMinimizedKeepsFocus();
211  void icon();
212  void hideWhenFocusWidgetIsChild();
213  void normalGeometry();
214  void setGeometry();
215  void setGeometryHidden();
216  void windowOpacity();
217  void raise();
218  void lower();
219  void stackUnder();
220  void testContentsPropagation();
221  void saveRestoreGeometry();
222  void restoreVersion1Geometry_data();
223  void restoreVersion1Geometry();
224 
225  void widgetAt();
226 #ifdef Q_OS_MACOS
227  void setMask();
228 #endif
229  void optimizedResizeMove();
230  void optimizedResize_topLevel();
231  void resizeEvent();
232  void task110173();
233 
234  void testDeletionInEventHandlers();
235 
236  void childDeletesItsSibling();
237 
238  void setMinimumSize();
239  void setMaximumSize();
240  void setFixedSize();
241 
242  void ensureCreated();
243  void createAndDestroy();
244  void winIdChangeEvent();
245  void persistentWinId();
246  void showNativeChild();
247  void closeAndShowNativeChild();
248  void closeAndShowWithNativeChild();
249  void transientParent();
250  void qobject_castInDestroyedSlot();
251 
252  void showHideEvent_data();
253  void showHideEvent();
254  void showHideEventWhileMinimize();
255  void showHideChildrenWhileMinimize_QTBUG50589();
256 
257  void lostUpdatesOnHide();
258 
259  void update();
260  void isOpaque();
261 
262 #ifndef Q_OS_MACOS
263  void scroll();
264  void scrollNativeChildren();
265 #endif
266 
267  // tests QWidget::setGeometry()
268  void setWindowGeometry_data();
269  void setWindowGeometry();
270 
271  // tests QWidget::move() and resize()
272  void windowMoveResize_data();
273  void windowMoveResize();
274 
275  void moveChild_data();
276  void moveChild();
277  void showAndMoveChild();
278 
279  void subtractOpaqueSiblings();
280 
281 #if defined (Q_OS_WIN)
282  void setGeometry_win();
283 #endif
284 
285  void setLocale();
286  void propagateLocale();
287  void deleteStyle();
288  void multipleToplevelFocusCheck();
289  void setFocus();
290 #ifndef QT_NO_CURSOR
291  void setCursor();
292 #endif
293  void setToolTip();
294  void testWindowIconChangeEventPropagation();
295 
296  void minAndMaxSizeWithX11BypassWindowManagerHint();
297  void showHideShowX11();
298  void clean_qt_x11_enforce_cursor();
299 
300  void childEvents();
301  void render();
302  void renderChildFillsBackground();
303  void renderTargetOffset();
304  void renderInvisible();
305  void renderWithPainter();
306  void render_task188133();
307  void render_task211796();
308  void render_task217815();
309  void render_windowOpacity();
310  void render_systemClip();
311  void render_systemClip2_data();
312  void render_systemClip2();
313  void render_systemClip3_data();
314  void render_systemClip3();
315  void render_task252837();
316  void render_worldTransform();
317 
318  void setContentsMargins();
319 
320  void moveWindowInShowEvent_data();
321  void moveWindowInShowEvent();
322 
323  void repaintWhenChildDeleted();
324  void hideOpaqueChildWhileHidden();
325  void updateWhileMinimized();
326  void alienWidgets();
327  void nativeWindowPosition_data();
328  void nativeWindowPosition();
329  void adjustSize();
330  void adjustSize_data();
331  void updateGeometry();
332  void updateGeometry_data();
333  void sendUpdateRequestImmediately();
334  void doubleRepaint();
335  void resizeInPaintEvent();
336  void opaqueChildren();
337 
338  void setMaskInResizeEvent();
339  void moveInResizeEvent();
340 
341 #ifdef QT_BUILD_INTERNAL
342  void immediateRepaintAfterInvalidateBackingStore();
343 #endif
344 
345  void effectiveWinId();
346  void effectiveWinId2();
347  void customDpi();
348  void customDpiProperty();
349 
350  void quitOnCloseAttribute();
351  void moveRect();
352 
353 #if defined (Q_OS_WIN)
354  void gdiPainting();
355  void paintOnScreenPossible();
356 #endif
357  void reparentStaticWidget();
358  void QTBUG6883_reparentStaticWidget2();
359 
360  void translucentWidget();
361 
362  void setClearAndResizeMask();
363  void maskedUpdate();
364 #ifndef QT_NO_CURSOR
365  void syntheticEnterLeave();
366  void enterLeaveOnWindowShowHide_data();
367  void enterLeaveOnWindowShowHide();
368  void taskQTBUG_4055_sendSyntheticEnterLeave();
369  void underMouse();
370  void taskQTBUG_27643_enterEvents();
371 #endif
372  void windowFlags();
373  void initialPosForDontShowOnScreenWidgets();
374  void updateOnDestroyedSignal();
375  void toplevelLineEditFocus();
376 
377  void focusWidget_task254563();
378  void rectOutsideCoordinatesLimit_task144779();
379  void setGraphicsEffect();
380  void render_graphicsEffect_data();
381  void render_graphicsEffect();
382 
383 #ifdef QT_BUILD_INTERNAL
384  void destroyBackingStore();
385 #endif
386 
387  void activateWindow();
388 
389  void openModal_taskQTBUG_5804();
390 
391  void focusProxy();
392  void focusProxyAndInputMethods();
393 #ifdef QT_BUILD_INTERNAL
394  void scrollWithoutBackingStore();
395 #endif
396 
397  void taskQTBUG_7532_tabOrderWithFocusProxy();
398  void movedAndResizedAttributes();
399  void childAt();
400 #ifdef Q_OS_MACOS
401  void taskQTBUG_11373();
402 #endif
403  void taskQTBUG_17333_ResizeInfiniteRecursion();
404 
405  void nativeChildFocus();
406  void grab();
407  void grabMouse();
408  void grabKeyboard();
409 
410  void touchEventSynthesizedMouseEvent();
411  void touchUpdateOnNewTouch();
412  void touchCancel();
413  void touchEventsForGesturePendingWidgets();
414 
415  void styleSheetPropagation();
416 
417  void destroyedSignal();
418 
419  void keyboardModifiers();
420  void mouseDoubleClickBubbling_QTBUG29680();
421  void largerThanScreen_QTBUG30142();
422 
423  void resizeStaticContentsChildWidget_QTBUG35282();
424 
425  void qmlSetParentHelper();
426 
427  void testForOutsideWSRangeFlag();
428 
429  void tabletTracking();
430 
431  void closeEvent();
432  void closeWithChildWindow();
433 
434  void winIdAfterClose();
435  void receivesLanguageChangeEvent();
436  void receivesApplicationFontChangeEvent();
437  void receivesApplicationPaletteChangeEvent();
438  void deleteWindowInCloseEvent();
439  void quitOnClose();
440 
441  void setParentChangesFocus_data();
442  void setParentChangesFocus();
443 
444  void activateWhileModalHidden();
445 
446 #ifdef Q_OS_ANDROID
447  void showFullscreenAndroid();
448 #endif
449 
450 private:
451  const QString m_platform;
452  QSize m_testWidgetSize;
453  QPoint m_availableTopLeft;
454  QPoint m_safeCursorPos;
455  const bool m_windowsAnimationsEnabled;
456  QPointingDevice *m_touchScreen;
457  const int m_fuzz;
458 };
459 
460 // Testing get/set functions
461 void tst_QWidget::getSetCheck()
462 {
463  QWidget obj1;
464  QWidget child1(&obj1);
465  // QStyle * QWidget::style()
466  // void QWidget::setStyle(QStyle *)
468  obj1.setStyle(var1.data());
469  QCOMPARE(static_cast<QStyle *>(var1.data()), obj1.style());
470  obj1.setStyle(nullptr);
471  QVERIFY(var1.data() != obj1.style());
472  QVERIFY(obj1.style() != nullptr); // style can never be 0 for a widget
473 
474  const QRegularExpression negativeNotPossible(u"^.*Negative sizes \\(.*\\) are not possible$"_qs);
475  const QRegularExpression largestAllowedSize(u"^.*The largest allowed size is \\(.*\\)$"_qs);
476  // int QWidget::minimumWidth()
477  // void QWidget::setMinimumWidth(int)
478  obj1.setMinimumWidth(0);
479  QCOMPARE(obj1.minimumWidth(), 0);
480  QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
481  obj1.setMinimumWidth(INT_MIN);
482  QCOMPARE(obj1.minimumWidth(), 0); // A widgets width can never be less than 0
483  QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
484  obj1.setMinimumWidth(INT_MAX);
485 
486  child1.setMinimumWidth(0);
487  QCOMPARE(child1.minimumWidth(), 0);
488  QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
489  child1.setMinimumWidth(INT_MIN);
490  QCOMPARE(child1.minimumWidth(), 0); // A widgets width can never be less than 0
491  QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
492  child1.setMinimumWidth(INT_MAX);
493  QCOMPARE(child1.minimumWidth(), QWIDGETSIZE_MAX); // The largest minimum size should only be as big as the maximium
494 
495  // int QWidget::minimumHeight()
496  // void QWidget::setMinimumHeight(int)
497  obj1.setMinimumHeight(0);
498  QCOMPARE(obj1.minimumHeight(), 0);
499  QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
500  obj1.setMinimumHeight(INT_MIN);
501  QCOMPARE(obj1.minimumHeight(), 0); // A widgets height can never be less than 0
502  QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
503  obj1.setMinimumHeight(INT_MAX);
504 
505  child1.setMinimumHeight(0);
506  QCOMPARE(child1.minimumHeight(), 0);
507  QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
508  child1.setMinimumHeight(INT_MIN);
509  QCOMPARE(child1.minimumHeight(), 0); // A widgets height can never be less than 0
510  QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
511  child1.setMinimumHeight(INT_MAX);
512  QCOMPARE(child1.minimumHeight(), QWIDGETSIZE_MAX); // The largest minimum size should only be as big as the maximium
513 
514  // int QWidget::maximumWidth()
515  // void QWidget::setMaximumWidth(int)
516  obj1.setMaximumWidth(0);
517  QCOMPARE(obj1.maximumWidth(), 0);
518  QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
519  obj1.setMaximumWidth(INT_MIN);
520  QCOMPARE(obj1.maximumWidth(), 0); // A widgets width can never be less than 0
521  QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
522  obj1.setMaximumWidth(INT_MAX);
523  QCOMPARE(obj1.maximumWidth(), QWIDGETSIZE_MAX); // QWIDGETSIZE_MAX is the abs max, not INT_MAX
524 
525  // int QWidget::maximumHeight()
526  // void QWidget::setMaximumHeight(int)
527  obj1.setMaximumHeight(0);
528  QCOMPARE(obj1.maximumHeight(), 0);
529  QTest::ignoreMessage(QtWarningMsg, negativeNotPossible);
530  obj1.setMaximumHeight(INT_MIN);
531  QCOMPARE(obj1.maximumHeight(), 0); // A widgets height can never be less than 0
532  QTest::ignoreMessage(QtWarningMsg, largestAllowedSize);
533  obj1.setMaximumHeight(INT_MAX);
534  QCOMPARE(obj1.maximumHeight(), QWIDGETSIZE_MAX); // QWIDGETSIZE_MAX is the abs max, not INT_MAX
535 
536  // back to normal
537  obj1.setMinimumWidth(0);
538  obj1.setMinimumHeight(0);
539  obj1.setMaximumWidth(QWIDGETSIZE_MAX);
540  obj1.setMaximumHeight(QWIDGETSIZE_MAX);
541 
542  // const QPalette & QWidget::palette()
543  // void QWidget::setPalette(const QPalette &)
544  QPalette var6;
545  obj1.setPalette(var6);
546  QCOMPARE(var6, obj1.palette());
547  obj1.setPalette(QPalette());
548  QCOMPARE(QPalette(), obj1.palette());
549 
550  // const QFont & QWidget::font()
551  // void QWidget::setFont(const QFont &)
552  QFont var7;
553  obj1.setFont(var7);
554  QCOMPARE(var7, obj1.font());
555  obj1.setFont(QFont());
556  QCOMPARE(QFont(), obj1.font());
557 
558  // qreal QWidget::windowOpacity()
559  // void QWidget::setWindowOpacity(qreal)
560  obj1.setWindowOpacity(0.0);
561  QCOMPARE(0.0, obj1.windowOpacity());
562  obj1.setWindowOpacity(1.1);
563  QCOMPARE(1.0, obj1.windowOpacity()); // 1.0 is the fullest opacity possible
564 
565  // QWidget * QWidget::focusProxy()
566  // void QWidget::setFocusProxy(QWidget *)
567  {
568  QScopedPointer<QWidget> var9(new QWidget());
569  obj1.setFocusProxy(var9.data());
570  QCOMPARE(var9.data(), obj1.focusProxy());
571  obj1.setFocusProxy(nullptr);
572  QCOMPARE(nullptr, obj1.focusProxy());
573  }
574 
575  // const QRect & QWidget::geometry()
576  // void QWidget::setGeometry(const QRect &)
578  QRect var10(10, 10, 100, 100);
579  obj1.setGeometry(var10);
581  qDebug() << obj1.geometry();
582  QCOMPARE(var10, obj1.geometry());
583  obj1.setGeometry(QRect(0,0,0,0));
584  qDebug() << obj1.geometry();
585  QCOMPARE(QRect(0,0,0,0), obj1.geometry());
586 
587  // QLayout * QWidget::layout()
588  // void QWidget::setLayout(QLayout *)
590  obj1.setLayout(var11);
591  QCOMPARE(static_cast<QLayout *>(var11), obj1.layout());
592  QTest::ignoreMessage(QtWarningMsg, "QWidget::setLayout: Cannot set layout to 0");
593  obj1.setLayout(nullptr);
594  QCOMPARE(static_cast<QLayout *>(var11), obj1.layout()); // You cannot set a 0-pointer layout, that keeps the current
595  delete var11; // This will remove the layout from the widget
596  QCOMPARE(nullptr, obj1.layout());
597 
598  // bool QWidget::acceptDrops()
599  // void QWidget::setAcceptDrops(bool)
600  obj1.setAcceptDrops(false);
601  QCOMPARE(false, obj1.acceptDrops());
602  obj1.setAcceptDrops(true);
603  QCOMPARE(true, obj1.acceptDrops());
604 
605  // bool QWidget::autoFillBackground()
606  // void QWidget::setAutoFillBackground(bool)
607  obj1.setAutoFillBackground(false);
608  QCOMPARE(false, obj1.autoFillBackground());
609  obj1.setAutoFillBackground(true);
610  QCOMPARE(true, obj1.autoFillBackground());
611 
612  var1.reset();
613 #if defined (Q_OS_WIN)
614  obj1.setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
615  const HWND handle = reinterpret_cast<HWND>(obj1.winId()); // explicitly create window handle
616  QVERIFY(GetWindowLong(handle, GWL_STYLE) & LONG(WS_POPUP));
617 #endif
618 }
619 
621  : m_platform(QGuiApplication::platformName().toLower())
622  , m_safeCursorPos(0, 0)
623  , m_windowsAnimationsEnabled(windowsAnimationsEnabled())
624  , m_touchScreen(QTest::createTouchDevice())
625  , m_fuzz(int(QGuiApplication::primaryScreen()->devicePixelRatio()))
626 {
627  if (m_windowsAnimationsEnabled) // Disable animations which can interfere with screen grabbing in moveChild(), showAndMoveChild()
629  QFont font;
630  font.setBold(true);
631  font.setPointSize(42);
632  QApplication::setFont(font, "QPropagationTestWidget");
633 
634  QPalette palette;
635  palette.setColor(QPalette::ToolTipBase, QColor(12, 13, 14));
636  palette.setColor(QPalette::Text, QColor(21, 22, 23));
637  QApplication::setPalette(palette, "QPropagationTestWidget");
638 
640  qputenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "1");
641 }
642 
644 {
645  if (m_windowsAnimationsEnabled)
646  setWindowsAnimationsEnabled(m_windowsAnimationsEnabled);
647 
648  delete m_touchScreen;
649 }
650 
652 {
653  // Size of reference widget, 200 for < 2000, scale up for larger screens
654  // to avoid Windows warnings about minimum size for decorated windows.
655  int width = 200;
657  const QRect availableGeometry = screen->availableGeometry();
658  m_availableTopLeft = availableGeometry.topLeft();
659  // XCB: Determine "safe" cursor position at bottom/right corner of screen.
660  // Pushing the mouse rapidly to the top left corner can trigger KDE / KWin's
661  // "Present all Windows" (Ctrl+F9) feature also programmatically.
662  if (m_platform == QLatin1String("xcb"))
663  m_safeCursorPos = availableGeometry.bottomRight() - QPoint(40, 40);
664  const int screenWidth = screen->geometry().width();
665  if (screenWidth > 2000)
666  width = 100 * ((screenWidth + 500) / 1000);
667  m_testWidgetSize = QSize(width, width);
668 }
669 
671 {
673 }
674 
675 template <typename T>
677  T t;
678  operator const T() const { return t; }
679  operator T() { return t; }
680 };
681 
682 void testFunction0() {}
683 void testFunction1(bool) {}
684 
685 void tst_QWidget::addActionOverloads()
686 {
687  // almost exhaustive check of addAction() overloads:
688  // (text), (icon, text), (icon, text, shortcut), (text, shortcut)
689  // each with a good sample of ways to QObject::connect() to
690  // QAction::triggered(bool)
691  QWidget w;
692 
693  // don't just pass QString etc - that'd be too easy (think QStringBuilder)
696 
697  const auto check = [&](auto &...args) { // don't need to perfectly-forward, only lvalues passed
698  w.addAction(args...);
699 
700  w.addAction(args..., &w, SLOT(deleteLater()));
701  w.addAction(args..., &w, &QObject::deleteLater);
702  w.addAction(args..., testFunction0);
703  w.addAction(args..., &w, testFunction0);
704  w.addAction(args..., testFunction1);
705  w.addAction(args..., &w, testFunction1);
706  w.addAction(args..., [&](bool b) { w.setEnabled(b); });
707  w.addAction(args..., &w, [&](bool b) { w.setEnabled(b); });
708 
709  w.addAction(args..., &w, SLOT(deleteLater()), Qt::QueuedConnection);
710  w.addAction(args..., &w, &QObject::deleteLater, Qt::QueuedConnection);
711  // doesn't exist: w.addAction(args..., testFunction0, Qt::QueuedConnection);
712  w.addAction(args..., &w, testFunction0, Qt::QueuedConnection);
713  // doesn't exist: w.addAction(args..., testFunction1, Qt::QueuedConnection);
714  w.addAction(args..., &w, testFunction1, Qt::QueuedConnection);
715  // doesn't exist: w.addAction(args..., [&](bool b) { w.setEnabled(b); }, Qt::QueuedConnection);
716  w.addAction(args..., &w, [&](bool b) { w.setEnabled(b); }, Qt::QueuedConnection);
717  };
718  const auto check1 = [&](auto &arg, auto &...args) {
719  check(arg, args...);
720  check(std::as_const(arg), args...);
721  };
722  const auto check2 = [&](auto &arg1, auto &arg2, auto &...args) {
723  check1(arg1, arg2, args...);
724  check1(arg1, std::as_const(arg2), args...);
725  };
726  [[maybe_unused]]
727  const auto check3 = [&](auto &arg1, auto &arg2, auto &arg3) {
728  check2(arg1, arg2, arg3);
729  check2(arg1, arg2, std::as_const(arg3));
730  };
731 
732  check1(text);
733  check2(icon, text);
734 #ifndef QT_NO_SHORTCUT
736  check2(text, keySequence);
737  check3(icon, text, keySequence);
738 #endif
739 }
740 
741 void tst_QWidget::fontPropagation()
742 {
743  QScopedPointer<QWidget> testWidget(new QWidget);
744  testWidget->resize(m_testWidgetSize);
745  testWidget->setWindowTitle(__FUNCTION__);
746  centerOnScreen(testWidget.data());
747  testWidget->show();
748  QVERIFY(QTest::qWaitForWindowExposed(testWidget.data()));
749  QFont font = testWidget->font();
750  QWidget* childWidget = new QWidget( testWidget.data() );
751  childWidget->show();
752  QCOMPARE( font, childWidget->font() );
753 
754  font.setBold( true );
755  testWidget->setFont( font );
756  QCOMPARE( font, testWidget->font() );
757  QCOMPARE( font, childWidget->font() );
758 
759  QFont newFont = font;
760  newFont.setItalic( true );
761  childWidget->setFont( newFont );
762  QWidget* grandChildWidget = new QWidget( childWidget );
763  QCOMPARE( font, testWidget->font() );
764  QCOMPARE( newFont, grandChildWidget->font() );
765 
766  font.setUnderline( true );
767  testWidget->setFont( font );
768 
769  // the child and grand child should now have merged bold and
770  // underline
771  newFont.setUnderline( true );
772 
773  QCOMPARE( newFont, childWidget->font() );
774  QCOMPARE( newFont, grandChildWidget->font() );
775 
776  // make sure font propagation continues working after reparenting
777  font = testWidget->font();
778  font.setPointSize(font.pointSize() + 2);
779  testWidget->setFont(font);
780 
781  QWidget *one = new QWidget(testWidget.data());
782  QWidget *two = new QWidget(one);
783  QWidget *three = new QWidget(two);
784  QWidget *four = new QWidget(two);
785 
786  four->setParent(three);
787  four->move(QPoint(0,0));
788 
789  font.setPointSize(font.pointSize() + 2);
790  testWidget->setFont(font);
791 
792  QCOMPARE(testWidget->font(), one->font());
793  QCOMPARE(one->font(), two->font());
794  QCOMPARE(two->font(), three->font());
795  QCOMPARE(three->font(), four->font());
796 
797  QVERIFY(testWidget->testAttribute(Qt::WA_SetFont));
798  QVERIFY(! one->testAttribute(Qt::WA_SetFont));
799  QVERIFY(! two->testAttribute(Qt::WA_SetFont));
800  QVERIFY(! three->testAttribute(Qt::WA_SetFont));
801  QVERIFY(! four->testAttribute(Qt::WA_SetFont));
802 
803  font.setPointSize(font.pointSize() + 2);
804  one->setFont(font);
805 
806  QCOMPARE(one->font(), two->font());
807  QCOMPARE(two->font(), three->font());
808  QCOMPARE(three->font(), four->font());
809 
810  QVERIFY(one->testAttribute(Qt::WA_SetFont));
811  QVERIFY(! two->testAttribute(Qt::WA_SetFont));
812  QVERIFY(! three->testAttribute(Qt::WA_SetFont));
813  QVERIFY(! four->testAttribute(Qt::WA_SetFont));
814 
815  font.setPointSize(font.pointSize() + 2);
816  two->setFont(font);
817 
818  QCOMPARE(two->font(), three->font());
819  QCOMPARE(three->font(), four->font());
820 
821  QVERIFY(two->testAttribute(Qt::WA_SetFont));
822  QVERIFY(! three->testAttribute(Qt::WA_SetFont));
823  QVERIFY(! four->testAttribute(Qt::WA_SetFont));
824 
825  font.setPointSize(font.pointSize() + 2);
826  three->setFont(font);
827 
828  QCOMPARE(three->font(), four->font());
829 
830  QVERIFY(three->testAttribute(Qt::WA_SetFont));
831  QVERIFY(! four->testAttribute(Qt::WA_SetFont));
832 
833  font.setPointSize(font.pointSize() + 2);
834  four->setFont(font);
835 
836  QVERIFY(four->testAttribute(Qt::WA_SetFont));
837 }
838 
840 {
841  Q_OBJECT
842 public:
843  using QWidget::QWidget;
844 };
845 
846 void tst_QWidget::fontPropagation2()
847 {
848  // ! Note, the code below is executed in tst_QWidget's constructor.
849  // QFont font;
850  // font.setBold(true);
851  // font.setPointSize(42);
852  // QApplication::setFont(font, "QPropagationTestWidget");
853 
855  root->setObjectName(QLatin1String("fontPropagation2"));
856  root->setWindowTitle(root->objectName());
857  root->resize(200, 200);
858 
859  QWidget *child0 = new QWidget(root.data());
860  QWidget *child1 = new QWidget(child0);
861  QWidget *child2 = new QPropagationTestWidget(child1);
862  QWidget *child3 = new QWidget(child2);
863  QWidget *child4 = new QWidget(child3);
864  QWidget *child5 = new QWidget(child4);
865  root->show();
866 
867  // Check that only the application fonts apply.
868  QCOMPARE(root->font(), QApplication::font());
869  QCOMPARE(child0->font(), QApplication::font());
870  QCOMPARE(child1->font(), QApplication::font());
871  QCOMPARE(child2->font().pointSize(), 42);
872  QVERIFY(child2->font().bold());
873  QCOMPARE(child3->font().pointSize(), 42);
874  QVERIFY(child3->font().bold());
875  QCOMPARE(child4->font().pointSize(), 42);
876  QVERIFY(child4->font().bold());
877  QCOMPARE(child5->font().pointSize(), 42);
878  QVERIFY(child5->font().bold());
879 
880  // Set child0's font size to 15, and remove bold on child4.
881  QFont font;
882  font.setPointSize(15);
883  child0->setFont(font);
884  QFont unboldFont;
885  unboldFont.setBold(false);
886  child4->setFont(unboldFont);
887 
888  // Check that the above settings propagate correctly.
889  QCOMPARE(root->font(), QApplication::font());
890  QCOMPARE(child0->font().pointSize(), 15);
891  QVERIFY(!child0->font().bold());
892  QCOMPARE(child1->font().pointSize(), 15);
893  QVERIFY(!child1->font().bold());
894  QCOMPARE(child2->font().pointSize(), 15);
895  QVERIFY(child2->font().bold());
896  QCOMPARE(child3->font().pointSize(), 15);
897  QVERIFY(child3->font().bold());
898  QCOMPARE(child4->font().pointSize(), 15);
899  QVERIFY(!child4->font().bold());
900  QCOMPARE(child5->font().pointSize(), 15);
901  QVERIFY(!child5->font().bold());
902 
903  // Replace the app font for child2. Italic should propagate
904  // but the size should still be ignored. The previous bold
905  // setting is gone.
906  QFont italicSizeFont;
907  italicSizeFont.setItalic(true);
908  italicSizeFont.setPointSize(33);
909  QApplication::setFont(italicSizeFont, "QPropagationTestWidget");
910 
911  // Check that this propagates correctly.
912  QCOMPARE(root->font(), QApplication::font());
913  QCOMPARE(child0->font().pointSize(), 15);
914  QVERIFY(!child0->font().bold());
915  QVERIFY(!child0->font().italic());
916  QCOMPARE(child1->font().pointSize(), 15);
917  QVERIFY(!child1->font().bold());
918  QVERIFY(!child1->font().italic());
919  QCOMPARE(child2->font().pointSize(), 15);
920  QVERIFY(!child2->font().bold());
921  QVERIFY(child2->font().italic());
922  QCOMPARE(child3->font().pointSize(), 15);
923  QVERIFY(!child3->font().bold());
924  QVERIFY(child3->font().italic());
925  QCOMPARE(child4->font().pointSize(), 15);
926  QVERIFY(!child4->font().bold());
927  QVERIFY(child4->font().italic());
928  QCOMPARE(child5->font().pointSize(), 15);
929  QVERIFY(!child5->font().bold());
930  QVERIFY(child5->font().italic());
931 }
932 
933 void tst_QWidget::fontPropagation3()
934 {
935  QWidget parent;
936  QWidget *child = new QWidget(&parent);
937  parent.setFont(QFont("Monospace", 9));
938  QImage image(32, 32, QImage::Format_RGB32);
939  QPainter p(&image);
940  p.setFont(child->font());
941  QCOMPARE(p.font().family(), child->font().family());
942  QCOMPARE(p.font().pointSize(), child->font().pointSize());
943 }
944 
950 void tst_QWidget::fontPropagationDynamic()
951 {
952  // override side effects from previous tests
953  QFont themedFont;
954  themedFont.setBold(true);
955  themedFont.setPointSize(42);
956  QApplication::setFont(themedFont, "QPropagationTestWidget");
957 
958  QWidget parent;
959  QWidget firstChild(&parent);
960 
961  const QFont defaultFont = parent.font();
962  QFont appFont = defaultFont;
963  appFont.setPointSize(72);
964 
965  // sanity check
966  QVERIFY(themedFont != defaultFont);
967  QVERIFY(themedFont != appFont);
968 
969  // palette propagates to existing children
970  parent.setFont(appFont);
971  QCOMPARE(firstChild.font().pointSize(), appFont.pointSize());
972 
973  // palatte propagates to children added later
974  QWidget secondChild(&parent);
975  QCOMPARE(secondChild.font().pointSize(), appFont.pointSize());
976  QWidget thirdChild;
977  QCOMPARE(thirdChild.font().pointSize(), defaultFont.pointSize());
978  thirdChild.setParent(&parent);
979  QCOMPARE(thirdChild.font().pointSize(), appFont.pointSize());
980 
981  // even if the child has an override in QApplication::font
982  QPropagationTestWidget themedChild;
983  themedChild.ensurePolished(); // needed for default font to be set up
984  QCOMPARE(themedChild.font().pointSize(), themedFont.pointSize());
985  QCOMPARE(themedChild.font().bold(), themedFont.bold());
986  themedChild.setParent(&parent);
987  QCOMPARE(themedChild.font().pointSize(), appFont.pointSize());
988  QCOMPARE(themedChild.font().bold(), themedFont.bold());
989 
990  // grand children as well
991  QPropagationTestWidget themedGrandChild;
992  themedGrandChild.setParent(&themedChild);
993  QCOMPARE(themedGrandChild.font().pointSize(), appFont.pointSize());
994  QCOMPARE(themedGrandChild.font().bold(), themedFont.bold());
995 
996  // child with own font attribute does not inherit from parent
997  QFont childFont = defaultFont;
998  childFont.setPointSize(9);
999  QWidget modifiedChild;
1000  modifiedChild.setFont(childFont);
1001  modifiedChild.setParent(&parent);
1002  QCOMPARE(modifiedChild.font().pointSize(), childFont.pointSize());
1003 }
1004 
1005 void tst_QWidget::palettePropagation()
1006 {
1007  QScopedPointer<QWidget> testWidget(new QWidget);
1008  testWidget->resize(m_testWidgetSize);
1009  testWidget->setWindowTitle(__FUNCTION__);
1010  centerOnScreen(testWidget.data());
1011  testWidget->show();
1012  QVERIFY(QTest::qWaitForWindowExposed(testWidget.data()));
1013 
1014  QPalette palette = testWidget->palette();
1015  QWidget* childWidget = new QWidget( testWidget.data() );
1016  childWidget->show();
1017  QCOMPARE( palette, childWidget->palette() );
1018 
1019  palette.setColor( QPalette::Base, Qt::red );
1020  testWidget->setPalette( palette );
1021  QCOMPARE( palette, testWidget->palette() );
1022  QCOMPARE( palette, childWidget->palette() );
1023 
1024  QPalette newPalette = palette;
1025  newPalette.setColor( QPalette::Highlight, Qt::green );
1026  childWidget->setPalette( newPalette );
1027  QWidget* grandChildWidget = new QWidget( childWidget );
1028  QCOMPARE( palette, testWidget->palette() );
1029  QCOMPARE( newPalette, grandChildWidget->palette() );
1030 
1031  palette.setColor( QPalette::Text, Qt::blue );
1032  testWidget->setPalette( palette );
1033 
1034  // the child and grand child should now have merged green
1035  // highlight and blue text
1036  newPalette.setColor( QPalette::Text, Qt::blue);
1037 
1038  QCOMPARE( newPalette, childWidget->palette() );
1039  QCOMPARE( newPalette, grandChildWidget->palette() );
1040 }
1041 
1042 void tst_QWidget::palettePropagation2()
1043 {
1045  QSKIP("Wayland: This fails. Figure out why.");
1046 
1047  // ! Note, the code below is executed in tst_QWidget's constructor.
1048  // QPalette palette;
1049  // palette.setColor(QPalette::ToolTipBase, QColor(12, 13, 14));
1050  // palette.setColor(QPalette::Text, QColor(21, 22, 23));
1051  // qApp->setPalette(palette, "QPropagationTestWidget");
1052 
1053  QScopedPointer<QWidget> root(new QWidget);
1054  root->setObjectName(QLatin1String("palettePropagation2"));
1055  root->setWindowTitle(root->objectName());
1056  root->resize(200, 200);
1057  QWidget *child0 = new QWidget(root.data());
1058  QWidget *child1 = new QWidget(child0);
1059  QWidget *child2 = new QPropagationTestWidget(child1);
1060  QWidget *child3 = new QWidget(child2);
1061  QWidget *child4 = new QWidget(child3);
1062  QWidget *child5 = new QWidget(child4);
1063  root->show();
1064  QVERIFY(QTest::qWaitForWindowExposed(root.data()));
1065 
1066  // These colors are unlikely to be imposed on the default palette of
1067  // QWidget ;-).
1068  QColor sysPalText(21, 22, 23);
1069  QColor sysPalToolTipBase(12, 13, 14);
1070  QColor overridePalText(42, 43, 44);
1071  QColor overridePalToolTipBase(45, 46, 47);
1072  QColor sysPalButton(99, 98, 97);
1073 
1074  // Check that only the application fonts apply.
1075  QPalette appPal = QApplication::palette();
1076  QCOMPARE(root->palette(), appPal);
1077  QCOMPARE(child0->palette(), appPal);
1078  QCOMPARE(child1->palette(), appPal);
1079  QCOMPARE(child2->palette().color(QPalette::ToolTipBase), sysPalToolTipBase);
1080  QCOMPARE(child2->palette().color(QPalette::Text), sysPalText);
1081  QCOMPARE(child2->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1082  QCOMPARE(child3->palette().color(QPalette::ToolTipBase), sysPalToolTipBase);
1083  QCOMPARE(child3->palette().color(QPalette::Text), sysPalText);
1084  QCOMPARE(child3->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1085  QCOMPARE(child4->palette().color(QPalette::ToolTipBase), sysPalToolTipBase);
1086  QCOMPARE(child4->palette().color(QPalette::Text), sysPalText);
1087  QCOMPARE(child4->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1088  QCOMPARE(child5->palette().color(QPalette::ToolTipBase), sysPalToolTipBase);
1089  QCOMPARE(child5->palette().color(QPalette::Text), sysPalText);
1090  QCOMPARE(child5->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1091 
1092  // Set child0's Text, and set ToolTipBase on child4.
1093  QPalette textPalette;
1094  textPalette.setColor(QPalette::Text, overridePalText);
1095  child0->setPalette(textPalette);
1096  QPalette toolTipPalette;
1097  toolTipPalette.setColor(QPalette::ToolTipBase, overridePalToolTipBase);
1098  child4->setPalette(toolTipPalette);
1099 
1100  // Check that the above settings propagate correctly.
1101  QCOMPARE(root->palette(), appPal);
1102  QCOMPARE(child0->palette().color(QPalette::Text), overridePalText);
1103  QCOMPARE(child0->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase));
1104  QCOMPARE(child0->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1105  QCOMPARE(child1->palette().color(QPalette::Text), overridePalText);
1106  QCOMPARE(child1->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase));
1107  QCOMPARE(child1->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1108  QCOMPARE(child2->palette().color(QPalette::Text), overridePalText);
1109  QCOMPARE(child2->palette().color(QPalette::ToolTipBase), sysPalToolTipBase);
1110  QCOMPARE(child2->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1111  QCOMPARE(child3->palette().color(QPalette::Text), overridePalText);
1112  QCOMPARE(child3->palette().color(QPalette::ToolTipBase), sysPalToolTipBase);
1113  QCOMPARE(child3->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1114  QCOMPARE(child4->palette().color(QPalette::Text), overridePalText);
1115  QCOMPARE(child4->palette().color(QPalette::ToolTipBase), overridePalToolTipBase);
1116  QCOMPARE(child4->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1117  QCOMPARE(child5->palette().color(QPalette::Text), overridePalText);
1118  QCOMPARE(child5->palette().color(QPalette::ToolTipBase), overridePalToolTipBase);
1119  QCOMPARE(child5->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1120 
1121  // Replace the app palette for child2. Button should propagate but Text
1122  // should still be ignored. The previous ToolTipBase setting is gone.
1123  QPalette buttonPalette;
1124  buttonPalette.setColor(QPalette::ToolTipText, sysPalButton);
1125  QApplication::setPalette(buttonPalette, "QPropagationTestWidget");
1126 
1127  // Check that the above settings propagate correctly.
1128  QCOMPARE(root->palette(), appPal);
1129  QCOMPARE(child0->palette().color(QPalette::Text), overridePalText);
1130  QCOMPARE(child0->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase));
1131  QCOMPARE(child0->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1132  QCOMPARE(child1->palette().color(QPalette::Text), overridePalText);
1133  QCOMPARE(child1->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase));
1134  QCOMPARE(child1->palette().color(QPalette::ToolTipText), appPal.color(QPalette::ToolTipText));
1135  QCOMPARE(child2->palette().color(QPalette::Text), overridePalText);
1136  QCOMPARE(child2->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase));
1137  QCOMPARE(child2->palette().color(QPalette::ToolTipText), sysPalButton);
1138  QCOMPARE(child3->palette().color(QPalette::Text), overridePalText);
1139  QCOMPARE(child3->palette().color(QPalette::ToolTipBase), appPal.color(QPalette::ToolTipBase));
1140  QCOMPARE(child3->palette().color(QPalette::ToolTipText), sysPalButton);
1141  QCOMPARE(child4->palette().color(QPalette::Text), overridePalText);
1142  QCOMPARE(child4->palette().color(QPalette::ToolTipBase), overridePalToolTipBase);
1143  QCOMPARE(child4->palette().color(QPalette::ToolTipText), sysPalButton);
1144  QCOMPARE(child5->palette().color(QPalette::Text), overridePalText);
1145  QCOMPARE(child5->palette().color(QPalette::ToolTipBase), overridePalToolTipBase);
1146  QCOMPARE(child5->palette().color(QPalette::ToolTipText), sysPalButton);
1147 }
1148 
1154 void tst_QWidget::palettePropagationDynamic()
1155 {
1156  // override side effects from previous tests
1157  QPalette themedPalette;
1158  themedPalette.setColor(QPalette::ToolTipBase, QColor(12, 13, 14));
1159  themedPalette.setColor(QPalette::Text, QColor(21, 22, 23));
1160  QApplication::setPalette(themedPalette, "QPropagationTestWidget");
1161 
1162  QWidget parent;
1163  QWidget firstChild(&parent);
1164 
1165  const QPalette defaultPalette = parent.palette();
1166  QPalette appPalette = defaultPalette;
1167  const QColor appColor(1, 2, 3);
1168  appPalette.setColor(QPalette::Text, appColor);
1169 
1170  // sanity check
1171  QVERIFY(themedPalette != defaultPalette);
1172  QVERIFY(themedPalette != appPalette);
1173 
1174  // palette propagates to existing children
1175  parent.setPalette(appPalette);
1176  QCOMPARE(firstChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text));
1177 
1178  // palatte propagates to children added later
1179  QWidget secondChild(&parent);
1180  QCOMPARE(secondChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text));
1181  QWidget thirdChild;
1182  QCOMPARE(thirdChild.palette().color(QPalette::Text), defaultPalette.color(QPalette::Text));
1183  thirdChild.setParent(&parent);
1184  QCOMPARE(thirdChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text));
1185 
1186  // even if the child has an override in QApplication::palette
1187  QPropagationTestWidget themedChild;
1188  themedChild.ensurePolished(); // needed for default palette to be set up
1189  QCOMPARE(themedChild.palette().color(QPalette::Text), themedPalette.color(QPalette::Text));
1190  QCOMPARE(themedChild.palette().color(QPalette::ToolTipBase), themedPalette.color(QPalette::ToolTipBase));
1191  themedChild.setParent(&parent);
1192  QCOMPARE(themedChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text));
1193  QCOMPARE(themedChild.palette().color(QPalette::ToolTipBase), themedPalette.color(QPalette::ToolTipBase));
1194 
1195  // grand children as well
1196  QPropagationTestWidget themedGrandChild;
1197  themedGrandChild.setParent(&themedChild);
1198  QCOMPARE(themedGrandChild.palette().color(QPalette::Text), appPalette.color(QPalette::Text));
1199  QCOMPARE(themedGrandChild.palette().color(QPalette::ToolTipBase), themedPalette.color(QPalette::ToolTipBase));
1200 
1201  // child with own color does not inherit from parent
1202  QPalette childPalette = defaultPalette;
1203  childPalette.setColor(QPalette::Text, Qt::red);
1204  QWidget modifiedChild;
1205  modifiedChild.setPalette(childPalette);
1206  modifiedChild.setParent(&parent);
1207  QCOMPARE(modifiedChild.palette().color(QPalette::Text), childPalette.color(QPalette::Text));
1208 
1209 }
1210 
1211 void tst_QWidget::enabledPropagation()
1212 {
1213  QScopedPointer<QWidget> testWidget(new QWidget);
1214  testWidget->resize(m_testWidgetSize);
1215  testWidget->setWindowTitle(__FUNCTION__);
1216  centerOnScreen(testWidget.data());
1217  testWidget->show();
1218  QVERIFY(QTest::qWaitForWindowExposed(testWidget.data()));
1219  QWidget* childWidget = new QWidget( testWidget.data() );
1220  childWidget->show();
1221  QVERIFY( testWidget->isEnabled() );
1222  QVERIFY( childWidget->isEnabled() );
1223 
1224  testWidget->setEnabled( false );
1225  QVERIFY( !testWidget->isEnabled() );
1226  QVERIFY( !childWidget->isEnabled() );
1227 
1228  testWidget->setDisabled( false );
1229  QVERIFY( testWidget->isEnabled() );
1230  QVERIFY( childWidget->isEnabled() );
1231 
1232  QWidget* grandChildWidget = new QWidget( childWidget );
1233  QVERIFY( grandChildWidget->isEnabled() );
1234 
1235  testWidget->setDisabled( true );
1236  QVERIFY( !testWidget->isEnabled() );
1237  QVERIFY( !childWidget->isEnabled() );
1238  QVERIFY( !grandChildWidget->isEnabled() );
1239 
1240  grandChildWidget->setEnabled( false );
1241  testWidget->setEnabled( true );
1242  QVERIFY( testWidget->isEnabled() );
1243  QVERIFY( childWidget->isEnabled() );
1244  QVERIFY( !grandChildWidget->isEnabled() );
1245 
1246  grandChildWidget->setEnabled( true );
1247  testWidget->setEnabled( false );
1248  childWidget->setDisabled( true );
1249  testWidget->setEnabled( true );
1250  QVERIFY( testWidget->isEnabled() );
1251  QVERIFY( !childWidget->isEnabled() );
1252  QVERIFY( !grandChildWidget->isEnabled() );
1253 }
1254 
1255 void tst_QWidget::ignoreKeyEventsWhenDisabled_QTBUG27417()
1256 {
1258  lineEdit.setWindowTitle(__FUNCTION__);
1259  lineEdit.setMinimumWidth(m_testWidgetSize.width());
1260  centerOnScreen(&lineEdit);
1261  lineEdit.setDisabled(true);
1262  lineEdit.show();
1263  QTest::ignoreMessage(QtWarningMsg, "Keyboard event not accepted by receiving widget");
1264  QTest::ignoreMessage(QtWarningMsg, "Keyboard event not accepted by receiving widget");
1265  QTest::keyClick(&lineEdit, Qt::Key_A);
1267 }
1268 
1269 void tst_QWidget::properTabHandlingWhenDisabled_QTBUG27417()
1270 {
1272  QSKIP("Wayland: This fails. Figure out why.");
1273 
1274  QWidget widget;
1275  widget.setWindowTitle(__FUNCTION__);
1276  widget.setMinimumWidth(m_testWidgetSize.width());
1277  centerOnScreen(&widget);
1278  QVBoxLayout *layout = new QVBoxLayout();
1279  QLineEdit *lineEdit = new QLineEdit();
1280  layout->addWidget(lineEdit);
1281  QLineEdit *lineEdit2 = new QLineEdit();
1282  layout->addWidget(lineEdit2);
1283  QLineEdit *lineEdit3 = new QLineEdit();
1284  layout->addWidget(lineEdit3);
1286  widget.show();
1287 
1288  lineEdit->setFocus();
1290  QTest::keyClick(&widget, Qt::Key_Tab);
1291  QTRY_VERIFY(lineEdit2->hasFocus());
1292  QTest::keyClick(&widget, Qt::Key_Tab);
1293  QTRY_VERIFY(lineEdit3->hasFocus());
1294 
1295  lineEdit2->setDisabled(true);
1296  lineEdit->setFocus();
1298  QTest::keyClick(&widget, Qt::Key_Tab);
1299  QTRY_VERIFY(!lineEdit2->hasFocus());
1300  QVERIFY(lineEdit3->hasFocus());
1301 }
1302 
1303 // Drag'n drop disabled in this build.
1304 #if QT_CONFIG(draganddrop)
1305 void tst_QWidget::acceptDropsPropagation()
1306 {
1307  QScopedPointer<QWidget> testWidget(new QWidget);
1308  testWidget->resize(m_testWidgetSize);
1309  testWidget->setWindowTitle(__FUNCTION__);
1310  centerOnScreen(testWidget.data());
1311  testWidget->show();
1312  QVERIFY(QTest::qWaitForWindowExposed(testWidget.data()));
1313  QWidget *childWidget = new QWidget(testWidget.data());
1314  childWidget->show();
1315  QVERIFY(!testWidget->acceptDrops());
1316  QVERIFY(!childWidget->acceptDrops());
1317 
1318  testWidget->setAcceptDrops(true);
1319  QVERIFY(testWidget->acceptDrops());
1320  QVERIFY(!childWidget->acceptDrops());
1321  QVERIFY(childWidget->testAttribute(Qt::WA_DropSiteRegistered));
1322 
1323  testWidget->setAcceptDrops(false);
1324  QVERIFY(!testWidget->acceptDrops());
1325  QVERIFY(!childWidget->acceptDrops());
1326  QVERIFY(!childWidget->testAttribute(Qt::WA_DropSiteRegistered));
1327 
1328  QWidget *grandChildWidget = new QWidget(childWidget);
1329  QVERIFY(!grandChildWidget->acceptDrops());
1330  QVERIFY(!grandChildWidget->testAttribute(Qt::WA_DropSiteRegistered));
1331 
1332  testWidget->setAcceptDrops(true);
1333  QVERIFY(testWidget->acceptDrops());
1334  QVERIFY(!childWidget->acceptDrops());
1335  QVERIFY(childWidget->testAttribute(Qt::WA_DropSiteRegistered));
1336  QVERIFY(!grandChildWidget->acceptDrops());
1337  QVERIFY(grandChildWidget->testAttribute(Qt::WA_DropSiteRegistered));
1338 
1339  grandChildWidget->setAcceptDrops(true);
1340  testWidget->setAcceptDrops(false);
1341  QVERIFY(!testWidget->acceptDrops());
1342  QVERIFY(!childWidget->acceptDrops());
1343  QVERIFY(grandChildWidget->acceptDrops());
1344  QVERIFY(grandChildWidget->testAttribute(Qt::WA_DropSiteRegistered));
1345 
1346  grandChildWidget->setAcceptDrops(false);
1347  QVERIFY(!grandChildWidget->testAttribute(Qt::WA_DropSiteRegistered));
1348  testWidget->setAcceptDrops(true);
1349  childWidget->setAcceptDrops(true);
1350  testWidget->setAcceptDrops(false);
1351  QVERIFY(!testWidget->acceptDrops());
1352  QVERIFY(childWidget->acceptDrops());
1353  QVERIFY(!grandChildWidget->acceptDrops());
1354  QVERIFY(grandChildWidget->testAttribute(Qt::WA_DropSiteRegistered));
1355 }
1356 #endif
1357 
1358 void tst_QWidget::isEnabledTo()
1359 {
1360  QWidget testWidget;
1361  testWidget.resize(m_testWidgetSize);
1362  testWidget.setWindowTitle(__FUNCTION__);
1363  centerOnScreen(&testWidget);
1364  testWidget.show();
1365  QWidget* childWidget = new QWidget( &testWidget );
1366  QWidget* grandChildWidget = new QWidget( childWidget );
1367 
1368  QVERIFY( childWidget->isEnabledTo( &testWidget ) );
1369  QVERIFY( grandChildWidget->isEnabledTo( &testWidget ) );
1370 
1371  childWidget->setEnabled( false );
1372  QVERIFY( !childWidget->isEnabledTo( &testWidget ) );
1373  QVERIFY( grandChildWidget->isEnabledTo( childWidget ) );
1374  QVERIFY( !grandChildWidget->isEnabledTo( &testWidget ) );
1375 
1376  QScopedPointer<QMainWindow> childDialog(new QMainWindow(&testWidget));
1377  testWidget.setEnabled(false);
1378  QVERIFY(!childDialog->isEnabled());
1379  QVERIFY(childDialog->isEnabledTo(nullptr));
1380 }
1381 
1382 void tst_QWidget::visible()
1383 {
1384  // Ensure that the testWidget is hidden for this test at the
1385  // start
1386  QScopedPointer<QWidget> testWidget(new QWidget);
1387  testWidget->resize(m_testWidgetSize);
1388  testWidget->setWindowTitle(__FUNCTION__);
1389  centerOnScreen(testWidget.data());
1390  QVERIFY( !testWidget->isVisible() );
1391  QWidget* childWidget = new QWidget( testWidget.data() );
1392  QVERIFY( !childWidget->isVisible() );
1393 
1394  testWidget->show();
1395  QVERIFY(testWidget->screen());
1396  QVERIFY( testWidget->isVisible() );
1397  QVERIFY( childWidget->isVisible() );
1398 
1399  QWidget* grandChildWidget = new QWidget( childWidget );
1400  QVERIFY( !grandChildWidget->isVisible() );
1401  grandChildWidget->show();
1402  QVERIFY( grandChildWidget->isVisible() );
1403 
1404  grandChildWidget->hide();
1405  testWidget->hide();
1406  testWidget->show();
1407  QVERIFY( !grandChildWidget->isVisible() );
1408  QVERIFY( testWidget->isVisible() );
1409  QVERIFY( childWidget->isVisible() );
1410 
1411  grandChildWidget->show();
1412  childWidget->hide();
1413  testWidget->hide();
1414  testWidget->show();
1415  QVERIFY( testWidget->isVisible() );
1416  QVERIFY( !childWidget->isVisible() );
1417  QVERIFY( !grandChildWidget->isVisible() );
1418 
1419  grandChildWidget->show();
1420  QVERIFY( !grandChildWidget->isVisible() );
1421 }
1422 
1423 void tst_QWidget::setLocale()
1424 {
1425  QWidget w;
1426  QCOMPARE(w.locale(), QLocale());
1427 
1428  w.setLocale(QLocale::Italian);
1429  QCOMPARE(w.locale(), QLocale(QLocale::Italian));
1430 
1431  QWidget child1(&w);
1432  QCOMPARE(child1.locale(), QLocale(QLocale::Italian));
1433 
1434  w.unsetLocale();
1435  QCOMPARE(w.locale(), QLocale());
1436  QCOMPARE(child1.locale(), QLocale());
1437 
1438  w.setLocale(QLocale::French);
1439  QCOMPARE(w.locale(), QLocale(QLocale::French));
1440  QCOMPARE(child1.locale(), QLocale(QLocale::French));
1441 
1442  child1.setLocale(QLocale::Italian);
1443  QCOMPARE(w.locale(), QLocale(QLocale::French));
1444  QCOMPARE(child1.locale(), QLocale(QLocale::Italian));
1445 
1446  child1.unsetLocale();
1447  QCOMPARE(w.locale(), QLocale(QLocale::French));
1448  QCOMPARE(child1.locale(), QLocale(QLocale::French));
1449 
1450  QWidget child2;
1451  QCOMPARE(child2.locale(), QLocale());
1452  child2.setParent(&w);
1453  QCOMPARE(child2.locale(), QLocale(QLocale::French));
1454 }
1455 
1456 void tst_QWidget::propagateLocale()
1457 {
1458  QWidget parent;
1459  parent.setLocale(QLocale::French);
1460  // Non-window widget; propagates locale:
1461  QWidget *child = new QWidget(&parent);
1462  QVERIFY(!child->isWindow());
1463  QVERIFY(!child->testAttribute(Qt::WA_WindowPropagation));
1464  QCOMPARE(child->locale(), QLocale(QLocale::French));
1465  parent.setLocale(QLocale::Italian);
1466  QCOMPARE(child->locale(), QLocale(QLocale::Italian));
1467  delete child;
1468  // Window: doesn't propagate locale:
1469  child = new QWidget(&parent, Qt::Window);
1470  QVERIFY(child->isWindow());
1471  QVERIFY(!child->testAttribute(Qt::WA_WindowPropagation));
1472  QCOMPARE(child->locale(), QLocale());
1473  parent.setLocale(QLocale::French);
1474  QCOMPARE(child->locale(), QLocale());
1475  // ... unless we tell it to:
1476  child->setAttribute(Qt::WA_WindowPropagation, true);
1477  QVERIFY(child->testAttribute(Qt::WA_WindowPropagation));
1478  QCOMPARE(child->locale(), QLocale(QLocale::French));
1479  parent.setLocale(QLocale::Italian);
1480  QCOMPARE(child->locale(), QLocale(QLocale::Italian));
1481 }
1482 
1483 void tst_QWidget::visible_setWindowOpacity()
1484 {
1485  QScopedPointer<QWidget> testWidget(new QWidget);
1486  testWidget->resize(m_testWidgetSize);
1487  testWidget->setWindowTitle(__FUNCTION__);
1488  centerOnScreen(testWidget.data());
1489  testWidget->winId();
1490 
1491  QVERIFY( !testWidget->isVisible() );
1492  testWidget->setWindowOpacity(0.5);
1493 #if defined(Q_OS_WIN)
1494  QVERIFY(!::IsWindowVisible(winHandleOf(testWidget.data())));
1495 #endif
1496  testWidget->setWindowOpacity(1.0);
1497 }
1498 
1499 void tst_QWidget::isVisibleTo()
1500 {
1501  // Ensure that the testWidget is hidden for this test at the
1502  // start
1503  QWidget testWidget;
1504  testWidget.resize(m_testWidgetSize);
1505  testWidget.setWindowTitle(__FUNCTION__);
1506  centerOnScreen(&testWidget);
1507 
1508  QWidget* childWidget = new QWidget( &testWidget );
1509  QVERIFY( childWidget->isVisibleTo( &testWidget ) );
1510  childWidget->hide();
1511  QVERIFY( !childWidget->isVisibleTo( &testWidget ) );
1512 
1513  QWidget* grandChildWidget = new QWidget( childWidget );
1514  QVERIFY( !grandChildWidget->isVisibleTo( &testWidget ) );
1515  QVERIFY( grandChildWidget->isVisibleTo( childWidget ) );
1516 
1517  testWidget.show();
1518  childWidget->show();
1519 
1520  QVERIFY( childWidget->isVisibleTo( &testWidget ) );
1521  grandChildWidget->hide();
1522  QVERIFY( !grandChildWidget->isVisibleTo( childWidget ) );
1523  QVERIFY( !grandChildWidget->isVisibleTo( &testWidget ) );
1524 }
1525 
1526 void tst_QWidget::isHidden()
1527 {
1528  // Ensure that the testWidget is hidden for this test at the
1529  // start
1530  QScopedPointer<QWidget> testWidget(new QWidget);
1531  testWidget->resize(m_testWidgetSize);
1532  testWidget->setWindowTitle(__FUNCTION__);
1533  centerOnScreen(testWidget.data());
1534 
1535  QVERIFY( testWidget->isHidden() );
1536  QWidget* childWidget = new QWidget( testWidget.data() );
1537  QVERIFY( !childWidget->isHidden() );
1538 
1539  testWidget->show();
1540  QVERIFY( !testWidget->isHidden() );
1541  QVERIFY( !childWidget->isHidden() );
1542 
1543  QWidget* grandChildWidget = new QWidget( childWidget );
1544  QVERIFY( grandChildWidget->isHidden() );
1545  grandChildWidget->show();
1546  QVERIFY( !grandChildWidget->isHidden() );
1547 
1548  grandChildWidget->hide();
1549  testWidget->hide();
1550  testWidget->show();
1551  QVERIFY( grandChildWidget->isHidden() );
1552  QVERIFY( !testWidget->isHidden() );
1553  QVERIFY( !childWidget->isHidden() );
1554 
1555  grandChildWidget->show();
1556  childWidget->hide();
1557  testWidget->hide();
1558  testWidget->show();
1559  QVERIFY( !testWidget->isHidden() );
1560  QVERIFY( childWidget->isHidden() );
1561  QVERIFY( !grandChildWidget->isHidden() );
1562 
1563  grandChildWidget->show();
1564  QVERIFY( !grandChildWidget->isHidden() );
1565 }
1566 
1567 void tst_QWidget::fonts()
1568 {
1569  QWidget testWidget;
1570  testWidget.resize(m_testWidgetSize);
1571  testWidget.setWindowTitle(__FUNCTION__);
1572  centerOnScreen(&testWidget);
1573  testWidget.show();
1574  QVERIFY(QTest::qWaitForWindowExposed(&testWidget));
1575 
1576  // Tests setFont(), ownFont() and unsetFont()
1577  QWidget* cleanTestWidget = new QWidget( &testWidget );
1578  QFont originalFont = cleanTestWidget->font();
1579 
1580  QVERIFY( !cleanTestWidget->testAttribute(Qt::WA_SetFont) );
1581  cleanTestWidget->setFont(QFont());
1582  QVERIFY( !cleanTestWidget->testAttribute(Qt::WA_SetFont) );
1583 
1584  QFont newFont( "times", 18 );
1585  cleanTestWidget->setFont( newFont );
1586  newFont = newFont.resolve( testWidget.font() );
1587 
1588  QVERIFY( cleanTestWidget->testAttribute(Qt::WA_SetFont) );
1589  QVERIFY2( cleanTestWidget->font() == newFont,
1590  msgComparisonFailed(cleanTestWidget->font(), "==", newFont));
1591 
1592  cleanTestWidget->setFont(QFont());
1593  QVERIFY( !cleanTestWidget->testAttribute(Qt::WA_SetFont) );
1594  QVERIFY2( cleanTestWidget->font() == originalFont,
1595  msgComparisonFailed(cleanTestWidget->font(), "==", originalFont));
1596 }
1597 
1598 void tst_QWidget::mapFromAndTo_data()
1599 {
1600  QTest::addColumn<bool>("windowHidden");
1601  QTest::addColumn<bool>("subWindow1Hidden");
1602  QTest::addColumn<bool>("subWindow2Hidden");
1603  QTest::addColumn<bool>("subSubWindowHidden");
1604  QTest::addColumn<bool>("windowMinimized");
1605  QTest::addColumn<bool>("subWindow1Minimized");
1606 
1607  QTest::newRow("window 1 sub1 1 sub2 1 subsub 1") << false << false << false << false << false << false;
1608  QTest::newRow("window 0 sub1 1 sub2 1 subsub 1") << true << false << false << false << false << false;
1609  QTest::newRow("window 1 sub1 0 sub2 1 subsub 1") << false << true << false << false << false << false;
1610  QTest::newRow("window 0 sub1 0 sub2 1 subsub 1") << true << true << false << false << false << false;
1611  QTest::newRow("window 1 sub1 1 sub2 0 subsub 1") << false << false << true << false << false << false;
1612  QTest::newRow("window 0 sub1 1 sub2 0 subsub 1") << true << false << true << false << false << false;
1613  QTest::newRow("window 1 sub1 0 sub2 0 subsub 1") << false << true << true << false << false << false;
1614  QTest::newRow("window 0 sub1 0 sub2 0 subsub 1") << true << true << true << false << false << false;
1615  QTest::newRow("window 1 sub1 1 sub2 1 subsub 0") << false << false << false << true << false << false;
1616  QTest::newRow("window 0 sub1 1 sub2 1 subsub 0") << true << false << false << true << false << false;
1617  QTest::newRow("window 1 sub1 0 sub2 1 subsub 0") << false << true << false << true << false << false;
1618  QTest::newRow("window 0 sub1 0 sub2 1 subsub 0") << true << true << false << true << false << false;
1619  QTest::newRow("window 1 sub1 1 sub2 0 subsub 0") << false << false << true << true << false << false;
1620  QTest::newRow("window 0 sub1 1 sub2 0 subsub 0") << true << false << true << true << false << false;
1621  QTest::newRow("window 1 sub1 0 sub2 0 subsub 0") << false << true << true << true << false << false;
1622  QTest::newRow("window 0 sub1 0 sub2 0 subsub 0") << true << true << true << true << false << false;
1623  QTest::newRow("window 1 sub1 1 sub2 1 subsub 1 windowMinimized") << false << false << false << false << true << false;
1624  QTest::newRow("window 0 sub1 1 sub2 1 subsub 1 windowMinimized") << true << false << false << false << true << false;
1625  QTest::newRow("window 1 sub1 0 sub2 1 subsub 1 windowMinimized") << false << true << false << false << true << false;
1626  QTest::newRow("window 0 sub1 0 sub2 1 subsub 1 windowMinimized") << true << true << false << false << true << false;
1627  QTest::newRow("window 1 sub1 1 sub2 0 subsub 1 windowMinimized") << false << false << true << false << true << false;
1628  QTest::newRow("window 0 sub1 1 sub2 0 subsub 1 windowMinimized") << true << false << true << false << true << false;
1629  QTest::newRow("window 1 sub1 0 sub2 0 subsub 1 windowMinimized") << false << true << true << false << true << false;
1630  QTest::newRow("window 0 sub1 0 sub2 0 subsub 1 windowMinimized") << true << true << true << false << true << false;
1631  QTest::newRow("window 1 sub1 1 sub2 1 subsub 0 windowMinimized") << false << false << false << true << true << false;
1632  QTest::newRow("window 0 sub1 1 sub2 1 subsub 0 windowMinimized") << true << false << false << true << true << false;
1633  QTest::newRow("window 1 sub1 0 sub2 1 subsub 0 windowMinimized") << false << true << false << true << true << false;
1634  QTest::newRow("window 0 sub1 0 sub2 1 subsub 0 windowMinimized") << true << true << false << true << true << false;
1635  QTest::newRow("window 1 sub1 1 sub2 0 subsub 0 windowMinimized") << false << false << true << true << true << false;
1636  QTest::newRow("window 0 sub1 1 sub2 0 subsub 0 windowMinimized") << true << false << true << true << true << false;
1637  QTest::newRow("window 1 sub1 0 sub2 0 subsub 0 windowMinimized") << false << true << true << true << true << false;
1638  QTest::newRow("window 0 sub1 0 sub2 0 subsub 0 windowMinimized") << true << true << true << true << true << false;
1639  QTest::newRow("window 1 sub1 1 sub2 1 subsub 1 subWindow1Minimized") << false << false << false << false << false << true;
1640  QTest::newRow("window 0 sub1 1 sub2 1 subsub 1 subWindow1Minimized") << true << false << false << false << false << true;
1641  QTest::newRow("window 1 sub1 0 sub2 1 subsub 1 subWindow1Minimized") << false << true << false << false << false << true;
1642  QTest::newRow("window 0 sub1 0 sub2 1 subsub 1 subWindow1Minimized") << true << true << false << false << false << true;
1643  QTest::newRow("window 1 sub1 1 sub2 0 subsub 1 subWindow1Minimized") << false << false << true << false << false << true;
1644  QTest::newRow("window 0 sub1 1 sub2 0 subsub 1 subWindow1Minimized") << true << false << true << false << false << true;
1645  QTest::newRow("window 1 sub1 0 sub2 0 subsub 1 subWindow1Minimized") << false << true << true << false << false << true;
1646  QTest::newRow("window 0 sub1 0 sub2 0 subsub 1 subWindow1Minimized") << true << true << true << false << false << true;
1647  QTest::newRow("window 1 sub1 1 sub2 1 subsub 0 subWindow1Minimized") << false << false << false << true << false << true;
1648  QTest::newRow("window 0 sub1 1 sub2 1 subsub 0 subWindow1Minimized") << true << false << false << true << false << true;
1649  QTest::newRow("window 1 sub1 0 sub2 1 subsub 0 subWindow1Minimized") << false << true << false << true << false << true;
1650  QTest::newRow("window 0 sub1 0 sub2 1 subsub 0 subWindow1Minimized") << true << true << false << true << false << true;
1651  QTest::newRow("window 1 sub1 1 sub2 0 subsub 0 subWindow1Minimized") << false << false << true << true << false << true;
1652  QTest::newRow("window 0 sub1 1 sub2 0 subsub 0 subWindow1Minimized") << true << false << true << true << false << true;
1653  QTest::newRow("window 1 sub1 0 sub2 0 subsub 0 subWindow1Minimized") << false << true << true << true << false << true;
1654  QTest::newRow("window 0 sub1 0 sub2 0 subsub 0 subWindow1Minimized") << true << true << true << true << false << true;
1655 
1656 
1657 }
1658 
1659 void tst_QWidget::mapFromAndTo()
1660 {
1661  QFETCH(bool, windowHidden);
1662  QFETCH(bool, subWindow1Hidden);
1663  QFETCH(bool, subWindow2Hidden);
1664  QFETCH(bool, subSubWindowHidden);
1665  QFETCH(bool, windowMinimized);
1666  QFETCH(bool, subWindow1Minimized);
1667 
1668  // create a toplevel and two overlapping siblings
1669  QWidget window;
1670  window.setObjectName(QStringLiteral("mapFromAndTo"));
1671  window.setWindowTitle(window.objectName());
1672  window.setWindowFlags(window.windowFlags() | Qt::X11BypassWindowManagerHint);
1673  QWidget *subWindow1 = new QWidget(&window);
1674  QWidget *subWindow2 = new QWidget(&window);
1675  QWidget *subSubWindow = new QWidget(subWindow1);
1676 
1677  // set their geometries
1678  window.setGeometry(100, 100, 100, 100);
1679  subWindow1->setGeometry(50, 50, 100, 100);
1680  subWindow2->setGeometry(75, 75, 100, 100);
1681  subSubWindow->setGeometry(10, 10, 10, 10);
1682 
1683 #if !defined(Q_OS_QNX)
1684  //update visibility
1685  if (windowMinimized) {
1686  if (!windowHidden) {
1687  window.showMinimized();
1688  QVERIFY(window.isMinimized());
1689  }
1690  } else {
1691  window.setVisible(!windowHidden);
1692  }
1693  if (subWindow1Minimized) {
1694  subWindow1->hide();
1695  subWindow1->showMinimized();
1696  QVERIFY(subWindow1->isMinimized());
1697  } else {
1698  subWindow1->setVisible(!subWindow1Hidden);
1699  }
1700 #else
1701  Q_UNUSED(windowHidden);
1702  Q_UNUSED(subWindow1Hidden);
1703  Q_UNUSED(windowMinimized);
1704  Q_UNUSED(subWindow1Minimized);
1705 #endif
1706 
1707  subWindow2->setVisible(!subWindow2Hidden);
1708  subSubWindow->setVisible(!subSubWindowHidden);
1709 
1710  // window
1711  QCOMPARE(window.mapToGlobal(QPoint(0, 0)), QPoint(100, 100));
1712  QCOMPARE(window.mapToGlobal(QPoint(10, 0)), QPoint(110, 100));
1713  QCOMPARE(window.mapToGlobal(QPoint(0, 10)), QPoint(100, 110));
1714  QCOMPARE(window.mapToGlobal(QPoint(-10, 0)), QPoint(90, 100));
1715  QCOMPARE(window.mapToGlobal(QPoint(0, -10)), QPoint(100, 90));
1716  QCOMPARE(window.mapToGlobal(QPoint(100, 100)), QPoint(200, 200));
1717  auto delta = window.mapToGlobal(QPointF(100.5, 100.5)) - QPointF(200.5, 200.5);
1718  QVERIFY(qFuzzyIsNull(delta.manhattanLength()));
1719  QCOMPARE(window.mapToGlobal(QPoint(110, 100)), QPoint(210, 200));
1720  QCOMPARE(window.mapToGlobal(QPoint(100, 110)), QPoint(200, 210));
1721  QCOMPARE(window.mapFromGlobal(QPoint(100, 100)), QPoint(0, 0));
1722  QCOMPARE(window.mapFromGlobal(QPoint(110, 100)), QPoint(10, 0));
1723  QCOMPARE(window.mapFromGlobal(QPoint(100, 110)), QPoint(0, 10));
1724  QCOMPARE(window.mapFromGlobal(QPoint(90, 100)), QPoint(-10, 0));
1725  QCOMPARE(window.mapFromGlobal(QPoint(100, 90)), QPoint(0, -10));
1726  QCOMPARE(window.mapFromGlobal(QPoint(200, 200)), QPoint(100, 100));
1727  delta = window.mapFromGlobal(QPointF(200.5, 200.5)) - QPointF(100.5, 100.5);
1728  QVERIFY(qFuzzyIsNull(delta.manhattanLength()));
1729  QCOMPARE(window.mapFromGlobal(QPoint(210, 200)), QPoint(110, 100));
1730  QCOMPARE(window.mapFromGlobal(QPoint(200, 210)), QPoint(100, 110));
1731  QCOMPARE(window.mapToParent(QPoint(0, 0)), QPoint(100, 100));
1732  QCOMPARE(window.mapToParent(QPoint(10, 0)), QPoint(110, 100));
1733  QCOMPARE(window.mapToParent(QPoint(0, 10)), QPoint(100, 110));
1734  QCOMPARE(window.mapToParent(QPoint(-10, 0)), QPoint(90, 100));
1735  QCOMPARE(window.mapToParent(QPoint(0, -10)), QPoint(100, 90));
1736  QCOMPARE(window.mapToParent(QPoint(100, 100)), QPoint(200, 200));
1737  QCOMPARE(window.mapToParent(QPoint(110, 100)), QPoint(210, 200));
1738  QCOMPARE(window.mapToParent(QPoint(100, 110)), QPoint(200, 210));
1739  QCOMPARE(window.mapFromParent(QPoint(100, 100)), QPoint(0, 0));
1740  QCOMPARE(window.mapFromParent(QPoint(110, 100)), QPoint(10, 0));
1741  QCOMPARE(window.mapFromParent(QPoint(100, 110)), QPoint(0, 10));
1742  QCOMPARE(window.mapFromParent(QPoint(90, 100)), QPoint(-10, 0));
1743  QCOMPARE(window.mapFromParent(QPoint(100, 90)), QPoint(0, -10));
1744  QCOMPARE(window.mapFromParent(QPoint(200, 200)), QPoint(100, 100));
1745  QCOMPARE(window.mapFromParent(QPoint(210, 200)), QPoint(110, 100));
1746  QCOMPARE(window.mapFromParent(QPoint(200, 210)), QPoint(100, 110));
1747 
1748  // first subwindow
1749  QCOMPARE(subWindow1->mapToGlobal(QPoint(0, 0)), QPoint(150, 150));
1750  QCOMPARE(subWindow1->mapToGlobal(QPoint(10, 0)), QPoint(160, 150));
1751  QCOMPARE(subWindow1->mapToGlobal(QPoint(0, 10)), QPoint(150, 160));
1752  QCOMPARE(subWindow1->mapToGlobal(QPoint(-10, 0)), QPoint(140, 150));
1753  QCOMPARE(subWindow1->mapToGlobal(QPoint(0, -10)), QPoint(150, 140));
1754  QCOMPARE(subWindow1->mapToGlobal(QPoint(100, 100)), QPoint(250, 250));
1755  QCOMPARE(subWindow1->mapToGlobal(QPoint(110, 100)), QPoint(260, 250));
1756  QCOMPARE(subWindow1->mapToGlobal(QPoint(100, 110)), QPoint(250, 260));
1757  QCOMPARE(subWindow1->mapFromGlobal(QPoint(150, 150)), QPoint(0, 0));
1758  QCOMPARE(subWindow1->mapFromGlobal(QPoint(160, 150)), QPoint(10, 0));
1759  QCOMPARE(subWindow1->mapFromGlobal(QPoint(150, 160)), QPoint(0, 10));
1760  QCOMPARE(subWindow1->mapFromGlobal(QPoint(140, 150)), QPoint(-10, 0));
1761  QCOMPARE(subWindow1->mapFromGlobal(QPoint(150, 140)), QPoint(0, -10));
1762  QCOMPARE(subWindow1->mapFromGlobal(QPoint(250, 250)), QPoint(100, 100));
1763  QCOMPARE(subWindow1->mapFromGlobal(QPoint(260, 250)), QPoint(110, 100));
1764  QCOMPARE(subWindow1->mapFromGlobal(QPoint(250, 260)), QPoint(100, 110));
1765  QCOMPARE(subWindow1->mapToParent(QPoint(0, 0)), QPoint(50, 50));
1766  QCOMPARE(subWindow1->mapToParent(QPoint(10, 0)), QPoint(60, 50));
1767  QCOMPARE(subWindow1->mapToParent(QPoint(0, 10)), QPoint(50, 60));
1768  QCOMPARE(subWindow1->mapToParent(QPoint(-10, 0)), QPoint(40, 50));
1769  QCOMPARE(subWindow1->mapToParent(QPoint(0, -10)), QPoint(50, 40));
1770  QCOMPARE(subWindow1->mapToParent(QPoint(100, 100)), QPoint(150, 150));
1771  QCOMPARE(subWindow1->mapToParent(QPoint(110, 100)), QPoint(160, 150));
1772  QCOMPARE(subWindow1->mapToParent(QPoint(100, 110)), QPoint(150, 160));
1773  QCOMPARE(subWindow1->mapFromParent(QPoint(50, 50)), QPoint(0, 0));
1774  QCOMPARE(subWindow1->mapFromParent(QPoint(60, 50)), QPoint(10, 0));
1775  QCOMPARE(subWindow1->mapFromParent(QPoint(50, 60)), QPoint(0, 10));
1776  QCOMPARE(subWindow1->mapFromParent(QPoint(40, 50)), QPoint(-10, 0));
1777  QCOMPARE(subWindow1->mapFromParent(QPoint(50, 40)), QPoint(0, -10));
1778  QCOMPARE(subWindow1->mapFromParent(QPoint(150, 150)), QPoint(100, 100));
1779  QCOMPARE(subWindow1->mapFromParent(QPoint(160, 150)), QPoint(110, 100));
1780  QCOMPARE(subWindow1->mapFromParent(QPoint(150, 160)), QPoint(100, 110));
1781 
1782  // subsubwindow
1783  QCOMPARE(subSubWindow->mapToGlobal(QPoint(0, 0)), QPoint(160, 160));
1784  QCOMPARE(subSubWindow->mapToGlobal(QPoint(10, 0)), QPoint(170, 160));
1785  QCOMPARE(subSubWindow->mapToGlobal(QPoint(0, 10)), QPoint(160, 170));
1786  QCOMPARE(subSubWindow->mapToGlobal(QPoint(-10, 0)), QPoint(150, 160));
1787  QCOMPARE(subSubWindow->mapToGlobal(QPoint(0, -10)), QPoint(160, 150));
1788  QCOMPARE(subSubWindow->mapToGlobal(QPoint(100, 100)), QPoint(260, 260));
1789  QCOMPARE(subSubWindow->mapToGlobal(QPoint(110, 100)), QPoint(270, 260));
1790  QCOMPARE(subSubWindow->mapToGlobal(QPoint(100, 110)), QPoint(260, 270));
1791  QCOMPARE(subSubWindow->mapFromGlobal(QPoint(160, 160)), QPoint(0, 0));
1792  QCOMPARE(subSubWindow->mapFromGlobal(QPoint(170, 160)), QPoint(10, 0));
1793  QCOMPARE(subSubWindow->mapFromGlobal(QPoint(160, 170)), QPoint(0, 10));
1794  QCOMPARE(subSubWindow->mapFromGlobal(QPoint(150, 160)), QPoint(-10, 0));
1795  QCOMPARE(subSubWindow->mapFromGlobal(QPoint(160, 150)), QPoint(0, -10));
1796  QCOMPARE(subSubWindow->mapFromGlobal(QPoint(260, 260)), QPoint(100, 100));
1797  QCOMPARE(subSubWindow->mapFromGlobal(QPoint(270, 260)), QPoint(110, 100));
1798  QCOMPARE(subSubWindow->mapFromGlobal(QPoint(260, 270)), QPoint(100, 110));
1799  QCOMPARE(subSubWindow->mapToParent(QPoint(0, 0)), QPoint(10, 10));
1800  QCOMPARE(subSubWindow->mapToParent(QPoint(10, 0)), QPoint(20, 10));
1801  QCOMPARE(subSubWindow->mapToParent(QPoint(0, 10)), QPoint(10, 20));
1802  QCOMPARE(subSubWindow->mapToParent(QPoint(-10, 0)), QPoint(0, 10));
1803  QCOMPARE(subSubWindow->mapToParent(QPoint(0, -10)), QPoint(10, 0));
1804  QCOMPARE(subSubWindow->mapToParent(QPoint(100, 100)), QPoint(110, 110));
1805  QCOMPARE(subSubWindow->mapToParent(QPoint(110, 100)), QPoint(120, 110));
1806  QCOMPARE(subSubWindow->mapToParent(QPoint(100, 110)), QPoint(110, 120));
1807  QCOMPARE(subSubWindow->mapFromParent(QPoint(10, 10)), QPoint(0, 0));
1808  QCOMPARE(subSubWindow->mapFromParent(QPoint(20, 10)), QPoint(10, 0));
1809  QCOMPARE(subSubWindow->mapFromParent(QPoint(10, 20)), QPoint(0, 10));
1810  QCOMPARE(subSubWindow->mapFromParent(QPoint(0, 10)), QPoint(-10, 0));
1811  QCOMPARE(subSubWindow->mapFromParent(QPoint(10, 0)), QPoint(0, -10));
1812  QCOMPARE(subSubWindow->mapFromParent(QPoint(110, 110)), QPoint(100, 100));
1813  QCOMPARE(subSubWindow->mapFromParent(QPoint(120, 110)), QPoint(110, 100));
1814  QCOMPARE(subSubWindow->mapFromParent(QPoint(110, 120)), QPoint(100, 110));
1815 }
1816 
1817 void tst_QWidget::focusChainOnReparent()
1818 {
1819  QWidget window;
1820  QWidget *child1 = new QWidget(&window);
1821  QWidget *child2 = new QWidget(&window);
1822  QWidget *child3 = new QWidget(&window);
1823  QWidget *child21 = new QWidget(child2);
1824  QWidget *child22 = new QWidget(child2);
1825  QWidget *child4 = new QWidget(&window);
1826 
1827  QWidget *expectedOriginalChain[8] = {&window, child1, child2, child3, child21, child22, child4, &window};
1828  QWidget *w = &window;
1829  for (auto expectedOriginal : expectedOriginalChain) {
1830  QCOMPARE(w, expectedOriginal);
1831  w = w->nextInFocusChain();
1832  }
1833  for (int i = 7; i >= 0; --i) {
1834  w = w->previousInFocusChain();
1835  QCOMPARE(w, expectedOriginalChain[i]);
1836  }
1837 
1838  QWidget window2;
1839  child2->setParent(&window2);
1840 
1841  QWidget *expectedNewChain[5] = {&window2, child2, child21, child22, &window2};
1842  w = &window2;
1843  for (auto expectedNew : expectedNewChain) {
1844  QCOMPARE(w, expectedNew);
1845  w = w->nextInFocusChain();
1846  }
1847  for (int i = 4; i >= 0; --i) {
1848  w = w->previousInFocusChain();
1849  QCOMPARE(w, expectedNewChain[i]);
1850  }
1851 
1852  QWidget *expectedOldChain[5] = {&window, child1, child3, child4, &window};
1853  w = &window;
1854  for (auto expectedOld : expectedOldChain) {
1855  QCOMPARE(w, expectedOld);
1856  w = w->nextInFocusChain();
1857  }
1858  for (int i = 4; i >= 0; --i) {
1859  w = w->previousInFocusChain();
1860  QCOMPARE(w, expectedOldChain[i]);
1861  }
1862 }
1863 
1864 
1865 void tst_QWidget::focusChainOnHide()
1866 {
1867  // focus should move to the next widget in the focus chain when we hide it.
1869  parent->setObjectName(QLatin1String("focusChainOnHide"));
1870  parent->resize(200, 200);
1871  parent->setWindowTitle(parent->objectName());
1872  parent->setFocusPolicy(Qt::StrongFocus);
1873  QWidget *child = new QWidget(parent.data());
1874  child->setObjectName(QLatin1String("child"));
1875  child->setFocusPolicy(Qt::StrongFocus);
1877 
1878  parent->show();
1880  child->activateWindow();
1881  child->setFocus();
1882 
1883  QTRY_VERIFY(child->hasFocus());
1884  child->hide();
1885 
1886  QTRY_VERIFY(parent->hasFocus());
1888 }
1889 
1890 class Container : public QWidget
1891 {
1892 public:
1893  QVBoxLayout* box;
1894 
1896  {
1897  box = new QVBoxLayout(this);
1898  //(new QVBoxLayout(this))->setAutoAdd(true);
1899  }
1900 
1901  void tab()
1902  {
1903  focusNextPrevChild(true);
1904  }
1905 
1906  void backTab()
1907  {
1908  focusNextPrevChild(false);
1909  }
1910 };
1911 
1912 class Composite : public QFrame
1913 {
1914 public:
1915  explicit Composite(QWidget *parent = nullptr, const QString &name = QString())
1916  : QFrame(parent)
1917  {
1919 
1920  lineEdit1 = new QLineEdit;
1921  lineEdit2 = new QLineEdit;
1922  lineEdit3 = new QLineEdit;
1923  lineEdit3->setEnabled(false);
1924 
1925  QHBoxLayout* hbox = new QHBoxLayout(this);
1926  hbox->addWidget(lineEdit1);
1927  hbox->addWidget(lineEdit2);
1928  hbox->addWidget(lineEdit3);
1929  }
1930 
1931 public:
1935 };
1936 
1937 void tst_QWidget::defaultTabOrder()
1938 {
1940  QSKIP("Wayland: This fails. Figure out why.");
1941 
1942  const int compositeCount = 2;
1943  Container container;
1944  Composite *composite[compositeCount];
1945 
1946  QLineEdit *firstEdit = new QLineEdit;
1947  container.box->addWidget(firstEdit);
1948 
1949  for (int i = 0; i < compositeCount; i++) {
1950  composite[i] = new Composite();
1951  container.box->addWidget(composite[i]);
1952  }
1953 
1954  QLineEdit *lastEdit = new QLineEdit();
1955  container.box->addWidget(lastEdit);
1956 
1957  container.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
1958  container.show();
1959  container.activateWindow();
1960  QApplication::setActiveWindow(&container);
1961  QVERIFY(QTest::qWaitForWindowActive(&container));
1962 
1963  QTRY_VERIFY(firstEdit->hasFocus());
1964 
1965  // Check that focus moves between the line edits when we tab forward
1966  for (int i = 0; i < compositeCount; ++i) {
1967  container.tab();
1968  QVERIFY(composite[i]->lineEdit1->hasFocus());
1969  QVERIFY(!composite[i]->lineEdit2->hasFocus());
1970  container.tab();
1971  QVERIFY(!composite[i]->lineEdit1->hasFocus());
1972  QVERIFY(composite[i]->lineEdit2->hasFocus());
1973  }
1974 
1975  container.tab();
1976  QVERIFY(lastEdit->hasFocus());
1977 
1978  // Check that focus moves between the line edits in reverse
1979  // order when we tab backwards
1980  for (int i = compositeCount - 1; i >= 0; --i) {
1981  container.backTab();
1982  QVERIFY(!composite[i]->lineEdit1->hasFocus());
1983  QVERIFY(composite[i]->lineEdit2->hasFocus());
1984 
1985  container.backTab();
1986  QVERIFY(composite[i]->lineEdit1->hasFocus());
1987  QVERIFY(!composite[i]->lineEdit2->hasFocus());
1988  }
1989 
1990  container.backTab();
1991  QVERIFY(firstEdit->hasFocus());
1992 }
1993 
1994 void tst_QWidget::reverseTabOrder()
1995 {
1997  QSKIP("Wayland: This fails. Figure out why.");
1998 
1999  const int compositeCount = 2;
2000  Container container;
2001  container.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
2002  Composite* composite[compositeCount];
2003 
2004  QLineEdit *firstEdit = new QLineEdit();
2005  container.box->addWidget(firstEdit);
2006 
2007  for (int i = 0; i < compositeCount; i++) {
2008  composite[i] = new Composite();
2009  container.box->addWidget(composite[i]);
2010  }
2011 
2012  QLineEdit *lastEdit = new QLineEdit();
2013  container.box->addWidget(lastEdit);
2014 
2015  // Reverse tab order inside each composite
2016  for (int i = 0; i < compositeCount; ++i)
2017  QWidget::setTabOrder(composite[i]->lineEdit2, composite[i]->lineEdit1);
2018 
2019  container.show();
2020  container.activateWindow();
2021  QApplication::setActiveWindow(&container);
2022  QVERIFY(QTest::qWaitForWindowActive(&container));
2023 
2024  QTRY_VERIFY(firstEdit->hasFocus());
2025 
2026  // Check that focus moves in reverse order when tabbing inside the composites
2027  // (but in the correct order when tabbing between them)
2028  for (int i = 0; i < compositeCount; ++i) {
2029  container.tab();
2030  QVERIFY(!composite[i]->lineEdit1->hasFocus());
2031  QVERIFY(composite[i]->lineEdit2->hasFocus());
2032  container.tab();
2033  QVERIFY(composite[i]->lineEdit1->hasFocus());
2034  QVERIFY(!composite[i]->lineEdit2->hasFocus());
2035  }
2036 
2037  container.tab();
2038  QVERIFY(lastEdit->hasFocus());
2039 
2040  // Check that focus moves in "normal" order when tabbing backwards inside the
2041  // composites (since backwards of reversed order cancels each other out),
2042  // but in the reverse order when tabbing between them.
2043  for (int i = compositeCount - 1; i >= 0; --i) {
2044  container.backTab();
2045  QVERIFY(composite[i]->lineEdit1->hasFocus());
2046  QVERIFY(!composite[i]->lineEdit2->hasFocus());
2047  container.backTab();
2048  QVERIFY(!composite[i]->lineEdit1->hasFocus());
2049  QVERIFY(composite[i]->lineEdit2->hasFocus());
2050  }
2051 
2052  container.backTab();
2053  QVERIFY(firstEdit->hasFocus());
2054 }
2055 
2056 void tst_QWidget::tabOrderWithProxy()
2057 {
2059  QSKIP("Wayland: This fails. Figure out why.");
2060 
2061  const int compositeCount = 2;
2062  Container container;
2063  container.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
2064  Composite* composite[compositeCount];
2065 
2066  QLineEdit *firstEdit = new QLineEdit();
2067  container.box->addWidget(firstEdit);
2068 
2069  for (int i = 0; i < compositeCount; i++) {
2070  composite[i] = new Composite();
2071  container.box->addWidget(composite[i]);
2072 
2073  // Set second child as focus proxy
2074  composite[i]->setFocusPolicy(Qt::StrongFocus);
2075  composite[i]->setFocusProxy(composite[i]->lineEdit2);
2076  }
2077 
2078  QLineEdit *lastEdit = new QLineEdit();
2079  container.box->addWidget(lastEdit);
2080 
2081  container.show();
2082  container.activateWindow();
2083  QApplication::setActiveWindow(&container);
2084  QVERIFY(QTest::qWaitForWindowActive(&container));
2085 
2086  QTRY_VERIFY(firstEdit->hasFocus());
2087 
2088  // Check that focus moves between the second line edits
2089  // (the focus proxies) when we tab forward
2090  for (int i = 0; i < compositeCount; ++i) {
2091  container.tab();
2092  QVERIFY(!composite[i]->lineEdit1->hasFocus());
2093  QVERIFY(composite[i]->lineEdit2->hasFocus());
2094  }
2095 
2096  container.tab();
2097  QVERIFY(lastEdit->hasFocus());
2098 
2099  // Check that focus moves between the line edits
2100  // in reverse order when we tab backwards.
2101  // Note that in this case, the focus proxies should not
2102  // be taken into consideration, since they only take
2103  // effect when tabbing forward
2104  for (int i = compositeCount - 1; i >= 0; --i) {
2105  container.backTab();
2106  QVERIFY(!composite[i]->lineEdit1->hasFocus());
2107  QVERIFY(composite[i]->lineEdit2->hasFocus());
2108  container.backTab();
2109  QVERIFY(composite[i]->lineEdit1->hasFocus());
2110  QVERIFY(!composite[i]->lineEdit2->hasFocus());
2111  }
2112 
2113  container.backTab();
2114  QVERIFY(firstEdit->hasFocus());
2115 }
2116 
2117 void tst_QWidget::tabOrderWithProxyDisabled()
2118 {
2119  Container container;
2120  container.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
2121 
2122  QLineEdit lineEdit1;
2123  lineEdit1.setObjectName("lineEdit1");
2124 
2125  QWidget containingWidget;
2126  containingWidget.setFocusPolicy(Qt::StrongFocus);
2127  auto *containingLayout = new QVBoxLayout;
2128  QLineEdit lineEdit2;
2129  lineEdit2.setObjectName("lineEdit2");
2130  QLineEdit lineEdit3;
2131  lineEdit3.setObjectName("lineEdit3");
2132  containingLayout->addWidget(&lineEdit2);
2133  containingLayout->addWidget(&lineEdit3);
2134  containingWidget.setLayout(containingLayout);
2135  containingWidget.setFocusProxy(&lineEdit2);
2136  lineEdit2.setEnabled(false);
2137 
2138  container.box->addWidget(&lineEdit1);
2139  container.box->addWidget(&containingWidget);
2140 
2141  container.show();
2142  container.activateWindow();
2143 
2144  QApplication::setActiveWindow(&container);
2145  if (!QTest::qWaitForWindowActive(&container))
2146  QSKIP("Window failed to activate, skipping test");
2147 
2148  QVERIFY2(lineEdit1.hasFocus(),
2149  qPrintable(QApplication::focusWidget()->objectName()));
2150  container.tab();
2151  QVERIFY2(!lineEdit2.hasFocus(),
2152  qPrintable(QApplication::focusWidget()->objectName()));
2153  QVERIFY2(lineEdit3.hasFocus(),
2154  qPrintable(QApplication::focusWidget()->objectName()));
2155  container.tab();
2156  QVERIFY2(lineEdit1.hasFocus(),
2157  qPrintable(QApplication::focusWidget()->objectName()));
2158  container.backTab();
2159  QVERIFY2(lineEdit3.hasFocus(),
2160  qPrintable(QApplication::focusWidget()->objectName()));
2161  container.backTab();
2162  QVERIFY2(!lineEdit2.hasFocus(),
2163  qPrintable(QApplication::focusWidget()->objectName()));
2164  QVERIFY2(lineEdit1.hasFocus(),
2165  qPrintable(QApplication::focusWidget()->objectName()));
2166 }
2167 
2168 void tst_QWidget::tabOrderWithCompoundWidgets()
2169 {
2171  QSKIP("Wayland: This fails. Figure out why.");
2172 
2173  const int compositeCount = 4;
2174  Container container;
2175  container.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
2176  Composite *composite[compositeCount];
2177 
2178  QLineEdit *firstEdit = new QLineEdit();
2179  container.box->addWidget(firstEdit);
2180 
2181  for (int i = 0; i < compositeCount; i++) {
2182  composite[i] = new Composite(nullptr, QStringLiteral("Composite: ") + QString::number(i));
2183  container.box->addWidget(composite[i]);
2184 
2185  // Let the composite handle focus, and set a child as focus proxy (use the second child, just
2186  // to ensure that we don't just tab to the first child by coinsidence). This will make the
2187  // composite "compound". Also enable the last line edit to have a bit more data to check when
2188  // tabbing forwards.
2189  composite[i]->setFocusPolicy(Qt::StrongFocus);
2190  composite[i]->setFocusProxy(composite[i]->lineEdit2);
2191  composite[i]->lineEdit3->setEnabled(true);
2192  }
2193 
2194  QLineEdit *lastEdit = new QLineEdit();
2195  container.box->addWidget(lastEdit);
2196 
2197  // Reverse tab order between each composite
2198  // (but not inside them), including first and last line edit.
2199  // The result should not affect local tab order inside each
2200  // composite, only between them.
2201  QWidget::setTabOrder(lastEdit, composite[compositeCount - 1]);
2202  for (int i = compositeCount - 1; i >= 1; --i)
2203  QWidget::setTabOrder(composite[i], composite[i-1]);
2204  QWidget::setTabOrder(composite[0], firstEdit);
2205 
2206  container.show();
2207  container.activateWindow();
2208  QApplication::setActiveWindow(&container);
2209  QVERIFY(QTest::qWaitForWindowActive(&container));
2210 
2211  lastEdit->setFocus();
2212  QTRY_VERIFY(lastEdit->hasFocus());
2213 
2214  // Check that focus moves between the line edits in the normal
2215  // order when tabbing inside each compound, but in the reverse
2216  // order when tabbing between them. Since the composites have
2217  // lineEdit2 as focus proxy, lineEdit2 will be the first with focus
2218  // when the compound gets focus, and lineEdit1 will therefore be skipped.
2219  for (int i = compositeCount - 1; i >= 0; --i) {
2220  container.tab();
2221  Composite *c = composite[i];
2222  QVERIFY(!c->lineEdit1->hasFocus());
2223  QVERIFY(c->lineEdit2->hasFocus());
2224  QVERIFY(!c->lineEdit3->hasFocus());
2225  container.tab();
2226  QVERIFY(!c->lineEdit1->hasFocus());
2227  QVERIFY(!c->lineEdit2->hasFocus());
2228  QVERIFY(c->lineEdit3->hasFocus());
2229  }
2230 
2231  container.tab();
2232  QVERIFY(firstEdit->hasFocus());
2233 
2234  // Check that focus moves in reverse order when backTab inside the composites, but
2235  // in the 'correct' order when backTab between them (since the composites are in reverse tab
2236  // order from before, which cancels it out). Note that when we backtab into a compound, we start
2237  // at lineEdit3 rather than the focus proxy, since that is the reverse of what happens when we tab
2238  // forward. And this time we will also backtab to lineEdit1, since there is no focus proxy that interferes.
2239  for (int i = 0; i < compositeCount; ++i) {
2240  container.backTab();
2241  Composite *c = composite[i];
2242  QVERIFY(!c->lineEdit1->hasFocus());
2243  QVERIFY(!c->lineEdit2->hasFocus());
2244  QVERIFY(c->lineEdit3->hasFocus());
2245  container.backTab();
2246  QVERIFY(!c->lineEdit1->hasFocus());
2247  QVERIFY(c->lineEdit2->hasFocus());
2248  QVERIFY(!c->lineEdit3->hasFocus());
2249  container.backTab();
2250  QVERIFY(c->lineEdit1->hasFocus());
2251  QVERIFY(!c->lineEdit2->hasFocus());
2252  QVERIFY(!c->lineEdit3->hasFocus());
2253  }
2254 
2255  container.backTab();
2256  QVERIFY(lastEdit->hasFocus());
2257 }
2258 
2259 static QList<QWidget *> getFocusChain(QWidget *start, bool bForward)
2260 {
2262  QWidget *cur = start;
2263  do {
2264  ret += cur;
2265  auto widgetPrivate = static_cast<QWidgetPrivate *>(qt_widget_private(cur));
2266  cur = bForward ? widgetPrivate->focus_next : widgetPrivate->focus_prev;
2267  } while (cur != start);
2268  return ret;
2269 }
2270 
2271 //#define DEBUG_FOCUS_CHAIN
2272 static void dumpFocusChain(QWidget *start, bool bForward, const char *desc = nullptr)
2273 {
2274 #ifdef DEBUG_FOCUS_CHAIN
2275  qDebug() << "Dump focus chain, start:" << start << "isForward:" << bForward << desc;
2276  QWidget *cur = start;
2277  do {
2278  qDebug() << cur;
2279  auto widgetPrivate = static_cast<QWidgetPrivate *>(qt_widget_private(cur));
2280  cur = bForward ? widgetPrivate->focus_next : widgetPrivate->focus_prev;
2281  } while (cur != start);
2282 #else
2283  Q_UNUSED(start);
2284  Q_UNUSED(bForward);
2285  Q_UNUSED(desc);
2286 #endif
2287 }
2288 
2289 void tst_QWidget::tabOrderWithCompoundWidgetsNoFocusPolicy()
2290 {
2291  Container container;
2292  container.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
2293  QSpinBox spinbox1;
2294  spinbox1.setObjectName("spinbox1");
2295  QSpinBox spinbox2;
2296  spinbox2.setObjectName("spinbox2");
2297  QSpinBox spinbox3;
2298  spinbox3.setObjectName("spinbox3");
2299 
2300  spinbox1.setFocusPolicy(Qt::StrongFocus);
2301  spinbox2.setFocusPolicy(Qt::NoFocus);
2302  spinbox3.setFocusPolicy(Qt::StrongFocus);
2303  container.box->addWidget(&spinbox1);
2304  container.box->addWidget(&spinbox2);
2305  container.box->addWidget(&spinbox3);
2306 
2307  container.show();
2308  container.activateWindow();
2309 
2310  QApplication::setActiveWindow(&container);
2311  if (!QTest::qWaitForWindowActive(&container))
2312  QSKIP("Window failed to activate, skipping test");
2313 
2314  QVERIFY2(spinbox1.hasFocus(),
2315  qPrintable(QApplication::focusWidget()->objectName()));
2316  container.tab();
2317  QVERIFY2(!spinbox2.hasFocus(),
2318  qPrintable(QApplication::focusWidget()->objectName()));
2319  QVERIFY2(spinbox3.hasFocus(),
2320  qPrintable(QApplication::focusWidget()->objectName()));
2321  container.tab();
2322  QVERIFY2(spinbox1.hasFocus(),
2323  qPrintable(QApplication::focusWidget()->objectName()));
2324  container.backTab();
2325  QVERIFY2(spinbox3.hasFocus(),
2326  qPrintable(QApplication::focusWidget()->objectName()));
2327  container.backTab();
2328  QVERIFY2(!spinbox2.hasFocus(),
2329  qPrintable(QApplication::focusWidget()->objectName()));
2330  QVERIFY2(spinbox1.hasFocus(),
2331  qPrintable(QApplication::focusWidget()->objectName()));
2332 }
2333 
2334 void tst_QWidget::tabOrderNoChange()
2335 {
2336  QWidget w;
2337  auto *verticalLayout = new QVBoxLayout(&w);
2338  auto *tabWidget = new QTabWidget(&w);
2339  auto *tv = new QTreeView(tabWidget);
2340  tabWidget->addTab(tv, QStringLiteral("Tab 1"));
2341  verticalLayout->addWidget(tabWidget);
2342 
2343  const auto focusChainForward = getFocusChain(&w, true);
2344  const auto focusChainBackward = getFocusChain(&w, false);
2345  dumpFocusChain(&w, true);
2346  QWidget::setTabOrder(tabWidget, tv);
2347  dumpFocusChain(&w, true);
2348  QCOMPARE(focusChainForward, getFocusChain(&w, true));
2349  QCOMPARE(focusChainBackward, getFocusChain(&w, false));
2350 }
2351 
2352 void tst_QWidget::tabOrderNoChange2()
2353 {
2354  QWidget w;
2355  auto *verticalLayout = new QVBoxLayout(&w);
2356  auto *tabWidget = new QTabWidget(&w);
2357  tabWidget->setObjectName("tabWidget");
2358  verticalLayout->addWidget(tabWidget);
2359 
2360  auto *tab1 = new QWidget(tabWidget);
2361  tab1->setObjectName("tab1");
2362  auto *vLay1 = new QVBoxLayout(tab1);
2363  auto *le1 = new QLineEdit(tab1);
2364  le1->setObjectName("le1");
2365  auto *le2 = new QLineEdit(tab1);
2366  le2->setObjectName("le2");
2367  vLay1->addWidget(le1);
2368  vLay1->addWidget(le2);
2369  tabWidget->addTab(tab1, QStringLiteral("Tab 1"));
2370 
2371  auto *tab2 = new QWidget(tabWidget);
2372  tab2->setObjectName("tab2");
2373  auto *vLay2 = new QVBoxLayout(tab2);
2374  auto *le3 = new QLineEdit(tab2);
2375  le3->setObjectName("le3");
2376  auto *le4 = new QLineEdit(tab2);
2377  le4->setObjectName("le4");
2378  vLay2->addWidget(le3);
2379  vLay2->addWidget(le4);
2380  tabWidget->addTab(tab2, QStringLiteral("Tab 2"));
2381 
2382  const auto focusChainForward = getFocusChain(&w, true);
2383  const auto focusChainBackward = getFocusChain(&w, false);
2384  dumpFocusChain(&w, true);
2385  dumpFocusChain(&w, false);
2386  // this will screw up the focus chain order without visible changes,
2387  // so don't call it here for the simplicity of the test
2388  //QWidget::setTabOrder(tabWidget, le1);
2389 
2390  QWidget::setTabOrder(le1, le2);
2391  dumpFocusChain(&w, true, "QWidget::setTabOrder(le1, le2)");
2392  QWidget::setTabOrder(le2, le3);
2393  dumpFocusChain(&w, true, "QWidget::setTabOrder(le2, le3)");
2394  QWidget::setTabOrder(le3, le4);
2395  dumpFocusChain(&w, true, "QWidget::setTabOrder(le3, le4)");
2396  QWidget::setTabOrder(le4, tabWidget);
2397  dumpFocusChain(&w, true, "QWidget::setTabOrder(le4, tabWidget)");
2398  dumpFocusChain(&w, false);
2399 
2400  QCOMPARE(focusChainForward, getFocusChain(&w, true));
2401  QCOMPARE(focusChainBackward, getFocusChain(&w, false));
2402 }
2403 
2404 void tst_QWidget::appFocusWidgetWithFocusProxyLater()
2405 {
2407  QSKIP("Wayland: This fails. Figure out why.");
2408 
2409  // Given a lineedit without a focus proxy
2410  QWidget window;
2411  window.setWindowTitle(QTest::currentTestFunction());
2412  QLineEdit *lineEditFocusProxy = new QLineEdit(&window);
2414  lineEdit->setFocus();
2415  window.show();
2419 
2420  // When setting a focus proxy for the focus widget (like QWebEngineView does)
2421  lineEdit->setFocusProxy(lineEditFocusProxy);
2422 
2423  // Then the focus widget should be updated
2424  QCOMPARE(QApplication::focusWidget(), lineEditFocusProxy);
2425 
2426  // So that deleting the lineEdit and later the window, doesn't crash
2427  delete lineEdit;
2428  QCOMPARE(QApplication::focusWidget(), nullptr);
2429 }
2430 
2431 void tst_QWidget::appFocusWidgetWhenLosingFocusProxy()
2432 {
2434  QSKIP("Wayland: This fails. Figure out why.");
2435 
2436  // Given a lineedit with a focus proxy
2437  QWidget window;
2438  window.setWindowTitle(QTest::currentTestFunction());
2439  QLineEdit *lineEditFocusProxy = new QLineEdit(&window);
2441  lineEdit->setFocusProxy(lineEditFocusProxy);
2442  lineEdit->setFocus();
2443  window.show();
2446  QCOMPARE(QApplication::focusWidget(), lineEditFocusProxy);
2448  QVERIFY(lineEditFocusProxy->hasFocus());
2449 
2450  // When unsetting the focus proxy
2451  lineEdit->setFocusProxy(nullptr);
2452 
2453  // then the focus widget should not change
2454  QCOMPARE(QApplication::focusWidget(), lineEditFocusProxy);
2455  QVERIFY(!lineEdit->hasFocus());
2456  QVERIFY(lineEditFocusProxy->hasFocus());
2457 }
2458 
2459 void tst_QWidget::explicitTabOrderWithComplexWidget()
2460 {
2461  // Check that handling tab/backtab with a widget comprimised of other widgets
2462  // handles tabbing correctly
2463  Container window;
2464  auto lineEditOne = new QLineEdit;
2465  window.box->addWidget(lineEditOne);
2466  auto lineEditTwo = new QLineEdit;
2467  window.box->addWidget(lineEditTwo);
2468  QWidget::setTabOrder(lineEditOne, lineEditTwo);
2469  lineEditOne->setFocus();
2470  window.show();
2473  QTRY_COMPARE(QApplication::focusWidget(), lineEditOne);
2474 
2475  window.tab();
2476  QTRY_COMPARE(QApplication::focusWidget(), lineEditTwo);
2477  window.tab();
2478  QTRY_COMPARE(QApplication::focusWidget(), lineEditOne);
2479  window.backTab();
2480  QTRY_COMPARE(QApplication::focusWidget(), lineEditTwo);
2481  window.backTab();
2482  QTRY_COMPARE(QApplication::focusWidget(), lineEditOne);
2483 }
2484 
2485 void tst_QWidget::explicitTabOrderWithSpinBox_QTBUG81097()
2486 {
2487  // Check the special case of QAbstractSpinBox-like widgets, that have a
2488  // child widget with a focusPolicy() set to its parent.
2489  Container window;
2490  auto spinBoxOne = new QDoubleSpinBox;
2491  auto spinBoxTwo = new QDoubleSpinBox;
2492  auto lineEdit = new QLineEdit;
2493  window.box->addWidget(spinBoxOne);
2494  window.box->addWidget(spinBoxTwo);
2495  window.box->addWidget(lineEdit);
2496  QWidget::setTabOrder(spinBoxOne, spinBoxTwo);
2497  QWidget::setTabOrder(spinBoxTwo, lineEdit);
2498  spinBoxOne->setFocus();
2499  window.show();
2502  QTRY_COMPARE(QApplication::focusWidget(), spinBoxOne);
2503 
2504  window.tab();
2505  QTRY_COMPARE(QApplication::focusWidget(), spinBoxTwo);
2506  window.tab();
2508  window.backTab();
2509  QTRY_COMPARE(QApplication::focusWidget(), spinBoxTwo);
2510  window.backTab();
2511  QTRY_COMPARE(QApplication::focusWidget(), spinBoxOne);
2512  window.backTab();
2514 }
2515 
2516 #if defined(Q_OS_WIN)
2517 void tst_QWidget::activation()
2518 {
2520 
2521  QWidget widget1;
2522  widget1.setObjectName("activation-Widget1");
2523  widget1.setWindowTitle(widget1.objectName());
2524 
2525  QWidget widget2;
2526  widget1.setObjectName("activation-Widget2");
2527  widget1.setWindowTitle(widget2.objectName());
2528 
2529  widget1.show();
2530  widget2.show();
2531 
2533  widget2.showMinimized();
2534 
2536  widget2.showMaximized();
2538  widget2.showMinimized();
2540  widget2.showNormal();
2542  widget2.hide();
2544 }
2545 #endif // Q_OS_WIN
2546 
2547 struct WindowStateChangeWatcher : public QObject
2548 {
2550  {
2551  Q_ASSERT(widget->window()->windowHandle());
2552  widget->window()->windowHandle()->installEventFilter(this);
2553  lastWindowStates = widget->window()->windowHandle()->windowState();
2554  }
2555  Qt::WindowStates lastWindowStates;
2556 protected:
2557  bool eventFilter(QObject *receiver, QEvent *event) override
2558  {
2559  if (event->type() == QEvent::WindowStateChange)
2560  lastWindowStates = static_cast<QWindow *>(receiver)->windowState();
2561  return QObject::eventFilter(receiver, event);
2562  }
2563 };
2564 
2565 void tst_QWidget::windowState()
2566 {
2567 #ifdef Q_OS_MACOS
2568  QSKIP("QTBUG-52974");
2569 #endif
2570 
2571  if (m_platform == QStringLiteral("xcb"))
2572  QSKIP("X11: Many window managers do not support window state properly, which causes this test to fail.");
2573  if (m_platform == QStringLiteral("wayland"))
2574  QSKIP("Wayland: This fails. Figure out why.");
2575 
2576  QPoint pos;
2577  QSize size = m_testWidgetSize;
2578  const Qt::WindowState defaultWidgetState =
2580  if (defaultWidgetState == Qt::WindowFullScreen)
2582  else if (defaultWidgetState == Qt::WindowMaximized)
2584  else
2585  pos = QPoint(10, 10);
2586 
2587  QWidget widget1;
2588  widget1.move(pos);
2589  widget1.resize(size);
2590  QCOMPARE(widget1.pos(), pos);
2591  QCOMPARE(widget1.size(), size);
2592  QTest::qWait(100);
2593  widget1.setObjectName(QStringLiteral("windowState-Widget1"));
2594  widget1.setWindowTitle(widget1.objectName());
2595  QCOMPARE(widget1.pos(), pos);
2596  QCOMPARE(widget1.size(), size);
2597 
2598 #define VERIFY_STATE(s) \
2599  QCOMPARE(int(widget1.windowState() & stateMask), int(s)); \
2600  QCOMPARE(int(widget1.windowHandle()->windowStates() & stateMask), int(s))
2601 
2603 
2604  widget1.setWindowState(Qt::WindowMaximized);
2605  QTest::qWait(100);
2607  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMaximized);
2608 
2609  widget1.setVisible(true);
2610  QTest::qWait(100);
2612  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMaximized);
2613 
2614  widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized);
2615  QTest::qWait(100);
2616  QVERIFY(!(widget1.windowState() & Qt::WindowMaximized));
2617  QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
2618  qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
2619  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
2620 
2621  widget1.setWindowState(Qt::WindowMinimized);
2622  QTest::qWait(100);
2624  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMinimized);
2625 
2626  widget1.setWindowState(widget1.windowState() | Qt::WindowMaximized);
2627  QTest::qWait(100);
2629  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMinimized);
2630 
2631  widget1.setWindowState(widget1.windowState() ^ Qt::WindowMinimized);
2632  QTest::qWait(100);
2634  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMaximized);
2635 
2636  widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized);
2637  QTest::qWait(100);
2638  QVERIFY(!(widget1.windowState() & (Qt::WindowMinimized|Qt::WindowMaximized)));
2639  QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
2640  qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
2641  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
2642 
2643  widget1.setWindowState(Qt::WindowFullScreen);
2644  QTest::qWait(100);
2646  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowFullScreen);
2647 
2648  widget1.setWindowState(widget1.windowState() ^ Qt::WindowMinimized);
2649  QTest::qWait(100);
2651  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMinimized);
2652 
2653  widget1.setWindowState(widget1.windowState() ^ Qt::WindowMinimized);
2654  QTest::qWait(100);
2656  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowFullScreen);
2657 
2658  widget1.setWindowState(Qt::WindowNoState);
2659  QTest::qWait(100);
2661  QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
2662  qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
2663  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
2664 
2665  widget1.setWindowState(Qt::WindowFullScreen);
2666  QTest::qWait(100);
2668  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowFullScreen);
2669 
2670  widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized);
2671  QTest::qWait(100);
2673  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowFullScreen);
2674 
2675  widget1.setWindowState(widget1.windowState() ^ Qt::WindowMinimized);
2676  QTest::qWait(100);
2678  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMinimized);
2679 
2680  widget1.setWindowState(widget1.windowState() ^ Qt::WindowMinimized);
2681  QTest::qWait(100);
2683  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowFullScreen);
2684 
2685  widget1.setWindowState(widget1.windowState() ^ Qt::WindowFullScreen);
2686  QTest::qWait(100);
2688  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowMaximized);
2689 
2690  widget1.setWindowState(widget1.windowState() ^ Qt::WindowMaximized);
2691  QTest::qWait(100);
2692  QVERIFY(!(widget1.windowState() & stateMask));
2693  QCOMPARE(widget1.windowHandle()->windowState(), Qt::WindowNoState);
2694 
2695  QTRY_VERIFY2(HighDpi::fuzzyCompare(widget1.pos(), pos, m_fuzz),
2696  qPrintable(HighDpi::msgPointMismatch(widget1.pos(), pos)));
2697  QTRY_COMPARE(widget1.size(), size);
2698 }
2699 
2700 void tst_QWidget::showMaximized()
2701 {
2702  QWidget plain;
2703  QHBoxLayout *layout;
2704  layout = new QHBoxLayout;
2705  QWidget layouted;
2706  QLineEdit le;
2707  QLineEdit le2;
2708  QLineEdit le3;
2709 
2710  layout->addWidget(&le);
2711  layout->addWidget(&le2);
2712  layout->addWidget(&le3);
2713 
2714  layouted.setLayout(layout);
2715 
2716  plain.showMaximized();
2717  QVERIFY(plain.windowState() & Qt::WindowMaximized);
2718 
2719  plain.showNormal();
2720  QVERIFY(!(plain.windowState() & Qt::WindowMaximized));
2721 
2722  layouted.showMaximized();
2723  QVERIFY(layouted.windowState() & Qt::WindowMaximized);
2724 
2725  layouted.showNormal();
2726  QVERIFY(!(layouted.windowState() & Qt::WindowMaximized));
2727 
2728  // ### fixme: embedded may choose a different size to fit on the screen.
2729  if (layouted.size() != layouted.sizeHint())
2730  QEXPECT_FAIL("", "QTBUG-22326", Continue);
2731  QCOMPARE(layouted.size(), layouted.sizeHint());
2732 
2733  layouted.showMaximized();
2734  QVERIFY(layouted.isMaximized());
2735  QVERIFY(layouted.isVisible());
2736 
2737  layouted.hide();
2738  QVERIFY(layouted.isMaximized());
2739  QVERIFY(!layouted.isVisible());
2740 
2741  layouted.showMaximized();
2742  QVERIFY(layouted.isMaximized());
2743  QVERIFY(layouted.isVisible());
2744 
2745  layouted.showMinimized();
2746  QVERIFY(layouted.isMinimized());
2747  QVERIFY(layouted.isMaximized());
2748 
2749  layouted.showMaximized();
2750  QVERIFY(!layouted.isMinimized());
2751  QVERIFY(layouted.isMaximized());
2752  QVERIFY(layouted.isVisible());
2753 
2754  layouted.showMinimized();
2755  QVERIFY(layouted.isMinimized());
2756  QVERIFY(layouted.isMaximized());
2757 
2758  layouted.showMaximized();
2759  QVERIFY(!layouted.isMinimized());
2760  QVERIFY(layouted.isMaximized());
2761  QVERIFY(layouted.isVisible());
2762 
2763  {
2764  QWidget frame;
2765  QWidget widget(&frame);
2768  }
2769 
2770  {
2771  QWidget widget;
2772  setFrameless(&widget);
2773  widget.setGeometry(0, 0, 10, 10);
2775  QTRY_VERIFY(widget.size().width() > 20 && widget.size().height() > 20);
2776  }
2777 }
2778 
2779 void tst_QWidget::showFullScreen()
2780 {
2781 #ifdef Q_OS_MACOS
2782  QSKIP("QTBUG-52974");
2783 #endif
2784 
2785  QWidget plain;
2786  QHBoxLayout *layout;
2787  QWidget layouted;
2788  QLineEdit le;
2789  QLineEdit le2;
2790  QLineEdit le3;
2791  layout = new QHBoxLayout;
2792 
2793  layout->addWidget(&le);
2794  layout->addWidget(&le2);
2795  layout->addWidget(&le3);
2796 
2797  layouted.setLayout(layout);
2798 
2799  plain.showFullScreen();
2800  QVERIFY(plain.windowState() & Qt::WindowFullScreen);
2801  QVERIFY(plain.windowHandle());
2802  QVERIFY(plain.windowHandle()->screen());
2803  const QRect expectedFullScreenGeometry = plain.windowHandle()->screen()->geometry();
2804  QTRY_COMPARE(plain.geometry(), expectedFullScreenGeometry);
2805 
2806  plain.showNormal();
2807  QVERIFY(!(plain.windowState() & Qt::WindowFullScreen));
2808 
2809  layouted.showFullScreen();
2810  QVERIFY(layouted.windowState() & Qt::WindowFullScreen);
2811  QTRY_COMPARE(layouted.geometry(), expectedFullScreenGeometry);
2812 
2813  layouted.showNormal();
2814  QVERIFY(!(layouted.windowState() & Qt::WindowFullScreen));
2815 
2816  // ### fixme: embedded may choose a different size to fit on the screen.
2817  if (layouted.size() != layouted.sizeHint())
2818  QEXPECT_FAIL("", "QTBUG-22326", Continue);
2819  QCOMPARE(layouted.size(), layouted.sizeHint());
2820 
2821  layouted.showFullScreen();
2822  QVERIFY(layouted.isFullScreen());
2823  QVERIFY(layouted.isVisible());
2824  QTRY_COMPARE(layouted.geometry(), expectedFullScreenGeometry);
2825 
2826  layouted.hide();
2827  QVERIFY(layouted.isFullScreen());
2828  QVERIFY(!layouted.isVisible());
2829 
2830  layouted.showFullScreen();
2831  QVERIFY(layouted.isFullScreen());
2832  QVERIFY(layouted.isVisible());
2833  QTRY_COMPARE(layouted.geometry(), expectedFullScreenGeometry);
2834 
2835  layouted.showMinimized();
2836  QVERIFY(layouted.isMinimized());
2837  QVERIFY(layouted.isFullScreen());
2838 
2839  layouted.showFullScreen();
2840  QVERIFY(!layouted.isMinimized());
2841  QVERIFY(layouted.isFullScreen());
2842  QVERIFY(layouted.isVisible());
2843  QTRY_COMPARE(layouted.geometry(), expectedFullScreenGeometry);
2844 
2845  layouted.showMinimized();
2846  QVERIFY(layouted.isMinimized());
2847  QVERIFY(layouted.isFullScreen());
2848 
2849  layouted.showFullScreen();
2850  QVERIFY(!layouted.isMinimized());
2851  QVERIFY(layouted.isFullScreen());
2852  QVERIFY(layouted.isVisible());
2853  QTRY_COMPARE(layouted.geometry(), expectedFullScreenGeometry);
2854 
2855  {
2856  QWidget frame;
2857  QWidget widget(&frame);
2860  QTRY_COMPARE(layouted.geometry(), expectedFullScreenGeometry);
2861  }
2862 }
2863 
2864 class ResizeWidget : public QWidget {
2865 public:
2866  explicit ResizeWidget(QWidget *p = nullptr) : QWidget(p)
2867  {
2868  setObjectName(QLatin1String("ResizeWidget"));
2869  setWindowTitle(objectName());
2870  }
2871 protected:
2872  void resizeEvent(QResizeEvent *e) override
2873  {
2874  QCOMPARE(size(), e->size());
2876  }
2877 
2878 public:
2880 };
2881 
2882 void tst_QWidget::resizeEvent()
2883 {
2884  {
2885  QWidget wParent;
2886  wParent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
2887  wParent.resize(m_testWidgetSize);
2888  ResizeWidget wChild(&wParent);
2889  QTestPrivate::androidCompatibleShow(&wParent);
2891  QCOMPARE (wChild.m_resizeEventCount, 1); // initial resize event before paint
2892  wParent.hide();
2893  QSize safeSize(640,480);
2894  if (wChild.size() == safeSize)
2895  safeSize.setWidth(639);
2896  wChild.resize(safeSize);
2897  QCOMPARE (wChild.m_resizeEventCount, 1);
2898  QTestPrivate::androidCompatibleShow(&wParent);
2899  QCOMPARE (wChild.m_resizeEventCount, 2);
2900  }
2901 
2902  {
2903  ResizeWidget wTopLevel;
2904  wTopLevel.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
2905  wTopLevel.resize(m_testWidgetSize);
2906  QTestPrivate::androidCompatibleShow(&wTopLevel);
2908  QCOMPARE (wTopLevel.m_resizeEventCount, 1); // initial resize event before paint for toplevels
2909  wTopLevel.hide();
2910  QSize safeSize(640,480);
2911  if (wTopLevel.size() == safeSize)
2912  safeSize.setWidth(639);
2913  wTopLevel.resize(safeSize);
2914  QCOMPARE (wTopLevel.m_resizeEventCount, 1);
2915  QTestPrivate::androidCompatibleShow(&wTopLevel);
2917  QCOMPARE (wTopLevel.m_resizeEventCount, 2);
2918  }
2919 }
2920 
2921 void tst_QWidget::showMinimized()
2922 {
2923  if (m_platform == QStringLiteral("wayland")) {
2924  QSKIP("Wayland: Neither xdg_shell, wl_shell or ivi_application support "
2925  "letting a client know whether it's minimized. So on these shells "
2926  "Qt Wayland will always report that it's unmimized.");
2927  }
2928 
2929  QWidget plain;
2930  plain.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
2931  plain.move(100, 100);
2932  plain.resize(200, 200);
2933  QPoint pos = plain.pos();
2934 
2935  plain.showMinimized();
2936  QVERIFY(plain.isMinimized());
2937  QVERIFY(plain.isVisible());
2938  QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz),
2939  qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos)));
2940 
2941  plain.showNormal();
2942  QVERIFY(!plain.isMinimized());
2943  QVERIFY(plain.isVisible());
2944  QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz),
2945  qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos)));
2946 
2947  plain.showMinimized();
2948  QVERIFY(plain.isMinimized());
2949  QVERIFY(plain.isVisible());
2950  QVERIFY2(HighDpi::fuzzyCompare(plain.pos(), pos, m_fuzz),
2951  qPrintable(HighDpi::msgPointMismatch(plain.pos(), pos)));
2952 
2953  plain.hide();
2954  QVERIFY(plain.isMinimized());
2955  QVERIFY(!plain.isVisible());
2956 
2957  plain.showMinimized();
2958  QVERIFY(plain.isMinimized());
2959  QVERIFY(plain.isVisible());
2960 
2961  plain.setGeometry(200, 200, 300, 300);
2962  plain.showNormal();
2963  QCOMPARE(plain.geometry(), QRect(200, 200, 300, 300));
2964 
2965  {
2966  QWidget frame;
2967  QWidget widget(&frame);
2970  }
2971 }
2972 
2973 void tst_QWidget::showMinimizedKeepsFocus()
2974 {
2975  if (m_platform == QStringLiteral("xcb"))
2976  QSKIP("QTBUG-26424");
2978  QSKIP("Window activation is not supported.");
2979  if (m_platform == QStringLiteral("offscreen"))
2980  QSKIP("Platform offscreen does not support showMinimized()");
2981 
2982  //here we test that minimizing a widget and restoring it doesn't change the focus inside of it
2983  {
2984  QWidget window;
2985  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
2986  window.resize(200, 200);
2987  QWidget child1(&window), child2(&window);
2988  child1.setFocusPolicy(Qt::StrongFocus);
2989  child2.setFocusPolicy(Qt::StrongFocus);
2990  window.show();
2993  child2.setFocus();
2994 
2995  QTRY_COMPARE(window.focusWidget(), &child2);
2997 
2998  window.showMinimized();
2999  QTRY_VERIFY(window.isMinimized());
3000  QTRY_COMPARE(window.focusWidget(), &child2);
3001 
3002  window.showNormal();
3003  QTest::qWait(10);
3004  QTRY_COMPARE(window.focusWidget(), &child2);
3005  }
3006 
3007  //testing deletion of the focusWidget
3008  {
3009  QWidget window;
3010  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
3011  window.resize(200, 200);
3012  QWidget *child = new QWidget(&window);
3013  child->setFocusPolicy(Qt::StrongFocus);
3014  window.show();
3017  child->setFocus();
3018  QTRY_COMPARE(window.focusWidget(), child);
3020 
3021  delete child;
3022  QCOMPARE(window.focusWidget(), nullptr);
3023  QCOMPARE(QApplication::focusWidget(), nullptr);
3024  }
3025 
3026  //testing reparenting the focus widget
3027  {
3028  QWidget window;
3029  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
3030  window.resize(200, 200);
3031  QWidget *child = new QWidget(&window);
3032  child->setFocusPolicy(Qt::StrongFocus);
3033  window.show();
3036  child->setFocus();
3037  QTRY_COMPARE(window.focusWidget(), child);
3039 
3040  child->setParent(nullptr);
3041  QScopedPointer<QWidget> childGuard(child);
3042  QCOMPARE(window.focusWidget(), nullptr);
3043  QCOMPARE(QApplication::focusWidget(), nullptr);
3044  }
3045 
3046  //testing setEnabled(false)
3047  {
3048  QWidget window;
3049  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
3050  window.resize(200, 200);
3051  QWidget *child = new QWidget(&window);
3052  child->setFocusPolicy(Qt::StrongFocus);
3053  window.show();
3056  child->setFocus();
3057  QTRY_COMPARE(window.focusWidget(), child);
3059 
3060  child->setEnabled(false);
3061  QCOMPARE(window.focusWidget(), nullptr);
3062  QCOMPARE(QApplication::focusWidget(), nullptr);
3063  }
3064 
3065  //testing clearFocus
3066  {
3067  QWidget window;
3068  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
3069  window.resize(200, 200);
3070  QWidget *firstchild = new QWidget(&window);
3071  firstchild->setFocusPolicy(Qt::StrongFocus);
3072  QWidget *child = new QWidget(&window);
3073  child->setFocusPolicy(Qt::StrongFocus);
3074  window.show();
3077  child->setFocus();
3078  QTRY_COMPARE(window.focusWidget(), child);
3080 
3081  child->clearFocus();
3082  QCOMPARE(window.focusWidget(), nullptr);
3083  QCOMPARE(QApplication::focusWidget(), nullptr);
3084 
3085  window.showMinimized();
3086  QTest::qWait(30);
3087  QTRY_VERIFY(window.isMinimized());
3088  QCOMPARE(window.focusWidget(), nullptr);
3090 
3091  window.showNormal();
3094 #ifdef Q_OS_MACOS
3095  if (!macHasAccessToWindowsServer())
3096  QEXPECT_FAIL("", "When not having WindowServer access, we lose focus.", Continue);
3097 #endif
3098  QTRY_COMPARE(window.focusWidget(), firstchild);
3099 #ifdef Q_OS_MACOS
3100  if (!macHasAccessToWindowsServer())
3101  QEXPECT_FAIL("", "When not having WindowServer access, we lose focus.", Continue);
3102 #endif
3103  QTRY_COMPARE(QApplication::focusWidget(), firstchild);
3104  }
3105 }
3106 
3107 
3108 void tst_QWidget::reparent()
3109 {
3110  QWidget parent;
3111  parent.setWindowTitle(QStringLiteral("Toplevel ") + __FUNCTION__);
3112  const QPoint parentPosition = m_availableTopLeft + QPoint(300, 300);
3113  parent.setGeometry(QRect(parentPosition, m_testWidgetSize));
3114 
3115  QWidget child;
3116  child.setObjectName("child");
3117  child.setGeometry(10, 10, 180, 130);
3118  QPalette pal1;
3119  pal1.setColor(child.backgroundRole(), Qt::white);
3120  child.setPalette(pal1);
3121 
3122  QWidget childTLW(&child, Qt::Window);
3123  childTLW.setObjectName(QStringLiteral("childTLW ") + __FUNCTION__);
3124  childTLW.setWindowTitle(childTLW.objectName());
3125  childTLW.setGeometry(QRect(m_availableTopLeft + QPoint(100, 100), m_testWidgetSize));
3126  QPalette pal2;
3127  pal2.setColor(childTLW.backgroundRole(), Qt::yellow);
3128  childTLW.setPalette(pal2);
3129 
3130  QTestPrivate::androidCompatibleShow(&parent);
3131  QTestPrivate::androidCompatibleShow(&childTLW);
3133 
3134  parent.move(parentPosition);
3135 
3136  QPoint childPos = parent.mapToGlobal(child.pos());
3137  QPoint tlwPos = childTLW.pos();
3138 
3139  child.setParent(nullptr, child.windowFlags() & ~Qt::WindowType_Mask);
3140  child.setGeometry(childPos.x(), childPos.y(), child.width(), child.height());
3141  QTestPrivate::androidCompatibleShow(&child);
3142 
3143 #if 0 // QTBUG-26424
3144  if (m_platform == QStringLiteral("xcb"))
3145  QEXPECT_FAIL("", "On X11, the window manager will apply NorthWestGravity rules to 'child', which"
3146  " means the top-left corner of the window frame will be placed at 'childPos'"
3147  " causing this test to fail.", Continue);
3148 #endif
3149 
3150  QCOMPARE(child.geometry().topLeft(), childPos);
3151  QTRY_COMPARE(childTLW.pos(), tlwPos);
3152 }
3153 
3154 void tst_QWidget::setScreen()
3155 {
3156  const auto screens = QApplication::screens();
3157  if (screens.count() < 2)
3158  QSKIP("This test tests nothing on a machine with a single screen.");
3159 
3160  QScreen *screen0 = screens.at(0);
3161  QScreen *screen1 = screens.at(1);
3162 
3163  QWidget window;
3165  window.setScreen(screen0);
3166  QCOMPARE(window.screen(), screen0);
3167  window.setScreen(screen1);
3168  QCOMPARE(window.screen(), screen1);
3169 
3170  // calling setScreen on a widget that is not a window does nothing
3171  QWidget child(&window);
3172  const QScreen *childScreen = child.screen();
3173  child.setScreen(childScreen == screen0 ? screen1 : screen0);
3174  QCOMPARE(child.screen(), childScreen);
3175 }
3176 
3177 // Qt/Embedded does it differently.
3178 void tst_QWidget::icon()
3179 {
3180 #ifdef Q_OS_MACOS
3181  QSKIP("QTBUG-52974");
3182 #endif
3183 
3184  QPixmap p(20,20);
3185  p.fill(Qt::red);
3186  QScopedPointer<QWidget> testWidget(new QWidget);
3187  testWidget->resize(m_testWidgetSize);
3188  testWidget->setWindowTitle(__FUNCTION__);
3189  centerOnScreen(testWidget.data());
3190  testWidget->show();
3191  QVERIFY(QTest::qWaitForWindowExposed(testWidget.data()));
3192  testWidget->setWindowIcon(p);
3193 
3194  QVERIFY(!testWidget->windowIcon().isNull());
3195  testWidget->show();
3196  QVERIFY(!testWidget->windowIcon().isNull());
3197  testWidget->showFullScreen();
3198  QVERIFY(!testWidget->windowIcon().isNull());
3199  testWidget->showNormal();
3200  QVERIFY(!testWidget->windowIcon().isNull());
3201 }
3202 
3203 void tst_QWidget::hideWhenFocusWidgetIsChild()
3204 {
3206  QSKIP("Window activation is not supported.");
3207 
3208  QScopedPointer<QWidget> testWidget(new QWidget);
3209  testWidget->setWindowTitle(__FUNCTION__);
3210  testWidget->resize(m_testWidgetSize);
3211  centerOnScreen(testWidget.data());
3212  QWidget *parentWidget(new QWidget(testWidget.data()));
3213  parentWidget->setObjectName("parentWidget");
3214  parentWidget->setGeometry(0, 0, 100, 100);
3215  QLineEdit *edit = new QLineEdit(parentWidget);
3216  edit->setObjectName("edit1");
3217  QLineEdit *edit3 = new QLineEdit(parentWidget);
3218  edit3->setObjectName("edit3");
3219  edit3->move(0,50);
3220  QLineEdit *edit2 = new QLineEdit(testWidget.data());
3221  edit2->setObjectName("edit2");
3222  edit2->move(110, 100);
3223  edit->setFocus();
3224  testWidget->show();
3225  testWidget->activateWindow();
3226  QVERIFY(QTest::qWaitForWindowActive(testWidget.data()));
3227 
3228  QString actualFocusWidget, expectedFocusWidget;
3229  if (!QApplication::focusWidget() && m_platform == QStringLiteral("xcb"))
3230  QSKIP("X11: Your window manager is too broken for this test");
3231 
3233  actualFocusWidget = QString::asprintf("%p %s %s", QApplication::focusWidget(), QApplication::focusWidget()->objectName().toLatin1().constData(), QApplication::focusWidget()->metaObject()->className());
3234  expectedFocusWidget = QString::asprintf("%p %s %s", edit, edit->objectName().toLatin1().constData(), edit->metaObject()->className());
3235  QCOMPARE(actualFocusWidget, expectedFocusWidget);
3236 
3237  parentWidget->hide();
3239  actualFocusWidget = QString::asprintf("%p %s %s", QApplication::focusWidget(), QApplication::focusWidget()->objectName().toLatin1().constData(), QApplication::focusWidget()->metaObject()->className());
3240  expectedFocusWidget = QString::asprintf("%p %s %s", edit2, edit2->objectName().toLatin1().constData(), edit2->metaObject()->className());
3241  QCOMPARE(actualFocusWidget, expectedFocusWidget);
3242 }
3243 
3244 void tst_QWidget::normalGeometry()
3245 {
3246  if (m_platform == QStringLiteral("wayland"))
3247  QSKIP("Wayland: This fails. Figure out why.");
3248  QWidget parent;
3249  QCOMPARE(parent.normalGeometry(), parent.geometry());
3250  parent.setWindowTitle("NormalGeometry parent");
3251  QWidget *child = new QWidget(&parent);
3252 
3253  QCOMPARE(parent.normalGeometry(), parent.geometry());
3254  QCOMPARE(child->normalGeometry(), QRect());
3255 
3256  parent.setGeometry(QRect(m_availableTopLeft + QPoint(100 ,100), m_testWidgetSize));
3257  parent.showNormal();
3259  WindowStateChangeWatcher stateChangeWatcher(&parent);
3260 
3261  const QRect normalGeometry = parent.geometry();
3262  // We can't make any assumptions about the actual geometry compared to the
3263  // requested geometry. In this test, we only care about normalGeometry.
3264  QCOMPARE(parent.normalGeometry(), normalGeometry);
3265 
3266  parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized);
3267  QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized);
3268  QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
3269  QTRY_VERIFY(parent.geometry() != normalGeometry);
3270  QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
3271 
3272  parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized);
3273  QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized));
3274  QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
3275  QTRY_COMPARE(parent.geometry(), normalGeometry);
3276  QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
3277 
3278  parent.showMaximized();
3279  QTRY_VERIFY(parent.windowHandle()->windowState() & Qt::WindowMaximized);
3280  QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
3281  QTRY_VERIFY(parent.geometry() != normalGeometry);
3282  QCOMPARE(parent.normalGeometry(), normalGeometry);
3283 
3284  parent.showNormal();
3285  QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized));
3286  QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
3287  QTRY_COMPARE(parent.geometry(), normalGeometry);
3288  QCOMPARE(parent.normalGeometry(), normalGeometry);
3289 
3290  parent.setWindowState(parent.windowState() ^ Qt::WindowFullScreen);
3291  QTRY_VERIFY(parent.windowState() & Qt::WindowFullScreen);
3292  QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
3293  QTRY_VERIFY(parent.geometry() != normalGeometry);
3294  QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
3295 
3296  parent.setWindowState(Qt::WindowNoState);
3297  QTRY_VERIFY(!(parent.windowState() & Qt::WindowFullScreen));
3298  QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
3299  QTRY_COMPARE(parent.geometry(), normalGeometry);
3300  QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
3301 
3302  parent.showFullScreen();
3303  QTRY_VERIFY(parent.window()->windowState() & Qt::WindowFullScreen);
3304  QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
3305  QTRY_VERIFY(parent.geometry() != normalGeometry);
3306  QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
3307 
3308  parent.showNormal();
3309  QTRY_VERIFY(!(parent.windowHandle()->windowState() & Qt::WindowFullScreen));
3310  QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
3311  QTRY_COMPARE(parent.geometry(), normalGeometry);
3312  QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
3313 
3314  if (m_platform == QStringLiteral("xcb"))
3315  QSKIP("QTBUG-26424");
3316 
3317  parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized);
3318  QTRY_VERIFY(stateChangeWatcher.lastWindowStates & Qt::WindowMaximized);
3319  parent.setWindowState(parent.windowState() ^ Qt::WindowMinimized);
3320  QTRY_VERIFY(stateChangeWatcher.lastWindowStates & Qt::WindowMinimized);
3321 
3323  QTRY_VERIFY(stateChangeWatcher.lastWindowStates & (Qt::WindowMinimized|Qt::WindowMaximized));
3324  // ### when minimized and maximized at the same time, the geometry
3325  // ### does *NOT* have to be the normal geometry, it could be the
3326  // ### maximized geometry.
3327  // QCOMPARE(parent.geometry(), geom);
3328  QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
3329 
3330  parent.setWindowState(parent.windowState() ^ Qt::WindowMinimized);
3331  QTRY_VERIFY(!(parent.windowState() & Qt::WindowMinimized));
3332  QTRY_VERIFY(parent.windowState() & Qt::WindowMaximized);
3333  QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
3334  QTRY_VERIFY(parent.geometry() != normalGeometry);
3335  QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
3336 
3337  parent.setWindowState(parent.windowState() ^ Qt::WindowMaximized);
3338  QTRY_VERIFY(!(parent.windowState() & Qt::WindowMaximized));
3339  QTRY_COMPARE(stateChangeWatcher.lastWindowStates, parent.windowState());
3340  QTRY_COMPARE(parent.geometry(), normalGeometry);
3341  QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
3342 
3343  parent.showNormal();
3344  stateChangeWatcher.lastWindowStates = {};
3348  // the actual window will be either fullscreen or maximized
3349  QTRY_VERIFY(stateChangeWatcher.lastWindowStates & (Qt:: WindowFullScreen | Qt::WindowMaximized));
3350  QTRY_COMPARE(parent.normalGeometry(), normalGeometry);
3351 }
3352 
3353 void tst_QWidget::setGeometry()
3354 {
3355  QWidget tlw;
3356  tlw.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
3357  QWidget child(&tlw);
3358 
3359  const QSize initialSize = 2 * m_testWidgetSize;
3360  QRect tr(m_availableTopLeft + QPoint(100,100), initialSize);
3361  QRect cr(50,50,50,50);
3362  tlw.setGeometry(tr);
3363  child.setGeometry(cr);
3364  tlw.showNormal();
3365  QTRY_COMPARE(tlw.geometry().size(), tr.size());
3366  QCOMPARE(child.geometry(), cr);
3367 
3368  tlw.setParent(nullptr, Qt::Window|Qt::FramelessWindowHint);
3369  tr = QRect(m_availableTopLeft, initialSize / 2);
3370  tlw.setGeometry(tr);
3371  QCOMPARE(tlw.geometry(), tr);
3372  tlw.showNormal();
3373  if (!QTest::qWaitFor([&tlw]{ return tlw.frameGeometry() == tlw.geometry(); }))
3374  QSKIP("Your window manager is too broken for this test");
3375  if (m_platform == QStringLiteral("xcb") && tlw.geometry() != tr)
3376  QEXPECT_FAIL("", "QTBUG-26424", Continue);
3377  QCOMPARE(tlw.geometry(), tr);
3378 }
3379 
3380 void tst_QWidget::setGeometryHidden()
3381 {
3382  if (QGuiApplication::styleHints()->showIsMaximized())
3383  QSKIP("Platform does not support QWidget::setGeometry() - skipping");
3384 
3385  QWidget tlw;
3386  tlw.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
3387  QWidget child(&tlw);
3388 
3389  const QRect tr(m_availableTopLeft + QPoint(100, 100), 2 * m_testWidgetSize);
3390  const QRect cr(QPoint(50, 50), m_testWidgetSize);
3391  tlw.setGeometry(tr);
3392  child.setGeometry(cr);
3393  tlw.showNormal();
3394 
3395  tlw.hide();
3396  QTRY_VERIFY(tlw.isHidden());
3397  tlw.setGeometry(cr);
3398  QVERIFY(tlw.testAttribute(Qt::WA_PendingMoveEvent));
3399  QVERIFY(tlw.testAttribute(Qt::WA_PendingResizeEvent));
3400  QImage img(tlw.size(), QImage::Format_ARGB32); // just needed to call QWidget::render()
3401  tlw.render(&img);
3402  QVERIFY(!tlw.testAttribute(Qt::WA_PendingMoveEvent));
3403  QVERIFY(!tlw.testAttribute(Qt::WA_PendingResizeEvent));
3404  tlw.setGeometry(cr);
3405  QVERIFY(!tlw.testAttribute(Qt::WA_PendingMoveEvent));
3406  QVERIFY(!tlw.testAttribute(Qt::WA_PendingResizeEvent));
3407  tlw.resize(cr.size());
3408  QVERIFY(!tlw.testAttribute(Qt::WA_PendingMoveEvent));
3409  QVERIFY(!tlw.testAttribute(Qt::WA_PendingResizeEvent));
3410 }
3411 
3412 void tst_QWidget::windowOpacity()
3413 {
3414  QWidget widget;
3415  QWidget child(&widget);
3416 
3417  // Initial value should be 1.0
3418  QCOMPARE(widget.windowOpacity(), 1.0);
3419  // children should always return 1.0
3420  QCOMPARE(child.windowOpacity(), 1.0);
3421 
3422  widget.setWindowOpacity(0.0);
3423  QCOMPARE(widget.windowOpacity(), 0.0);
3424  child.setWindowOpacity(0.0);
3425  QCOMPARE(child.windowOpacity(), 1.0);
3426 
3427  widget.setWindowOpacity(1.0);
3428  QCOMPARE(widget.windowOpacity(), 1.0);
3429  child.setWindowOpacity(1.0);
3430  QCOMPARE(child.windowOpacity(), 1.0);
3431 
3432  widget.setWindowOpacity(2.0);
3433  QCOMPARE(widget.windowOpacity(), 1.0);
3434  child.setWindowOpacity(2.0);
3435  QCOMPARE(child.windowOpacity(), 1.0);
3436 
3437  widget.setWindowOpacity(-1.0);
3438  QCOMPARE(widget.windowOpacity(), 0.0);
3439  child.setWindowOpacity(-1.0);
3440  QCOMPARE(child.windowOpacity(), 1.0);
3441 }
3442 
3443 class UpdateWidget : public QWidget
3444 {
3445 public:
3446  explicit UpdateWidget(QWidget *parent = nullptr) : QWidget(parent)
3447  {
3448  setObjectName(QLatin1String("UpdateWidget"));
3449  reset();
3450  }
3451 
3452  void paintEvent(QPaintEvent *e) override
3453  {
3454  paintedRegion += e->region();
3455  ++numPaintEvents;
3456  if (resizeInPaintEvent) {
3457  resizeInPaintEvent = false;
3458  resize(size() + QSize(2, 2));
3459  }
3460  }
3461 
3462  bool event(QEvent *event) override
3463  {
3464  switch (event->type()) {
3465  case QEvent::ZOrderChange:
3467  break;
3468  case QEvent::UpdateRequest:
3470  break;
3472  case QEvent::FocusIn:
3473  case QEvent::FocusOut:
3477  return true; // Filter out to avoid update() calls in QWidget.
3478  break;
3479  default:
3480  break;
3481  }
3482  return QWidget::event(event);
3483  }
3484 
3485  void reset()
3486  {
3489  paintedRegion = QRegion();
3490  }
3491 
3498 };
3499 
3500 void tst_QWidget::lostUpdatesOnHide()
3501 {
3502 #ifndef Q_OS_MACOS
3506  widget.show();
3507  widget.hide();
3508  QTest::qWait(50);
3509  widget.show();
3510  QTest::qWait(50);
3511 
3512  QCOMPARE(widget.numPaintEvents, 1);
3513 #endif
3514 }
3515 
3516 void tst_QWidget::raise()
3517 {
3518  std::unique_ptr<QWidget> parentPtr(new QWidget);
3519  parentPtr->resize(200, 200);
3520  parentPtr->setObjectName(QLatin1String("raise"));
3521  parentPtr->setWindowTitle(parentPtr->objectName());
3522  QList<UpdateWidget *> allChildren;
3523 
3524  UpdateWidget *child1 = new UpdateWidget(parentPtr.get());
3525  child1->setAutoFillBackground(true);
3526  allChildren.append(child1);
3527 
3528  UpdateWidget *child2 = new UpdateWidget(parentPtr.get());
3529  child2->setAutoFillBackground(true);
3530  allChildren.append(child2);
3531 
3532  UpdateWidget *child3 = new UpdateWidget(parentPtr.get());
3533  child3->setAutoFillBackground(true);
3534  allChildren.append(child3);
3535 
3536  UpdateWidget *child4 = new UpdateWidget(parentPtr.get());
3537  child4->setAutoFillBackground(true);
3538  allChildren.append(child4);
3539 
3540  parentPtr->show();
3541  QVERIFY(QTest::qWaitForWindowExposed(parentPtr.get()));
3542 
3543 #ifdef Q_OS_MACOS
3544  if (child1->internalWinId()) {
3545  QSKIP("Cocoa has no Z-Order for views, we hack it, but it results in paint events.");
3546  }
3547 #endif
3548 
3549  QObjectList list1{child1, child2, child3, child4};
3550  QCOMPARE(parentPtr->children(), list1);
3551  QCOMPARE(allChildren.count(), list1.count());
3552 
3553  for (UpdateWidget *child : qAsConst(allChildren)) {
3554  int expectedPaintEvents = child == child4 ? 1 : 0;
3555  if (expectedPaintEvents == 0) {
3556  QCOMPARE(child->numPaintEvents, 0);
3557  } else {
3558  // show() issues multiple paint events on some window managers
3559  QTRY_VERIFY(child->numPaintEvents >= expectedPaintEvents);
3560  }
3561  QCOMPARE(child->numZOrderChangeEvents, 0);
3562  child->reset();
3563  }
3564 
3565  for (int i = 0; i < 5; ++i)
3566  child2->raise();
3567  QTest::qWait(50);
3568 
3569  for (UpdateWidget *child : qAsConst(allChildren)) {
3570  int expectedPaintEvents = child == child2 ? 1 : 0;
3571  int expectedZOrderChangeEvents = child == child2 ? 1 : 0;
3572  QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents);
3573  QCOMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents);
3574  child->reset();
3575  }
3576 
3578  list2 << child1 << child3 << child4 << child2;
3579  QCOMPARE(parentPtr->children(), list2);
3580 
3581  // Creates a widget on top of all the children and checks that raising one of
3582  // the children underneath doesn't trigger a repaint on the covering widget.
3583  QWidget topLevel;
3584  topLevel.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
3585  QWidget *parent = parentPtr.release();
3586  parent->setParent(&topLevel);
3587  topLevel.show();
3588 
3589  UpdateWidget *onTop = new UpdateWidget(&topLevel);
3590  onTop->reset();
3591  onTop->resize(topLevel.size());
3592  onTop->setAutoFillBackground(true);
3593  onTop->show();
3595  QTRY_VERIFY(onTop->numPaintEvents > 0);
3596  onTop->reset();
3597 
3598  // Reset all the children.
3599  for (UpdateWidget *child : qAsConst(allChildren))
3600  child->reset();
3601 
3602  for (int i = 0; i < 5; ++i)
3603  child3->raise();
3604  QTest::qWait(50);
3605 
3606  QCOMPARE(onTop->numPaintEvents, 0);
3607  QCOMPARE(onTop->numZOrderChangeEvents, 0);
3608 
3609  QObjectList list3{child1, child4, child2, child3};
3610  QCOMPARE(parent->children(), list3);
3611 
3612  for (UpdateWidget *child : qAsConst(allChildren)) {
3613  int expectedPaintEvents = 0;
3614  int expectedZOrderChangeEvents = child == child3 ? 1 : 0;
3615  QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents);
3616  QCOMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents);
3617  child->reset();
3618  }
3619 }
3620 
3621 void tst_QWidget::lower()
3622 {
3624  parent->setObjectName(QLatin1String("lower"));
3625  parent->setWindowTitle(parent->objectName());
3626  parent->resize(200, 200);
3627  QList<UpdateWidget *> allChildren;
3628 
3629  UpdateWidget *child1 = new UpdateWidget(parent.data());
3630  child1->setAutoFillBackground(true);
3631  allChildren.append(child1);
3632 
3633  UpdateWidget *child2 = new UpdateWidget(parent.data());
3634  child2->setAutoFillBackground(true);
3635  allChildren.append(child2);
3636 
3637  UpdateWidget *child3 = new UpdateWidget(parent.data());
3638  child3->setAutoFillBackground(true);
3639  allChildren.append(child3);
3640 
3641  UpdateWidget *child4 = new UpdateWidget(parent.data());
3642  child4->setAutoFillBackground(true);
3643  allChildren.append(child4);
3644 
3645  parent->show();
3647 
3648  QObjectList list1{child1, child2, child3, child4};
3649  QCOMPARE(parent->children(), list1);
3650  QCOMPARE(allChildren.count(), list1.count());
3651 
3652  for (UpdateWidget *child : qAsConst(allChildren)) {
3653  int expectedPaintEvents = child == child4 ? 1 : 0;
3654  if (expectedPaintEvents == 0) {
3655  QCOMPARE(child->numPaintEvents, 0);
3656  } else {
3657  // show() issues multiple paint events on some window managers
3658  QTRY_VERIFY(child->numPaintEvents >= expectedPaintEvents);
3659  }
3660  QCOMPARE(child->numZOrderChangeEvents, 0);
3661  child->reset();
3662  }
3663 
3664  for (int i = 0; i < 5; ++i)
3665  child4->lower();
3666 
3667  QTest::qWait(100);
3668 
3669  for (UpdateWidget *child : qAsConst(allChildren)) {
3670  int expectedPaintEvents = child == child3 ? 1 : 0;
3671  int expectedZOrderChangeEvents = child == child4 ? 1 : 0;
3672  QTRY_COMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents);
3673  QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents);
3674  child->reset();
3675  }
3676 
3678  list2 << child4 << child1 << child2 << child3;
3679  QCOMPARE(parent->children(), list2);
3680 }
3681 
3682 void tst_QWidget::stackUnder()
3683 {
3684 #ifdef Q_OS_MACOS
3685  QSKIP("QTBUG-52974: Cocoa has no Z-Order for views, we hack it, but it results in paint events.");
3686 #endif
3687 
3689  parent->setObjectName(QLatin1String("stackUnder"));
3690  parent->setWindowTitle(parent->objectName());
3691  parent->resize(200, 200);
3692  QList<UpdateWidget *> allChildren;
3693 
3694  UpdateWidget *child1 = new UpdateWidget(parent.data());
3695  child1->setAutoFillBackground(true);
3696  allChildren.append(child1);
3697 
3698  UpdateWidget *child2 = new UpdateWidget(parent.data());
3699  child2->setAutoFillBackground(true);
3700  allChildren.append(child2);
3701 
3702  UpdateWidget *child3 = new UpdateWidget(parent.data());
3703  child3->setAutoFillBackground(true);
3704  allChildren.append(child3);
3705 
3706  UpdateWidget *child4 = new UpdateWidget(parent.data());
3707  child4->setAutoFillBackground(true);
3708  allChildren.append(child4);
3709 
3710  parent->show();
3712  QObjectList list1{child1, child2, child3, child4};
3713  QCOMPARE(parent->children(), list1);
3714 
3715  for (UpdateWidget *child : qAsConst(allChildren)) {
3716  int expectedPaintEvents = child == child4 ? 1 : 0;
3717 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
3718  if (expectedPaintEvents == 1 && child->numPaintEvents == 2)
3719  QEXPECT_FAIL(0, "Mac and Windows issues double repaints for Z-Order change", Continue);
3720 #endif
3721  QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents);
3722  QCOMPARE(child->numZOrderChangeEvents, 0);
3723  child->reset();
3724  }
3725 
3726  for (int i = 0; i < 5; ++i)
3727  child4->stackUnder(child2);
3728  QTest::qWait(10);
3729 
3730  QObjectList list2{child1, child4, child2, child3};
3731  QCOMPARE(parent->children(), list2);
3732 
3733  for (UpdateWidget *child : qAsConst(allChildren)) {
3734  int expectedPaintEvents = child == child3 ? 1 : 0;
3735  int expectedZOrderChangeEvents = child == child4 ? 1 : 0;
3736  QTRY_COMPARE(child->numPaintEvents, expectedPaintEvents);
3737  QTRY_COMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents);
3738  child->reset();
3739  }
3740 
3741  for (int i = 0; i < 5; ++i)
3742  child1->stackUnder(child3);
3743  QTest::qWait(10);
3744 
3745  QObjectList list3{child4, child2, child1, child3};
3746  QCOMPARE(parent->children(), list3);
3747 
3748  for (UpdateWidget *child : qAsConst(allChildren)) {
3749  int expectedZOrderChangeEvents = child == child1 ? 1 : 0;
3750  if (child == child3) {
3751 #ifndef Q_OS_MACOS
3752  QEXPECT_FAIL(0, "See QTBUG-493", Continue);
3753 #endif
3754  QCOMPARE(child->numPaintEvents, 0);
3755  } else {
3756  QCOMPARE(child->numPaintEvents, 0);
3757  }
3758  QTRY_COMPARE(child->numZOrderChangeEvents, expectedZOrderChangeEvents);
3759  child->reset();
3760  }
3761 }
3762 
3763 void drawPolygon(QPaintDevice *dev, int w, int h)
3764 {
3765  QPainter p(dev);
3766  p.fillRect(0, 0, w, h, Qt::white);
3767 
3768  QPolygon a;
3769  a << QPoint(0, 0) << QPoint(w/2, h/2) << QPoint(w, 0)
3770  << QPoint(w/2, h) << QPoint(0, 0);
3771 
3772  p.setPen(QPen(Qt::black, 1));
3773  p.setBrush(Qt::DiagCrossPattern);
3774  p.drawPolygon(a);
3775 }
3776 
3777 class ContentsPropagationWidget : public QWidget
3778 {
3779  Q_OBJECT
3780 public:
3781  explicit ContentsPropagationWidget(QWidget *parent = nullptr) : QWidget(parent)
3782  {
3783  setObjectName(QLatin1String("ContentsPropagationWidget"));
3784  setWindowTitle(objectName());
3785  QWidget *child = this;
3786  for (int i = 0; i < 32; ++i) {
3787  child = new QWidget(child);
3788  child->setGeometry(i, i, 400 - i * 2, 400 - i * 2);
3789  }
3790  }
3791 
3793  {
3794  for (QObject *child : children())
3795  qobject_cast<QWidget *>(child)->setAutoFillBackground(!enable);
3796  }
3797 
3798 protected:
3799  void paintEvent(QPaintEvent *) override
3800  {
3801  int w = width(), h = height();
3802  drawPolygon(this, w, h);
3803  }
3804 
3805  QSize sizeHint() const override { return {500, 500}; }
3806 };
3807 
3808 // Scale to remove devicePixelRatio should scaling be active.
3809 static QPixmap grabFromWidget(QWidget *w, const QRect &rect)
3810 {
3811  QPixmap pixmap = w->grab(rect);
3812  const qreal devicePixelRatio = pixmap.devicePixelRatio();
3813  if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
3814  pixmap = pixmap.scaled((QSizeF(pixmap.size()) / devicePixelRatio).toSize(),
3816  pixmap.setDevicePixelRatio(1);
3817  }
3818  return pixmap;
3819 }
3820 
3821 void tst_QWidget::testContentsPropagation()
3822 {
3823  if (!qFuzzyCompare(qApp->devicePixelRatio(), qreal(1)))
3824  QSKIP("This test does not work with scaling.");
3826  widget.setFixedSize(500, 500);
3827  widget.setContentsPropagation(false);
3828  QPixmap widgetSnapshot = widget.grab(QRect(QPoint(0, 0), QSize(-1, -1)));
3829 
3830  QPixmap correct(500, 500);
3831  drawPolygon(&correct, 500, 500);
3832  //correct.save("correct.png", "PNG");
3833 
3834  //widgetSnapshot.save("snap1.png", "PNG");
3835  QVERIFY(widgetSnapshot.toImage() != correct.toImage());
3836 
3837  widget.setContentsPropagation(true);
3838  widgetSnapshot = widgetSnapshot = widget.grab(QRect(QPoint(0, 0), QSize(-1, -1)));
3839  //widgetSnapshot.save("snap2.png", "PNG");
3840 
3841  QCOMPARE(widgetSnapshot, correct);
3842 }
3843 
3844 /*
3845  Test that saving and restoring window geometry with
3846  saveGeometry() and restoreGeometry() works.
3847 */
3848 
3849 void tst_QWidget::saveRestoreGeometry()
3850 {
3851 #ifdef Q_OS_MACOS
3852  QSKIP("QTBUG-52974");
3853 #endif
3854 
3855  if (m_platform == QStringLiteral("wayland"))
3856  QSKIP("Wayland: This fails. Figure out why.");
3857  const QPoint position = m_availableTopLeft + QPoint(100, 100);
3858  const QSize size = m_testWidgetSize;
3859 
3860  QByteArray savedGeometry;
3861 
3862  {
3863  QWidget widget;
3864  widget.move(position);
3865  widget.resize(size);
3866  widget.showNormal();
3869 
3871  qPrintable(HighDpi::msgPointMismatch(widget.pos(), position)));
3872  QCOMPARE(widget.size(), size);
3873  savedGeometry = widget.saveGeometry();
3874  }
3875 
3876  {
3877  QWidget widget;
3879 
3880  const QByteArray empty;
3881  const QByteArray one("a");
3882  const QByteArray two("ab");
3883  const QByteArray three("abc");
3884  const QByteArray four("abca");
3885  const QByteArray garbage("abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc");
3886 
3887  QVERIFY(!widget.restoreGeometry(empty));
3891  QVERIFY(!widget.restoreGeometry(four));
3892  QVERIFY(!widget.restoreGeometry(garbage));
3893 
3894  QVERIFY(widget.restoreGeometry(savedGeometry));
3895  widget.showNormal();
3898 
3900  qPrintable(HighDpi::msgPointMismatch(widget.pos(), position)));
3901  QCOMPARE(widget.size(), size);
3902  widget.show();
3904  qPrintable(HighDpi::msgPointMismatch(widget.pos(), position)));
3905  QCOMPARE(widget.size(), size);
3906  }
3907 
3908  {
3909  QWidget widget;
3910  widget.move(position);
3911  widget.resize(size);
3912  widget.showNormal();
3914  QTRY_COMPARE(widget.geometry().size(), size);
3915 
3916  QRect geom;
3917 
3918  //Restore from Full screen
3919  savedGeometry = widget.saveGeometry();
3920  geom = widget.geometry();
3923  QTest::qWait(500);
3924  QVERIFY(widget.restoreGeometry(savedGeometry));
3925  QTest::qWait(120);
3927  QTRY_COMPARE(widget.geometry(), geom);
3928 
3929  //Restore to full screen
3931  QTest::qWait(120);
3933  QTest::qWait(500);
3934  savedGeometry = widget.saveGeometry();
3935  geom = widget.geometry();
3937  QTest::qWait(120);
3939  QTest::qWait(400);
3940  QVERIFY(widget.restoreGeometry(savedGeometry));
3941  QTest::qWait(120);
3943  QTRY_COMPARE(widget.geometry(), geom);
3946  QTest::qWait(120);
3948  QTest::qWait(120);
3949 
3950  //Restore from Maximised
3951  widget.move(position);
3952  widget.resize(size);
3953  QTest::qWait(10);
3955  QTest::qWait(500);
3956  savedGeometry = widget.saveGeometry();
3957  geom = widget.geometry();
3959  QTest::qWait(120);
3961  QTRY_VERIFY(widget.geometry() != geom);
3962  QTest::qWait(500);
3963  QVERIFY(widget.restoreGeometry(savedGeometry));
3964  QTest::qWait(120);
3965  QTRY_COMPARE(widget.geometry(), geom);
3966 
3968 
3969  //Restore to maximised
3971  QTest::qWait(120);
3973  QTest::qWait(500);
3974  geom = widget.geometry();
3975  savedGeometry = widget.saveGeometry();
3977  QTest::qWait(120);
3979  QTest::qWait(500);
3980  QVERIFY(widget.restoreGeometry(savedGeometry));
3981  QTest::qWait(120);
3983  QTRY_COMPARE(widget.geometry(), geom);
3984  }
3985 }
3986 
3987 void tst_QWidget::restoreVersion1Geometry_data()
3988 {
3989  if (m_platform == QStringLiteral("wayland"))
3990  QSKIP("Wayland: This fails. Figure out why.");
3991  QTest::addColumn<QString>("fileName");
3992  QTest::addColumn<Qt::WindowState>("expectedWindowState");
3993  QTest::addColumn<QPoint>("expectedPosition");
3994  QTest::addColumn<QSize>("expectedSize");
3995  QTest::addColumn<QRect>("expectedNormalGeometry");
3996  const QPoint position(100, 100);
3997  const QSize size(200, 200);
3998  const QRect normalGeometry(102, 124, 200, 200);
3999 
4000  QTest::newRow("geometry.dat") << ":geometry.dat" << Qt::WindowNoState << position << size << normalGeometry;
4001  QTest::newRow("geometry-maximized.dat") << ":geometry-maximized.dat" << Qt::WindowMaximized << position << size << normalGeometry;
4002  QTest::newRow("geometry-fullscreen.dat") << ":geometry-fullscreen.dat" << Qt::WindowFullScreen << position << size << normalGeometry;
4003 }
4004 
4005 /*
4006  Test that the current version of restoreGeometry() can restore geometry
4007  saved width saveGeometry() version 1.0.
4008 */
4009 void tst_QWidget::restoreVersion1Geometry()
4010 {
4012  QFETCH(Qt::WindowState, expectedWindowState);
4013  QFETCH(QPoint, expectedPosition);
4014  Q_UNUSED(expectedPosition);
4015  QFETCH(QSize, expectedSize);
4016  QFETCH(QRect, expectedNormalGeometry);
4017 
4018  if (m_platform == QLatin1String("windows") && QGuiApplication::primaryScreen()->geometry().width() > 2000)
4019  QSKIP("Skipping due to minimum decorated window size on Windows");
4020 
4021  // WindowActive is uninteresting for this test
4022  const Qt::WindowStates WindowStateMask = Qt::WindowFullScreen | Qt::WindowMaximized | Qt::WindowMinimized;
4023 
4024  QFile f(fileName);
4025  QVERIFY(f.exists());
4026  f.open(QIODevice::ReadOnly);
4027  const QByteArray savedGeometry = f.readAll();
4028  QCOMPARE(savedGeometry.count(), 46);
4029  f.close();
4030 
4031  QWidget widget;
4034 
4035  QVERIFY(widget.restoreGeometry(savedGeometry));
4036 
4037  QCOMPARE(widget.windowState() & WindowStateMask, expectedWindowState);
4038  if (expectedWindowState == Qt::WindowNoState) {
4039  QTRY_COMPARE(widget.geometry(), expectedNormalGeometry);
4040  QCOMPARE(widget.size(), expectedSize);
4041  }
4042 
4043  widget.showNormal();
4045  QTest::qWait(100);
4046 
4047  if (expectedWindowState == Qt::WindowNoState) {
4048  QTRY_COMPARE(widget.size(), expectedSize);
4049  QCOMPARE(widget.geometry(), expectedNormalGeometry);
4050  }
4051 
4052  widget.showNormal();
4053  QTest::qWait(10);
4054 
4055  QTRY_COMPARE(widget.geometry(), expectedNormalGeometry);
4056  if (expectedWindowState == Qt::WindowNoState)
4057  QCOMPARE(widget.size(), expectedSize);
4058 
4059 #if 0
4060  // Code for saving a new geometry*.dat files
4061  {
4062  QWidget widgetToSave;
4063  widgetToSave.move(expectedPosition);
4064  widgetToSave.resize(expectedSize);
4065  widgetToSave.show();
4067  QTest::qWait(500); // stabilize
4068  widgetToSave.setWindowState(Qt::WindowStates(expectedWindowState));
4069  QTest::qWait(500); // stabilize
4070 
4071  QByteArray geometryToSave = widgetToSave.saveGeometry();
4072 
4073  // Code for saving a new geometry.dat file.
4074  f.setFileName(fileName.mid(1));
4075  QVERIFY(f.open(QIODevice::WriteOnly)); // did you forget to 'p4 edit *.dat'? :)
4076  f.write(geometryToSave);
4077  f.close();
4078  }
4079 #endif
4080 }
4081 
4082 void tst_QWidget::widgetAt()
4083 {
4084 #ifdef Q_OS_MACOS
4085  QSKIP("QTBUG-52974");
4086 #endif
4087 
4088  if (m_platform == QStringLiteral("wayland"))
4089  QSKIP("Wayland: This fails. Figure out why.");
4090  if (m_platform == QStringLiteral("offscreen"))
4091  QSKIP("Platform offscreen does not support lower()/raise() or WindowMasks");
4092 
4094 
4095  const QPoint referencePos = m_availableTopLeft + QPoint(100, 100);
4097  w1->setGeometry(QRect(referencePos, QSize(m_testWidgetSize.width(), 150)));
4098  w1->setObjectName(QLatin1String("w1"));
4099  w1->setWindowTitle(w1->objectName());
4101  w2->setGeometry(QRect(referencePos + QPoint(50, 50), QSize(m_testWidgetSize.width(), 100)));
4102  w2->setObjectName(QLatin1String("w2"));
4103  w2->setWindowTitle(w2->objectName());
4104  w1->showNormal();
4106  const QPoint testPos = referencePos + QPoint(100, 100);
4107  QWidget *wr;
4108  QTRY_VERIFY((wr = QApplication::widgetAt((testPos))));
4109  QCOMPARE(wr->objectName(), QString("w1"));
4110 
4111  w2->showNormal();
4113  QTRY_VERIFY((wr = QApplication::widgetAt(testPos)));
4114  QCOMPARE(wr->objectName(), QString("w2"));
4115 
4116  w2->lower();
4117  QTRY_VERIFY((wr = QApplication::widgetAt(testPos)) && wr->objectName() == QString("w1"));
4118  w2->raise();
4119 
4120  QTRY_VERIFY((wr = QApplication::widgetAt(testPos)) && wr->objectName() == QString("w2"));
4121 
4122  QWidget *w3 = new QWidget(w2.data());
4123  w3->setGeometry(10,10,50,50);
4124  w3->setObjectName("w3");
4125  w3->showNormal();
4126  QTRY_VERIFY((wr = QApplication::widgetAt(testPos)) && wr->objectName() == QString("w3"));
4127 
4128  w3->setAttribute(Qt::WA_TransparentForMouseEvents);
4129  QTRY_VERIFY((wr = QApplication::widgetAt(testPos)) && wr->objectName() == QString("w2"));
4130 
4132  ->hasCapability(QPlatformIntegration::WindowMasks)) {
4133  QSKIP("Platform does not support WindowMasks");
4134  }
4135 
4136  QRegion rgn = QRect(QPoint(0,0), w2->size());
4137  QPoint point = w2->mapFromGlobal(testPos);
4138  rgn -= QRect(point, QSize(1,1));
4139  w2->setMask(rgn);
4140 
4141  QTRY_VERIFY((wr = QApplication::widgetAt(testPos)));
4142  QTRY_COMPARE(wr->objectName(), w1->objectName());
4143  QTRY_VERIFY((wr = QApplication::widgetAt(testPos + QPoint(1, 1))));
4144  QTRY_COMPARE(wr->objectName(), w2->objectName());
4145 
4146  QBitmap bitmap(w2->size());
4147  QPainter p(&bitmap);
4148  p.fillRect(bitmap.rect(), Qt::color1);
4149  p.setPen(Qt::color0);
4150  p.drawPoint(w2->mapFromGlobal(testPos));
4151  p.end();
4152  w2->setMask(bitmap);
4153  QTRY_COMPARE(QApplication::widgetAt(testPos), w1.data());
4154  QTRY_VERIFY(QApplication::widgetAt(testPos + QPoint(1, 1)) == w2.data());
4155 }
4156 
4157 void tst_QWidget::task110173()
4158 {
4159  QWidget w;
4160  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
4161 
4162  QPushButton *pb1 = new QPushButton("click", &w);
4163  pb1->setFocusPolicy(Qt::ClickFocus);
4164  pb1->move(100, 100);
4165 
4166  QPushButton *pb2 = new QPushButton("push", &w);
4167  pb2->setFocusPolicy(Qt::ClickFocus);
4168  pb2->move(300, 300);
4169 
4170  QTest::keyClick( &w, Qt::Key_Tab );
4171  w.show();
4173 }
4174 
4175 class Widget : public QWidget
4176 {
4177 public:
4179  void actionEvent(QActionEvent *) override { if (deleteThis) delete this; }
4180  void changeEvent(QEvent *) override { if (deleteThis) delete this; }
4181  void closeEvent(QCloseEvent *) override { if (deleteThis) delete this; }
4182  void hideEvent(QHideEvent *) override { if (deleteThis) delete this; }
4183  void focusOutEvent(QFocusEvent *) override { if (deleteThis) delete this; }
4184  void keyPressEvent(QKeyEvent *) override { if (deleteThis) delete this; }
4185  void keyReleaseEvent(QKeyEvent *) override { if (deleteThis) delete this; }
4186  void mouseDoubleClickEvent(QMouseEvent *) override { if (deleteThis) delete this; }
4187  void mousePressEvent(QMouseEvent *) override { if (deleteThis) delete this; }
4188  void mouseReleaseEvent(QMouseEvent *) override { if (deleteThis) delete this; }
4189  void mouseMoveEvent(QMouseEvent *) override { if (deleteThis) delete this; }
4190 
4191  bool deleteThis = false;
4192 };
4193 
4194 void tst_QWidget::testDeletionInEventHandlers()
4195 {
4196  // closeEvent
4197  QPointer<Widget> w = new Widget;
4198  w->deleteThis = true;
4199  w->close();
4200  QVERIFY(w.isNull());
4201  delete w;
4202 
4203  // focusOut (crashes)
4204  //w = new Widget;
4205  //w->show();
4206  //w->setFocus();
4207  //QCOMPARE(qApp->focusWidget(), w);
4208  //w->deleteThis = true;
4209  //w->clearFocus();
4210  //QVERIFY(w.isNull());
4211 
4212  // key press
4213  w = new Widget;
4214  w->show();
4215  w->deleteThis = true;
4216  QTest::keyPress(w, Qt::Key_A);
4217  QVERIFY(w.isNull());
4218  delete w;
4219 
4220  // key release
4221  w = new Widget;
4222  w->show();
4223  w->deleteThis = true;
4224  QTest::keyRelease(w, Qt::Key_A);
4225  QVERIFY(w.isNull());
4226  delete w;
4227 
4228  // mouse press
4229  w = new Widget;
4230  w->show();
4231  w->deleteThis = true;
4233  QVERIFY(w.isNull());
4234  delete w;
4235 
4236  // mouse release
4237  w = new Widget;
4238  w->show();
4239  w->deleteThis = true;
4240  QMouseEvent me(QEvent::MouseButtonRelease, QPoint(1, 1), Qt::LeftButton, Qt::LeftButton, Qt::KeyboardModifiers());
4241  qApp->notify(w, &me);
4242  QVERIFY(w.isNull());
4243  delete w;
4244 
4245  // mouse double click
4246  w = new Widget;
4247  w->show();
4248  w->deleteThis = true;
4250  QVERIFY(w.isNull());
4251  delete w;
4252 
4253  // hide event (crashes)
4254  //w = new Widget;
4255  //w->show();
4256  //w->deleteThis = true;
4257  //w->hide();
4258  //QVERIFY(w.isNull());
4259 
4260  // action event
4261  w = new Widget;
4262  w->deleteThis = true;
4263  w->addAction(new QAction(w));
4264  QVERIFY(w.isNull());
4265  delete w;
4266 
4267  // change event
4268  w = new Widget;
4269  w->show();
4270  w->deleteThis = true;
4271  w->setMouseTracking(true);
4272  QVERIFY(w.isNull());
4273  delete w;
4274 
4275  w = new Widget;
4276  w->setMouseTracking(true);
4277  w->show();
4278  w->deleteThis = true;
4280  QApplication::sendEvent(w, &me2);
4281  QVERIFY(w.isNull());
4282  delete w;
4283 }
4284 
4285 #ifdef Q_OS_MACOS
4286 class MaskedPainter : public QWidget
4287 {
4288 public:
4289  QRect mask;
4290 
4291  MaskedPainter()
4292  : mask(20, 20, 50, 50)
4293  {
4294  setMask(mask);
4295  }
4296 
4297  void paintEvent(QPaintEvent *)
4298  {
4299  QPainter p(this);
4300  p.fillRect(mask, QColor(Qt::red));
4301  }
4302 };
4303 
4304 /*
4305  Verifies that the entire area inside the mask is painted red.
4306 */
4307 bool verifyWidgetMask(QWidget *widget, QRect mask)
4308 {
4309  const QImage image = widget->grab(QRect(QPoint(0, 0), widget->size())).toImage();
4310 
4311  const QImage masked = image.copy(mask);
4312  QImage red(masked);
4313  red.fill(QColor(Qt::red).rgb());
4314 
4315  return (masked == red);
4316 }
4317 
4318 void tst_QWidget::setMask()
4319 {
4320  {
4321  MaskedPainter w;
4322  w.resize(200, 200);
4323  w.show();
4324  QTest::qWait(100);
4325  QVERIFY(verifyWidgetMask(&w, w.mask));
4326  }
4327  {
4328  MaskedPainter w;
4329  w.resize(200, 200);
4330  w.setWindowFlags(w.windowFlags() | Qt::FramelessWindowHint);
4331  w.show();
4332  QTest::qWait(100);
4333  QRect mask = w.mask;
4334 
4335  QVERIFY(verifyWidgetMask(&w, mask));
4336  }
4337 }
4338 #endif
4339 
4340 class StaticWidget : public QWidget
4341 {
4342 Q_OBJECT
4343 public:
4344  bool partial = false;
4345  bool gotPaintEvent = false;
4347 
4348  explicit StaticWidget(QWidget *parent = nullptr) : QWidget(parent)
4349  {
4352  setPalette(Qt::red); // Make sure we have an opaque palette.
4353  setAutoFillBackground(true);
4354  }
4355 
4356  void paintEvent(QPaintEvent *e) override
4357  {
4358  paintedRegion += e->region();
4359  gotPaintEvent = true;
4360 // qDebug() << "paint" << e->region();
4361  // Look for a full update, set partial to false if found.
4362  for (QRect r : e->region()) {
4363  partial = (r != rect());
4364  if (!partial)
4365  break;
4366  }
4367  }
4368 };
4369 
4370 /*
4371  Test that widget resizes and moves can be done with minimal repaints when WA_StaticContents
4372  and WA_OpaquePaintEvent is set. Test is mac-only for now.
4373 */
4374 void tst_QWidget::optimizedResizeMove()
4375 {
4376  if (m_platform == QStringLiteral("wayland"))
4377  QSKIP("Wayland: This fails. Figure out why.");
4378  QWidget parent;
4379  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
4380  parent.resize(400, 400);
4381 
4382  StaticWidget staticWidget(&parent);
4383  staticWidget.gotPaintEvent = false;
4384  staticWidget.move(150, 150);
4385  staticWidget.resize(150, 150);
4386  parent.show();
4388  QTRY_VERIFY(staticWidget.gotPaintEvent);
4389 
4390  staticWidget.gotPaintEvent = false;
4391  staticWidget.move(staticWidget.pos() + QPoint(10, 10));
4392  QTest::qWait(20);
4393  QCOMPARE(staticWidget.gotPaintEvent, false);
4394 
4395  staticWidget.gotPaintEvent = false;
4396  staticWidget.move(staticWidget.pos() + QPoint(-10, -10));
4397  QTest::qWait(20);
4398  QCOMPARE(staticWidget.gotPaintEvent, false);
4399 
4400  staticWidget.gotPaintEvent = false;
4401  staticWidget.move(staticWidget.pos() + QPoint(-10, 10));
4402  QTest::qWait(20);
4403  QCOMPARE(staticWidget.gotPaintEvent, false);
4404 
4405  staticWidget.gotPaintEvent = false;
4406  staticWidget.resize(staticWidget.size() + QSize(10, 10));
4407  QTRY_VERIFY(staticWidget.gotPaintEvent);
4408  QCOMPARE(staticWidget.partial, true);
4409 
4410  staticWidget.gotPaintEvent = false;
4411  staticWidget.resize(staticWidget.size() + QSize(-10, -10));
4412  QTest::qWait(20);
4413  QCOMPARE(staticWidget.gotPaintEvent, false);
4414 
4415  staticWidget.gotPaintEvent = false;
4416  staticWidget.resize(staticWidget.size() + QSize(10, -10));
4417  QTRY_VERIFY(staticWidget.gotPaintEvent);
4418  QCOMPARE(staticWidget.partial, true);
4419 
4420  staticWidget.gotPaintEvent = false;
4421  staticWidget.move(staticWidget.pos() + QPoint(10, 10));
4422  staticWidget.resize(staticWidget.size() + QSize(-10, -10));
4423  QTest::qWait(20);
4424  QCOMPARE(staticWidget.gotPaintEvent, false);
4425 
4426  staticWidget.gotPaintEvent = false;
4427  staticWidget.move(staticWidget.pos() + QPoint(10, 10));
4428  staticWidget.resize(staticWidget.size() + QSize(10, 10));
4429  QTRY_VERIFY(staticWidget.gotPaintEvent);
4430  QCOMPARE(staticWidget.partial, true);
4431 
4432  staticWidget.gotPaintEvent = false;
4433  staticWidget.move(staticWidget.pos() + QPoint(-10, -10));
4434  staticWidget.resize(staticWidget.size() + QSize(-10, -10));
4435  QTest::qWait(20);
4436  QCOMPARE(staticWidget.gotPaintEvent, false);
4437 
4438  staticWidget.setAttribute(Qt::WA_StaticContents, false);
4439  staticWidget.gotPaintEvent = false;
4440  staticWidget.move(staticWidget.pos() + QPoint(-10, -10));
4441  staticWidget.resize(staticWidget.size() + QSize(-10, -10));
4442  QTRY_VERIFY(staticWidget.gotPaintEvent);
4443  QCOMPARE(staticWidget.partial, false);
4444  staticWidget.setAttribute(Qt::WA_StaticContents, true);
4445 
4446  staticWidget.setAttribute(Qt::WA_StaticContents, false);
4447  staticWidget.gotPaintEvent = false;
4448  staticWidget.move(staticWidget.pos() + QPoint(10, 10));
4449  QTest::qWait(20);
4450  QCOMPARE(staticWidget.gotPaintEvent, false);
4451  staticWidget.setAttribute(Qt::WA_StaticContents, true);
4452 }
4453 
4454 void tst_QWidget::optimizedResize_topLevel()
4455 {
4457  QSKIP("Wayland: This fails. Figure out why.");
4458 
4460  QSKIP("Skip due to rounding errors in the regions.");
4461  StaticWidget topLevel;
4463  topLevel.gotPaintEvent = false;
4464  topLevel.show();
4466  QTRY_VERIFY(topLevel.gotPaintEvent);
4467 
4468  topLevel.gotPaintEvent = false;
4469  topLevel.partial = false;
4470  topLevel.paintedRegion = QRegion();
4471 
4472 #if !defined(Q_OS_WIN32)
4473  topLevel.resize(topLevel.size() + QSize(10, 10));
4474 #else
4475  // Static contents does not work when programmatically resizing
4476  // top-levels with QWidget::resize. We do some funky stuff in
4477  // setGeometry_sys. However, resizing it with the mouse or with
4478  // a native function call works (it basically has to go through
4479  // WM_RESIZE in QApplication). This is a corner case, though.
4480  // See task 243708
4481  RECT rect;
4482  GetWindowRect(winHandleOf(&topLevel), &rect);
4483  MoveWindow(winHandleOf(&topLevel), rect.left, rect.top,
4484  rect.right - rect.left + 10, rect.bottom - rect.top + 10,
4485  true);
4486  QTest::qWait(100);
4487 #endif
4488 
4489  // Expected update region: New rect - old rect.
4490  QRegion expectedUpdateRegion(topLevel.rect());
4491  expectedUpdateRegion -= QRect(QPoint(), topLevel.size() - QSize(10, 10));
4492 
4493  QTRY_VERIFY(topLevel.gotPaintEvent);
4494  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("offscreen"))
4495  QSKIP("QTBUG-26424");
4496  QCOMPARE(topLevel.partial, true);
4497  QCOMPARE(topLevel.paintedRegion, expectedUpdateRegion);
4498 }
4499 
4500 class SiblingDeleter : public QWidget
4501 {
4502 public:
4503  inline SiblingDeleter(QWidget *sibling, QWidget *parent)
4504  : QWidget(parent), sibling(sibling) {}
4505  inline ~SiblingDeleter() { delete sibling; }
4506 
4507 private:
4508  QPointer<QWidget> sibling;
4509 };
4510 
4511 
4512 void tst_QWidget::childDeletesItsSibling()
4513 {
4514  auto commonParent = new QWidget(nullptr);
4515  QPointer<QWidget> child(new QWidget(nullptr));
4516  QPointer<QWidget> siblingDeleter = new SiblingDeleter(child, commonParent);
4517  child->setParent(commonParent);
4518  delete commonParent; // don't crash
4519  QVERIFY(!child);
4520  QVERIFY(!siblingDeleter);
4521 
4522 }
4523 
4524 void tst_QWidget::setMinimumSize()
4525 {
4526  QWidget w;
4527  QSize defaultSize = w.size();
4528 
4529  w.setMinimumSize(defaultSize + QSize(100, 100));
4530  QCOMPARE(w.size(), defaultSize + QSize(100, 100));
4531  QVERIFY(!w.testAttribute(Qt::WA_Resized));
4532 
4533  w.setMinimumSize(defaultSize + QSize(50, 50));
4534  QCOMPARE(w.size(), defaultSize + QSize(100, 100));
4535  QVERIFY(!w.testAttribute(Qt::WA_Resized));
4536 
4537  w.setMinimumSize(defaultSize + QSize(200, 200));
4538  QCOMPARE(w.size(), defaultSize + QSize(200, 200));
4539  QVERIFY(!w.testAttribute(Qt::WA_Resized));
4540 
4541  QSize nonDefaultSize = defaultSize + QSize(5,5);
4542  w.setMinimumSize(nonDefaultSize);
4543  w.showNormal();
4545  QVERIFY2(w.height() >= nonDefaultSize.height(),
4546  msgComparisonFailed(w.height(), ">=", nonDefaultSize.height()));
4547  QVERIFY2(w.width() >= nonDefaultSize.width(),
4548  msgComparisonFailed(w.width(), ">=", nonDefaultSize.width()));
4549 }
4550 
4551 void tst_QWidget::setMaximumSize()
4552 {
4553  QWidget w;
4554  QSize defaultSize = w.size();
4555 
4556  w.setMinimumSize(defaultSize + QSize(100, 100));
4557  QCOMPARE(w.size(), defaultSize + QSize(100, 100));
4558  QVERIFY(!w.testAttribute(Qt::WA_Resized));
4559  w.setMinimumSize(defaultSize);
4560 
4561  w.setMaximumSize(defaultSize + QSize(200, 200));
4562  QCOMPARE(w.size(), defaultSize + QSize(100, 100));
4563  QVERIFY(!w.testAttribute(Qt::WA_Resized));
4564 
4565  w.setMaximumSize(defaultSize + QSize(50, 50));
4566  QCOMPARE(w.size(), defaultSize + QSize(50, 50));
4567  QVERIFY(!w.testAttribute(Qt::WA_Resized));
4568 }
4569 
4570 void tst_QWidget::setFixedSize()
4571 {
4573  QSKIP("Wayland: This fails. Figure out why.");
4574 
4575  QWidget w;
4576  QSize defaultSize = w.size();
4577 
4578  w.setFixedSize(defaultSize + QSize(100, 100));
4579  QCOMPARE(w.size(), defaultSize + QSize(100, 100));
4580  QVERIFY(w.testAttribute(Qt::WA_Resized));
4581 
4582  w.setFixedSize(defaultSize + QSize(200, 200));
4583 
4584  QCOMPARE(w.minimumSize(), defaultSize + QSize(200,200));
4585  QCOMPARE(w.maximumSize(), defaultSize + QSize(200,200));
4586  QCOMPARE(w.size(), defaultSize + QSize(200, 200));
4587  QVERIFY(w.testAttribute(Qt::WA_Resized));
4588 
4589  w.setFixedSize(defaultSize + QSize(50, 50));
4590  QCOMPARE(w.size(), defaultSize + QSize(50, 50));
4591  QVERIFY(w.testAttribute(Qt::WA_Resized));
4592 
4593  w.setAttribute(Qt::WA_Resized, false);
4594  w.setFixedSize(defaultSize + QSize(50, 50));
4595  QVERIFY(!w.testAttribute(Qt::WA_Resized));
4596 
4597  w.setFixedSize(defaultSize + QSize(150, 150));
4598  w.showNormal();
4600  if (m_platform == QStringLiteral("xcb"))
4601  QSKIP("QTBUG-26424");
4602  QCOMPARE(w.size(), defaultSize + QSize(150,150));
4603 }
4604 
4605 void tst_QWidget::ensureCreated()
4606 {
4607  {
4608  QWidget widget;
4609  WId widgetWinId = widget.winId();
4610  Q_UNUSED(widgetWinId);
4612  }
4613 
4614  {
4615  QWidget window;
4616 
4617  QDialog dialog(&window);
4619 
4620  WId dialogWinId = dialog.winId();
4621  Q_UNUSED(dialogWinId);
4623  QVERIFY(window.testAttribute(Qt::WA_WState_Created));
4624  }
4625 
4626  {
4627  QWidget window;
4628 
4629  QDialog dialog(&window);
4631 
4632  WId dialogWinId = dialog.winId();
4633  Q_UNUSED(dialogWinId);
4635  QVERIFY(window.testAttribute(Qt::WA_WState_Created));
4636  }
4637 
4638  {
4639  QWidget window;
4640 
4641  QDialog dialog(&window);
4643 
4644  WId dialogWinId = dialog.winId();
4645  Q_UNUSED(dialogWinId);
4647  QVERIFY(window.testAttribute(Qt::WA_WState_Created));
4648  }
4649 }
4650 
4652 {
4653 public:
4654  using QWidget::QWidget;
4655 protected:
4656  bool event(QEvent *e) override
4657  {
4658  if (e->type() == QEvent::WinIdChange) {
4659  m_winIdList.append(internalWinId());
4660  return true;
4661  }
4662  return QWidget::event(e);
4663  }
4664 public:
4666  int winIdChangeEventCount() const { return m_winIdList.count(); }
4667 };
4668 
4670 {
4671 public:
4672  void create() { QWidget::create(); }
4674 };
4675 
4676 void tst_QWidget::createAndDestroy()
4677 {
4679 
4680  // Create and destroy via QWidget
4681  widget.create();
4683  QCOMPARE(widget.winIdChangeEventCount(), 1);
4685 
4686  widget.destroy();
4688  QCOMPARE(widget.winIdChangeEventCount(), 2);
4690 
4691  // Create via QWidget, destroy via QWindow
4692  widget.create();
4694  QCOMPARE(widget.winIdChangeEventCount(), 3);
4696 
4697  widget.windowHandle()->destroy();
4699  QCOMPARE(widget.winIdChangeEventCount(), 4);
4701 
4702  // Create via QWidget again
4703  widget.create();
4705  QCOMPARE(widget.winIdChangeEventCount(), 5);
4707 
4708  // Destroy via QWindow, create via QWindow
4709  widget.windowHandle()->destroy();
4712  QCOMPARE(widget.winIdChangeEventCount(), 6);
4714 
4715  widget.windowHandle()->create();
4717  QCOMPARE(widget.winIdChangeEventCount(), 7);
4719 }
4720 
4721 void tst_QWidget::winIdChangeEvent()
4722 {
4723  {
4724  // Transforming an alien widget into a native widget
4726  const WId winIdBefore = widget.internalWinId();
4727  const WId winIdAfter = widget.winId();
4728  QVERIFY(winIdBefore != winIdAfter);
4729  QCOMPARE(widget.winIdChangeEventCount(), 1);
4730  }
4731 
4732  {
4733  // Changing parent of a native widget
4734  QWidget parent1, parent2;
4735  WinIdChangeWidget child(&parent1);
4736  const WId winIdBefore = child.winId();
4737  QCOMPARE(child.winIdChangeEventCount(), 1);
4738  child.setParent(&parent2);
4739  const WId winIdAfter = child.internalWinId();
4740  QCOMPARE(winIdBefore, winIdAfter);
4741  QCOMPARE(child.winIdChangeEventCount(), 3);
4742  // winId is set to zero during reparenting
4743  QCOMPARE(WId(0), child.m_winIdList[1]);
4744  }
4745 
4746  {
4747  // Changing grandparent of a native widget
4748  QWidget grandparent1, grandparent2;
4749  QWidget parent(&grandparent1);
4751  const WId winIdBefore = child.winId();
4752  QCOMPARE(child.winIdChangeEventCount(), 1);
4753  parent.setParent(&grandparent2);
4754  const WId winIdAfter = child.internalWinId();
4755  QCOMPARE(winIdBefore, winIdAfter);
4756  QCOMPARE(child.winIdChangeEventCount(), 1);
4757  }
4758 
4759  {
4760  // Changing parent of an alien widget
4761  QWidget parent1, parent2;
4762  WinIdChangeWidget child(&parent1);
4763  const WId winIdBefore = child.internalWinId();
4764  child.setParent(&parent2);
4765  const WId winIdAfter = child.internalWinId();
4766  QCOMPARE(winIdBefore, winIdAfter);
4767  QCOMPARE(child.winIdChangeEventCount(), 0);
4768  }
4769 
4770  {
4771  // Making native child widget into a top-level window
4772  QWidget parent;
4774  child.winId();
4775  const WId winIdBefore = child.internalWinId();
4776  QCOMPARE(child.winIdChangeEventCount(), 1);
4777  const Qt::WindowFlags flags = child.windowFlags();
4778  child.setWindowFlags(flags | Qt::Window);
4779  const WId winIdAfter = child.internalWinId();
4780  QCOMPARE(winIdBefore, winIdAfter);
4781  QCOMPARE(child.winIdChangeEventCount(), 3);
4782  // winId is set to zero during reparenting
4783  QCOMPARE(WId(0), child.m_winIdList[1]);
4784  }
4785 }
4786 
4787 void tst_QWidget::persistentWinId()
4788 {
4790  QWidget *w1 = new QWidget;
4791  QWidget *w2 = new QWidget;
4792  QWidget *w3 = new QWidget;
4793  w1->setParent(parent.data());
4794  w2->setParent(w1);
4795  w3->setParent(w2);
4796 
4797  WId winId1 = w1->winId();
4798  WId winId2 = w2->winId();
4799  WId winId3 = w3->winId();
4800 
4801  // reparenting should preserve the winId of the widget being reparented and of its children
4802  w1->setParent(nullptr);
4803  QCOMPARE(w1->winId(), winId1);
4804  QCOMPARE(w2->winId(), winId2);
4805  QCOMPARE(w3->winId(), winId3);
4806 
4807  w1->setParent(parent.data());
4808  QCOMPARE(w1->winId(), winId1);
4809  QCOMPARE(w2->winId(), winId2);
4810  QCOMPARE(w3->winId(), winId3);
4811 
4812  w2->setParent(nullptr);
4813  QCOMPARE(w2->winId(), winId2);
4814  QCOMPARE(w3->winId(), winId3);
4815 
4816  w2->setParent(parent.data());
4817  QCOMPARE(w2->winId(), winId2);
4818  QCOMPARE(w3->winId(), winId3);
4819 
4820  w2->setParent(w1);
4821  QCOMPARE(w2->winId(), winId2);
4822  QCOMPARE(w3->winId(), winId3);
4823 
4824  w3->setParent(nullptr);
4825  QCOMPARE(w3->winId(), winId3);
4826 
4827  w3->setParent(w1);
4828  QCOMPARE(w3->winId(), winId3);
4829 
4830  w3->setParent(w2);
4831  QCOMPARE(w3->winId(), winId3);
4832 }
4833 
4834 void tst_QWidget::transientParent()
4835 {
4836  QWidget topLevel;
4837  topLevel.setGeometry(QRect(m_availableTopLeft + QPoint(100, 100), m_testWidgetSize));
4838  topLevel.setWindowTitle(__FUNCTION__);
4839  QWidget *child = new QWidget(&topLevel);
4840  QMenu *menu = new QMenu(child); // QTBUG-41898: Use top level as transient parent for native widgets as well.
4841  QToolButton *toolButton = new QToolButton(child);
4842  toolButton->setMenu(menu);
4843  toolButton->winId();
4844  topLevel.show();
4846  QCOMPARE(menu->windowHandle()->transientParent(), topLevel.windowHandle());
4847 }
4848 
4849 void tst_QWidget::showNativeChild()
4850 {
4851  QWidget topLevel;
4852  topLevel.setGeometry(QRect(m_availableTopLeft + QPoint(100, 100), m_testWidgetSize));
4853  topLevel.setWindowTitle(__FUNCTION__);
4854  QWidget child(&topLevel);
4855  child.winId();
4856  topLevel.show();
4858 }
4859 
4860 void tst_QWidget::closeAndShowNativeChild()
4861 {
4862  QWidget topLevel;
4863  QWidget *nativeChild = new QWidget;
4864  nativeChild->winId();
4865  nativeChild->setFixedSize(200, 200);
4866 
4867  QHBoxLayout *layout = new QHBoxLayout;
4868  layout->addWidget(nativeChild);
4869  topLevel.setLayout(layout);
4870 
4871  topLevel.show();
4872  QVERIFY(!nativeChild->isHidden());
4873  nativeChild->close();
4874  QVERIFY(nativeChild->isHidden());
4875  nativeChild->show();
4876  QVERIFY(!nativeChild->isHidden());
4877 }
4878 
4879 void tst_QWidget::closeAndShowWithNativeChild()
4880 {
4881  bool dontCreateNativeWidgetSiblings = QApplication::testAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
4882  auto resetAttribute = qScopeGuard([&]{
4883  QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, dontCreateNativeWidgetSiblings);
4884  });
4886 
4887  QWidget topLevel;
4888  QWidget *nativeChild = new QWidget;
4889  nativeChild->setFixedSize(200, 200);
4890  QWidget *nativeHiddenChild = new QWidget;
4891  nativeHiddenChild->setFixedSize(200, 200);
4892  QWidget *normalChild = new QWidget;
4893  normalChild->setFixedSize(200, 200);
4894 
4895  QHBoxLayout *layout = new QHBoxLayout;
4896  layout->addWidget(nativeChild);
4897  layout->addWidget(nativeHiddenChild);
4898  layout->addWidget(normalChild);
4899  topLevel.setLayout(layout);
4900 
4901  nativeHiddenChild->hide();
4902 
4903  topLevel.show();
4905  nativeChild->winId();
4906  const QSize originalSize = topLevel.size();
4907  topLevel.close();
4908 
4909  // all children must have the same state
4910  QCOMPARE(nativeChild->isHidden(), normalChild->isHidden());
4911  QCOMPARE(nativeChild->isVisible(), normalChild->isVisible());
4912  QCOMPARE(nativeChild->testAttribute(Qt::WA_WState_Visible),
4913  normalChild->testAttribute(Qt::WA_WState_Visible));
4914  QCOMPARE(nativeChild->testAttribute(Qt::WA_WState_Hidden),
4915  normalChild->testAttribute(Qt::WA_WState_Hidden));
4916  QCOMPARE(nativeChild->testAttribute(Qt::WA_WState_ExplicitShowHide),
4917  normalChild->testAttribute(Qt::WA_WState_ExplicitShowHide));
4918 
4919  topLevel.show();
4921  QCOMPARE(topLevel.size(), originalSize);
4922 }
4923 
4925 {
4926 public:
4929 
4930  using QWidget::QWidget;
4931  using QWidget::create;
4932 
4933  void showEvent(QShowEvent *e) override
4934  {
4936  if (e->spontaneous())
4938  }
4939 
4940  void hideEvent(QHideEvent *e) override
4941  {
4943  if (e->spontaneous())
4945  }
4946 };
4947 
4948 void tst_QWidget::showHideEvent_data()
4949 {
4950  QTest::addColumn<bool>("show");
4951  QTest::addColumn<bool>("hide");
4952  QTest::addColumn<bool>("create");
4953  QTest::addColumn<int>("expectedShowEvents");
4954  QTest::addColumn<int>("expectedHideEvents");
4955 
4956  QTest::newRow("window: only show")
4957  << true
4958  << false
4959  << false
4960  << 1
4961  << 0;
4962  QTest::newRow("window: show/hide")
4963  << true
4964  << true
4965  << false
4966  << 1
4967  << 1;
4968  QTest::newRow("window: show/hide/create")
4969  << true
4970  << true
4971  << true
4972  << 1
4973  << 1;
4974  QTest::newRow("window: hide/create")
4975  << false
4976  << true
4977  << true
4978  << 0
4979  << 0;
4980  QTest::newRow("window: only hide")
4981  << false
4982  << true
4983  << false
4984  << 0
4985  << 0;
4986  QTest::newRow("window: nothing")
4987  << false
4988  << false
4989  << false
4990  << 0
4991  << 0;
4992 }
4993 
4994 void tst_QWidget::showHideEvent()
4995 {
4996  QFETCH(bool, show);
4997  QFETCH(bool, hide);
4998  QFETCH(bool, create);
4999  QFETCH(int, expectedShowEvents);
5000  QFETCH(int, expectedHideEvents);
5001 
5004  if (show)
5005  widget.show();
5006  if (hide)
5007  widget.hide();
5009  widget.create();
5010 
5011  QCOMPARE(widget.numberOfShowEvents, expectedShowEvents);
5012  QCOMPARE(widget.numberOfHideEvents, expectedHideEvents);
5013 }
5014 
5015 void tst_QWidget::showHideEventWhileMinimize()
5016 {
5018  if (!pi->hasCapability(QPlatformIntegration::MultipleWindows)
5020  || !pi->hasCapability(QPlatformIntegration::WindowManagement)) {
5021  QSKIP("This test requires window management capabilities");
5022  }
5023  // QTBUG-41312, hide, show events should be received during minimized.
5025  widget.setWindowTitle(__FUNCTION__);
5026  widget.resize(m_testWidgetSize);
5027  centerOnScreen(&widget);
5028  widget.show();
5030  const int showEventsBeforeMinimize = widget.numberOfShowEvents;
5031  const int hideEventsBeforeMinimize = widget.numberOfHideEvents;
5033  QTRY_COMPARE(widget.numberOfHideEvents, hideEventsBeforeMinimize + 1);
5034  widget.showNormal();
5035  QTRY_COMPARE(widget.numberOfShowEvents, showEventsBeforeMinimize + 1);
5036 }
5037 
5038 void tst_QWidget::showHideChildrenWhileMinimize_QTBUG50589()
5039 {
5041  if (!pi->hasCapability(QPlatformIntegration::MultipleWindows)
5043  || !pi->hasCapability(QPlatformIntegration::WindowManagement)) {
5044  QSKIP("This test requires window management capabilities");
5045  }
5046 
5047  QWidget parent;
5049 
5050  parent.setWindowTitle(QTest::currentTestFunction());
5051  parent.resize(m_testWidgetSize);
5052  centerOnScreen(&parent);
5053  parent.show();
5055 
5056  const int showEventsBeforeMinimize = child.numberOfSpontaneousShowEvents;
5057  const int hideEventsBeforeMinimize = child.numberOfSpontaneousHideEvents;
5058  parent.showMinimized();
5059  QTRY_COMPARE(child.numberOfSpontaneousHideEvents, hideEventsBeforeMinimize + 1);
5060  parent.showNormal();
5061  QTRY_COMPARE(child.numberOfSpontaneousShowEvents, showEventsBeforeMinimize + 1);
5062 }
5063 
5064 void tst_QWidget::update()
5065 {
5066 #ifdef Q_OS_MACOS
5067  QSKIP("QTBUG-52974");
5068 #endif
5069 
5071 
5072  UpdateWidget w;
5073  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
5074  w.resize(100, 100);
5075  centerOnScreen(&w);
5076  w.show();
5078 
5079  QTRY_COMPARE(w.numPaintEvents, 1);
5080 
5081  QCOMPARE(w.visibleRegion(), QRegion(w.rect()));
5082  QCOMPARE(w.paintedRegion, w.visibleRegion());
5083  w.reset();
5084 
5085  UpdateWidget child(&w);
5086  child.setGeometry(10, 10, 80, 80);
5087  child.show();
5088 
5089  QPoint childOffset = child.mapToParent(QPoint());
5090 
5091  // widgets are transparent by default, so both should get repaints
5092  {
5095  QCOMPARE(child.numPaintEvents, 1);
5096  QCOMPARE(child.visibleRegion(), QRegion(child.rect()));
5097  QCOMPARE(child.paintedRegion, child.visibleRegion());
5098  QCOMPARE(w.numPaintEvents, 1);
5099  QCOMPARE(w.visibleRegion(), QRegion(w.rect()));
5100  QCOMPARE(w.paintedRegion, child.visibleRegion().translated(childOffset));
5101 
5102  w.reset();
5103  child.reset();
5104 
5105  w.update();
5108  QCOMPARE(child.numPaintEvents, 1);
5109  QCOMPARE(child.visibleRegion(), QRegion(child.rect()));
5110  QCOMPARE(child.paintedRegion, child.visibleRegion());
5111  QCOMPARE(w.numPaintEvents, 1);
5112  QCOMPARE(w.visibleRegion(), QRegion(w.rect()));
5113  QCOMPARE(w.paintedRegion, w.visibleRegion());
5114  }
5115 
5116  QPalette opaquePalette = child.palette();
5117  opaquePalette.setColor(child.backgroundRole(), QColor(Qt::red));
5118 
5119  // setting an opaque background on the child should prevent paint-events
5120  // for the parent in the child area
5121  {
5122  child.setPalette(opaquePalette);
5123  child.setAutoFillBackground(true);
5125 
5126  w.reset();
5127  child.reset();
5128 
5129  w.update();
5132 
5133  QCOMPARE(w.numPaintEvents, 1);
5134  QRegion expectedVisible = QRegion(w.rect())
5135  - child.visibleRegion().translated(childOffset);
5136  QCOMPARE(w.visibleRegion(), expectedVisible);
5137  QCOMPARE(w.paintedRegion, expectedVisible);
5138  QCOMPARE(child.numPaintEvents, 0);
5139 
5140  w.reset();
5141  child.reset();
5142 
5143  child.update();
5146 
5147  QCOMPARE(w.numPaintEvents, 0);
5148  QCOMPARE(child.numPaintEvents, 1);
5149  QCOMPARE(child.paintedRegion, child.visibleRegion());
5150 
5151  w.reset();
5152  child.reset();
5153  }
5154 
5155  // overlapping sibling
5156  UpdateWidget sibling(&w);
5157  child.setGeometry(10, 10, 20, 20);
5158  sibling.setGeometry(15, 15, 20, 20);
5159  sibling.show();
5160 
5162  w.reset();
5163  child.reset();
5164  sibling.reset();
5165 
5166  const QPoint siblingOffset = sibling.mapToParent(QPoint());
5167 
5168  sibling.update();
5171 
5172  // child is opaque, sibling transparent
5173  {
5174  QCOMPARE(sibling.numPaintEvents, 1);
5175  QCOMPARE(sibling.paintedRegion, sibling.visibleRegion());
5176 
5177  QCOMPARE(child.numPaintEvents, 1);
5178  QCOMPARE(child.paintedRegion.translated(childOffset),
5179  child.visibleRegion().translated(childOffset)
5180  & sibling.visibleRegion().translated(siblingOffset));
5181 
5182  QCOMPARE(w.numPaintEvents, 1);
5183  QCOMPARE(w.paintedRegion,
5184  w.visibleRegion() & sibling.visibleRegion().translated(siblingOffset));
5185  QCOMPARE(w.paintedRegion,
5186  (w.visibleRegion() - child.visibleRegion().translated(childOffset))
5187  & sibling.visibleRegion().translated(siblingOffset));
5188 
5189  }
5190  w.reset();
5191  child.reset();
5192  sibling.reset();
5193 
5194  sibling.setPalette(opaquePalette);
5195  sibling.setAutoFillBackground(true);
5196 
5197  sibling.update();
5200 
5201  // child opaque, sibling opaque
5202  {
5203  QCOMPARE(sibling.numPaintEvents, 1);
5204  QCOMPARE(sibling.paintedRegion, sibling.visibleRegion());
5205 
5206 #ifdef Q_OS_MACOS
5207  if (child.internalWinId()) // child is native
5208  QEXPECT_FAIL(0, "Cocoa compositor paints child and sibling", Continue);
5209 #endif
5210  QCOMPARE(child.numPaintEvents, 0);
5211  QCOMPARE(child.visibleRegion(),
5212  QRegion(child.rect())
5213  - sibling.visibleRegion().translated(siblingOffset - childOffset));
5214 
5215  QCOMPARE(w.numPaintEvents, 0);
5216  QCOMPARE(w.visibleRegion(),
5217  QRegion(w.rect())
5218  - child.visibleRegion().translated(childOffset)
5219  - sibling.visibleRegion().translated(siblingOffset));
5220  }
5221 }
5222 
5223 #ifndef Q_OS_MACOS
5224 static inline bool isOpaque(QWidget *widget)
5225 {
5226  if (!widget)
5227  return false;
5229 }
5230 #endif
5231 
5232 void tst_QWidget::isOpaque()
5233 {
5234 #ifndef Q_OS_MACOS
5235  QWidget w;
5236  QVERIFY(::isOpaque(&w));
5237 
5238  QWidget child(&w);
5239  QVERIFY(!::isOpaque(&child));
5240 
5241  child.setAutoFillBackground(true);
5242  QVERIFY(::isOpaque(&child));
5243 
5244  QPalette palette;
5245 
5246  // background color
5247 
5248  palette = child.palette();
5249  palette.setColor(child.backgroundRole(), QColor(255, 0, 0, 127));
5250  child.setPalette(palette);
5251  QVERIFY(!::isOpaque(&child));
5252 
5253  palette.setColor(child.backgroundRole(), QColor(255, 0, 0, 255));
5254  child.setPalette(palette);
5255  QVERIFY(::isOpaque(&child));
5256 
5257  palette.setColor(QPalette::Window, QColor(0, 0, 255, 127));
5258  w.setPalette(palette);
5259 
5260  QVERIFY(!::isOpaque(&w));
5261 
5262  child.setAutoFillBackground(false);
5263  QVERIFY(!::isOpaque(&child));
5264 
5265  // Qt::WA_OpaquePaintEvent
5266 
5267  child.setAttribute(Qt::WA_OpaquePaintEvent);
5268  QVERIFY(::isOpaque(&child));
5269 
5270  child.setAttribute(Qt::WA_OpaquePaintEvent, false);
5271  QVERIFY(!::isOpaque(&child));
5272 
5273  // Qt::WA_NoSystemBackground
5274 
5275  child.setAttribute(Qt::WA_NoSystemBackground);
5276  QVERIFY(!::isOpaque(&child));
5277 
5278  child.setAttribute(Qt::WA_NoSystemBackground, false);
5279  QVERIFY(!::isOpaque(&child));
5280 
5281  palette.setColor(QPalette::Window, QColor(0, 0, 255, 255));
5282  w.setPalette(palette);
5283  QVERIFY(::isOpaque(&w));
5284 
5285  w.setAttribute(Qt::WA_NoSystemBackground);
5286  QVERIFY(!::isOpaque(&w));
5287 
5288  w.setAttribute(Qt::WA_NoSystemBackground, false);
5289  QVERIFY(::isOpaque(&w));
5290 
5291  {
5292  QPalette palette = QApplication::palette();
5293  QPalette old = palette;
5296 
5297  QWidget widget;
5298  QVERIFY(!::isOpaque(&widget));
5299 
5302  QCOMPARE(::isOpaque(&widget), old.color(QPalette::Window).alpha() == 255);
5303  }
5304 #endif
5305 }
5306 
5307 #ifndef Q_OS_MACOS
5308 /*
5309  Test that scrolling of a widget invalidates the correct regions
5310 */
5311 void tst_QWidget::scroll()
5312 {
5313  if (m_platform == QStringLiteral("wayland"))
5314  QSKIP("Wayland: This fails. Figure out why.");
5316  const int w = qMin(500, screen->availableGeometry().width() / 2);
5317  const int h = qMin(500, screen->availableGeometry().height() / 2);
5318 
5319  UpdateWidget updateWidget;
5320  updateWidget.resize(w, h);
5321  updateWidget.reset();
5322  updateWidget.move(m_availableTopLeft);
5323  updateWidget.showNormal();
5324  QApplication::setActiveWindow(&updateWidget);
5325  QVERIFY(QTest::qWaitForWindowActive(&updateWidget));
5326  QVERIFY(updateWidget.numPaintEvents > 0);
5327 
5328  {
5329  updateWidget.reset();
5330  updateWidget.scroll(10, 10);
5332  QRegion dirty(QRect(0, 0, w, 10));
5333  dirty += QRegion(QRect(0, 10, 10, h - 10));
5334  QTRY_COMPARE(updateWidget.paintedRegion, dirty);
5335  }
5336 
5337  {
5338  updateWidget.reset();
5339  updateWidget.update(0, 0, 10, 10);
5340  updateWidget.scroll(0, 10);
5342  QRegion dirty(QRect(0, 0, w, 10));
5343  dirty += QRegion(QRect(0, 10, 10, 10));
5344  QTRY_COMPARE(updateWidget.paintedRegion, dirty);
5345  }
5346 
5347  if (updateWidget.width() < 200 || updateWidget.height() < 200)
5348  QSKIP("Skip this test due to too small screen geometry.");
5349 
5350  {
5351  updateWidget.reset();
5352  updateWidget.update(0, 0, 100, 100);
5353  updateWidget.scroll(10, 10, QRect(50, 50, 100, 100));
5355  QRegion dirty(QRect(0, 0, 100, 50));
5356  dirty += QRegion(QRect(0, 50, 150, 10));
5357  dirty += QRegion(QRect(0, 60, 110, 40));
5358  dirty += QRegion(QRect(50, 100, 60, 10));
5359  dirty += QRegion(QRect(50, 110, 10, 40));
5360  QTRY_COMPARE(updateWidget.paintedRegion, dirty);
5361  }
5362 
5363  {
5364  updateWidget.reset();
5365  updateWidget.update(0, 0, 100, 100);
5366  updateWidget.scroll(10, 10, QRect(100, 100, 100, 100));
5368  QRegion dirty(QRect(0, 0, 100, 100));
5369  dirty += QRegion(QRect(100, 100, 100, 10));
5370  dirty += QRegion(QRect(100, 110, 10, 90));
5371  QTRY_COMPARE(updateWidget.paintedRegion, dirty);
5372  }
5373 }
5374 
5375 // QTBUG-38999, scrolling a widget with native child widgets should move the children.
5376 void tst_QWidget::scrollNativeChildren()
5377 {
5378  QWidget parent;
5379  parent.setWindowTitle(QLatin1String(__FUNCTION__));
5380  parent.resize(400, 400);
5381  centerOnScreen(&parent);
5382  QLabel *nativeLabel = new QLabel(QStringLiteral("nativeLabel"), &parent);
5383  const QPoint oldLabelPos(100, 100);
5384  nativeLabel->move(oldLabelPos);
5385  QVERIFY(nativeLabel->winId());
5386  parent.show();
5388  const QPoint delta(50, 50);
5389  parent.scroll(delta.x(), delta.y());
5390  const QPoint newLabelPos = oldLabelPos + delta;
5391  QWindow *labelWindow = nativeLabel->windowHandle();
5392  QVERIFY(labelWindow);
5393  QTRY_COMPARE(labelWindow->geometry().topLeft(), newLabelPos);
5394  QTRY_COMPARE(nativeLabel->geometry().topLeft(), newLabelPos);
5395 }
5396 
5397 #endif // Mac OS
5398 
5399 class DestroyedSlotChecker : public QObject
5400 {
5401  Q_OBJECT
5402 
5403 public:
5404  bool wasQWidget = false;
5405 
5406 public slots:
5407  void destroyedSlot(QObject *object)
5408  {
5409  wasQWidget = (qobject_cast<QWidget *>(object) != nullptr || object->isWidgetType());
5410  }
5411 };
5412 
5413 /*
5414  Test that qobject_cast<QWidget*> returns 0 in a slot
5415  connected to QObject::destroyed.
5416 */
5417 void tst_QWidget::qobject_castInDestroyedSlot()
5418 {
5419  DestroyedSlotChecker checker;
5420 
5421  QWidget *widget = new QWidget();
5422 
5424  delete widget;
5425 
5426  QVERIFY(checker.wasQWidget);
5427 }
5428 
5429 // Since X11 WindowManager operations are all async, and we have no way to know if the window
5430 // manager has finished playing with the window geometry, this test can't be reliable on X11.
5431 
5433 
5434 void tst_QWidget::setWindowGeometry_data()
5435 {
5436  QTest::addColumn<Rects>("rects");
5437  QTest::addColumn<int>("windowFlags");
5438 
5439  QList<Rects> rects;
5440  const int width = m_testWidgetSize.width();
5441  const int height = m_testWidgetSize.height();
5442  const QRect availableAdjusted = QGuiApplication::primaryScreen()->availableGeometry().adjusted(100, 100, -100, -100);
5443  rects << Rects{QRect(m_availableTopLeft + QPoint(100, 100), m_testWidgetSize),
5444  availableAdjusted,
5445  QRect(m_availableTopLeft + QPoint(130, 100), QSize(0, height)),
5446  QRect(m_availableTopLeft + QPoint(100, 50), QSize(width, 0)),
5447  QRect(m_availableTopLeft + QPoint(130, 50), QSize(0, 0))}
5448  << Rects{availableAdjusted,
5449  QRect(m_availableTopLeft + QPoint(130, 100), QSize(0, height)),
5450  QRect(m_availableTopLeft + QPoint(100, 50), QSize(width, 0)),
5451  QRect(m_availableTopLeft + QPoint(130, 50), QSize(0, 0)),
5452  QRect(m_availableTopLeft + QPoint(100, 100), QSize(width, height))}
5453  << Rects{QRect(m_availableTopLeft + QPoint(130, 100), QSize(0, height)),
5454  QRect(m_availableTopLeft + QPoint(100, 50), QSize(width, 0)),
5455  QRect(m_availableTopLeft + QPoint(130, 50), QSize(0, 0)),
5456  QRect(m_availableTopLeft + QPoint(100, 100), QSize(width, height)),
5457  availableAdjusted}
5458  << Rects{QRect(m_availableTopLeft + QPoint(100, 50), QSize(width, 0)),
5459  QRect(m_availableTopLeft + QPoint(130, 50), QSize(0, 0)),
5460  QRect(m_availableTopLeft + QPoint(100, 100), QSize(width, height)),
5461  availableAdjusted,
5462  QRect(m_availableTopLeft + QPoint(130, 100), QSize(0, height))}
5463  << Rects{QRect(m_availableTopLeft + QPoint(130, 50), QSize(0, 0)),
5464  QRect(m_availableTopLeft + QPoint(100, 100), QSize(width, height)),
5465  availableAdjusted,
5466  QRect(m_availableTopLeft + QPoint(130, 100), QSize(0, height)),
5467  QRect(m_availableTopLeft + QPoint(100, 50), QSize(width, 0))};
5468 
5469  const Qt::WindowFlags windowFlags[] = {Qt::WindowFlags(), Qt::FramelessWindowHint};
5470 
5471  const bool skipEmptyRects = (m_platform == QStringLiteral("windows"));
5472  for (Rects l : qAsConst(rects)) {
5473  if (skipEmptyRects)
5474  l.removeIf([] (const QRect &r) { return r.isEmpty(); });
5475  const QRect &rect = l.constFirst();
5476  for (int windowFlag : windowFlags) {
5477  QTest::newRow(QString("%1,%2 %3x%4, flags %5")
5478  .arg(rect.x())
5479  .arg(rect.y())
5480  .arg(rect.width())
5481  .arg(rect.height())
5482  .arg(windowFlag, 0, 16).toLatin1())
5483  << l
5484  << windowFlag;
5485  }
5486  }
5487 }
5488 
5489 void tst_QWidget::setWindowGeometry()
5490 {
5491  if (m_platform == QStringLiteral("xcb"))
5492  QSKIP("X11: Skip this test due to Window manager positioning issues.");
5493 
5494  QFETCH(Rects, rects);
5495  QFETCH(int, windowFlags);
5496  QRect rect = rects.takeFirst();
5497 
5498  {
5499  // test setGeometry() without actually showing the window
5500  QWidget widget;
5501  if (windowFlags != 0)
5502  widget.setWindowFlags(Qt::WindowFlags(windowFlags));
5503 
5505  QTest::qWait(100);
5507 
5508  // setGeometry() without showing
5509  for (const QRect &r : qAsConst(rects)) {
5510  widget.setGeometry(r);
5511  QTest::qWait(100);
5512  QCOMPARE(widget.geometry(), r);
5513  }
5514  }
5515 
5516  {
5517  // setGeometry() first, then show()
5518  QWidget widget;
5520  if (windowFlags != 0)
5521  widget.setWindowFlags(Qt::WindowFlags(windowFlags));
5522 
5524  widget.showNormal();
5525  if (rect.isValid()) {
5527  } else {
5528  // in case of an invalid rect, wait for the geometry to become
5529  // adjusted to the actual (valid) value.
5531  }
5533 
5534  // setGeometry() while shown
5535  for (const QRect &r : qAsConst(rects)) {
5536  widget.setGeometry(r);
5537  QTest::qWait(10);
5539  }
5541  QTest::qWait(20);
5543 
5544  // now hide
5545  widget.hide();
5546  QTest::qWait(20);
5548 
5549  // setGeometry() after hide()
5550  for (const QRect &r : qAsConst(rects)) {
5551  widget.setGeometry(r);
5552  QTest::qWait(10);
5554  }
5556  QTest::qWait(10);
5558 
5559  // show() again, geometry() should still be the same
5560  QTestPrivate::androidCompatibleShow(&widget);
5561  if (rect.isValid())
5564 
5565  // final hide(), again geometry() should be unchanged
5566  widget.hide();
5567  QTest::qWait(10);
5569  }
5570 
5571  {
5572  // show() first, then setGeometry()
5573  QWidget widget;
5575  if (windowFlags != 0)
5576  widget.setWindowFlags(Qt::WindowFlags(windowFlags));
5577 
5578  widget.showNormal();
5579  if (rect.isValid())
5582  QTest::qWait(10);
5584 
5585  // setGeometry() while shown
5586  for (const QRect &r : qAsConst(rects)) {
5587  widget.setGeometry(r);
5588  QTest::qWait(10);
5590  }
5592  QTest::qWait(10);
5594 
5595  // now hide
5596  widget.hide();
5597  QTest::qWait(10);
5599 
5600  // setGeometry() after hide()
5601  for (const QRect &r : qAsConst(rects)) {
5602  widget.setGeometry(r);
5603  QTest::qWait(10);
5605  }
5607  QTest::qWait(10);
5609 
5610  // show() again, geometry() should still be the same
5611  QTestPrivate::androidCompatibleShow(&widget);
5612  if (rect.isValid())
5614  QTest::qWait(10);
5616 
5617  // final hide(), again geometry() should be unchanged
5618  widget.hide();
5619  QTest::qWait(10);
5621  }
5622 }
5623 
5624 #if defined (Q_OS_WIN)
5625 void tst_QWidget::setGeometry_win()
5626 {
5627  QWidget widget;
5628 
5629  setFrameless(&widget);
5630  widget.setGeometry(QRect(m_availableTopLeft + QPoint(0, 600), QSize(100, 100)));
5631  widget.show();
5633  QRect geom = widget.normalGeometry();
5634  widget.close();
5635  widget.setGeometry(geom);
5637  widget.show();
5638  RECT rt;
5639  ::GetWindowRect(winHandleOf(&widget), &rt);
5640  QVERIFY2(rt.left <= m_availableTopLeft.x(),
5641  msgComparisonFailed(int(rt.left), "<=", m_availableTopLeft.x()));
5642  QVERIFY2(rt.top <= m_availableTopLeft.y(),
5643  msgComparisonFailed(int(rt.top), "<=", m_availableTopLeft.y()));
5644 }
5645 #endif // defined (Q_OS_WIN)
5646 
5647 // Since X11 WindowManager operation are all async, and we have no way to know if the window
5648 // manager has finished playing with the window geometry, this test can't be reliable on X11.
5649 
5650 void tst_QWidget::windowMoveResize_data()
5651 {
5652  setWindowGeometry_data();
5653 }
5654 
5655 void tst_QWidget::windowMoveResize()
5656 {
5657  if (m_platform == QStringLiteral("xcb"))
5658  QSKIP("X11: Skip this test due to Window manager positioning issues.");
5659  if (m_platform == QStringLiteral("wayland"))
5660  QSKIP("Wayland: This fails. Figure out why.");
5661 
5662  QFETCH(Rects, rects);
5663  QFETCH(int, windowFlags);
5664 
5665  QRect rect = rects.takeFirst();
5666 
5667  {
5668  // test setGeometry() without actually showing the window
5669  QWidget widget;
5670  if (windowFlags != 0)
5671  widget.setWindowFlags(Qt::WindowFlags(windowFlags));
5672 
5673  widget.move(rect.topLeft());
5674  widget.resize(rect.size());
5675  QTest::qWait(10);
5676  QTRY_COMPARE(widget.pos(), rect.topLeft());
5677  QTRY_COMPARE(widget.size(), rect.size());
5678 
5679  // move() without showing
5680  for (const QRect &r : qAsConst(rects)) {
5681  widget.move(r.topLeft());
5682  widget.resize(r.size());
5684  QTRY_COMPARE(widget.pos(), r.topLeft());
5685  QTRY_COMPARE(widget.size(), r.size());
5686  }
5687  }
5688 
5689  {
5690  // move() first, then show()
5691  QWidget widget;
5693  if (windowFlags != 0)
5694  widget.setWindowFlags(Qt::WindowFlags(windowFlags));
5695 
5696  widget.move(rect.topLeft());
5697  widget.resize(rect.size());
5698  widget.showNormal();
5699 
5700  QTest::qWait(10);
5701  QTRY_VERIFY2(HighDpi::fuzzyCompare(widget.pos(), rect.topLeft(), m_fuzz),
5702  qPrintable(HighDpi::msgPointMismatch(widget.pos(), rect.topLeft())));
5703  // Windows: Minimum size of decorated windows.
5704  const bool expectResizeFail = (!windowFlags && (rect.width() < 160 || rect.height() < 40))
5705  && m_platform == QStringLiteral("windows");
5706  if (!expectResizeFail)
5707  QTRY_COMPARE(widget.size(), rect.size());
5708 
5709  // move() while shown
5710  for (const QRect &r : qAsConst(rects)) {
5711  // XCB: First resize after show of zero-sized gets wrong win_gravity.
5712  const bool expectMoveFail = !windowFlags
5713  && ((widget.width() == 0 || widget.height() == 0) && r.width() != 0 && r.height() != 0)
5714  && m_platform == QStringLiteral("xcb")
5715  && (rect == QRect(QPoint(130, 100), QSize(0, 200))
5716  || rect == QRect(QPoint(100, 50), QSize(200, 0))
5717  || rect == QRect(QPoint(130, 50), QSize(0, 0)));
5718  widget.move(r.topLeft());
5719  widget.resize(r.size());
5721  if (!expectMoveFail) {
5722  QTRY_COMPARE(widget.pos(), r.topLeft());
5723  QTRY_COMPARE(widget.size(), r.size());
5724  }
5725  }
5726  widget.move(rect.topLeft());
5727  widget.resize(rect.size());
5729  QTRY_COMPARE(widget.pos(), rect.topLeft());
5730  QTRY_COMPARE(widget.size(), rect.size());
5731 
5732  // now hide
5733  widget.hide();
5734  QTest::qWait(10);
5735  QTRY_COMPARE(widget.pos(), rect.topLeft());
5736  QTRY_COMPARE(widget.size(), rect.size());
5737 
5738  // move() after hide()
5739  for (const QRect &r : qAsConst(rects)) {
5740  widget.move(r.topLeft());
5741  widget.resize(r.size());
5743 #if defined(Q_OS_MACOS)
5744  if (r.width() == 0 && r.height() > 0) {
5745  widget.move(r.topLeft());
5746  widget.resize(r.size());
5747  }
5748 #endif
5749  QTRY_COMPARE(widget.pos(), r.topLeft());
5750  QTRY_COMPARE(widget.size(), r.size());
5751  }
5752  widget.move(rect.topLeft());
5753  widget.resize(rect.size());
5754  QTest::qWait(10);
5755  QTRY_COMPARE(widget.pos(), rect.topLeft());
5756  QTRY_COMPARE(widget.size(), rect.size());
5757 
5758  // show() again, pos() should be the same
5759  QTestPrivate::androidCompatibleShow(&widget);
5760  if (rect.isValid())
5763  QTRY_COMPARE(widget.pos(), rect.topLeft());
5764  QTRY_COMPARE(widget.size(), rect.size());
5765 
5766  // final hide(), again pos() should be unchanged
5767  widget.hide();
5769  QTRY_COMPARE(widget.pos(), rect.topLeft());
5770  QTRY_COMPARE(widget.size(), rect.size());
5771  }
5772 
5773  {
5774  // show() first, then move()
5775  QWidget widget;
5776  if (windowFlags != 0)
5777  widget.setWindowFlags(Qt::WindowFlags(windowFlags));
5778 
5779  widget.showNormal();
5780  if (rect.isValid())
5783  widget.move(rect.topLeft());
5784  widget.resize(rect.size());
5786  QTRY_COMPARE(widget.pos(), rect.topLeft());
5787  QTRY_COMPARE(widget.size(), rect.size());
5788 
5789  // move() while shown
5790  for (const QRect &r : qAsConst(rects)) {
5791  widget.move(r.topLeft());
5792  widget.resize(r.size());
5794  QTRY_COMPARE(widget.pos(), r.topLeft());
5795  QTRY_COMPARE(widget.size(), r.size());
5796  }
5797  widget.move(rect.topLeft());
5798  widget.resize(rect.size());
5800  QTRY_COMPARE(widget.pos(), rect.topLeft());
5801  QTRY_COMPARE(widget.size(), rect.size());
5802 
5803  // now hide
5804  widget.hide();
5806  QTRY_COMPARE(widget.pos(), rect.topLeft());
5807  QTRY_COMPARE(widget.size(), rect.size());
5808 
5809  // move() after hide()
5810  for (const QRect &r : qAsConst(rects)) {
5811  widget.move(r.topLeft());
5812  widget.resize(r.size());
5814 #if defined(Q_OS_MACOS)
5815  if (r.width() == 0 && r.height() > 0) {
5816  widget.move(r.topLeft());
5817  widget.resize(r.size());
5818  }
5819 #endif
5820  QTRY_COMPARE(widget.pos(), r.topLeft());
5821  QTRY_COMPARE(widget.size(), r.size());
5822  }
5823  widget.move(rect.topLeft());
5824  widget.resize(rect.size());
5826  QTRY_COMPARE(widget.pos(), rect.topLeft());
5827  QTRY_COMPARE(widget.size(), rect.size());
5828 
5829  // show() again, pos() should be the same
5830  QTestPrivate::androidCompatibleShow(&widget);
5831  if (rect.isValid())
5833  QTest::qWait(10);
5834  QTRY_COMPARE(widget.pos(), rect.topLeft());
5835  QTRY_COMPARE(widget.size(), rect.size());
5836 
5837  // final hide(), again pos() should be unchanged
5838  widget.hide();
5839  QTest::qWait(10);
5840  QTRY_COMPARE(widget.pos(), rect.topLeft());
5841  QTRY_COMPARE(widget.size(), rect.size());
5842  }
5843 }
5844 
5845 class ColorWidget : public QWidget
5846 {
5847 public:
5848  explicit ColorWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags(),
5849  const QColor &c = QColor(Qt::red))
5850  : QWidget(parent, f), color(c)
5851  {
5852  QPalette opaquePalette = palette();
5853  opaquePalette.setColor(backgroundRole(), color);
5854  setPalette(opaquePalette);
5855  setAutoFillBackground(true);
5856  }
5857 
5858  void paintEvent(QPaintEvent *e) override
5859  {
5860  r += e->region();
5861  }
5862 
5863  void reset()
5864  {
5865  r = QRegion();
5866  }
5867 
5868  void enterEvent(QEnterEvent *) override { ++enters; }
5869  void leaveEvent(QEvent *) override { ++leaves; }
5870 
5872  {
5873  enters = 0;
5874  leaves = 0;
5875  }
5876 
5877  QColor color;
5879  int enters = 0;
5880  int leaves = 0;
5881 };
5882 
5883 static inline QByteArray msgRgbMismatch(unsigned actual, unsigned expected)
5884 {
5885  return QByteArrayLiteral("Color mismatch, 0x") + QByteArray::number(actual, 16) +
5886  QByteArrayLiteral(" != 0x") + QByteArray::number(expected, 16);
5887 }
5888 
5889 static QPixmap grabWindow(QWindow *window, int x, int y, int width, int height)
5890 {
5891  QScreen *screen = window->screen();
5892  Q_ASSERT(screen);
5893  return screen->grabWindow(window->winId(), x, y, width, height);
5894 }
5895 
5896 #define VERIFY_COLOR(child, region, color) verifyColor(child, region, color, __LINE__)
5897 
5898 bool verifyColor(QWidget &child, const QRegion &region, const QColor &color, int callerLine)
5899 {
5900  QWindow *window = child.window()->windowHandle();
5901  Q_ASSERT(window);
5902  const QPoint offset = child.mapTo(child.window(), QPoint(0,0));
5903  bool grabBackingStore = false;
5904  for (QRect r : region) {
5905  QRect rect = r.translated(offset);
5906  for (int t = 0; t < 6; t++) {
5907  const QPixmap pixmap = grabBackingStore
5908  ? child.grab(rect)
5909  : grabWindow(window, rect.left(), rect.top(), rect.width(), rect.height());
5910  const QSize actualSize = pixmap.size() / pixmap.devicePixelRatio();
5911  if (!QTest::qCompare(actualSize, rect.size(), "pixmap.size()", "rect.size()", __FILE__, callerLine))
5912  return false;
5913  QPixmap expectedPixmap(pixmap); /* ensure equal formats */
5914  expectedPixmap.detach();
5915  expectedPixmap.fill(color);
5916  QImage image = pixmap.toImage();
5917  uint alphaCorrection = image.format() == QImage::Format_RGB32 ? 0xff000000 : 0;
5918  uint firstPixel = image.pixel(0,0) | alphaCorrection;
5919  if (t < 5) {
5920  /* Normal run.
5921  If it succeeds: return success
5922  If it fails: do not return, but wait a bit and reiterate (retry)
5923  */
5924  if (firstPixel == QColor(color).rgb() && image == expectedPixmap.toImage())
5925  return true;
5926  if (t == 4) {
5927  grabBackingStore = true;
5928  rect = r;
5929  } else {
5930  QTest::qWait(200);
5931  }
5932  } else {
5933  // Last run, report failure if it still fails
5934  if (!QTest::qVerify(firstPixel == QColor(color).rgb(),
5935  "firstPixel == QColor(color).rgb()",
5936  qPrintable(msgRgbMismatch(firstPixel, QColor(color).rgb())),
5937  __FILE__, callerLine))
5938  return false;
5939  if (!QTest::qVerify(image == expectedPixmap.toImage(),
5940  "image == expectedPixmap.toImage()",
5941  "grabbed pixmap differs from expected pixmap",
5942  __FILE__, callerLine))
5943  return false;
5944  }
5945  }
5946  }
5947  return true;
5948 }
5949 
5950 void tst_QWidget::moveChild_data()
5951 {
5952  QTest::addColumn<QPoint>("offset");
5953 
5954  QTest::newRow("right") << QPoint(20, 0);
5955  QTest::newRow("down") << QPoint(0, 20);
5956  QTest::newRow("left") << QPoint(-20, 0);
5957  QTest::newRow("up") << QPoint(0, -20);
5958 }
5959 
5960 void tst_QWidget::moveChild()
5961 {
5962  if (m_platform == QStringLiteral("wayland"))
5963  QSKIP("Wayland: This fails. Figure out why.");
5964  QFETCH(QPoint, offset);
5965 
5967  // prevent custom styles
5969  parent.setStyle(style.data());
5971 
5972  parent.setGeometry(QRect(m_availableTopLeft + QPoint(50, 50), QSize(200, 200)));
5973  child.setGeometry(25, 25, 50, 50);
5974 #ifndef QT_NO_CURSOR // Try to make sure the cursor is not in a taskbar area to prevent tooltips or window highlighting
5975  QCursor::setPos(parent.geometry().topRight() + QPoint(50 , 50));
5976 #endif
5977  parent.showNormal();
5979 
5981  // On some platforms (macOS), the palette will be different depending on if a
5982  // window is active or not. And because of that, the whole window will be
5983  // repainted when going from Inactive to Active. So wait for the window to be
5984  // active before we continue, so the activation doesn't happen at a random
5985  // time below. And call processEvents to have the paint events delivered right away.
5987  qApp->processEvents();
5988  }
5989 
5990  QTRY_COMPARE(parent.r, QRegion(parent.rect()) - child.geometry());
5991  QTRY_COMPARE(child.r, QRegion(child.rect()));
5992 
5993  VERIFY_COLOR(child, child.rect(),
5994  child.color);
5995  VERIFY_COLOR(parent, QRegion(parent.rect()) - child.geometry(), parent.color);
5996  parent.reset();
5997  child.reset();
5998 
5999  // move
6000 
6001  const QRect oldGeometry = child.geometry();
6002 
6003  QPoint pos = child.pos() + offset;
6004  child.move(pos);
6005  QTRY_COMPARE(pos, child.pos());
6006 
6007  QTRY_COMPARE(parent.r, QRegion(oldGeometry) - child.geometry());
6008 
6009  // should be scrolled in backingstore
6010  QCOMPARE(child.r, QRegion());
6011  VERIFY_COLOR(child, child.rect(), child.color);
6012  VERIFY_COLOR(parent, QRegion(parent.rect()) - child.geometry(), parent.color);
6013 }
6014 
6015 void tst_QWidget::showAndMoveChild()
6016 {
6017  if (m_platform == QStringLiteral("wayland"))
6018  QSKIP("Wayland: This fails. Figure out why.");
6020  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
6021  // prevent custom styles
6023  parent.setStyle(style.data());
6024 
6025  QRect desktopDimensions = parent.screen()->availableGeometry();
6026  desktopDimensions = desktopDimensions.adjusted(64, 64, -64, -64);
6027 
6028 #ifndef QT_NO_CURSOR // Try to make sure the cursor is not in a taskbar area to prevent tooltips or window highlighting
6029  QCursor::setPos(desktopDimensions.topRight() + QPoint(40, 40));
6030 #endif
6031  parent.setGeometry(desktopDimensions);
6032  parent.setPalette(Qt::red);
6033  parent.show();
6036 
6037  QWidget child(&parent);
6038  child.resize(desktopDimensions.width()/2, desktopDimensions.height()/2);
6039  child.setPalette(Qt::blue);
6040  child.setAutoFillBackground(true);
6041 
6042  // Ensure that the child is repainted correctly when moved right after show.
6043  // NB! Do NOT processEvents() (or qWait()) in between show() and move().
6044  child.show();
6045  child.move(desktopDimensions.width()/2, desktopDimensions.height()/2);
6047 
6048  VERIFY_COLOR(child, child.rect(), Qt::blue);
6050 }
6051 
6052 
6053 void tst_QWidget::subtractOpaqueSiblings()
6054 {
6055 #ifdef Q_OS_MACOS
6056  QSKIP("QTBUG-52974: Cocoa only has rect granularity.");
6057 #endif
6058 
6059  QWidget w;
6060  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
6061  w.setGeometry(50, 50, 300, 300);
6062 
6063  ColorWidget *large = new ColorWidget(&w, Qt::Widget, Qt::red);
6064  large->setGeometry(50, 50, 200, 200);
6065 
6066  ColorWidget *medium = new ColorWidget(large, Qt::Widget, Qt::gray);
6067  medium->setGeometry(50, 50, 100, 100);
6068 
6069  ColorWidget *tall = new ColorWidget(&w, Qt::Widget, Qt::blue);
6070  tall->setGeometry(100, 30, 50, 100);
6071 
6072  w.show();
6074 
6075  large->reset();
6076  medium->reset();
6077  tall->reset();
6078 
6079  medium->update();
6080 
6081  // QWidgetPrivate::subtractOpaqueSiblings() should prevent parts of medium
6082  // to be repainted and tall from be repainted at all.
6083 
6084  QTRY_COMPARE(large->r, QRegion());
6085  QTRY_COMPARE(tall->r, QRegion());
6086  QTRY_COMPARE(medium->r.translated(medium->mapTo(&w, QPoint())),
6087  QRegion(medium->geometry().translated(large->pos()))
6088  - tall->geometry());
6089 }
6090 
6091 void tst_QWidget::deleteStyle()
6092 {
6093  QWidget widget;
6096  widget.show();
6097  delete widget.style();
6099 }
6100 
6101 class TopLevelFocusCheck: public QWidget
6102 {
6103  Q_OBJECT
6104 public:
6106  explicit TopLevelFocusCheck(QWidget *parent = nullptr)
6107  : QWidget(parent), edit(new QLineEdit(this))
6108  {
6109  edit->hide();
6110  edit->installEventFilter(this);
6111  }
6112 
6113 public slots:
6114  void mouseDoubleClickEvent ( QMouseEvent * /*event*/ ) override
6115  {
6116  edit->show();
6119  }
6120  bool eventFilter(QObject *obj, QEvent *event) override
6121  {
6122  if (obj == edit && event->type()== QEvent::FocusOut) {
6123  edit->hide();
6124  return true;
6125  }
6126  return false;
6127  }
6128 };
6129 
6130 void tst_QWidget::multipleToplevelFocusCheck()
6131 {
6132 #ifdef Q_OS_MACOS
6133  QSKIP("QTBUG-52974");
6134 #endif
6135 
6137  QSKIP("Window activation is not supported");
6140 
6142  w1.setWindowTitle(title + QLatin1String("_W1"));
6143  w1.move(m_availableTopLeft + QPoint(20, 20));
6144  w1.resize(200, 200);
6145  w1.show();
6147  w2.setWindowTitle(title + QLatin1String("_W2"));
6148  w2.move(w1.frameGeometry().topRight() + QPoint(20, 0));
6149  w2.resize(200,200);
6150  w2.show();
6152 
6154  w1.activateWindow();
6156  QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w1));
6158  QTRY_COMPARE(QApplication::focusWidget(), static_cast<QWidget *>(w1.edit));
6159 
6160  w2.activateWindow();
6163  QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w2));
6166 
6168  QTRY_COMPARE(QApplication::focusWidget(), static_cast<QWidget *>(w2.edit));
6169 
6170  w1.activateWindow();
6173  QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w1));
6175  QTRY_COMPARE(QApplication::focusWidget(), static_cast<QWidget *>(w1.edit));
6176 
6177  w2.activateWindow();
6180  QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&w2));
6183 }
6184 
6185 class FocusWidget: public QWidget
6186 {
6187 protected:
6188  bool event(QEvent *ev) override
6189  {
6190  if (ev->type() == QEvent::FocusAboutToChange)
6192  return QWidget::event(ev);
6193  }
6194  void focusInEvent(QFocusEvent *) override
6195  {
6198  }
6199  void focusOutEvent(QFocusEvent *) override
6200  {
6204  }
6205 
6206  void focusObjectChanged(QObject *focusObject)
6207  {
6208  mostRecentFocusObjectChange = focusObject;
6209  }
6210 
6211 public:
6213  {
6215  }
6216 
6219 
6222 
6225 };
6226 
6227 void tst_QWidget::setFocus()
6228 {
6230  QSKIP("Window activation is not supported");
6231 
6232  QScopedPointer<QWidget> testWidget(new QWidget);
6233  testWidget->resize(m_testWidgetSize);
6234  testWidget->setWindowTitle(__FUNCTION__);
6235  centerOnScreen(testWidget.data());
6236  testWidget->show();
6237  QVERIFY(QTest::qWaitForWindowExposed(testWidget.data()));
6238 
6239  const QPoint windowPos = testWidget->geometry().topRight() + QPoint(50, 0);
6240  {
6241  // move focus to another window
6242  testWidget->activateWindow();
6243  QApplication::setActiveWindow(testWidget.data());
6244  if (testWidget->focusWidget())
6245  testWidget->focusWidget()->clearFocus();
6246  else
6247  testWidget->clearFocus();
6248 
6249  // window and children never shown, nobody gets focus
6250  QWidget window;
6251  window.setWindowTitle(QStringLiteral("#1 ") + __FUNCTION__);
6252  window.resize(m_testWidgetSize);
6253  window.move(windowPos);
6254 
6255  QWidget child1(&window);
6256  child1.setFocusPolicy(Qt::StrongFocus);
6257 
6258  QWidget child2(&window);
6259  child2.setFocusPolicy(Qt::StrongFocus);
6260 
6261  child1.setFocus();
6262  QVERIFY(!child1.hasFocus());
6263  QCOMPARE(window.focusWidget(), &child1);
6264  QCOMPARE(QApplication::focusWidget(), nullptr);
6265 
6266  child2.setFocus();
6267  QVERIFY(!child2.hasFocus());
6268  QCOMPARE(window.focusWidget(), &child2);
6269  QCOMPARE(QApplication::focusWidget(), nullptr);
6270  }
6271 
6272  {
6273  // window and children show, but window not active, nobody gets focus
6274  QWidget window;
6275  window.setWindowTitle(QStringLiteral("#2 ") + __FUNCTION__);
6276  window.resize(m_testWidgetSize);
6277  window.move(windowPos);
6278 
6279  QWidget child1(&window);
6281 
6282  QWidget child2(&window);
6284 
6285  window.show();
6286 
6287  // note: window may be active, but we don't want it to be
6288  testWidget->activateWindow();
6289  QApplication::setActiveWindow(testWidget.data());
6290  if (testWidget->focusWidget())
6291  testWidget->focusWidget()->clearFocus();
6292  else
6293  testWidget->clearFocus();
6294 
6295  child1.setFocus();
6296  QVERIFY(!child1.hasFocus());
6297  QCOMPARE(window.focusWidget(), &child1);
6298  QCOMPARE(QApplication::focusWidget(), nullptr);
6299 
6300  child2.setFocus();
6301  QVERIFY(!child2.hasFocus());
6302  QCOMPARE(window.focusWidget(), &child2);
6303  QCOMPARE(QApplication::focusWidget(), nullptr);
6304  }
6305 
6306  {
6307  // window and children show, but window *is* active, children get focus
6308  QWidget window;
6309  window.setWindowTitle(QStringLiteral("#3 ") + __FUNCTION__);
6310  window.resize(m_testWidgetSize);
6311  window.move(windowPos);
6312 
6313  FocusWidget child1(&window);
6315 
6316  QWidget child2(&window);
6318 
6319  window.show();
6320  window.activateWindow();
6323 
6324  child1.setFocus();
6325  QTRY_VERIFY(child1.hasFocus());
6326  QCOMPARE(window.focusWidget(), &child1);
6327  QCOMPARE(QApplication::focusWidget(), &child1);
6328 
6329  child2.setFocus();
6330  QVERIFY(child2.hasFocus());
6331  QCOMPARE(window.focusWidget(), &child2);
6332  QCOMPARE(QApplication::focusWidget(), &child2);
6333 
6334  // focus changed in between the events
6335  QCOMPARE(child1.widgetDuringFocusAboutToChange, &child1);
6336  QCOMPARE(child1.widgetDuringFocusOut, &child2);
6337  }
6338 
6339  {
6340  // window shown and active, children created, don't get focus, but get focus when shown
6341  QWidget window;
6342  window.setWindowTitle(QStringLiteral("#4 ") + __FUNCTION__);
6343  window.resize(m_testWidgetSize);
6344  window.move(windowPos);
6345 
6346  window.show();
6347  window.activateWindow();
6350 
6351  QWidget child1(&window);
6353 
6354  QWidget child2(&window);
6356 
6357  child1.setFocus();
6358  QVERIFY(!child1.hasFocus());
6359  QCOMPARE(window.focusWidget(), nullptr);
6360  QCOMPARE(QApplication::focusWidget(), nullptr);
6361 
6362  child1.show();
6364  QTRY_VERIFY(child1.hasFocus());
6365  QCOMPARE(window.focusWidget(), &child1);
6366  QCOMPARE(QApplication::focusWidget(), &child1);
6367 
6368  child2.setFocus();
6369  QVERIFY(!child2.hasFocus());
6370  QCOMPARE(window.focusWidget(), &child1);
6371  QCOMPARE(QApplication::focusWidget(), &child1);
6372 
6373  child2.show();
6374  QVERIFY(child2.hasFocus());
6375  QCOMPARE(window.focusWidget(), &child2);
6376  QCOMPARE(QApplication::focusWidget(), &child2);
6377  }
6378 
6379  {
6380  // window shown and active, children created, don't get focus,
6381  // even after setFocus(), hide(), then show()
6382  QWidget window;
6383  window.setWindowTitle(QStringLiteral("#5 ") + __FUNCTION__);
6384  window.resize(m_testWidgetSize);
6385  window.move(windowPos);
6386 
6387  window.show();
6388  window.activateWindow();
6391 
6392  QWidget child1(&window);
6394 
6395  QWidget child2(&window);
6397 
6398  child1.setFocus();
6399  QVERIFY(!child1.hasFocus());
6400  QCOMPARE(window.focusWidget(), nullptr);
6401  QCOMPARE(QApplication::focusWidget(), nullptr);
6402 
6403  child1.hide();
6404  QVERIFY(!child1.hasFocus());
6405  QCOMPARE(window.focusWidget(), nullptr);
6406  QCOMPARE(QApplication::focusWidget(), nullptr);
6407 
6408  child1.show();
6409  QVERIFY(!child1.hasFocus());
6410  QCOMPARE(window.focusWidget(), nullptr);
6411  QCOMPARE(QApplication::focusWidget(), nullptr);
6412 
6413  child2.setFocus();
6414  QVERIFY(!child2.hasFocus());
6415  QCOMPARE(window.focusWidget(), nullptr);
6416  QCOMPARE(QApplication::focusWidget(), nullptr);
6417 
6418  child2.hide();
6419  QVERIFY(!child2.hasFocus());
6420  QCOMPARE(window.focusWidget(), nullptr);
6421  QCOMPARE(QApplication::focusWidget(), nullptr);
6422 
6423  child2.show();
6424  QVERIFY(!child2.hasFocus());
6425  QCOMPARE(window.focusWidget(), nullptr);
6426  QCOMPARE(QApplication::focusWidget(), nullptr);
6427  }
6428 
6429  {
6430  QWidget window;
6431  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
6432  window.resize(m_testWidgetSize);
6433  window.move(windowPos);
6434 
6435  FocusWidget child1(&window);
6436  QWidget child2(&window);
6437 
6438  window.show();
6439  window.activateWindow();
6442 
6444 
6445  child1.setFocus();
6446  QTRY_VERIFY(child1.hasFocus());
6447  QCOMPARE(window.focusWidget(), &child1);
6448  QCOMPARE(QApplication::focusWidget(), &child1);
6449  QCOMPARE(QApplication::focusObject(), &child1);
6450  QCOMPARE(child1.focusObjectDuringFocusIn, &child1);
6451  QVERIFY2(!child1.detectedBadEventOrdering,
6452  "focusObjectChanged should be delivered before widget focus events on setFocus");
6453 
6454  child1.clearFocus();
6455  QTRY_VERIFY(!child1.hasFocus());
6456  QCOMPARE(window.focusWidget(), nullptr);
6457  QCOMPARE(QApplication::focusWidget(), nullptr);
6459  QVERIFY(child1.focusObjectDuringFocusOut != &child1);
6460  QVERIFY2(!child1.detectedBadEventOrdering,
6461  "focusObjectChanged should be delivered before widget focus events on clearFocus");
6462  }
6463 }
6464 
6465 template<class T> class EventSpy : public QObject
6466 {
6467 public:
6469  : m_widget(widget), eventToSpy(event)
6470  {
6471  if (m_widget)
6472  m_widget->installEventFilter(this);
6473  }
6474 
6475  T *widget() const { return m_widget; }
6476  int count() const { return m_count; }
6477  void clear() { m_count = 0; }
6478 
6479 protected:
6480  bool eventFilter(QObject *object, QEvent *event) override
6481  {
6482  if (event->type() == eventToSpy)
6483  ++m_count;
6484  return QObject::eventFilter(object, event);
6485  }
6486 
6487 private:
6488  T *m_widget;
6489  const QEvent::Type eventToSpy;
6490  int m_count = 0;
6491 };
6492 
6493 #ifndef QT_NO_CURSOR
6494 void tst_QWidget::setCursor()
6495 {
6496  {
6497  QWidget window;
6498  window.resize(200, 200);
6499  QWidget child(&window);
6500 
6501  QVERIFY(!window.testAttribute(Qt::WA_SetCursor));
6502  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6503 
6504  window.setCursor(window.cursor());
6505  QVERIFY(window.testAttribute(Qt::WA_SetCursor));
6506  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6507  QCOMPARE(child.cursor().shape(), window.cursor().shape());
6508  }
6509 
6510  // do it again, but with window show()n
6511  {
6512  QWidget window;
6513  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
6514  window.resize(200, 200);
6515  QWidget child(&window);
6516  window.show();
6517 
6518  QVERIFY(!window.testAttribute(Qt::WA_SetCursor));
6519  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6520 
6521  window.setCursor(window.cursor());
6522  QVERIFY(window.testAttribute(Qt::WA_SetCursor));
6523  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6524  QCOMPARE(child.cursor().shape(), window.cursor().shape());
6525  }
6526 
6527 
6528  {
6529  QWidget window;
6530  window.resize(200, 200);
6531  QWidget child(&window);
6532 
6533  window.setCursor(Qt::WaitCursor);
6534  QVERIFY(window.testAttribute(Qt::WA_SetCursor));
6535  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6536  QCOMPARE(child.cursor().shape(), window.cursor().shape());
6537  }
6538 
6539  // same thing again, just with window show()n
6540  {
6541  QWidget window;
6542  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
6543  window.resize(200, 200);
6544  QWidget child(&window);
6545 
6546  window.show();
6548  window.setCursor(Qt::WaitCursor);
6549  QVERIFY(window.testAttribute(Qt::WA_SetCursor));
6550  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6551  QCOMPARE(child.cursor().shape(), window.cursor().shape());
6552  }
6553 
6554  // reparenting child should not cause the WA_SetCursor to become set
6555  {
6556  QWidget window;
6557  window.resize(200, 200);
6558  QWidget window2;
6559  window2.resize(200, 200);
6560  QWidget child(&window);
6561 
6562  window.setCursor(Qt::WaitCursor);
6563 
6564  child.setParent(nullptr);
6565  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6566  QCOMPARE(child.cursor().shape(), QCursor().shape());
6567 
6568  child.setParent(&window2);
6569  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6570  QCOMPARE(child.cursor().shape(), window2.cursor().shape());
6571 
6572  window2.setCursor(Qt::WaitCursor);
6573  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6574  QCOMPARE(child.cursor().shape(), window2.cursor().shape());
6575  }
6576 
6577  // again, with windows show()n
6578  {
6579  QWidget window;
6580  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
6581  window.resize(200, 200);
6582  QWidget window2;
6583  window2.resize(200, 200);
6584  QWidget child(&window);
6585 
6586  window.setCursor(Qt::WaitCursor);
6587  window.show();
6588 
6589  child.setParent(nullptr);
6590  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6591  QCOMPARE(child.cursor().shape(), QCursor().shape());
6592 
6593  child.setParent(&window2);
6594  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6595  QCOMPARE(child.cursor().shape(), window2.cursor().shape());
6596 
6597  window2.show();
6598  window2.setCursor(Qt::WaitCursor);
6599  QVERIFY(!child.testAttribute(Qt::WA_SetCursor));
6600  QCOMPARE(child.cursor().shape(), window2.cursor().shape());
6601  }
6602 
6603  // test if CursorChange is sent
6604  {
6605  QWidget widget;
6607  QCOMPARE(spy.count(), 0);
6608  widget.setCursor(QCursor(Qt::WaitCursor));
6609  QCOMPARE(spy.count(), 1);
6610  widget.unsetCursor();
6611  QCOMPARE(spy.count(), 2);
6612  }
6613 }
6614 #endif
6615 
6616 void tst_QWidget::setToolTip()
6617 {
6619  QSKIP("Setting mouse cursor position is not possible on Wayland");
6620 
6621  QWidget widget;
6622  widget.resize(200, 200);
6623  // Showing the widget is not required for the tooltip event count test
6624  // to work. It should just prevent the application from becoming inactive
6625  // which would cause it to close all popups, interfering with the test
6626  // in the loop below.
6627  widget.setObjectName(QLatin1String("tst_qwidget setToolTip"));
6629  widget.show();
6632  QCOMPARE(spy.count(), 0);
6633 
6634  QCOMPARE(widget.toolTip(), QString());
6635  widget.setToolTip(QString("Hello"));
6636  QCOMPARE(widget.toolTip(), QString("Hello"));
6637  QCOMPARE(spy.count(), 1);
6638  widget.setToolTip(QString());
6639  QCOMPARE(widget.toolTip(), QString());
6640  QCOMPARE(spy.count(), 2);
6641 
6642  const int wakeUpDelay = widget.style()->styleHint(QStyle::SH_ToolTip_WakeUpDelay);
6643  const int fallAsleepDelay = widget.style()->styleHint(QStyle::SH_ToolTip_FallAsleepDelay);
6644 
6645  for (int pass = 0; pass < 2; ++pass) {
6646  QCursor::setPos(m_safeCursorPos);
6647  QScopedPointer<QWidget> popup(new QWidget(nullptr, Qt::Popup));
6648  popup->setObjectName(QLatin1String("tst_qwidget setToolTip #") + QString::number(pass));
6649  popup->setWindowTitle(popup->objectName());
6650  popup->setGeometry(50, 50, 150, 50);
6651  QFrame *frame = new QFrame(popup.data());
6652  frame->setGeometry(0, 0, 50, 50);
6655  EventSpy<QWidget> spy2(popup.data(), QEvent::ToolTip);
6656  frame->setMouseTracking(pass != 0);
6657  frame->setToolTip(QLatin1String("TOOLTIP FRAME"));
6658  popup->setToolTip(QLatin1String("TOOLTIP POPUP"));
6659  popup->show();
6660  QVERIFY(QTest::qWaitForWindowExposed(popup.data()));
6661  QWindow *popupWindow = popup->windowHandle();
6662  QTest::qWait(10);
6663  QTest::mouseMove(popupWindow, QPoint(25, 25));
6664  QTest::qWait(wakeUpDelay + 200);
6665 
6666  QCOMPARE(spy1.count(), 1);
6667  QCOMPARE(spy2.count(), 0);
6668  if (pass == 0)
6669  QTest::qWait(fallAsleepDelay + 200);
6670  QTest::mouseMove(popupWindow);
6671  }
6672 
6674 }
6675 
6676 void tst_QWidget::testWindowIconChangeEventPropagation()
6677 {
6678  typedef QSharedPointer<EventSpy<QWidget> > EventSpyPtr;
6679  typedef QSharedPointer<EventSpy<QWindow> > WindowEventSpyPtr;
6680  // Create widget hierarchy.
6681  QWidget topLevelWidget;
6682  topLevelWidget.setWindowTitle(QStringLiteral("TopLevel ") + __FUNCTION__);
6683  topLevelWidget.resize(m_testWidgetSize);
6684  topLevelWidget.move(m_availableTopLeft + QPoint(100, 100));
6685  QWidget topLevelChild(&topLevelWidget);
6686 
6687  QDialog dialog(&topLevelWidget);
6688  dialog.resize(m_testWidgetSize);
6689  dialog.move(topLevelWidget.geometry().topRight() + QPoint(100, 0));
6690  dialog.setWindowTitle(QStringLiteral("Dialog ") + __FUNCTION__);
6691  QWidget dialogChild(&dialog);
6692 
6694  widgets << &topLevelWidget << &topLevelChild
6695  << &dialog << &dialogChild;
6696  QCOMPARE(widgets.count(), 4);
6697 
6698  topLevelWidget.show();
6699  dialog.show();
6700 
6702  windows << topLevelWidget.windowHandle() << dialog.windowHandle();
6703  QWindow otherWindow;
6704  windows << &otherWindow;
6705  const int lastWidgetWindow = 1; // 0 and 1 are qwidgetwindow, 2 is a pure qwindow
6706 
6707  // Create spy lists.
6708  QList <EventSpyPtr> applicationEventSpies;
6709  QList <EventSpyPtr> widgetEventSpies;
6710  for (QWidget *widget : qAsConst(widgets)) {
6711  applicationEventSpies.append(EventSpyPtr::create(widget, QEvent::ApplicationWindowIconChange));
6712  widgetEventSpies.append(EventSpyPtr::create(widget, QEvent::WindowIconChange));
6713  }
6714  QList <WindowEventSpyPtr> appWindowEventSpies;
6715  QList <WindowEventSpyPtr> windowEventSpies;
6716  for (QWindow *window : qAsConst(windows)) {
6719  }
6720 
6721  // QApplication::setWindowIcon
6722  const QIcon windowIcon = qApp->style()->standardIcon(QStyle::SP_TitleBarMenuButton);
6723  qApp->setWindowIcon(windowIcon);
6724 
6725  for (int i = 0; i < widgets.count(); ++i) {
6726  // Check QEvent::ApplicationWindowIconChange
6727  EventSpyPtr spy = applicationEventSpies.at(i);
6728  QWidget *widget = spy->widget();
6729  if (widget->isWindow()) {
6730  QCOMPARE(spy->count(), 1);
6731  QCOMPARE(widget->windowIcon(), windowIcon);
6732  } else {
6733  QCOMPARE(spy->count(), 0);
6734  }
6735  spy->clear();
6736 
6737  // Check QEvent::WindowIconChange
6738  spy = widgetEventSpies.at(i);
6739  QCOMPARE(spy->count(), 1);
6740  spy->clear();
6741  }
6742  for (int i = 0; i < windows.count(); ++i) {
6743  // Check QEvent::ApplicationWindowIconChange (sent to QWindow)
6744  // QWidgetWindows don't get this event, since the widget takes care of changing the icon
6745  WindowEventSpyPtr spy = appWindowEventSpies.at(i);
6746  QWindow *window = spy->widget();
6747  QCOMPARE(spy->count(), i > lastWidgetWindow ? 1 : 0);
6748  QCOMPARE(window->icon(), windowIcon);
6749  spy->clear();
6750 
6751  // Check QEvent::WindowIconChange (sent to QWindow)
6752  spy = windowEventSpies.at(i);
6753  QCOMPARE(spy->count(), 1);
6754  spy->clear();
6755  }
6756 
6757  // Set icon on a top-level widget.
6758  topLevelWidget.setWindowIcon(QIcon());
6759 
6760  for (int i = 0; i < widgets.count(); ++i) {
6761  // Check QEvent::ApplicationWindowIconChange
6762  EventSpyPtr spy = applicationEventSpies.at(i);
6763  QCOMPARE(spy->count(), 0);
6764  spy->clear();
6765 
6766  // Check QEvent::WindowIconChange
6767  spy = widgetEventSpies.at(i);
6768  QWidget *widget = spy->widget();
6769  if (widget == &topLevelWidget) {
6770  QCOMPARE(widget->windowIcon(), QIcon());
6771  QCOMPARE(spy->count(), 1);
6772  } else if (topLevelWidget.isAncestorOf(widget)) {
6773  QCOMPARE(spy->count(), 1);
6774  } else {
6775  QCOMPARE(spy->count(), 0);
6776  }
6777  spy->clear();
6778  }
6779 
6780  // Cleanup.
6781  qApp->setWindowIcon(QIcon());
6782 }
6783 
6784 void tst_QWidget::minAndMaxSizeWithX11BypassWindowManagerHint()
6785 {
6786  if (m_platform != QStringLiteral("xcb"))
6787  QSKIP("This test is for X11 only.");
6788  // Same size as in QWidgetPrivate::create.
6789  const QSize desktopSize = QGuiApplication::primaryScreen()->size();
6790  const QSize originalSize(desktopSize.width() / 2, desktopSize.height() * 4 / 10);
6791 
6792  { // Maximum size.
6795 
6796  const QSize newMaximumSize = widget.size().boundedTo(originalSize) - QSize(10, 10);
6797  widget.setMaximumSize(newMaximumSize);
6798  QCOMPARE(widget.size(), newMaximumSize);
6799 
6800  widget.show();
6802  QCOMPARE(widget.size(), newMaximumSize);
6803  }
6804 
6805  { // Minimum size.
6808 
6809  const QSize newMinimumSize = widget.size().expandedTo(originalSize) + QSize(10, 10);
6810  widget.setMinimumSize(newMinimumSize);
6811  QCOMPARE(widget.size(), newMinimumSize);
6812 
6813  widget.show();
6815  QCOMPARE(widget.size(), newMinimumSize);
6816  }
6817 }
6818 
6819 class ShowHideShowWidget : public QWidget, public QAbstractNativeEventFilter
6820 {
6821  Q_OBJECT
6822 
6823  int state = 0;
6824 public:
6825  bool gotExpectedMapNotify = false;
6827 
6829  {
6830  startTimer(1000);
6831  }
6832 
6833  void timerEvent(QTimerEvent *) override
6834  {
6835  switch (state++) {
6836  case 0:
6837  show();
6838  break;
6839  case 1:
6840  emit done();
6841  break;
6842  }
6843  }
6844 
6845  bool isMapNotify(const QByteArray &eventType, void *message)
6846  {
6847  enum { XCB_MAP_NOTIFY = 19 };
6848  if (state == 1 && eventType == QByteArrayLiteral("xcb_generic_event_t")) {
6849  // XCB events have a uint8 response_type member at the beginning.
6850  const auto responseType = *reinterpret_cast<const unsigned char *>(message);
6851  return ((responseType & ~0x80) == XCB_MAP_NOTIFY);
6852  }
6853  return false;
6854  }
6855 
6856 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
6857  bool nativeEvent(const QByteArray &eventType, void *message, qintptr *) override
6858 #else
6859  bool nativeEvent(const QByteArray &eventType, void *message, long *) override
6860 #endif
6861  {
6862  if (isMapNotify(eventType, message))
6863  gotExpectedMapNotify = true;
6864  return false;
6865  }
6866 
6867  // QAbstractNativeEventFilter interface
6868 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
6869  bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *) override
6870 #else
6871  bool nativeEventFilter(const QByteArray &eventType, void *message, long *) override
6872 #endif
6873  {
6874  if (isMapNotify(eventType, message))
6875  gotExpectedGlobalEvent = true;
6876  return false;
6877  }
6878 
6879 signals:
6880  void done();
6881 };
6882 
6883 void tst_QWidget::showHideShowX11()
6884 {
6885  if (m_platform != QStringLiteral("xcb"))
6886  QSKIP("This test is for X11 only.");
6887 
6889  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
6890  qApp->installNativeEventFilter(&w);
6891 
6892  w.show();
6894  w.hide();
6895 
6896  QEventLoop eventLoop;
6898  eventLoop.exec();
6899 
6900  QVERIFY(w.gotExpectedGlobalEvent);
6901  QVERIFY(w.gotExpectedMapNotify);
6902 }
6903 
6904 void tst_QWidget::clean_qt_x11_enforce_cursor()
6905 {
6906  if (m_platform != QStringLiteral("xcb"))
6907  QSKIP("This test is for X11 only.");
6908 
6909  {
6910  QWidget window;
6911  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
6912  QWidget *w = new QWidget(&window);
6913  QWidget *child = new QWidget(w);
6914  child->setAttribute(Qt::WA_SetCursor, true);
6915 
6916  window.show();
6919  QTest::qWait(100);
6920  QCursor::setPos(window.geometry().center());
6921  QTest::qWait(100);
6922 
6923  child->setFocus();
6924  QTest::qWait(100);
6925 
6926  delete w;
6927  }
6928 
6930  QLineEdit *edit = new QLineEdit;
6931  scene.addWidget(edit);
6932 
6933  // If the test didn't crash, then it passed.
6934 }
6935 
6936 class EventRecorder : public QObject
6937 {
6938  Q_OBJECT
6939 
6940 public:
6943 
6944  using QObject::QObject;
6945 
6947  {
6948  return events;
6949  }
6950 
6951  void clear()
6952  {
6953  events.clear();
6954  }
6955 
6956  bool eventFilter(QObject *object, QEvent *event) override
6957  {
6958  QWidget *widget = qobject_cast<QWidget *>(object);
6959  if (widget && !event->spontaneous()) {
6960  switch (event->type()) {
6961  // we might get those events if we couldn't move the cursor
6962  case QEvent::Enter:
6963  case QEvent::Leave:
6964  // we might get this on systems that have an input method installed
6966  break;
6967  default:
6968  events.append(qMakePair(widget, event->type()));
6969  break;
6970  }
6971  }
6972  return false;
6973  }
6974 
6975  static QByteArray msgEventListMismatch(const EventList &expected, const EventList &actual);
6976  static QByteArray msgExpectFailQtBug26424(const EventList &expected, const EventList &actual)
6977  { return QByteArrayLiteral("QTBUG-26424: ") + msgEventListMismatch(expected, actual); }
6978 
6979 private:
6980  static inline void formatEventList(const EventList &l, QDebug &d);
6981 
6982  EventList events;
6983 };
6984 
6985 void EventRecorder::formatEventList(const EventList &l, QDebug &d)
6986 {
6987  QWidget *lastWidget = nullptr;
6988  for (const WidgetEventTypePair &p : l) {
6989  if (p.first != lastWidget) {
6990  d << p.first << ':';
6991  lastWidget = p.first;
6992  }
6993  d << p.second << ' ';
6994  }
6995 }
6996 
6998 {
6999  QString result;
7000  QDebug d = QDebug(&result).nospace();
7001  d << "Event list mismatch, expected " << expected.size() << " (";
7002  EventRecorder::formatEventList(expected, d);
7003  d << "), actual " << actual.size() << " (";
7004  EventRecorder::formatEventList(actual, d);
7005  d << ')';
7006  return result.toLocal8Bit();
7007 }
7008 
7009 void tst_QWidget::childEvents()
7010 {
7011  EventRecorder::EventList expected;
7012 
7013  {
7014  // no children created, not shown
7015  QWidget widget;
7016  widget.resize(200, 200);
7019 
7021 
7023 
7024  expected =
7026  << qMakePair(&widget, QEvent::PolishRequest)
7027  << qMakePair(&widget, QEvent::Polish)
7028  << qMakePair(&widget, QEvent::Type(QEvent::User + 1));
7029  QVERIFY2(spy.eventList() == expected,
7030  EventRecorder::msgEventListMismatch(expected, spy.eventList()).constData());
7031  }
7032 
7033  {
7034  // no children, shown
7035  QWidget widget;
7036  widget.resize(200, 200);
7039 
7041 
7042  widget.showNormal();
7043  expected =
7045  << qMakePair(&widget, QEvent::Polish)
7046  << qMakePair(&widget, QEvent::PlatformSurface)
7047  << qMakePair(&widget, QEvent::WinIdChange)
7048  << qMakePair(&widget, QEvent::WindowIconChange)
7049  << qMakePair(&widget, QEvent::Move)
7050  << qMakePair(&widget, QEvent::Resize)
7051  << qMakePair(&widget, QEvent::Show)
7052 #ifndef Q_OS_ANDROID
7053  << qMakePair(&widget, QEvent::CursorChange)
7054 #endif
7055  << qMakePair(&widget, QEvent::ShowToParent);
7056 
7057  QVERIFY2(spy.eventList() == expected,
7058  EventRecorder::msgEventListMismatch(expected, spy.eventList()).constData());
7059  spy.clear();
7060 
7062  expected =
7064  << qMakePair(&widget, QEvent::PolishRequest)
7065  << qMakePair(&widget, QEvent::Type(QEvent::User + 1))
7066  << qMakePair(&widget, QEvent::UpdateLater)
7067  << qMakePair(&widget, QEvent::UpdateRequest);
7068 
7069  QVERIFY2(spy.eventList() == expected,
7070  EventRecorder::msgEventListMismatch(expected, spy.eventList()).constData());
7071  }
7072 
7073  {
7074  // 2 children, not shown
7075  QWidget widget;
7076  widget.resize(200, 200);
7079 
7081 
7082  QWidget child1(&widget);
7083  QWidget child2;
7084  child2.setParent(&widget);
7085 
7087 
7088  expected =
7090  << qMakePair(&widget, QEvent::ChildAdded)
7091  << qMakePair(&widget, QEvent::ChildAdded);
7092  QVERIFY2(spy.eventList() == expected,
7093  EventRecorder::msgEventListMismatch(expected, spy.eventList()).constData());
7094  spy.clear();
7095 
7097  expected =
7099  << qMakePair(&widget, QEvent::PolishRequest)
7100  << qMakePair(&widget, QEvent::Polish)
7101  << qMakePair(&widget, QEvent::ChildPolished)
7102  << qMakePair(&widget, QEvent::ChildPolished)
7103  << qMakePair(&widget, QEvent::Type(QEvent::User + 1))
7104  << qMakePair(&widget, QEvent::Type(QEvent::User + 2));
7105  QVERIFY2(spy.eventList() == expected,
7106  EventRecorder::msgEventListMismatch(expected, spy.eventList()).constData());
7107  }
7108 
7109  {
7110  // 2 children, widget shown
7111  QWidget widget;
7112  widget.resize(200, 200);
7115 
7117 
7118  QWidget child1(&widget);
7119  QWidget child2;
7120  child2.setParent(&widget);
7121 
7123 
7124  expected =
7126  << qMakePair(&widget, QEvent::ChildAdded)
7127  << qMakePair(&widget, QEvent::ChildAdded);
7128  QCOMPARE(spy.eventList(), expected);
7129  spy.clear();
7130 
7131  widget.showNormal();
7132  expected =
7134  << qMakePair(&widget, QEvent::Polish)
7135  << qMakePair(&widget, QEvent::ChildPolished)
7136  << qMakePair(&widget, QEvent::ChildPolished)
7137  << qMakePair(&widget, QEvent::PlatformSurface)
7138  << qMakePair(&widget, QEvent::WinIdChange)
7139  << qMakePair(&widget, QEvent::WindowIconChange)
7140  << qMakePair(&widget, QEvent::Move)
7141  << qMakePair(&widget, QEvent::Resize)
7142  << qMakePair(&widget, QEvent::Show)
7143 #ifndef Q_OS_ANDROID
7144  << qMakePair(&widget, QEvent::CursorChange)
7145 #endif
7146  << qMakePair(&widget, QEvent::ShowToParent);
7147 
7148  QVERIFY2(spy.eventList() == expected,
7149  EventRecorder::msgEventListMismatch(expected, spy.eventList()).constData());
7150  spy.clear();
7151 
7153  expected =
7155  << qMakePair(&widget, QEvent::PolishRequest)
7156  << qMakePair(&widget, QEvent::Type(QEvent::User + 1))
7157  << qMakePair(&widget, QEvent::Type(QEvent::User + 2))
7158  << qMakePair(&widget, QEvent::UpdateLater)
7159  << qMakePair(&widget, QEvent::UpdateRequest);
7160 
7161  QVERIFY2(spy.eventList() == expected,
7162  EventRecorder::msgEventListMismatch(expected, spy.eventList()).constData());
7163  }
7164 
7165  {
7166  // 2 children, but one is reparented away, not shown
7167  QWidget widget;
7168  widget.resize(200, 200);
7171 
7173 
7174  QWidget child1(&widget);
7175  QWidget child2;
7176  child2.setParent(&widget);
7177  child2.setParent(nullptr);
7178 
7180 
7181  expected =
7183  << qMakePair(&widget, QEvent::ChildAdded)
7184  << qMakePair(&widget, QEvent::ChildAdded)
7185  << qMakePair(&widget, QEvent::ChildRemoved);
7186  QCOMPARE(spy.eventList(), expected);
7187  spy.clear();
7188 
7190  expected =
7192  << qMakePair(&widget, QEvent::PolishRequest)
7193  << qMakePair(&widget, QEvent::Polish)
7194  << qMakePair(&widget, QEvent::ChildPolished)
7195  << qMakePair(&widget, QEvent::Type(QEvent::User + 1))
7196  << qMakePair(&widget, QEvent::Type(QEvent::User + 2));
7197 
7198  QVERIFY2(spy.eventList() == expected,
7199  EventRecorder::msgEventListMismatch(expected, spy.eventList()).constData());
7200  }
7201 
7202  {
7203  // 2 children, but one is reparented away, then widget is shown
7204  QWidget widget;
7205  widget.resize(200, 200);
7208 
7210 
7211  QWidget child1(&widget);
7212  QWidget child2;
7213  child2.setParent(&widget);
7214  child2.setParent(nullptr);
7215 
7217 
7218  expected =
7220  << qMakePair(&widget, QEvent::ChildAdded)
7221  << qMakePair(&widget, QEvent::ChildAdded)
7222  << qMakePair(&widget, QEvent::ChildRemoved);
7223  QCOMPARE(spy.eventList(), expected);
7224  spy.clear();
7225 
7226  widget.showNormal();
7227  expected =
7229  << qMakePair(&widget, QEvent::Polish)
7230  << qMakePair(&widget, QEvent::ChildPolished)
7231  << qMakePair(&widget, QEvent::PlatformSurface)
7232  << qMakePair(&widget, QEvent::WinIdChange)
7233  << qMakePair(&widget, QEvent::WindowIconChange)
7234  << qMakePair(&widget, QEvent::Move)
7235  << qMakePair(&widget, QEvent::Resize)
7236  << qMakePair(&widget, QEvent::Show)
7237 #ifndef Q_OS_ANDROID
7238  << qMakePair(&widget, QEvent::CursorChange)
7239 #endif
7240  << qMakePair(&widget, QEvent::ShowToParent);
7241 
7242  QVERIFY2(spy.eventList() == expected,
7243  EventRecorder::msgEventListMismatch(expected, spy.eventList()).constData());
7244  spy.clear();
7245 
7247  expected =
7249  << qMakePair(&widget, QEvent::PolishRequest)
7250  << qMakePair(&widget, QEvent::Type(QEvent::User + 1))
7251  << qMakePair(&widget, QEvent::Type(QEvent::User + 2))
7252  << qMakePair(&widget, QEvent::UpdateLater)
7253  << qMakePair(&widget, QEvent::UpdateRequest);
7254 
7255  QVERIFY2(spy.eventList() == expected,
7256  EventRecorder::msgEventListMismatch(expected, spy.eventList()).constData());
7257  }
7258 }
7259 
7260 class RenderWidget : public QWidget
7261 {
7262 public:
7264  : source(source), ellipse(false) {}
7265 
7266  void setEllipseEnabled(bool enable = true)
7267  {
7268  ellipse = enable;
7269  update();
7270  }
7271 
7272 protected:
7273  void paintEvent(QPaintEvent *) override
7274  {
7275  if (ellipse) {
7276  QPainter painter(this);
7277  painter.fillRect(rect(), Qt::red);
7278  painter.end();
7279  QRegion regionToRender = QRegion(0, 0, source->width(), source->height() / 2,
7281  source->render(this, QPoint(0, 30), regionToRender);
7282  } else {
7283  source->render(this);
7284  }
7285  }
7286 
7287 private:
7288  QWidget *source;
7289  bool ellipse;
7290 };
7291 
7292 void tst_QWidget::render()
7293 {
7295  source.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
7296  // disable anti-aliasing to eliminate potential differences when subpixel antialiasing
7297  // is enabled on the screen
7298  QFont f;
7299  f.setStyleStrategy(QFont::NoAntialias);
7300  source.setFont(f);
7301  source.show();
7303 
7304  // Render the entire source into target.
7306  target.resize(source.size());
7307  target.show();
7309 
7310  const QImage sourceImage = source.grab(QRect(QPoint(0, 0), QSize(-1, -1))).toImage();
7311  QImage targetImage = target.grab(QRect(QPoint(0, 0), QSize(-1, -1))).toImage();
7312  QTRY_COMPARE(sourceImage, targetImage);
7313 
7314  // Fill target.rect() will Qt::red and render
7315  // QRegion(0, 0, source->width(), source->height() / 2, QRegion::Ellipse)
7316  // of source into target with offset (0, 30).
7317  target.setEllipseEnabled();
7320 
7321  targetImage = target.grab(QRect(QPoint(0, 0), QSize(-1, -1))).toImage();
7322  QVERIFY(sourceImage != targetImage);
7323 
7324  QCOMPARE(targetImage.pixel(target.width() / 2, 29), QColor(Qt::red).rgb());
7325  if (targetImage.devicePixelRatioF() > 1)
7326  QEXPECT_FAIL("", "This test fails on high-DPI displays", Continue);
7327  QCOMPARE(targetImage.pixel(target.width() / 2, 30), sourceImage.pixel(source.width() / 2, 0));
7328 }
7329 
7330 // Test that a child widget properly fills its background
7331 void tst_QWidget::renderChildFillsBackground()
7332 {
7333  QWidget window;
7334  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
7335  window.resize(100, 100);
7336  // prevent custom styles
7337  window.setStyle(QStyleFactory::create(QLatin1String("Windows")));
7338  window.show();
7340  QWidget child(&window);
7341  child.resize(window.size());
7342  child.show();
7343 
7345  const QPixmap childPixmap = child.grab(QRect(QPoint(0, 0), QSize(-1, -1)));
7346  const QPixmap windowPixmap = window.grab(QRect(QPoint(0, 0), QSize(-1, -1)));
7347 #ifndef Q_OS_ANDROID
7348  // On Android all widgets are shown maximized, so the pixmaps
7349  // will be similar
7350  QEXPECT_FAIL("", "This test fails on all platforms", Continue);
7351 #endif
7352  QCOMPARE(childPixmap, windowPixmap);
7353 }
7354 
7355 void tst_QWidget::renderTargetOffset()
7356 { // Check that the target offset is correct.
7357  QWidget widget;
7359  widget.resize(200, 200);
7362  // prevent custom styles
7364  widget.show();
7367  image.fill(QColor(Qt::blue).rgb());
7368 
7369  // Target offset (0, 0)
7370  widget.render(&image, QPoint(), QRect(20, 20, 100, 100));
7371  QCOMPARE(image.pixel(0, 0), QColor(Qt::red).rgb());
7372  QCOMPARE(image.pixel(99, 99), QColor(Qt::red).rgb());
7373  QCOMPARE(image.pixel(100, 100), QColor(Qt::blue).rgb());
7374 
7375  // Target offset (20, 20).
7376  image.fill(QColor(Qt::blue).rgb());
7377  widget.render(&image, QPoint(20, 20), QRect(20, 20, 100, 100));
7378  QCOMPARE(image.pixel(0, 0), QColor(Qt::blue).rgb());
7379  QCOMPARE(image.pixel(19, 19), QColor(Qt::blue).rgb());
7380  QCOMPARE(image.pixel(20, 20), QColor(Qt::red).rgb());
7381  QCOMPARE(image.pixel(119, 119), QColor(Qt::red).rgb());
7382  QCOMPARE(image.pixel(120, 120), QColor(Qt::blue).rgb());
7383 }
7384 
7385 // On Windows the active palette is used instead of the inactive palette even
7386 // though the widget is invisible. This is probably related to task 178507/168682,
7387 // but for the renderInvisible test it doesn't matter, we're mostly interested
7388 // in testing the geometry so just workaround the palette issue for now.
7389 static void workaroundPaletteIssue(QWidget *widget)
7390 {
7391 #ifndef Q_OS_WIN
7392  return;
7393 #endif
7394  if (!widget)
7395  return;
7396 
7397  QWidget *navigationBar = widget->findChild<QWidget *>(QLatin1String("qt_calendar_navigationbar"));
7398  QVERIFY(navigationBar);
7399 
7400  QPalette palette = navigationBar->palette();
7401  const QColor background = palette.color(QPalette::Inactive, navigationBar->backgroundRole());
7402  const QColor highlightedText = palette.color(QPalette::Inactive, QPalette::HighlightedText);
7403  palette.setColor(QPalette::Active, navigationBar->backgroundRole(), background);
7404  palette.setColor(QPalette::Active, QPalette::HighlightedText, highlightedText);
7405  navigationBar->setPalette(palette);
7406 }
7407 
7408 //#define RENDER_DEBUG
7409 void tst_QWidget::renderInvisible()
7410 {
7411  if (m_platform == QStringLiteral("xcb"))
7412  QSKIP("QTBUG-26424");
7413 
7415  calendar->move(m_availableTopLeft + QPoint(100, 100));
7417  // disable anti-aliasing to eliminate potential differences when subpixel antialiasing
7418  // is enabled on the screen
7419  QFont f;
7420  f.setStyleStrategy(QFont::NoAntialias);
7421  calendar->setFont(f);
7422  calendar->showNormal();
7424 
7425  // Create a dummy focus widget to get rid of focus rect in reference image.
7426  QLineEdit dummyFocusWidget;
7427  dummyFocusWidget.setMinimumWidth(m_testWidgetSize.width());
7428  dummyFocusWidget.move(calendar->geometry().bottomLeft() + QPoint(0, 100));
7429  dummyFocusWidget.show();
7430  QVERIFY(QTest::qWaitForWindowExposed(&dummyFocusWidget));
7431 
7432  // Create normal reference image.
7433  const QSize calendarSize = calendar->size();
7434  QImage referenceImage(calendarSize, QImage::Format_ARGB32);
7435  calendar->render(&referenceImage);
7436 #ifdef RENDER_DEBUG
7437  referenceImage.save("referenceImage.png");
7438 #endif
7439  QVERIFY(!referenceImage.isNull());
7440 
7441  // Create resized reference image.
7442  const QSize calendarSizeResized = calendar->size() + QSize(50, 50);
7443  calendar->resize(calendarSizeResized);
7444  QTest::qWait(30);
7445  QImage referenceImageResized(calendarSizeResized, QImage::Format_ARGB32);
7446  calendar->render(&referenceImageResized);
7447 #ifdef RENDER_DEBUG
7448  referenceImageResized.save("referenceImageResized.png");
7449 #endif
7450  QVERIFY(!referenceImageResized.isNull());
7451 
7452  // Explicitly hide the calendar.
7453  calendar->hide();
7454  QTest::qWait(30);
7455  workaroundPaletteIssue(calendar.data());
7456 
7457  { // Make sure we get the same image when the calendar is explicitly hidden.
7458  QImage testImage(calendarSizeResized, QImage::Format_ARGB32);
7460 #ifdef RENDER_DEBUG
7461  testImage.save("explicitlyHiddenCalendarResized.png");
7462 #endif
7463  QCOMPARE(testImage, referenceImageResized);
7464  }
7465 
7466  // Now that we have reference images we can delete the source and re-create
7467  // the calendar and check that we get the same images from a calendar which has never
7468  // been visible, laid out or created (Qt::WA_WState_Created).
7469  calendar.reset(new QCalendarWidget);
7470  calendar->setFont(f);
7471  workaroundPaletteIssue(calendar.data());
7472 
7473  { // Never been visible, created or laid out.
7474  QImage testImage(calendarSize, QImage::Format_ARGB32);
7476 #ifdef RENDER_DEBUG
7477  testImage.save("neverBeenVisibleCreatedOrLaidOut.png");
7478 #endif
7479  QCOMPARE(testImage, referenceImage);
7480  }
7481 
7482  calendar->hide();
7483  QTest::qWait(30);
7484 
7485  { // Calendar explicitly hidden.
7486  QImage testImage(calendarSize, QImage::Format_ARGB32);
7488 #ifdef RENDER_DEBUG
7489  testImage.save("explicitlyHiddenCalendar.png");
7490 #endif
7491  QCOMPARE(testImage, referenceImage);
7492  }
7493 
7494  // Get navigation bar and explicitly hide it.
7495  QWidget *navigationBar = calendar.data()->findChild<QWidget *>(QLatin1String("qt_calendar_navigationbar"));
7496  QVERIFY(navigationBar);
7497  navigationBar->hide();
7498 
7499  { // Check that the navigation bar isn't drawn when rendering the entire calendar.
7500  QImage testImage(calendarSize, QImage::Format_ARGB32);
7502 #ifdef RENDER_DEBUG
7503  testImage.save("calendarWithoutNavigationBar.png");
7504 #endif
7505  QVERIFY(testImage != referenceImage);
7506  }
7507 
7508  { // Make sure the navigation bar renders correctly even though it's hidden.
7509  QImage testImage(navigationBar->size(), QImage::Format_ARGB32);
7510  navigationBar->render(&testImage);
7511 #ifdef RENDER_DEBUG
7512  testImage.save("explicitlyHiddenNavigationBar.png");
7513 #endif
7514  QCOMPARE(testImage, referenceImage.copy(navigationBar->rect()));
7515  }
7516 
7517  // Get next month button.
7518  QWidget *nextMonthButton = navigationBar->findChild<QWidget *>(QLatin1String("qt_calendar_nextmonth"));
7519  QVERIFY(nextMonthButton);
7520 
7521  { // Render next month button.
7522  // Fill test image with correct background color.
7523  QImage testImage(nextMonthButton->size(), QImage::Format_ARGB32);
7524  navigationBar->render(&testImage, QPoint(), QRegion(), QWidget::RenderFlags());
7525 #ifdef RENDER_DEBUG
7526  testImage.save("nextMonthButtonBackground.png");
7527 #endif
7528 
7529  // Set the button's background color to Qt::transparent; otherwise it will fill the
7530  // background with QPalette::Window.
7531  const QPalette originalPalette = nextMonthButton->palette();
7532  QPalette palette = originalPalette;
7534  nextMonthButton->setPalette(palette);
7535 
7536  // Render the button on top of the background.
7537  nextMonthButton->render(&testImage);
7538 #ifdef RENDER_DEBUG
7539  testImage.save("nextMonthButton.png");
7540 #endif
7541  const QRect buttonRect(nextMonthButton->mapTo(calendar.data(), QPoint()), nextMonthButton->size());
7542  QCOMPARE(testImage, referenceImage.copy(buttonRect));
7543 
7544  // Restore palette.
7545  nextMonthButton->setPalette(originalPalette);
7546  }
7547 
7548  // Navigation bar isn't explicitly hidden anymore.
7549  navigationBar->show();
7550  QTest::qWait(30);
7551  QVERIFY(!calendar->isVisible());
7552 
7553  // Now, completely mess up the layout. This will trigger an update on the layout
7554  // when the calendar is visible or shown, but it's not. QWidget::render must therefore
7555  // make sure the layout is activated before rendering.
7556  QVERIFY(!calendar->isVisible());
7557  calendar->resize(calendarSizeResized);
7559 
7560  { // Make sure we get an image equal to the resized reference image.
7561  QImage testImage(calendarSizeResized, QImage::Format_ARGB32);
7563 #ifdef RENDER_DEBUG
7564  testImage.save("calendarResized.png");
7565 #endif
7566  QCOMPARE(testImage, referenceImageResized);
7567  }
7568 
7569  { // Make sure we lay out the widget correctly the first time it's rendered.
7571  const QSize calendarSize = calendar.sizeHint();
7572 
7573  QImage image(2 * calendarSize, QImage::Format_ARGB32);
7574  image.fill(QColor(Qt::red).rgb());
7575  calendar.render(&image);
7576 
7577  for (int i = calendarSize.height(); i < 2 * calendarSize.height(); ++i)
7578  for (int j = calendarSize.width(); j < 2 * calendarSize.width(); ++j)
7579  QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb());
7580  }
7581 
7582  { // Ensure that we don't call adjustSize() on invisible top-levels if render() is called
7583  // right after widgets have been added/removed to/from its layout.
7584  QWidget topLevel;
7585  topLevel.setLayout(new QVBoxLayout);
7586 
7587  QWidget *widget = new QLineEdit;
7588  topLevel.layout()->addWidget(widget);
7589 
7590  const QSize initialSize = topLevel.size();
7591  QPixmap pixmap(topLevel.sizeHint());
7592  topLevel.render(&pixmap); // triggers adjustSize()
7593  const QSize finalSize = topLevel.size();
7594  QVERIFY2(finalSize != initialSize,
7595  msgComparisonFailed(finalSize, "!=", initialSize));
7596 
7597  topLevel.layout()->removeWidget(widget);
7598  QCOMPARE(topLevel.size(), finalSize);
7599  topLevel.render(&pixmap);
7600  QCOMPARE(topLevel.size(), finalSize);
7601 
7602  topLevel.layout()->addWidget(widget);
7603  QCOMPARE(topLevel.size(), finalSize);
7604  topLevel.render(&pixmap);
7605  QCOMPARE(topLevel.size(), finalSize);
7606  }
7607 }
7608 
7609 void tst_QWidget::renderWithPainter()
7610 {
7611  QWidget widget(nullptr, Qt::Tool);
7612  // prevent custom styles
7613 
7615  widget.setStyle(style.data());
7616  widget.show();
7617  widget.resize(70, 50);
7620 
7621  // Render the entire widget onto the image.
7622  QImage image(QSize(70, 50), QImage::Format_ARGB32);
7623  image.fill(QColor(Qt::red).rgb());
7624  QPainter painter(&image);
7625  widget.render(&painter);
7626 
7627  for (int i = 0; i < image.height(); ++i) {
7628  for (int j = 0; j < image.width(); ++j)
7629  QCOMPARE(image.pixel(j, i), QColor(Qt::black).rgb());
7630  }
7631 
7632  // Translate painter (10, 10).
7633  painter.save();
7634  image.fill(QColor(Qt::red).rgb());
7635  painter.translate(10, 10);
7636  widget.render(&painter);
7637  painter.restore();
7638 
7639  for (int i = 0; i < image.height(); ++i) {
7640  for (int j = 0; j < image.width(); ++j) {
7641  if (i < 10 || j < 10)
7642  QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb());
7643  else
7644  QCOMPARE(image.pixel(j, i), QColor(Qt::black).rgb());
7645  }
7646  }
7647 
7648  // Pass target offset (10, 10) (the same as QPainter::translate).
7649  image.fill(QColor(Qt::red).rgb());
7650  widget.render(&painter, QPoint(10, 10));
7651 
7652  for (int i = 0; i < image.height(); ++i) {
7653  for (int j = 0; j < image.width(); ++j) {
7654  if (i < 10 || j < 10)
7655  QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb());
7656  else
7657  QCOMPARE(image.pixel(j, i), QColor(Qt::black).rgb());
7658  }
7659  }
7660 
7661  // Translate (10, 10) and pass target offset (10, 10).
7662  painter.save();
7663  image.fill(QColor(Qt::red).rgb());
7664  painter.translate(10, 10);
7665  widget.render(&painter, QPoint(10, 10));
7666  painter.restore();
7667 
7668  for (int i = 0; i < image.height(); ++i) {
7669  for (int j = 0; j < image.width(); ++j) {
7670  if (i < 20 || j < 20)
7671  QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb());
7672  else
7673  QCOMPARE(image.pixel(j, i), QColor(Qt::black).rgb());
7674  }
7675  }
7676 
7677  // Rotate painter 90 degrees.
7678  painter.save();
7679  image.fill(QColor(Qt::red).rgb());
7680  painter.rotate(90);
7681  widget.render(&painter);
7682  painter.restore();
7683 
7684  for (int i = 0; i < image.height(); ++i) {
7685  for (int j = 0; j < image.width(); ++j)
7686  QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb());
7687  }
7688 
7689  // Translate and rotate.
7690  image.fill(QColor(Qt::red).rgb());
7691  widget.resize(40, 10);
7692  painter.translate(10, 10);
7693  painter.rotate(90);
7694  widget.render(&painter);
7695 
7696  for (int i = 0; i < image.height(); ++i) {
7697  for (int j = 0; j < image.width(); ++j) {
7698  if (i >= 10 && j >= 0 && j < 10)
7699  QCOMPARE(image.pixel(j, i), QColor(Qt::black).rgb());
7700  else
7701  QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb());
7702  }
7703  }
7704 
7705  // Make sure QWidget::render does not modify the render hints set on the painter.
7708  QPainter::RenderHints oldRenderHints = painter.renderHints();
7709  widget.render(&painter);
7710  QCOMPARE(painter.renderHints(), oldRenderHints);
7711 }
7712 
7713 void tst_QWidget::render_task188133()
7714 {
7716 
7717  // Make sure QWidget::render does not trigger QWidget::repaint/update
7718  // and asserts for Qt::WA_WState_Created.
7719  const QPixmap pixmap = mainWindow.grab(QRect(QPoint(0, 0), QSize(-1, -1)));
7720  Q_UNUSED(pixmap);
7721 }
7722 
7723 void tst_QWidget::render_task211796()
7724 {
7725  class MyWidget : public QWidget
7726  {
7727  void resizeEvent(QResizeEvent *) override
7728  {
7729  QPixmap pixmap(size());
7730  render(&pixmap);
7731  }
7732  };
7733 
7734  { // Please don't die in a resize recursion.
7735  MyWidget widget;
7737  widget.resize(m_testWidgetSize);
7738  centerOnScreen(&widget);
7739  widget.show();
7740  }
7741 
7742  { // Same check with a deeper hierarchy.
7743  QWidget widget;
7745  widget.resize(m_testWidgetSize);
7746  centerOnScreen(&widget);
7747  widget.show();
7748  QWidget child(&widget);
7749  MyWidget grandChild;
7750  grandChild.setParent(&child);
7751  grandChild.resize(100, 100);
7752  child.show();
7753  }
7754 }
7755 
7756 void tst_QWidget::render_task217815()
7757 {
7758  // Make sure we don't change the size of the widget when calling
7759  // render() and the widget has an explicit size set.
7760  // This was a problem on Windows because we called createWinId(),
7761  // which in turn enforced the size to be bigger than the smallest
7762  // possible native window size (which is (115,something) on WinXP).
7763  QWidget widget;
7764  const QSize explicitSize(80, 20);
7765  widget.resize(explicitSize);
7766  QCOMPARE(widget.size(), explicitSize);
7767 
7768  QPixmap pixmap(explicitSize);
7769  widget.render(&pixmap);
7770 
7771  QCOMPARE(widget.size(), explicitSize);
7772 }
7773 
7774 // Window Opacity is not supported on Windows CE.
7775 void tst_QWidget::render_windowOpacity()
7776 {
7777  if (m_platform == QStringLiteral("offscreen"))
7778  QSKIP("Platform offscreen does not support setting opacity");
7779 
7780  const qreal opacity = 0.5;
7781 
7782  { // Check that the painter opacity effects the widget drawing.
7783  QWidget topLevel;
7784  QWidget child(&topLevel);
7785  child.resize(50, 50);
7786  child.setPalette(Qt::red);
7787  child.setAutoFillBackground(true);
7788 
7789  QPixmap expected(child.size());
7790 
7791  if (m_platform == QStringLiteral("xcb") && expected.depth() < 24)
7792  QSKIP("This test won't give correct results with dithered pixmaps");
7793 
7794  expected.fill(Qt::green);
7795  QPainter painter(&expected);
7796  painter.setOpacity(opacity);
7797  painter.fillRect(QRect(QPoint(0, 0), child.size()), Qt::red);
7798  painter.end();
7799 
7800  QPixmap result(child.size());
7801  result.fill(Qt::green);
7802  painter.begin(&result);
7803  painter.setOpacity(opacity);
7804  child.render(&painter);
7805  painter.end();
7806  QCOMPARE(result, expected);
7807  }
7808 
7809  { // Combine the opacity set on the painter with the widget opacity.
7810  class MyWidget : public QWidget
7811  {
7812  public:
7813  explicit MyWidget(qreal opacityIn) : opacity(opacityIn) {}
7814  void paintEvent(QPaintEvent *) override
7815  {
7816  QPainter painter(this);
7817  painter.setOpacity(opacity);
7818  QCOMPARE(painter.opacity(), opacity);
7819  painter.fillRect(rect(), Qt::red);
7820  }
7821  const qreal opacity;
7822  };
7823 
7824  MyWidget widget(opacity);
7825  widget.resize(50, 50);
7828 
7829  QPixmap expected(widget.size());
7830  expected.fill(Qt::green);
7831  QPainter painter(&expected);
7832  painter.setOpacity(opacity);
7833  QPixmap pixmap(widget.size());
7834  pixmap.fill(Qt::blue);
7835  QPainter pixmapPainter(&pixmap);
7836  pixmapPainter.setOpacity(opacity);
7837  pixmapPainter.fillRect(QRect(QPoint(), widget.size()), Qt::red);
7838  painter.drawPixmap(QPoint(), pixmap);
7839  painter.end();
7840 
7841  QPixmap result(widget.size());
7842  result.fill(Qt::green);
7843  painter.begin(&result);
7844  painter.setOpacity(opacity);
7845  widget.render(&painter);
7846  painter.end();
7847  QCOMPARE(result, expected);
7848  }
7849 }
7850 
7851 void tst_QWidget::render_systemClip()
7852 {
7853  QWidget widget;
7855  widget.resize(100, 100);
7856 
7858  image.fill(QColor(Qt::red).rgb());
7859 
7860  QPaintEngine *paintEngine = image.paintEngine();
7861  QVERIFY(paintEngine);
7862  paintEngine->setSystemClip(QRegion(0, 0, 50, 50));
7863 
7864  QPainter painter(&image);
7865  // Make sure we're using the same paint engine and has the right clip set.
7866  QCOMPARE(painter.paintEngine(), paintEngine);
7867  QCOMPARE(paintEngine->systemClip(), QRegion(0, 0, 50, 50));
7868 
7869  // Translate painter outside system clip.
7870  painter.translate(50, 0);
7871  widget.render(&painter);
7872 
7873 #ifdef RENDER_DEBUG
7874  image.save("outside_systemclip.png");
7875 #endif
7876 
7877  // All pixels should be red.
7878  for (int i = 0; i < image.height(); ++i) {
7879  for (int j = 0; j < image.width(); ++j)
7880  QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb());
7881  }
7882 
7883  // Restore painter and refill image with red.
7884  image.fill(QColor(Qt::red).rgb());
7885  painter.translate(-50, 0);
7886 
7887  // Set transform on the painter.
7888  QTransform transform;
7889  transform.shear(0, 1);
7890  painter.setTransform(transform);
7891  widget.render(&painter);
7892 
7893 #ifdef RENDER_DEBUG
7894  image.save("blue_triangle.png");
7895 #endif
7896 
7897  // We should now have a blue triangle starting at scan line 1, and the rest should be red.
7898  // rrrrrrrrrr
7899  // brrrrrrrrr
7900  // bbrrrrrrrr
7901  // bbbrrrrrrr
7902  // bbbbrrrrrr
7903  // rrrrrrrrrr
7904  // ...
7905 
7906 #ifndef Q_OS_MACOS
7907  for (int i = 0; i < image.height(); ++i) {
7908  for (int j = 0; j < image.width(); ++j) {
7909  if (i < 50 && j < i)
7910  QCOMPARE(image.pixel(j, i), QColor(Qt::blue).rgb());
7911  else
7912  QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb());
7913  }
7914  }
7915 #else
7916  // We don't paint directly on the image on the Mac, so we cannot do the pixel comparison
7917  // as above due to QPainter::SmoothPixmapTransform. We therefore need to generate an
7918  // expected image by first painting on a pixmap, and then draw the pixmap onto
7919  // the image using QPainter::SmoothPixmapTransform. Then we can compare pixels :)
7920  // The check is basically the same, except that it takes the smoothening into account.
7921  QPixmap pixmap(50, 50);
7922  const QRegion sysClip(0, 0, 50, 50);
7923  widget.render(&pixmap, QPoint(), sysClip);
7924 
7925  QImage expectedImage(widget.size(), QImage::Format_RGB32);
7926  expectedImage.fill(QColor(Qt::red).rgb());
7927  expectedImage.paintEngine()->setSystemClip(sysClip);
7928 
7929  QPainter expectedImagePainter(&expectedImage);
7930  expectedImagePainter.setTransform(QTransform().shear(0, 1));
7931  // NB! This is the important part (SmoothPixmapTransform).
7932  expectedImagePainter.setRenderHints(QPainter::SmoothPixmapTransform);
7933  expectedImagePainter.drawPixmap(QPoint(0, 0), pixmap);
7934  expectedImagePainter.end();
7935 
7936  QCOMPARE(image, expectedImage);
7937 #endif
7938 }
7939 
7940 void tst_QWidget::render_systemClip2_data()
7941 {
7942  QTest::addColumn<bool>("autoFillBackground");
7943  QTest::addColumn<bool>("usePaintEvent");
7944  QTest::addColumn<QColor>("expectedColor");
7945 
7946  QTest::newRow("Only auto-fill background") << true << false << QColor(Qt::blue);
7947  QTest::newRow("Only draw in paintEvent") << false << true << QColor(Qt::green);
7948  QTest::newRow("Auto-fill background and draw in paintEvent") << true << true << QColor(Qt::green);
7949 }
7950 
7951 void tst_QWidget::render_systemClip2()
7952 {
7953  QFETCH(bool, autoFillBackground);
7954  QFETCH(bool, usePaintEvent);
7955  QFETCH(QColor, expectedColor);
7956 
7957  QVERIFY2(expectedColor != QColor(Qt::red), "Qt::red is the reference color for the image, pick another color");
7958 
7959  class MyWidget : public QWidget
7960  {
7961  public:
7962  explicit MyWidget(bool usePaintEventIn) : usePaintEvent(usePaintEventIn) {}
7963  const bool usePaintEvent;
7964  void paintEvent(QPaintEvent *) override
7965  {
7966  if (usePaintEvent)
7967  QPainter(this).fillRect(rect(), Qt::green);
7968  }
7969  };
7970 
7971  MyWidget widget(usePaintEvent);
7973  // NB! widget.setAutoFillBackground(autoFillBackground) won't do the
7974  // trick here since the widget is a top-level. The background is filled
7975  // regardless, unless Qt::WA_OpaquePaintEvent or Qt::WA_NoSystemBackground
7976  // is set. We therefore use the opaque attribute to turn off auto-fill.
7977  if (!autoFillBackground)
7979  widget.resize(100, 100);
7980 
7982  image.fill(QColor(Qt::red).rgb());
7983 
7984  QPaintEngine *paintEngine = image.paintEngine();
7985  QVERIFY(paintEngine);
7986 
7987  QRegion systemClip(QRegion(50, 0, 50, 10));
7988  systemClip += QRegion(90, 10, 10, 40);
7989  paintEngine->setSystemClip(systemClip);
7990 
7991  // Render entire widget directly onto device.
7992  widget.render(&image);
7993 
7994 #ifdef RENDER_DEBUG
7995  image.save("systemclip_with_device.png");
7996 #endif
7997  // All pixels within the system clip should now be
7998  // the expectedColor, and the rest should be red.
7999  for (int i = 0; i < image.height(); ++i) {
8000  for (int j = 0; j < image.width(); ++j) {
8001  if (systemClip.contains(QPoint(j, i)))
8002  QCOMPARE(image.pixel(j, i), expectedColor.rgb());
8003  else
8004  QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb());
8005  }
8006  }
8007 
8008  // Refill image with red.
8009  image.fill(QColor(Qt::red).rgb());
8010  paintEngine->setSystemClip(systemClip);
8011 
8012  // Do the same with an untransformed painter.
8013  QPainter painter(&image);
8014  //Make sure we're using the same paint engine and has the right clip set.
8015  QCOMPARE(painter.paintEngine(), paintEngine);
8016  QCOMPARE(paintEngine->systemClip(), systemClip);
8017 
8018  widget.render(&painter);
8019 
8020 #ifdef RENDER_DEBUG
8021  image.save("systemclip_with_untransformed_painter.png");
8022 #endif
8023  // All pixels within the system clip should now be
8024  // the expectedColor, and the rest should be red.
8025  for (int i = 0; i < image.height(); ++i) {
8026  for (int j = 0; j < image.width(); ++j) {
8027  if (systemClip.contains(QPoint(j, i)))
8028  QCOMPARE(image.pixel(j, i), expectedColor.rgb());
8029  else
8030  QCOMPARE(image.pixel(j, i), QColor(Qt::red).rgb());
8031  }
8032  }
8033 }
8034 
8035 void tst_QWidget::render_systemClip3_data()
8036 {
8037  QTest::addColumn<QSize>("size");
8038  QTest::addColumn<bool>("useSystemClip");
8039 
8040  // Reference: http://en.wikipedia.org/wiki/Flag_of_Norway
8041  QTest::newRow("Norwegian Civil Flag") << QSize(220, 160) << false;
8042  QTest::newRow("Norwegian War Flag") << QSize(270, 160) << true;
8043 }
8044 
8045 // This test ensures that the current engine clip (systemClip + painter clip)
8046 // is preserved after QPainter::setClipRegion(..., Qt::ReplaceClip);
8047 void tst_QWidget::render_systemClip3()
8048 {
8049  QFETCH(QSize, size);
8050  QFETCH(bool, useSystemClip);
8051 
8052  // Calculate the inner/outer cross of the flag.
8053  QRegion outerCross(0, 0, size.width(), size.height());
8054  outerCross -= QRect(0, 0, 60, 60);
8055  outerCross -= QRect(100, 0, size.width() - 100, 60);
8056  outerCross -= QRect(0, 100, 60, 60);
8057  outerCross -= QRect(100, 100, size.width() - 100, 60);
8058 
8059  QRegion innerCross(0, 0, size.width(), size.height());
8060  innerCross -= QRect(0, 0, 70, 70);
8061  innerCross -= QRect(90, 0, size.width() - 90, 70);
8062  innerCross -= QRect(0, 90, 70, 70);
8063  innerCross -= QRect(90, 90, size.width() - 90, 70);
8064 
8065  const QRegion redArea(QRegion(0, 0, size.width(), size.height()) - outerCross);
8066  const QRegion whiteArea(outerCross - innerCross);
8067  QRegion systemClip;
8068 
8069  // Okay, here's the image that should look like a Norwegian civil/war flag in the end.
8070  QImage flag(size, QImage::Format_ARGB32);
8071  flag.fill(QColor(Qt::transparent).rgba());
8072 
8073  if (useSystemClip) {
8074  QPainterPath warClip(QPoint(size.width(), 0));
8075  warClip.lineTo(size.width() - 110, 60);
8076  warClip.lineTo(size.width(), 80);
8077  warClip.lineTo(size.width() - 110, 100);
8078  warClip.lineTo(size.width(), 160);
8079  warClip.closeSubpath();
8080  systemClip = QRegion(0, 0, size.width(), size.height()) - QRegion(warClip.toFillPolygon().toPolygon());
8081  flag.paintEngine()->setSystemClip(systemClip);
8082  }
8083 
8084  QPainter painter(&flag);
8085  painter.fillRect(QRect(QPoint(), size), Qt::red); // Fill image background with red.
8086  painter.setClipRegion(outerCross); // Limit widget painting to inside the outer cross.
8087 
8088  // Here's the widget that's supposed to draw the inner/outer cross of the flag.
8089  // The outer cross (white) should be drawn when the background is auto-filled, and
8090  // the inner cross (blue) should be drawn in the paintEvent.
8091  class MyWidget : public QWidget
8092  {
8093  public:
8094  void paintEvent(QPaintEvent *) override
8095  {
8096  QPainter painter(this);
8097  // Be evil and try to paint outside the outer cross. This should not be
8098  // possible since the shared painter is clipped to the outer cross.
8099  painter.setClipRect(0, 0, 60, 60, Qt::ReplaceClip);
8100  painter.fillRect(rect(), Qt::green);
8101  painter.setClipRegion(clip, Qt::ReplaceClip);
8102  painter.fillRect(rect(), Qt::blue);
8103  }
8104  QRegion clip;
8105  };
8106 
8107  MyWidget widget;
8108  widget.clip = innerCross;
8112  widget.render(&painter);
8113 
8114 #ifdef RENDER_DEBUG
8115  flag.save("flag.png");
8116 #endif
8117 
8118  // Let's make sure we got a Norwegian flag.
8119  for (int i = 0; i < flag.height(); ++i) {
8120  for (int j = 0; j < flag.width(); ++j) {
8121  const QPoint pixel(j, i);
8122  const QRgb pixelValue = flag.pixel(pixel);
8123  if (useSystemClip && !systemClip.contains(pixel))
8124  QCOMPARE(pixelValue, QColor(Qt::transparent).rgba());
8125  else if (redArea.contains(pixel))
8126  QCOMPARE(pixelValue, QColor(Qt::red).rgba());
8127  else if (whiteArea.contains(pixel))
8128  QCOMPARE(pixelValue, QColor(Qt::white).rgba());
8129  else
8130  QCOMPARE(pixelValue, QColor(Qt::blue).rgba());
8131  }
8132  }
8133 }
8134 
8135 void tst_QWidget::render_task252837()
8136 {
8137  QWidget widget;
8138  widget.resize(200, 200);
8139 
8140  QPixmap pixmap(widget.size());
8141  QPainter painter(&pixmap);
8142  // Please do not crash.
8143  widget.render(&painter);
8144 }
8145 
8146 void tst_QWidget::render_worldTransform()
8147 {
8148  class MyWidget : public QWidget
8149  {
8150  public:
8151  void paintEvent(QPaintEvent *) override
8152  {
8153  QPainter painter(this);
8154  // Make sure world transform is identity.
8155  QCOMPARE(painter.worldTransform(), QTransform());
8156 
8157  // Make sure device transform is correct.
8158  const QPoint widgetOffset = geometry().topLeft();
8159  QTransform expectedDeviceTransform = QTransform::fromTranslate(105, 5);
8160  expectedDeviceTransform.rotate(90);
8161  expectedDeviceTransform.translate(widgetOffset.x(), widgetOffset.y());
8162  QCOMPARE(painter.deviceTransform(), expectedDeviceTransform);
8163 
8164  // Set new world transform.
8165  QTransform newWorldTransform = QTransform::fromTranslate(10, 10);
8166  newWorldTransform.rotate(90);
8167  painter.setWorldTransform(newWorldTransform);
8168  QCOMPARE(painter.worldTransform(), newWorldTransform);
8169 
8170  // Again, check device transform.
8171  expectedDeviceTransform.translate(10, 10);
8172  expectedDeviceTransform.rotate(90);
8173  QCOMPARE(painter.deviceTransform(), expectedDeviceTransform);
8174 
8175  painter.fillRect(QRect(0, 0, 20, 10), Qt::green);
8176  }
8177  };
8178 
8179  MyWidget widget;
8180  widget.setFixedSize(100, 100);
8183 
8184  MyWidget child;
8185  child.setParent(&widget);
8186  child.move(50, 50);
8187  child.setFixedSize(50, 50);
8188  child.setPalette(Qt::blue);
8189  child.setAutoFillBackground(true);
8190 
8191  QImage image(QSize(110, 110), QImage::Format_RGB32);
8192  image.fill(QColor(Qt::black).rgb());
8193 
8194  QPainter painter(&image);
8195  painter.translate(105, 5);
8196  painter.rotate(90);
8197 
8198  // Render widgets onto image.
8199  widget.render(&painter);
8200 #ifdef RENDER_DEBUG
8201  image.save("render_worldTransform_image.png");
8202 #endif
8203 
8204  // Ensure the transforms are unchanged after render.
8205  QCOMPARE(painter.worldTransform(), painter.worldTransform());
8206  QCOMPARE(painter.deviceTransform(), painter.deviceTransform());
8207  painter.end();
8208 
8209  // Paint expected image.
8210  QImage expected(QSize(110, 110), QImage::Format_RGB32);
8211  expected.fill(QColor(Qt::black).rgb());
8212 
8213  QPainter expectedPainter(&expected);
8214  expectedPainter.translate(105, 5);
8215  expectedPainter.rotate(90);
8216  expectedPainter.save();
8217  expectedPainter.fillRect(widget.rect(),Qt::red);
8218  expectedPainter.translate(10, 10);
8219  expectedPainter.rotate(90);
8220  expectedPainter.fillRect(QRect(0, 0, 20, 10), Qt::green);
8221  expectedPainter.restore();
8222  expectedPainter.translate(50, 50);
8223  expectedPainter.fillRect(child.rect(),Qt::blue);
8224  expectedPainter.translate(10, 10);
8225  expectedPainter.rotate(90);
8226  expectedPainter.fillRect(QRect(0, 0, 20, 10), Qt::green);
8227  expectedPainter.end();
8228 
8229 #ifdef RENDER_DEBUG
8230  expected.save("render_worldTransform_expected.png");
8231 #endif
8232 
8233  QCOMPARE(image, expected);
8234 }
8235 
8236 void tst_QWidget::setContentsMargins()
8237 {
8238  QLabel label("why does it always rain on me?");
8239  QSize oldSize = label.sizeHint();
8240  label.setFrameStyle(QFrame::Sunken | QFrame::Box);
8241  QSize newSize = label.sizeHint();
8242  QVERIFY2(oldSize != newSize, msgComparisonFailed(oldSize, "!=", newSize));
8243 
8244  QLabel label2("why does it always rain on me?");
8245  label2.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
8246  label2.show();
8247  label2.setFrameStyle(QFrame::Sunken | QFrame::Box);
8248  QCOMPARE(newSize, label2.sizeHint());
8249 
8250  QLabel label3("why does it always rain on me?");
8251  label3.setFrameStyle(QFrame::Sunken | QFrame::Box);
8252  QCOMPARE(newSize, label3.sizeHint());
8253 }
8254 
8255 void tst_QWidget::moveWindowInShowEvent_data()
8256 {
8257  QTest::addColumn<QPoint>("initial");
8258  QTest::addColumn<QPoint>("position");
8259 
8260  QPoint p = m_availableTopLeft;
8261 
8262  QTest::newRow("1") << p << (p + QPoint(10, 10));
8263  QTest::newRow("2") << (p + QPoint(10,10)) << p;
8264 }
8265 
8266 void tst_QWidget::moveWindowInShowEvent()
8267 {
8268  if (m_platform == QStringLiteral("xcb"))
8269  QSKIP("QTBUG-26424");
8270 
8271  QFETCH(QPoint, initial);
8272  QFETCH(QPoint, position);
8273 
8274  class MoveWindowInShowEventWidget : public QWidget
8275  {
8276  public:
8277  QPoint position;
8278  void showEvent(QShowEvent *) override
8279  {
8280  move(position);
8281  }
8282  };
8283 
8284  MoveWindowInShowEventWidget widget;
8286  widget.resize(QSize(screen->availableGeometry().size() / 3).expandedTo(QSize(1, 1)));
8287  // move to this position in showEvent()
8288  widget.position = position;
8289 
8290  // put the widget in it's starting position
8291  widget.move(initial);
8292  QCOMPARE(widget.pos(), initial);
8293 
8294  // show it
8295  widget.showNormal();
8297  // it should have moved
8299 }
8300 
8301 void tst_QWidget::repaintWhenChildDeleted()
8302 {
8304  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
8305  const QPoint startPoint = m_availableTopLeft + QPoint(50, 50);
8306  w.setGeometry(QRect(startPoint, QSize(100, 100)));
8307  w.show();
8309  QTRY_COMPARE(w.r, QRegion(w.rect()));
8310  w.r = QRegion();
8311 
8312  {
8314  child.setGeometry(10, 10, 10, 10);
8315  child.show();
8316  QTRY_COMPARE(child.r, QRegion(child.rect()));
8317  w.r = QRegion();
8318  }
8319 
8320  QTRY_COMPARE(w.r, QRegion(10, 10, 10, 10));
8321 }
8322 
8323 // task 175114
8324 void tst_QWidget::hideOpaqueChildWhileHidden()
8325 {
8327  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
8328  const QPoint startPoint = m_availableTopLeft + QPoint(50, 50);
8329  w.setGeometry(QRect(startPoint, QSize(100, 100)));
8330 
8332  child.setGeometry(10, 10, 80, 80);
8333 
8335  child2.setGeometry(10, 10, 60, 60);
8336 
8337  w.show();
8339 
8341  // On some platforms (macOS), the palette will be different depending on if a
8342  // window is active or not. And because of that, the whole window will be
8343  // repainted when going from Inactive to Active. So wait for the window to be
8344  // active before we continue, so the activation doesn't happen at a random
8345  // time below. And call processEvents to have the paint events delivered right away.
8347  qApp->processEvents();
8348  }
8349 
8350  QTRY_COMPARE(child2.r, QRegion(child2.rect()));
8351  child.r = QRegion();
8352  child2.r = QRegion();
8353  w.r = QRegion();
8354 
8355  child.hide();
8356  child2.hide();
8357 
8359 
8360  child.show();
8361  QTRY_COMPARE(child.r, QRegion(child.rect()));
8362  QCOMPARE(child2.r, QRegion());
8363 }
8364 
8365 // This test doesn't make sense without support for showMinimized().
8366 void tst_QWidget::updateWhileMinimized()
8367 {
8368  if (m_platform == QStringLiteral("wayland"))
8369  QSKIP("Wayland: This fails. Figure out why.");
8370  if (m_platform == QStringLiteral("offscreen"))
8371  QSKIP("Platform offscreen does not support showMinimized()");
8372 
8373 #if defined(Q_OS_QNX)
8374  QSKIP("Platform does not support showMinimized()");
8375 #endif
8378  // Filter out activation change and focus events to avoid update() calls in QWidget.
8379  widget.updateOnActivationChangeAndFocusIn = false;
8380  widget.reset();
8381  widget.show();
8383  QTRY_VERIFY(widget.numPaintEvents > 0);
8384  QTest::qWait(150);
8385 
8386  // Minimize window.
8388  QTest::qWait(110);
8389 
8390  widget.reset();
8391 
8392  // The widget is not visible on the screen (but isVisible() still returns true).
8393  // Make sure update requests are discarded until the widget is shown again.
8394  widget.update(0, 0, 50, 50);
8395  QTest::qWait(10);
8396  int count = 0;
8397  // mutter/GNOME Shell doesn't unmap when minimizing window.
8398  // More details at https://gitlab.gnome.org/GNOME/mutter/issues/185
8399  if (m_platform == QStringLiteral("xcb")) {
8400  const QString desktop = qgetenv("XDG_CURRENT_DESKTOP");
8401  qDebug() << "xcb: XDG_CURRENT_DESKTOP=" << desktop;
8402  if (desktop == QStringLiteral("ubuntu:GNOME")
8403  || desktop == QStringLiteral("GNOME-Classic:GNOME")
8404  || desktop == QStringLiteral("GNOME")
8405  || desktop.isEmpty()) // on local VMs
8406  count = 1;
8407  }
8408  QCOMPARE(widget.numPaintEvents, count);
8409 
8410  // Restore window.
8411  widget.showNormal();
8412  QTRY_COMPARE(widget.numPaintEvents, 1);
8413  QCOMPARE(widget.paintedRegion, QRegion(0, 0, 50, 50));
8414 }
8415 
8417 {
8418 public:
8419  using QWidget::QWidget;
8420 #if defined(Q_OS_WIN)
8421  // This is the only way to enable PaintOnScreen on Windows.
8422  QPaintEngine *paintEngine() const override { return nullptr; }
8423 #endif
8424 };
8425 
8426 void tst_QWidget::alienWidgets()
8427 {
8428  if (m_platform != QStringLiteral("xcb") && m_platform != QStringLiteral("windows"))
8429  QSKIP("This test is only for X11/Windows.");
8430 
8432  QWidget parent;
8433  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
8434  parent.resize(m_testWidgetSize);
8435  QWidget child(&parent);
8436  QWidget grandChild(&child);
8437  QWidget greatGrandChild(&grandChild);
8438  parent.show();
8439 
8441 
8442  // Verify that the WA_WState_Created attribute is set
8443  // and the top-level is the only native window.
8444  QVERIFY(parent.testAttribute(Qt::WA_WState_Created));
8445  QVERIFY(parent.internalWinId());
8446 
8447  QVERIFY(child.testAttribute(Qt::WA_WState_Created));
8448  QVERIFY(!child.internalWinId());
8449 
8451  QVERIFY(!grandChild.internalWinId());
8452 
8453  QVERIFY(greatGrandChild.testAttribute(Qt::WA_WState_Created));
8454  QVERIFY(!greatGrandChild.internalWinId());
8455 
8456  // Enforce native windows all the way up in the parent hierarchy
8457  // if not WA_DontCreateNativeAncestors is set.
8459  greatGrandChild.setAttribute(Qt::WA_NativeWindow);
8460  QVERIFY(greatGrandChild.internalWinId());
8461  QVERIFY(grandChild.internalWinId());
8462  QVERIFY(!child.internalWinId());
8463 
8464  {
8465  // Ensure that hide() on an ancestor of a widget with
8466  // Qt::WA_DontCreateNativeAncestors still gets unmapped
8467  QWidget window;
8468  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
8469  window.resize(m_testWidgetSize);
8470  QWidget widget(&window);
8471  QWidget child(&widget);
8472  child.setAttribute(Qt::WA_NativeWindow);
8474  window.show();
8476  QTRY_VERIFY(child.testAttribute(Qt::WA_Mapped));
8477  widget.hide();
8478  QTRY_VERIFY(!child.testAttribute(Qt::WA_Mapped));
8479  }
8480 
8481  // Enforce a native window when calling QWidget::winId.
8482  QVERIFY(child.winId());
8483  QVERIFY(child.internalWinId());
8484 
8485  // Check that paint on screen widgets (incl. children) are native.
8486  PaintOnScreenWidget paintOnScreen(&parent);
8487  QWidget paintOnScreenChild(&paintOnScreen);
8488  paintOnScreen.show();
8489  QVERIFY(paintOnScreen.testAttribute(Qt::WA_WState_Created));
8490  QVERIFY(!paintOnScreen.testAttribute(Qt::WA_NativeWindow));
8491  QVERIFY(!paintOnScreen.internalWinId());
8492  QVERIFY(!paintOnScreenChild.testAttribute(Qt::WA_NativeWindow));
8493  QVERIFY(!paintOnScreenChild.internalWinId());
8494 
8495  paintOnScreen.setAttribute(Qt::WA_PaintOnScreen);
8496  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8497  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8498  QVERIFY(paintOnScreen.testAttribute(Qt::WA_NativeWindow));
8499  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8500  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8501  QVERIFY(paintOnScreen.internalWinId());
8502  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8503  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8504  QVERIFY(paintOnScreenChild.testAttribute(Qt::WA_NativeWindow));
8505  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8506  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8507  QVERIFY(paintOnScreenChild.internalWinId());
8508 
8509  // Check that widgets with the Qt::MSWindowsOwnDC attribute set
8510  // are native.
8511  QWidget msWindowsOwnDC(&parent, Qt::MSWindowsOwnDC);
8512  msWindowsOwnDC.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
8513  msWindowsOwnDC.show();
8514  QVERIFY(msWindowsOwnDC.testAttribute(Qt::WA_WState_Created));
8515  QVERIFY(msWindowsOwnDC.testAttribute(Qt::WA_NativeWindow));
8516  QVERIFY(msWindowsOwnDC.internalWinId());
8517 
8518  { // Enforce a native window when calling QWidget::handle() (on X11) or QWidget::getDC() (on Windows).
8519  QWidget widget(&parent);
8520  widget.show();
8523 
8524  widget.winId();
8526  }
8527 
8528  if (m_platform == QStringLiteral("xcb")) {
8529  // Make sure we don't create native windows when setting Qt::WA_X11NetWmWindowType attributes
8530  // on alien widgets (see task 194231).
8531  QWidget dummy;
8532  dummy.resize(m_testWidgetSize);
8533  QVERIFY(dummy.winId());
8534  QWidget widget(&dummy);
8537  }
8538 
8539  { // Make sure we create native ancestors when setting Qt::WA_PaintOnScreen before show().
8540  QWidget topLevel;
8541  topLevel.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
8542  topLevel.resize(m_testWidgetSize);
8543  QWidget child(&topLevel);
8544  QWidget grandChild(&child);
8545  PaintOnScreenWidget greatGrandChild(&grandChild);
8546 
8547  greatGrandChild.setAttribute(Qt::WA_PaintOnScreen);
8548  QVERIFY(!child.internalWinId());
8549  QVERIFY(!grandChild.internalWinId());
8550  QVERIFY(!greatGrandChild.internalWinId());
8551 
8552  topLevel.show();
8553  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8554  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8555  QVERIFY(child.internalWinId());
8556  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8557  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8558  QVERIFY(grandChild.internalWinId());
8559  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8560  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8561  QVERIFY(greatGrandChild.internalWinId());
8562  }
8563 
8564  { // Ensure that widgets reparented into Qt::WA_PaintOnScreen widgets become native.
8565  QWidget topLevel;
8566  topLevel.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
8567  topLevel.resize(m_testWidgetSize);
8568  QWidget *widget = new PaintOnScreenWidget(&topLevel);
8570  QWidget *child = new QWidget;
8571  QWidget *dummy = new QWidget(child);
8572  QWidget *grandChild = new QWidget(child);
8573  QWidget *dummy2 = new QWidget(grandChild);
8574 
8575  child->setParent(widget);
8576 
8577  QVERIFY(!topLevel.internalWinId());
8578  QVERIFY(!child->internalWinId());
8579  QVERIFY(!dummy->internalWinId());
8580  QVERIFY(!grandChild->internalWinId());
8581  QVERIFY(!dummy2->internalWinId());
8582 
8583  topLevel.show();
8584  QVERIFY(topLevel.internalWinId());
8586  QVERIFY(child->internalWinId());
8587  QVERIFY(child->testAttribute(Qt::WA_NativeWindow));
8588  QVERIFY(!child->testAttribute(Qt::WA_PaintOnScreen));
8589  QVERIFY(!dummy->internalWinId());
8590  QVERIFY(!dummy->testAttribute(Qt::WA_NativeWindow));
8591  QVERIFY(!grandChild->internalWinId());
8592  QVERIFY(!grandChild->testAttribute(Qt::WA_NativeWindow));
8593  QVERIFY(!dummy2->internalWinId());
8594  QVERIFY(!dummy2->testAttribute(Qt::WA_NativeWindow));
8595  }
8596 
8597  { // Ensure that ancestors of a Qt::WA_PaintOnScreen widget stay native
8598  // if they are re-created (typically in QWidgetPrivate::setParent_sys) (task 210822).
8599  QWidget window;
8600  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
8601  window.resize(m_testWidgetSize);
8602  QWidget child(&window);
8603 
8604  QWidget grandChild;
8605  grandChild.setWindowTitle("This causes the widget to be created");
8606 
8607  PaintOnScreenWidget paintOnScreenWidget;
8608  paintOnScreenWidget.setAttribute(Qt::WA_PaintOnScreen);
8609  paintOnScreenWidget.setParent(&grandChild);
8610 
8611  grandChild.setParent(&child);
8612 
8613  window.show();
8614 
8615  QVERIFY(window.internalWinId());
8616  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8617  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8618  QVERIFY(child.internalWinId());
8619  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8620  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8621  QVERIFY(child.testAttribute(Qt::WA_NativeWindow));
8622  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8623  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8624  QVERIFY(grandChild.internalWinId());
8625  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8626  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8627  QVERIFY(grandChild.testAttribute(Qt::WA_NativeWindow));
8628  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8629  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8630  QVERIFY(paintOnScreenWidget.internalWinId());
8631  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
8632  QEXPECT_FAIL("", "QTBUG-26424", Continue);
8633  QVERIFY(paintOnScreenWidget.testAttribute(Qt::WA_NativeWindow));
8634  }
8635 
8636  { // Ensure that all siblings are native unless Qt::AA_DontCreateNativeWidgetSiblings is set.
8637  qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, false);
8640  QWidget *toolBar = new QWidget(&mainWindow);
8642  QWidget *centralWidget = new QWidget(&mainWindow);
8643  centralWidget->setMinimumSize(m_testWidgetSize);
8644 
8645  QWidget *button = new QWidget(centralWidget);
8646  QWidget *mdiArea = new QWidget(centralWidget);
8647 
8648  QWidget *horizontalScroll = new QWidget(mdiArea);
8649  QWidget *verticalScroll = new QWidget(mdiArea);
8650  QWidget *viewport = new QWidget(mdiArea);
8651 
8652  viewport->setAttribute(Qt::WA_NativeWindow);
8653  mainWindow.show();
8654 
8655  // Ensure that the viewport and its siblings are native:
8656  QVERIFY(verticalScroll->testAttribute(Qt::WA_NativeWindow));
8657  QVERIFY(verticalScroll->testAttribute(Qt::WA_NativeWindow));
8658  QVERIFY(horizontalScroll->testAttribute(Qt::WA_NativeWindow));
8659 
8660  // Ensure that the mdi area and its siblings are native:
8661  QVERIFY(mdiArea->testAttribute(Qt::WA_NativeWindow));
8662  QVERIFY(button->testAttribute(Qt::WA_NativeWindow));
8663 
8664  // Ensure that the central widget and its siblings are native:
8665  QVERIFY(centralWidget->testAttribute(Qt::WA_NativeWindow));
8667  QVERIFY(toolBar->testAttribute(Qt::WA_NativeWindow));
8668  }
8669 }
8670 
8672 
8673 void tst_QWidget::nativeWindowPosition_data()
8674 {
8675  QTest::addColumn<WidgetAttributes>("attributes");
8676 
8677  QTest::newRow("non-native all the way")
8678  << WidgetAttributes{};
8679  QTest::newRow("native all the way")
8681  QTest::newRow("native with non-native ancestor")
8683 }
8684 
8685 void tst_QWidget::nativeWindowPosition()
8686 {
8687  QWidget topLevel;
8688  QWidget child(&topLevel);
8689  child.move(5, 5);
8690 
8691  QWidget grandChild(&child);
8692  grandChild.move(10, 10);
8693 
8694  QFETCH(WidgetAttributes, attributes);
8695  for (auto attribute : attributes)
8696  grandChild.setAttribute(attribute);
8697 
8698  topLevel.show();
8700 
8701  QCOMPARE(child.pos(), QPoint(5, 5));
8702  QCOMPARE(grandChild.pos(), QPoint(10, 10));
8703 }
8704 
8705 class ASWidget : public QWidget
8706 {
8707 public:
8708  ASWidget(QSize sizeHint, QSizePolicy sizePolicy, bool layout, bool hfwLayout, QWidget *parent = nullptr)
8709  : QWidget(parent), mySizeHint(sizeHint)
8710  {
8711  setObjectName(QStringLiteral("ASWidget"));
8712  setWindowTitle(objectName());
8714  if (layout) {
8715  QSizePolicy sp = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
8716  sp.setHeightForWidth(hfwLayout);
8717 
8718  QVBoxLayout *vbox = new QVBoxLayout;
8719  vbox->setContentsMargins(0, 0, 0, 0);
8720  vbox->addWidget(new ASWidget(sizeHint + QSize(30, 20), sp, false, false));
8721  setLayout(vbox);
8722  }
8723  }
8724 
8725  QSize sizeHint() const override
8726  {
8727  if (layout())
8728  return layout()->totalSizeHint();
8729  return mySizeHint;
8730  }
8731  int heightForWidth(int width) const override
8732  {
8733  return sizePolicy().hasHeightForWidth() ? width * 2 : -1;
8734  }
8735 
8736  QSize mySizeHint;
8737 };
8738 
8739 void tst_QWidget::adjustSize_data()
8740 {
8741  const int MagicW = 200;
8742  const int MagicH = 100;
8743 
8744  QTest::addColumn<QSize>("sizeHint");
8745  QTest::addColumn<int>("hPolicy");
8746  QTest::addColumn<int>("vPolicy");
8747  QTest::addColumn<bool>("hfwSP");
8748  QTest::addColumn<bool>("layout");
8749  QTest::addColumn<bool>("hfwLayout");
8750  QTest::addColumn<bool>("haveParent");
8751  QTest::addColumn<QSize>("expectedSize");
8752 
8753  QTest::newRow("1") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8754  << false << false << false << false << QSize(5, qMax(6, MagicH));
8755  QTest::newRow("2") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8756  << true << false << false << false << QSize(5, qMax(10, MagicH));
8757  QTest::newRow("3") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8758  << false << true << false << false << QSize(35, 26);
8759  QTest::newRow("4") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8760  << false << true << true << false << QSize(35, 70);
8761  QTest::newRow("5") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8762  << false << false << false << false << QSize(100000, 100000);
8763  QTest::newRow("6") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8764  << true << false << false << false << QSize(100000, 100000);
8765  QTest::newRow("7") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8766  << false << true << false << false << QSize(100000, 100000);
8767  QTest::newRow("8") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8768  << false << true << true << false << QSize(100000, 100000);
8769  QTest::newRow("9") << QSize(5, 6) << int(QSizePolicy::Expanding) << int(QSizePolicy::Minimum)
8770  << true << false << false << false << QSize(qMax(5, MagicW), 10);
8771 
8772  QTest::newRow("1c") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8773  << false << false << false << true << QSize(5, 6);
8774  QTest::newRow("2c") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8775  << true << false << false << true << QSize(5, 6 /* or 10 would be OK too, since hfw contradicts sizeHint() */);
8776  QTest::newRow("3c") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8777  << false << true << false << true << QSize(35, 26);
8778  QTest::newRow("4c") << QSize(5, 6) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8779  << false << true << true << true << QSize(35, 70);
8780  QTest::newRow("5c") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8781  << false << false << false << true << QSize(40001, 30001);
8782  QTest::newRow("6c") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8783  << true << false << false << true << QSize(40001, 30001 /* or 80002 would be OK too, since hfw contradicts sizeHint() */);
8784  QTest::newRow("7c") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8785  << false << true << false << true << QSize(40001 + 30, 30001 + 20);
8786  QTest::newRow("8c") << QSize(40001, 30001) << int(QSizePolicy::Minimum) << int(QSizePolicy::Expanding)
8787  << false << true << true << true << QSize(40001 + 30, 80002 + 60);
8788  QTest::newRow("9c") << QSize(5, 6) << int(QSizePolicy::Expanding) << int(QSizePolicy::Minimum)
8789  << true << false << false << true << QSize(5, 6);
8790 }
8791 
8792 void tst_QWidget::adjustSize()
8793 {
8794  QFETCH(QSize, sizeHint);
8795  QFETCH(int, hPolicy);
8796  QFETCH(int, vPolicy);
8797  QFETCH(bool, hfwSP);
8798  QFETCH(bool, layout);
8799  QFETCH(bool, hfwLayout);
8800  QFETCH(bool, haveParent);
8801  QFETCH(QSize, expectedSize);
8802 
8804 
8805  QSizePolicy sp = QSizePolicy(QSizePolicy::Policy(hPolicy), QSizePolicy::Policy(vPolicy));
8806  sp.setHeightForWidth(hfwSP);
8807 
8808  QWidget *child = new ASWidget(sizeHint, sp, layout, hfwLayout, haveParent ? parent.data() : nullptr);
8809  child->resize(123, 456);
8810  child->adjustSize();
8811  if (expectedSize == QSize(100000, 100000)) {
8812  QVERIFY2(child->size().width() < sizeHint.width(),
8813  msgComparisonFailed(child->size().width(), "<", sizeHint.width()));
8814  QVERIFY2(child->size().height() < sizeHint.height(),
8815  msgComparisonFailed(child->size().height(), "<", sizeHint.height()));
8816  } else {
8817  QCOMPARE(child->size(), expectedSize);
8818  }
8819  if (!haveParent)
8820  delete child;
8821 }
8822 
8823 class TestLayout : public QVBoxLayout
8824 {
8825  Q_OBJECT
8826 public:
8828 
8829  void invalidate() override
8830  {
8831  invalidated = true;
8832  }
8833 
8834  bool invalidated = false;
8835 };
8836 
8837 void tst_QWidget::updateGeometry_data()
8838 {
8839  QTest::addColumn<QSize>("minSize");
8840  QTest::addColumn<bool>("shouldInvalidate");
8841  QTest::addColumn<QSize>("maxSize");
8842  QTest::addColumn<bool>("shouldInvalidate2");
8843  QTest::addColumn<QSizePolicy::Policy>("verticalSizePolicy");
8844  QTest::addColumn<bool>("shouldInvalidate3");
8845  QTest::addColumn<bool>("setVisible");
8846  QTest::addColumn<bool>("shouldInvalidate4");
8847 
8848  QTest::newRow("setMinimumSize")
8849  << QSize(100, 100) << true
8850  << QSize() << false
8851  << QSizePolicy::Preferred << false
8852  << true << false;
8853  QTest::newRow("setMaximumSize")
8854  << QSize() << false
8855  << QSize(100, 100) << true
8856  << QSizePolicy::Preferred << false
8857  << true << false;
8858  QTest::newRow("setMinimumSize, then maximumSize to a different size")
8859  << QSize(100, 100) << true
8860  << QSize(300, 300) << true
8861  << QSizePolicy::Preferred << false
8862  << true << false;
8863  QTest::newRow("setMinimumSize, then maximumSize to the same size")
8864  << QSize(100, 100) << true
8865  << QSize(100, 100) << true
8866  << QSizePolicy::Preferred << false
8867  << true << false;
8868  QTest::newRow("setMinimumSize, then maximumSize to the same size and then hide it")
8869  << QSize(100, 100) << true
8870  << QSize(100, 100) << true
8871  << QSizePolicy::Preferred << false
8872  << false << true;
8873  QTest::newRow("Change sizePolicy")
8874  << QSize() << false
8875  << QSize() << false
8876  << QSizePolicy::Minimum << true
8877  << true << false;
8878 
8879 }
8880 
8881 void tst_QWidget::updateGeometry()
8882 {
8883  QFETCH(QSize, minSize);
8884  QFETCH(bool, shouldInvalidate);
8885  QFETCH(QSize, maxSize);
8886  QFETCH(bool, shouldInvalidate2);
8887  QFETCH(QSizePolicy::Policy, verticalSizePolicy);
8888  QFETCH(bool, shouldInvalidate3);
8889  QFETCH(bool, setVisible);
8890  QFETCH(bool, shouldInvalidate4);
8891  QWidget parent;
8894  parent.resize(200, 200);
8895  TestLayout *lout = new TestLayout();
8896  parent.setLayout(lout);
8897  QWidget *child = new QWidget(&parent);
8898  lout->addWidget(child);
8899  parent.show();
8901 
8902  lout->invalidated = false;
8903  if (minSize.isValid())
8904  child->setMinimumSize(minSize);
8905  QCOMPARE(lout->invalidated, shouldInvalidate);
8906 
8907  lout->invalidated = false;
8908  if (maxSize.isValid())
8909  child->setMaximumSize(maxSize);
8910  QCOMPARE(lout->invalidated, shouldInvalidate2);
8911 
8912  lout->invalidated = false;
8913  child->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, verticalSizePolicy));
8914  if (shouldInvalidate3)
8915  QCOMPARE(lout->invalidated, true);
8916 
8917  lout->invalidated = false;
8918  if (!setVisible)
8919  child->setVisible(false);
8920  QCOMPARE(lout->invalidated, shouldInvalidate4);
8921 }
8922 
8923 void tst_QWidget::sendUpdateRequestImmediately()
8924 {
8925  UpdateWidget updateWidget;
8927  updateWidget.show();
8928 
8929  QVERIFY(QTest::qWaitForWindowExposed(&updateWidget));
8930 
8932  updateWidget.reset();
8933 
8934  QCOMPARE(updateWidget.numUpdateRequestEvents, 0);
8935  updateWidget.repaint();
8936  QCOMPARE(updateWidget.numUpdateRequestEvents, 1);
8937 }
8938 
8939 void tst_QWidget::doubleRepaint()
8940 {
8941 #ifdef Q_OS_MACOS
8942  QSKIP("QTBUG-52974");
8943 #endif
8944 
8945 #if defined(Q_OS_MACOS)
8946  if (!macHasAccessToWindowsServer())
8947  QSKIP("Not having window server access causes the wrong number of repaints to be issues");
8948 #endif
8951  centerOnScreen(&widget);
8953  // Filter out activation change and focus events to avoid update() calls in QWidget.
8954  widget.updateOnActivationChangeAndFocusIn = false;
8955 
8956  // Show: 1 repaint
8957  int expectedRepaints = 1;
8958  widget.show();
8960  QTRY_COMPARE(widget.numPaintEvents, expectedRepaints);
8961  widget.numPaintEvents = 0;
8962 
8963  // Minmize: Should not trigger a repaint.
8965  QTest::qWait(10);
8966  QCOMPARE(widget.numPaintEvents, 0);
8967  widget.numPaintEvents = 0;
8968 
8969  // Restore: Should not trigger a repaint.
8970  widget.showNormal();
8972  QTest::qWait(10);
8973  QCOMPARE(widget.numPaintEvents, 0);
8974 }
8975 
8976 void tst_QWidget::resizeInPaintEvent()
8977 {
8978  QWidget window;
8979  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
8981  window.resize(200, 200);
8982  window.show();
8985  QTRY_VERIFY(widget.numPaintEvents > 0);
8986 
8987  widget.reset();
8988  QCOMPARE(widget.numPaintEvents, 0);
8989 
8990  widget.resizeInPaintEvent = true;
8991  // This will call resize in the paintEvent, which in turn will call
8992  // invalidateBackingStore() and a new update request should be posted.
8993  // the resize triggers another update.
8994  widget.update();
8995  QTRY_COMPARE(widget.numPaintEvents, 2);
8996 }
8997 
8998 void tst_QWidget::opaqueChildren()
8999 {
9000  QWidget widget;
9002  widget.resize(200, 200);
9003 
9004  QWidget child(&widget);
9005  child.setGeometry(-700, -700, 200, 200);
9006 
9007  QWidget grandChild(&child);
9008  grandChild.resize(200, 200);
9009 
9010  QWidget greatGrandChild(&grandChild);
9011  greatGrandChild.setGeometry(50, 50, 200, 200);
9012  greatGrandChild.setPalette(Qt::red);
9013  greatGrandChild.setAutoFillBackground(true); // Opaque child widget.
9014 
9015  widget.show();
9017 
9018  // Child, grandChild and greatGrandChild are outside the ancestor clip.
9019  QRegion expectedOpaqueRegion(50, 50, 150, 150);
9020  QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), expectedOpaqueRegion);
9021 
9022  // Now they are all inside the ancestor clip.
9023  child.setGeometry(50, 50, 150, 150);
9024  QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), expectedOpaqueRegion);
9025 
9026  // Set mask on greatGrandChild.
9027  const QRegion mask(10, 10, 50, 50);
9028  greatGrandChild.setMask(mask);
9029  expectedOpaqueRegion &= mask.translated(50, 50);
9030  QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), expectedOpaqueRegion);
9031 
9032  // Make greatGrandChild "transparent".
9033  greatGrandChild.setAutoFillBackground(false);
9034  QCOMPARE(qt_widget_private(&grandChild)->getOpaqueChildren(), QRegion());
9035 }
9036 
9037 class MaskSetWidget : public QWidget
9038 {
9039  Q_OBJECT
9040 public:
9041  using QWidget::QWidget;
9042 
9043  void paintEvent(QPaintEvent *event) override
9044  {
9045  QPainter p(this);
9046 
9047  paintedRegion += event->region();
9048  for (const QRect &r : event->region())
9049  p.fillRect(r, Qt::red);
9050 
9051  repainted = true;
9052  }
9053 
9054  void resizeEvent(QResizeEvent *) override
9055  {
9056  setMask(QRegion(QRect(0, 0, width(), 10)));
9057  }
9058 
9060  bool repainted = false;
9061 
9062 public slots:
9063  void resizeDown() { setGeometry(QRect(0, 50, 50, 50)); }
9064  void resizeUp() { setGeometry(QRect(0, 50, 150, 50)); }
9065 };
9066 
9067 void tst_QWidget::setMaskInResizeEvent()
9068 {
9069  UpdateWidget w;
9070  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
9071  w.reset();
9072  w.resize(200, 200);
9073  centerOnScreen(&w);
9075  w.raise();
9076 
9077  MaskSetWidget testWidget(&w);
9078  testWidget.setGeometry(0, 0, 100, 100);
9079  testWidget.setMask(QRegion(QRect(0,0,100,10)));
9080  testWidget.show();
9081  w.show();
9083  QTRY_VERIFY(w.numPaintEvents > 0);
9084 
9085  w.reset();
9086  testWidget.paintedRegion = QRegion();
9087  testWidget.resizeDown();
9088 
9089  QRegion expectedParentUpdate(0, 0, 100, 10); // Old testWidget area.
9090  expectedParentUpdate += testWidget.geometry(); // New testWidget area.
9091  QTRY_VERIFY(testWidget.repainted);
9092  QTRY_COMPARE(w.paintedRegion, expectedParentUpdate);
9093  QTRY_COMPARE(testWidget.paintedRegion, testWidget.mask());
9094 
9095  testWidget.paintedRegion = QRegion();
9096  testWidget.repainted = false;
9097  // Now resize the widget again, but in the opposite direction
9098  testWidget.resizeUp();
9099  QTRY_VERIFY(testWidget.repainted);
9100  QTRY_COMPARE(testWidget.paintedRegion, testWidget.mask());
9101 }
9102 
9103 class MoveInResizeWidget : public QWidget
9104 {
9105  Q_OBJECT
9106 public:
9107  explicit MoveInResizeWidget(QWidget *p = nullptr)
9108  : QWidget(p)
9109  {
9110  setWindowFlags(Qt::FramelessWindowHint);
9111  }
9112 
9113  void resizeEvent(QResizeEvent *) override
9114  {
9115  move(QPoint(100,100));
9116 
9117  static bool firstTime = true;
9118  if (firstTime)
9120 
9121  firstTime = false;
9122  }
9123 
9124 public slots:
9125  void resizeMe() {
9126  resize(100, 100);
9127  }
9128 };
9129 
9130 void tst_QWidget::moveInResizeEvent()
9131 {
9132  MoveInResizeWidget testWidget;
9133  testWidget.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
9134  testWidget.setGeometry(50, 50, 200, 200);
9135  testWidget.show();
9136  QVERIFY(QTest::qWaitForWindowExposed(&testWidget));
9137 
9138  QRect expectedGeometry(100,100, 100, 100);
9139  QTRY_COMPARE(testWidget.geometry(), expectedGeometry);
9140 }
9141 
9142 #ifdef QT_BUILD_INTERNAL
9143 void tst_QWidget::immediateRepaintAfterInvalidateBackingStore()
9144 {
9145  if (m_platform != QStringLiteral("xcb") && m_platform != QStringLiteral("windows"))
9146  QSKIP("We don't support immediate repaint right after show on other platforms.");
9147 
9150  centerOnScreen(widget.data());
9151  widget->show();
9153 
9154  widget->numPaintEvents = 0;
9155 
9156  // Marks the area covered by the widget as dirty in the backing store and
9157  // posts an UpdateRequest event.
9159  QCOMPARE(widget->numPaintEvents, 0);
9160 
9161  // The entire widget is already dirty, but this time we want to update immediately
9162  // by calling repaint(), and thus we have to repaint the widget and not wait for
9163  // the UpdateRequest to be sent when we get back to the event loop.
9164  widget->update();
9165  QTRY_COMPARE(widget->numPaintEvents, 1);
9166 }
9167 #endif
9168 
9169 void tst_QWidget::effectiveWinId()
9170 {
9171  QWidget parent;
9172  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
9173  parent.resize(200, 200);
9174  QWidget child(&parent);
9175 
9176  // Shouldn't crash.
9177  QVERIFY(!parent.effectiveWinId());
9178  QVERIFY(!child.effectiveWinId());
9179 
9180  parent.show();
9181 
9182  QVERIFY(parent.effectiveWinId());
9183  QVERIFY(child.effectiveWinId());
9184 }
9185 
9186 void tst_QWidget::effectiveWinId2()
9187 {
9188  QWidget parent;
9189 
9190  class MyWidget : public QWidget
9191  {
9192  bool event(QEvent *e) override
9193  {
9194  if (e->type() == QEvent::WinIdChange) {
9195  // Shouldn't crash.
9196  effectiveWinId();
9197  }
9198 
9199  return QWidget::event(e);
9200  }
9201  };
9202 
9203  MyWidget child;
9204  child.setParent(&parent);
9205  parent.show();
9206 
9207  child.setParent(nullptr);
9208  child.setParent(&parent);
9209 }
9210 
9211 class CustomWidget : public QWidget
9212 {
9213 public:
9214  mutable int metricCallCount = 0;
9215 
9216  using QWidget::QWidget;
9217 
9218  int metric(PaintDeviceMetric metric) const override
9219  {
9220  ++metricCallCount;
9221  return QWidget::metric(metric);
9222  }
9223 };
9224 
9225 void tst_QWidget::customDpi()
9226 {
9227  QScopedPointer<QWidget> topLevel(new QWidget);
9228  CustomWidget *custom = new CustomWidget(topLevel.data());
9229  QWidget *child = new QWidget(custom);
9230 
9231  custom->metricCallCount = 0;
9232  topLevel->logicalDpiX();
9233  QCOMPARE(custom->metricCallCount, 0);
9234  custom->logicalDpiX();
9235  QCOMPARE(custom->metricCallCount, 1);
9236  child->logicalDpiX();
9237  QCOMPARE(custom->metricCallCount, 1);
9238 }
9239 
9240 void tst_QWidget::customDpiProperty()
9241 {
9242  QScopedPointer<QWidget> topLevel(new QWidget);
9243  QWidget *middle = new CustomWidget(topLevel.data());
9244  QWidget *child = new QWidget(middle);
9245 
9246  const int initialDpiX = topLevel->logicalDpiX();
9247  const int initialDpiY = topLevel->logicalDpiY();
9248 
9249  middle->setProperty("_q_customDpiX", 300);
9250  middle->setProperty("_q_customDpiY", 400);
9251 
9252  QCOMPARE(topLevel->logicalDpiX(), initialDpiX);
9253  QCOMPARE(topLevel->logicalDpiY(), initialDpiY);
9254 
9255  QCOMPARE(middle->logicalDpiX(), 300);
9256  QCOMPARE(middle->logicalDpiY(), 400);
9257 
9258  QCOMPARE(child->logicalDpiX(), 300);
9259  QCOMPARE(child->logicalDpiY(), 400);
9260 
9261  middle->setProperty("_q_customDpiX", QVariant());
9262  middle->setProperty("_q_customDpiY", QVariant());
9263 
9264  QCOMPARE(topLevel->logicalDpiX(), initialDpiX);
9265  QCOMPARE(topLevel->logicalDpiY(), initialDpiY);
9266 
9267  QCOMPARE(middle->logicalDpiX(), initialDpiX);
9268  QCOMPARE(middle->logicalDpiY(), initialDpiY);
9269 
9270  QCOMPARE(child->logicalDpiX(), initialDpiX);
9271  QCOMPARE(child->logicalDpiY(), initialDpiY);
9272 }
9273 
9274 void tst_QWidget::quitOnCloseAttribute()
9275 {
9276  QWidget w;
9277  QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), true);
9278  w.setAttribute(Qt::WA_QuitOnClose, false);
9279  QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false);
9280 
9281  w.setAttribute(Qt::WA_QuitOnClose);
9282  w.setWindowFlags(Qt::Tool);
9283  QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false);
9284 
9285  w.setAttribute(Qt::WA_QuitOnClose);
9286  w.setWindowFlags(Qt::Popup);
9287  QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false);
9288 
9289  w.setAttribute(Qt::WA_QuitOnClose);
9290  w.setWindowFlags(Qt::ToolTip);
9291  QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false);
9292 
9293  w.setAttribute(Qt::WA_QuitOnClose);
9294  w.setWindowFlags(Qt::SplashScreen);
9295  QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false);
9296 
9297  w.setAttribute(Qt::WA_QuitOnClose);
9298  w.setWindowFlags(Qt::SubWindow);
9299  QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false);
9300 
9301  w.setAttribute(Qt::WA_QuitOnClose);
9302  w.setWindowFlags(Qt::Dialog);
9303  QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), true);
9304  w.show();
9305  QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), true);
9306  w.setWindowFlags(Qt::Tool);
9307  QCOMPARE(w.testAttribute(Qt::WA_QuitOnClose), false);
9308 }
9309 
9310 void tst_QWidget::moveRect()
9311 {
9312  QWidget widget;
9314  widget.resize(200, 200);
9315  widget.setUpdatesEnabled(false);
9316  QWidget child(&widget);
9317  child.setUpdatesEnabled(false);
9318  child.setAttribute(Qt::WA_OpaquePaintEvent);
9319  widget.show();
9321  child.move(10, 10); // Don't crash.
9322 }
9323 
9324 #if defined(Q_OS_WIN)
9325 class GDIWidget : public QDialog
9326 {
9327  Q_OBJECT
9328 public:
9329  GDIWidget() {
9331  timer.setSingleShot(true);
9332  timer.setInterval(0);
9333  }
9334  QPaintEngine *paintEngine() const override { return nullptr; }
9335 
9336  void paintEvent(QPaintEvent *) override
9337  {
9339  const auto hdc = reinterpret_cast<HDC>(ni->nativeResourceForWindow(QByteArrayLiteral("getDC"), windowHandle()));
9340  if (hdc) {
9341  const HBRUSH brush = CreateSolidBrush(RGB(255, 0, 0));
9342  SelectObject(hdc, brush);
9343  Rectangle(hdc, 0, 0, 10, 10);
9344  DeleteObject(brush);
9345  ni->nativeResourceForWindow(QByteArrayLiteral("releaseDC"), windowHandle());
9346  } else {
9347  qWarning("%s: Unable to obtain native DC.", Q_FUNC_INFO);
9348  }
9349  if (!timer.isActive()) {
9350  connect(&timer, &QTimer::timeout, this,
9351  hdc ? &GDIWidget::slotTimer : &QDialog::reject);
9352  timer.start();
9353  }
9354  }
9355 
9356  QSize sizeHint() const override { return {400, 300}; };
9357 
9358 private slots:
9359  void slotTimer() {
9360  QScreen *screen = windowHandle()->screen();
9361  const QImage im = screen->grabWindow(internalWinId(), 0, 0, -1, -1).toImage();
9362  color = im.pixel(1, 1);
9363  accept();
9364  }
9365 
9366 public:
9367  QColor color;
9368  QTimer timer;
9369 };
9370 
9371 void tst_QWidget::gdiPainting()
9372 {
9373  GDIWidget w;
9374  w.exec();
9375 
9376  QCOMPARE(w.color, QColor(255, 0, 0));
9377 
9378 }
9379 
9380 void tst_QWidget::paintOnScreenPossible()
9381 {
9382  QWidget w1;
9383  w1.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
9384  w1.setAttribute(Qt::WA_PaintOnScreen);
9385  QVERIFY(!w1.testAttribute(Qt::WA_PaintOnScreen));
9386 
9387  GDIWidget w2;
9388  w2.setAttribute(Qt::WA_PaintOnScreen);
9389  QVERIFY(w2.testAttribute(Qt::WA_PaintOnScreen));
9390 }
9391 #endif // Q_OS_WIN
9392 
9393 void tst_QWidget::reparentStaticWidget()
9394 {
9395  QWidget window1;
9396  window1.setWindowTitle(QStringLiteral("window1 ") + __FUNCTION__);
9397  window1.resize(m_testWidgetSize);
9398  window1.move(m_availableTopLeft + QPoint(100, 100));
9399 
9400  QWidget *child = new QWidget(&window1);
9401  child->setPalette(Qt::red);
9402  child->setAutoFillBackground(true);
9403  child->setAttribute(Qt::WA_StaticContents);
9404  child->resize(window1.width() - 40, window1.height() - 40);
9405  child->setWindowTitle(QStringLiteral("child ") + __FUNCTION__);
9406 
9407  QWidget *grandChild = new QWidget(child);
9408  grandChild->setPalette(Qt::blue);
9409  grandChild->setAutoFillBackground(true);
9410  grandChild->resize(50, 50);
9411  grandChild->setAttribute(Qt::WA_StaticContents);
9412  window1.show();
9414 
9415  QWidget window2;
9416  window2.setWindowTitle(QStringLiteral("window2 ") + __FUNCTION__);
9417  window2.resize(m_testWidgetSize);
9418  window2.move(window1.geometry().topRight() + QPoint(100, 0));
9419  window2.show();
9421 
9422  // Reparent into another top-level.
9423  child->setParent(&window2);
9424  child->show();
9425 
9426  // Please don't crash.
9427  window1.resize(window1.size() + QSize(2, 2));
9428  QTest::qWait(20);
9429 
9430  // Make sure we move all static children even though
9431  // the reparented widget itself is non-static.
9432  child->setAttribute(Qt::WA_StaticContents, false);
9433  child->setParent(&window1);
9434  child->show();
9435 
9436  // Please don't crash.
9437  window2.resize(window2.size() + QSize(2, 2));
9438  QTest::qWait(20);
9439 
9440  child->setParent(nullptr);
9441  child->show();
9442  QTest::qWait(20);
9443 
9444  // Please don't crash.
9445  child->resize(child->size() + QSize(2, 2));
9446  window2.resize(window2.size() + QSize(2, 2));
9447  QTest::qWait(20);
9448 
9449  QWidget *siblingOfGrandChild = new QWidget(child);
9450  siblingOfGrandChild->show();
9451  QTest::qWait(20);
9452 
9453  // Nothing should happen when reparenting within the same top-level.
9454  grandChild->setParent(siblingOfGrandChild);
9455  grandChild->show();
9456  QTest::qWait(20);
9457 
9458  QWidget paintOnScreen;
9459  paintOnScreen.setWindowTitle(QStringLiteral("paintOnScreen ") + __FUNCTION__);
9460  paintOnScreen.resize(m_testWidgetSize);
9461  paintOnScreen.move(window1.geometry().bottomLeft() + QPoint(0, 50));
9462 
9463  paintOnScreen.setAttribute(Qt::WA_PaintOnScreen);
9464  paintOnScreen.show();
9465  QVERIFY(QTest::qWaitForWindowExposed(&paintOnScreen));
9466  QTest::qWait(20);
9467 
9468  child->setParent(&paintOnScreen);
9469  child->show();
9470  QTest::qWait(20);
9471 
9472  // Please don't crash.
9473  paintOnScreen.resize(paintOnScreen.size() + QSize(2, 2));
9474  QTest::qWait(20);
9475 
9476 }
9477 
9478 void tst_QWidget::QTBUG6883_reparentStaticWidget2()
9479 {
9480  QMainWindow mw;
9481  mw.setWindowTitle(QStringLiteral("MainWindow ") + __FUNCTION__);
9482  mw.move(m_availableTopLeft + QPoint(100, 100));
9483 
9484  QDockWidget *one = new QDockWidget(QStringLiteral("Dock ") + __FUNCTION__, &mw);
9485  mw.addDockWidget(Qt::LeftDockWidgetArea, one , Qt::Vertical);
9486 
9487  QWidget *child = new QWidget();
9488  child->setPalette(Qt::red);
9489  child->setAutoFillBackground(true);
9490  child->setAttribute(Qt::WA_StaticContents);
9491  child->resize(m_testWidgetSize);
9492  one->setWidget(child);
9493 
9494  QToolBar *mainTools = mw.addToolBar("Main Tools");
9495  QLineEdit *le = new QLineEdit;
9496  le->setMinimumWidth(m_testWidgetSize.width());
9497  mainTools->addWidget(le);
9498 
9499  mw.show();
9501 
9502  one->setFloating(true);
9503  QTest::qWait(20);
9504  //do not crash
9505 }
9506 
9507 class ColorRedWidget : public QWidget
9508 {
9509 public:
9510  explicit ColorRedWidget(QWidget *parent = nullptr)
9512  {
9513  }
9514 
9515  void paintEvent(QPaintEvent *) override
9516  {
9517  QPainter p(this);
9518  p.fillRect(rect(),Qt::red);
9519  }
9520 };
9521 
9522 void tst_QWidget::translucentWidget()
9523 {
9525  QSKIP("Wayland: This fails. Figure out why.");
9526 
9527  QPixmap pm(16,16);
9528  pm.fill(Qt::red);
9530  label.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
9531  label.setFixedSize(16,16);
9532  label.setAttribute(Qt::WA_TranslucentBackground);
9533  label.move(m_availableTopLeft);
9534  label.show();
9536 
9537  QPixmap widgetSnapshot =
9538  label.grab(QRect(QPoint(0, 0), label.size()));
9539  const QImage actual = widgetSnapshot.toImage().convertToFormat(QImage::Format_RGB32);
9540  QImage expected = pm.toImage().scaled(label.devicePixelRatio() * pm.size());
9541  expected.setDevicePixelRatio(label.devicePixelRatio());
9542 #ifdef Q_OS_ANDROID
9543  // Android uses Format_ARGB32_Premultiplied by default
9544  expected = expected.convertToFormat(QImage::Format_RGB32);
9545 #endif
9546  QCOMPARE(actual.size(),expected.size());
9547  QCOMPARE(actual,expected);
9548 
9549  const QWindow *window = label.windowHandle();
9550  const QSurfaceFormat translucentFormat = window->format();
9551  label.setAttribute(Qt::WA_TranslucentBackground, false);
9552  // Changing WA_TranslucentBackground with an already created native window
9553  // has no effect since Qt 5.0 due to the introduction of QWindow et al.
9554  // This means that the change must *not* be reflected in the
9555  // QSurfaceFormat, because there is no change when it comes to the
9556  // underlying native window. Otherwise the state would no longer
9557  // describe reality (the native window) See QTBUG-85714.
9558  QVERIFY(translucentFormat == window->format());
9559 }
9560 
9561 class MaskResizeTestWidget : public QWidget
9562 {
9563  Q_OBJECT
9564 public:
9565  explicit MaskResizeTestWidget(QWidget* p = nullptr) : QWidget(p)
9566  {
9567  setMask(QRegion(QRect(0, 0, 100, 100)));
9568  }
9569 
9570  void paintEvent(QPaintEvent* event) override
9571  {
9572  QPainter p(this);
9573 
9574  paintedRegion += event->region();
9575  for (const QRect &r : event->region())
9576  p.fillRect(r, Qt::red);
9577  }
9578 
9580 
9581 public slots:
9582  void enlargeMask() {
9583  QRegion newMask(QRect(0, 0, 150, 150));
9584  setMask(newMask);
9585  }
9586 
9587  void shrinkMask() {
9588  QRegion newMask(QRect(0, 0, 50, 50));
9589  setMask(newMask);
9590  }
9591 
9592 };
9593 
9594 void tst_QWidget::setClearAndResizeMask()
9595 {
9597  QSKIP("Wayland: This fails. Figure out why.");
9598 
9599  UpdateWidget topLevel;
9601  topLevel.resize(160, 160);
9602  centerOnScreen(&topLevel);
9603  topLevel.show();
9604  QApplication::setActiveWindow(&topLevel);
9606  QTRY_VERIFY(topLevel.numPaintEvents > 0);
9607  topLevel.reset();
9608 
9609  // Mask top-level widget
9610  const QRegion topLevelMask(0, 0, 100, 100, QRegion::Ellipse);
9611  topLevel.setMask(topLevelMask);
9612  QCOMPARE(topLevel.mask(), topLevelMask);
9613  // Ensure that the top-level doesn't get any update.
9614  // We don't control what's happening on platforms other than X11, Windows
9615  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows"))
9616  QCOMPARE(topLevel.numPaintEvents, 0);
9617 
9618  topLevel.reset();
9619 
9620  // Clear top-level mask
9621  topLevel.clearMask();
9622  QCOMPARE(topLevel.mask(), QRegion());
9623  QTest::qWait(10);
9624  QRegion outsideOldMask(topLevel.rect());
9625  outsideOldMask -= topLevelMask;
9626  // Ensure that the top-level gets an update for the area outside the old mask.
9627  // We don't control what's happening on platforms other than X11, Windows
9628  if (m_platform == QStringLiteral("xcb") || m_platform == QStringLiteral("windows")) {
9629  QTRY_VERIFY(topLevel.numPaintEvents > 0);
9630  QTRY_COMPARE(topLevel.paintedRegion, outsideOldMask);
9631  }
9632 
9633  UpdateWidget child(&topLevel);
9634  child.setAutoFillBackground(true); // NB! Opaque child.
9635  child.setPalette(Qt::red);
9636  child.resize(100, 100);
9637  child.show();
9638  QTest::qWait(10);
9639 
9640  child.reset();
9641  topLevel.reset();
9642 
9643  // Mask child widget with a mask that is smaller than the rect
9644  const QRegion childMask(0, 0, 50, 50);
9645  child.setMask(childMask);
9646  QTRY_COMPARE(child.mask(), childMask);
9647  // and ensure that the child widget doesn't get any update.
9648 #ifdef Q_OS_MACOS
9649  // Mac always issues a full update when calling setMask, and we cannot force it to not do so.
9650  if (child.internalWinId())
9651  QCOMPARE(child.numPaintEvents, 1);
9652  else
9653 #endif
9654  QCOMPARE(child.numPaintEvents, 0);
9655  // and the parent widget gets an update for the newly exposed area.
9656  QTRY_COMPARE(topLevel.numPaintEvents, 1);
9657  QRegion expectedParentExpose(child.rect());
9658  expectedParentExpose -= childMask;
9659  QCOMPARE(topLevel.paintedRegion, expectedParentExpose);
9660 
9661  child.reset();
9662  topLevel.reset();
9663 
9664  // Clear child widget mask
9665  child.clearMask();
9666  QTRY_COMPARE(child.mask(), QRegion());
9667  // and ensure that that the child widget gets an update for the area outside the old mask.
9668  QTRY_COMPARE(child.numPaintEvents, 1);
9669  outsideOldMask = child.rect();
9670 #ifdef Q_OS_MACOS
9671  // Mac always issues a full update when calling setMask, and we cannot force it to not do so.
9672  if (!child.internalWinId())
9673 #endif
9674  outsideOldMask -= childMask;
9675  QCOMPARE(child.paintedRegion, outsideOldMask);
9676  // and the parent widget doesn't get any update.
9677  QCOMPARE(topLevel.numPaintEvents, 0);
9678 
9679  child.reset();
9680  topLevel.reset();
9681 
9682  // Mask child widget with a mask that is bigger than the rect
9683  child.setMask(QRegion(0, 0, 1000, 1000));
9684 #ifdef Q_OS_MACOS
9685  // Mac always issues a full update when calling setMask, and we cannot force it to not do so.
9686  if (child.internalWinId())
9687  QTRY_COMPARE(child.numPaintEvents, 1);
9688  else
9689 #endif
9690  // and ensure that we don't get any updates at all.
9691  QTRY_COMPARE(child.numPaintEvents, 0);
9692  QCOMPARE(topLevel.numPaintEvents, 0);
9693 
9694  // ...and the same applies when clearing the mask.
9695  child.clearMask();
9696  QTest::qWait(100);
9697 #ifdef Q_OS_MACOS
9698  // Mac always issues a full update when calling setMask, and we cannot force it to not do so.
9699  if (child.internalWinId())
9700  QTRY_VERIFY(child.numPaintEvents > 0);
9701  else
9702 #endif
9703  QCOMPARE(child.numPaintEvents, 0);
9704  QCOMPARE(topLevel.numPaintEvents, 0);
9705 
9706  QWidget resizeParent;
9707  MaskResizeTestWidget resizeChild(&resizeParent);
9708 
9709  resizeParent.resize(300,300);
9710  resizeParent.raise();
9711  resizeParent.setWindowFlags(Qt::WindowStaysOnTopHint);
9712  resizeChild.setGeometry(50,50,200,200);
9713  QPalette pal = resizeParent.palette();
9714  pal.setColor(QPalette::Window, QColor(Qt::white));
9715  resizeParent.setPalette(pal);
9716 
9717  resizeParent.show();
9718  QVERIFY(QTest::qWaitForWindowExposed(&resizeParent));
9719  // Disable the size grip on the Mac; otherwise it'll be included when grabbing the window.
9720  resizeParent.setFixedSize(resizeParent.size());
9721  resizeChild.show();
9722  QTest::qWait(100);
9723  resizeChild.paintedRegion = QRegion();
9724 
9725  QTimer::singleShot(100, &resizeChild, SLOT(shrinkMask()));
9726  QTest::qWait(200);
9727 #ifdef Q_OS_MACOS
9728  // Mac always issues a full update when calling setMask, and we cannot force it to not do so.
9729  if (child.internalWinId())
9730  QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask());
9731  else
9732 #endif
9733  QTRY_COMPARE(resizeChild.paintedRegion, QRegion());
9734 
9735  resizeChild.paintedRegion = QRegion();
9736  const QRegion oldMask = resizeChild.mask();
9737  QTimer::singleShot(0, &resizeChild, SLOT(enlargeMask()));
9738  QTest::qWait(100);
9739 #ifdef Q_OS_MACOS
9740  // Mac always issues a full update when calling setMask, and we cannot force it to not do so.
9741  if (child.internalWinId())
9742  QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask());
9743  else
9744 #endif
9745  QTRY_COMPARE(resizeChild.paintedRegion, resizeChild.mask() - oldMask);
9746 }
9747 
9748 void tst_QWidget::maskedUpdate()
9749 {
9750  UpdateWidget topLevel;
9752  topLevel.resize(200, 200);
9753  centerOnScreen(&topLevel);
9754  const QRegion topLevelMask(50, 50, 70, 70);
9755  topLevel.setMask(topLevelMask);
9756 
9757  UpdateWidget child(&topLevel);
9758  child.setGeometry(20, 20, 180, 180);
9759  const QRegion childMask(60, 60, 30, 30);
9760  child.setMask(childMask);
9761 
9762  UpdateWidget grandChild(&child);
9763  grandChild.setGeometry(50, 50, 100, 100);
9764  const QRegion grandChildMask(20, 20, 10, 10);
9765  grandChild.setMask(grandChildMask);
9766 
9767  topLevel.show();
9769  QTRY_VERIFY(topLevel.numPaintEvents > 0);
9770 
9771 
9772 #define RESET_WIDGETS \
9773  topLevel.reset(); \
9774  child.reset(); \
9775  grandChild.reset();
9776 
9777 #define CLEAR_MASK(widget) \
9778  widget.clearMask(); \
9779  QTest::qWait(100); \
9780  RESET_WIDGETS;
9781 
9782  // All widgets are transparent at this point, so any call to update() will result
9783  // in composition, i.e. the update propagates to ancestors and children.
9784 
9785  // TopLevel update.
9786  RESET_WIDGETS;
9787  topLevel.update();
9788  QTest::qWait(10);
9789 
9790  QTRY_COMPARE(topLevel.paintedRegion, topLevelMask);
9791  QTRY_COMPARE(child.paintedRegion, childMask);
9792  QTRY_COMPARE(grandChild.paintedRegion, grandChildMask);
9793 
9794  // Child update.
9795  RESET_WIDGETS;
9796  child.update();
9797  QTest::qWait(10);
9798 
9799  QTRY_COMPARE(topLevel.paintedRegion, childMask.translated(child.pos()));
9800  QTRY_COMPARE(child.paintedRegion, childMask);
9801  QTRY_COMPARE(grandChild.paintedRegion, grandChildMask);
9802 
9803  // GrandChild update.
9804  RESET_WIDGETS;
9805  grandChild.update();
9806  QTest::qWait(10);
9807 
9808  QTRY_COMPARE(topLevel.paintedRegion, grandChildMask.translated(grandChild.mapTo(&topLevel, QPoint())));
9809  QTRY_COMPARE(child.paintedRegion, grandChildMask.translated(grandChild.pos()));
9810  QTRY_COMPARE(grandChild.paintedRegion, grandChildMask);
9811 
9813  child.setAttribute(Qt::WA_OpaquePaintEvent);
9814  grandChild.setAttribute(Qt::WA_OpaquePaintEvent);
9815 
9816  // All widgets are now opaque, which means no composition, i.e.
9817  // the update does not propate to ancestors and children.
9818 
9819  // TopLevel update.
9820  RESET_WIDGETS;
9821  topLevel.update();
9822  QTest::qWait(10);
9823 
9824  QRegion expectedTopLevelUpdate = topLevelMask;
9825  expectedTopLevelUpdate -= childMask.translated(child.pos()); // Subtract opaque children.
9826  QTRY_COMPARE(topLevel.paintedRegion, expectedTopLevelUpdate);
9827  QTRY_COMPARE(child.paintedRegion, QRegion());
9828  QTRY_COMPARE(grandChild.paintedRegion, QRegion());
9829 
9830  // Child update.
9831  RESET_WIDGETS;
9832  child.update();
9833  QTest::qWait(10);
9834 
9835  QTRY_COMPARE(topLevel.paintedRegion, QRegion());
9836  QRegion expectedChildUpdate = childMask;
9837  expectedChildUpdate -= grandChildMask.translated(grandChild.pos()); // Subtract oapque children.
9838  QTRY_COMPARE(child.paintedRegion, expectedChildUpdate);
9839  QTRY_COMPARE(grandChild.paintedRegion, QRegion());
9840 
9841  // GrandChild update.
9842  RESET_WIDGETS;
9843  grandChild.update();
9844  QTest::qWait(10);
9845 
9846  QTRY_COMPARE(topLevel.paintedRegion, QRegion());
9847  QTRY_COMPARE(child.paintedRegion, QRegion());
9848  QTRY_COMPARE(grandChild.paintedRegion, grandChildMask);
9849 
9850  // GrandChild update.
9851  CLEAR_MASK(grandChild);
9852  grandChild.update();
9853  QTest::qWait(10);
9854 
9855  QTRY_COMPARE(topLevel.paintedRegion, QRegion());
9856  QTRY_COMPARE(child.paintedRegion, QRegion());
9857  QRegion expectedGrandChildUpdate = grandChild.rect();
9858  // Clip with parent's mask.
9859  expectedGrandChildUpdate &= childMask.translated(-grandChild.pos());
9860  QCOMPARE(grandChild.paintedRegion, expectedGrandChildUpdate);
9861 
9862  // GrandChild update.
9863  CLEAR_MASK(child);
9864  grandChild.update();
9865  QTest::qWait(10);
9866 
9867  QTRY_COMPARE(topLevel.paintedRegion, QRegion());
9868  QTRY_COMPARE(child.paintedRegion, QRegion());
9869  expectedGrandChildUpdate = grandChild.rect();
9870  // Clip with parent's mask.
9871  expectedGrandChildUpdate &= topLevelMask.translated(-grandChild.mapTo(&topLevel, QPoint()));
9872  QTRY_COMPARE(grandChild.paintedRegion, expectedGrandChildUpdate);
9873 
9874  // Child update.
9875  RESET_WIDGETS;
9876  child.update();
9877  QTest::qWait(10);
9878 
9879  QTRY_COMPARE(topLevel.paintedRegion, QRegion());
9880  expectedChildUpdate = child.rect();
9881  // Clip with parent's mask.
9882  expectedChildUpdate &= topLevelMask.translated(-child.pos());
9883  expectedChildUpdate -= grandChild.geometry(); // Subtract opaque children.
9884  QTRY_COMPARE(child.paintedRegion, expectedChildUpdate);
9885  QTRY_COMPARE(grandChild.paintedRegion, QRegion());
9886 
9887  // GrandChild update.
9888  CLEAR_MASK(topLevel);
9889  grandChild.update();
9890  QTest::qWait(10);
9891 
9892  QTRY_COMPARE(topLevel.paintedRegion, QRegion());
9893  QTRY_COMPARE(child.paintedRegion, QRegion());
9894  QTRY_COMPARE(grandChild.paintedRegion, QRegion(grandChild.rect())); // Full update.
9895 }
9896 
9897 #ifndef QT_NO_CURSOR
9898 void tst_QWidget::syntheticEnterLeave()
9899 {
9900  if (m_platform == QStringLiteral("wayland"))
9901  QSKIP("Wayland: This fails. Figure out why.");
9902  class MyWidget : public QWidget
9903  {
9904  public:
9905  using QWidget::QWidget;
9906  void enterEvent(QEnterEvent *) override { ++numEnterEvents; }
9907  void leaveEvent(QEvent *) override { ++numLeaveEvents; }
9908  int numEnterEvents = 0;
9909  int numLeaveEvents = 0;
9910  };
9911 
9912  QCursor::setPos(m_safeCursorPos);
9913  if (!QTest::qWaitFor([this]{ return QCursor::pos() == m_safeCursorPos; }))
9914  QSKIP("Can't move cursor");
9915 
9916  MyWidget window;
9917  window.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
9918  window.setWindowFlags(Qt::WindowStaysOnTopHint);
9919  window.move(200, 200);
9920  window.resize(200, 200);
9921 
9922  MyWidget *child1 = new MyWidget(&window);
9923  child1->setPalette(Qt::blue);
9924  child1->setAutoFillBackground(true);
9925  child1->resize(200, 200);
9926  child1->setCursor(Qt::OpenHandCursor);
9927 
9928  MyWidget *child2 = new MyWidget(&window);
9929  child2->resize(200, 200);
9930 
9931  MyWidget *grandChild = new MyWidget(child2);
9932  grandChild->setPalette(Qt::red);
9933  grandChild->setAutoFillBackground(true);
9934  grandChild->resize(200, 200);
9935  grandChild->setCursor(Qt::WaitCursor);
9936 
9937  window.show();
9938  window.raise();
9939 
9941 
9942 #define RESET_EVENT_COUNTS \
9943  window.numEnterEvents = 0; \
9944  window.numLeaveEvents = 0; \
9945  child1->numEnterEvents = 0; \
9946  child1->numLeaveEvents = 0; \
9947  child2->numEnterEvents = 0; \
9948  child2->numLeaveEvents = 0; \
9949  grandChild->numEnterEvents = 0; \
9950  grandChild->numLeaveEvents = 0;
9951 
9952  // Position the cursor in the middle of the window.
9953  const QPoint globalPos = window.mapToGlobal(QPoint(100, 100));
9954  QCursor::setPos(globalPos); // Enter child2 and grandChild.
9955  if (!QTest::qWaitFor([globalPos]{ return QCursor::pos() == globalPos; }))
9956  QSKIP("Can't move cursor");
9957 
9958  QCOMPARE(window.numLeaveEvents, 0);
9959  QCOMPARE(child2->numLeaveEvents, 0);
9960  QCOMPARE(grandChild->numLeaveEvents, 0);
9961  QCOMPARE(child1->numLeaveEvents, 0);
9962 
9963  // This event arrives asynchronously
9964  QTRY_COMPARE(window.numEnterEvents, 1);
9965  QCOMPARE(child2->numEnterEvents, 1);
9966  QCOMPARE(grandChild->numEnterEvents, 1);
9967  QCOMPARE(child1->numEnterEvents, 0);
9968 
9970  child2->hide(); // Leave child2 and grandChild, enter child1.
9971 
9972  QCOMPARE(window.numLeaveEvents, 0);
9973  QCOMPARE(child2->numLeaveEvents, 1);
9974  QCOMPARE(grandChild->numLeaveEvents, 1);
9975  QCOMPARE(child1->numLeaveEvents, 0);
9976 
9977  QCOMPARE(window.numEnterEvents, 0);
9978  QCOMPARE(child2->numEnterEvents, 0);
9979  QCOMPARE(grandChild->numEnterEvents, 0);
9980  QCOMPARE(child1->numEnterEvents, 1);
9981 
9983  child2->show(); // Leave child1, enter child2 and grandChild.
9984 
9985  QCOMPARE(window.numLeaveEvents, 0);
9986  QCOMPARE(child2->numLeaveEvents, 0);
9987  QCOMPARE(grandChild->numLeaveEvents, 0);
9988  QCOMPARE(child1->numLeaveEvents, 1);
9989 
9990  QCOMPARE(window.numEnterEvents, 0);
9991  QCOMPARE(child2->numEnterEvents, 1);
9992  QCOMPARE(grandChild->numEnterEvents, 1);
9993  QCOMPARE(child1->numEnterEvents, 0);
9994 
9996  delete child2; // Enter child1 (and do not send leave events to child2 and grandChild).
9997 
9998  QCOMPARE(window.numLeaveEvents, 0);
9999  QCOMPARE(child1->numLeaveEvents, 0);
10000 
10001  QCOMPARE(window.numEnterEvents, 0);
10002  QCOMPARE(child1->numEnterEvents, 1);
10003 }
10004 #endif
10005 
10006 #ifndef QT_NO_CURSOR
10007 void tst_QWidget::enterLeaveOnWindowShowHide_data()
10008 {
10009  QTest::addColumn<Qt::WindowType>("windowType");
10010  QTest::addRow("dialog") << Qt::Dialog;
10011  QTest::addRow("popup") << Qt::Popup;
10012 }
10013 
10014 
10025 void tst_QWidget::enterLeaveOnWindowShowHide()
10026 {
10027  QFETCH(Qt::WindowType, windowType);
10028  class Widget : public QWidget
10029  {
10030  public:
10031  int numEnterEvents = 0;
10032  int numLeaveEvents = 0;
10033  QPoint enterPosition;
10034  Qt::WindowType secondaryWindowType = {};
10035  protected:
10036  void enterEvent(QEnterEvent *e) override
10037  {
10038  enterPosition = e->position().toPoint();
10039  ++numEnterEvents;
10040  }
10041  void leaveEvent(QEvent *) override
10042  {
10043  enterPosition = {};
10044  ++numLeaveEvents;
10045  }
10046  void mousePressEvent(QMouseEvent *e) override
10047  {
10048  QWidget *secondary = nullptr;
10049  switch (secondaryWindowType) {
10050  case Qt::Dialog: {
10051  QDialog *dialog = new QDialog(this);
10052  dialog->setModal(true);
10054  secondary = dialog;
10055  break;
10056  }
10057  case Qt::Popup: {
10058  QMenu *menu = new QMenu(this);
10059  menu->addAction("Action 1");
10060  menu->addAction("Action 2");
10061  secondary = menu;
10062  break;
10063  }
10064  default:
10065  QVERIFY2(false, "Test case not implemented for window type");
10066  break;
10067  }
10068 
10069  QPoint secondaryPos = e->globalPosition().toPoint();
10070  if (e->button() == Qt::LeftButton)
10071  secondaryPos += QPoint(10, 10); // cursor outside secondary
10072  else
10073  secondaryPos -= QPoint(10, 10); // cursor inside secondary
10074  secondary->move(secondaryPos);
10075  secondary->show();
10076  if (!QTest::qWaitForWindowExposed(secondary))
10077  QEXPECT_FAIL("", "Secondary window failed to show, test will fail", Abort);
10078  if (secondaryWindowType == Qt::Dialog && QGuiApplication::platformName() == "windows")
10079  QTest::qWait(250); // on Windows, we have to wait for fade-in effects
10080  }
10081  };
10082 
10083  int expectedEnter = 0;
10084  int expectedLeave = 0;
10085 
10086  Widget widget;
10087  widget.secondaryWindowType = windowType;
10088  const QRect screenGeometry = widget.screen()->availableGeometry();
10089  const QPoint cursorPos = screenGeometry.topLeft() + QPoint(50, 50);
10090  widget.setGeometry(QRect(cursorPos - QPoint(50, 50), screenGeometry.size() / 4));
10091  QCursor::setPos(cursorPos);
10092 
10093  if (!QTest::qWaitFor([&]{ return widget.geometry().contains(QCursor::pos()); }))
10094  QSKIP("We can't move the cursor");
10095  widget.show();
10098 
10099  ++expectedEnter;
10100  QTRY_COMPARE_WITH_TIMEOUT(widget.numEnterEvents, expectedEnter, 250);
10101  QCOMPARE(widget.enterPosition, widget.mapFromGlobal(cursorPos));
10103 
10104  QTest::mouseClick(&widget, Qt::LeftButton, {}, widget.mapFromGlobal(cursorPos));
10105  ++expectedLeave;
10106  QTRY_COMPARE_WITH_TIMEOUT(widget.numLeaveEvents, expectedLeave, 1000);
10113  ++expectedEnter;
10114  // Use default timeout, the test is flaky on Windows otherwise.
10115  QTRY_VERIFY(widget.numEnterEvents >= expectedEnter);
10116  // When a modal dialog closes we might get more than one enter event on macOS.
10117  // This seems to depend on timing, so we tolerate that flakiness for now.
10118  if (widget.numEnterEvents > expectedEnter && QGuiApplication::platformName() == "cocoa")
10119  QEXPECT_FAIL("dialog", "On macOS, we might get more than one Enter event", Continue);
10120 
10121  QCOMPARE(widget.numEnterEvents, expectedEnter);
10122  QCOMPARE(widget.enterPosition, widget.mapFromGlobal(cursorPos));
10124 }
10125 #endif
10126 
10127 #ifndef QT_NO_CURSOR
10128 void tst_QWidget::taskQTBUG_4055_sendSyntheticEnterLeave()
10129 {
10130  if (m_platform == QStringLiteral("wayland"))
10131  QSKIP("Wayland: Clients can't set cursor position on wayland.");
10132  class SELParent : public QWidget
10133  {
10134  public:
10135  using QWidget::QWidget;
10136 
10137  void mousePressEvent(QMouseEvent *) override { child->show(); }
10138  QWidget *child = nullptr;
10139  };
10140 
10141  class SELChild : public QWidget
10142  {
10143  public:
10144  using QWidget::QWidget;
10145  void enterEvent(QEnterEvent *) override { ++numEnterEvents; }
10146  void mouseMoveEvent(QMouseEvent *event) override
10147  {
10148  QCOMPARE(event->button(), Qt::NoButton);
10149  QCOMPARE(event->buttons(), QApplication::mouseButtons());
10151  ++numMouseMoveEvents;
10152  }
10153  void reset() { numEnterEvents = numMouseMoveEvents = 0; }
10154  int numEnterEvents = 0, numMouseMoveEvents = 0;
10155  };
10156 
10157  QCursor::setPos(m_safeCursorPos);
10158  if (!QTest::qWaitFor([this]{ return QCursor::pos() == m_safeCursorPos; }))
10159  QSKIP("Can't move cursor");
10160 
10161  SELParent parent;
10162  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
10163  parent.move(200, 200);
10164  parent.resize(200, 200);
10165  SELChild child(&parent);
10166  child.resize(200, 200);
10167  parent.show();
10169 
10170  const QPoint childPos = child.mapToGlobal(QPoint(100, 100));
10171  QCursor::setPos(childPos);
10172  if (!QTest::qWaitFor([childPos]{ return QCursor::pos() == childPos; }))
10173  QSKIP("Can't move cursor");
10174 
10175  // Make sure the cursor has entered the child.
10176  QTRY_VERIFY(child.numEnterEvents > 0);
10177 
10178  child.hide();
10179  child.reset();
10180  child.show();
10181 
10182  // Make sure the child gets enter event and no mouse move event.
10183  QTRY_COMPARE(child.numEnterEvents, 1);
10184  QCOMPARE(child.numMouseMoveEvents, 0);
10185 
10186  child.hide();
10187  child.reset();
10188  child.setMouseTracking(true);
10189  child.show();
10190 
10191  // Make sure the child gets enter event.
10192  // Note that we verify event->button() and event->buttons()
10193  // in SELChild::mouseMoveEvent().
10194  QTRY_COMPARE(child.numEnterEvents, 1);
10195  QCOMPARE(child.numMouseMoveEvents, 0);
10196 
10197  // Sending synthetic enter/leave trough the parent's mousePressEvent handler.
10198  parent.child = &child;
10199 
10200  child.hide();
10201  child.reset();
10203 
10204  // Make sure the child gets enter event.
10205  QTRY_COMPARE(child.numEnterEvents, 1);
10206  QCOMPARE(child.numMouseMoveEvents, 0);
10207 
10208  child.hide();
10209  child.reset();
10210  QTest::keyPress(&parent, Qt::Key_Shift);
10212 
10213  // Make sure the child gets enter event
10214  QTRY_COMPARE(child.numEnterEvents, 1);
10215  QCOMPARE(child.numMouseMoveEvents, 0);
10216  QTest::keyRelease(&child, Qt::Key_Shift);
10217  child.hide();
10218  child.reset();
10219  child.setMouseTracking(false);
10221 
10222  // Make sure the child gets enter event and no mouse move event.
10223  QTRY_COMPARE(child.numEnterEvents, 1);
10224  QCOMPARE(child.numMouseMoveEvents, 0);
10225  }
10226 #endif
10227 
10228 void tst_QWidget::windowFlags()
10229 {
10230  QWidget w;
10231  const auto baseFlags = w.windowFlags();
10232  w.setWindowFlags(w.windowFlags() | Qt::FramelessWindowHint);
10233  QVERIFY(w.windowFlags() & Qt::FramelessWindowHint);
10234  w.setWindowFlag(Qt::WindowStaysOnTopHint, true);
10235  QCOMPARE(w.windowFlags(), baseFlags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
10236  w.setWindowFlag(Qt::FramelessWindowHint, false);
10237  QCOMPARE(w.windowFlags(), baseFlags | Qt::WindowStaysOnTopHint);
10238 }
10239 
10240 void tst_QWidget::initialPosForDontShowOnScreenWidgets()
10241 {
10242  { // Check default position.
10243  const QPoint expectedPos(0, 0);
10244  QWidget widget;
10246  widget.winId(); // Make sure QWidgetPrivate::create is called.
10247  QCOMPARE(widget.pos(), expectedPos);
10248  QCOMPARE(widget.geometry().topLeft(), expectedPos);
10249  }
10250 
10251  { // Explicitly move to a position.
10252  const QPoint expectedPos(100, 100);
10253  QWidget widget;
10255  widget.move(expectedPos);
10256  widget.winId(); // Make sure QWidgetPrivate::create is called.
10257  QCOMPARE(widget.pos(), expectedPos);
10258  QCOMPARE(widget.geometry().topLeft(), expectedPos);
10259  }
10260 }
10261 
10262 class MyEvilObject : public QObject
10263 {
10264  Q_OBJECT
10265 public:
10266  explicit MyEvilObject(QWidget *widgetToCrash) : QObject(), widget(widgetToCrash)
10267  {
10268  connect(widget, &QObject::destroyed, this, &MyEvilObject::beEvil);
10269  delete widget;
10270  }
10271  QWidget *widget;
10272 
10273 private slots:
10274  void beEvil(QObject *) { widget->update(0, 0, 150, 150); }
10275 };
10276 
10277 void tst_QWidget::updateOnDestroyedSignal()
10278 {
10279  QWidget widget;
10281 
10282  QWidget *child = new QWidget(&widget);
10283  child->resize(m_testWidgetSize);
10284  child->setAutoFillBackground(true);
10285  child->setPalette(Qt::red);
10286 
10287  widget.show();
10289 
10290  // Please do not crash.
10291  MyEvilObject evil(child);
10292  QTest::qWait(200);
10293 }
10294 
10295 void tst_QWidget::toplevelLineEditFocus()
10296 {
10298  QSKIP("Wayland: This fails. Figure out why.");
10299 
10300  QLineEdit w;
10301  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
10302  w.setMinimumWidth(m_testWidgetSize.width());
10303  w.show();
10305 
10306  QTRY_COMPARE(QApplication::activeWindow(), static_cast<const QWidget *>(&w));
10307  QTRY_COMPARE(QApplication::focusWidget(), static_cast<const QWidget *>(&w));
10308 }
10309 
10310 void tst_QWidget::focusWidget_task254563()
10311 {
10312  //having different visibility for widget is important
10313  QWidget top;
10314  top.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
10315  top.show();
10316  QWidget container(&top);
10317  QWidget *widget = new QWidget(&container);
10318  widget->show();
10319 
10320  widget->setFocus(); //set focus (will set the focus widget up to the toplevel to be 'widget')
10321  container.setFocus();
10322  delete widget; // will call clearFocus but that doesn't help
10323  QVERIFY(top.focusWidget() != widget); //dangling pointer
10324 }
10325 
10326 // This test case relies on developer build (AUTOTEST_EXPORT).
10327 #ifdef QT_BUILD_INTERNAL
10328 void tst_QWidget::destroyBackingStore()
10329 {
10330  UpdateWidget w;
10331  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
10332  centerOnScreen(&w);
10333  w.reset();
10334  w.show();
10335 
10338  QTRY_VERIFY(w.numPaintEvents > 0);
10339  w.reset();
10340  w.update();
10342 
10343  w.update();
10345 
10346  QCOMPARE(w.numPaintEvents, 1);
10347 
10348  // Check one more time, because the second time around does more caching.
10349  w.update();
10351  QCOMPARE(w.numPaintEvents, 2);
10352 }
10353 #endif // QT_BUILD_INTERNAL
10354 
10355 // Helper function
10357 {
10359 #ifdef QT_BUILD_INTERNAL
10360  if (QTLWExtra *topExtra = qt_widget_private(&widget)->maybeTopData())
10361  repaintManager = topExtra->repaintManager.get();
10362 #endif
10363  return repaintManager;
10364 }
10365 
10366 // Tables of 5000 elements do not make sense on Windows Mobile.
10367 void tst_QWidget::rectOutsideCoordinatesLimit_task144779()
10368 {
10369 #ifndef QT_NO_CURSOR
10370  QGuiApplication::setOverrideCursor(Qt::BlankCursor); //keep the cursor out of screen grabs
10371 #endif
10372  QWidget main(nullptr, Qt::FramelessWindowHint); //don't get confused by the size of the window frame
10373  main.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
10374  QPalette palette;
10375  palette.setColor(QPalette::Window, Qt::red);
10376  main.setPalette(palette);
10377 
10378  QRect desktopDimensions = main.screen()->availableGeometry();
10379  QSize mainSize(400, 400);
10380  mainSize = mainSize.boundedTo(desktopDimensions.size());
10381  main.resize(mainSize);
10382 
10383  QWidget *offsetWidget = new QWidget(&main);
10384  offsetWidget->setGeometry(0, -(15000 - mainSize.height()), mainSize.width(), 15000);
10385 
10386  // big widget is too big for the coordinates, it must be limited by wrect
10387  // if wrect is not at the right position because of offsetWidget, bigwidget
10388  // is not painted correctly
10389  QWidget *bigWidget = new QWidget(offsetWidget);
10390  bigWidget->setGeometry(0, 0, mainSize.width(), 50000);
10391  palette.setColor(QPalette::Window, Qt::green);
10392  bigWidget->setPalette(palette);
10393  bigWidget->setAutoFillBackground(true);
10394 
10395  main.showNormal();
10397 
10398  QPixmap correct(main.size());
10399  correct.fill(Qt::green);
10400  const QPixmap mainPixmap = grabFromWidget(&main, QRect(QPoint(0, 0), QSize(-1, -1)));
10401 
10402  QTRY_COMPARE(mainPixmap.toImage().convertToFormat(QImage::Format_RGB32),
10403  correct.toImage().convertToFormat(QImage::Format_RGB32));
10404 #ifndef QT_NO_CURSOR
10406 #endif
10407 }
10408 
10409 void tst_QWidget::setGraphicsEffect()
10410 {
10411  // Check that we don't have any effect by default.
10414  QVERIFY(!widget->graphicsEffect());
10415 
10416  // SetGet check.
10418  widget->setGraphicsEffect(blurEffect);
10419  QCOMPARE(widget->graphicsEffect(), static_cast<QGraphicsEffect *>(blurEffect));
10420 
10421  // Ensure the existing effect is deleted when setting a new one.
10423  widget->setGraphicsEffect(shadowEffect);
10424  QVERIFY(!blurEffect);
10425  QCOMPARE(widget->graphicsEffect(), static_cast<QGraphicsEffect *>(shadowEffect));
10426  blurEffect = new QGraphicsBlurEffect;
10427 
10428  // Ensure the effect is uninstalled when setting it on a new target.
10429  QScopedPointer<QWidget> anotherWidget(new QWidget);
10430  anotherWidget->setGraphicsEffect(blurEffect);
10431  widget->setGraphicsEffect(blurEffect);
10432  QVERIFY(!anotherWidget->graphicsEffect());
10433  QVERIFY(!shadowEffect);
10434 
10435  // Ensure the existing effect is deleted when deleting the widget.
10436  widget.reset();
10437  QVERIFY(!blurEffect);
10438  anotherWidget.reset();
10439 
10440  // Ensure the effect is uninstalled when deleting it
10441  widget.reset(new QWidget);
10442  blurEffect = new QGraphicsBlurEffect;
10443  widget->setGraphicsEffect(blurEffect);
10444  delete blurEffect;
10445  QVERIFY(!widget->graphicsEffect());
10446 
10447  // Ensure the existing effect is uninstalled and deleted when setting a null effect
10448  blurEffect = new QGraphicsBlurEffect;
10449  widget->setGraphicsEffect(blurEffect);
10450  widget->setGraphicsEffect(nullptr);
10451  QVERIFY(!widget->graphicsEffect());
10452  QVERIFY(!blurEffect);
10453 }
10454 
10455 
10457 {
10458 public:
10461  {
10462  m_pattern = QPixmap(10, 10);
10463  m_pattern.fill(Qt::lightGray);
10464  QPainter p(&m_pattern);
10465  p.fillRect(QRectF(0, 0, 5, 5), QBrush(Qt::darkGray));
10466  p.fillRect(QRectF(5, 5, 5, 5), QBrush(Qt::darkGray));
10467  }
10468  void setExtent(int extent)
10469  {
10470  m_extent = extent;
10471  }
10472  QRectF boundingRectFor(const QRectF &sr) const override
10473  {
10474  return QRectF(sr.x() - m_extent, sr.y() - m_extent,
10475  sr.width() + 2 * m_extent, sr.height() + 2 * m_extent);
10476  }
10477 protected:
10478  void draw(QPainter *painter) override
10479  {
10480  QBrush brush;
10481  brush.setTexture(m_pattern);
10482  brush.setStyle(Qt::TexturePattern);
10483  QPaintDevice *p = painter->device();
10484  painter->fillRect(QRect(-m_extent, -m_extent,
10485  p->width() + m_extent, p->height() + m_extent), brush);
10486  }
10487  QPixmap m_pattern;
10488  int m_extent = 0;
10489 };
10490 
10491 static QImage fillExpected1()
10492 {
10493  QImage expected(QSize(40, 40), QImage::Format_RGB32);
10494  QPainter p(&expected);
10495  p.fillRect(QRect{{0, 0}, expected.size()}, QBrush(Qt::gray));
10496  p.fillRect(QRect(10, 10, 10, 10), QBrush(Qt::red));
10497  p.fillRect(QRect(20, 20, 10, 10), QBrush(Qt::blue));
10498  return expected;
10499 }
10500 static QImage fillExpected2()
10501 {
10502  QImage expected = fillExpected1();
10503  QPainter p(&expected);
10504  p.fillRect(QRect(10, 10, 5, 5), QBrush(Qt::darkGray));
10505  p.fillRect(QRect(15, 15, 5, 5), QBrush(Qt::darkGray));
10506  p.fillRect(QRect(15, 10, 5, 5), QBrush(Qt::lightGray));
10507  p.fillRect(QRect(10, 15, 5, 5), QBrush(Qt::lightGray));
10508  return expected;
10509 }
10510 static QImage fillExpected3()
10511 {
10512  QImage expected(QSize(40, 40), QImage::Format_RGB32);
10513  QPixmap pattern;
10514  pattern = QPixmap(10, 10);
10515  pattern.fill(Qt::lightGray);
10516  QPainter p(&pattern);
10517  p.fillRect(QRectF(0, 0, 5, 5), QBrush(Qt::darkGray));
10518  p.fillRect(QRectF(5, 5, 5, 5), QBrush(Qt::darkGray));
10519  QBrush brush;
10520  brush.setTexture(pattern);
10521  brush.setStyle(Qt::TexturePattern);
10522  QPainter p2(&expected);
10523  p2.fillRect(QRect{{0, 0}, expected.size()}, brush);
10524  return expected;
10525 }
10526 static QImage fillExpected4()
10527 {
10528  QImage expected = fillExpected1();
10529  QPixmap pattern;
10530  pattern = QPixmap(10, 10);
10531  pattern.fill(Qt::lightGray);
10532  QPainter p(&pattern);
10533  p.fillRect(QRectF(0, 0, 5, 5), QBrush(Qt::darkGray));
10534  p.fillRect(QRectF(5, 5, 5, 5), QBrush(Qt::darkGray));
10535  QBrush brush;
10536  brush.setTexture(pattern);
10537  brush.setStyle(Qt::TexturePattern);
10538  QPainter p2(&expected);
10539  p2.fillRect(QRect{{15, 15}, QSize{20, 20}}, brush);
10540  return expected;
10541 }
10542 
10543 void tst_QWidget::render_graphicsEffect_data()
10544 {
10545  QTest::addColumn<QImage>("expected");
10546  QTest::addColumn<bool>("topLevelEffect");
10547  QTest::addColumn<bool>("child1Effect");
10548  QTest::addColumn<bool>("child2Effect");
10549  QTest::addColumn<int>("extent");
10550 
10551  QTest::addRow("no_effect") << fillExpected1() << false << false << false << 0;
10552  QTest::addRow("first_child_effect") << fillExpected2() << false << true << false << 0;
10553  QTest::addRow("top_level_effect") << fillExpected3() << true << false << false << 0;
10554  QTest::addRow("effect_with_extent") << fillExpected4() << false << false << true << 5;
10555 }
10556 
10557 void tst_QWidget::render_graphicsEffect()
10558 {
10559  QFETCH(QImage, expected);
10560  QFETCH(bool, topLevelEffect);
10561  QFETCH(bool, child1Effect);
10562  QFETCH(bool, child2Effect);
10563  QFETCH(int, extent);
10564 
10565  QScopedPointer<QWidget> topLevel(new QWidget);
10566  topLevel->setPalette(Qt::gray);
10567  topLevel->resize(40, 40);
10570 
10571  // Render widget with 2 child widgets
10572  QImage image(topLevel->size(), QImage::Format_RGB32);
10573  image.fill(QColor(Qt::gray).rgb());
10574 
10575  QPainter painter(&image);
10576 
10577  QWidget *childWidget1(new QWidget(topLevel.data()));
10578  childWidget1->setAutoFillBackground(true);
10579  childWidget1->setPalette(Qt::red);
10580  childWidget1->resize(10, 10);
10581  childWidget1->move(10, 10);
10582  QWidget *childWidget2(new QWidget(topLevel.data()));
10583  childWidget2->setAutoFillBackground(true);
10584  childWidget2->setPalette(Qt::blue);
10585  childWidget2->resize(10, 10);
10586  childWidget2->move(20, 20);
10587 
10588  TestGraphicsEffect *graphicsEffect(new TestGraphicsEffect(topLevel.data()));
10589  if (topLevelEffect)
10590  topLevel->setGraphicsEffect(graphicsEffect);
10591  if (child1Effect)
10592  childWidget1->setGraphicsEffect(graphicsEffect);
10593  if (child2Effect)
10594  childWidget2->setGraphicsEffect(graphicsEffect);
10595  graphicsEffect->setExtent(extent);
10596 
10597  // Render without effect
10598  topLevel->render(&painter);
10599 #ifdef RENDER_DEBUG
10600  image.save("render_GraphicsEffect" + QTest::currentDataTag() + ".png");
10601  expected.save("render_GraphicsEffect_expected" + QTest::currentDataTag() + ".png");
10602 #endif
10603  QCOMPARE(image, expected);
10604 }
10605 
10606 void tst_QWidget::activateWindow()
10607 {
10609  QSKIP("Window activation is not supported.");
10610 
10611  // Test case for QTBUG-26711
10612 
10613  // Create first mainwindow and set it active
10614  QScopedPointer<QMainWindow> mainwindow(new QMainWindow);
10615  mainwindow->setWindowTitle(QLatin1String(QTest::currentTestFunction()));
10616  QLabel* label = new QLabel(mainwindow.data());
10617  label->setMinimumWidth(m_testWidgetSize.width());
10618  mainwindow->setWindowTitle(QStringLiteral("#1 ") + __FUNCTION__);
10619  mainwindow->setCentralWidget(label);
10620  mainwindow->move(m_availableTopLeft + QPoint(100, 100));
10621  mainwindow->setVisible(true);
10622  mainwindow->activateWindow();
10623  QVERIFY(QTest::qWaitForWindowActive(mainwindow.data()));
10624  QVERIFY(mainwindow->isActiveWindow());
10625 
10626  // Create second mainwindow and set it active
10627  QScopedPointer<QMainWindow> mainwindow2(new QMainWindow);
10628  mainwindow2->setWindowTitle(QStringLiteral("#2 ") + __FUNCTION__);
10629  QLabel* label2 = new QLabel(mainwindow2.data());
10630  label2->setMinimumWidth(m_testWidgetSize.width());
10631  mainwindow2->setCentralWidget(label2);
10632  mainwindow2->move(mainwindow->geometry().bottomLeft() + QPoint(0, 50));
10633  mainwindow2->setVisible(true);
10634  mainwindow2->activateWindow();
10636 
10637  QTRY_VERIFY(!mainwindow->isActiveWindow());
10638  QTRY_VERIFY(mainwindow2->isActiveWindow());
10639 
10640  // Revert first mainwindow back to visible active
10641  mainwindow->setVisible(true);
10642  mainwindow->activateWindow();
10644 
10645  QTRY_VERIFY(mainwindow->isActiveWindow());
10646  QTRY_VERIFY(!mainwindow2->isActiveWindow());
10647 }
10648 
10649 void tst_QWidget::openModal_taskQTBUG_5804()
10650 {
10651 #ifdef Q_OS_ANDROID
10652  QSKIP("This test hangs on Android");
10653 #endif
10654  class Widget : public QWidget
10655  {
10656  public:
10658  ~Widget()
10659  {
10660  QMessageBox msgbox;
10661  QTimer::singleShot(10, &msgbox, SLOT(accept()));
10662  msgbox.exec(); //open a modal dialog
10663  }
10664  };
10665 
10667  win->resize(m_testWidgetSize);
10668  win->setWindowTitle(__FUNCTION__);
10669  centerOnScreen(win.data());
10670 
10671  new Widget(win.data());
10672  win->show();
10674 }
10675 
10683 void tst_QWidget::focusProxy()
10684 {
10685  QWidget window;
10686  window.setFocusPolicy(Qt::StrongFocus);
10687  class Container : public QWidget
10688  {
10689  public:
10690  Container()
10691  {
10692  edit = new QLineEdit;
10693  edit->installEventFilter(this);
10694  setFocusProxy(edit);
10695  QHBoxLayout *layout = new QHBoxLayout;
10696  layout->addWidget(edit);
10697  setLayout(layout);
10698  }
10699 
10700  QLineEdit *edit;
10701  int focusInCount = 0;
10702  int focusOutCount = 0;
10703 
10704  protected:
10705  bool eventFilter(QObject *receiver, QEvent *event) override
10706  {
10707  if (receiver == edit) {
10708  switch (event->type()) {
10709  case QEvent::FocusIn:
10710  ++focusInCount;
10711  break;
10712  case QEvent::FocusOut:
10713  ++focusOutCount;
10714  break;
10715  default:
10716  break;
10717  }
10718  }
10719 
10720  return QWidget::eventFilter(receiver, event);
10721  }
10722  };
10723 
10724  auto container1 = new Container;
10725  container1->edit->setObjectName("edit1");
10726  auto container2 = new Container;
10727  container2->edit->setObjectName("edit2");
10728 
10729  QHBoxLayout *layout = new QHBoxLayout;
10730  layout->addWidget(container1);
10731  layout->addWidget(container2);
10732  window.setLayout(layout);
10733 
10734  window.setFocus();
10735  window.show();
10737  QSKIP("Window exposed failed");
10739  window.activateWindow();
10741  QSKIP("Window activation failed");
10742  } else {
10743  if (!QTest::qWaitFor([&]() { return window.windowHandle()->isActive(); }, 5000))
10744  QSKIP("Window activation failed");
10745  }
10746 
10747  // given a widget without focus proxy
10748  QVERIFY(window.hasFocus());
10750  QVERIFY(!container1->hasFocus());
10751  QVERIFY(!container2->hasFocus());
10752  QCOMPARE(container1->focusInCount, 0);
10753  QCOMPARE(container1->focusOutCount, 0);
10754 
10755  // setting a (nested) focus proxy moves focus
10756  window.setFocusProxy(container1);
10757  QCOMPARE(window.focusWidget(), container1->edit);
10758  QCOMPARE(window.focusWidget(), QApplication::focusWidget());
10759  QVERIFY(window.hasFocus()); // and redirects hasFocus correctly
10760  QVERIFY(container1->edit->hasFocus());
10761  QCOMPARE(container1->focusInCount, 1);
10762 
10763  // changing the focus proxy should not move focus
10764  window.setFocusProxy(container2);
10765  QCOMPARE(window.focusWidget(), container1->edit);
10766  QCOMPARE(window.focusWidget(), QApplication::focusWidget());
10767  QVERIFY(!window.hasFocus());
10768  QCOMPARE(container1->focusOutCount, 0);
10769 
10770  // but setting focus again does
10771  window.setFocus();
10772  QCOMPARE(window.focusWidget(), container2->edit);
10773  QCOMPARE(window.focusWidget(), QApplication::focusWidget());
10774  QVERIFY(window.hasFocus());
10775  QVERIFY(!container1->edit->hasFocus());
10776  QVERIFY(container2->edit->hasFocus());
10777  QCOMPARE(container1->focusInCount, 1);
10778  QCOMPARE(container1->focusOutCount, 1);
10779  QCOMPARE(container2->focusInCount, 1);
10780  QCOMPARE(container2->focusOutCount, 0);
10781 
10782  // clearing the focus proxy does not move focus
10783  window.setFocusProxy(nullptr);
10784  QCOMPARE(window.focusWidget(), container2->edit);
10785  QCOMPARE(window.focusWidget(), QApplication::focusWidget());
10786  QVERIFY(!window.hasFocus());
10787  QCOMPARE(container1->focusInCount, 1);
10788  QCOMPARE(container1->focusOutCount, 1);
10789  QCOMPARE(container2->focusInCount, 1);
10790  QCOMPARE(container2->focusOutCount, 0);
10791 
10792  // but clearing focus does
10793  window.focusWidget()->clearFocus();
10794  QCOMPARE(QApplication::focusWidget(), nullptr);
10795  QVERIFY(!window.hasFocus());
10796  QVERIFY(!container2->hasFocus());
10797  QVERIFY(!container2->edit->hasFocus());
10798  QCOMPARE(container2->focusOutCount, 1);
10799 }
10800 
10801 void tst_QWidget::focusProxyAndInputMethods()
10802 {
10804  QSKIP("Window activation is not supported.");
10806  toplevel->setWindowTitle(QLatin1String(QTest::currentTestFunction()));
10807  toplevel->resize(200, 200);
10808  toplevel->setAttribute(Qt::WA_InputMethodEnabled, true);
10809 
10810  QWidget *child = new QWidget(toplevel.data());
10811  child->setFocusProxy(toplevel.data());
10812  child->setAttribute(Qt::WA_InputMethodEnabled, true);
10813 
10814  toplevel->setFocusPolicy(Qt::WheelFocus);
10815  child->setFocusPolicy(Qt::WheelFocus);
10816 
10817  QVERIFY(!child->hasFocus());
10818  QVERIFY(!toplevel->hasFocus());
10819 
10820  toplevel->show();
10821  QVERIFY(QTest::qWaitForWindowExposed(toplevel.data()));
10822  QApplication::setActiveWindow(toplevel.data());
10823  QVERIFY(QTest::qWaitForWindowActive(toplevel.data()));
10824  QVERIFY(toplevel->hasFocus());
10825  QVERIFY(child->hasFocus());
10826  QCOMPARE(qApp->focusObject(), toplevel.data());
10827 }
10828 
10829 #ifdef QT_BUILD_INTERNAL
10830 class scrollWidgetWBS : public QWidget
10831 {
10832 public:
10833  void deleteBackingStore()
10834  {
10835  static_cast<QWidgetPrivate*>(d_ptr.data())->topData()->repaintManager.reset(nullptr);
10836  }
10837  void enableBackingStore()
10838  {
10839  if (!static_cast<QWidgetPrivate*>(d_ptr.data())->maybeRepaintManager()) {
10840  static_cast<QWidgetPrivate*>(d_ptr.data())->topData()->repaintManager.reset(new QWidgetRepaintManager(this));
10841  static_cast<QWidgetPrivate*>(d_ptr.data())->invalidateBackingStore(this->rect());
10842  update();
10843  }
10844  }
10845 };
10846 #endif
10847 
10848 // Test case relies on developer build (AUTOTEST_EXPORT).
10849 #ifdef QT_BUILD_INTERNAL
10850 void tst_QWidget::scrollWithoutBackingStore()
10851 {
10852  scrollWidgetWBS scrollable;
10853  scrollable.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
10854  scrollable.resize(200, 200);
10855  QLabel child(QString("@"),&scrollable);
10856  child.resize(50,50);
10857  scrollable.show();
10858  QVERIFY(QTest::qWaitForWindowExposed(&scrollable));
10859  scrollable.scroll(50,50);
10860  QCOMPARE(child.pos(),QPoint(50,50));
10861  scrollable.deleteBackingStore();
10862  scrollable.scroll(-25,-25);
10863  QCOMPARE(child.pos(),QPoint(25,25));
10864  scrollable.enableBackingStore();
10865  QTRY_COMPARE(child.pos(),QPoint(25,25));
10866 }
10867 #endif
10868 
10869 void tst_QWidget::taskQTBUG_7532_tabOrderWithFocusProxy()
10870 {
10871  QWidget w;
10872  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
10873  w.setFocusPolicy(Qt::TabFocus);
10874  QWidget *fp = new QWidget(&w);
10875  fp->setFocusPolicy(Qt::TabFocus);
10876  w.setFocusProxy(fp);
10878 
10879  // In debug mode, no assertion failure means it's alright.
10880 }
10881 
10882 void tst_QWidget::movedAndResizedAttributes()
10883 {
10884  // Use Qt::Tool as fully decorated windows have a minimum width of 160 on
10885  QWidget w;
10886  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
10887  w.show();
10888 
10889  QVERIFY(!w.testAttribute(Qt::WA_Moved));
10890  QVERIFY(!w.testAttribute(Qt::WA_Resized));
10891 
10892  w.setWindowState(Qt::WindowFullScreen);
10893 
10894  QVERIFY(!w.testAttribute(Qt::WA_Moved));
10895  QVERIFY(!w.testAttribute(Qt::WA_Resized));
10896 
10897  w.setWindowState(Qt::WindowMaximized);
10898 
10899  QVERIFY(!w.testAttribute(Qt::WA_Moved));
10900  QVERIFY(!w.testAttribute(Qt::WA_Resized));
10901 
10902  w.setWindowState(Qt::WindowMinimized);
10903 
10904  QVERIFY(!w.testAttribute(Qt::WA_Moved));
10905  QVERIFY(!w.testAttribute(Qt::WA_Resized));
10906 
10907  w.showNormal();
10908 
10909  QVERIFY(!w.testAttribute(Qt::WA_Moved));
10910  QVERIFY(!w.testAttribute(Qt::WA_Resized));
10911 
10912  w.showMaximized();
10913 
10914  QVERIFY(!w.testAttribute(Qt::WA_Moved));
10915  QVERIFY(!w.testAttribute(Qt::WA_Resized));
10916 
10917  w.showFullScreen();
10918 
10919  QVERIFY(!w.testAttribute(Qt::WA_Moved));
10920  QVERIFY(!w.testAttribute(Qt::WA_Resized));
10921 
10922  w.showNormal();
10923  w.move(m_availableTopLeft);
10924  QVERIFY(w.testAttribute(Qt::WA_Moved));
10925  QVERIFY(!w.testAttribute(Qt::WA_Resized));
10926 
10927  w.resize(m_testWidgetSize);
10928  QVERIFY(w.testAttribute(Qt::WA_Moved));
10929  QVERIFY(w.testAttribute(Qt::WA_Resized));
10930 }
10931 
10932 void tst_QWidget::childAt()
10933 {
10935  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
10936  parent.resize(200, 200);
10937 
10938  QWidget *child = new QWidget(&parent);
10939  child->setPalette(Qt::red);
10940  child->setAutoFillBackground(true);
10941  child->setGeometry(20, 20, 160, 160);
10942 
10943  QWidget *grandChild = new QWidget(child);
10944  grandChild->setPalette(Qt::blue);
10945  grandChild->setAutoFillBackground(true);
10946  grandChild->setGeometry(-20, -20, 220, 220);
10947 
10948  QVERIFY(!parent.childAt(19, 19));
10949  QVERIFY(!parent.childAt(180, 180));
10950  QCOMPARE(parent.childAt(20, 20), grandChild);
10951  QCOMPARE(parent.childAt(179, 179), grandChild);
10952 
10953  grandChild->setAttribute(Qt::WA_TransparentForMouseEvents);
10954  QCOMPARE(parent.childAt(20, 20), child);
10955  QCOMPARE(parent.childAt(179, 179), child);
10956  grandChild->setAttribute(Qt::WA_TransparentForMouseEvents, false);
10957 
10958  child->setMask(QRect(50, 50, 60, 60));
10959 
10960  QVERIFY(!parent.childAt(69, 69));
10961  QVERIFY(!parent.childAt(130, 130));
10962  QCOMPARE(parent.childAt(70, 70), grandChild);
10963  QCOMPARE(parent.childAt(129, 129), grandChild);
10964 
10965  child->setAttribute(Qt::WA_MouseNoMask);
10966  QCOMPARE(parent.childAt(69, 69), grandChild);
10967  QCOMPARE(parent.childAt(130, 130), grandChild);
10968  child->setAttribute(Qt::WA_MouseNoMask, false);
10969 
10970  grandChild->setAttribute(Qt::WA_TransparentForMouseEvents);
10971  QCOMPARE(parent.childAt(70, 70), child);
10972  QCOMPARE(parent.childAt(129, 129), child);
10973  grandChild->setAttribute(Qt::WA_TransparentForMouseEvents, false);
10974 
10975  grandChild->setMask(QRect(80, 80, 40, 40));
10976 
10977  QCOMPARE(parent.childAt(79, 79), child);
10978  QCOMPARE(parent.childAt(120, 120), child);
10979  QCOMPARE(parent.childAt(80, 80), grandChild);
10980  QCOMPARE(parent.childAt(119, 119), grandChild);
10981 
10982  grandChild->setAttribute(Qt::WA_MouseNoMask);
10983 
10984  QCOMPARE(parent.childAt(79, 79), grandChild);
10985  QCOMPARE(parent.childAt(120, 120), grandChild);
10986 }
10987 
10988 #ifdef Q_OS_MACOS
10989 
10990 void tst_QWidget::taskQTBUG_11373()
10991 {
10992  QSKIP("QTBUG-52974");
10993 
10995  QWidget * center = new QWidget();
10996  myWindow -> setCentralWidget(center);
10997  QWidget * drawer = new QWidget(myWindow.data(), Qt::Drawer);
10998  drawer -> hide();
10999  QCOMPARE(drawer->isVisible(), false);
11000  myWindow -> show();
11001  myWindow -> raise();
11002  // The drawer shouldn't be visible now.
11003  QCOMPARE(drawer->isVisible(), false);
11006  // The drawer should still not be visible, since we haven't shown it.
11007  QCOMPARE(drawer->isVisible(), false);
11008 }
11009 
11010 #endif
11011 
11012 void tst_QWidget::taskQTBUG_17333_ResizeInfiniteRecursion()
11013 {
11014  QTableView tb;
11015  tb.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
11016  const char *s = "border: 1px solid;";
11017  tb.setStyleSheet(s);
11018  tb.show();
11019 
11021  tb.setGeometry(QRect(100, 100, 0, 100));
11022  // No crash, it works.
11023 }
11024 
11025 void tst_QWidget::nativeChildFocus()
11026 {
11028  QSKIP("Wayland: This fails. Figure out why.");
11029 
11030  QWidget w;
11031  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
11032  w.setMinimumWidth(m_testWidgetSize.width());
11033  w.setWindowTitle(__FUNCTION__);
11034  QLayout *layout = new QVBoxLayout;
11035  w.setLayout(layout);
11036  QLineEdit *p1 = new QLineEdit;
11037  QLineEdit *p2 = new QLineEdit;
11038  layout->addWidget(p1);
11039  layout->addWidget(p2);
11040  p1->setObjectName("p1");
11041  p2->setObjectName("p2");
11042  centerOnScreen(&w);
11043  w.show();
11044  w.activateWindow();
11045  p1->setFocus();
11046  p1->setAttribute(Qt::WA_NativeWindow);
11047  p2->setAttribute(Qt::WA_NativeWindow);
11049 
11051  QCOMPARE(QApplication::focusWidget(), static_cast<QWidget*>(p1));
11052 }
11053 
11054 static bool lenientCompare(const QPixmap &actual, const QPixmap &expected)
11055 {
11056  QImage expectedImage = expected.toImage().convertToFormat(QImage::Format_RGB32);
11057  QImage actualImage = actual.toImage().convertToFormat(QImage::Format_RGB32);
11058 
11059  if (expectedImage.size() != actualImage.size()) {
11060  qWarning("Image size comparison failed: expected: %dx%d, got %dx%d",
11061  expectedImage.size().width(), expectedImage.size().height(),
11062  actualImage.size().width(), actualImage.size().height());
11063  return false;
11064  }
11065 
11066  const int size = actual.width() * actual.height();
11067  const int threshold = QPixmap::defaultDepth() == 16 ? 10 : 2;
11068 
11069  auto a = reinterpret_cast<const QRgb *>(actualImage.bits());
11070  auto e = reinterpret_cast<const QRgb *>(expectedImage.bits());
11071  for (int i = 0; i < size; ++i) {
11072  const QColor ca(a[i]);
11073  const QColor ce(e[i]);
11074  if (qAbs(ca.red() - ce.red()) > threshold
11075  || qAbs(ca.green() - ce.green()) > threshold
11076  || qAbs(ca.blue() - ce.blue()) > threshold) {
11077  qWarning("Color mismatch at pixel #%d: Expected: %d,%d,%d, got %d,%d,%d",
11078  i, ce.red(), ce.green(), ce.blue(), ca.red(), ca.green(), ca.blue());
11079  return false;
11080  }
11081  }
11082 
11083  return true;
11084 }
11085 
11086 void tst_QWidget::grab()
11087 {
11088  for (int opaque = 0; opaque < 2; ++opaque) {
11089  QWidget widget;
11091  QImage image(128, 128, opaque ? QImage::Format_RGB32 : QImage::Format_ARGB32_Premultiplied);
11092  for (int row = 0; row < image.height(); ++row) {
11093  QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(row));
11094  for (int col = 0; col < image.width(); ++col)
11095  line[col] = qRgba(QRandomGenerator::global()->bounded(255), row, col, opaque ? 255 : 127);
11096  }
11097 
11098  QPalette pal = widget.palette();
11099  pal.setBrush(QPalette::Window, QBrush(image));
11100  widget.setPalette(pal);
11101  widget.resize(128, 128);
11102 
11103  QPixmap expected(64, 64);
11104  if (!opaque)
11105  expected.fill(Qt::transparent);
11106 
11107  QPainter p(&expected);
11108  p.translate(-64, -64);
11109  p.drawTiledPixmap(0, 0, 128, 128, pal.brush(QPalette::Window).texture(), 0, 0);
11110  p.end();
11111 
11112  QPixmap actual = grabFromWidget(&widget, QRect(64, 64, 64, 64));
11113  QVERIFY(lenientCompare(actual, expected));
11114 
11115  actual = grabFromWidget(&widget, QRect(64, 64, -1, -1));
11116  QVERIFY(lenientCompare(actual, expected));
11117 
11118  // Make sure a widget that is not yet shown is grabbed correctly.
11119  QTreeWidget widget2;
11120  actual = widget2.grab(QRect());
11121  widget2.show();
11122  expected = widget2.grab(QRect());
11123 
11124  QVERIFY(lenientCompare(actual, expected));
11125  }
11126 }
11127 
11128 /* grabMouse() tests whether mouse grab for a widget without window handle works.
11129  * It creates a top level widget with another nested widget inside. The inner widget grabs
11130  * the mouse and a series of mouse presses moving over the top level's window is simulated.
11131  * Only the inner widget should receive events. */
11132 
11133 static inline QString mouseEventLogEntry(const QString &objectName, QEvent::Type t, const QPoint &p, Qt::MouseButtons b)
11134 {
11135  QString result;
11136  QDebug(&result).nospace() << objectName << " Mouse event " << t << " at " << p << " buttons " << b;
11137  return result;
11138 }
11139 
11140 class GrabLoggerWidget : public QWidget
11141 {
11142 public:
11143  explicit GrabLoggerWidget(QStringList *log, QWidget *parent = nullptr) : QWidget(parent), m_log(log) {}
11144 
11145 protected:
11146  bool event(QEvent *e) override
11147  {
11148  switch (e->type()) {
11150  case QEvent::MouseMove:
11152  QMouseEvent *me = static_cast<QMouseEvent *>(e);
11153  m_log->push_back(mouseEventLogEntry(objectName(), me->type(), me->position().toPoint(), me->buttons()));
11154  me->accept();
11155  return true;
11156  }
11157  default:
11158  break;
11159  }
11160  return QWidget::event(e);
11161  }
11162 private:
11163  QStringList *m_log;
11164 };
11165 
11166 void tst_QWidget::grabMouse()
11167 {
11169  QSKIP("Wayland: This fails. Figure out why.");
11170 
11171  QStringList log;
11172  GrabLoggerWidget w(&log);
11173  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
11174  w.setObjectName(QLatin1String("tst_qwidget_grabMouse"));
11175  w.setWindowTitle(w.objectName());
11176  QLayout *layout = new QVBoxLayout(&w);
11177  layout->setContentsMargins(50, 50, 50, 50);
11178  GrabLoggerWidget *grabber = new GrabLoggerWidget(&log, &w);
11179  const QString grabberObjectName = QLatin1String("tst_qwidget_grabMouse_grabber");
11180  grabber->setObjectName(grabberObjectName);
11181  grabber->setMinimumSize(m_testWidgetSize);
11182  layout->addWidget(grabber);
11183  centerOnScreen(&w);
11184  w.show();
11187 
11188  QStringList expectedLog;
11189  QPoint mousePos = QPoint(w.width() / 2, 10);
11190  QTest::mouseMove(w.windowHandle(), mousePos);
11191  grabber->grabMouse();
11192  const int step = w.height() / 5;
11193  for ( ; mousePos.y() < w.height() ; mousePos.ry() += step) {
11194  QTest::mouseClick(w.windowHandle(), Qt::LeftButton, Qt::KeyboardModifiers(), mousePos);
11195  // Events should go to the grabber child using its coordinates.
11196  const QPoint expectedPos = grabber->mapFromParent(mousePos);
11197  expectedLog.push_back(mouseEventLogEntry(grabberObjectName, QEvent::MouseButtonPress, expectedPos, Qt::LeftButton));
11198  expectedLog.push_back(mouseEventLogEntry(grabberObjectName, QEvent::MouseButtonRelease, expectedPos, Qt::NoButton));
11199  }
11200  grabber->releaseMouse();
11201  QCOMPARE(log, expectedLog);
11202 }
11203 
11204 void tst_QWidget::grabKeyboard()
11205 {
11207  QSKIP("Wayland: This fails. Figure out why.");
11208 
11209  QWidget w;
11210  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
11211  w.setObjectName(QLatin1String("tst_qwidget_grabKeyboard"));
11212  w.setWindowTitle(w.objectName());
11213  QLayout *layout = new QVBoxLayout(&w);
11214  QLineEdit *grabber = new QLineEdit(&w);
11215  grabber->setMinimumWidth(m_testWidgetSize.width());
11216  layout->addWidget(grabber);
11217  QLineEdit *nonGrabber = new QLineEdit(&w);
11218  nonGrabber->setMinimumWidth(m_testWidgetSize.width());
11219  layout->addWidget(nonGrabber);
11220  centerOnScreen(&w);
11221  w.show();
11224  nonGrabber->setFocus();
11225  grabber->grabKeyboard();
11226  QTest::keyClick(w.windowHandle(), Qt::Key_A);
11227  grabber->releaseKeyboard();
11228  QCOMPARE(grabber->text().toLower(), QStringLiteral("a"));
11229  QVERIFY2(nonGrabber->text().isEmpty(), qPrintable(nonGrabber->text()));
11230 }
11231 
11232 class TouchMouseWidget : public QWidget {
11233 public:
11234  explicit TouchMouseWidget(QWidget *parent = nullptr) : QWidget(parent)
11235  {
11236  resize(200, 200);
11237  }
11238 
11239  void setAcceptTouch(bool accept)
11240  {
11241  m_acceptTouch = accept;
11243  }
11244 
11245  void setAcceptMouse(bool accept)
11246  {
11247  m_acceptMouse = accept;
11248  }
11249 
11250 protected:
11251  bool event(QEvent *e) override
11252  {
11253  qCDebug(lcTests) << e;
11254  switch (e->type()) {
11255  case QEvent::TouchBegin:
11256  case QEvent::TouchCancel:
11257  case QEvent::TouchUpdate:
11258  case QEvent::TouchEnd: {
11259  auto te = static_cast<QTouchEvent *>(e);
11260  touchDevice = const_cast<QPointingDevice *>(te->pointingDevice());
11261  touchPointStates = te->touchPointStates();
11262  touchPoints = te->points();
11263  if (e->type() == QEvent::TouchBegin)
11265  else if (e->type() == QEvent::TouchCancel)
11267  else if (e->type() == QEvent::TouchUpdate)
11269  else if (e->type() == QEvent::TouchEnd)
11270  ++m_touchEndCount;
11272  if (m_acceptTouch)
11273  e->accept();
11274  else
11275  e->ignore();
11276  }
11277  return true;
11278  case QEvent::Gesture:
11280  return true;
11281 
11283  case QEvent::MouseMove:
11286  m_lastMouseEventPos = static_cast<QMouseEvent *>(e)->position();
11287  if (m_acceptMouse)
11288  e->accept();
11289  else
11290  e->ignore();
11291  return true;
11292 
11293  default:
11294  return QWidget::event(e);
11295  }
11296  }
11297 
11298 public:
11308  bool m_acceptTouch = false;
11310  bool m_acceptMouse = true;
11312 };
11313 
11314 void tst_QWidget::touchEventSynthesizedMouseEvent()
11315 {
11316  {
11317  // Simple case, we ignore the touch events, we get mouse events instead
11320  widget.show();
11322  QCOMPARE(widget.m_touchEventCount, 0);
11323  QCOMPARE(widget.m_mouseEventCount, 0);
11324 
11325  QTest::touchEvent(&widget, m_touchScreen).press(0, QPoint(10, 10), &widget);
11326  QCOMPARE(widget.m_touchEventCount, 0);
11327  QCOMPARE(widget.m_mouseEventCount, 1);
11328  QCOMPARE(widget.m_lastMouseEventPos, QPointF(10, 10));
11329  QTest::touchEvent(&widget, m_touchScreen).move(0, QPoint(15, 15), &widget);
11330  QCOMPARE(widget.m_touchEventCount, 0);
11331  QCOMPARE(widget.m_mouseEventCount, 2);
11332  QCOMPARE(widget.m_lastMouseEventPos, QPointF(15, 15));
11333  QTest::touchEvent(&widget, m_touchScreen).release(0, QPoint(20, 20), &widget);
11334  QCOMPARE(widget.m_touchEventCount, 0);
11335  QCOMPARE(widget.m_mouseEventCount, 4); // we receive extra mouse move event
11336  QCOMPARE(widget.m_lastMouseEventPos, QPointF(20, 20));
11337  }
11338 
11339  {
11340  // We accept the touch events, no mouse event is generated
11343  widget.setAcceptTouch(true);
11344  widget.show();
11346  QCOMPARE(widget.m_touchEventCount, 0);
11347  QCOMPARE(widget.m_mouseEventCount, 0);
11348 
11349  QTest::touchEvent(&widget, m_touchScreen).press(0, QPoint(10, 10), &widget);
11350  QCOMPARE(widget.m_touchEventCount, 1);
11351  QCOMPARE(widget.m_mouseEventCount, 0);
11352  QTest::touchEvent(&widget, m_touchScreen).move(0, QPoint(15, 15), &widget);
11353  QCOMPARE(widget.m_touchEventCount, 2);
11354  QCOMPARE(widget.m_mouseEventCount, 0);
11355  QTest::touchEvent(&widget, m_touchScreen).release(0, QPoint(20, 20), &widget);
11356  QCOMPARE(widget.m_touchEventCount, 3);
11357  QCOMPARE(widget.m_mouseEventCount, 0);
11358  }
11359 
11360  {
11361  // Parent accepts touch events, child ignore both mouse and touch
11362  // We should see propagation of the TouchBegin
11364  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
11365  parent.setAcceptTouch(true);
11367  child.move(5, 5);
11368  child.setAcceptMouse(false);
11369  parent.show();
11370  QVERIFY(QTest::qWaitForWindowExposed(parent.windowHandle()));
11371  QCOMPARE(parent.m_touchEventCount, 0);
11372  QCOMPARE(parent.m_mouseEventCount, 0);
11373  QCOMPARE(child.m_touchEventCount, 0);
11374  QCOMPARE(child.m_mouseEventCount, 0);
11375 
11376  QTest::touchEvent(parent.window(), m_touchScreen).press(0, QPoint(10, 10), &child);
11377  QCOMPARE(parent.m_touchEventCount, 1);
11378  QCOMPARE(parent.m_mouseEventCount, 0);
11379  QCOMPARE(child.m_touchEventCount, 0);
11380  QCOMPARE(child.m_mouseEventCount, 0);
11381  }
11382 
11383  {
11384  // Parent accepts mouse events, child ignore both mouse and touch
11385  // We should see propagation of the TouchBegin into a MouseButtonPress
11387  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
11389  const QPoint childPos(5, 5);
11390  child.move(childPos);
11391  child.setAcceptMouse(false);
11392  parent.show();
11393  QVERIFY(QTest::qWaitForWindowExposed(parent.windowHandle()));
11394  QCOMPARE(parent.m_touchEventCount, 0);
11395  QCOMPARE(parent.m_mouseEventCount, 0);
11396  QCOMPARE(child.m_touchEventCount, 0);
11397  QCOMPARE(child.m_mouseEventCount, 0);
11398 
11399  const QPoint touchPos(20, 20);
11400  QTest::touchEvent(parent.window(), m_touchScreen).press(0, touchPos, &child);
11401  QCOMPARE(parent.m_touchEventCount, 0);
11402  QCOMPARE(parent.m_mouseEventCount, 1);
11403  QCOMPARE(parent.m_lastMouseEventPos, childPos + touchPos);
11404  QCOMPARE(child.m_touchEventCount, 0);
11405  QCOMPARE(child.m_mouseEventCount, 1); // Attempt at mouse event before propagation
11406  QCOMPARE(child.m_lastMouseEventPos, touchPos);
11407  }
11408 }
11409 
11410 void tst_QWidget::touchCancel()
11411 {
11414  widget.setAcceptTouch(true);
11415  widget.show();
11417 
11418  { // cancel right after press
11419  QTest::touchEvent(&widget, m_touchScreen).press(1, QPoint(20, 21), &widget);
11420  QCOMPARE(widget.m_touchBeginCount, 1);
11421  QCOMPARE(widget.touchDevice, m_touchScreen);
11422  QCOMPARE(widget.touchPoints.size(), 1);
11423  QCOMPARE(widget.touchPointStates, Qt::TouchPointPressed);
11424  QCOMPARE(widget.touchPoints.first().position(), QPointF(20, 21));
11425 
11427  QTRY_COMPARE(widget.m_touchCancelCount, 1);
11428  QCOMPARE(widget.touchDevice, m_touchScreen);
11429  QCOMPARE(widget.touchPoints.size(), 0);
11430 
11431  // should not propagate, since after cancel there should be only new press
11432  QTest::touchEvent(&widget, m_touchScreen).move(1, QPoint(25, 26), &widget);
11433  QCOMPARE(widget.m_touchUpdateCount, 0);
11434  }
11435 
11436  { // cancel after update
11437  QTest::touchEvent(&widget, m_touchScreen).press(1, QPoint(30, 31), &widget);
11438  QCOMPARE(widget.m_touchBeginCount, 2);
11439  QCOMPARE(widget.touchPoints.size(), 1);
11440  QCOMPARE(widget.touchPointStates, Qt::TouchPointPressed);
11441  QCOMPARE(widget.touchPoints.first().position(), QPointF(30, 31));
11442 
11443  QTest::touchEvent(&widget, m_touchScreen).move(1, QPoint(20, 21));
11444  QCOMPARE(widget.m_touchUpdateCount, 1);
11445  QCOMPARE(widget.touchPoints.size(), 1);
11446  QCOMPARE(widget.touchPointStates, Qt::TouchPointMoved);
11447  QCOMPARE(widget.touchPoints.first().position(), QPointF(20, 21));
11448 
11450  QTRY_COMPARE(widget.m_touchCancelCount, 2);
11451  QCOMPARE(widget.touchDevice, m_touchScreen);
11452  QCOMPARE(widget.touchPoints.size(), 0);
11453 
11454  // should not propagate, since after cancel there should be only new press
11455  QTest::touchEvent(&widget, m_touchScreen).move(1, QPoint(25, 26), &widget);
11456  QCOMPARE(widget.m_touchUpdateCount, 1);
11457  }
11458 
11459  { // proper press/release after multiple cancel events should proceed as usual
11460  QTest::touchEvent(&widget, m_touchScreen).press(2, QPoint(15, 16), &widget).press(3, QPoint(25, 26), &widget);
11461  QCOMPARE(widget.m_touchBeginCount, 3);
11462  QCOMPARE(widget.touchDevice, m_touchScreen);
11463  QCOMPARE(widget.touchPoints.size(), 2);
11464  QCOMPARE(widget.touchPointStates, Qt::TouchPointPressed);
11465 
11466  QTest::touchEvent(&widget, m_touchScreen).release(3, QPoint(30, 30), &widget).release(2, QPoint(10, 10), &widget);
11467  QCOMPARE(widget.m_touchEndCount, 1);
11468  QCOMPARE(widget.touchDevice, m_touchScreen);
11469  QCOMPARE(widget.touchPoints.size(), 2);
11470  QCOMPARE(widget.touchPointStates, Qt::TouchPointReleased);
11471  }
11472 }
11473 
11474 void tst_QWidget::touchUpdateOnNewTouch()
11475 {
11478  widget.setAcceptTouch(true);
11479  QVBoxLayout *layout = new QVBoxLayout;
11480  layout->addWidget(new QWidget);
11482  widget.show();
11483 
11486  QCOMPARE(widget.m_touchBeginCount, 0);
11487  QCOMPARE(widget.m_touchUpdateCount, 0);
11488  QCOMPARE(widget.m_touchEndCount, 0);
11489  QTest::touchEvent(window, m_touchScreen).press(0, QPoint(20, 20), window);
11490  QCOMPARE(widget.m_touchBeginCount, 1);
11491  QCOMPARE(widget.m_touchUpdateCount, 0);
11492  QCOMPARE(widget.m_touchEndCount, 0);
11493  QTest::touchEvent(window, m_touchScreen).move(0, QPoint(25, 25), window);
11494  QCOMPARE(widget.m_touchBeginCount, 1);
11495  QCOMPARE(widget.m_touchUpdateCount, 1);
11496  QCOMPARE(widget.m_touchEndCount, 0);
11497  QTest::touchEvent(window, m_touchScreen).stationary(0).press(1, QPoint(40, 40), window);
11498  QCOMPARE(widget.m_touchBeginCount, 1);
11499  QCOMPARE(widget.m_touchUpdateCount, 2);
11500  QCOMPARE(widget.m_touchEndCount, 0);
11501  QTest::touchEvent(window, m_touchScreen).stationary(1).release(0, QPoint(25, 25), window);
11502  QCOMPARE(widget.m_touchBeginCount, 1);
11503  QCOMPARE(widget.m_touchUpdateCount, 3);
11504  QCOMPARE(widget.m_touchEndCount, 0);
11505  QTest::touchEvent(window, m_touchScreen).release(1, QPoint(40, 40), window);
11506  QCOMPARE(widget.m_touchBeginCount, 1);
11507  QCOMPARE(widget.m_touchUpdateCount, 3);
11508  QCOMPARE(widget.m_touchEndCount, 1);
11509 }
11510 
11511 void tst_QWidget::touchEventsForGesturePendingWidgets()
11512 {
11514  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
11516  parent.grabGesture(Qt::TapAndHoldGesture);
11517  parent.show();
11518 
11519  QWindow* window = parent.windowHandle();
11521  QTest::qWait(500); // needed for QApplication::topLevelAt(), which is used by QGestureManager
11522  QCOMPARE(child.m_touchEventCount, 0);
11523  QCOMPARE(child.m_gestureEventCount, 0);
11524  QCOMPARE(parent.m_touchEventCount, 0);
11525  QCOMPARE(parent.m_gestureEventCount, 0);
11526  QTest::touchEvent(window, m_touchScreen).press(0, QPoint(20, 20), window);
11527  QCOMPARE(child.m_touchEventCount, 0);
11528  QCOMPARE(child.m_gestureEventCount, 0);
11529  QCOMPARE(parent.m_touchBeginCount, 1); // QTapAndHoldGestureRecognizer::create() sets Qt::WA_AcceptTouchEvents
11530  QCOMPARE(parent.m_touchUpdateCount, 0);
11531  QCOMPARE(parent.m_touchEndCount, 0);
11532  QCOMPARE(parent.m_gestureEventCount, 0);
11533  QTest::touchEvent(window, m_touchScreen).move(0, QPoint(25, 25), window);
11534  QCOMPARE(child.m_touchEventCount, 0);
11535  QCOMPARE(child.m_gestureEventCount, 0);
11536  QCOMPARE(parent.m_touchBeginCount, 1);
11537  QCOMPARE(parent.m_touchUpdateCount, 0);
11538  QCOMPARE(parent.m_touchEndCount, 0);
11539  QCOMPARE(parent.m_gestureEventCount, 0);
11540  QTest::qWait(1000);
11541  QTest::touchEvent(window, m_touchScreen).release(0, QPoint(25, 25), window);
11542  QCOMPARE(child.m_touchEventCount, 0);
11543  QCOMPARE(child.m_gestureEventCount, 0);
11544  QCOMPARE(parent.m_touchBeginCount, 1);
11545  QCOMPARE(parent.m_touchUpdateCount, 0);
11546  QCOMPARE(parent.m_touchEndCount, 0);
11547  QVERIFY(parent.m_gestureEventCount > 0);
11548 }
11549 
11550 void tst_QWidget::styleSheetPropagation()
11551 {
11552  QTableView tw;
11553  tw.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
11554  tw.setStyleSheet("background-color: red;");
11555  for (QObject *child : tw.children()) {
11557  QCOMPARE(w->style(), tw.style());
11558  }
11559 }
11560 
11561 class DestroyTester : public QObject
11562 {
11563  Q_OBJECT
11564 public:
11565  explicit DestroyTester(QObject *parent = nullptr) : QObject(parent) { parentDestroyed = 0; }
11566  static int parentDestroyed;
11567 public slots:
11569  ++parentDestroyed;
11570  }
11571 };
11572 
11574 
11575 void tst_QWidget::destroyedSignal()
11576 {
11577  {
11578  QWidget *w = new QWidget;
11579  DestroyTester *t = new DestroyTester(w);
11582  delete w;
11584  }
11585 
11586  {
11587  QWidget *w = new QWidget;
11588  DestroyTester *t = new DestroyTester(w);
11590  w->blockSignals(true);
11592  delete w;
11594  }
11595 
11596  {
11597  QObject *o = new QWidget;
11598  DestroyTester *t = new DestroyTester(o);
11601  delete o;
11603  }
11604 
11605  {
11606  QObject *o = new QWidget;
11607  auto t = new DestroyTester;
11609  o->blockSignals(true);
11611  delete o;
11613  }
11614 
11615  {
11616  QWidget *w = new QWidget;
11617  auto t = new DestroyTester;
11620  delete w;
11622  delete t;
11623  }
11624 
11625  {
11626  QWidget *w = new QWidget;
11627  auto t = new DestroyTester;
11629  w->blockSignals(true);
11631  delete w;
11633  delete t;
11634  }
11635 
11636  {
11637  QObject *o = new QWidget;
11638  auto t = new DestroyTester;
11641  delete o;
11643  delete t;
11644  }
11645 
11646  {
11647  QObject *o = new QWidget;
11648  auto t = new DestroyTester;
11650  o->blockSignals(true);
11652  delete o;
11654  delete t;
11655  }
11656 
11657 }
11658 
11659 #ifndef QT_NO_CURSOR
11660 void tst_QWidget::underMouse()
11661 {
11662  // Move the mouse cursor to a safe location
11663  QCursor::setPos(m_safeCursorPos);
11664 
11665  ColorWidget topLevelWidget(nullptr, Qt::FramelessWindowHint, Qt::blue);
11666  topLevelWidget.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
11667  ColorWidget childWidget1(&topLevelWidget, Qt::Widget, Qt::yellow);
11668  ColorWidget childWidget2(&topLevelWidget, Qt::Widget, Qt::black);
11669  ColorWidget popupWidget(nullptr, Qt::Popup, Qt::green);
11670 
11671  topLevelWidget.setObjectName("topLevelWidget");
11672  childWidget1.setObjectName("childWidget1");
11673  childWidget2.setObjectName("childWidget2");
11674  popupWidget.setObjectName("popupWidget");
11675 
11676  topLevelWidget.setGeometry(100, 100, 300, 300);
11677  childWidget1.setGeometry(20, 20, 100, 100);
11678  childWidget2.setGeometry(20, 120, 100, 100);
11679  popupWidget.setGeometry(50, 100, 50, 50);
11680 
11681  topLevelWidget.show();
11682  QVERIFY(QTest::qWaitForWindowExposed(&topLevelWidget));
11683  QWindow *window = topLevelWidget.windowHandle();
11684 
11685  QPoint outsideWindowPoint(30, -10);
11686  QPoint inWindowPoint(30, 10);
11687  QPoint child1Point(30, 50);
11688  QPoint child2PointA(30, 150);
11689  QPoint child2PointB(31, 151);
11690 
11691  // Outside window
11692  QTest::mouseMove(window, outsideWindowPoint);
11693  QVERIFY(!topLevelWidget.underMouse());
11694  QVERIFY(!childWidget1.underMouse());
11695  QVERIFY(!childWidget2.underMouse());
11696 
11697  // Enter window, outside children
11698  // Note: QTest::mouseMove will not generate enter events for windows, so send one explicitly
11699  QWindowSystemInterface::handleEnterEvent(window, inWindowPoint, window->mapToGlobal(inWindowPoint));
11700  QTest::mouseMove(window, inWindowPoint);
11701  QVERIFY(topLevelWidget.underMouse());
11702  QVERIFY(!childWidget1.underMouse());
11703  QVERIFY(!childWidget2.underMouse());
11704 
11705  // In childWidget1
11706  QTest::mouseMove(window, child1Point);
11707  QVERIFY(topLevelWidget.underMouse());
11708  QVERIFY(childWidget1.underMouse());
11709  QVERIFY(!childWidget2.underMouse());
11710 
11711  // In childWidget2
11712  QTest::mouseMove(window, child2PointA);
11713  QVERIFY(topLevelWidget.underMouse());
11714  QVERIFY(!childWidget1.underMouse());
11715  QVERIFY(childWidget2.underMouse());
11716 
11717  topLevelWidget.resetCounts();
11718  childWidget1.resetCounts();
11719  childWidget2.resetCounts();
11720  popupWidget.resetCounts();
11721 
11722  // Throw up a popup window
11723  popupWidget.show();
11724  QVERIFY(QTest::qWaitForWindowExposed(&popupWidget));
11725  QWindow *popupWindow = popupWidget.windowHandle();
11726  QVERIFY(popupWindow);
11727  QCOMPARE(QApplication::activePopupWidget(), &popupWidget);
11728 
11729  // Send an artificial leave event for window, as it won't get generated automatically
11730  // due to cursor not actually being over the window. The Cocoa and offscreen plugins
11731  // do this for us.
11732  if (QGuiApplication::platformName() != "cocoa" && QGuiApplication::platformName() != "offscreen")
11733  QWindowSystemInterface::handleLeaveEvent<QWindowSystemInterface::SynchronousDelivery>(window);
11734 
11735  // If there is an active popup, undermouse should not be reported (QTBUG-27478),
11736  // but opening a popup causes leave for widgets under mouse.
11737  QVERIFY(!topLevelWidget.underMouse());
11738  QVERIFY(!childWidget1.underMouse());
11739  QVERIFY(!childWidget2.underMouse());
11740  QVERIFY(!popupWidget.underMouse());
11741  QCOMPARE(popupWidget.enters, 0);
11742  QCOMPARE(popupWidget.leaves, 0);
11743  QCOMPARE(topLevelWidget.enters, 0);
11744  QCOMPARE(topLevelWidget.leaves, 1);
11745  QCOMPARE(childWidget1.enters, 0);
11746  QCOMPARE(childWidget1.leaves, 0);
11747  QCOMPARE(childWidget2.enters, 0);
11748  QCOMPARE(childWidget2.leaves, 1);
11749  topLevelWidget.resetCounts();
11750  childWidget2.resetCounts();
11751 
11752  // Moving around while popup active should not change undermouse or cause
11753  // enter and leave events for widgets.
11754  QTest::mouseMove(popupWindow, popupWindow->mapFromGlobal(window->mapToGlobal(child2PointB)));
11755  QVERIFY(!topLevelWidget.underMouse());
11756  QVERIFY(!childWidget1.underMouse());
11757  QVERIFY(!childWidget2.underMouse());
11758  QVERIFY(!popupWidget.underMouse());
11759  QCOMPARE(popupWidget.enters, 0);
11760  QCOMPARE(popupWidget.leaves, 0);
11761  QCOMPARE(topLevelWidget.enters, 0);
11762  QCOMPARE(topLevelWidget.leaves, 0);
11763  QCOMPARE(childWidget1.enters, 0);
11764  QCOMPARE(childWidget1.leaves, 0);
11765  QCOMPARE(childWidget2.enters, 0);
11766  QCOMPARE(childWidget2.leaves, 0);
11767 
11768  QTest::mouseMove(popupWindow, popupWindow->mapFromGlobal(window->mapToGlobal(inWindowPoint)));
11769  QVERIFY(!topLevelWidget.underMouse());
11770  QVERIFY(!childWidget1.underMouse());
11771  QVERIFY(!childWidget2.underMouse());
11772  QVERIFY(!popupWidget.underMouse());
11773  QCOMPARE(popupWidget.enters, 0);
11774  QCOMPARE(popupWidget.leaves, 0);
11775  QCOMPARE(topLevelWidget.enters, 0);
11776  QCOMPARE(topLevelWidget.leaves, 0);
11777  QCOMPARE(childWidget1.enters, 0);
11778  QCOMPARE(childWidget1.leaves, 0);
11779  QCOMPARE(childWidget2.enters, 0);
11780  QCOMPARE(childWidget2.leaves, 0);
11781 
11782  QTest::mouseMove(popupWindow, popupWindow->mapFromGlobal(window->mapToGlobal(child1Point)));
11783  QVERIFY(!topLevelWidget.underMouse());
11784  QVERIFY(!childWidget1.underMouse());
11785  QVERIFY(!childWidget2.underMouse());
11786  QVERIFY(!popupWidget.underMouse());
11787  QCOMPARE(popupWidget.enters, 0);
11788  QCOMPARE(popupWidget.leaves, 0);
11789  QCOMPARE(topLevelWidget.enters, 0);
11790  QCOMPARE(topLevelWidget.leaves, 0);
11791  QCOMPARE(childWidget1.enters, 0);
11792  QCOMPARE(childWidget1.leaves, 0);
11793  QCOMPARE(childWidget2.enters, 0);
11794  QCOMPARE(childWidget2.leaves, 0);
11795 
11796  // Note: Mouse moving off-application while there is an active popup cannot be simulated
11797  // without actually moving the cursor so it is not tested.
11798 
11799  // Mouse enters popup, should cause enter to popup.
11800  // Once again, need to create artificial enter event.
11801  const QPoint popupCenter = popupWindow->geometry().center();
11802  QWindowSystemInterface::handleEnterEvent(popupWindow, popupWindow->mapFromGlobal(popupCenter), popupCenter);
11803  QTest::mouseMove(popupWindow, popupCenter);
11804  QVERIFY(!topLevelWidget.underMouse());
11805  QVERIFY(!childWidget1.underMouse());
11806  QVERIFY(!childWidget2.underMouse());
11807  QVERIFY(popupWidget.underMouse());
11808  QCOMPARE(popupWidget.enters, 1);
11809  QCOMPARE(popupWidget.leaves, 0);
11810  QCOMPARE(topLevelWidget.enters, 0);
11811  QCOMPARE(topLevelWidget.leaves, 0);
11812  QCOMPARE(childWidget1.enters, 0);
11813  QCOMPARE(childWidget1.leaves, 0);
11814  QCOMPARE(childWidget2.enters, 0);
11815  QCOMPARE(childWidget2.leaves, 0);
11816  popupWidget.resetCounts();
11817 
11818  // Mouse moves around inside popup, no changes
11819  QTest::mouseMove(popupWindow, QPoint(5, 5));
11820  QVERIFY(!topLevelWidget.underMouse());
11821  QVERIFY(!childWidget1.underMouse());
11822  QVERIFY(!childWidget2.underMouse());
11823  QVERIFY(popupWidget.underMouse());
11824  QCOMPARE(popupWidget.enters, 0);
11825  QCOMPARE(popupWidget.leaves, 0);
11826  QCOMPARE(topLevelWidget.enters, 0);
11827  QCOMPARE(topLevelWidget.leaves, 0);
11828  QCOMPARE(childWidget1.enters, 0);
11829  QCOMPARE(childWidget1.leaves, 0);
11830  QCOMPARE(childWidget2.enters, 0);
11831  QCOMPARE(childWidget2.leaves, 0);
11832 
11833  // Mouse leaves popup and enters topLevelWidget, should cause leave for popup
11834  // but no enter to topLevelWidget.
11835  QTest::mouseMove(popupWindow, popupWindow->mapFromGlobal(window->mapToGlobal(inWindowPoint)));
11837  QVERIFY(!topLevelWidget.underMouse());
11838  QVERIFY(!childWidget1.underMouse());
11839  QVERIFY(!childWidget2.underMouse());
11840  QVERIFY(!popupWidget.underMouse());
11841  QCOMPARE(popupWidget.enters, 0);
11842  QCOMPARE(popupWidget.leaves, 1);
11843  QCOMPARE(topLevelWidget.enters, 0);
11844  QCOMPARE(topLevelWidget.leaves, 0);
11845  QCOMPARE(childWidget1.enters, 0);
11846  QCOMPARE(childWidget1.leaves, 0);
11847  QCOMPARE(childWidget2.enters, 0);
11848  QCOMPARE(childWidget2.leaves, 0);
11849 }
11850 
11851 class EnterTestModalDialog : public QDialog
11852 {
11853  Q_OBJECT
11854 public:
11856  {
11857  setGeometry(100, 300, 150, 100);
11858  button = new QPushButton(this);
11859  button->setGeometry(10, 10, 50, 30);
11860  }
11861 
11863 };
11864 
11865 class EnterTestMainDialog : public QDialog
11866 {
11867  Q_OBJECT
11868 public:
11869 
11870 public slots:
11872  {
11873  qApp->installEventFilter(this);
11874  modal = new EnterTestModalDialog();
11875  QTimer::singleShot(2000, modal, SLOT(close())); // Failsafe
11876  QTimer::singleShot(100, this, SLOT(doMouseMoves()));
11877  modal->exec();
11878  delete modal;
11879  modal = nullptr;
11880  }
11881 
11883  {
11884  QPoint point1(15, 15);
11885  QPoint point2(15, 20);
11886  QPoint point3(20, 20);
11887  QWindow *window = modal->windowHandle();
11888  const QPoint nativePoint1 = QHighDpi::toNativePixels(point1, window->screen());
11890  QTest::mouseMove(window, point1);
11891  QTest::mouseMove(window, point2);
11892  QTest::mouseMove(window, point3);
11893  modal->close();
11894  }
11895 
11896  bool eventFilter(QObject *o, QEvent *e) override
11897  {
11898  switch (e->type()) {
11899  case QEvent::Enter:
11900  if (modal && modal->button && o == modal->button)
11901  enters++;
11902  break;
11903  default:
11904  break;
11905  }
11906  return QDialog::eventFilter(o, e);
11907  }
11908 
11909 public:
11911  int enters = 0;
11912 };
11913 
11914 // A modal dialog launched by clicking a button should not trigger excess enter events
11915 // when mousing over it.
11916 void tst_QWidget::taskQTBUG_27643_enterEvents()
11917 {
11918  // Move the mouse cursor to a safe location so it won't interfere
11919  QCursor::setPos(m_safeCursorPos);
11920 
11924 
11926 
11927  dialog.setGeometry(100, 100, 150, 100);
11928  button.setGeometry(10, 10, 100, 50);
11929  dialog.show();
11931 
11933  QPoint overButton(25, 25);
11934 
11935  QWindowSystemInterface::handleEnterEvent(window, overButton, window->mapToGlobal(overButton));
11936  QTest::mouseMove(window, overButton);
11937  QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), overButton, 0);
11938 
11939  // Modal dialog opened in EnterTestMainDialog::buttonPressed()...
11940 
11941  // Must only register only single enter on modal dialog's button after all said and done
11942  QCOMPARE(dialog.enters, 1);
11943 }
11944 #endif // QT_NO_CURSOR
11945 
11946 class KeyboardWidget : public QWidget
11947 {
11948 public:
11949  using QWidget::QWidget;
11950  void mousePressEvent(QMouseEvent* ev) override
11951  {
11952  m_modifiers = ev->modifiers();
11954  ++m_eventCounter;
11955  }
11956  Qt::KeyboardModifiers m_modifiers;
11957  Qt::KeyboardModifiers m_appModifiers;
11959 };
11960 
11961 void tst_QWidget::keyboardModifiers()
11962 {
11963  KeyboardWidget w;
11964  w.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
11965  w.resize(300, 300);
11966  w.show();
11969  QCOMPARE(w.m_eventCounter, 1);
11970  QCOMPARE(int(w.m_modifiers), int(Qt::ControlModifier));
11971  QCOMPARE(int(w.m_appModifiers), int(Qt::ControlModifier));
11972 }
11973 
11974 class DClickWidget : public QWidget
11975 {
11976 public:
11978  {
11979  triggered = true;
11980  }
11981  bool triggered = false;
11982 };
11983 
11984 void tst_QWidget::mouseDoubleClickBubbling_QTBUG29680()
11985 {
11987  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
11988  QWidget child(&parent);
11989  parent.resize(200, 200);
11990  child.resize(200, 200);
11991  parent.show();
11993 
11995 
11996  QTRY_VERIFY(parent.triggered);
11997 }
11998 
11999 void tst_QWidget::largerThanScreen_QTBUG30142()
12000 {
12001  QWidget widget;
12003  widget.resize(200, 4000);
12004  widget.show();
12006  QVERIFY2(widget.frameGeometry().y() >= 0,
12007  msgComparisonFailed(widget.frameGeometry().y(), " >=", 0));
12008 
12009  QWidget widget2;
12010  widget2.resize(10000, 400);
12011  widget2.show();
12013  QVERIFY2(widget2.frameGeometry().x() >= 0,
12014  msgComparisonFailed(widget.frameGeometry().x(), " >=", 0));
12015 }
12016 
12017 void tst_QWidget::resizeStaticContentsChildWidget_QTBUG35282()
12018 {
12019  QWidget widget;
12021  widget.resize(200,200);
12022 
12023  UpdateWidget childWidget(&widget);
12024  childWidget.setAttribute(Qt::WA_StaticContents);
12025  childWidget.setAttribute(Qt::WA_OpaquePaintEvent);
12026  childWidget.setGeometry(250, 250, 500, 500);
12027 
12028  widget.showNormal();
12030  QCOMPARE(childWidget.numPaintEvents, 0);
12031  childWidget.reset();
12032 
12033  widget.resize(1000,1000);
12036  QVERIFY2(childWidget.numPaintEvents >= 1,
12037  msgComparisonFailed(childWidget.numPaintEvents, ">=", 1));
12038 }
12039 
12040 void tst_QWidget::qmlSetParentHelper()
12041 {
12042 #ifdef QT_BUILD_INTERNAL
12043  QWidget parent;
12044  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
12045  QWidget child;
12048  QCOMPARE(child.parentWidget(), &parent);
12050  QVERIFY(!child.parentWidget());
12051 #else
12052  QSKIP("Needs QT_BUILD_INTERNAL");
12053 #endif
12054 }
12055 
12056 void tst_QWidget::testForOutsideWSRangeFlag()
12057 {
12058  QSKIP("Test assumes QWindows can have 0x0 size, see QTBUG-61953");
12059 
12060  // QTBUG-49445
12061  {
12062  QWidget widget;
12063  widget.resize(0, 0);
12064  widget.show();
12065  QTest::qWait(100); // Wait for a while...
12066  QVERIFY(!widget.windowHandle()->isExposed()); // The window should not be visible
12067  QVERIFY(widget.isVisible()); // The widget should be in visible state
12068  }
12069  {
12070  QWidget widget;
12071 
12072  QWidget native(&widget);
12073  native.setAttribute(Qt::WA_NativeWindow);
12074  native.resize(0, 0);
12075 
12076  widget.show();
12078  QVERIFY(!native.windowHandle()->isExposed());
12079  }
12080  {
12081  QWidget widget;
12082  QWidget native(&widget);
12083 
12084  widget.show();
12086  QVERIFY(native.isVisible());
12087 
12088  native.resize(0, 0);
12089  native.setAttribute(Qt::WA_NativeWindow);
12090  QTest::qWait(100); // Wait for a while...
12091  QVERIFY(!native.windowHandle()->isExposed());
12092  }
12093 
12094  // QTBUG-48321
12095  {
12096  QWidget widget;
12097 
12098  QWidget native(&widget);
12099  native.setAttribute(Qt::WA_NativeWindow);
12100 
12101  widget.show();
12103  QVERIFY(native.windowHandle()->isExposed());
12104 
12105  native.resize(0, 0);
12106  QTest::qWait(100); // Wait for a while...
12107  QVERIFY(!native.windowHandle()->isExposed());
12108  }
12109 
12110  // QTBUG-51788
12111  {
12112  QWidget widget;
12113  widget.setLayout(new QGridLayout);
12114  widget.layout()->addWidget(new QLineEdit);
12115  widget.resize(0, 0);
12116  widget.show();
12117  // The layout should change the size, so the widget must be visible!
12119  }
12120 }
12121 
12122 class TabletWidget : public QWidget
12123 {
12124 public:
12126 
12132  qint64 uid = -1;
12133 
12134 protected:
12135  void tabletEvent(QTabletEvent *event) override {
12136  ++tabletEventCount;
12137  uid = event->pointingDevice()->uniqueId().numericId();
12138  switch (event->type()) {
12139  case QEvent::TabletMove:
12140  ++moveEventCount;
12141  break;
12142  case QEvent::TabletPress:
12143  ++pressEventCount;
12144  break;
12145  case QEvent::TabletRelease:
12147  break;
12148  default:
12149  break;
12150  }
12151  }
12152 
12153  bool event(QEvent *ev) override {
12154  if (ev->type() == QEvent::TabletTrackingChange)
12156  return QWidget::event(ev);
12157  }
12158 };
12159 
12160 void tst_QWidget::tabletTracking()
12161 {
12162  QWidget parent;
12163  parent.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
12164  parent.resize(200,200);
12165  // QWidgetWindow::handleTabletEvent doesn't deliver tablet events to the window's widget, only to a child.
12166  // So it doesn't do any good to show a TabletWidget directly: it needs a parent.
12168  widget.resize(200,200);
12169  parent.showNormal();
12172  QTRY_COMPARE(widget.trackingChangeEventCount, 1);
12174 
12175  QWindow *window = parent.windowHandle();
12176  QPointF local(10, 10);
12177  QPointF global = window->mapToGlobal(local.toPoint());
12179  QPointF deviceGlobal = QHighDpi::toNativePixels(global, window->screen());
12180  qint64 uid = 1234UL;
12181 
12185  QTRY_COMPARE(widget.moveEventCount, 1);
12186  QCOMPARE(widget.uid, uid);
12187 
12188  local += QPoint(10, 10);
12189  deviceLocal += QPoint(10, 10);
12190  deviceGlobal += QPoint(10, 10);
12194  QTRY_COMPARE(widget.moveEventCount, 2);
12195 
12196  widget.setTabletTracking(false);
12198  QTRY_COMPARE(widget.trackingChangeEventCount, 2);
12199 
12203  QTRY_COMPARE(widget.pressEventCount, 1);
12204 
12205  local += QPoint(10, 10);
12206  deviceLocal += QPoint(10, 10);
12207  deviceGlobal += QPoint(10, 10);
12211  QTRY_COMPARE(widget.moveEventCount, 3);
12212 
12216  QTRY_COMPARE(widget.releaseEventCount, 1);
12217 
12218  local += QPoint(10, 10);
12219  deviceLocal += QPoint(10, 10);
12220  deviceGlobal += QPoint(10, 10);
12224  QTRY_COMPARE(widget.moveEventCount, 3);
12225 }
12226 
12227 class CloseCountingWidget : public QWidget
12228 {
12229 public:
12230  int closeCount = 0;
12231  void closeEvent(QCloseEvent *ev) override;
12232 };
12233 
12235 {
12236  ++closeCount;
12237  ev->accept();
12238 }
12239 
12240 void tst_QWidget::closeEvent()
12241 {
12243  widget.show();
12245  // Yes we call the close() function twice. This mimics the behavior of QTBUG-43344 where
12246  // QApplication first closes all windows and then QCocoaApplication flushes window system
12247  // events, triggering more close events.
12248  widget.windowHandle()->close();
12249  widget.windowHandle()->close();
12250  QCOMPARE(widget.closeCount, 1);
12251 
12252  CloseCountingWidget widget2;
12253  widget2.show();
12255  widget2.close();
12256  widget2.close();
12257  QCOMPARE(widget2.closeCount, 1);
12258  widget2.closeCount = 0;
12259 
12260  widget2.show();
12262  widget2.close();
12263  QCOMPARE(widget2.closeCount, 1);
12264 
12265  CloseCountingWidget widget3;
12266  widget3.close();
12267  widget3.close();
12268  QEXPECT_FAIL("", "Closing a widget without a window will unconditionally send close events", Continue);
12269  QCOMPARE(widget3.closeCount, 0);
12270 
12271  QWidget parent;
12273  child.setParent(&parent);
12274  parent.show();
12276  child.close();
12277  QCOMPARE(child.closeCount, 1);
12278  child.close();
12279  QEXPECT_FAIL("", "Closing a widget without a window will unconditionally send close events", Continue);
12280  QCOMPARE(child.closeCount, 1);
12281 }
12282 
12283 void tst_QWidget::closeWithChildWindow()
12284 {
12285  QWidget widget;
12286  auto childWidget = new QWidget(&widget);
12287  childWidget->setAttribute(Qt::WA_NativeWindow);
12288  childWidget->windowHandle()->create();
12289  widget.show();
12291  widget.windowHandle()->close();
12292  widget.show();
12294  // Check that the child window inside the window is now visible
12295  QVERIFY(childWidget->isVisible());
12296 
12297  // Now explicitly hide the childWidget
12298  childWidget->hide();
12299  widget.windowHandle()->close();
12300  widget.show();
12302  QVERIFY(!childWidget->isVisible());
12303 }
12304 
12305 class WinIdChangeSpy : public QObject
12306 {
12307  Q_OBJECT
12308 public:
12309  QWidget *widget = nullptr;
12310  WId winId = 0;
12311  explicit WinIdChangeSpy(QWidget *w, QObject *parent = nullptr)
12312  : QObject(parent)
12313  , widget(w)
12314  , winId(widget->winId())
12315  {
12316  }
12317 
12318 public slots:
12319  bool eventFilter(QObject *obj, QEvent *event) override
12320  {
12321  if (obj == widget) {
12322  if (event->type() == QEvent::WinIdChange) {
12323  winId = widget->winId();
12324  return true;
12325  }
12326  }
12327  return false;
12328  }
12329 };
12330 
12331 void tst_QWidget::winIdAfterClose()
12332 {
12333  auto widget = new QWidget;
12334  auto notifier = new QObject(widget);
12335  auto deleteWidget = new QWidget(new QWidget(widget));
12336  auto spy = new WinIdChangeSpy(deleteWidget);
12337  deleteWidget->installEventFilter(spy);
12338  connect(notifier, &QObject::destroyed, [&] { delete deleteWidget; });
12339 
12341  widget->windowHandle()->create();
12342  widget->show();
12343 
12345  QVERIFY(spy->winId);
12346 
12347  widget->windowHandle()->close();
12348  delete widget;
12349 
12350  QCOMPARE(spy->winId, WId(0));
12351  delete spy;
12352 }
12353 
12354 class ChangeEventWidget : public QWidget
12355 {
12356 public:
12357  ChangeEventWidget(QWidget *parent = nullptr) : QWidget(parent) {}
12361 protected:
12362  bool event(QEvent *e) override
12363  {
12364  if (e->type() == QEvent::LanguageChange)
12366  else if (e->type() == QEvent::ApplicationFontChange)
12368  else if (e->type() == QEvent::ApplicationPaletteChange)
12370  return QWidget::event(e);
12371  }
12372 };
12373 
12375 {
12376 public:
12381 protected:
12382  bool event(QEvent *e) override
12383  {
12384  if (e->type() == QEvent::LanguageChange)
12386  else if (e->type() == QEvent::ApplicationFontChange)
12388  else if (e->type() == QEvent::ApplicationPaletteChange)
12390  return QWindow::event(e);
12391  }
12392 };
12393 
12394 void tst_QWidget::receivesLanguageChangeEvent()
12395 {
12396  // Confirm that any QWindow or QWidget only gets a single
12397  // LanguageChange event when a translator is installed
12398  ChangeEventWidget topLevel;
12399  auto childWidget = new ChangeEventWidget(&topLevel);
12400  topLevel.show();
12402  ChangeEventWindow ww;
12403  ww.show();
12405  ChangeEventWidget topLevelNotShown;
12406  QTranslator t;
12407  QVERIFY(t.load("hellotr_la.qm", ":/"));
12408  QVERIFY(qApp->installTranslator(&t));
12410  QCOMPARE(topLevel.languageChangeCount, 1);
12411  QCOMPARE(topLevelNotShown.languageChangeCount, 1);
12412  QCOMPARE(childWidget->languageChangeCount, 1);
12414 }
12415 
12416 void tst_QWidget::receivesApplicationFontChangeEvent()
12417 {
12418  // Confirm that any QWindow or top level QWidget only gets a single
12419  // ApplicationFontChange event when the font is changed
12420  const QFont origFont = QApplication::font();
12421 
12422  ChangeEventWidget topLevel;
12423  auto childWidget = new ChangeEventWidget(&topLevel);
12424  topLevel.show();
12426  ChangeEventWindow ww;
12427  ww.show();
12429  ChangeEventWidget topLevelNotShown;
12430  QFont changedFont = origFont;
12431  changedFont.setPointSize(changedFont.pointSize() + 2);
12432  QApplication::setFont(changedFont);
12434  QCOMPARE(topLevel.applicationFontChangeCount, 1);
12435  QCOMPARE(topLevelNotShown.applicationFontChangeCount, 1);
12436  // QWidget should not be passing the event on automatically
12437  QCOMPARE(childWidget->applicationFontChangeCount, 0);
12439 
12440  QApplication::setFont(origFont);
12441 }
12442 
12443 void tst_QWidget::receivesApplicationPaletteChangeEvent()
12444 {
12445  // Confirm that any QWindow or top level QWidget only gets a single
12446  // ApplicationPaletteChange event when the font is changed
12447  const QPalette origPalette = QApplication::palette();
12448 
12449  ChangeEventWidget topLevel;
12450  auto childWidget = new ChangeEventWidget(&topLevel);
12451  topLevel.show();
12453  ChangeEventWindow ww;
12454  ww.show();
12456  ChangeEventWidget topLevelNotShown;
12457  QPalette changedPalette = origPalette;
12458  changedPalette.setColor(QPalette::Base, Qt::red);
12459  QApplication::setPalette(changedPalette);
12462  QCOMPARE(topLevelNotShown.applicationPaletteChangeCount, 1);
12463  // QWidget should not be passing the event on automatically
12464  QCOMPARE(childWidget->applicationPaletteChangeCount, 0);
12466 
12467  QApplication::setPalette(origPalette);
12468 }
12469 
12470 class DeleteOnCloseEventWidget : public QWidget
12471 {
12472 protected:
12473  virtual void closeEvent(QCloseEvent *e) override
12474  {
12475  e->accept();
12476  delete this;
12477  }
12478 };
12479 
12480 void tst_QWidget::deleteWindowInCloseEvent()
12481 {
12482 #ifdef Q_OS_ANDROID
12483  QSKIP("This test crashes on Android");
12484 #endif
12486 
12487  // Closing this widget should not cause a crash
12488  auto widget = new DeleteOnCloseEventWidget;
12489  widget->show();
12491  QTimer::singleShot(0, widget, [&]{
12492  widget->close();
12493  });
12495 
12496  // It should still result in a single lastWindowClosed emit
12497  QCOMPARE(quitSpy.count(), 1);
12498 }
12499 
12504 void tst_QWidget::quitOnClose()
12505 {
12507 
12508  std::unique_ptr<QWidget>widget(new QWidget);
12509  widget->show();
12511 
12512  // QGuiApplication::lastWindowClosed is documented to only be emitted
12513  // when we are in exec()
12514  QTimer::singleShot(0, widget.get(), [&]{
12515  widget->close();
12516  });
12518  QCOMPARE(quitSpy.count(), 1);
12519 
12520  widget->show();
12522  QTimer::singleShot(0, widget.get(), [&]{
12523  widget.reset();
12524  });
12526  QCOMPARE(quitSpy.count(), 2);
12527 }
12528 
12529 void tst_QWidget::setParentChangesFocus_data()
12530 {
12531  QTest::addColumn<Qt::WindowType>("initialType");
12532  QTest::addColumn<bool>("initialParent");
12533  QTest::addColumn<Qt::WindowType>("targetType");
12534  QTest::addColumn<bool>("targetParent");
12535  QTest::addColumn<bool>("reparentBeforeShow");
12536  QTest::addColumn<QString>("focusWidget");
12537 
12538  for (const bool before : {true, false}) {
12539  const char *tag = before ? "before" : "after";
12540  QTest::addRow("give dialog parent, %s", tag)
12541  << Qt::Dialog << false << Qt::Dialog << true << before << "lineEdit";
12542  QTest::addRow("make dialog parentless, %s", tag)
12543  << Qt::Dialog << true << Qt::Dialog << false << before << "lineEdit";
12544  QTest::addRow("dialog to sheet, %s", tag)
12545  << Qt::Dialog << true << Qt::Sheet << true << before << "lineEdit";
12546  QTest::addRow("window to widget, %s", tag)
12547  << Qt::Window << true << Qt::Widget << true << before << "windowEdit";
12548  QTest::addRow("widget to window, %s", tag)
12549  << Qt::Widget << true << Qt::Window << true << before << "lineEdit";
12550  }
12551 }
12552 
12553 void tst_QWidget::setParentChangesFocus()
12554 {
12555  QFETCH(Qt::WindowType, initialType);
12556  QFETCH(bool, initialParent);
12557  QFETCH(Qt::WindowType, targetType);
12558  QFETCH(bool, targetParent);
12559  QFETCH(bool, reparentBeforeShow);
12560  QFETCH(QString, focusWidget);
12561 
12562  QWidget window;
12563  window.setObjectName("window");
12564  QLineEdit *windowEdit = new QLineEdit(&window);
12565  windowEdit->setObjectName("windowEdit");
12566  windowEdit->setFocus();
12567 
12568  std::unique_ptr<QWidget> secondary(new QWidget(initialParent ? &window : nullptr, initialType));
12569  secondary->setObjectName("secondary");
12570  QLineEdit *lineEdit = new QLineEdit(secondary.get());
12571  lineEdit->setObjectName("lineEdit");
12572  QPushButton *pushButton = new QPushButton(secondary.get());
12573  pushButton->setObjectName("pushButton");
12574  lineEdit->setFocus();
12575 
12576  window.show();
12578 
12579  if (reparentBeforeShow) {
12580  secondary->setParent(targetParent ? &window : nullptr, targetType);
12581  // making a widget into a window doesn't set a focusWidget until shown
12582  if (secondary->focusWidget())
12583  QCOMPARE(secondary->focusWidget()->objectName(), focusWidget);
12584  }
12585  secondary->show();
12586  QApplication::setActiveWindow(secondary.get());
12587  QVERIFY(QTest::qWaitForWindowActive(secondary.get()));
12588 
12589  if (!reparentBeforeShow) {
12590  secondary->setParent(targetParent ? &window : nullptr, targetType);
12591  secondary->show(); // reparenting hides, so show again
12592  QApplication::setActiveWindow(secondary.get());
12593  QVERIFY(QTest::qWaitForWindowActive(secondary.get()));
12594  }
12595  QCOMPARE(QApplication::focusWidget()->objectName(), focusWidget);
12596 }
12597 
12598 void tst_QWidget::activateWhileModalHidden()
12599 {
12600  QDialog dialog;
12602  dialog.show();
12606 
12607  dialog.hide();
12609 
12611  window.show();
12613  QVERIFY(window.isActiveWindow());
12615 }
12616 
12617 #ifdef Q_OS_ANDROID
12618 void tst_QWidget::showFullscreenAndroid()
12619 {
12620  QWidget w;
12621  w.setAutoFillBackground(true);
12622  QPalette p = w.palette();
12623  p.setColor(QPalette::Window, Qt::red);
12624  w.setPalette(p);
12625 
12626  // Need to toggle showFullScreen() twice, see QTBUG-101968
12627  w.showFullScreen();
12629  w.show();
12631  w.showFullScreen();
12633 
12634  // Make sure that the lower part of the screen contains the red widget, not
12635  // the buttons.
12636 
12637  const QRect fullGeometry = w.screen()->geometry();
12638  // Take a rect of (20 x 20) from the bottom area
12639  const QRect grabArea(10, fullGeometry.height() - 30, 20, 20);
12640  const QImage img = grabFromWidget(&w, grabArea).toImage().convertedTo(QImage::Format_RGB32);
12641 
12642  QPixmap expectedPix(20, 20);
12643  expectedPix.fill(Qt::red);
12644  const QImage expectedImg = expectedPix.toImage().convertedTo(QImage::Format_RGB32);
12645 
12646  QCOMPARE(img, expectedImg);
12647 }
12648 #endif // Q_OS_ANDROID
12649 
12651 #include "tst_qwidget.moc"
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
Arabic default style
Definition: afstyles.h:94
#define Q_CHECK_PAINTEVENTS
void testFunction1(bool)
#define CLEAR_MASK(widget)
#define VERIFY_STATE(s)
void drawPolygon(QPaintDevice *dev, int w, int h)
void testFunction0()
void setWindowsAnimationsEnabled(bool)
bool verifyColor(QWidget &child, const QRegion &region, const QColor &color, int callerLine)
#define RESET_WIDGETS
#define VERIFY_COLOR(child, region, color)
#define RESET_EVENT_COUNTS
QWidgetRepaintManager * repaintManager(QWidget &widget)
int heightForWidth(int width) const override
ASWidget(QSize sizeHint, QSizePolicy sizePolicy, bool layout, bool hfwLayout, QWidget *parent=nullptr)
QSize sizeHint() const override
QSize mySizeHint
ChangeEventWidget(QWidget *parent=nullptr)
bool event(QEvent *e) override
ChangeEventWindow(QWindow *parent=nullptr)
bool event(QEvent *e) override
void closeEvent(QCloseEvent *ev) override
ColorRedWidget(QWidget *parent=nullptr)
void paintEvent(QPaintEvent *) override
void paintEvent(QPaintEvent *e) override
ColorWidget(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags(), const QColor &c=QColor(Qt::red))
QColor color
Definition: guitest.h:88
void enterEvent(QEnterEvent *) override
void resetCounts()
void leaveEvent(QEvent *) override
Composite(QWidget *parent=nullptr, const QString &name=QString())
QLineEdit * lineEdit1
QLineEdit * lineEdit2
QLineEdit * lineEdit3
void backTab()
QVBoxLayout * box
void paintEvent(QPaintEvent *) override
QSize sizeHint() const override
ContentsPropagationWidget(QWidget *parent=nullptr)
void setContentsPropagation(bool enable)
QWidget(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
int metric(PaintDeviceMetric metric) const override
void mouseDoubleClickEvent(QMouseEvent *) override
virtual void closeEvent(QCloseEvent *e) override
DestroyTester(QObject *parent=nullptr)
static int parentDestroyed
void parentDestroyedSlot()
void destroyedSlot(QObject *object)
bool eventFilter(QObject *o, QEvent *e) override
EnterTestModalDialog * modal
Q_INVOKABLE QObject(QObject *parent=nullptr)
Definition: qobject.cpp:913
QPair< QWidget *, QEvent::Type > WidgetEventTypePair
bool eventFilter(QObject *object, QEvent *event) override
static QByteArray msgEventListMismatch(const EventList &expected, const EventList &actual)
EventList eventList() const
static QByteArray msgExpectFailQtBug26424(const EventList &expected, const EventList &actual)
QList< WidgetEventTypePair > EventList
void clear()
EventSpy(T *widget, QEvent::Type event)
bool eventFilter(QObject *object, QEvent *event) override
int count() const
T * widget() const
FocusWidget(QWidget *parent)
bool detectedBadEventOrdering
QObject * focusObjectDuringFocusOut
QObject * focusObjectDuringFocusIn
void focusObjectChanged(QObject *focusObject)
bool event(QEvent *ev) override
void focusInEvent(QFocusEvent *) override
QObject * mostRecentFocusObjectChange
QWidget * widgetDuringFocusOut
void focusOutEvent(QFocusEvent *) override
QWidget * widgetDuringFocusAboutToChange
GrabLoggerWidget(QStringList *log, QWidget *parent=nullptr)
bool event(QEvent *e) override
static QByteArray msgPointMismatch(const QPoint &p1, const QPoint p2)
Definition: highdpi.h:61
static bool fuzzyCompare(const QPoint &p1, const QPoint p2, int fuzz)
Definition: highdpi.h:56
QWidget(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
Qt::KeyboardModifiers m_modifiers
void mousePressEvent(QMouseEvent *ev) override
Qt::KeyboardModifiers m_appModifiers
MaskResizeTestWidget(QWidget *p=nullptr)
void paintEvent(QPaintEvent *event) override
QWidget(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
void paintEvent(QPaintEvent *event) override
QRegion paintedRegion
void resizeEvent(QResizeEvent *) override
void resizeEvent(QResizeEvent *) override
MoveInResizeWidget(QWidget *p=nullptr)
QWidget * widget
MyEvilObject(QWidget *widgetToCrash)
QWidget(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
void clicked(bool checked=false)
static void(* setWidgetParent)(QObject *, QObject *)
Definition: qobject_p.h:95
The QAbstractNativeEventFilter class provides an interface for receiving native events,...
The QActionEvent class provides an event that is generated when a QAction is added,...
The QAction class provides an abstraction for user commands that can be added to different user inter...
Definition: qaction.h:65
static void setPalette(const QPalette &, const char *className=nullptr)
static QWidget * widgetAt(const QPoint &p)
static QPalette palette()
static QWidget * activeModalWidget()
static QWidget * focusWidget()
static QWidgetList topLevelWidgets()
static QFont font()
static QWidget * activePopupWidget()
static int exec()
static QWidget * activeWindow()
static void setActiveWindow(QWidget *act)
static void setFont(const QFont &, const char *className=nullptr)
The QBitmap class provides monochrome (1-bit depth) pixmaps.
Definition: qbitmap.h:52
The QBoxLayout class lines up child widgets horizontally or vertically.
Definition: qboxlayout.h:57
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
const char * constData() const noexcept
Definition: qbytearray.h:144
static QByteArray number(int, int base=10)
qsizetype count(char c) const
The QCalendarWidget class provides a monthly based calendar widget allowing the user to select a date...
virtual QSize sizeHint() const override
The QCloseEvent class contains parameters that describe a close event.
Definition: qevent.h:629
QRgb
Definition: qrgb.h:49
static bool sendEvent(QObject *receiver, QEvent *event)
static void processEvents(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
static void setAttribute(Qt::ApplicationAttribute attribute, bool on=true)
[95]
static bool testAttribute(Qt::ApplicationAttribute attribute)
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
static void sendPostedEvents(QObject *receiver=nullptr, int event_type=0)
static void setPos(int x, int y)
Definition: qcursor.cpp:276
static QPoint pos()
Definition: qcursor.cpp:224
static qint64 currentMSecsSinceEpoch() noexcept
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:65
QDebug & nospace()
Definition: qdebug.h:113
bool eventFilter(QObject *, QEvent *) override
Definition: qdialog.cpp:684
virtual void reject()
Definition: qdialog.cpp:678
virtual int exec()
Definition: qdialog.cpp:595
void setModal(bool modal)
Definition: qdialog.cpp:1038
The QDockWidget class provides a widget that can be docked inside a QMainWindow or floated as a top-l...
Definition: qdockwidget.h:56
void setWidget(QWidget *widget)
void setFloating(bool floating)
The QDoubleSpinBox class provides a spin box widget that takes doubles.
Definition: qspinbox.h:118
The QEnterEvent class contains parameters that describe an enter event.
Definition: qevent.h:197
The QEvent class is the base class of all event classes. Event objects contain event parameters.
Definition: qcoreevent.h:58
@ TabletMove
Definition: qcoreevent.h:134
@ ApplicationPaletteChange
Definition: qcoreevent.h:106
@ Gesture
Definition: qcoreevent.h:266
@ WindowStateChange
Definition: qcoreevent.h:156
@ FocusAboutToChange
Definition: qcoreevent.h:81
@ PolishRequest
Definition: qcoreevent.h:123
@ ChildPolished
Definition: qcoreevent.h:120
@ ToolTip
Definition: qcoreevent.h:160
@ ApplicationWindowIconChange
Definition: qcoreevent.h:103
@ FocusOut
Definition: qcoreevent.h:80
@ ChildRemoved
Definition: qcoreevent.h:121
@ CursorChange
Definition: qcoreevent.h:241
@ Enter
Definition: qcoreevent.h:82
@ InputMethodQuery
Definition: qcoreevent.h:274
@ Leave
Definition: qcoreevent.h:83
@ MouseMove
Definition: qcoreevent.h:76
@ Show
Definition: qcoreevent.h:89
@ ZOrderChange
Definition: qcoreevent.h:186
@ Resize
Definition: qcoreevent.h:86
@ FocusIn
Definition: qcoreevent.h:79
@ TouchCancel
Definition: qcoreevent.h:277
@ ActivationChange
Definition: qcoreevent.h:148
@ MouseButtonPress
Definition: qcoreevent.h:73
@ TouchEnd
Definition: qcoreevent.h:256
@ TouchUpdate
Definition: qcoreevent.h:255
@ TouchBegin
Definition: qcoreevent.h:254
@ ToolTipChange
Definition: qcoreevent.h:242
@ WindowActivate
Definition: qcoreevent.h:96
@ LanguageChange
Definition: qcoreevent.h:136
@ TabletRelease
Definition: qcoreevent.h:140
@ WindowIconChange
Definition: qcoreevent.h:102
@ UpdateRequest
Definition: qcoreevent.h:126
@ UpdateLater
Definition: qcoreevent.h:127
@ PlatformSurface
Definition: qcoreevent.h:291
@ TabletPress
Definition: qcoreevent.h:139
@ ApplicationFontChange
Definition: qcoreevent.h:104
@ TabletTrackingChange
Definition: qcoreevent.h:295
@ WinIdChange
Definition: qcoreevent.h:264
@ Polish
Definition: qcoreevent.h:124
@ ShowToParent
Definition: qcoreevent.h:98
@ WindowDeactivate
Definition: qcoreevent.h:97
@ Move
Definition: qcoreevent.h:85
@ MouseButtonRelease
Definition: qcoreevent.h:74
@ ChildAdded
Definition: qcoreevent.h:119
Type type() const
Definition: qcoreevent.h:307
void accept()
Definition: qcoreevent.h:313
The QEventLoop class provides a means of entering and leaving an event loop.
Definition: qeventloop.h:50
int exec(ProcessEventsFlags flags=AllEvents)
Definition: qeventloop.cpp:162
void quit()
Definition: qeventloop.cpp:329
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:94
The QFocusEvent class contains event parameters for widget focus events. \inmodule QtGui.
Definition: qevent.h:520
@ NoAntialias
Definition: qfont.h:81
The QFrame class is the base class of widgets that can have a frame.
Definition: qframe.h:53
@ Plain
Definition: qframe.h:85
@ Sunken
Definition: qframe.h:87
void setFrameStyle(int)
Definition: qframe.cpp:335
@ Box
Definition: qframe.h:76
The QGraphicsBlurEffect class provides a blur effect.
The QGraphicsDropShadowEffect class provides a drop shadow effect.
The QGraphicsEffect class is the base class for all graphics effects.
QGraphicsObject * parent
the parent of the item
The QGraphicsScene class provides a surface for managing a large number of 2D graphical items.
QGraphicsProxyWidget * addWidget(QWidget *widget, Qt::WindowFlags wFlags=Qt::WindowFlags())
void setFocusPolicy(Qt::FocusPolicy policy)
friend class QWidget
The QGuiApplication class manages the GUI application's control flow and main settings.
static QPlatformNativeInterface * platformNativeInterface()
QScreen * primaryScreen
the primary (or default) screen of the application.
static QObject * focusObject()
static void sync()
void focusObjectChanged(QObject *focusObject)
static QStyleHints * styleHints()
static QWindow * focusWindow()
void lastWindowClosed()
static Qt::KeyboardModifiers keyboardModifiers()
static void setOverrideCursor(const QCursor &)
static void restoreOverrideCursor()
QString platformName
The name of the underlying platform plugin.
static QList< QScreen * > screens()
static Qt::MouseButtons mouseButtons()
static QPlatformIntegration * platformIntegration()
The QHideEvent class provides an event which is sent after a widget is hidden.
Definition: qevent.h:656
static bool isActive()
@ Format_RGB32
Definition: qimage.h:82
@ Format_ARGB32_Premultiplied
Definition: qimage.h:84
@ Format_ARGB32
Definition: qimage.h:83
Qt::KeyboardModifiers modifiers() const
Definition: qevent.h:85
The QKeyEvent class describes a key event.
Definition: qevent.h:471
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
The QLayout class is the base class of geometry managers.
Definition: qlayout.h:62
void addWidget(QWidget *w)
Definition: qlayout.cpp:223
QLayout * layout() override
virtual QRect geometry() const =0
virtual void setGeometry(const QRect &)=0
The QLineEdit widget is a one-line text editor.
Definition: qlineedit.h:64
QString text
the line edit's text.
Definition: qlineedit.h:68
qsizetype size() const noexcept
Definition: qlist.h:414
QList< T > & fill(parameter_type t, qsizetype size=-1)
Definition: qlist.h:907
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
qsizetype count() const noexcept
Definition: qlist.h:415
void append(parameter_type t)
Definition: qlist.h:469
void clear()
Definition: qlist.h:445
@ Italian
Definition: qlocale.h:197
@ French
Definition: qlocale.h:163
The QMainWindow class provides a main application window.\inmodule QtWidgets.
Definition: qmainwindow.h:61
bool qFuzzyCompare(const QMatrix4x4 &m1, const QMatrix4x4 &m2)
Definition: qmatrix4x4.cpp:774
The QMenu class provides a menu widget for use in menu bars, context menus, and other popup menus.
Definition: qmenu.h:62
void addAction(QAction *action)
Definition: qwidget.cpp:3129
The QMessageBox class provides a modal dialog for informing the user or for asking the user a questio...
Definition: qmessagebox.h:57
The QMouseEvent class contains parameters that describe a mouse event.
Definition: qevent.h:231
Q_INVOKABLE QObject(QObject *parent=nullptr)
Definition: qobject.cpp:913
T findChild(const QString &aName=QString(), Qt::FindChildOptions options=Qt::FindChildrenRecursively) const
Definition: qobject.h:168
void installEventFilter(QObject *filterObj)
Definition: qobject.cpp:2235
QObject * parent() const
Definition: qobject.h:409
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Definition: qobject.cpp:2772
QString objectName
the name of this object
Definition: qobject.h:129
virtual bool event(QEvent *event)
Definition: qobject.cpp:1329
virtual bool eventFilter(QObject *watched, QEvent *event)
Definition: qobject.cpp:1484
friend class QWidget
Definition: qobject.h:445
void setObjectName(const QString &name)
Definition: qobject.cpp:1261
void destroyed(QObject *=nullptr)
void deleteLater()
Definition: qobject.cpp:2319
int logicalDpiX() const
Definition: qpaintdevice.h:81
The QPaintEngine class provides an abstract definition of how QPainter draws to a given device on a g...
Definition: qpaintengine.h:87
void setSystemClip(const QRegion &baseClip)
QRegion systemClip() const
The QPaintEvent class contains event parameters for paint events. \inmodule QtGui.
Definition: qevent.h:539
@ SmoothPixmapTransform
Definition: qpainter.h:90
@ Antialiasing
Definition: qpainter.h:88
@ TextAntialiasing
Definition: qpainter.h:89
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:65
@ Inactive
Definition: qpalette.h:84
@ Active
Definition: qpalette.h:84
@ HighlightedText
Definition: qpalette.h:88
@ ToolTipBase
Definition: qpalette.h:92
@ Window
Definition: qpalette.h:87
@ Base
Definition: qpalette.h:87
@ Text
Definition: qpalette.h:87
@ Highlight
Definition: qpalette.h:88
@ ToolTipText
Definition: qpalette.h:92
The QPen class defines how a QPainter should draw lines and outlines of shapes.
Definition: qpen.h:61
static int defaultDepth()
Definition: qpixmap.cpp:1410
virtual Qt::WindowState defaultWindowState(Qt::WindowFlags) const
virtual QPlatformNativeInterface * nativeInterface() const
virtual void * nativeResourceForWindow(const QByteArray &resource, QWindow *window)
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:242
constexpr QPoint toPoint() const
Definition: qpoint.h:420
The QPointingDevice class describes a device from which mouse, touch or tablet events originate.
The QPolygon class provides a list of points using integer precision. \inmodule QtGui.
Definition: qpolygon.h:57
QWidget(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
Definition: qrandom.h:311
double bounded(double highest)
Definition: qrandom.h:108
The QRectF class defines a finite rectangle in the plane using floating point precision.
Definition: qrect.h:511
constexpr qreal y() const noexcept
Definition: qrect.h:681
constexpr qreal height() const noexcept
Definition: qrect.h:741
constexpr qreal width() const noexcept
Definition: qrect.h:738
constexpr qreal x() const noexcept
Definition: qrect.h:678
The QRegion class specifies a clip region for a painter.
Definition: qregion.h:63
bool contains(const QPoint &p) const
@ Ellipse
Definition: qregion.h:65
QRegion translated(int dx, int dy) const
Definition: qregion.cpp:629
The QRegularExpression class provides pattern matching using regular expressions.
The QResizeEvent class contains event parameters for resize events. \inmodule QtGui.
Definition: qevent.h:612
The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon dest...
T * data() const noexcept
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition: qscreen.h:68
QRect availableGeometry
the screen's available geometry in pixels
Definition: qscreen.h:82
QRect geometry
the screen's geometry in pixels
Definition: qscreen.h:81
QPixmap grabWindow(WId window=0, int x=0, int y=0, int w=-1, int h=-1)
Definition: qscreen.cpp:772
QSize size
the pixel resolution of the screen
Definition: qscreen.h:77
QSize availableSize
the screen's available size in pixels
Definition: qscreen.h:78
The QSharedPointer class holds a strong reference to a shared pointer.
The QShowEvent class provides an event that is sent when a widget is shown.
Definition: qevent.h:647
QPointF position() const
Definition: qevent.h:150
Qt::MouseButtons buttons() const
Definition: qevent.h:148
The QSizeF class defines the size of a two-dimensional object using floating point precision.
Definition: qsize.h:235
The QString class provides a Unicode character string.
Definition: qstring.h:388
QByteArray toLatin1() const &
Definition: qstring.h:745
bool isEmpty() const
Definition: qstring.h:1216
QString toLower() const &
Definition: qstring.h:611
static QString number(int, int base=10)
Definition: qstring.cpp:7538
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition: qstring.cpp:6759
The QStringList class provides a list of strings.
static QStyle * create(const QString &)
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition: qstyle.h:65
@ SH_ToolTip_FallAsleepDelay
Definition: qstyle.h:718
@ SH_ToolTip_WakeUpDelay
Definition: qstyle.h:717
virtual int styleHint(StyleHint stylehint, const QStyleOption *opt=nullptr, const QWidget *widget=nullptr, QStyleHintReturn *returnData=nullptr) const =0
@ SP_TitleBarMenuButton
Definition: qstyle.h:751
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
The QTabWidget class provides a stack of tabbed widgets.
Definition: qtabwidget.h:56
The QTableView class provides a default model/view implementation of a table view.
Definition: qtableview.h:54
QTouchEventSequence & move(int touchId, const QPoint &pt, QWindow *window=nullptr)
QTouchEventSequence & press(int touchId, const QPoint &pt, QWindow *window=nullptr)
QTouchEventSequence & release(int touchId, const QPoint &pt, QWindow *window=nullptr)
virtual QTouchEventSequence & stationary(int touchId)
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:367
The QTimer class provides repetitive and single-shot timers.
Definition: qtimer.h:58
void setSingleShot(bool singleShot)
Definition: qtimer.cpp:730
void start(int msec)
Definition: qtimer.cpp:259
void setInterval(int msec)
Definition: qtimer.cpp:757
bool isActive() const
Definition: qtimer.cpp:206
bool singleShot
whether the timer is a single-shot timer
Definition: qtimer.h:60
void timeout(QPrivateSignal)
The QToolBar class provides a movable panel that contains a set of controls.
Definition: qtoolbar.h:59
QAction * addWidget(QWidget *widget)
Definition: qtoolbar.cpp:781
The QToolButton class provides a quick-access button to commands or options, usually used inside a QT...
Definition: qtoolbutton.h:56
The QTouchEvent class contains parameters that describe a touch event.
Definition: qevent.h:1020
static QTransform fromTranslate(qreal dx, qreal dy)
Definition: qtransform.cpp:437
The QTranslator class provides internationalization support for text output.
Definition: qtranslator.h:55
The QTreeView class provides a default model/view implementation of a tree view.
Definition: qtreeview.h:56
The QTreeWidget class provides a tree view that uses a predefined tree model.
Definition: qtreewidget.h:250
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:95
void setAutoFillBackground(bool enabled)
Definition: qwidget.cpp:361
QRect normalGeometry
the geometry of the widget as it will appear when shown as a normal (not maximized or full screen) to...
Definition: qwidget.h:142
void setLayout(QLayout *)
Definition: qwidget.cpp:10146
int metric(PaintDeviceMetric) const override
Definition: qwidget.cpp:12723
void setAttribute(Qt::WidgetAttribute, bool on=true)
Definition: qwidget.cpp:11088
void repaint()
Definition: qwidget.cpp:10899
QWidget * window() const
Definition: qwidget.cpp:4319
WId internalWinId() const
Definition: qwidget.h:251
void setGeometry(int x, int y, int w, int h)
Definition: qwidget.h:919
bool hasTabletTracking() const
Definition: qwidget.h:898
void raise()
Definition: qwidget.cpp:11707
void setUpdatesEnabled(bool enable)
Definition: qwidget.cpp:7809
void scroll(int dx, int dy)
Definition: qwidget.cpp:10815
void setWindowModality(Qt::WindowModality windowModality)
Definition: qwidget.cpp:2811
void grabKeyboard()
Definition: qwidget.cpp:12618
Q_INVOKABLE QPixmap grab(const QRect &rectangle=QRect(QPoint(0, 0), QSize(-1, -1)))
Definition: qwidget.cpp:5218
void setParent(QWidget *parent)
Definition: qwidget.cpp:10512
void setMinimumSize(const QSize &)
Definition: qwidget.h:865
void setMask(const QBitmap &)
void setStyle(QStyle *)
Definition: qwidget.cpp:2642
void setMinimumWidth(int minw)
Definition: qwidget.cpp:4118
void setTabletTracking(bool enable)
Definition: qwidget.h:895
bool isMinimized() const
Definition: qwidget.cpp:2848
bool isFullScreen() const
Definition: qwidget.cpp:2994
QSize size
the size of the widget excluding any window frame
Definition: qwidget.h:147
void clearFocus()
Definition: qwidget.cpp:6665
static void setTabOrder(QWidget *, QWidget *)
Definition: qwidget.cpp:6930
void setEnabled(bool)
Definition: qwidget.cpp:3368
void setWindowOpacity(qreal level)
Definition: qwidget.cpp:11330
void setFocusProxy(QWidget *)
Definition: qwidget.cpp:6382
QRect geometry
the geometry of the widget relative to its parent and excluding the window frame
Definition: qwidget.h:140
QLayout * layout() const
Definition: qwidget.cpp:10115
void setPalette(const QPalette &)
Definition: qwidget.cpp:4536
QPalette palette
the widget's palette
Definition: qwidget.h:166
int width
the width of the widget excluding any window frame
Definition: qwidget.h:148
void showMinimized()
Definition: qwidget.cpp:2859
void setMouseTracking(bool enable)
Definition: qwidget.h:886
void releaseKeyboard()
Definition: qwidget.cpp:12643
QPoint pos
the position of the widget within its parent widget
Definition: qwidget.h:145
bool isMaximized() const
Definition: qwidget.cpp:2888
void unsetCursor()
Definition: qwidget.cpp:4989
bool close()
Definition: qwidget.cpp:8468
void move(int x, int y)
Definition: qwidget.h:913
void showFullScreen()
Definition: qwidget.cpp:3033
void setFocusPolicy(Qt::FocusPolicy policy)
Definition: qwidget.cpp:7773
void hide()
Definition: qwidget.cpp:8078
int height
the height of the widget excluding any window frame
Definition: qwidget.h:149
QRect rect
the internal geometry of the widget excluding any window frame
Definition: qwidget.h:150
void setWindowState(Qt::WindowStates state)
Definition: qwidget.cpp:2949
void setDisabled(bool)
Definition: qwidget.cpp:3460
void setFocus()
Definition: qwidget.h:454
void show()
Definition: qwidget.cpp:7825
void stackUnder(QWidget *)
Definition: qwidget.cpp:11808
void setMaximumSize(const QSize &)
Definition: qwidget.h:868
QIcon windowIcon
the widget's icon
Definition: qwidget.h:186
void lower()
Definition: qwidget.cpp:11761
void update()
Definition: qwidget.cpp:10977
QWindow * windowHandle() const
Definition: qwidget.cpp:2495
void showMaximized()
Definition: qwidget.cpp:3056
WId winId() const
Definition: qwidget.cpp:2359
void setWindowTitle(const QString &)
Definition: qwidget.cpp:6119
QByteArray saveGeometry() const
Definition: qwidget.cpp:7348
bool event(QEvent *event) override
Definition: qwidget.cpp:8772
QStyle * style() const
Definition: qwidget.cpp:2612
void setFont(const QFont &)
Definition: qwidget.cpp:4673
void resize(int w, int h)
Definition: qwidget.h:916
void render(QPaintDevice *target, const QPoint &targetOffset=QPoint(), const QRegion &sourceRegion=QRegion(), RenderFlags renderFlags=RenderFlags(DrawWindowBackground|DrawChildren))
QRegion mask() const
Definition: qwidget.cpp:10100
void create(WId=0, bool initializeWindow=true, bool destroyOldWindow=true)
Definition: qwidget.cpp:1127
void destroy(bool destroyWindow=true, bool destroySubWindows=true)
Definition: qwidget.cpp:12286
bool hasFocus() const
Definition: qwidget.cpp:6430
bool underMouse() const
Definition: qwidget.h:892
double windowOpacity
The level of opacity for the window.
Definition: qwidget.h:188
QPointF mapTo(const QWidget *, const QPointF &) const
bool isWindow() const
Definition: qwidget.h:844
Qt::WindowStates windowState() const
Definition: qwidget.cpp:2900
QRect frameGeometry
geometry of the widget relative to its parent including any window frame
Definition: qwidget.h:141
QScreen * screen() const
Definition: qwidget.cpp:2508
void showNormal()
Definition: qwidget.cpp:3072
void clearMask()
Definition: qwidget.cpp:12934
bool restoreGeometry(const QByteArray &geometry)
Definition: qwidget.cpp:7408
bool isActiveWindow
whether this widget's window is the active window
Definition: qwidget.h:173
QPalette::ColorRole backgroundRole() const
Definition: qwidget.cpp:4366
void setFixedSize(const QSize &)
bool isVisible() const
Definition: qwidget.h:907
QPointF mapFromGlobal(const QPointF &) const
void setCursor(const QCursor &)
Definition: qwidget.cpp:4966
bool testAttribute(Qt::WidgetAttribute) const
Definition: qwidget.h:943
void setWindowFlags(Qt::WindowFlags type)
Definition: qwidget.cpp:10410
QWidget * focus_next
Definition: qwidget_p.h:667
QWidgetRepaintManager * maybeRepaintManager() const
Definition: qwidget_p.h:879
QTLWExtra * topData() const
Definition: qwidget_p.h:847
void invalidateBackingStore(const T &)
The QWindow class represents a window in the underlying windowing system.
Definition: qwindow.h:99
void show()
Definition: qwindow.cpp:2167
virtual bool event(QEvent *) override
Definition: qwindow.cpp:2419
bool close()
Definition: qwindow.cpp:2262
static bool handleTabletEvent(QWindow *window, ulong timestamp, const QPointingDevice *device, const QPointF &local, const QPointF &global, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, int z, Qt::KeyboardModifiers modifiers=Qt::NoModifier)
static bool handleTouchCancelEvent(QWindow *window, const QPointingDevice *device, Qt::KeyboardModifiers mods=Qt::NoModifier)
static void handleEnterEvent(QWindow *window, const QPointF &local=QPointF(), const QPointF &global=QPointF())
void setEllipseEnabled(bool enable=true)
RenderWidget(QWidget *source)
void paintEvent(QPaintEvent *) override
ResizeWidget(QWidget *p=nullptr)
void resizeEvent(QResizeEvent *e) override
void hideEvent(QHideEvent *e) override
QWidget(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
void showEvent(QShowEvent *e) override
bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *) override
void timerEvent(QTimerEvent *) override
bool nativeEvent(const QByteArray &eventType, void *message, qintptr *) override
bool isMapNotify(const QByteArray &eventType, void *message)
SiblingDeleter(QWidget *sibling, QWidget *parent)
void paintEvent(QPaintEvent *e) override
StaticWidget(QWidget *parent=nullptr)
QRegion paintedRegion
void tabletEvent(QTabletEvent *event) override
TabletWidget(QWidget *parent)
bool event(QEvent *ev) override
int trackingChangeEventCount
TestGraphicsEffect(QObject *parent=nullptr)
void setExtent(int extent)
void draw(QPainter *painter) override
QRectF boundingRectFor(const QRectF &sr) const override
void invalidate() override
void mouseDoubleClickEvent(QMouseEvent *) override
TopLevelFocusCheck(QWidget *parent=nullptr)
bool eventFilter(QObject *obj, QEvent *event) override
QList< QTouchEvent::TouchPoint > touchPoints
QPointingDevice * touchDevice
QTouchEvent::TouchPoint::States touchPointStates
TouchMouseWidget(QWidget *parent=nullptr)
void setAcceptTouch(bool accept)
void setAcceptMouse(bool accept)
bool event(QEvent *e) override
QPointF m_lastMouseEventPos
int numZOrderChangeEvents
bool event(QEvent *event) override
bool resizeInPaintEvent
int numUpdateRequestEvents
UpdateWidget(QWidget *parent=nullptr)
bool updateOnActivationChangeAndFocusIn
QRegion paintedRegion
void paintEvent(QPaintEvent *e) override
Definition: widget.h:60
void closeEvent(QCloseEvent *) override
void changeEvent(QEvent *) override
void keyPressEvent(QKeyEvent *) override
void keyReleaseEvent(QKeyEvent *) override
void mouseDoubleClickEvent(QMouseEvent *) override
void actionEvent(QActionEvent *) override
bool deleteThis
void hideEvent(QHideEvent *) override
void mouseMoveEvent(QMouseEvent *) override
void mouseReleaseEvent(QMouseEvent *) override
void mousePressEvent(QMouseEvent *) override
[0]
void focusOutEvent(QFocusEvent *) override
bool eventFilter(QObject *obj, QEvent *event) override
WinIdChangeSpy(QWidget *w, QObject *parent=nullptr)
int winIdChangeEventCount() const
QWidget(QWidget *parent=nullptr, Qt::WindowFlags f=Qt::WindowFlags())
bool event(QEvent *e) override
QList< WId > m_winIdList
virtual ~tst_QWidget()
void cleanup()
void initTestCase()
QPushButton
[1]
float step
#define T(x)
Definition: main.cpp:42
#define this
Definition: dialogs.cpp:56
QOpenGLWidget * widget
[1]
a resize(100000)
QPixmap p2
QPixmap p1
[0]
QPushButton * button
[2]
double pi
[0]
double e
set contains("Julia")
object setObjectName("A new object name")
QSignalSpy spy(myCustomObject, SIGNAL(mySignal(int, QString, double)))
[0]
QCOMPARE(spy.count(), 1)
rect
[4]
palette
else opt state
[0]
#define local
Definition: zutil.h:30
QRhiTextureRenderTarget * rt
Definition: mrt.cpp:84
QList< QWindow * > windows
std::string toLower(std::string const &s)
bool testImage(const QImage &img, QByteArray *msg, bool *error)
T toNativePixels(const T &value, const C *context)
QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind)
T toNativeLocalPosition(const T &value, const C *context)
[15]
Definition: tst_encoder.cpp:33
Q_TESTLIB_EXPORT QTestData & newRow(const char *dataTag)
Definition: qtestcase.cpp:2658
bool qCompare(QString const &t1, QLatin1String const &t2, const char *actual, const char *expected, const char *file, int line)
Definition: qtest.h:411
Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description, const char *file, int line)
Definition: qtestcase.cpp:2207
Q_TESTLIB_EXPORT const char * currentTestFunction()
Definition: qtestcase.cpp:2749
Q_GUI_EXPORT QPointingDevice * createTouchDevice(QInputDevice::DeviceType devType=QInputDevice::DeviceType::TouchScreen, QInputDevice::Capabilities caps=QInputDevice::Capability::Position)
Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window, int timeout=5000)
Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window, int timeout=5000)
void mouseMove(QWindow *window, QPoint pos=QPoint(), int delay=-1)
Definition: qtestmouse.h:175
Q_TESTLIB_EXPORT void ignoreMessage(QtMsgType type, const char *message)
Definition: qtestcase.cpp:2292
void mouseDClick(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey=Qt::KeyboardModifiers(), QPoint pos=QPoint(), int delay=-1)
Definition: qtestmouse.h:171
Q_TESTLIB_EXPORT const char * currentDataTag()
Definition: qtestcase.cpp:2758
void mouseClick(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey=Qt::KeyboardModifiers(), QPoint pos=QPoint(), int delay=-1)
Definition: qtestmouse.h:167
Q_TESTLIB_EXPORT QTestData & addRow(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition: qtestcase.cpp:2690
void mousePress(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey=Qt::KeyboardModifiers(), QPoint pos=QPoint(), int delay=-1)
Definition: qtestmouse.h:159
Q_CORE_EXPORT void qWait(int ms)
QTouchEventSequence touchEvent(QWindow *window, QPointingDevice *device, bool autoCommit=true)
Definition: qtesttouch.h:78
Definition: qnamespace.h:55
WindowState
Definition: qnamespace.h:276
@ WindowFullScreen
Definition: qnamespace.h:280
@ WindowNoState
Definition: qnamespace.h:277
@ WindowMinimized
Definition: qnamespace.h:278
@ WindowMaximized
Definition: qnamespace.h:279
@ CTRL
Definition: qnamespace.h:1096
@ LeftDockWidgetArea
Definition: qnamespace.h:1218
@ LeftButton
Definition: qnamespace.h:83
@ NoButton
Definition: qnamespace.h:82
@ SmoothTransformation
Definition: qnamespace.h:1351
@ WA_WState_ExplicitShowHide
Definition: qnamespace.h:360
@ WA_AcceptTouchEvents
Definition: qnamespace.h:429
@ WA_TransparentForMouseEvents
Definition: qnamespace.h:342
@ WA_PendingResizeEvent
Definition: qnamespace.h:327
@ WA_WindowPropagation
Definition: qnamespace.h:374
@ WA_SetCursor
Definition: qnamespace.h:330
@ WA_Resized
Definition: qnamespace.h:333
@ WA_QuitOnClose
Definition: qnamespace.h:367
@ WA_TranslucentBackground
Definition: qnamespace.h:427
@ WA_DontShowOnScreen
Definition: qnamespace.h:408
@ WA_X11NetWmWindowTypeToolBar
Definition: qnamespace.h:413
@ WA_DropSiteRegistered
Definition: qnamespace.h:372
@ WA_PendingMoveEvent
Definition: qnamespace.h:326
@ WA_PaintOnScreen
Definition: qnamespace.h:315
@ WA_DontCreateNativeAncestors
Definition: qnamespace.h:404
@ WA_Moved
Definition: qnamespace.h:334
@ WA_NativeWindow
Definition: qnamespace.h:403
@ WA_TabletTracking
Definition: qnamespace.h:438
@ WA_WState_Hidden
Definition: qnamespace.h:322
@ WA_StaticContents
Definition: qnamespace.h:313
@ WA_WState_Visible
Definition: qnamespace.h:321
@ WA_NoSystemBackground
Definition: qnamespace.h:316
@ WA_SetFont
Definition: qnamespace.h:329
@ WA_WState_Created
Definition: qnamespace.h:352
@ WA_MouseNoMask
Definition: qnamespace.h:363
@ WA_InputMethodEnabled
Definition: qnamespace.h:320
@ WA_Mapped
Definition: qnamespace.h:318
@ WA_OpaquePaintEvent
Definition: qnamespace.h:312
@ ReplaceClip
Definition: qnamespace.h:1332
@ NonModal
Definition: qnamespace.h:1564
@ WindowModal
Definition: qnamespace.h:1565
@ ApplicationModal
Definition: qnamespace.h:1566
@ KeepAspectRatio
Definition: qnamespace.h:1213
@ WheelFocus
Definition: qnamespace.h:136
@ ClickFocus
Definition: qnamespace.h:134
@ NoFocus
Definition: qnamespace.h:132
@ TabFocus
Definition: qnamespace.h:133
@ StrongFocus
Definition: qnamespace.h:135
@ Vertical
Definition: qnamespace.h:125
@ BlankCursor
Definition: qnamespace.h:1187
@ WaitCursor
Definition: qnamespace.h:1180
@ OpenHandCursor
Definition: qnamespace.h:1194
@ color1
Definition: qnamespace.h:60
@ gray
Definition: qnamespace.h:64
@ white
Definition: qnamespace.h:62
@ transparent
Definition: qnamespace.h:78
@ blue
Definition: qnamespace.h:68
@ yellow
Definition: qnamespace.h:71
@ darkGray
Definition: qnamespace.h:63
@ black
Definition: qnamespace.h:61
@ lightGray
Definition: qnamespace.h:65
@ color0
Definition: qnamespace.h:59
@ green
Definition: qnamespace.h:67
@ red
Definition: qnamespace.h:66
@ Key_Tab
Definition: qnamespace.h:685
@ Key_C
Definition: qnamespace.h:574
@ Key_Shift
Definition: qnamespace.h:704
@ Key_A
Definition: qnamespace.h:572
@ ControlModifier
Definition: qnamespace.h:1076
@ NoModifier
Definition: qnamespace.h:1074
@ AA_DontCreateNativeWidgetSiblings
Definition: qnamespace.h:454
@ CaseInsensitive
Definition: qnamespace.h:1283
@ DiagCrossPattern
Definition: qnamespace.h:1154
@ TexturePattern
Definition: qnamespace.h:1158
@ QueuedConnection
Definition: qnamespace.h:1307
@ TapAndHoldGesture
Definition: qnamespace.h:1643
QTextStream & center(QTextStream &stream)
WindowType
Definition: qnamespace.h:230
@ CustomizeWindowHint
Definition: qnamespace.h:264
@ Widget
Definition: qnamespace.h:231
@ FramelessWindowHint
Definition: qnamespace.h:250
@ MSWindowsOwnDC
Definition: qnamespace.h:247
@ ToolTip
Definition: qnamespace.h:238
@ Drawer
Definition: qnamespace.h:235
@ Popup
Definition: qnamespace.h:236
@ WindowType_Mask
Definition: qnamespace.h:245
@ Window
Definition: qnamespace.h:232
@ SplashScreen
Definition: qnamespace.h:239
@ WindowStaysOnTopHint
Definition: qnamespace.h:258
@ Dialog
Definition: qnamespace.h:233
@ Sheet
Definition: qnamespace.h:234
@ SubWindow
Definition: qnamespace.h:241
@ Tool
Definition: qnamespace.h:237
@ X11BypassWindowManagerHint
Definition: qnamespace.h:249
@ WindowSystemMenuHint
Definition: qnamespace.h:252
@ OtherFocusReason
Definition: qnamespace.h:1368
@ TouchPointReleased
Definition: qnamespace.h:1625
@ TouchPointPressed
Definition: qnamespace.h:1622
@ TouchPointMoved
Definition: qnamespace.h:1623
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
Definition: brush.cpp:52
Definition: image.cpp:51
const char * sizePolicy(int v)
Definition: language.cpp:146
MyMainWidget mySession(nullptr)
#define QString()
Definition: parse-defines.h:51
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld cleanup[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld SRC pixld MASK if DST_R else pixld DST_R endif if src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head if pixblock_size cache_preload_simple endif process_pixblock_tail pixinterleave dst_w_basereg irp if pixblock_size chunk_size tst beq if DST_W else pixst DST_W else mov ORIG_W endif add lsl if lsl endif if lsl endif lsl endif lsl endif lsl endif subs mov DST_W if regs_shortage str endif bge start_of_loop_label endm macro generate_composite_function
set set set set set set set macro pixldst1 op
png_structrp int png_fixed_point red
Definition: png.h:1081
#define QByteArrayLiteral(str)
Definition: qbytearray.h:80
#define rgb(r, g, b)
Definition: qcolor.cpp:157
#define Q_FUNC_INFO
std::pair< T1, T2 > QPair
Definition: qcontainerfwd.h:56
#define qApp
EGLOutputLayerEXT EGLint attribute
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition: qfloat16.h:233
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition: qfloat16.h:249
unsigned long ulong
Definition: qglobal.h:335
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
unsigned int uint
Definition: qglobal.h:334
long long qint64
Definition: qglobal.h:298
ptrdiff_t qintptr
Definition: qglobal.h:309
#define qGuiApp
@ text
#define qDebug
[1]
Definition: qlogging.h:177
@ QtWarningMsg
Definition: qlogging.h:62
#define qWarning
Definition: qlogging.h:179
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define SLOT(a)
Definition: qobjectdefs.h:87
GLenum GLuint GLenum GLsizei const GLchar * message
Definition: qopengl.h:270
GLint GLfloat GLfloat GLfloat v2
GLboolean GLboolean GLboolean b
GLuint64 GLenum void * handle
GLint GLint GLint GLint GLint x
[0]
GLboolean r
[2]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLfloat GLfloat f
GLint GLsizei width
GLuint color
[2]
GLuint GLsizei const GLchar * label
[43]
GLenum target
GLbitfield flags
GLint GLfloat GLfloat v1
GLboolean enable
GLuint start
GLenum GLuint GLintptr offset
GLuint name
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLeglImageOES image
struct _cl_event * event
Definition: qopenglext.h:2998
GLuint GLenum GLenum transform
Definition: qopenglext.h:11564
GLhandleARB obj
[2]
Definition: qopenglext.h:4164
GLboolean reset
Definition: qopenglext.h:2748
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble GLdouble w2
Definition: qopenglext.h:12395
const GLubyte * c
Definition: qopenglext.h:12701
GLint void * img
Definition: qopenglext.h:233
GLuint GLuint GLuint GLuint arg1
Definition: qopenglext.h:6221
GLuint GLuint GLuint GLuint GLuint GLuint GLuint GLuint GLuint GLuint arg3
Definition: qopenglext.h:6223
GLuint GLuint GLuint GLuint GLuint GLuint GLuint arg2
Definition: qopenglext.h:6222
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap
Definition: qopenglext.h:5182
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLenum GLenum GLsizei void * row
Definition: qopenglext.h:2747
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble w1
Definition: qopenglext.h:12395
GLubyte * pattern
Definition: qopenglext.h:2744
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition: qpair.h:55
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition: qrgb.h:49
constexpr QRgb qRgba(int r, int g, int b, int a)
Definition: qrgb.h:69
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition: qscopeguard.h:93
QPointF qAbs(const QPointF &p)
Definition: qscroller.cpp:119
SSL_CTX int(*) void arg)
#define QStringLiteral(str)
#define sp
#define tr(X)
#define QTEST_MAIN(TestObject)
Definition: qtest.h:664
#define QSKIP(statement,...)
Definition: qtestcase.h:222
#define QFETCH(Type, name)
Definition: qtestcase.h:230
#define QTRY_COMPARE_WITH_TIMEOUT(expr, expected, timeout)
Definition: qtestcase.h:208
#define QEXPECT_FAIL(dataIndex, comment, mode)
Definition: qtestcase.h:224
#define QTRY_COMPARE(expr, expected)
Definition: qtestcase.h:214
#define QVERIFY(statement)
Definition: qtestcase.h:64
#define QTRY_VERIFY(expr)
Definition: qtestcase.h:196
#define QVERIFY2(statement, description)
Definition: qtestcase.h:76
#define QTRY_VERIFY2(expr, messageExpression)
Definition: qtestcase.h:205
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define slots
Definition: qtmetamacros.h:76
#define signals
Definition: qtmetamacros.h:77
#define emit
Definition: qtmetamacros.h:85
@ desc
Q_WIDGETS_EXPORT QWidgetPrivate * qt_widget_private(QWidget *widget)
Definition: qwidget.cpp:12216
#define QWIDGETSIZE_MAX
Definition: qwidget.h:951
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition: qwidget.h:819
const char className[16]
[1]
Definition: qwizard.cpp:135
Q_UNUSED(salary)
[21]
view show()
[18] //! [19]
QWidget * win
Definition: settings.cpp:53
QScreen * screen
[1]
Definition: main.cpp:76
QPropertyAnimation * animation
[0]
QIcon icon
[15]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QPointer< QFile > fp(new QFile)
[11]
QPushButton * pushButton
obj metaObject() -> className()
QList< QWidget * > widgets
[11]
QVBoxLayout * layout
QLineEdit * lineEdit
QString title
[35]
QTimer * timer
[3]
QString three
QFileDialog dialog(this)
[1]
QGraphicsScene scene
[0]
form setLayout(layout)
item setCursor(Qt::IBeamCursor)
[1]
view viewport() -> scroll(dx, dy, deviceRect)
edit hide()
app setAttribute(Qt::AA_DontShowIconsInMenus)
QPointer< QLineEdit > le
QLayoutItem * child
[0]
w setWindowState(w->windowState() ^ Qt::WindowFullScreen)
[0]
widget render & pixmap
QPainter painter(this)
[7]
aWidget window() -> setWindowTitle("New Window Title")
[2]
myWidget render(this)
QFrame frame
[0]
QCalendarWidget * calendar
[0]
QDockWidget * dockWidget
[0]
QMenu menu
[5]
widget setSizePolicy(policy)
backaction setToolTip(browser.historyTitle(-1))
[0]
view create()
QWidget myWindow
[26]
std::unique_ptr< QWidgetRepaintManager > repaintManager
Definition: qwidget_p.h:129
Definition: main.cpp:38
bool eventFilter(QObject *receiver, QEvent *event) override
WindowStateChangeWatcher(QWidget *widget)
Qt::WindowStates lastWindowStates
Definition: jquant2.c:237
Global global
Definition: main.cpp:114
#define main
[0]
QThreadStorage< int * > dummy[8]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent
XmlOutput::xml_output tag(const QString &name)
Definition: xmloutput.h:154