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

Popups and menus sink behind modal windows

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P3: Somewhat important
    • None
    • 5.15.1
    • Widgets: Main Window
    • None
    • Mac OS 11.0.1 ARM, XPC, Motion 5.5/Final Cut 10.5
    • macOS

    Description

      I am implementing a Qt based UI for an XPC service called by another application (Motion, Final Cut).
      The main window of my app has ApplicatonModal flag set.
      I observe that all transients: Menus, Popup menus, Tooltips еtc. end up behind the main window OR behind any other modal window opened on top of the main window.

      Even though the root cause of this behaviour is still not clear to me, while searching for the solution I noticed that Qt internally has a notion of transientParent that it tracks. I also noticed that all transients are created as top-level cocoa windows and they are not connected to the windows hierarchy. This fact can add to the problem.

      Cocoa has an NSWindow::addChildWindow:ordered: interface that can be used to establish the parent-child relationship between windows. For some reason unclear to me, Qt does not use this interface and resorts to all top-level windows instead. I am no expert in Qt, so you guys might shed some light on the idea behind this design decision.

      Anyways, to workaround the problem that I'm fighting with, I came up with this:

      --- qcocoawindow.mm.bak Mon May 11 18:45:08 2020
       +++ qcocoawindow.mm Thu Feb 04 20:22:32 2021
       @@ -192,6 +192,14 @@
       qCDebug(lcQpaWindow) << "QCocoaWindow::~QCocoaWindow" << window();
      
      QMacAutoReleasePool pool;
       +
       + if (window()->transientParent())
       +
      
      { + QCocoaWindow *parentCocoaWindow = parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle()); + [parentCocoaWindow->nativeWindow() removeChildWindow:nativeWindow()]; + }
      
      +
       +
       [m_nsWindow makeFirstResponder:nil];
       [m_nsWindow setContentView:nil];
       if ([m_view superview])
       @@ -324,7 +332,10 @@
       QMacAutoReleasePool pool;
       QCocoaWindow *parentCocoaWindow = nullptr;
       if (window()->transientParent())
       +
      
      { parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle()); + [parentCocoaWindow->nativeWindow() addChildWindow:nativeWindow() ordered:NSWindowAbove]; + }
      
      auto eventDispatcher = [] {
       return static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(qApp->eventDispatcher()));
       }}
      

      This patch is pretty dirty. I would rather channel the call to setTransientParent() through QWindow to QPlatformWindow to QCocoaWindow. I don't want to complicate things until it is clear enough as I may be completely off and should look elsewhere, hope you guys can point me to the right direction.

      Attachments

        1. patch.diff
          1 kB
          Sergei Kulik
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            qt.team.quick.subscriptions Qt Quick and Widgets Team
            skoulik Sergei Kulik
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes