From 4b61607094dc9a9f95e4c83f72ba9a67d99519c4 Mon Sep 17 00:00:00 2001
From: tanyulong <tanyulong@kylinos.cn>
Date: Sat, 31 Jul 2021 09:56:25 +0800
Subject: [PATCH] Fix multi process contention for the DBusName in VNC
 environment

---
 src/main.cpp         | 59 ++++++++++++++++++++++++++++++++++++++------
 src/ukws_common.h    |  4 +++
 src/ukws_manager.cpp | 20 +++++++++------
 3 files changed, 69 insertions(+), 14 deletions(-)

diff --git a/src/main.cpp b/src/main.cpp
index ae0442f..4f02dc0 100755
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -37,6 +37,7 @@
 #include <QCommandLineOption>
 #include <QCommandLineParser>
 #include <QStyleFactory>
+#include <QProcess>
 
 #include <stdio.h>
 #include <sys/file.h>
@@ -161,18 +162,62 @@ void msgHandler(QtMsgType type, const QMessageLogContext& context, const QString
         abort();
 }
 
+bool startUkws(QString serviceName) {
+    bool dbusIsReady = false;
+
+    QProcess *newUkws = new QProcess();
+    newUkws->setProgram("/usr/bin/ukui-window-switch");
+    newUkws->setStandardOutputFile("/dev/null");
+    newUkws->setStandardErrorFile("/dev/null");
+    newUkws->startDetached();
+
+    QTime curTime = QTime::currentTime();
+    curTime.start();
+
+    while (curTime.elapsed() < 1100) {
+        QDBusInterface interface(serviceName, UKWS_DBUS_PATH, UKWS_DBUS_INTERFACE,
+                                    QDBusConnection::sessionBus());
+        if (!interface.isValid()) {
+            usleep(250 * 1000);
+        } else {
+            dbusIsReady = true;
+            break;
+        }
+    }
+
+    if (dbusIsReady) {
+        qInfo() << "ukui-window-switch is started";
+        return true;
+    } else {
+        qInfo() << "ukui-window-switch start failed";
+        return false;
+    }
+
+    return false;
+}
+
 void handleWorkspaceView()
 {
-    QString object = QString(getenv("DISPLAY"));
-    object = object.trimmed().replace(":", "_").replace(".", "_").replace("-", "_");
-    object = "/org/ukui/WindowSwitch/display/" + object;
-    QDBusInterface interface("org.ukui.WindowSwitch", object,
-                                "org.ukui.WindowSwitch",
+    // 根据当前的DISPLAY环境变量构造单独的DBus Name
+    QString serviceName = QString(getenv("DISPLAY"));
+    serviceName = serviceName.trimmed().replace(":", "_").replace(".", "_").replace("-", "_");
+    if (!serviceName.isEmpty())
+        serviceName = QString(UKWS_DBUS_NAME_PREFIX) + "." + serviceName;
+    else
+        serviceName = UKWS_DBUS_NAME_PREFIX;
+    qDebug() << "Access DBus:" << serviceName;
+
+    QDBusInterface interface(serviceName, UKWS_DBUS_PATH, UKWS_DBUS_INTERFACE,
                                 QDBusConnection::sessionBus());
     if (!interface.isValid()) {
-        qCritical() << QDBusConnection::sessionBus().lastError().message();
-        exit(1);
+        qDebug() << QDBusConnection::sessionBus().lastError().message();
+        qInfo() << "Try to start ukui-window-switch";
+        if (!startUkws(serviceName)) {
+            qCritical() << "Start ukui-window-switch failed";
+            exit(1);
+        }
     }
+    
     //调用远程的value方法
     QDBusReply<bool> reply = interface.call("handleWorkspace");
     if (reply.isValid()) {
diff --git a/src/ukws_common.h b/src/ukws_common.h
index f3631ef..39c660d 100755
--- a/src/ukws_common.h
+++ b/src/ukws_common.h
@@ -34,6 +34,10 @@
 #define UKWS_OBJ_NEW_WS_TITLE       "new-workspace-title"
 #define UKWS_OBJ_NEW_WS_LABEL       "new-workspace-label"
 
+#define UKWS_DBUS_NAME_PREFIX       "org.ukui.WindowSwitch.Display"
+#define UKWS_DBUS_PATH              "/org/ukui/WindowSwitch"
+#define UKWS_DBUS_INTERFACE         "org.ukui.WindowSwitch"
+
 enum UkwsWidgetShowStatus {
     Hidden = 0,
     Shown,
diff --git a/src/ukws_manager.cpp b/src/ukws_manager.cpp
index e9cffe3..ecd4f1e 100755
--- a/src/ukws_manager.cpp
+++ b/src/ukws_manager.cpp
@@ -92,19 +92,25 @@ UkwsManager::UkwsManager(QWidget *parent) : QWidget(parent)
     connect(ws, &UkwsWorkspaceManager::isHidden, this, &UkwsManager::hideWorkspace);
 //    connect(altChecker, &UkwsAltChecker::altReleased, this, &UkwsManager::hideIndicator);
 
+    // 根据当前的DISPLAY环境变量构造单独的DBus Name
+    QString serviceName = QString(getenv("DISPLAY"));
+    serviceName = serviceName.trimmed().replace(":", "_").replace(".", "_").replace("-", "_");
+    if (!serviceName.isEmpty())
+        serviceName = QString(UKWS_DBUS_NAME_PREFIX) + "." + serviceName;
+    else
+        serviceName = UKWS_DBUS_NAME_PREFIX;
+    qDebug() << "Register DBus Name:" << serviceName;
+
+ 
     // 连接session总线
     QDBusConnection connection = QDBusConnection::sessionBus();
 
     // 在session总线上为UKWS注册服务
-    if(!connection.registerService("org.ukui.WindowSwitch")) {
+    if(!connection.registerService(serviceName)) {
         qCritical() << "Register DBus Service Error:" << connection.lastError().message();
     }
-    // 注册org.ukui.WindowSwitch服务的object，把UkwsManager类的所有公共槽函数导出为object的method
-    QString object = QString(getenv("DISPLAY"));
-    object = object.trimmed().replace(":", "_").replace(".", "_").replace("-", "_");
-    object = "/org/ukui/WindowSwitch/display/" + object;
-    qDebug() << "Register DBus:" << object;
-    connection.registerObject(object, this, QDBusConnection::ExportAllSlots);
+    connection.registerObject(UKWS_DBUS_PATH, UKWS_DBUS_INTERFACE,
+                              this, QDBusConnection::ExportAllSlots);
 }
 
 void UkwsManager::setConfig(UkwsConfig *config)
-- 
2.23.0

