diff --git a/CMakeLists.txt b/CMakeLists.txt
index f38abd0..de70376 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -121,6 +121,13 @@ set(SOURCE_FILES
src/settings/user-config.cpp src/settings/user-config.h
)
+
+if(COMMAND qt_add_dbus_adaptor)
+ qt_add_dbus_adaptor(SOURCE_FILES data/org.ukui.menu.xml menu-dbus-service.h UkuiMenu::MenuDbusService)
+else()
+ qt5_add_dbus_adaptor(SOURCE_FILES data/org.ukui.menu.xml menu-dbus-service.h UkuiMenu::MenuDbusService)
+endif()
+
# library sources
set(LIBRARY_SOURCES
src/data-entity.cpp
diff --git a/data/org.ukui.menu.xml b/data/org.ukui.menu.xml
new file mode 100644
index 0000000..5ab53f7
--- /dev/null
+++ b/data/org.ukui.menu.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main.cpp b/src/main.cpp
index 59453ae..35f291d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -149,6 +149,7 @@ int main(int argc, char *argv[])
QString appid = QString("ukui-menu-%1").arg(display);
qDebug() << "ukui-menu launch with:" << display << "appid:" << appid;
QtSingleApplication app(appid, argc, argv);
+ QGuiApplication::instance()->setProperty("display", display);
QTranslator translator;
QString translationFile{(QString(UKUI_MENU_TRANSLATION_DIR) + "/ukui-menu_" + QLocale::system().name() + ".qm")};
diff --git a/src/menu-dbus-service.cpp b/src/menu-dbus-service.cpp
index 8202d84..832e9d0 100644
--- a/src/menu-dbus-service.cpp
+++ b/src/menu-dbus-service.cpp
@@ -16,25 +16,69 @@
*
*/
-#include
#include "menu-dbus-service.h"
+#include "menuadaptor.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
#define MENU_CORE_DBUS_SERVICE "org.ukui.menu"
#define MENU_CORE_DBUS_PATH "/org/ukui/menu"
+#define MENU_CORE_DBUS_INTERFACE "org.ukui.menu"
using namespace UkuiMenu;
-MenuDbusService::MenuDbusService(QObject *parent) : QObject(parent)
+QString MenuDbusService::displayFromPid(uint pid)
{
- QDBusConnection::sessionBus().unregisterService(MENU_CORE_DBUS_SERVICE);
- QDBusConnection::sessionBus().registerService(MENU_CORE_DBUS_SERVICE);
- //注册对象路径,导出所有此对象的插槽 ,registerObject参数:路径,interface,对象,options
- QDBusConnection::sessionBus().registerObject(MENU_CORE_DBUS_PATH, this, QDBusConnection::ExportAllSlots);
+ QFile environFile(QStringLiteral("/proc/%1/environ").arg(QString::number(pid)));
+ if (environFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ const QByteArray DISPLAY = KWindowSystem::isPlatformWayland() ? QByteArrayLiteral("WAYLAND_DISPLAY")
+ : QByteArrayLiteral("DISPLAY");
+ const auto lines = environFile.readAll().split('\0');
+ for (const QByteArray &line : lines) {
+ const int equalsIdx = line.indexOf('=');
+ if (equalsIdx <= 0) {
+ continue;
+ }
+ const QByteArray key = line.left(equalsIdx);
+ if (key == DISPLAY) {
+ const QByteArray value = line.mid(equalsIdx + 1);
+ return value;
+ }
+ }
+ }
+
+ return {};
+}
+
+MenuDbusService::MenuDbusService(const QString &display, QObject *parent) : QObject(parent), m_display(display)
+{
+ bool isServiceRegistered = QDBusConnection::sessionBus().interface()->isServiceRegistered(MENU_CORE_DBUS_SERVICE);
+ qDebug() << "menu service is registered:" << isServiceRegistered << ", display:" << display;
+
+ if (isServiceRegistered) {
+ initWatcher();
+
+ } else {
+ bool success = registerService();
+ if (!success) {
+ initWatcher();
+ }
+ qDebug() << "menu service register:" << success;
+ }
}
void MenuDbusService::WinKeyResponse()
{
- Q_EMIT menuActive();
+ uint callerPid = QDBusConnection::sessionBus().interface()->servicePid(message().service()).value();
+ QString display = MenuDbusService::displayFromPid(callerPid);
+
+ active(display);
}
QString MenuDbusService::GetSecurityConfigPath()
@@ -47,3 +91,90 @@ void MenuDbusService::ReloadSecurityConfig()
{
Q_EMIT reloadConfigSignal();
}
+
+void MenuDbusService::active(const QString &display)
+{
+ if (display.isEmpty() || (display == m_display)) {
+ Q_EMIT menuActive();
+ return;
+ }
+
+ if (m_menuAdaptor) {
+ Q_EMIT m_menuAdaptor->activeRequest(display);
+ }
+}
+
+void MenuDbusService::activeMenu(QString display)
+{
+ if (display == m_display) {
+ Q_EMIT menuActive();
+ }
+}
+
+bool MenuDbusService::registerService()
+{
+ m_menuAdaptor = new MenuAdaptor(this);
+ QDBusReply reply =
+ QDBusConnection::sessionBus().interface()->registerService(MENU_CORE_DBUS_SERVICE,
+ QDBusConnectionInterface::ReplaceExistingService,
+ QDBusConnectionInterface::DontAllowReplacement);
+
+ if (reply.value() == QDBusConnectionInterface::ServiceNotRegistered) {
+ return false;
+ }
+
+ bool res = QDBusConnection::sessionBus().registerObject(MENU_CORE_DBUS_PATH, this);
+ if (!res) {
+ QDBusConnection::sessionBus().interface()->unregisterService(MENU_CORE_DBUS_SERVICE);
+ }
+
+ return res;
+}
+
+void MenuDbusService::onServiceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner)
+{
+ qDebug() << "serviceOwnerChanged:" << service << oldOwner << newOwner;
+ if (newOwner.isEmpty()) {
+ bool success = registerService();
+ if (success) {
+ disConnectActiveRequest();
+ delete m_watcher;
+ m_watcher = nullptr;
+ }
+ qDebug() << "try to register service:" << success;
+ return;
+ }
+
+ uint newOwnerPid = QDBusConnection::sessionBus().interface()->servicePid(newOwner);
+ qDebug() << "newOwnerPid:" << newOwnerPid << ", myPid:" << QCoreApplication::applicationPid() << ", display:" << m_display;
+// if (newOwnerPid == QCoreApplication::applicationPid()) {
+// qDebug() << "Becoming a new service";
+// }
+}
+
+void MenuDbusService::connectToActiveRequest()
+{
+ QDBusConnection::sessionBus().connect(MENU_CORE_DBUS_SERVICE,
+ MENU_CORE_DBUS_PATH,
+ MENU_CORE_DBUS_INTERFACE,
+ "activeRequest",
+ this,
+ SLOT(activeMenu(QString)));
+}
+
+void MenuDbusService::disConnectActiveRequest()
+{
+ QDBusConnection::sessionBus().disconnect(MENU_CORE_DBUS_SERVICE,
+ MENU_CORE_DBUS_PATH,
+ MENU_CORE_DBUS_INTERFACE,
+ "activeRequest",
+ this,
+ SLOT(activeMenu(QString)));
+}
+
+void MenuDbusService::initWatcher()
+{
+ m_watcher = new QDBusServiceWatcher(MENU_CORE_DBUS_SERVICE,QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange);
+ connect(m_watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &MenuDbusService::onServiceOwnerChanged);
+ connectToActiveRequest();
+}
diff --git a/src/menu-dbus-service.h b/src/menu-dbus-service.h
index d2819f5..e533cdd 100644
--- a/src/menu-dbus-service.h
+++ b/src/menu-dbus-service.h
@@ -20,27 +20,45 @@
#define MENU_DBUS_SERVICE_H
#include
-#include
-#include
+#include
+
+class MenuAdaptor;
+class QDBusServiceWatcher;
namespace UkuiMenu {
-class MenuDbusService : public QObject
+class MenuDbusService : public QObject, public QDBusContext
{
Q_OBJECT
- //申明该类有D-BUS服务接口
- Q_CLASSINFO("D-Bus Interface", "org.ukui.menu")
public:
- explicit MenuDbusService(QObject *parent = nullptr); //传入父指针,调用
+ explicit MenuDbusService(const QString& display, QObject *parent = nullptr);
public Q_SLOTS:
void WinKeyResponse();
QString GetSecurityConfigPath();
void ReloadSecurityConfig();
+ void active(const QString &display);
Q_SIGNALS:
void menuActive();
void reloadConfigSignal();
+
+private Q_SLOTS:
+ void activeMenu(QString display);
+ void onServiceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner);
+
+private:
+ static QString displayFromPid(uint pid);
+ bool registerService();
+
+ void initWatcher();
+ void connectToActiveRequest();
+ void disConnectActiveRequest();
+
+private:
+ QString m_display {};
+ MenuAdaptor *m_menuAdaptor {nullptr};
+ QDBusServiceWatcher *m_watcher {nullptr};
};
}
diff --git a/src/ukui-menu-application.cpp b/src/ukui-menu-application.cpp
index 8b6bc3a..0267bf8 100644
--- a/src/ukui-menu-application.cpp
+++ b/src/ukui-menu-application.cpp
@@ -32,7 +32,7 @@
#include "menu-manager.h"
#include "data-provider-manager.h"
-#include
+#include
#include
#include
#include
@@ -127,7 +127,7 @@ void UkuiMenuApplication::loadMenuUI()
void UkuiMenuApplication::initDbusService()
{
- m_menuDbusService = new MenuDbusService(this);
+ m_menuDbusService = new MenuDbusService(QGuiApplication::instance()->property("display").toString(), this);
if (m_menuDbusService) {
connect(m_menuDbusService, &MenuDbusService::menuActive, this, [this] {
execCommand(Active);