Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-61977

QPA sends events durning platform window construction

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • None
    • 5.10
    • QPA: Windows
    • None

    Description

      QWindow calls QPlatformIntegration::createPlatformWindow() from create(), and assigns the result to d->platformWindow. 

      There's currently nothing preventing the platform from delivering synchronous QPA events during that createPlatformWindow call, in which the QWindow will not have a valid handle() yet.

      This can typically happen when creating the native window handle results in native callbacks for geometry or expose changes, as seen on e.g. macOS and Windows:

      
        * frame #0: 0x00007fff892b891a libsystem_kernel.dylib`__wait4_nocancel + 10
           frame #1: 0x00007fff8c48921c libsystem_c.dylib`system + 459
           frame #2: 0x000000010695ada4 QtTest`stackTrace() + 164
           frame #3: 0x000000010695acb5 QtTest`QTest::FatalSignalHandler::signal(int) + 197
           frame #4: 0x00007fff94fe0f1a libsystem_platform.dylib`_sigtramp + 26
           frame #5: 0x0000000108c35a35 libqcocoa.dylib`QRasterBackingStore::beginPaint(QRegion const&) + 37
           frame #6: 0x00000001060438cc QtGui`QBackingStore::beginPaint(QRegion const&) + 364
           frame #7: 0x0000000105e8a739 tst_qbackingstore`Window::exposeEvent(QExposeEvent*) + 89
           frame #8: 0x0000000105ed0d4e QtGui`QWindow::event(QEvent*) + 254
           frame #9: 0x00000001065b30cf QtCore`QCoreApplicationPrivate::notify_helper(QObject*, QEvent*) + 303
           frame #10: 0x00000001065b2d2d QtCore`QCoreApplication::notify(QObject*, QEvent*) + 45
           frame #11: 0x00000001065b2c84 QtCore`QCoreApplication::notifyInternal2(QObject*, QEvent*) + 164
           frame #12: 0x0000000105ec54d4 QtGui`QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent*) + 308
           frame #13: 0x0000000105ea58f3 QtGui`bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterface::SynchronousDelivery>(QWindowSystemInterfacePrivate::WindowSystemEvent*) + 99
           frame #14: 0x0000000105eab903 QtGui`void QWindowSystemInterface::handleExposeEvent<QWindowSystemInterface::SynchronousDelivery>(QWindow*, QRegion const&) + 467
           frame #15: 0x0000000108b4edfa libqcocoa.dylib`QCocoaWindow::handleExposeEvent(QRegion const&) + 618
           frame #16: 0x0000000108b556ea libqcocoa.dylib`-[QNSView drawRect:] + 922
           frame #17: 0x00007fff8fc6c689 AppKit`-[NSView _drawRect:clip:] + 4238
           frame #18: 0x00007fff8fc6acfa AppKit`-[NSView _recursiveDisplayAllDirtyWithLockFocus:visRect:] + 1875
           frame #19: 0x00007fff8fc6b0fe AppKit`-[NSView _recursiveDisplayAllDirtyWithLockFocus:visRect:] + 2903
           frame #20: 0x00007fff8fc68b96 AppKit`-[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:] + 913
           frame #21: 0x00007fff8fc682f3 AppKit`-[NSThemeFrame _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:] + 333
           frame #22: 0x00007fff8fc6468b AppKit`-[NSView _displayRectIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:] + 2761
           frame #23: 0x00007fff8fc1c1ae AppKit`-[NSView displayIfNeeded] + 1876
           frame #24: 0x00007fff8fc612af AppKit`-[NSThemeFrame handleSetFrameCommonRedisplay] + 251
           frame #25: 0x00007fff8fc5990d AppKit`-[NSWindow _setFrameCommon:display:stashSize:] + 3570
           frame #26: 0x00007fff8fd16895 AppKit`-[NSWindow setFrame:display:animate:] + 147
           frame #27: 0x00007fff8fe0d6e3 AppKit`-[NSWindow zoom:] + 808
           frame #28: 0x0000000108b4b3e0 libqcocoa.dylib`QCocoaWindow::applyWindowState(QFlags<Qt::WindowState>) + 848
           frame #29: 0x0000000108b492fa libqcocoa.dylib`QCocoaWindow::recreateWindowIfNeeded() + 1946
           frame #30: 0x0000000108b488b4 libqcocoa.dylib`QCocoaWindow::QCocoaWindow(QWindow*, unsigned long long) + 1140
           frame #31: 0x0000000108b44b64 libqcocoa.dylib`QCocoaIntegration::createPlatformWindow(QWindow*) const + 36
           frame #32: 0x0000000105ecd71c QtGui`QWindowPrivate::create(bool, unsigned long long) + 108
           frame #33: 0x0000000105ecbc7e QtGui`QWindowPrivate::setVisible(bool) + 382
      
      00000081`9dafda90 00007ff9`3cc5a74e Qt5Guid!QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::DefaultDelivery>(class QWindow * window = 0x000001d7`adb08cf0, class QRect * newRect = 0x00000081`9dafdc64, class QRect * oldRect = 0x00000081`9dafdd80)+0x13 [d:\projects\qt5-dev\qtbase\src\gui\kernel\qwindowsysteminterface.cpp @ 281]
      00000081`9dafdb00 00007ff9`33acf2bd qwindowsd!QWindowsIntegration::createPlatformWindow(class QWindow * window = 0x000001d7`adb08cf0)+0x7ee [d:\projects\qt5-dev\qtbase\src\plugins\platforms\windows\qwindowsintegration.cpp @ 357]
      00000081`9dafde80 00007ff9`33ac9c07 Qt5Guid!QWindowPrivate::create(bool recursive = false, unsigned int64 nativeHandle = 0)+0xad [d:\projects\qt5-dev\qtbase\src\gui\kernel\qwindow.cpp @ 503]
      00000081`9dafdf80 00000000`5a5d1d4d Qt5Guid!QWindow::create(void)+0x27 [d:\projects\qt5-dev\qtbase\src\gui\kernel\qwindow.cpp @ 622]
      00000081`9dafdfc0 00000000`5a5cf366 Qt5Widgetsd!QWidgetPrivate::create_sys(unsigned int64 window = 0, bool initializeWindow = true, bool destroyOldWindow = true)+0x57d [d:\projects\qt5-dev\qtbase\src\widgets\kernel\qwidget.cpp @ 1479]
      00000081`9dafe100 00000000`5a5c6deb Qt5Widgetsd!QWidget::create(unsigned int64 window = 0, bool initializeWindow = true, bool destroyOldWindow = true)+0x2e6 [d:\projects\qt5-dev\qtbase\src\widgets\kernel\qwidget.cpp @ 1340]
      00000081`9dafe170 00000000`5a5c73f9 Qt5Widgetsd!QWidget::setVisible(bool visible = true)+0x15b [d:\projects\qt5-dev\qtbase\src\widgets\kernel\qwidget.cpp @ 8169]
      00000081`9dafe230 00007ff6`076081b0 Qt5Widgetsd!QWidget::show(void)+0x79 [d:\projects\qt5-dev\qtbase\src\widgets\kernel\qwidget.cpp @ 7770]
      

      All user and Qt code should of course ideally guard against this, checking for a handle(), but we have a few cases that don't, e.g. QBackingStore, resulting in crashes.

      The bigger issue however is that those events are sent from the platform thinking they will be handled, so we may end up sending only one expose event, which gets ignored (during painting, by QBackingStore once that's fixed), and then the window never sees another expose event.

      One way to fix this would be to tag QWindows during create, and teach QPA to que up any events for window in this state, even if sent synchronously or flushed explicitly, and then have QWindowPrivate::create flush those events once done creating the window.

      The downside is that events that the native platform expected synchronous delivery of, are now delivered async, so we should probably couple this with adding a QPlatformWindow::initialize(), that QWindowPrivate::create() calls after createPlatformWindow().

      Ideally platforms would do as little as possible in the QPlatformWindow constructor, and move all init logic to initialize(). The former solution with QPA having logic to defer events, would be a safe-guard for platform that still use the constructor for init, or for the cases where things in the constructor accidentally trigger events.

       

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              vestbo Tor Arne Vestbø
              vestbo Tor Arne Vestbø
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes