diff --git a/gmenu-dbusmenu-proxy/menuproxy.cpp b/gmenu-dbusmenu-proxy/menuproxy.cpp index 16cd522a0..06e32b65e 100644 --- a/gmenu-dbusmenu-proxy/menuproxy.cpp +++ b/gmenu-dbusmenu-proxy/menuproxy.cpp @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include #include @@ -39,6 +41,8 @@ static const QString s_ourServiceName = QStringLiteral("org.kde.plasma.gmenu_dbusmenu_proxy"); +static const QString s_dbusMenuRegistrar = QStringLiteral("com.canonical.AppMenu.Registrar"); + static const QByteArray s_gtkUniqueBusName = QByteArrayLiteral("_GTK_UNIQUE_BUS_NAME"); static const QByteArray s_gtkApplicationObjectPath = QByteArrayLiteral("_GTK_APPLICATION_OBJECT_PATH"); @@ -50,27 +54,66 @@ static const QByteArray s_gtkAppMenuObjectPath = QByteArrayLiteral("_GTK_APP_MEN static const QByteArray s_kdeNetWmAppMenuServiceName = QByteArrayLiteral("_KDE_NET_WM_APPMENU_SERVICE_NAME"); static const QByteArray s_kdeNetWmAppMenuObjectPath = QByteArrayLiteral("_KDE_NET_WM_APPMENU_OBJECT_PATH"); -MenuProxy::MenuProxy() : QObject() +MenuProxy::MenuProxy() + : QObject() + , m_serviceWatcher(new QDBusServiceWatcher(this)) { - // TODO do nothing if no dbusmenu service is unavailable and wait for it to come + m_serviceWatcher->setConnection(QDBusConnection::sessionBus()); + m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration | + QDBusServiceWatcher::WatchForRegistration); + m_serviceWatcher->addWatchedService(s_dbusMenuRegistrar); + + connect(m_serviceWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this](const QString &service) { + Q_UNUSED(service); + qDebug() << "Global menu service became available, starting"; + init(); + }); + connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, [this](const QString &service) { + Q_UNUSED(service); + qDebug() << "Global menu service disappeared, cleaning up"; + teardown(); + }); + + // It's fine to do a blocking call here as we're a separate binary with no UI + if (QDBusConnection::sessionBus().interface()->isServiceRegistered(s_dbusMenuRegistrar)) { + qDebug() << "Global menu service is there, starting up right away"; + init(); + } else { + qDebug() << "No global menu service available, waiting for it before we do anything"; + } +} +bool MenuProxy::init() +{ if (!QDBusConnection::sessionBus().registerService(s_ourServiceName)) { qWarning() << "Failed to register DBus service" << s_ourServiceName; - //qApp->exit(1); // doensn't work? - ::exit(1); - return; + return false; } connect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, &MenuProxy::onWindowAdded); connect(KWindowSystem::self(), &KWindowSystem::windowRemoved, this, &MenuProxy::onWindowRemoved); - for (WId id : KWindowSystem::windows()) { // detaches? + const auto windows = KWindowSystem::windows(); + for (WId id : windows) { onWindowAdded(id); } if (m_menus.isEmpty()) { qDebug() << "Up and running but no menus in sight"; } + + return true; +} + +void MenuProxy::teardown() +{ + QDBusConnection::sessionBus().unregisterService(s_ourServiceName); + + disconnect(KWindowSystem::self(), &KWindowSystem::windowAdded, this, &MenuProxy::onWindowAdded); + disconnect(KWindowSystem::self(), &KWindowSystem::windowRemoved, this, &MenuProxy::onWindowRemoved); + + qDeleteAll(m_menus); + m_menus.clear(); } void MenuProxy::onWindowAdded(WId id) diff --git a/gmenu-dbusmenu-proxy/menuproxy.h b/gmenu-dbusmenu-proxy/menuproxy.h index f02ecac85..3a6e87331 100644 --- a/gmenu-dbusmenu-proxy/menuproxy.h +++ b/gmenu-dbusmenu-proxy/menuproxy.h @@ -26,6 +26,8 @@ #include +class QDBusServiceWatcher; + class Menu; class MenuProxy : public QObject//, public QAbstractNativeEventFilter @@ -44,6 +46,9 @@ private Q_SLOTS: void onWindowRemoved(WId id); private: + bool init(); + void teardown(); + // FIXME the get one reads "UTF8String" (reads gnome) the write thing writes "String" (writes kde) QByteArray getWindowPropertyString(WId id, const QByteArray &name); void writeWindowProperty(WId id, const QByteArray &name, const QByteArray &value); @@ -51,4 +56,6 @@ private: QHash m_menus; + QDBusServiceWatcher *m_serviceWatcher; + };