Support window activation on wayland

This is a bit hacky, because we open a window to actually get a valid
activation token, but...
This commit is contained in:
Nicolas Werner 2023-11-20 03:20:26 +01:00
parent 8ea03e41e0
commit 234e05eef3
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
3 changed files with 53 additions and 3 deletions

View file

@ -117,6 +117,7 @@ build-tw:
"cmake(Qt6Widgets)" "cmake(Qt6Widgets)"
"cmake(Qt6Gui)" "cmake(Qt6Gui)"
"qt6-qml-private-devel" "qt6-qml-private-devel"
"qt6-gui-private-devel"
"pkgconfig(libcurl)" "pkgconfig(libcurl)"
"pkgconfig(libevent)" "pkgconfig(libevent)"
"pkgconfig(gstreamer-webrtc-1.0)" "pkgconfig(gstreamer-webrtc-1.0)"

View file

@ -902,6 +902,10 @@ target_link_libraries(nheko PRIVATE
lmdbxx::lmdbxx lmdbxx::lmdbxx
liblmdb::lmdb) 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") if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0")
target_precompile_headers(nheko target_precompile_headers(nheko

View file

@ -10,7 +10,6 @@
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QFontDatabase> #include <QFontDatabase>
#include <QGuiApplication>
#include <QLabel> #include <QLabel>
#include <QLibraryInfo> #include <QLibraryInfo>
#include <QMessageBox> #include <QMessageBox>
@ -20,6 +19,10 @@
#include <QStandardPaths> #include <QStandardPaths>
#include <QTranslator> #include <QTranslator>
#ifdef Q_OS_UNIX
#include <QtGui/qpa/qplatformwindow_p.h>
#endif
#include <kdsingleapplication.h> #include <kdsingleapplication.h>
#include "Cache.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 // This check needs to happen _after_ process(), so that we actually print help for --help when
// Nheko is already running. // Nheko is already running.
if (!singleapp.isPrimaryInstance()) { 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 // open uri in main instance
// TODO(Nico): Send also an activation token. // TODO(Nico): Send also an activation token.
singleapp.sendMessage("activate"); singleapp.sendMessage("activate" + token);
if (!matrixUri.isEmpty()) { if (!matrixUri.isEmpty()) {
std::cout << "Sending Matrix URL to main application: " << matrixUri.toStdString() std::cout << "Sending Matrix URL to main application: " << matrixUri.toStdString()
@ -400,6 +440,11 @@ main(int argc, char *argv[])
ChatPage::instance(), ChatPage::instance(),
[&](QByteArray message) { [&](QByteArray message) {
if (message.isEmpty() || message.startsWith("activate")) { 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.show();
w.raise(); w.raise();
w.requestActivate(); w.requestActivate();