summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2023-11-20 03:20:26 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2023-11-20 13:31:51 +0100
commit234e05eef3c6c2894ee7467efd20f7ebe03e3494 (patch)
treeffe3681721fc69677d01b65935392fb1712b0e44
parentSwitch to KDSingleApplication (diff)
downloadnheko-234e05eef3c6c2894ee7467efd20f7ebe03e3494.tar.xz
Support window activation on wayland
This is a bit hacky, because we open a window to actually get a valid
activation token, but...
-rw-r--r--.gitlab-ci.yml1
-rw-r--r--CMakeLists.txt4
-rw-r--r--src/main.cpp51
3 files changed, 53 insertions, 3 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5476f1ac..b8b1c247 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -117,6 +117,7 @@ build-tw:
         "cmake(Qt6Widgets)"
         "cmake(Qt6Gui)"
         "qt6-qml-private-devel"
+        "qt6-gui-private-devel"
         "pkgconfig(libcurl)"
         "pkgconfig(libevent)"
         "pkgconfig(gstreamer-webrtc-1.0)"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7f7eb942..53501db6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -902,6 +902,10 @@ target_link_libraries(nheko PRIVATE
     lmdbxx::lmdbxx
     liblmdb::lmdb)
     
+if(UNIX)
+    # for wayland activation tokens
+    target_link_libraries(nheko PRIVATE Qt::GuiPrivate)
+endif()
 
 if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0")
     target_precompile_headers(nheko
diff --git a/src/main.cpp b/src/main.cpp
index e740b27a..3cf794f8 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -10,7 +10,6 @@
 #include <QDir>
 #include <QFile>
 #include <QFontDatabase>
-#include <QGuiApplication>
 #include <QLabel>
 #include <QLibraryInfo>
 #include <QMessageBox>
@@ -20,6 +19,10 @@
 #include <QStandardPaths>
 #include <QTranslator>
 
+#ifdef Q_OS_UNIX
+#include <QtGui/qpa/qplatformwindow_p.h>
+#endif
+
 #include <kdsingleapplication.h>
 
 #include "Cache.h"
@@ -248,10 +251,47 @@ main(int argc, char *argv[])
     // This check needs to happen _after_ process(), so that we actually print help for --help when
     // Nheko is already running.
     if (!singleapp.isPrimaryInstance()) {
-        std::cout << "Activating main app (instead of opening it a second time)." << std::endl;
+        auto token = qgetenv("XDG_ACTIVATION_TOKEN");
+
+#ifdef Q_OS_UNIX
+        // getting a valid activation token on wayland is a bit of a pain, it works most reliably
+        // when you have an actual window, that has the focus...
+        auto waylandApp = app.nativeInterface<QNativeInterface::QWaylandApplication>();
+        if (waylandApp) {
+            QQuickView window;
+            window.setTitle("Activate main instance");
+            window.setMaximumSize(QSize(100, 50));
+            window.setMinimumSize(QSize(100, 50));
+            window.setResizeMode(QQuickView::ResizeMode::SizeRootObjectToView);
+            window.setSource(QUrl(QStringLiteral("qrc:///resources/qml/ui/Spinner.qml")));
+            window.show();
+            auto waylandWindow =
+              window.nativeInterface<QNativeInterface::Private::QWaylandWindow>();
+            if (waylandWindow) {
+                std::cout << "Launching temp window to activate main instance!\n";
+                QObject::connect(
+                  waylandWindow,
+                  &QNativeInterface::Private::QWaylandWindow::xdgActivationTokenCreated,
+                  waylandWindow,
+                  [&token, &app](QString newToken) { // clazy:exclude=lambda-in-connect
+                      token = newToken.toUtf8();
+                      app.exit();
+                  },
+                  Qt::SingleShotConnection);
+                QTimer::singleShot(100, waylandWindow, [waylandWindow, waylandApp] {
+                    waylandWindow->requestXdgActivationToken(waylandApp->lastInputSerial());
+                });
+                app.exec();
+            }
+        }
+#endif
+
+        std::cout << "Activating main app (instead of opening it a second time)."
+                  << token.toStdString() << std::endl;
+
         //  open uri in main instance
         //  TODO(Nico): Send also an activation token.
-        singleapp.sendMessage("activate");
+        singleapp.sendMessage("activate" + token);
 
         if (!matrixUri.isEmpty()) {
             std::cout << "Sending Matrix URL to main application: " << matrixUri.toStdString()
@@ -400,6 +440,11 @@ main(int argc, char *argv[])
       ChatPage::instance(),
       [&](QByteArray message) {
           if (message.isEmpty() || message.startsWith("activate")) {
+              auto token = message.remove(0, sizeof("activate") - 1);
+              if (!token.isEmpty()) {
+                  nhlog::ui()->debug("Setting activation token to: {}", token.toStdString());
+                  qputenv("XDG_ACTIVATION_TOKEN", token);
+              }
               w.show();
               w.raise();
               w.requestActivate();