From b8f8ce418e3b2bb00b6a5b4c75aebfb6e99147ef Mon Sep 17 00:00:00 2001 From: Mavridis Philippe Date: Sun, 7 Jul 2024 20:40:21 +0300 Subject: [PATCH] Code reorganization and some improvements borrowed from kdbusnotification Signed-off-by: Mavridis Philippe --- src/CMakeLists.txt | 5 +- src/file_chooser_portal.cpp | 5 ++ src/file_chooser_portal.h | 8 ++- src/main.cpp | 20 +------ src/portal_daemon.cpp | 114 ++++++++++++++++++++++++++++++++++++ src/portal_daemon.h | 73 +++++++++++++++++++++++ src/portal_service.cpp | 108 ++++++++++++++++++++++++++-------- src/portal_service.h | 109 ++++++++++++++++++++++++++++++++-- 8 files changed, 390 insertions(+), 52 deletions(-) create mode 100644 src/portal_daemon.cpp create mode 100644 src/portal_daemon.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 34b4c02..8ca6297 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,13 +12,13 @@ include_directories( ${TDE_INCLUDE_DIR} ${TQT_INCLUDE_DIRS} ${DBUS_TQT_INCLUDE_DIRS} - ${CMAKE_BINARY_DIR}/interfaces + ${CMAKE_BINARY_DIR} ) link_directories( ${TQT_LIBRARY_DIRS} ${DBUS_TQT_LIBRARY_DIRS} - ${CMAKE_BINARY_DIR}/interfaces + ${CMAKE_BINARY_DIR} ) tde_add_executable( @@ -26,6 +26,7 @@ tde_add_executable( SOURCES main.cpp + portal_daemon.cpp portal_service.cpp file_chooser_portal.cpp diff --git a/src/file_chooser_portal.cpp b/src/file_chooser_portal.cpp index 1d037ec..0a7b340 100644 --- a/src/file_chooser_portal.cpp +++ b/src/file_chooser_portal.cpp @@ -134,6 +134,11 @@ void TDEFileChooserPortal::handleMethodReply(const TQT_DBusMessage &reply) m_connection.send(reply); } +bool TDEFileChooserPortal::handleSignalSend(const TQT_DBusMessage& reply) { + handleMethodReply(reply); + return true; +} + bool TDEFileChooserPortal::execFileDialog(FileDialogOpts options, const TQT_DBusObjectPath& handle, TQ_UINT32& response, diff --git a/src/file_chooser_portal.h b/src/file_chooser_portal.h index 375b7c8..ef7b43a 100644 --- a/src/file_chooser_portal.h +++ b/src/file_chooser_portal.h @@ -33,7 +33,7 @@ #include // Portal -#include "filechooserInterface.h" +#include "interfaces/filechooserInterface.h" struct FileDialogOpts { @@ -64,6 +64,8 @@ class TDEFileChooserPortal : public TQObject, TDEFileChooserPortal(TQT_DBusConnection &connection); virtual ~TDEFileChooserPortal(); + static const TQString interface() { return "org.freedesktop.impl.portal.FileChooser"; } + protected: virtual bool OpenFile(const TQT_DBusObjectPath& handle, const TQString& app_id, @@ -92,7 +94,9 @@ class TDEFileChooserPortal : public TQObject, TQMap &results, TQT_DBusError& error); - virtual void handleMethodReply(const TQT_DBusMessage &reply); + virtual void handleMethodReply(const TQT_DBusMessage& reply); + virtual bool handleSignalSend(const TQT_DBusMessage& reply); + private: TQT_DBusConnection m_connection; diff --git a/src/main.cpp b/src/main.cpp index 278d754..c9b9e30 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,17 +19,12 @@ Improvements and feedback are welcome! *******************************************************************************/ -// TQt -#include - // TDE -#include #include #include -#include // Portal -#include "portal_service.h" +#include "portal_daemon.h" static const char description[] = I18N_NOOP("TDE XDG desktop portal"); @@ -48,17 +43,8 @@ int main(int argc, char **argv) if (!KUniqueApplication::start()) return 0; - KUniqueApplication app; - - TQT_DBusConnection connection = TQT_DBusConnection::sessionBus(); - if (!connection.isConnected()) - tqFatal("Failed to connect to session bus!"); - - if (!connection.requestName("org.freedesktop.impl.portal.desktop.tde")) - tqFatal("Failed to register XDG portal service!"); - - TDEPortalService portal(connection); - + PortalDaemon app; + app.disableSessionManagement(); return app.exec(); } diff --git a/src/portal_daemon.cpp b/src/portal_daemon.cpp new file mode 100644 index 0000000..cc8615f --- /dev/null +++ b/src/portal_daemon.cpp @@ -0,0 +1,114 @@ +/******************************************************************************* + XDG desktop portal implementation for TDE + Copyright © 2024 Mavridis Philippe + + Partially based on code from kdbusnotification + Copyright © 2021 Emanoil Kotsev + + This program or library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Improvements and feedback are welcome! +*******************************************************************************/ + +// TQt +#include + +// TDE +#include + +// Portal +#include "portal_daemon.h" +#include "portal_daemon.moc" + +PortalDaemon::PortalDaemon() +: KUniqueApplication(), + m_retryCount(0) +{ + connectDBus(); +} + +PortalDaemon::~PortalDaemon() +{ + disconnectDBus(); +} + +void PortalDaemon::connectDBus() +{ + if (d_desktop) disconnectDBus(); + + m_connection = TQT_DBusConnection::addConnection( + TQT_DBusConnection::SessionBus, + DBUS_PORTAL_SERVICE + ); + + if (m_connection.isConnected()) + { + m_connection.connect(this, TQ_SLOT(slotDBusSignal(const TQT_DBusMessage&))); + if (m_connection.requestName(DBUS_PORTAL_SERVICE, TQT_DBusConnection::NoReplace)) + { + m_connection.scheduleDispatch(); + kdDebug() << "TDE portal service successfully registered." << endl; + return; + } + } + + ++m_retryCount; + kdWarning() << "Failed to connect to DBus, retrying in " + << DBUS_RETRY_TIMEOUT << " secs " + << "(" << m_retryCount << "/" << DBUS_RETRY_COUNT << "tries)" + << endl; + + if (m_retryCount < DBUS_RETRY_COUNT) + { + TQTimer::singleShot(DBUS_RETRY_TIMEOUT, this, TQ_SLOT(connectDBus())); + } +} + +void PortalDaemon::disconnectDBus() +{ + ZAP(d_root) + ZAP(d_org) + ZAP(d_freedesktop) + ZAP(d_portal) + ZAP(d_desktop) + + if (m_connection.isConnected()) + { + m_connection.disconnect(this, TQ_SLOT(slotDBusSignal(const TQT_DBusMessage&))); + m_connection.closeConnection(DBUS_PORTAL_SERVICE); + } + + m_retryCount = 0; +} + +void PortalDaemon::slotDBusSignal(const TQT_DBusMessage &message) +{ + TQString serviceName = message[0].toString(); + if (message.interface() == TQString("org.freedesktop.DBus") && + message.member() == TQString("NameAcquired") && + serviceName == DBUS_PORTAL_SERVICE) + { + kdDebug() << "Portal daemon acquired unique DBus name: " + << serviceName << endl; + + d_root = new RootNodeService(m_connection); + d_org = new OrgNodeService(m_connection); + d_freedesktop = new FreeDesktopNodeService(m_connection); + d_portal = new PortalNodeService(m_connection); + d_desktop = new DesktopNodeService(m_connection); + } +} + +// kate: replace-tabs true; tab-width 4; indent-width 4; \ No newline at end of file diff --git a/src/portal_daemon.h b/src/portal_daemon.h new file mode 100644 index 0000000..974f234 --- /dev/null +++ b/src/portal_daemon.h @@ -0,0 +1,73 @@ +/******************************************************************************* + XDG desktop portal implementation for TDE + Copyright © 2024 Mavridis Philippe + + Partially based on code from kdbusnotification + Copyright © 2021 Emanoil Kotsev + + This program or library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Improvements and feedback are welcome! +*******************************************************************************/ + +#ifndef __PORTAL_DAEMON_H +#define __PORTAL_DAEMON_H + +// TQt +#include +#include + +// TDE +#include + +// DBus +#include "portal_service.h" + +// Defines +#define DBUS_PORTAL_SERVICE "org.freedesktop.impl.portal.desktop.tde" +#define DBUS_RETRY_TIMEOUT 5000 +#define DBUS_RETRY_COUNT 3 + +#define ZAP(x) if (x) { delete x; x = nullptr; } + +class PortalDaemon : public KUniqueApplication +{ + TQ_OBJECT + + public: + PortalDaemon(); + virtual ~PortalDaemon(); + + private: + void connectDBus(); + void disconnectDBus(); + + private slots: + void slotDBusSignal(const TQT_DBusMessage&); + + private: + RootNodeService *d_root; + OrgNodeService *d_org; + FreeDesktopNodeService *d_freedesktop; + PortalNodeService *d_portal; + DesktopNodeService *d_desktop; + + TQT_DBusConnection m_connection; + uint m_retryCount; +}; + +#endif // __PORTAL_DAEMON_H + +// kate: replace-tabs true; tab-width 4; indent-width 4; \ No newline at end of file diff --git a/src/portal_service.cpp b/src/portal_service.cpp index 86baa63..4e0eae3 100644 --- a/src/portal_service.cpp +++ b/src/portal_service.cpp @@ -2,6 +2,9 @@ XDG desktop portal implementation for TDE Copyright © 2024 Mavridis Philippe + Partially based on code from kdbusnotification + Copyright © 2021 Emanoil Kotsev + This program or library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, @@ -34,42 +37,97 @@ static const char *dbusObjectPath = "/org/freedesktop/portal/desktop"; static const char *dbusInterfaceRoot = "org.freedesktop.impl.portal"; -TDEPortalService::TDEPortalService(TQT_DBusConnection &connection) -: m_connection(connection) +DesktopNodeService::DesktopNodeService(TQT_DBusConnection &connection) +: org::freedesktop::portal::desktopNode(), + m_connection(connection) +{ + m_interfaces.insert("org.freedesktop.DBus.Introspectable", this); + + REGISTER_PORTAL(TDEFileChooserPortal) + + registerObject(connection, dbusObjectPath); +} + +DesktopNodeService::~DesktopNodeService() +{ + DESTROY_PORTAL(TDEFileChooserPortal) +} + +TQT_DBusObjectBase* DesktopNodeService::createInterface(const TQString& iface) +{ + return (TQT_DBusObjectBase*) m_interfaces[iface]; +} + +// ---------------------------------------------------------------------------------------- + +PortalNodeService::PortalNodeService(TQT_DBusConnection &connection) +: DBusBaseNode(), m_connection(connection) +{ + addChildNode("desktop"); + registerObject(m_connection, "/org/freedesktop/portal"); +} + +PortalNodeService::~PortalNodeService() { - if (!m_connection.registerObject(dbusObjectPath, this)) - kdFatal() << "Unable to register XDG desktop portal object " << dbusObjectPath << endl; - else - kdDebug() << "Registered XDG desktop portal object " << dbusObjectPath << endl; } -TDEPortalService::~TDEPortalService() +TQT_DBusObjectBase* PortalNodeService::createInterface(const TQString& iface) { - m_connection.unregisterObject(dbusObjectPath); + return (TQT_DBusObjectBase*) m_interfaces[iface]; } -TQT_DBusObjectBase* TDEPortalService::getPortalInterface(TQCString portal) +// ---------------------------------------------------------------------------------------- + +FreeDesktopNodeService::FreeDesktopNodeService(TQT_DBusConnection &connection) +: DBusBaseNode(), m_connection(connection) { - if (portal == "FileChooser") - return new TDEFileChooserPortal(m_connection); + addChildNode("portal"); + registerObject(m_connection, "/org/freedesktop"); +} - return nullptr; +FreeDesktopNodeService::~FreeDesktopNodeService() +{ +} + +TQT_DBusObjectBase* FreeDesktopNodeService::createInterface(const TQString& iface) +{ + return (TQT_DBusObjectBase*) m_interfaces[iface]; +} + +// ---------------------------------------------------------------------------------------- + +OrgNodeService::OrgNodeService(TQT_DBusConnection &connection) +: DBusBaseNode(), m_connection(connection) +{ + addChildNode("freedesktop"); + registerObject(m_connection, "/org"); +} + +OrgNodeService::~OrgNodeService() +{ +} + +TQT_DBusObjectBase* OrgNodeService::createInterface(const TQString& iface) +{ + return (TQT_DBusObjectBase*) m_interfaces[iface]; +} + +// ---------------------------------------------------------------------------------------- + +RootNodeService::RootNodeService(TQT_DBusConnection &connection) +: DBusBaseNode(), m_connection(connection) +{ + addChildNode("org"); + registerObject(m_connection, "/"); +} + +RootNodeService::~RootNodeService() +{ } -bool TDEPortalService::handleMethodCall(const TQT_DBusMessage &message) +TQT_DBusObjectBase* RootNodeService::createInterface(const TQString& iface) { - if (!message.interface().startsWith(dbusInterfaceRoot)) - return false; - - TQCString portal = message.interface().mid(TQString(dbusInterfaceRoot).length() + 1).local8Bit(); - TQT_DBusObjectBase *iface = getPortalInterface(portal); - if (!iface) - { - kdWarning() << "Unsupported XDG portal requested: " << portal << endl; - return false; - } - - return delegateMethodCall(message, iface); + return (TQT_DBusObjectBase*) m_interfaces[iface]; } // kate: replace-tabs true; tab-width 4; indent-width 4; \ No newline at end of file diff --git a/src/portal_service.h b/src/portal_service.h index 8e7c400..9e3b282 100644 --- a/src/portal_service.h +++ b/src/portal_service.h @@ -2,6 +2,9 @@ XDG desktop portal implementation for TDE Copyright © 2024 Mavridis Philippe + Partially based on code from kdbusnotification + Copyright © 2021 Emanoil Kotsev + This program or library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, @@ -26,20 +29,114 @@ #include #include -class TDEFileChooserPortal; +// DBus +#include "interfaces/desktopNode.h" +#include "interfaces/dbusbaseNode.h" + +#define REGISTER_PORTAL(klass) \ + m_interfaces.insert(klass::interface(), new klass(connection)); + +#define DESTROY_PORTAL(klass) \ + delete m_interfaces[klass::interface()]; + +/** + * DesktopNodeService + * Service : org.freedesktop.DBus.Introspectable + * Path : /org/freedesktop/portal/desktop + * Children : - + */ +class DesktopNodeService : public org::freedesktop::portal::desktopNode +{ + public: + DesktopNodeService(TQT_DBusConnection&); + ~DesktopNodeService(); + + protected: + virtual TQT_DBusObjectBase* createInterface(const TQString&); + + private: + TQMap m_interfaces; + TQT_DBusConnection m_connection; +}; + +/** + * PortalNodeService + * Service : - + * Path : /org/freedesktop/portal + * Children : Desktop + */ +class PortalNodeService : public DBusBaseNode +{ + public: + PortalNodeService(TQT_DBusConnection&); + ~PortalNodeService(); + + protected: + virtual TQT_DBusObjectBase* createInterface(const TQString&); + + private: + TQMap m_interfaces; + TQT_DBusConnection m_connection; +}; + +/** + * FreeDesktopNodeService + * Service : - + * Path : /org/freedesktop + * Children : portal + */ +class FreeDesktopNodeService : public DBusBaseNode +{ + public: + FreeDesktopNodeService(TQT_DBusConnection&); + ~FreeDesktopNodeService(); + + protected: + virtual TQT_DBusObjectBase* createInterface(const TQString&); + + private: + TQMap m_interfaces; + TQT_DBusConnection m_connection; +}; + +/** + * OrgNodeService + * Service : - + * Path : /org + * Children : freedesktop + */ +class OrgNodeService : public DBusBaseNode +{ + public: + OrgNodeService(TQT_DBusConnection&); + ~OrgNodeService(); + + protected: + virtual TQT_DBusObjectBase* createInterface(const TQString&); + + private: + TQMap m_interfaces; + TQT_DBusConnection m_connection; +}; -class TDEPortalService : public TQT_DBusObjectBase +/** + * RootNodeService + * Service : - + * Path : / + * Children : org + */ +class RootNodeService : public DBusBaseNode { public: - TDEPortalService(TQT_DBusConnection &connection); - ~TDEPortalService(); + RootNodeService(TQT_DBusConnection&); + ~RootNodeService(); protected: - bool handleMethodCall(const TQT_DBusMessage &message); + virtual TQT_DBusObjectBase* createInterface(const TQString&); private: + TQMap m_interfaces; TQT_DBusConnection m_connection; - TQT_DBusObjectBase* getPortalInterface(TQCString portal); }; #endif // __DESTKOP_PORTAL_H