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

[macOS] Foreign window support not working

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • None
    • 5.12.3
    • None
    • macOS

    Description

      The foreign window support on macos is really in a bad shape, to not say it does not works at all.
      There is various issues:

      • WId from same process
        • Foreign window geometry is modified - it should not
        • Deleting the foreign window lead to foreign window corruption (content can no longer be rendered and errors are throws)
      #include <QtGui>
      #include <QtWidgets>
      
      // Mimic KwindowSystem::setMainWindow
      void KWindowSystemSetMainWindow(QWidget *subWidget, WId mainWindowId) {
          // Set the WA_NativeWindow attribute to force the creation of the QWindow.
          // Without this QWidget::windowHandle() returns 0.
          subWidget->setAttribute(Qt::WA_NativeWindow, true);
          QWindow *subWindow = subWidget->windowHandle();
          Q_ASSERT(subWindow);
      
          QWindow *mainWindow = QWindow::fromWinId(mainWindowId);
          if (!mainWindow) {
              // foreign windows not supported on all platforms
              return;
          }
      
          // mainWindow is not the child of any object, so make sure it gets deleted at some point
          QObject::connect(subWidget, &QObject::destroyed, mainWindow, &QObject::deleteLater);
          subWindow->setTransientParent(mainWindow);
      }
      
      class D : public QDialog {
      public:
          explicit D(QWidget *parent = nullptr)
              : QDialog(parent)
          {
              auto closeButton = new QPushButton(QString::fromLatin1("Close"));
              connect(closeButton, &QPushButton::clicked, this, &QDialog::accept);
      
              auto vLayout = new QVBoxLayout(this);
      
              vLayout->addWidget(closeButton);
          }
      };
      
      class W : public QMainWindow {
      public:
          explicit W(QWidget *parent = nullptr)
              : QMainWindow(parent)
          {
              auto autoDelete = new QCheckBox(QString::fromLatin1("Dlg DeleteOnClose"));
              auto usePointer = new QCheckBox(QString::fromLatin1("Dlg use pointer"));
      
              auto inProcess = new QPushButton(QString::fromLatin1("In-Process"));
              connect(inProcess, &QPushButton::clicked, this, [this, autoDelete, usePointer]() {
                  process(winId(), autoDelete->isChecked(), usePointer->isChecked());
              });
      
              auto outProcess = new QPushButton(QString::fromLatin1("Out-Process"));
              connect(outProcess, &QPushButton::clicked, this, [this, autoDelete, usePointer]() {
                  const QString cmd = QApplication::applicationFilePath();
                  const QStringList args = { QString::number(winId()),
                                             QString::number(autoDelete->isChecked() ? 1 : 0),
                                             QString::number(usePointer->isChecked() ? 1 : 0) };
                  QProcess::startDetached(cmd, args);
              });
      
              auto centralWidget = new QWidget(this);
              auto vLayout = new QVBoxLayout(centralWidget);
      
              vLayout->addWidget(autoDelete);
              vLayout->addWidget(usePointer);
              vLayout->addWidget(inProcess);
              vLayout->addWidget(outProcess);
      
              setCentralWidget(centralWidget);
          }
      
          void process(WId id, bool autoDelete, bool usePointer) {
              qWarning() << Q_FUNC_INFO << id << autoDelete << usePointer;
      
              const auto setup = [id, autoDelete](QDialog *dlg) {
                  dlg->setAttribute(Qt::WA_DeleteOnClose, autoDelete);
                  KWindowSystemSetMainWindow(dlg, id);
                  dlg->exec();
              };
      
              if (usePointer) {
                  auto d = new D;
                  setup(d);
              } else {
                  D d;
                  setup(&d);
              }
          }
      };
      
      int main(int argc, char *argv[])
      {
          QApplication app(argc, argv);
          QApplication::setApplicationName(QFileInfo(QString::fromLatin1(argv[0])).baseName());
          QApplication::setApplicationDisplayName(QApplication::applicationName());
      
          const WId id = argc > 1
                  ? static_cast<quintptr>(QString::fromLatin1(argv[1]).toULongLong())
                  : 0;
          const bool deleteOnClose = argc > 2
                  ? QString::fromLatin1(argv[2]).toInt() == 1
                  : 0;
          const bool usePointer = argc > 3
                  ? QString::fromLatin1(argv[3]).toInt() == 1
                  : 0;
      
          W w;
          w.setWindowTitle(QApplication::applicationDisplayName());
      
          if (id != 0) {
              w.process(id, deleteOnClose, usePointer);
          } else {
              w.show();
          }
      
          return app.exec();
      }
      

      Attachments

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

        Activity

          People

            vestbo Tor Arne Vestbø
            filipe.azevedo Filipe Azevedo
            Veli-Pekka Heinonen Veli-Pekka Heinonen
            Votes:
            2 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes