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

[REG 5.15->6.X] QWidget embedded in native window display popup menus at wrong position

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P2: Important
    • None
    • 5.15.1, 6.1.0 Beta 1
    • None
    • macOS 10.15, Qt 5.15 & 6.1, single monitor
    • macOS

    Description

      In Qt 5.15 and earlier, there was a QMacNativeWidget class to embed a QWidget inside a native window, which is specially useful when creating plugins using Qt inside other non-Qt apps.

      Since Qt 6.0 the QMacNativeWidget class was removed ( QTBUG-83254 ), and fully replaced by QWindow::fromWinId, which allows creating a QWindow from a native window handle.
      From there, you can assign your main app QWidget to it like this:

      windowHandle()->setParent(nativeWindow);
      move(0,0);

       

      And this works pretty well on both macOS and Windows... Except for one issue on macOS: popup menus appear at the wrong position (see attached screenshots at the end of this post).

      The only instance where the popup menus are correctly positioned is when the globalPos is directly accessible, for instance when invoking a contextual menu.

      Here's a recap of when popup menu position works/doesn't work: 
      Qt 5.15, macOS, QMacNativeWidget: OK
      Qt 5.15, macOS, QWindow::fromWinId: NOT OK
      Qt 6.1, macOS, QWindow::fromWinId: NOT OK
      Qt 6.1, Windows, QWindow::fromWinId: OK

      Here's the minimal code to repro the issue, corresponding to the attached screenshots:

      //project.pro
      QT = core gui widgets
      SOURCES += main.mm
      //main.mm
      #import <Cocoa/Cocoa.h>
      
      #include <QApplication>
      #include <QtWidgets>
      
      int main(int argc, char *argv[])
      {
          //////////////////
          //NATIVE HOST VIEW
          //////////////////
      
          //Create a NSWindow
          [NSApplication sharedApplication];
          [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
          id applicationName = [[NSProcessInfo processInfo] processName];
          id window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 256, 256)
              styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO];
          [window cascadeTopLeftFromPoint:NSMakePoint(20,20)];
          [window setTitle: applicationName];
          [window makeKeyAndOrderFront:nil];
          [NSApp activateIgnoringOtherApps:YES];
      
          //Create a NSView
          NSRect frameRect = NSMakeRect(0, 0 , 256, 256);
          NSView* view = [[NSView alloc] initWithFrame:frameRect];
          [view setHidden:NO];
          [view setNeedsDisplay:YES];
          [window setContentView:view];
      
      
          ////////////////////
          //EMBEDDED QT WIDGET
          ////////////////////
      
          //Create a Qt app and a QWindow from the NSView handle
          QApplication* a=new QApplication(argc, argv);
      
          QWindow* qwindow=QWindow::fromWinId((WId)view);
          QWidget* widget=new QWidget();
      
          //Add a contextual menu to the main widget (right click to show)
          widget->setContextMenuPolicy(Qt::ActionsContextMenu);
          widget->addAction(new QAction("Context Action 1"));
          widget->addAction(new QAction("Context Action 2"));
          widget->addAction(new QAction("Context Action 3"));
      
          //Add actions to the tool button (long click the tool button to show)
          QToolButton* toolButton=new QToolButton();
          QMenu* menu=new QMenu();
          menu->addAction(new QAction("Toolbutton Action 1"));
          menu->addAction(new QAction("Toolbutton Action 2"));
          menu->addAction(new QAction("Toolbutton Action 3"));
          toolButton->setMenu(menu);
      
          //Add items to the combo box (click the combo box to show)
          QComboBox* comboBox=new QComboBox();
          comboBox->addItem("Combo Item 1");
          comboBox->addItem("Combo Item 2");
          comboBox->addItem("Combo Item 3");
      
          //Set the layout of the main widget
          QVBoxLayout* layout=new QVBoxLayout();
          layout->addWidget(toolButton);
          layout->addWidget(comboBox);
          widget->setLayout(layout);
      
          //Show the main widget, and assign it to the QWindow
          widget->show();
          widget->move(0,0);
          widget->windowHandle()->setParent(qwindow);
      
          a->exec();
      
          [NSApp run];
      
          return 0;
      }
      

      Also attached as a zip file to this issue.

      Attachments

        1. MacEmbed.zip
          2 kB
        2. MacEmbed2.zip
          2 kB
        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
            divide Robin Lobel
            Votes:
            3 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes