diff --git a/debian/control b/debian/control index 335fef0..e4fe3ee 100644 --- a/debian/control +++ b/debian/control @@ -10,6 +10,12 @@ Build-Depends: qt5-qmake, qtbase5-dev, qttools5-dev, + libdtkcore-dev (>=5.4.14), + libdtkcore5-bin (>=5.4.14), + libxcb1-dev, + libxcb-icccm4-dev, + libxcb-ewmh-dev, + libx11-dev, Standards-Version: 4.1.3 Homepage: https://www.deepin.org @@ -20,3 +26,4 @@ Depends: ${shlibs:Depends}, Description: dde application manager module Application manager for DDE. + diff --git a/misc/CMakeLists.txt b/misc/CMakeLists.txt index eaa79cc..74a05c6 100644 --- a/misc/CMakeLists.txt +++ b/misc/CMakeLists.txt @@ -1 +1,3 @@ -add_subdirectory(systemd) \ No newline at end of file +add_subdirectory(systemd) +add_subdirectory(dconf) + diff --git a/misc/dconf/CMakeLists.txt b/misc/dconf/CMakeLists.txt new file mode 100644 index 0000000..0f12a84 --- /dev/null +++ b/misc/dconf/CMakeLists.txt @@ -0,0 +1,7 @@ +set(DCONFIG_FILES + com.deepin.dde.launcher.json + com.deepin.dde.dock.json + com.deepin.dde.appearance.json +) + +install(FILES ${DCONFIG_FILES} DESTINATION /usr/share/dsg/configs/dde-application-manager) diff --git a/misc/dconf/com.deepin.dde.appearance.json b/misc/dconf/com.deepin.dde.appearance.json new file mode 100644 index 0000000..6ac3a34 --- /dev/null +++ b/misc/dconf/com.deepin.dde.appearance.json @@ -0,0 +1,145 @@ +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "Extra_Picture_Uris": { + "serial": 0, + "flags": ["global"], + "name": "Extra_Picture_Uris", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Font_Standard": { + "value": "Noto Sans", + "serial": 0, + "flags": ["global"], + "name": "Font_Standard", + "name[zh_CN]": "*****", + "description": "The standard font for desktop", + "permissions": "readwrite", + "visibility": "private" + }, + "Theme_Auto": { + "value": false, + "serial": 0, + "flags": ["global"], + "name": "Theme_Auto", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Wallpaper_Slideshow": { + "value": "", + "serial": 0, + "flags": ["global"], + "name": "Wallpaper_Slideshow", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Cursor_Theme": { + "value": "bloom", + "serial": 0, + "flags": ["global"], + "name": "Cursor_Theme", + "name[zh_CN]": "*****", + "description": "Cursor theme name. Used only by Xservers that support the Xcursor extension.", + "permissions": "readwrite", + "visibility": "private" + }, + "Font_Size": { + "value": 10.5, + "serial": 0, + "flags": ["global"], + "name": "Font_Size", + "name[zh_CN]": "*****", + "description": "The desktop font size", + "permissions": "readwrite", + "visibility": "private" + }, + "Wallpaper_Uris": { + "value": "", + "serial": 0, + "flags": ["global"], + "name": "Wallpaper_Uris", + "name[zh_CN]": "*****", + "description": "wallpaper json string", + "permissions": "readwrite", + "visibility": "private" + }, + "Icon_Theme": { + "value": "bloom", + "serial": 0, + "flags": ["global"], + "name": "Icon_Theme", + "name[zh_CN]": "*****", + "description": "Icon theme to use for the panel, nautilus etc.", + "permissions": "readwrite", + "visibility": "private" + }, + "Opacity": { + "value": 0.40000000000000002, + "serial": 0, + "flags": ["global"], + "name": "Opacity", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Font_Monospace": { + "value": "Noto Mono", + "serial": 0, + "flags": ["global"], + "name": "Font_Monospace", + "name[zh_CN]": "*****", + "description": "The monospace font for desktop", + "permissions": "readwrite", + "visibility": "private" + }, + "Excluded_Icon_Themes": { + "value": ["hicolor", "gnome", "Adwaita"], + "serial": 0, + "flags": ["global"], + "name": "Excluded_Icon_Themes", + "name[zh_CN]": "*****", + "description": "Icon theme black list.", + "permissions": "readwrite", + "visibility": "private" + }, + "Gtk_Theme": { + "value": "deepin", + "serial": 0, + "flags": ["global"], + "name": "Gtk_Theme", + "name[zh_CN]": "*****", + "description": "Basename of the default theme used by gtk+.", + "permissions": "readwrite", + "visibility": "private" + }, + "Sound_Theme": { + "value": "deepin", + "serial": 0, + "flags": ["global"], + "name": "Sound_Theme", + "name[zh_CN]": "*****", + "description": "Set the system sound theme", + "permissions": "readwrite", + "visibility": "private" + }, + "Background_Uris": { + "value": ["file:///usr/share/backgrounds/default_background.jpg"], + "serial": 0, + "flags": ["global"], + "name": "Background_Uris", + "name[zh_CN]": "*****", + "description": "Note that the backend only supports local (file://) URIs.", + "permissions": "readwrite", + "visibility": "private" + } + } +} diff --git a/misc/dconf/com.deepin.dde.dock.json b/misc/dconf/com.deepin.dde.dock.json new file mode 100644 index 0000000..08c61ef --- /dev/null +++ b/misc/dconf/com.deepin.dde.dock.json @@ -0,0 +1,146 @@ +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "Window_Size_Fashion": { + "value": 48, + "serial": 0, + "flags": ["global"], + "name": "Window_Size_Fashion", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Icon_Size": { + "value": 36, + "serial": 0, + "flags": ["global"], + "name": "Icon_Size", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Position": { + "value": "bottom", + "serial": 0, + "flags": ["global"], + "name": "Position", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Wireless_Scan_Interval": { + "value": 5, + "serial": 0, + "flags": ["global"], + "name": "Wireless_Scan_Interval", + "name[zh_CN]": "*****", + "description": "wireless scan interval", + "permissions": "readwrite", + "visibility": "private" + }, + "Hide_Timeout": { + "value": 0, + "serial": 0, + "flags": ["global"], + "name": "Hide_Timeout", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Hide_Mode": { + "value": "keep-showing", + "serial": 0, + "flags": ["global"], + "name": "Hide_Mode", + "name[zh_CN]": "*****", + "description": "The value will influence when the dock is shown or hidden.", + "permissions": "readwrite", + "visibility": "private" + }, + "Show_Timeout": { + "value": 100, + "serial": 0, + "flags": ["global"], + "name": "Show_Timeout", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Window_Size_Efficient": { + "value": 40, + "serial": 0, + "flags": ["global"], + "name": "Window_Size_Efficient", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Plugin_Settings": { + "value": "{}", + "serial": 0, + "flags": ["global"], + "name": "Plugin_Settings", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Docked_Apps": { + "value": ["/S@dde-file-manager", "/S@uos-browser", "/S@org.deepin.browser", "/S@deepin-appstore", "/S@deepin-app-store", "/S@com.deepin.store.intranet", "/S@deepin-album", "/S@deepin-music", "/S@deepin-contacts", "/S@dde-calendar", "/S@dde-control-center"], + "serial": 0, + "flags": ["global"], + "name": "Docked_Apps", + "name[zh_CN]": "*****", + "description": "The default apps which is docked when dock is started.", + "permissions": "readwrite", + "visibility": "private" + }, + "Win_Icon_Preferred_Apps": { + "value": ["apps.com.qq.im", "deepin.com.qq.im", "apps.com.qq.im.light", "apps.com.qq.b.eim", "apps.com.qq.rtxclient"], + "serial": 0, + "flags": ["global"], + "name": "Win_Icon_Preferred_Apps", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Delay_Plugins_Time": { + "value": 0, + "serial": 0, + "flags": ["global"], + "name": "Delay_Plugins_Time", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Force_Quit_App": { + "value": "enabled", + "serial": 0, + "flags": ["global"], + "name": "Force_Quit_App", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Display_Mode": { + "value": "efficient", + "serial": 0, + "flags": ["global"], + "name": "Display_Mode", + "name[zh_CN]": "*****", + "description": "The dock gets different display mode, for instance, dock looks like win7 taskbar on classic mode.", + "permissions": "readwrite", + "visibility": "private" + } + } +} diff --git a/misc/dconf/com.deepin.dde.launcher.json b/misc/dconf/com.deepin.dde.launcher.json new file mode 100644 index 0000000..a15fbca --- /dev/null +++ b/misc/dconf/com.deepin.dde.launcher.json @@ -0,0 +1,246 @@ +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "Apps_Can_Not_Start_Up_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Can_Not_Start_Up_List", + "name[zh_CN]": "*****", + "description": "apps not allowed to start up", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Order_Zh_Cn": { + "value": ["uos-browser", "org.deepin.browser", "dde-file-manager", "deepin-app-store", "deepin-appstore", "deepin-music", "deepin-movie", "deepin-screen-recorder", "deepin-image-viewer", "deepin-album", "deepin-draw", "deepin-reader", "deepin-editor", "deepin-mail", "thunderbird", "deepin-terminal", "terminal", "org.gnome.Terminal", "deepin-contacts", "deepin-voice-note", "downloader", "deepin-manual", "org.deepin.scanner", "org.deepin.scaner", "dde-computer", "dde-trash", "deepin-defender", "dde-control-center", "chineseime-setting", "fcitx-config-gtk3", "chineseime-setting-wizard", "deepin-system-monitor", "deepin-boot-maker", "deepin-devicemanager", "deepin-log-viewer", "dde-printer", "dde-calendar", "deepin-calculator", "deepin-font-manager", "deepin-compressor", "deepin-deb-installer", "deepin-diskmanager", "dde-introduction", "uos-service-support", "uos-remote-assistance", "deepin-camera", "deepin-phone-master", "gparted", "org.gnome.Cheese", "Cheese", "gnome.Cheese"], + "serial": 0, + "flags": ["global"], + "name": "Apps_Order_Zh_Cn", + "name[zh_CN]": "*****", + "description": "launcher apps order, ensure that all lowercase.", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Icon_Ratio": { + "value": 0.5, + "serial": 0, + "flags": ["global"], + "name": "Apps_Icon_Ratio", + "name[zh_CN]": "*****", + "description": "(null)", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Can_Not_Use_Proxy_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Can_Not_Use_Proxy_List", + "name[zh_CN]": "*****", + "description": "apps disable use proxy menu", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Hide_Start_Up_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Hide_Start_Up_List", + "name[zh_CN]": "*****", + "description": "apps hide function start up", + "permissions": "readwrite", + "visibility": "private" + }, + "Fullscreen": { + "value": false, + "serial": 0, + "flags": ["global"], + "name": "Fullscreen", + "name[zh_CN]": "*****", + "description": "(null)", + "permissions": "readwrite", + "visibility": "private" + }, + "Mini_Frame_Right_Bar_Hide_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Mini_Frame_Right_Bar_Hide_List", + "name[zh_CN]": "*****", + "description": "icons not allowed to show on mini frame right bar", + "permissions": "readwrite", + "visibility": "private" + }, + "Auto_Exit": { + "value": false, + "serial": 0, + "flags": ["global"], + "name": "Auto_Exit", + "name[zh_CN]": "*****", + "description": "(null)", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Order_Zh_Tw": { + "value": ["uos-browser", "org.deepin.browser", "dde-file-manager", "deepin-app-store", "deepin-appstore", "deepin-music", "deepin-movie", "deepin-screen-recorder", "deepin-image-viewer", "deepin-album", "deepin-draw", "deepin-reader", "deepin-editor", "deepin-mail", "thunderbird", "deepin-terminal", "terminal", "org.gnome.Terminal", "deepin-contacts", "deepin-voice-note", "downloader", "deepin-manual", "org.deepin.scanner", "org.deepin.scaner", "dde-computer", "dde-trash", "deepin-defender", "dde-control-center", "chineseime-setting", "fcitx-config-gtk3", "chineseime-setting-wizard", "deepin-system-monitor", "deepin-boot-maker", "deepin-devicemanager", "deepin-log-viewer", "dde-printer", "dde-calendar", "deepin-calculator", "deepin-font-manager", "deepin-compressor", "deepin-deb-installer", "deepin-diskmanager", "dde-introduction", "uos-service-support", "uos-remote-assistance", "deepin-camera", "deepin-phone-master", "gparted", "org.gnome.Cheese", "Cheese", "gnome.Cheese"], + "serial": 0, + "flags": ["global"], + "name": "Apps_Order_Zh_Tw", + "name[zh_CN]": "*****", + "description": "launcher apps order, ensure that all lowercase.", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Can_Not_Send_To_Dock_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Can_Not_Send_To_Dock_List", + "name[zh_CN]": "*****", + "description": "apps not allowed to send to Dock", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Can_Not_Send_To_Desktop_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Can_Not_Send_To_Desktop_List", + "name[zh_CN]": "*****", + "description": "apps not allowed to send to Desktop", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Hide_Send_To_Desktop_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Hide_Send_To_Desktop_List", + "name[zh_CN]": "*****", + "description": "apps hide function send to desktop", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Hold_List": { + "value": ["dde-introduction", "dde-file-manager", "deepin-appstore", "deepin-app-store", "deepin-terminal", "deepin-manual", "dde-computer", "dde-trash", "deepin-defender", "dde-control-center", "fcitx-config-gtk3", "fcitx-configtool", "deepin-system-monitor", "deepin-devicemanager", "dde-printer", "dde-calendar", "uos-service-support", "deepin-toggle-desktop", "deepin-wm-multitaskingview", "kwin-wm-multitaskingview", "com.deepin.store.intranet", "chineseime-setting"], + "serial": 0, + "flags": ["global"], + "name": "Apps_Hold_List", + "name[zh_CN]": "*****", + "description": "apps not allowed to uninstall", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Hide_Open_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Hide_Open_List", + "name[zh_CN]": "*****", + "description": "apps hide function open", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Can_Not_Open_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Can_Not_Open_List", + "name[zh_CN]": "*****", + "description": "apps not allowed to open", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Use_Proxy": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Use_Proxy", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Search_Package_Name": { + "value": false, + "serial": 0, + "flags": ["global"], + "name": "Search_Package_Name", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Order": { + "value": ["uos-browser", "org.deepin.browser", "dde-file-manager", "deepin-app-store", "deepin-appstore", "deepin-music", "deepin-movie", "deepin-screen-recorder", "deepin-image-viewer", "deepin-album", "deepin-draw", "deepin-reader", "deepin-editor", "deepin-mail", "thunderbird", "deepin-terminal", "terminal", "org.gnome.Terminal", "deepin-contacts", "deepin-voice-note", "downloader", "deepin-manual", "org.deepin.scanner", "org.deepin.scaner", "dde-computer", "dde-trash", "deepin-defender", "dde-control-center", "chineseime-setting", "fcitx-config-gtk3", "chineseime-setting-wizard", "deepin-system-monitor", "deepin-boot-maker", "deepin-devicemanager", "deepin-log-viewer", "dde-printer", "dde-calendar", "deepin-calculator", "deepin-font-manager", "deepin-compressor", "deepin-deb-installer", "deepin-diskmanager", "dde-introduction", "uos-service-support", "uos-remote-assistance", "deepin-camera", "deepin-phone-master", "gparted", "org.gnome.Cheese", "Cheese", "gnome.Cheese"], + "serial": 0, + "flags": ["global"], + "name": "Apps_Order", + "name[zh_CN]": "*****", + "description": "launcher apps order, ensure that all lowercase.", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Hide_Use_Proxy_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Hide_Use_Proxy_List", + "name[zh_CN]": "*****", + "description": "apps hide use proxy menu", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Disable_Scaling": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Disable_Scaling", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Hidden": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Hidden", + "name[zh_CN]": "*****", + "description": "", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Hide_Send_To_Dock_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Hide_Send_To_Dock_List", + "name[zh_CN]": "*****", + "description": "apps hide function send to dock", + "permissions": "readwrite", + "visibility": "private" + }, + "Apps_Hide_Uninstall_List": { + "value": [], + "serial": 0, + "flags": ["global"], + "name": "Apps_Hide_Uninstall_List", + "name[zh_CN]": "*****", + "description": "apps hide function uninstall", + "permissions": "readwrite", + "visibility": "private" + }, + "Display_Mode": { + "value": "free", + "serial": 0, + "flags": ["global"], + "name": "Display_Mode", + "name[zh_CN]": "*****", + "description": "Launcher display mode.", + "permissions": "readwrite", + "visibility": "private" + } + } +} diff --git a/src/frameworkdbus/dbusbamfapplication.cpp b/src/frameworkdbus/dbusbamfapplication.cpp new file mode 100644 index 0000000..7cf33f5 --- /dev/null +++ b/src/frameworkdbus/dbusbamfapplication.cpp @@ -0,0 +1,73 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c BamfApplication -p BamfApplication Application.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "dbusbamfapplication.h" + +/* + * Implementation of interface class __BamfApplication + */ + +class __BamfApplicationPrivate +{ +public: + __BamfApplicationPrivate() = default; + + // begin member variables + +public: + QMap m_processingCalls; + QMap> m_waittingCalls; +}; + +__BamfApplication::__BamfApplication(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent) + , d_ptr(new __BamfApplicationPrivate) +{ + if (QMetaType::type("QList") == QMetaType::UnknownType) { + qRegisterMetaType< QList >("QList"); + qDBusRegisterMetaType< QList >(); + } +} + +__BamfApplication::~__BamfApplication() +{ + qDeleteAll(d_ptr->m_processingCalls.values()); + delete d_ptr; +} + +void __BamfApplication::CallQueued(const QString &callName, const QList &args) +{ + if (d_ptr->m_waittingCalls.contains(callName)) + { + d_ptr->m_waittingCalls[callName] = args; + return; + } + if (d_ptr->m_processingCalls.contains(callName)) + { + d_ptr->m_waittingCalls.insert(callName, args); + } else { + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncCallWithArgumentList(callName, args)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &__BamfApplication::onPendingCallFinished); + d_ptr->m_processingCalls.insert(callName, watcher); + } +} + +void __BamfApplication::onPendingCallFinished(QDBusPendingCallWatcher *w) +{ + w->deleteLater(); + const auto callName = d_ptr->m_processingCalls.key(w); + Q_ASSERT(!callName.isEmpty()); + d_ptr->m_processingCalls.remove(callName); + if (!d_ptr->m_waittingCalls.contains(callName)) + return; + const auto args = d_ptr->m_waittingCalls.take(callName); + CallQueued(callName, args); +} diff --git a/src/frameworkdbus/dbusbamfapplication.h b/src/frameworkdbus/dbusbamfapplication.h new file mode 100644 index 0000000..c6f2978 --- /dev/null +++ b/src/frameworkdbus/dbusbamfapplication.h @@ -0,0 +1,134 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c BamfApplication -p BamfApplication Application.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef BAMFAPPLICATION_H +#define BAMFAPPLICATION_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * Proxy class for interface org.ayatana.bamf.application + */ +class __BamfApplicationPrivate; +class __BamfApplication : public DBusExtendedAbstractInterface +{ + Q_OBJECT + +public: + static inline const char *staticInterfaceName() + { return "org.ayatana.bamf.application"; } + +public: + explicit __BamfApplication(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~__BamfApplication(); + +public Q_SLOTS: // METHODS + inline Q_DECL_DEPRECATED QDBusPendingReply ApplicationMenu() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ApplicationMenu"), argumentList); + } + + + inline Q_DECL_DEPRECATED QDBusReply ApplicationMenu(QString &objectpath) + { + QList argumentList; + QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("ApplicationMenu"), argumentList); + if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 2) { + objectpath = qdbus_cast(reply.arguments().at(1)); + } + return reply; + } + + inline QDBusPendingReply ApplicationType() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ApplicationType"), argumentList); + } + + + + inline QDBusPendingReply DesktopFile() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("DesktopFile"), argumentList); + } + + + + inline QDBusPendingReply FocusableChild() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("FocusableChild"), argumentList); + } + + + + inline QDBusPendingReply ShowStubs() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ShowStubs"), argumentList); + } + + + + inline QDBusPendingReply SupportedMimeTypes() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("SupportedMimeTypes"), argumentList); + } + + + + inline QDBusPendingReply > Xids() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Xids"), argumentList); + } + + + + +Q_SIGNALS: // SIGNALS + void DesktopFileUpdated(const QString &desktop_file); + void SupportedMimeTypesChanged(const QStringList &dnd_mimes); + Q_DECL_DEPRECATED void WindowAdded(const QString &path); + Q_DECL_DEPRECATED void WindowRemoved(const QString &path); + // begin property changed signals + +public Q_SLOTS: + void CallQueued(const QString &callName, const QList &args); + +private Q_SLOTS: + void onPendingCallFinished(QDBusPendingCallWatcher *w); + +private: + __BamfApplicationPrivate *d_ptr; +}; + +namespace org { + namespace ayatana { + namespace bamf { + typedef ::__BamfApplication BamfApplication; + } + } +} +#endif diff --git a/src/frameworkdbus/dbusbamfmatcher.cpp b/src/frameworkdbus/dbusbamfmatcher.cpp new file mode 100644 index 0000000..10072c2 --- /dev/null +++ b/src/frameworkdbus/dbusbamfmatcher.cpp @@ -0,0 +1,75 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c BamfMatcher -p BamfMatcher Matcher.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "dbusbamfmatcher.h" + +/* + * Implementation of interface class __BamfMatcher + */ + +class __BamfMatcherPrivate +{ +public: + __BamfMatcherPrivate() = default; + + // begin member variables + +public: + QMap m_processingCalls; + QMap> m_waittingCalls; +}; + +__BamfMatcher::__BamfMatcher(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent) + , d_ptr(new __BamfMatcherPrivate) +{ + if (QMetaType::type("QList") == QMetaType::UnknownType) { + qRegisterMetaType< QList >("QList"); + qDBusRegisterMetaType< QList >(); + } +} + +__BamfMatcher::~__BamfMatcher() +{ + qDeleteAll(d_ptr->m_processingCalls.values()); + delete d_ptr; +} + +void __BamfMatcher::CallQueued(const QString &callName, const QList &args) +{ + if (d_ptr->m_waittingCalls.contains(callName)) + { + d_ptr->m_waittingCalls[callName] = args; + return; + } + if (d_ptr->m_processingCalls.contains(callName)) + { + d_ptr->m_waittingCalls.insert(callName, args); + } else { + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncCallWithArgumentList(callName, args)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &__BamfMatcher::onPendingCallFinished); + d_ptr->m_processingCalls.insert(callName, watcher); + } +} + +void __BamfMatcher::onPendingCallFinished(QDBusPendingCallWatcher *w) +{ + w->deleteLater(); + const auto callName = d_ptr->m_processingCalls.key(w); + Q_ASSERT(!callName.isEmpty()); + if (callName.isEmpty()) + return; + d_ptr->m_processingCalls.remove(callName); + if (!d_ptr->m_waittingCalls.contains(callName)) + return; + const auto args = d_ptr->m_waittingCalls.take(callName); + CallQueued(callName, args); +} diff --git a/src/frameworkdbus/dbusbamfmatcher.h b/src/frameworkdbus/dbusbamfmatcher.h new file mode 100644 index 0000000..1c09efb --- /dev/null +++ b/src/frameworkdbus/dbusbamfmatcher.h @@ -0,0 +1,188 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c BamfMatcher -p BamfMatcher Matcher.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef BAMFMATCHER_H +#define BAMFMATCHER_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * Proxy class for interface org.ayatana.bamf.matcher + */ +class __BamfMatcherPrivate; +class __BamfMatcher : public DBusExtendedAbstractInterface +{ + Q_OBJECT + +public: + static inline const char *staticInterfaceName() + { return "org.ayatana.bamf.matcher"; } + +public: + explicit __BamfMatcher(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~__BamfMatcher(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply ActiveApplication() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ActiveApplication"), argumentList); + } + + + + inline QDBusPendingReply ActiveWindow() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ActiveWindow"), argumentList); + } + + + + inline QDBusPendingReply ApplicationForXid(uint xid) + { + QList argumentList; + argumentList << QVariant::fromValue(xid); + return asyncCallWithArgumentList(QStringLiteral("ApplicationForXid"), argumentList); + } + + + + inline QDBusPendingReply ApplicationIsRunning(const QString &desktop_file) + { + QList argumentList; + argumentList << QVariant::fromValue(desktop_file); + return asyncCallWithArgumentList(QStringLiteral("ApplicationIsRunning"), argumentList); + } + + + + inline QDBusPendingReply ApplicationPaths() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ApplicationPaths"), argumentList); + } + + + + inline QDBusPendingReply PathForApplication(const QString &desktop_file) + { + QList argumentList; + argumentList << QVariant::fromValue(desktop_file); + return asyncCallWithArgumentList(QStringLiteral("PathForApplication"), argumentList); + } + + + + inline QDBusPendingReply<> RegisterFavorites(const QStringList &favorites) + { + QList argumentList; + argumentList << QVariant::fromValue(favorites); + return asyncCallWithArgumentList(QStringLiteral("RegisterFavorites"), argumentList); + } + + inline void RegisterFavoritesQueued(const QStringList &favorites) + { + QList argumentList; + argumentList << QVariant::fromValue(favorites); + + CallQueued(QStringLiteral("RegisterFavorites"), argumentList); + } + + + inline QDBusPendingReply RunningApplications() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RunningApplications"), argumentList); + } + + + + inline QDBusPendingReply RunningApplicationsDesktopFiles() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RunningApplicationsDesktopFiles"), argumentList); + } + + + + inline QDBusPendingReply TabPaths() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("TabPaths"), argumentList); + } + + + + inline QDBusPendingReply WindowPaths() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("WindowPaths"), argumentList); + } + + + + inline QDBusPendingReply WindowStackForMonitor(int monitor_id) + { + QList argumentList; + argumentList << QVariant::fromValue(monitor_id); + return asyncCallWithArgumentList(QStringLiteral("WindowStackForMonitor"), argumentList); + } + + + + inline QDBusPendingReply > XidsForApplication(const QString &desktop_file) + { + QList argumentList; + argumentList << QVariant::fromValue(desktop_file); + return asyncCallWithArgumentList(QStringLiteral("XidsForApplication"), argumentList); + } + + + + +Q_SIGNALS: // SIGNALS + void ActiveApplicationChanged(const QString &old_app, const QString &new_app); + void ActiveWindowChanged(const QString &old_win, const QString &new_win); + void RunningApplicationsChanged(const QStringList &opened_desktop_files, const QStringList &closed_desktop_files); + void StackingOrderChanged(); + void ViewClosed(const QString &path, const QString &type); + void ViewOpened(const QString &path, const QString &type); + // begin property changed signals + +public Q_SLOTS: + void CallQueued(const QString &callName, const QList &args); + +private Q_SLOTS: + void onPendingCallFinished(QDBusPendingCallWatcher *w); + +private: + __BamfMatcherPrivate *d_ptr; +}; + +namespace org { + namespace ayatana { + namespace bamf { + typedef ::__BamfMatcher BamfMatcher; + } + } +} +#endif diff --git a/src/frameworkdbus/dbuskwaylandoutput.cpp b/src/frameworkdbus/dbuskwaylandoutput.cpp new file mode 100644 index 0000000..8b4f23d --- /dev/null +++ b/src/frameworkdbus/dbuskwaylandoutput.cpp @@ -0,0 +1,71 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c OutputManagement -p generated/outputmanagement ../xml/OutputManagement.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "dbuskwaylandoutput.h" + +/* + * Implementation of interface class __OutputManagement + */ + +class __OutputManagementPrivate +{ +public: + __OutputManagementPrivate() = default; + + // begin member variables + +public: + QMap m_processingCalls; + QMap> m_waittingCalls; +}; + +__OutputManagement::__OutputManagement(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent) + , d_ptr(new __OutputManagementPrivate) +{ +} + +__OutputManagement::~__OutputManagement() +{ + qDeleteAll(d_ptr->m_processingCalls.values()); + delete d_ptr; +} + +void __OutputManagement::CallQueued(const QString &callName, const QList &args) +{ + if (d_ptr->m_waittingCalls.contains(callName)) + { + d_ptr->m_waittingCalls[callName] = args; + return; + } + if (d_ptr->m_processingCalls.contains(callName)) + { + d_ptr->m_waittingCalls.insert(callName, args); + } else { + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncCallWithArgumentList(callName, args)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &__OutputManagement::onPendingCallFinished); + d_ptr->m_processingCalls.insert(callName, watcher); + } +} + +void __OutputManagement::onPendingCallFinished(QDBusPendingCallWatcher *w) +{ + w->deleteLater(); + const auto callName = d_ptr->m_processingCalls.key(w); + Q_ASSERT(!callName.isEmpty()); + if (callName.isEmpty()) + return; + d_ptr->m_processingCalls.remove(callName); + if (!d_ptr->m_waittingCalls.contains(callName)) + return; + const auto args = d_ptr->m_waittingCalls.take(callName); + CallQueued(callName, args); +} diff --git a/src/frameworkdbus/dbuskwaylandoutput.h b/src/frameworkdbus/dbuskwaylandoutput.h new file mode 100644 index 0000000..244af62 --- /dev/null +++ b/src/frameworkdbus/dbuskwaylandoutput.h @@ -0,0 +1,119 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c OutputManagement -p generated/outputmanagement ../xml/OutputManagement.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef OUTPUTMANAGEMENT_H +#define OUTPUTMANAGEMENT_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * Proxy class for interface com.deepin.daemon.KWayland.Output + */ +class __OutputManagementPrivate; +class __OutputManagement : public DBusExtendedAbstractInterface +{ + Q_OBJECT + +public: + static inline const char *staticInterfaceName() + { return "com.deepin.daemon.KWayland.Output"; } + +public: + explicit __OutputManagement(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~__OutputManagement(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<> Apply(const QString &outputs) + { + QList argumentList; + argumentList << QVariant::fromValue(outputs); + return asyncCallWithArgumentList(QStringLiteral("Apply"), argumentList); + } + + inline void ApplyQueued(const QString &outputs) + { + QList argumentList; + argumentList << QVariant::fromValue(outputs); + + CallQueued(QStringLiteral("Apply"), argumentList); + } + + + inline QDBusPendingReply GetOutput(const QString &uuid) + { + QList argumentList; + argumentList << QVariant::fromValue(uuid); + return asyncCallWithArgumentList(QStringLiteral("GetOutput"), argumentList); + } + + + + inline QDBusPendingReply ListOutput() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ListOutput"), argumentList); + } + + + + inline QDBusPendingReply<> WlSimulateKey(int state) + { + QList argumentList; + argumentList << QVariant::fromValue(state); + return asyncCallWithArgumentList(QStringLiteral("WlSimulateKey"), argumentList); + } + + inline void WlSimulateKeyQueued(int state) + { + QList argumentList; + argumentList << QVariant::fromValue(state); + + CallQueued(QStringLiteral("WlSimulateKey"), argumentList); + } + + + +Q_SIGNALS: // SIGNALS + void OutputAdded(const QString &output); + void OutputChanged(const QString &output); + void OutputRemoved(const QString &output); + // begin property changed signals + +public Q_SLOTS: + void CallQueued(const QString &callName, const QList &args); + +private Q_SLOTS: + void onPendingCallFinished(QDBusPendingCallWatcher *w); + +private: + __OutputManagementPrivate *d_ptr; +}; + +namespace com { + namespace deepin { + namespace daemon { + namespace kwayland { + typedef ::__OutputManagement Output; + } + } + } +} +#endif diff --git a/src/frameworkdbus/dbuskwaylandwindowmanager.cpp b/src/frameworkdbus/dbuskwaylandwindowmanager.cpp new file mode 100644 index 0000000..7c051ce --- /dev/null +++ b/src/frameworkdbus/dbuskwaylandwindowmanager.cpp @@ -0,0 +1,71 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c kwaylandmanager -p kwaylandmanager com.deepin.daemon.KWayland.WindowManager.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "dbuskwaylandwindowmanager.h" + +/* + * Implementation of interface class __kwaylandmanager + */ + +class __kwaylandmanagerPrivate +{ +public: + __kwaylandmanagerPrivate() = default; + + // begin member variables + +public: + QMap m_processingCalls; + QMap> m_waittingCalls; +}; + +__KwaylandManager::__KwaylandManager(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent) + , d_ptr(new __kwaylandmanagerPrivate) +{ +} + +__KwaylandManager::~__KwaylandManager() +{ + qDeleteAll(d_ptr->m_processingCalls.values()); + delete d_ptr; +} + +void __KwaylandManager::CallQueued(const QString &callName, const QList &args) +{ + if (d_ptr->m_waittingCalls.contains(callName)) + { + d_ptr->m_waittingCalls[callName] = args; + return; + } + if (d_ptr->m_processingCalls.contains(callName)) + { + d_ptr->m_waittingCalls.insert(callName, args); + } else { + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncCallWithArgumentList(callName, args)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &__KwaylandManager::onPendingCallFinished); + d_ptr->m_processingCalls.insert(callName, watcher); + } +} + +void __KwaylandManager::onPendingCallFinished(QDBusPendingCallWatcher *w) +{ + w->deleteLater(); + const auto callName = d_ptr->m_processingCalls.key(w); + Q_ASSERT(!callName.isEmpty()); + if (callName.isEmpty()) + return; + d_ptr->m_processingCalls.remove(callName); + if (!d_ptr->m_waittingCalls.contains(callName)) + return; + const auto args = d_ptr->m_waittingCalls.take(callName); + CallQueued(callName, args); +} diff --git a/src/frameworkdbus/dbuskwaylandwindowmanager.h b/src/frameworkdbus/dbuskwaylandwindowmanager.h new file mode 100644 index 0000000..ced6126 --- /dev/null +++ b/src/frameworkdbus/dbuskwaylandwindowmanager.h @@ -0,0 +1,94 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c kwaylandmanager -p kwaylandmanager com.deepin.daemon.KWayland.WindowManager.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef KWAYLANDMANAGER_H +#define KWAYLANDMANAGER_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * Proxy class for interface com.deepin.daemon.KWayland.WindowManager + */ +class __kwaylandmanagerPrivate; +class __KwaylandManager : public DBusExtendedAbstractInterface +{ + Q_OBJECT + +public: + static inline const char *staticInterfaceName() + { return "com.deepin.daemon.KWayland.WindowManager"; } + +public: + explicit __KwaylandManager(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~__KwaylandManager(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply ActiveWindow() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ActiveWindow"), argumentList); + } + + + + inline QDBusPendingReply IsShowingDesktop() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsShowingDesktop"), argumentList); + } + + + + inline QDBusPendingReply Windows() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Windows"), argumentList); + } + + + + +Q_SIGNALS: // SIGNALS + void ActiveWindowChanged(); + void WindowCreated(const QString &ObjPath); + void WindowRemove(const QString &ObjPath); + // begin property changed signals + +public Q_SLOTS: + void CallQueued(const QString &callName, const QList &args); + +private Q_SLOTS: + void onPendingCallFinished(QDBusPendingCallWatcher *w); + +private: + __kwaylandmanagerPrivate *d_ptr; +}; + +namespace com { + namespace deepin { + namespace daemon { + namespace kwayland { + typedef ::__KwaylandManager WindowManager; + } + } + } +} +#endif diff --git a/src/frameworkdbus/dbuslauncher.cpp b/src/frameworkdbus/dbuslauncher.cpp new file mode 100644 index 0000000..16ee681 --- /dev/null +++ b/src/frameworkdbus/dbuslauncher.cpp @@ -0,0 +1,129 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c Launcherd -p generated/com_deepin_dde_daemon_launcherd ../xml/com.deepin.dde.daemon.Launcherd.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "dbuslauncher.h" + +/* + * Implementation of interface class __Launcherd + */ + +class __LauncherdPrivate +{ +public: + __LauncherdPrivate() = default; + + // begin member variables + int DisplayMode; + bool Fullscreen; + +public: + QMap m_processingCalls; + QMap> m_waittingCalls; +}; + +LauncherBackEnd::LauncherBackEnd(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent) + , d_ptr(new __LauncherdPrivate) +{ + connect(this, &LauncherBackEnd::propertyChanged, this, &LauncherBackEnd::onPropertyChanged); + + if (QMetaType::type("LauncherItemInfo") == QMetaType::UnknownType) + registerLauncherItemInfoMetaType(); + if (QMetaType::type("LauncherItemInfoList") == QMetaType::UnknownType) + registerLauncherItemInfoListMetaType(); +} + +LauncherBackEnd::~LauncherBackEnd() +{ + qDeleteAll(d_ptr->m_processingCalls.values()); + delete d_ptr; +} + +void LauncherBackEnd::onPropertyChanged(const QString &propName, const QVariant &value) +{ + if (propName == QStringLiteral("DisplayMode")) + { + const int &DisplayMode = qvariant_cast(value); + if (d_ptr->DisplayMode != DisplayMode) + { + d_ptr->DisplayMode = DisplayMode; + Q_EMIT DisplayModeChanged(d_ptr->DisplayMode); + } + return; + } + + if (propName == QStringLiteral("Fullscreen")) + { + const bool &Fullscreen = qvariant_cast(value); + if (d_ptr->Fullscreen != Fullscreen) + { + d_ptr->Fullscreen = Fullscreen; + Q_EMIT FullscreenChanged(d_ptr->Fullscreen); + } + return; + } + + qWarning() << "property not handle: " << propName; + return; +} + +int LauncherBackEnd::displayMode() +{ + return qvariant_cast(internalPropGet("DisplayMode", &d_ptr->DisplayMode)); +} + +void LauncherBackEnd::setDisplayMode(int value) +{ + + internalPropSet("DisplayMode", QVariant::fromValue(value), &d_ptr->DisplayMode); +} + +bool LauncherBackEnd::fullscreen() +{ + return qvariant_cast(internalPropGet("Fullscreen", &d_ptr->Fullscreen)); +} + +void LauncherBackEnd::setFullscreen(bool value) +{ + + internalPropSet("Fullscreen", QVariant::fromValue(value), &d_ptr->Fullscreen); +} + +void LauncherBackEnd::CallQueued(const QString &callName, const QList &args) +{ + if (d_ptr->m_waittingCalls.contains(callName)) + { + d_ptr->m_waittingCalls[callName] = args; + return; + } + if (d_ptr->m_processingCalls.contains(callName)) + { + d_ptr->m_waittingCalls.insert(callName, args); + } else { + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncCallWithArgumentList(callName, args)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &LauncherBackEnd::onPendingCallFinished); + d_ptr->m_processingCalls.insert(callName, watcher); + } +} + +void LauncherBackEnd::onPendingCallFinished(QDBusPendingCallWatcher *w) +{ + w->deleteLater(); + const auto callName = d_ptr->m_processingCalls.key(w); + Q_ASSERT(!callName.isEmpty()); + if (callName.isEmpty()) + return; + d_ptr->m_processingCalls.remove(callName); + if (!d_ptr->m_waittingCalls.contains(callName)) + return; + const auto args = d_ptr->m_waittingCalls.take(callName); + CallQueued(callName, args); +} diff --git a/src/frameworkdbus/dbuslauncher.h b/src/frameworkdbus/dbuslauncher.h new file mode 100644 index 0000000..3dab6be --- /dev/null +++ b/src/frameworkdbus/dbuslauncher.h @@ -0,0 +1,235 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c Launcherd -p generated/com_deepin_dde_daemon_launcherd ../xml/com.deepin.dde.daemon.Launcherd.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef COM_DEEPIN_DDE_DAEMON_LAUNCHERD_H +#define COM_DEEPIN_DDE_DAEMON_LAUNCHERD_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "types/launcheriteminfo.h" +#include "types/launcheriteminfolist.h" + +/* + * Proxy class for interface org.deepin.dde.daemon.Launcher1 + */ +class __LauncherdPrivate; +class LauncherBackEnd : public DBusExtendedAbstractInterface +{ + Q_OBJECT + +public: + static inline const char *staticInterfaceName() + { return "org.deepin.dde.daemon.Launcher1"; } + +public: + explicit LauncherBackEnd(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~LauncherBackEnd(); + + Q_PROPERTY(int DisplayMode READ displayMode WRITE setDisplayMode NOTIFY DisplayModeChanged) + int displayMode(); + void setDisplayMode(int value); + + Q_PROPERTY(bool Fullscreen READ fullscreen WRITE setFullscreen NOTIFY FullscreenChanged) + bool fullscreen(); + void setFullscreen(bool value); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply GetAllItemInfos() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("GetAllItemInfos"), argumentList); + } + + + + inline QDBusPendingReply GetAllNewInstalledApps() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("GetAllNewInstalledApps"), argumentList); + } + + + + inline QDBusPendingReply GetDisableScaling(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + return asyncCallWithArgumentList(QStringLiteral("GetDisableScaling"), argumentList); + } + + + + inline QDBusPendingReply GetItemInfo(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + return asyncCallWithArgumentList(QStringLiteral("GetItemInfo"), argumentList); + } + + + + inline QDBusPendingReply GetUseProxy(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + return asyncCallWithArgumentList(QStringLiteral("GetUseProxy"), argumentList); + } + + + + inline QDBusPendingReply IsItemOnDesktop(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + return asyncCallWithArgumentList(QStringLiteral("IsItemOnDesktop"), argumentList); + } + + + + inline QDBusPendingReply<> MarkLaunched(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + return asyncCallWithArgumentList(QStringLiteral("MarkLaunched"), argumentList); + } + + inline void MarkLaunchedQueued(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + + CallQueued(QStringLiteral("MarkLaunched"), argumentList); + } + + + inline QDBusPendingReply RequestRemoveFromDesktop(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + return asyncCallWithArgumentList(QStringLiteral("RequestRemoveFromDesktop"), argumentList); + } + + + + inline QDBusPendingReply RequestSendToDesktop(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + return asyncCallWithArgumentList(QStringLiteral("RequestSendToDesktop"), argumentList); + } + + + + inline QDBusPendingReply<> RequestUninstall(const QString &id, bool purge) + { + QList argumentList; + argumentList << QVariant::fromValue(id) << QVariant::fromValue(purge); + return asyncCallWithArgumentList(QStringLiteral("RequestUninstall"), argumentList); + } + + inline void RequestUninstallQueued(const QString &id, bool purge) + { + QList argumentList; + argumentList << QVariant::fromValue(id) << QVariant::fromValue(purge); + + CallQueued(QStringLiteral("RequestUninstall"), argumentList); + } + + + inline QDBusPendingReply<> Search(const QString &key) + { + QList argumentList; + argumentList << QVariant::fromValue(key); + return asyncCallWithArgumentList(QStringLiteral("Search"), argumentList); + } + + inline void SearchQueued(const QString &key) + { + QList argumentList; + argumentList << QVariant::fromValue(key); + + CallQueued(QStringLiteral("Search"), argumentList); + } + + + inline QDBusPendingReply<> SetDisableScaling(const QString &id, bool value) + { + QList argumentList; + argumentList << QVariant::fromValue(id) << QVariant::fromValue(value); + return asyncCallWithArgumentList(QStringLiteral("SetDisableScaling"), argumentList); + } + + inline void SetDisableScalingQueued(const QString &id, bool value) + { + QList argumentList; + argumentList << QVariant::fromValue(id) << QVariant::fromValue(value); + + CallQueued(QStringLiteral("SetDisableScaling"), argumentList); + } + + + inline QDBusPendingReply<> SetUseProxy(const QString &id, bool value) + { + QList argumentList; + argumentList << QVariant::fromValue(id) << QVariant::fromValue(value); + return asyncCallWithArgumentList(QStringLiteral("SetUseProxy"), argumentList); + } + + inline void SetUseProxyQueued(const QString &id, bool value) + { + QList argumentList; + argumentList << QVariant::fromValue(id) << QVariant::fromValue(value); + + CallQueued(QStringLiteral("SetUseProxy"), argumentList); + } + + + +Q_SIGNALS: // SIGNALS + void ItemChanged(const QString &status, LauncherItemInfo itemInfo, qlonglong categoryID); + void NewAppLaunched(const QString &appID); + void SearchDone(const QStringList &apps); + void UninstallFailed(const QString &appId, const QString &errMsg); + void UninstallSuccess(const QString &appID); + // begin property changed signals + void DisplayModeChanged(int value) const; + void FullscreenChanged(bool value) const; + +public Q_SLOTS: + void CallQueued(const QString &callName, const QList &args); + +private Q_SLOTS: + void onPendingCallFinished(QDBusPendingCallWatcher *w); + void onPropertyChanged(const QString &propName, const QVariant &value); + +private: + __LauncherdPrivate *d_ptr; +}; + +namespace com { + namespace deepin { + namespace dde { + namespace daemon { + typedef ::LauncherBackEnd LauncherBackEnd; + } + } + } +} +#endif diff --git a/src/frameworkdbus/dbuslauncherfront.cpp b/src/frameworkdbus/dbuslauncherfront.cpp new file mode 100644 index 0000000..e7ffef9 --- /dev/null +++ b/src/frameworkdbus/dbuslauncherfront.cpp @@ -0,0 +1,96 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c Launcher -p generated/com_deepin_dde_launcher ../xml/com.deepin.dde.Launcher.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "dbuslauncherfront.h" + +/* + * Implementation of interface class __Launcher + */ + +class __LauncherPrivate +{ +public: + __LauncherPrivate() = default; + + // begin member variables + bool Visible; + +public: + QMap m_processingCalls; + QMap> m_waittingCalls; +}; + +LauncherFront::LauncherFront(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent) + , d_ptr(new __LauncherPrivate) +{ + connect(this, &LauncherFront::propertyChanged, this, &LauncherFront::onPropertyChanged); + +} + +LauncherFront::~LauncherFront() +{ + qDeleteAll(d_ptr->m_processingCalls.values()); + delete d_ptr; +} + +void LauncherFront::onPropertyChanged(const QString &propName, const QVariant &value) +{ + if (propName == QStringLiteral("Visible")) + { + const bool &Visible = qvariant_cast(value); + if (d_ptr->Visible != Visible) + { + d_ptr->Visible = Visible; + Q_EMIT VisibleChanged(d_ptr->Visible); + } + return; + } + + qWarning() << "property not handle: " << propName; + return; +} + +bool LauncherFront::visible() +{ + return qvariant_cast(internalPropGet("Visible", &d_ptr->Visible)); +} + +void LauncherFront::CallQueued(const QString &callName, const QList &args) +{ + if (d_ptr->m_waittingCalls.contains(callName)) + { + d_ptr->m_waittingCalls[callName] = args; + return; + } + if (d_ptr->m_processingCalls.contains(callName)) + { + d_ptr->m_waittingCalls.insert(callName, args); + } else { + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncCallWithArgumentList(callName, args)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &LauncherFront::onPendingCallFinished); + d_ptr->m_processingCalls.insert(callName, watcher); + } +} + +void LauncherFront::onPendingCallFinished(QDBusPendingCallWatcher *w) +{ + w->deleteLater(); + const auto callName = d_ptr->m_processingCalls.key(w); + Q_ASSERT(!callName.isEmpty()); + if (callName.isEmpty()) + return; + d_ptr->m_processingCalls.remove(callName); + if (!d_ptr->m_waittingCalls.contains(callName)) + return; + const auto args = d_ptr->m_waittingCalls.take(callName); + CallQueued(callName, args); +} diff --git a/src/frameworkdbus/dbuslauncherfront.h b/src/frameworkdbus/dbuslauncherfront.h new file mode 100644 index 0000000..df42cf4 --- /dev/null +++ b/src/frameworkdbus/dbuslauncherfront.h @@ -0,0 +1,169 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c Launcher -p generated/com_deepin_dde_launcher ../xml/com.deepin.dde.Launcher.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef COM_DEEPIN_DDE_LAUNCHER_H +#define COM_DEEPIN_DDE_LAUNCHER_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * Proxy class for interface org.deepin.dde.Launcher1 + */ +class __LauncherPrivate; +class LauncherFront : public DBusExtendedAbstractInterface +{ + Q_OBJECT + +public: + static inline const char *staticInterfaceName() + { return "org.deepin.dde.Launcher1"; } + +public: + explicit LauncherFront(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~LauncherFront(); + + Q_PROPERTY(bool Visible READ visible NOTIFY VisibleChanged) + bool visible(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<> Exit() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Exit"), argumentList); + } + + inline void ExitQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("Exit"), argumentList); + } + + + inline QDBusPendingReply<> Hide() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Hide"), argumentList); + } + + inline void HideQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("Hide"), argumentList); + } + + + inline QDBusPendingReply IsVisible() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsVisible"), argumentList); + } + + + + inline QDBusPendingReply<> Show() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Show"), argumentList); + } + + inline void ShowQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("Show"), argumentList); + } + + + inline QDBusPendingReply<> ShowByMode(qlonglong in0) + { + QList argumentList; + argumentList << QVariant::fromValue(in0); + return asyncCallWithArgumentList(QStringLiteral("ShowByMode"), argumentList); + } + + inline void ShowByModeQueued(qlonglong in0) + { + QList argumentList; + argumentList << QVariant::fromValue(in0); + + CallQueued(QStringLiteral("ShowByMode"), argumentList); + } + + + inline QDBusPendingReply<> Toggle() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Toggle"), argumentList); + } + + inline void ToggleQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("Toggle"), argumentList); + } + + + inline QDBusPendingReply<> UninstallApp(const QString &appKey) + { + QList argumentList; + argumentList << QVariant::fromValue(appKey); + return asyncCallWithArgumentList(QStringLiteral("UninstallApp"), argumentList); + } + + inline void UninstallAppQueued(const QString &appKey) + { + QList argumentList; + argumentList << QVariant::fromValue(appKey); + + CallQueued(QStringLiteral("UninstallApp"), argumentList); + } + + + +Q_SIGNALS: // SIGNALS + void Closed(); + void Shown(); + void VisibleChanged(bool visible); + // begin property changed signals + //void VisibleChanged(bool value) const; + +public Q_SLOTS: + void CallQueued(const QString &callName, const QList &args); + +private Q_SLOTS: + void onPendingCallFinished(QDBusPendingCallWatcher *w); + void onPropertyChanged(const QString &propName, const QVariant &value); + +private: + __LauncherPrivate *d_ptr; +}; + +namespace com { + namespace deepin { + namespace dde { + typedef ::LauncherFront LauncherFront; + } + } +} +#endif diff --git a/src/frameworkdbus/dbusplasmawindow.cpp b/src/frameworkdbus/dbusplasmawindow.cpp new file mode 100644 index 0000000..5b9c901 --- /dev/null +++ b/src/frameworkdbus/dbusplasmawindow.cpp @@ -0,0 +1,73 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c Window -p generated/window ../xml/Window.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "dbusplasmawindow.h" + +/* + * Implementation of interface class __Window + */ + +class __WindowPrivate +{ +public: + __WindowPrivate() = default; + + // begin member variables + +public: + QMap m_processingCalls; + QMap> m_waittingCalls; +}; + +PlasmaWindow::PlasmaWindow(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent) + , d_ptr(new __WindowPrivate) +{ + if (QMetaType::type("Rect") == QMetaType::UnknownType) + registerRectMetaType(); +} + +PlasmaWindow::~PlasmaWindow() +{ + qDeleteAll(d_ptr->m_processingCalls.values()); + delete d_ptr; +} + +void PlasmaWindow::CallQueued(const QString &callName, const QList &args) +{ + if (d_ptr->m_waittingCalls.contains(callName)) + { + d_ptr->m_waittingCalls[callName] = args; + return; + } + if (d_ptr->m_processingCalls.contains(callName)) + { + d_ptr->m_waittingCalls.insert(callName, args); + } else { + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncCallWithArgumentList(callName, args)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &PlasmaWindow::onPendingCallFinished); + d_ptr->m_processingCalls.insert(callName, watcher); + } +} + +void PlasmaWindow::onPendingCallFinished(QDBusPendingCallWatcher *w) +{ + w->deleteLater(); + const auto callName = d_ptr->m_processingCalls.key(w); + Q_ASSERT(!callName.isEmpty()); + if (callName.isEmpty()) + return; + d_ptr->m_processingCalls.remove(callName); + if (!d_ptr->m_waittingCalls.contains(callName)) + return; + const auto args = d_ptr->m_waittingCalls.take(callName); + CallQueued(callName, args); +} diff --git a/src/frameworkdbus/dbusplasmawindow.h b/src/frameworkdbus/dbusplasmawindow.h new file mode 100644 index 0000000..df78724 --- /dev/null +++ b/src/frameworkdbus/dbusplasmawindow.h @@ -0,0 +1,499 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c Window -p generated/window ../xml/Window.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef WINDOW_H +#define WINDOW_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "types/rect.h" + +/* + * Proxy class for interface com.deepin.daemon.KWayland.PlasmaWindow + */ +class __WindowPrivate; +class PlasmaWindow : public DBusExtendedAbstractInterface +{ + Q_OBJECT + +public: + static inline const char *staticInterfaceName() + { return "com.deepin.daemon.KWayland.PlasmaWindow"; } + +public: + explicit PlasmaWindow(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~PlasmaWindow(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply AppId() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("AppId"), argumentList); + } + + + + inline QDBusPendingReply Geometry() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Geometry"), argumentList); + } + + + + inline QDBusPendingReply Icon() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Icon"), argumentList); + } + + + + inline QDBusPendingReply InternalId() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("InternalId"), argumentList); + } + + + + inline QDBusPendingReply IsActive() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsActive"), argumentList); + } + + + + inline QDBusPendingReply IsCloseable() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsCloseable"), argumentList); + } + + + + inline QDBusPendingReply IsDemandingAttention() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsDemandingAttention"), argumentList); + } + + + + inline QDBusPendingReply IsFullscreen() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsFullscreen"), argumentList); + } + + + + inline QDBusPendingReply IsFullscreenable() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsFullscreenable"), argumentList); + } + + + + inline QDBusPendingReply IsKeepAbove() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsKeepAbove"), argumentList); + } + + + + inline QDBusPendingReply IsMaximizeable() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsMaximizeable"), argumentList); + } + + + + inline QDBusPendingReply IsMaximized() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsMaximized"), argumentList); + } + + + + inline QDBusPendingReply IsMinimizeable() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsMinimizeable"), argumentList); + } + + + + inline QDBusPendingReply IsMinimized() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsMinimized"), argumentList); + } + + + + inline QDBusPendingReply IsMovable() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsMovable"), argumentList); + } + + + + inline QDBusPendingReply IsOnAllDesktops() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsOnAllDesktops"), argumentList); + } + + + + inline QDBusPendingReply IsResizable() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsResizable"), argumentList); + } + + + + inline QDBusPendingReply IsShadeable() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsShadeable"), argumentList); + } + + + + inline QDBusPendingReply IsShaded() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsShaded"), argumentList); + } + + + + inline QDBusPendingReply IsValid() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsValid"), argumentList); + } + + + + inline QDBusPendingReply IsVirtualDesktopChangeable() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("IsVirtualDesktopChangeable"), argumentList); + } + + + + inline QDBusPendingReply Pid() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Pid"), argumentList); + } + + + + inline QDBusPendingReply<> RequestActivate() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RequestActivate"), argumentList); + } + + inline void RequestActivateQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RequestActivate"), argumentList); + } + + + inline QDBusPendingReply<> RequestClose() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RequestClose"), argumentList); + } + + inline void RequestCloseQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RequestClose"), argumentList); + } + + + inline QDBusPendingReply<> RequestEnterNewVirtualDesktop() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RequestEnterNewVirtualDesktop"), argumentList); + } + + inline void RequestEnterNewVirtualDesktopQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RequestEnterNewVirtualDesktop"), argumentList); + } + + + inline QDBusPendingReply<> RequestEnterVirtualDesktop(const QString &argin0) + { + QList argumentList; + argumentList << QVariant::fromValue(argin0); + return asyncCallWithArgumentList(QStringLiteral("RequestEnterVirtualDesktop"), argumentList); + } + + inline void RequestEnterVirtualDesktopQueued(const QString &argin0) + { + QList argumentList; + argumentList << QVariant::fromValue(argin0); + + CallQueued(QStringLiteral("RequestEnterVirtualDesktop"), argumentList); + } + + + inline QDBusPendingReply<> RequestLeaveVirtualDesktop(const QString &argin0) + { + QList argumentList; + argumentList << QVariant::fromValue(argin0); + return asyncCallWithArgumentList(QStringLiteral("RequestLeaveVirtualDesktop"), argumentList); + } + + inline void RequestLeaveVirtualDesktopQueued(const QString &argin0) + { + QList argumentList; + argumentList << QVariant::fromValue(argin0); + + CallQueued(QStringLiteral("RequestLeaveVirtualDesktop"), argumentList); + } + + + inline QDBusPendingReply<> RequestMove() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RequestMove"), argumentList); + } + + inline void RequestMoveQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RequestMove"), argumentList); + } + + + inline QDBusPendingReply<> RequestResize() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RequestResize"), argumentList); + } + + inline void RequestResizeQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RequestResize"), argumentList); + } + + + inline QDBusPendingReply<> RequestToggleKeepAbove() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RequestToggleKeepAbove"), argumentList); + } + + inline void RequestToggleKeepAboveQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RequestToggleKeepAbove"), argumentList); + } + + + inline QDBusPendingReply<> RequestToggleKeepBelow() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RequestToggleKeepBelow"), argumentList); + } + + inline void RequestToggleKeepBelowQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RequestToggleKeepBelow"), argumentList); + } + + + inline QDBusPendingReply<> RequestToggleMaximized() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RequestToggleMaximized"), argumentList); + } + + inline void RequestToggleMaximizedQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RequestToggleMaximized"), argumentList); + } + + + inline QDBusPendingReply<> RequestToggleMinimized() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RequestToggleMinimized"), argumentList); + } + + inline void RequestToggleMinimizedQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RequestToggleMinimized"), argumentList); + } + + + inline QDBusPendingReply<> RequestToggleShaded() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RequestToggleShaded"), argumentList); + } + + inline void RequestToggleShadedQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RequestToggleShaded"), argumentList); + } + + + inline QDBusPendingReply<> RequestVirtualDesktop(uint argin0) + { + QList argumentList; + argumentList << QVariant::fromValue(argin0); + return asyncCallWithArgumentList(QStringLiteral("RequestVirtualDesktop"), argumentList); + } + + inline void RequestVirtualDesktopQueued(uint argin0) + { + QList argumentList; + argumentList << QVariant::fromValue(argin0); + + CallQueued(QStringLiteral("RequestVirtualDesktop"), argumentList); + } + + + inline QDBusPendingReply SkipSwitcher() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("SkipSwitcher"), argumentList); + } + + + + inline QDBusPendingReply SkipTaskbar() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("SkipTaskbar"), argumentList); + } + + + + inline QDBusPendingReply Title() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Title"), argumentList); + } + + + + inline QDBusPendingReply VirtualDesktop() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("VirtualDesktop"), argumentList); + } + + + + inline QDBusPendingReply WindowId() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("WindowId"), argumentList); + } + + + + +Q_SIGNALS: // SIGNALS + void ActiveChanged(); + void AppIdChanged(); + void CloseableChanged(); + void DemandsAttentionChanged(); + void FullscreenChanged(); + void FullscreenableChanged(); + void GeometryChanged(); + void IconChanged(); + void KeepAboveChanged(); + void KeepBelowChanged(); + void MaximizeableChanged(); + void MaximizedChanged(); + void MinimizeableChanged(); + void MinimizedChanged(); + void MovableChanged(); + void OnAllDesktopsChanged(); + void ParentWindowChanged(); + void ResizableChanged(); + void ShadeableChanged(); + void ShadedChanged(); + void SkipSwitcherChanged(); + void SkipTaskbarChanged(); + void TitleChanged(); + void Unmapped(); + void VirtualDesktopChangeableChanged(); + void VirtualDesktopChanged(); + void WindowIdChanged(); + // begin property changed signals + +public Q_SLOTS: + void CallQueued(const QString &callName, const QList &args); + +private Q_SLOTS: + void onPendingCallFinished(QDBusPendingCallWatcher *w); + +private: + __WindowPrivate *d_ptr; +}; + +namespace com { + namespace deepin { + namespace daemon { + namespace kwayland { + typedef ::PlasmaWindow PlasmaWindow; + } + } + } +} +#endif diff --git a/src/frameworkdbus/dbuswm.cpp b/src/frameworkdbus/dbuswm.cpp new file mode 100644 index 0000000..008baee --- /dev/null +++ b/src/frameworkdbus/dbuswm.cpp @@ -0,0 +1,209 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c wm -p generated/com_deepin_wm ../xml/com.deepin.wm.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "dbuswm.h" + +/* + * Implementation of interface class __wm + */ + +class __wmPrivate +{ +public: + __wmPrivate() = default; + + // begin member variables + bool compositingAllowSwitch; + bool compositingEnabled; + bool compositingPossible; + int cursorSize; + QString cursorTheme; + bool zoneEnabled; + +public: + QMap m_processingCalls; + QMap> m_waittingCalls; +}; + +__wm::__wm(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent) + , d_ptr(new __wmPrivate) +{ + connect(this, &__wm::propertyChanged, this, &__wm::onPropertyChanged); + + if (QMetaType::type("QList") == QMetaType::UnknownType) { + qRegisterMetaType< QList >("QList"); + qDBusRegisterMetaType< QList >(); + } +} + +__wm::~__wm() +{ + qDeleteAll(d_ptr->m_processingCalls.values()); + delete d_ptr; +} + +void __wm::onPropertyChanged(const QString &propName, const QVariant &value) +{ + if (propName == QStringLiteral("compositingAllowSwitch")) + { + const bool &compositingAllowSwitch = qvariant_cast(value); + if (d_ptr->compositingAllowSwitch != compositingAllowSwitch) + { + d_ptr->compositingAllowSwitch = compositingAllowSwitch; + Q_EMIT CompositingAllowSwitchChanged(d_ptr->compositingAllowSwitch); + } + return; + } + + if (propName == QStringLiteral("compositingEnabled")) + { + const bool &compositingEnabled = qvariant_cast(value); + if (d_ptr->compositingEnabled != compositingEnabled) + { + d_ptr->compositingEnabled = compositingEnabled; + Q_EMIT CompositingEnabledChanged(d_ptr->compositingEnabled); + } + return; + } + + if (propName == QStringLiteral("compositingPossible")) + { + const bool &compositingPossible = qvariant_cast(value); + if (d_ptr->compositingPossible != compositingPossible) + { + d_ptr->compositingPossible = compositingPossible; + Q_EMIT CompositingPossibleChanged(d_ptr->compositingPossible); + } + return; + } + + if (propName == QStringLiteral("cursorSize")) + { + const int &cursorSize = qvariant_cast(value); + if (d_ptr->cursorSize != cursorSize) + { + d_ptr->cursorSize = cursorSize; + Q_EMIT CursorSizeChanged(d_ptr->cursorSize); + } + return; + } + + if (propName == QStringLiteral("cursorTheme")) + { + const QString &cursorTheme = qvariant_cast(value); + if (d_ptr->cursorTheme != cursorTheme) + { + d_ptr->cursorTheme = cursorTheme; + Q_EMIT CursorThemeChanged(d_ptr->cursorTheme); + } + return; + } + + if (propName == QStringLiteral("zoneEnabled")) + { + const bool &zoneEnabled = qvariant_cast(value); + if (d_ptr->zoneEnabled != zoneEnabled) + { + d_ptr->zoneEnabled = zoneEnabled; + Q_EMIT ZoneEnabledChanged(d_ptr->zoneEnabled); + } + return; + } + + qWarning() << "property not handle: " << propName; + return; +} + +bool __wm::compositingAllowSwitch() +{ + return qvariant_cast(internalPropGet("compositingAllowSwitch", &d_ptr->compositingAllowSwitch)); +} + +bool __wm::compositingEnabled() +{ + return qvariant_cast(internalPropGet("compositingEnabled", &d_ptr->compositingEnabled)); +} + +void __wm::setCompositingEnabled(bool value) +{ + + internalPropSet("compositingEnabled", QVariant::fromValue(value), &d_ptr->compositingEnabled); +} + +bool __wm::compositingPossible() +{ + return qvariant_cast(internalPropGet("compositingPossible", &d_ptr->compositingPossible)); +} + +int __wm::cursorSize() +{ + return qvariant_cast(internalPropGet("cursorSize", &d_ptr->cursorSize)); +} + +void __wm::setCursorSize(int value) +{ + + internalPropSet("cursorSize", QVariant::fromValue(value), &d_ptr->cursorSize); +} + +QString __wm::cursorTheme() +{ + return qvariant_cast(internalPropGet("cursorTheme", &d_ptr->cursorTheme)); +} + +void __wm::setCursorTheme(const QString &value) +{ + + internalPropSet("cursorTheme", QVariant::fromValue(value), &d_ptr->cursorTheme); +} + +bool __wm::zoneEnabled() +{ + return qvariant_cast(internalPropGet("zoneEnabled", &d_ptr->zoneEnabled)); +} + +void __wm::setZoneEnabled(bool value) +{ + + internalPropSet("zoneEnabled", QVariant::fromValue(value), &d_ptr->zoneEnabled); +} + +void __wm::CallQueued(const QString &callName, const QList &args) +{ + if (d_ptr->m_waittingCalls.contains(callName)) + { + d_ptr->m_waittingCalls[callName] = args; + return; + } + if (d_ptr->m_processingCalls.contains(callName)) + { + d_ptr->m_waittingCalls.insert(callName, args); + } else { + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncCallWithArgumentList(callName, args)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &__wm::onPendingCallFinished); + d_ptr->m_processingCalls.insert(callName, watcher); + } +} + +void __wm::onPendingCallFinished(QDBusPendingCallWatcher *w) +{ + w->deleteLater(); + const auto callName = d_ptr->m_processingCalls.key(w); + Q_ASSERT(!callName.isEmpty()); + if (callName.isEmpty()) + return; + d_ptr->m_processingCalls.remove(callName); + if (!d_ptr->m_waittingCalls.contains(callName)) + return; + const auto args = d_ptr->m_waittingCalls.take(callName); + CallQueued(callName, args); +} diff --git a/src/frameworkdbus/dbuswm.h b/src/frameworkdbus/dbuswm.h new file mode 100644 index 0000000..dd6f0e3 --- /dev/null +++ b/src/frameworkdbus/dbuswm.h @@ -0,0 +1,708 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c wm -p generated/com_deepin_wm ../xml/com.deepin.wm.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef COM_DEEPIN_WM_H +#define COM_DEEPIN_WM_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * Proxy class for interface com.deepin.wm + */ +class __wmPrivate; +class __wm : public DBusExtendedAbstractInterface +{ + Q_OBJECT + +public: + static inline const char *staticInterfaceName() + { return "com.deepin.wm"; } + +public: + explicit __wm(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~__wm(); + + Q_PROPERTY(bool compositingAllowSwitch READ compositingAllowSwitch NOTIFY CompositingAllowSwitchChanged) + bool compositingAllowSwitch(); + + Q_PROPERTY(bool compositingEnabled READ compositingEnabled WRITE setCompositingEnabled NOTIFY CompositingEnabledChanged) + bool compositingEnabled(); + void setCompositingEnabled(bool value); + + Q_PROPERTY(bool compositingPossible READ compositingPossible NOTIFY CompositingPossibleChanged) + bool compositingPossible(); + + Q_PROPERTY(int cursorSize READ cursorSize WRITE setCursorSize NOTIFY CursorSizeChanged) + int cursorSize(); + void setCursorSize(int value); + + Q_PROPERTY(QString cursorTheme READ cursorTheme WRITE setCursorTheme NOTIFY CursorThemeChanged) + QString cursorTheme(); + void setCursorTheme(const QString &value); + + Q_PROPERTY(bool zoneEnabled READ zoneEnabled WRITE setZoneEnabled NOTIFY ZoneEnabledChanged) + bool zoneEnabled(); + void setZoneEnabled(bool value); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<> BeginToMoveActiveWindow() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("BeginToMoveActiveWindow"), argumentList); + } + + inline void BeginToMoveActiveWindowQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("BeginToMoveActiveWindow"), argumentList); + } + + + inline QDBusPendingReply<> CancelPreviewWindow() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("CancelPreviewWindow"), argumentList); + } + + inline void CancelPreviewWindowQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("CancelPreviewWindow"), argumentList); + } + + + inline QDBusPendingReply<> ChangeCurrentWorkspaceBackground(const QString &uri) + { + QList argumentList; + argumentList << QVariant::fromValue(uri); + return asyncCallWithArgumentList(QStringLiteral("ChangeCurrentWorkspaceBackground"), argumentList); + } + + inline void ChangeCurrentWorkspaceBackgroundQueued(const QString &uri) + { + QList argumentList; + argumentList << QVariant::fromValue(uri); + + CallQueued(QStringLiteral("ChangeCurrentWorkspaceBackground"), argumentList); + } + + + inline QDBusPendingReply<> ClearMoveStatus() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ClearMoveStatus"), argumentList); + } + + inline void ClearMoveStatusQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("ClearMoveStatus"), argumentList); + } + + + inline QDBusPendingReply<> EnableZoneDetected(bool enabled) + { + QList argumentList; + argumentList << QVariant::fromValue(enabled); + return asyncCallWithArgumentList(QStringLiteral("EnableZoneDetected"), argumentList); + } + + inline void EnableZoneDetectedQueued(bool enabled) + { + QList argumentList; + argumentList << QVariant::fromValue(enabled); + + CallQueued(QStringLiteral("EnableZoneDetected"), argumentList); + } + + + inline QDBusPendingReply GetAccel(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + return asyncCallWithArgumentList(QStringLiteral("GetAccel"), argumentList); + } + + + + inline QDBusPendingReply GetAllAccels() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("GetAllAccels"), argumentList); + } + + + + inline QDBusPendingReply GetCurrentDesktopStatus() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("GetCurrentDesktopStatus"), argumentList); + } + + + + inline QDBusPendingReply GetCurrentWorkspace() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("GetCurrentWorkspace"), argumentList); + } + + + + inline QDBusPendingReply GetCurrentWorkspaceBackground() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("GetCurrentWorkspaceBackground"), argumentList); + } + + + + inline QDBusPendingReply GetCurrentWorkspaceBackgroundForMonitor(const QString &strMonitorName) + { + QList argumentList; + argumentList << QVariant::fromValue(strMonitorName); + return asyncCallWithArgumentList(QStringLiteral("GetCurrentWorkspaceBackgroundForMonitor"), argumentList); + } + + + + inline QDBusPendingReply GetDefaultAccel(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + return asyncCallWithArgumentList(QStringLiteral("GetDefaultAccel"), argumentList); + } + + + + inline QDBusPendingReply GetIsShowDesktop() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("GetIsShowDesktop"), argumentList); + } + + + + inline QDBusPendingReply GetMultiTaskingStatus() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("GetMultiTaskingStatus"), argumentList); + } + + + + inline QDBusPendingReply GetTouchBorderInterval() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("GetTouchBorderInterval"), argumentList); + } + + + + inline QDBusPendingReply GetWorkspaceBackground(int index) + { + QList argumentList; + argumentList << QVariant::fromValue(index); + return asyncCallWithArgumentList(QStringLiteral("GetWorkspaceBackground"), argumentList); + } + + + + inline QDBusPendingReply GetWorkspaceBackgroundForMonitor(int index, const QString &strMonitorName) + { + QList argumentList; + argumentList << QVariant::fromValue(index) << QVariant::fromValue(strMonitorName); + return asyncCallWithArgumentList(QStringLiteral("GetWorkspaceBackgroundForMonitor"), argumentList); + } + + + + inline QDBusPendingReply<> MinimizeActiveWindow() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("MinimizeActiveWindow"), argumentList); + } + + inline void MinimizeActiveWindowQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("MinimizeActiveWindow"), argumentList); + } + + + inline QDBusPendingReply<> NextWorkspace() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("NextWorkspace"), argumentList); + } + + inline void NextWorkspaceQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("NextWorkspace"), argumentList); + } + + + inline QDBusPendingReply<> PerformAction(int type) + { + QList argumentList; + argumentList << QVariant::fromValue(type); + return asyncCallWithArgumentList(QStringLiteral("PerformAction"), argumentList); + } + + inline void PerformActionQueued(int type) + { + QList argumentList; + argumentList << QVariant::fromValue(type); + + CallQueued(QStringLiteral("PerformAction"), argumentList); + } + + + inline QDBusPendingReply<> PresentWindows(const QList &xids) + { + QList argumentList; + argumentList << QVariant::fromValue(xids); + return asyncCallWithArgumentList(QStringLiteral("PresentWindows"), argumentList); + } + + inline void PresentWindowsQueued(const QList &xids) + { + QList argumentList; + argumentList << QVariant::fromValue(xids); + + CallQueued(QStringLiteral("PresentWindows"), argumentList); + } + + + inline QDBusPendingReply<> PreviewWindow(uint xid) + { + QList argumentList; + argumentList << QVariant::fromValue(xid); + return asyncCallWithArgumentList(QStringLiteral("PreviewWindow"), argumentList); + } + + inline void PreviewWindowQueued(uint xid) + { + QList argumentList; + argumentList << QVariant::fromValue(xid); + + CallQueued(QStringLiteral("PreviewWindow"), argumentList); + } + + + inline QDBusPendingReply<> PreviousWorkspace() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("PreviousWorkspace"), argumentList); + } + + inline void PreviousWorkspaceQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("PreviousWorkspace"), argumentList); + } + + + inline QDBusPendingReply<> RemoveAccel(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + return asyncCallWithArgumentList(QStringLiteral("RemoveAccel"), argumentList); + } + + inline void RemoveAccelQueued(const QString &id) + { + QList argumentList; + argumentList << QVariant::fromValue(id); + + CallQueued(QStringLiteral("RemoveAccel"), argumentList); + } + + + inline QDBusPendingReply SetAccel(const QString &data) + { + QList argumentList; + argumentList << QVariant::fromValue(data); + return asyncCallWithArgumentList(QStringLiteral("SetAccel"), argumentList); + } + + + + inline QDBusPendingReply<> SetCurrentWorkspace(int index) + { + QList argumentList; + argumentList << QVariant::fromValue(index); + return asyncCallWithArgumentList(QStringLiteral("SetCurrentWorkspace"), argumentList); + } + + inline void SetCurrentWorkspaceQueued(int index) + { + QList argumentList; + argumentList << QVariant::fromValue(index); + + CallQueued(QStringLiteral("SetCurrentWorkspace"), argumentList); + } + + + inline QDBusPendingReply<> SetCurrentWorkspaceBackground(const QString &uri) + { + QList argumentList; + argumentList << QVariant::fromValue(uri); + return asyncCallWithArgumentList(QStringLiteral("SetCurrentWorkspaceBackground"), argumentList); + } + + inline void SetCurrentWorkspaceBackgroundQueued(const QString &uri) + { + QList argumentList; + argumentList << QVariant::fromValue(uri); + + CallQueued(QStringLiteral("SetCurrentWorkspaceBackground"), argumentList); + } + + + inline QDBusPendingReply<> SetCurrentWorkspaceBackgroundForMonitor(const QString &uri, const QString &strMonitorName) + { + QList argumentList; + argumentList << QVariant::fromValue(uri) << QVariant::fromValue(strMonitorName); + return asyncCallWithArgumentList(QStringLiteral("SetCurrentWorkspaceBackgroundForMonitor"), argumentList); + } + + inline void SetCurrentWorkspaceBackgroundForMonitorQueued(const QString &uri, const QString &strMonitorName) + { + QList argumentList; + argumentList << QVariant::fromValue(uri) << QVariant::fromValue(strMonitorName); + + CallQueued(QStringLiteral("SetCurrentWorkspaceBackgroundForMonitor"), argumentList); + } + + + inline QDBusPendingReply<> SetDecorationDeepinTheme(const QString &deepinThemeName) + { + QList argumentList; + argumentList << QVariant::fromValue(deepinThemeName); + return asyncCallWithArgumentList(QStringLiteral("SetDecorationDeepinTheme"), argumentList); + } + + inline void SetDecorationDeepinThemeQueued(const QString &deepinThemeName) + { + QList argumentList; + argumentList << QVariant::fromValue(deepinThemeName); + + CallQueued(QStringLiteral("SetDecorationDeepinTheme"), argumentList); + } + + + inline QDBusPendingReply<> SetDecorationTheme(const QString &themeType, const QString &themeName) + { + QList argumentList; + argumentList << QVariant::fromValue(themeType) << QVariant::fromValue(themeName); + return asyncCallWithArgumentList(QStringLiteral("SetDecorationTheme"), argumentList); + } + + inline void SetDecorationThemeQueued(const QString &themeType, const QString &themeName) + { + QList argumentList; + argumentList << QVariant::fromValue(themeType) << QVariant::fromValue(themeName); + + CallQueued(QStringLiteral("SetDecorationTheme"), argumentList); + } + + + inline QDBusPendingReply<> SetMultiTaskingStatus(bool isActive) + { + QList argumentList; + argumentList << QVariant::fromValue(isActive); + return asyncCallWithArgumentList(QStringLiteral("SetMultiTaskingStatus"), argumentList); + } + + inline void SetMultiTaskingStatusQueued(bool isActive) + { + QList argumentList; + argumentList << QVariant::fromValue(isActive); + + CallQueued(QStringLiteral("SetMultiTaskingStatus"), argumentList); + } + + + inline QDBusPendingReply<> SetShowDesktop(bool isShowDesktop) + { + QList argumentList; + argumentList << QVariant::fromValue(isShowDesktop); + return asyncCallWithArgumentList(QStringLiteral("SetShowDesktop"), argumentList); + } + + inline void SetShowDesktopQueued(bool isShowDesktop) + { + QList argumentList; + argumentList << QVariant::fromValue(isShowDesktop); + + CallQueued(QStringLiteral("SetShowDesktop"), argumentList); + } + + + inline QDBusPendingReply<> SetTouchBorderInterval(double interval) + { + QList argumentList; + argumentList << QVariant::fromValue(interval); + return asyncCallWithArgumentList(QStringLiteral("SetTouchBorderInterval"), argumentList); + } + + inline void SetTouchBorderIntervalQueued(double interval) + { + QList argumentList; + argumentList << QVariant::fromValue(interval); + + CallQueued(QStringLiteral("SetTouchBorderInterval"), argumentList); + } + + + inline QDBusPendingReply<> SetTransientBackground(const QString &in0) + { + QList argumentList; + argumentList << QVariant::fromValue(in0); + return asyncCallWithArgumentList(QStringLiteral("SetTransientBackground"), argumentList); + } + + inline void SetTransientBackgroundQueued(const QString &in0) + { + QList argumentList; + argumentList << QVariant::fromValue(in0); + + CallQueued(QStringLiteral("SetTransientBackground"), argumentList); + } + + + inline QDBusPendingReply<> SetTransientBackgroundForMonitor(const QString &uri, const QString &strMonitorName) + { + QList argumentList; + argumentList << QVariant::fromValue(uri) << QVariant::fromValue(strMonitorName); + return asyncCallWithArgumentList(QStringLiteral("SetTransientBackgroundForMonitor"), argumentList); + } + + inline void SetTransientBackgroundForMonitorQueued(const QString &uri, const QString &strMonitorName) + { + QList argumentList; + argumentList << QVariant::fromValue(uri) << QVariant::fromValue(strMonitorName); + + CallQueued(QStringLiteral("SetTransientBackgroundForMonitor"), argumentList); + } + + + inline QDBusPendingReply<> SetWorkspaceBackground(int index, const QString &uri) + { + QList argumentList; + argumentList << QVariant::fromValue(index) << QVariant::fromValue(uri); + return asyncCallWithArgumentList(QStringLiteral("SetWorkspaceBackground"), argumentList); + } + + inline void SetWorkspaceBackgroundQueued(int index, const QString &uri) + { + QList argumentList; + argumentList << QVariant::fromValue(index) << QVariant::fromValue(uri); + + CallQueued(QStringLiteral("SetWorkspaceBackground"), argumentList); + } + + + inline QDBusPendingReply<> SetWorkspaceBackgroundForMonitor(int index, const QString &strMonitorName, const QString &uri) + { + QList argumentList; + argumentList << QVariant::fromValue(index) << QVariant::fromValue(strMonitorName) << QVariant::fromValue(uri); + return asyncCallWithArgumentList(QStringLiteral("SetWorkspaceBackgroundForMonitor"), argumentList); + } + + inline void SetWorkspaceBackgroundForMonitorQueued(int index, const QString &strMonitorName, const QString &uri) + { + QList argumentList; + argumentList << QVariant::fromValue(index) << QVariant::fromValue(strMonitorName) << QVariant::fromValue(uri); + + CallQueued(QStringLiteral("SetWorkspaceBackgroundForMonitor"), argumentList); + } + + + inline QDBusPendingReply<> ShowAllWindow() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ShowAllWindow"), argumentList); + } + + inline void ShowAllWindowQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("ShowAllWindow"), argumentList); + } + + + inline QDBusPendingReply<> ShowWindow() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ShowWindow"), argumentList); + } + + inline void ShowWindowQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("ShowWindow"), argumentList); + } + + + inline QDBusPendingReply<> ShowWorkspace() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ShowWorkspace"), argumentList); + } + + inline void ShowWorkspaceQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("ShowWorkspace"), argumentList); + } + + + inline QDBusPendingReply<> SwitchApplication(bool backward) + { + QList argumentList; + argumentList << QVariant::fromValue(backward); + return asyncCallWithArgumentList(QStringLiteral("SwitchApplication"), argumentList); + } + + inline void SwitchApplicationQueued(bool backward) + { + QList argumentList; + argumentList << QVariant::fromValue(backward); + + CallQueued(QStringLiteral("SwitchApplication"), argumentList); + } + + + inline QDBusPendingReply<> SwitchToWorkspace(bool backward) + { + QList argumentList; + argumentList << QVariant::fromValue(backward); + return asyncCallWithArgumentList(QStringLiteral("SwitchToWorkspace"), argumentList); + } + + inline void SwitchToWorkspaceQueued(bool backward) + { + QList argumentList; + argumentList << QVariant::fromValue(backward); + + CallQueued(QStringLiteral("SwitchToWorkspace"), argumentList); + } + + + inline QDBusPendingReply<> TileActiveWindow(uint side) + { + QList argumentList; + argumentList << QVariant::fromValue(side); + return asyncCallWithArgumentList(QStringLiteral("TileActiveWindow"), argumentList); + } + + inline void TileActiveWindowQueued(uint side) + { + QList argumentList; + argumentList << QVariant::fromValue(side); + + CallQueued(QStringLiteral("TileActiveWindow"), argumentList); + } + + + inline QDBusPendingReply<> ToggleActiveWindowMaximize() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("ToggleActiveWindowMaximize"), argumentList); + } + + inline void ToggleActiveWindowMaximizeQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("ToggleActiveWindowMaximize"), argumentList); + } + + + inline QDBusPendingReply<> TouchToMove(int x, int y) + { + QList argumentList; + argumentList << QVariant::fromValue(x) << QVariant::fromValue(y); + return asyncCallWithArgumentList(QStringLiteral("TouchToMove"), argumentList); + } + + inline void TouchToMoveQueued(int x, int y) + { + QList argumentList; + argumentList << QVariant::fromValue(x) << QVariant::fromValue(y); + + CallQueued(QStringLiteral("TouchToMove"), argumentList); + } + + + inline QDBusPendingReply WorkspaceCount() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("WorkspaceCount"), argumentList); + } + + + + +Q_SIGNALS: // SIGNALS + void WorkspaceBackgroundChanged(int index, const QString &newUri); + void WorkspaceBackgroundChangedForMonitor(int index, const QString &strMonitorName, const QString &uri); + void WorkspaceSwitched(int from, int to); + void compositingEnabledChanged(bool enabled); + void wmCompositingEnabledChanged(bool enabled); + void workspaceCountChanged(int count); + // begin property changed signals + void CompositingAllowSwitchChanged(bool value) const; + void CompositingEnabledChanged(bool value) const; + void CompositingPossibleChanged(bool value) const; + void CursorSizeChanged(int value) const; + void CursorThemeChanged(const QString & value) const; + void ZoneEnabledChanged(bool value) const; + +public Q_SLOTS: + void CallQueued(const QString &callName, const QList &args); + +private Q_SLOTS: + void onPendingCallFinished(QDBusPendingCallWatcher *w); + void onPropertyChanged(const QString &propName, const QVariant &value); + +private: + __wmPrivate *d_ptr; +}; + +namespace com { + namespace deepin { + typedef ::__wm WM; + } +} +#endif diff --git a/src/frameworkdbus/dbuswmswitcher.cpp b/src/frameworkdbus/dbuswmswitcher.cpp new file mode 100644 index 0000000..4216bc5 --- /dev/null +++ b/src/frameworkdbus/dbuswmswitcher.cpp @@ -0,0 +1,71 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c WMSwitcher -p generated/com_deepin_wmswitcher ../xml/com.deepin.WMSwitcher.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "dbuswmswitcher.h" + +/* + * Implementation of interface class __WMSwitcher + */ + +class __WMSwitcherPrivate +{ +public: + __WMSwitcherPrivate() = default; + + // begin member variables + +public: + QMap m_processingCalls; + QMap> m_waittingCalls; +}; + +__WMSwitcher::__WMSwitcher(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : DBusExtendedAbstractInterface(service, path, staticInterfaceName(), connection, parent) + , d_ptr(new __WMSwitcherPrivate) +{ +} + +__WMSwitcher::~__WMSwitcher() +{ + qDeleteAll(d_ptr->m_processingCalls.values()); + delete d_ptr; +} + +void __WMSwitcher::CallQueued(const QString &callName, const QList &args) +{ + if (d_ptr->m_waittingCalls.contains(callName)) + { + d_ptr->m_waittingCalls[callName] = args; + return; + } + if (d_ptr->m_processingCalls.contains(callName)) + { + d_ptr->m_waittingCalls.insert(callName, args); + } else { + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncCallWithArgumentList(callName, args)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &__WMSwitcher::onPendingCallFinished); + d_ptr->m_processingCalls.insert(callName, watcher); + } +} + +void __WMSwitcher::onPendingCallFinished(QDBusPendingCallWatcher *w) +{ + w->deleteLater(); + const auto callName = d_ptr->m_processingCalls.key(w); + Q_ASSERT(!callName.isEmpty()); + if (callName.isEmpty()) + return; + d_ptr->m_processingCalls.remove(callName); + if (!d_ptr->m_waittingCalls.contains(callName)) + return; + const auto args = d_ptr->m_waittingCalls.take(callName); + CallQueued(callName, args); +} diff --git a/src/frameworkdbus/dbuswmswitcher.h b/src/frameworkdbus/dbuswmswitcher.h new file mode 100644 index 0000000..7ac3b24 --- /dev/null +++ b/src/frameworkdbus/dbuswmswitcher.h @@ -0,0 +1,122 @@ +/* + * This file was generated by qdbusxml2cpp-fix version 0.8 + * Command line was: qdbusxml2cpp-fix -c WMSwitcher -p generated/com_deepin_wmswitcher ../xml/com.deepin.WMSwitcher.xml + * + * qdbusxml2cpp-fix is Copyright (C) 2016 Deepin Technology Co., Ltd. + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef COM_DEEPIN_WMSWITCHER_H +#define COM_DEEPIN_WMSWITCHER_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * Proxy class for interface com.deepin.WMSwitcher + */ +class __WMSwitcherPrivate; +class __WMSwitcher : public DBusExtendedAbstractInterface +{ + Q_OBJECT + +public: + static inline const char *staticInterfaceName() + { return "com.deepin.WMSwitcher"; } + +public: + explicit __WMSwitcher(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~__WMSwitcher(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply AllowSwitch() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("AllowSwitch"), argumentList); + } + + + + inline QDBusPendingReply CurrentWM() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("CurrentWM"), argumentList); + } + + + + inline QDBusPendingReply<> RequestSwitchWM() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RequestSwitchWM"), argumentList); + } + + inline void RequestSwitchWMQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RequestSwitchWM"), argumentList); + } + + + inline QDBusPendingReply<> RestartWM() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("RestartWM"), argumentList); + } + + inline void RestartWMQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("RestartWM"), argumentList); + } + + + inline QDBusPendingReply<> Start2DWM() + { + QList argumentList; + return asyncCallWithArgumentList(QStringLiteral("Start2DWM"), argumentList); + } + + inline void Start2DWMQueued() + { + QList argumentList; + + CallQueued(QStringLiteral("Start2DWM"), argumentList); + } + + + +Q_SIGNALS: // SIGNALS + void WMChanged(const QString &in0); + // begin property changed signals + +public Q_SLOTS: + void CallQueued(const QString &callName, const QList &args); + +private Q_SLOTS: + void onPendingCallFinished(QDBusPendingCallWatcher *w); + +private: + __WMSwitcherPrivate *d_ptr; +}; + +namespace com { + namespace deepin { + typedef ::__WMSwitcher WMSwitcher; + } +} +#endif diff --git a/src/frameworkdbus/qtdbusextended/DBusExtended b/src/frameworkdbus/qtdbusextended/DBusExtended new file mode 100644 index 0000000..719c49b --- /dev/null +++ b/src/frameworkdbus/qtdbusextended/DBusExtended @@ -0,0 +1 @@ +#include "dbusextended.h" diff --git a/src/frameworkdbus/qtdbusextended/DBusExtendedAbstractInterface b/src/frameworkdbus/qtdbusextended/DBusExtendedAbstractInterface new file mode 100644 index 0000000..246af8a --- /dev/null +++ b/src/frameworkdbus/qtdbusextended/DBusExtendedAbstractInterface @@ -0,0 +1 @@ +#include "dbusextendedabstractinterface.h" diff --git a/src/frameworkdbus/qtdbusextended/dbusextended.h b/src/frameworkdbus/qtdbusextended/dbusextended.h new file mode 100644 index 0000000..6b27aa2 --- /dev/null +++ b/src/frameworkdbus/qtdbusextended/dbusextended.h @@ -0,0 +1,35 @@ +// -*- c++ -*- + +/*! + * + * Copyright (C) 2015 Jolla Ltd. + * + * Contact: Valerio Valerio + * Author: Andres Gomez + * + * This 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 + */ + + +#ifndef QT_DBUS_EXTENDED_H +#define QT_DBUS_EXTENDED_H + +#if defined(QT_DBUS_EXTENDED_LIBRARY) +# define QT_DBUS_EXTENDED_EXPORT Q_DECL_EXPORT +#else +# define QT_DBUS_EXTENDED_EXPORT Q_DECL_IMPORT +#endif + +#endif /* QT_DBUS_EXTENDED_H */ diff --git a/src/frameworkdbus/qtdbusextended/dbusextendedabstractinterface.cpp b/src/frameworkdbus/qtdbusextended/dbusextendedabstractinterface.cpp new file mode 100644 index 0000000..54d46f3 --- /dev/null +++ b/src/frameworkdbus/qtdbusextended/dbusextendedabstractinterface.cpp @@ -0,0 +1,525 @@ +// -*- c++ -*- + +/*! + * + * Copyright (C) 2015 Jolla Ltd. + * + * Contact: Valerio Valerio + * Author: Andres Gomez + * + * This 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 + */ + + +#include "dbusextendedpendingcallwatcher_p.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include + + +Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, dBusInterface, ("org.freedesktop.DBus")) +Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, dBusPropertiesInterface, ("org.freedesktop.DBus.Properties")) +Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, dBusPropertiesChangedSignal, ("PropertiesChanged")) +Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, propertyChangedSignature, ("propertyChanged(QString,QVariant)")) +Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, propertyInvalidatedSignature, ("propertyInvalidated(QString)")) + + +DBusExtendedAbstractInterface::DBusExtendedAbstractInterface(const QString &service, const QString &path, const char *interface, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, interface, connection, parent) + , m_sync(true) + , m_useCache(false) + , m_getAllPendingCallWatcher(0) + , m_propertiesChangedConnected(false) +{ + const_cast(connection).connect(QString("org.freedesktop.DBus"), QString("/org/freedesktop/DBus"), QString("org.freedesktop.DBus"), QString("NameOwnerChanged"), this, SLOT(onDBusNameOwnerChanged(QString,QString,QString))); +} + +DBusExtendedAbstractInterface::~DBusExtendedAbstractInterface() +{ +} + +void DBusExtendedAbstractInterface::setSync(bool sync) { setSync(sync, true); } + +/* + * Note: After sync is set to false, it will always return a empty value + * if you call the property's get function directly. So you can only get it + * through the changed signal when you get an property, and it's also a good idea + * to save a cache yourself. + */ + +/* + * 注意: 如果设置 sync 为 false 那么在调用属性的 get 函数获取一个属性时会一直返回空值, + * 解决方法是监听属性的 changed 信号并自行保存一份缓存, 让 changed 信号修改这个缓存 + */ +void DBusExtendedAbstractInterface::setSync(bool sync, bool autoStart) +{ + m_sync = sync; + + // init all properties + if (autoStart && !m_sync && !isValid()) + startServiceProcess(); +} + +void DBusExtendedAbstractInterface::getAllProperties() +{ + m_lastExtendedError = QDBusError(); + + if (!isValid()) { + QString errorMessage = QStringLiteral("This Extended DBus interface is not valid yet."); + m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); + qDebug() << Q_FUNC_INFO << errorMessage; + return; + } + + if (!m_sync && m_getAllPendingCallWatcher) { + // Call already in place, not repeating ... + return; + } + + QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), *dBusPropertiesInterface(), QStringLiteral("GetAll")); + msg << interface(); + + if (m_sync) { + QDBusMessage reply = connection().call(msg); + + if (reply.type() != QDBusMessage::ReplyMessage) { + m_lastExtendedError = QDBusError(reply); + qWarning() << Q_FUNC_INFO << m_lastExtendedError.message(); + return; + } + + if (reply.signature() != QLatin1String("a{sv}")) { + QString errorMessage = QStringLiteral("Invalid signature \"%1\" in return from call to %2") + .arg(reply.signature(), + QString(*dBusPropertiesInterface())); + qWarning() << Q_FUNC_INFO << errorMessage; + m_lastExtendedError = QDBusError(QDBusError::InvalidSignature, errorMessage); + return; + } + + QVariantMap value = reply.arguments().at(0).toMap(); + onPropertiesChanged(interface(), value, QStringList()); + } else { + QDBusPendingReply async = connection().asyncCall(msg); + m_getAllPendingCallWatcher = new QDBusPendingCallWatcher(async, this); + + connect(m_getAllPendingCallWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onAsyncGetAllPropertiesFinished(QDBusPendingCallWatcher*))); + return; + } +} + +void DBusExtendedAbstractInterface::connectNotify(const QMetaMethod &signal) +{ + if (signal.methodType() == QMetaMethod::Signal + && (signal.methodSignature() == *propertyChangedSignature() + || signal.methodSignature() == *propertyInvalidatedSignature())) { + if (!m_propertiesChangedConnected) { + QStringList argumentMatch; + argumentMatch << interface(); + connection().connect(service(), path(), *dBusPropertiesInterface(), *dBusPropertiesChangedSignal(), + argumentMatch, QString(), + this, SLOT(onPropertiesChanged(QString, QVariantMap, QStringList))); + + m_propertiesChangedConnected = true; + return; + } + } else { + QDBusAbstractInterface::connectNotify(signal); + } +} + +void DBusExtendedAbstractInterface::disconnectNotify(const QMetaMethod &signal) +{ + if (signal.methodType() == QMetaMethod::Signal + && (signal.methodSignature() == *propertyChangedSignature() + || signal.methodSignature() == *propertyInvalidatedSignature())) { + if (m_propertiesChangedConnected + && 0 == receivers(propertyChangedSignature()->constData()) + && 0 == receivers(propertyInvalidatedSignature()->constData())) { + QStringList argumentMatch; + argumentMatch << interface(); + connection().disconnect(service(), path(), *dBusPropertiesInterface(), *dBusPropertiesChangedSignal(), + argumentMatch, QString(), + this, SLOT(onPropertiesChanged(QString, QVariantMap, QStringList))); + + m_propertiesChangedConnected = false; + return; + } + } else { + QDBusAbstractInterface::disconnectNotify(signal); + } +} + +QVariant DBusExtendedAbstractInterface::internalPropGet(const char *propname, void *propertyPtr) +{ + m_lastExtendedError = QDBusError(); + + if (m_useCache) { + int propertyIndex = metaObject()->indexOfProperty(propname); + QMetaProperty metaProperty = metaObject()->property(propertyIndex); + return QVariant(metaProperty.userType(), propertyPtr); + } + + if (m_sync) { + QVariant ret = property(propname); + + QMetaType::construct(ret.userType(), propertyPtr, ret.constData()); + + return ret; + } else { + if (!isValid()) { + QString errorMessage = QStringLiteral("This Extended DBus interface is not valid yet."); + m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); + qDebug() << Q_FUNC_INFO << errorMessage; + return QVariant(); + } + + int propertyIndex = metaObject()->indexOfProperty(propname); + + if (-1 == propertyIndex) { + QString errorMessage = QStringLiteral("Got unknown property \"%1\" to read") + .arg(QString::fromLatin1(propname)); + m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); + qWarning() << Q_FUNC_INFO << errorMessage; + return QVariant(); + } + + QMetaProperty metaProperty = metaObject()->property(propertyIndex); + + if (!metaProperty.isReadable()) { + QString errorMessage = QStringLiteral("Property \"%1\" is NOT readable") + .arg(QString::fromLatin1(propname)); + m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); + qWarning() << Q_FUNC_INFO << errorMessage; + return QVariant(); + } + + // is this metatype registered? + const char *expectedSignature = ""; + if (int(metaProperty.type()) != QMetaType::QVariant) { + expectedSignature = QDBusMetaType::typeToSignature(metaProperty.userType()); + if (0 == expectedSignature) { + QString errorMessage = + QStringLiteral("Type %1 must be registered with Qt D-Bus " + "before it can be used to read property " + "%2.%3") + .arg(metaProperty.typeName(), + interface(), + propname); + m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); + qWarning() << Q_FUNC_INFO << errorMessage; + return QVariant(); + } + } + + asyncProperty(propname); + return QVariant(metaProperty.userType(), propertyPtr); + } +} + +void DBusExtendedAbstractInterface::internalPropSet(const char *propname, const QVariant &value, void *propertyPtr) +{ + m_lastExtendedError = QDBusError(); + + if (m_sync) { + setProperty(propname, value); + } else { + if (!isValid()) { + QString errorMessage = QStringLiteral("This interface is not yet valid"); + m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); + qDebug() << Q_FUNC_INFO << errorMessage; + return; + } + + int propertyIndex = metaObject()->indexOfProperty(propname); + + if (-1 == propertyIndex) { + QString errorMessage = QStringLiteral("Got unknown property \"%1\" to write") + .arg(QString::fromLatin1(propname)); + m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); + qWarning() << Q_FUNC_INFO << errorMessage; + return; + } + + QMetaProperty metaProperty = metaObject()->property(propertyIndex); + + if (!metaProperty.isWritable()) { + QString errorMessage = QStringLiteral("Property \"%1\" is NOT writable") + .arg(QString::fromLatin1(propname)); + m_lastExtendedError = QDBusMessage::createError(QDBusError::Failed, errorMessage); + qWarning() << Q_FUNC_INFO << errorMessage; + return; + } + + QVariant variant = QVariant(metaProperty.type(), propertyPtr); + variant = value; + + asyncSetProperty(propname, variant); + } +} + +QVariant DBusExtendedAbstractInterface::asyncProperty(const QString &propertyName) +{ + QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), *dBusPropertiesInterface(), QStringLiteral("Get")); + msg << interface() << propertyName; + QDBusPendingReply async = connection().asyncCall(msg); + DBusExtendedPendingCallWatcher *watcher = new DBusExtendedPendingCallWatcher(async, propertyName, QVariant(), this); + + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onAsyncPropertyFinished(QDBusPendingCallWatcher*))); + + return QVariant(); +} + +void DBusExtendedAbstractInterface::asyncSetProperty(const QString &propertyName, const QVariant &value) +{ + QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), *dBusPropertiesInterface(), QStringLiteral("Set")); + + msg << interface() << propertyName << QVariant::fromValue(QDBusVariant(value)); + QDBusPendingReply<> async = connection().asyncCall(msg); + DBusExtendedPendingCallWatcher *watcher = new DBusExtendedPendingCallWatcher(async, propertyName, value, this); + + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(onAsyncSetPropertyFinished(QDBusPendingCallWatcher*))); +} + +void DBusExtendedAbstractInterface::startServiceProcess() +{ + const QString &servName = service(); + + if (isValid()) + { + qWarning() << "Service" << servName << "is already started."; + return; + } + + QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus", "/", *dBusInterface(), QStringLiteral("StartServiceByName")); + msg << servName << quint32(0); + QDBusPendingReply async = connection().asyncCall(msg); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this); + + connect(watcher, &QDBusPendingCallWatcher::finished, this, &DBusExtendedAbstractInterface::onStartServiceProcessFinished); +} + +void DBusExtendedAbstractInterface::onStartServiceProcessFinished(QDBusPendingCallWatcher *w) +{ + if (w->isError()) + { + m_lastExtendedError = w->error(); + } else { + m_lastExtendedError = QDBusError(); + } + + QDBusPendingReply reply = *w; + + Q_EMIT serviceStartFinished(reply.value()); + + w->deleteLater(); +} + +void DBusExtendedAbstractInterface::onAsyncPropertyFinished(QDBusPendingCallWatcher *w) +{ + DBusExtendedPendingCallWatcher *watcher = qobject_cast(w); + Q_ASSERT(watcher); + + QDBusPendingReply reply = *watcher; + + if (reply.isError()) { + m_lastExtendedError = reply.error(); + } else { + int propertyIndex = metaObject()->indexOfProperty(watcher->asyncProperty().toLatin1().constData()); + QVariant value = demarshall(interface(), + metaObject()->property(propertyIndex), + reply.value(), + &m_lastExtendedError); + + if (m_lastExtendedError.isValid()) { + Q_EMIT propertyInvalidated(watcher->asyncProperty()); + } else { + Q_EMIT propertyChanged(watcher->asyncProperty(), value); + } + } + + Q_EMIT asyncPropertyFinished(watcher->asyncProperty()); + watcher->deleteLater(); +} + +void DBusExtendedAbstractInterface::onAsyncSetPropertyFinished(QDBusPendingCallWatcher *w) +{ + DBusExtendedPendingCallWatcher *watcher = qobject_cast(w); + Q_ASSERT(watcher); + + QDBusPendingReply<> reply = *watcher; + + if (reply.isError()) { + m_lastExtendedError = reply.error(); + } else { + m_lastExtendedError = QDBusError(); + } + + Q_EMIT asyncSetPropertyFinished(watcher->asyncProperty()); + + // Resetting the property to its previous value after sending the + // finished signal + if (reply.isError()) { + m_lastExtendedError = QDBusError(); + Q_EMIT propertyChanged(watcher->asyncProperty(), watcher->previousValue()); + } + + watcher->deleteLater(); +} + +void DBusExtendedAbstractInterface::onAsyncGetAllPropertiesFinished(QDBusPendingCallWatcher *watcher) +{ + m_getAllPendingCallWatcher = 0; + + QDBusPendingReply reply = *watcher; + + if (reply.isError()) { + m_lastExtendedError = reply.error(); + } else { + m_lastExtendedError = QDBusError(); + } + + Q_EMIT asyncGetAllPropertiesFinished(); + + if (!reply.isError()) { + onPropertiesChanged(interface(), reply.value(), QStringList()); + } + + watcher->deleteLater(); +} + +void DBusExtendedAbstractInterface::onPropertiesChanged(const QString& interfaceName, + const QVariantMap& changedProperties, + const QStringList& invalidatedProperties) +{ + if (interfaceName == interface()) { + QVariantMap::const_iterator i = changedProperties.constBegin(); + while (i != changedProperties.constEnd()) { + int propertyIndex = metaObject()->indexOfProperty(i.key().toLatin1().constData()); + + if (-1 == propertyIndex) { + qDebug() << Q_FUNC_INFO << "Got unknown changed property" << i.key(); + } else { + QVariant value = demarshall(interface(), metaObject()->property(propertyIndex), i.value(), &m_lastExtendedError); + + if (m_lastExtendedError.isValid()) { + Q_EMIT propertyInvalidated(i.key()); + } else { + Q_EMIT propertyChanged(i.key(), value); + } + } + + ++i; + } + + QStringList::const_iterator j = invalidatedProperties.constBegin(); + while (j != invalidatedProperties.constEnd()) { + if (-1 == metaObject()->indexOfProperty(j->toLatin1().constData())) { + qDebug() << Q_FUNC_INFO << "Got unknown invalidated property" << *j; + } else { + m_lastExtendedError = QDBusError(); + Q_EMIT propertyInvalidated(*j); + } + + ++j; + } + } +} + +void DBusExtendedAbstractInterface::onDBusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) +{ + if (name == service() && oldOwner.isEmpty()) + { + m_dbusOwner = newOwner; + Q_EMIT serviceValidChanged(true); + } + else if (name == m_dbusOwner && newOwner.isEmpty()) + { + m_dbusOwner.clear(); + Q_EMIT serviceValidChanged(false); + } +} + +QVariant DBusExtendedAbstractInterface::demarshall(const QString &interface, const QMetaProperty &metaProperty, const QVariant &value, QDBusError *error) +{ + Q_ASSERT(metaProperty.isValid()); + Q_ASSERT(error != 0); + + if (value.userType() == metaProperty.userType()) { + // No need demarshalling. Passing back straight away ... + *error = QDBusError(); + return value; + } + + QVariant result = QVariant(metaProperty.userType(), (void*)0); + QString errorMessage; + const char *expectedSignature = QDBusMetaType::typeToSignature(metaProperty.userType()); + + if (value.userType() == qMetaTypeId()) { + // demarshalling a DBus argument ... + QDBusArgument dbusArg = value.value(); + + if (expectedSignature == dbusArg.currentSignature().toLatin1()) { + QDBusMetaType::demarshall(dbusArg, metaProperty.userType(), result.data()); + if (!result.isValid()) { + errorMessage = QStringLiteral("Unexpected failure demarshalling " + "upon PropertiesChanged signal arrival " + "for property `%3.%4' (expected type `%5' (%6))") + .arg(interface, + QString::fromLatin1(metaProperty.name()), + QString::fromLatin1(metaProperty.typeName()), + expectedSignature); + } + } else { + errorMessage = QStringLiteral("Unexpected `user type' (%2) " + "upon PropertiesChanged signal arrival " + "for property `%3.%4' (expected type `%5' (%6))") + .arg(dbusArg.currentSignature(), + interface, + QString::fromLatin1(metaProperty.name()), + QString::fromLatin1(metaProperty.typeName()), + QString::fromLatin1(expectedSignature)); + } + } else { + const char *actualSignature = QDBusMetaType::typeToSignature(value.userType()); + + errorMessage = QStringLiteral("Unexpected `%1' (%2) " + "upon PropertiesChanged signal arrival " + "for property `%3.%4' (expected type `%5' (%6))") + .arg(QString::fromLatin1(value.typeName()), + QString::fromLatin1(actualSignature), + interface, + QString::fromLatin1(metaProperty.name()), + QString::fromLatin1(metaProperty.typeName()), + QString::fromLatin1(expectedSignature)); + } + + if (errorMessage.isEmpty()) { + *error = QDBusError(); + } else { + *error = QDBusMessage::createError(QDBusError::InvalidSignature, errorMessage); + qDebug() << Q_FUNC_INFO << errorMessage; + } + + return result; +} diff --git a/src/frameworkdbus/qtdbusextended/dbusextendedabstractinterface.h b/src/frameworkdbus/qtdbusextended/dbusextendedabstractinterface.h new file mode 100644 index 0000000..812d0ae --- /dev/null +++ b/src/frameworkdbus/qtdbusextended/dbusextendedabstractinterface.h @@ -0,0 +1,103 @@ +// -*- c++ -*- + +/*! + * + * Copyright (C) 2015 Jolla Ltd. + * + * Contact: Valerio Valerio + * Author: Andres Gomez + * + * This 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 + */ + + +#ifndef DBUSEXTENDEDABSTRACTINTERFACE_H +#define DBUSEXTENDEDABSTRACTINTERFACE_H + +#include + +#include +#include + +class QDBusPendingCallWatcher; +class DBusExtendedPendingCallWatcher; + +class QT_DBUS_EXTENDED_EXPORT DBusExtendedAbstractInterface: public QDBusAbstractInterface +{ + Q_OBJECT + +public: + virtual ~DBusExtendedAbstractInterface(); + + Q_PROPERTY(bool sync READ sync WRITE setSync) + inline bool sync() const { return m_sync; } + void setSync(bool sync); + void setSync(bool sync, bool autoStart); + + Q_PROPERTY(bool useCache READ useCache WRITE setUseCache) + inline bool useCache() const { return m_useCache; } + inline void setUseCache(bool useCache) { m_useCache = useCache; } + + void getAllProperties(); + inline QDBusError lastExtendedError() const { return m_lastExtendedError; } + +public Q_SLOTS: + void startServiceProcess(); + +protected: + DBusExtendedAbstractInterface(const QString &service, + const QString &path, + const char *interface, + const QDBusConnection &connection, + QObject *parent); + + void connectNotify(const QMetaMethod &signal); + void disconnectNotify(const QMetaMethod &signal); + QVariant internalPropGet(const char *propname, void *propertyPtr); + void internalPropSet(const char *propname, const QVariant &value, void *propertyPtr); + +Q_SIGNALS: + void serviceValidChanged(const bool valid) const; + void serviceStartFinished(const quint32 ret) const; + void propertyChanged(const QString &propertyName, const QVariant &value); + void propertyInvalidated(const QString &propertyName); + void asyncPropertyFinished(const QString &propertyName); + void asyncSetPropertyFinished(const QString &propertyName); + void asyncGetAllPropertiesFinished(); + +private Q_SLOTS: + void onPropertiesChanged(const QString& interfaceName, + const QVariantMap& changedProperties, + const QStringList& invalidatedProperties); + void onDBusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); + void onAsyncPropertyFinished(QDBusPendingCallWatcher *w); + void onAsyncSetPropertyFinished(QDBusPendingCallWatcher *w); + void onAsyncGetAllPropertiesFinished(QDBusPendingCallWatcher *watcher); + void onStartServiceProcessFinished(QDBusPendingCallWatcher *w); + +private: + QVariant asyncProperty(const QString &propertyName); + void asyncSetProperty(const QString &propertyName, const QVariant &value); + static QVariant demarshall(const QString &interface, const QMetaProperty &metaProperty, const QVariant &value, QDBusError *error); + + bool m_sync; + bool m_useCache; + QDBusPendingCallWatcher *m_getAllPendingCallWatcher; + QDBusError m_lastExtendedError; + QString m_dbusOwner; + bool m_propertiesChangedConnected; +}; + +#endif /* DBUSEXTENDEDABSTRACTINTERFACE_H */ diff --git a/src/frameworkdbus/qtdbusextended/dbusextendedpendingcallwatcher.cpp b/src/frameworkdbus/qtdbusextended/dbusextendedpendingcallwatcher.cpp new file mode 100644 index 0000000..a8404d9 --- /dev/null +++ b/src/frameworkdbus/qtdbusextended/dbusextendedpendingcallwatcher.cpp @@ -0,0 +1,38 @@ +// -*- c++ -*- + +/*! + * + * Copyright (C) 2015 Jolla Ltd. + * + * Contact: Valerio Valerio + * Author: Andres Gomez + * + * This 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 + */ + + +#include "dbusextendedpendingcallwatcher_p.h" + + +DBusExtendedPendingCallWatcher::DBusExtendedPendingCallWatcher(const QDBusPendingCall &call, const QString &asyncProperty, const QVariant &previousValue, QObject *parent) + : QDBusPendingCallWatcher(call, parent) + , m_asyncProperty(asyncProperty) + , m_previousValue(previousValue) +{ +} + +DBusExtendedPendingCallWatcher::~DBusExtendedPendingCallWatcher() +{ +} diff --git a/src/frameworkdbus/qtdbusextended/dbusextendedpendingcallwatcher_p.h b/src/frameworkdbus/qtdbusextended/dbusextendedpendingcallwatcher_p.h new file mode 100644 index 0000000..ff7a85d --- /dev/null +++ b/src/frameworkdbus/qtdbusextended/dbusextendedpendingcallwatcher_p.h @@ -0,0 +1,67 @@ +// -*- c++ -*- + +/*! + * + * Copyright (C) 2015 Jolla Ltd. + * + * Contact: Valerio Valerio + * Author: Andres Gomez + * + * This 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 + */ + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the public API. This header file may +// change from version to version without notice, or even be +// removed. +// +// We mean it. +// +// + + +#ifndef DBUSEXTENDEDPENDINGCALLWATCHER_P_H +#define DBUSEXTENDEDPENDINGCALLWATCHER_P_H + +#include +#include + +class DBusExtendedPendingCallWatcher: public QDBusPendingCallWatcher +{ + Q_OBJECT + +public: + explicit DBusExtendedPendingCallWatcher(const QDBusPendingCall &call, + const QString &asyncProperty, + const QVariant &previousValue, + QObject *parent = 0); + ~DBusExtendedPendingCallWatcher(); + + Q_PROPERTY(QString AsyncProperty READ asyncProperty) + inline QString asyncProperty() const { return m_asyncProperty; } + + Q_PROPERTY(QVariant PreviousValue READ previousValue) + inline QVariant previousValue() const { return m_previousValue; } + +private: + QString m_asyncProperty; + QVariant m_previousValue; +}; + +#endif /* DBUSEXTENDEDPENDINGCALLWATCHER_P_H */ diff --git a/src/frameworkdbus/types/launcheriteminfo.cpp b/src/frameworkdbus/types/launcheriteminfo.cpp new file mode 100644 index 0000000..44b449b --- /dev/null +++ b/src/frameworkdbus/types/launcheriteminfo.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2017 ~ 2019 Deepin Technology Co., Ltd. + * + * Author: LiLinling + * + * Maintainer: LiLinling + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "launcheriteminfo.h" + +bool LauncherItemInfo::operator!=(const LauncherItemInfo &itemInfo) +{ + return itemInfo.ID != ID; +} + +QDBusArgument &operator<<(QDBusArgument &argument, const LauncherItemInfo &itemInfo) +{ + argument.beginStructure(); + argument << itemInfo.Path << itemInfo.Name << itemInfo.ID << itemInfo.Icon << itemInfo.CategoryID << itemInfo.TimeInstalled; + argument.endStructure(); + return argument; +} + +const QDBusArgument &operator>>(const QDBusArgument &argument, LauncherItemInfo &itemInfo) +{ + argument.beginStructure(); + argument >> itemInfo.Path >> itemInfo.Name >> itemInfo.ID >> itemInfo.Icon >> itemInfo.CategoryID >> itemInfo.TimeInstalled; + argument.endStructure(); + return argument; +} + +void registerLauncherItemInfoMetaType() +{ + qRegisterMetaType("ItemInfo"); + qDBusRegisterMetaType(); +} diff --git a/src/frameworkdbus/types/launcheriteminfo.h b/src/frameworkdbus/types/launcheriteminfo.h new file mode 100644 index 0000000..9d5b7df --- /dev/null +++ b/src/frameworkdbus/types/launcheriteminfo.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2017 ~ 2019 Deepin Technology Co., Ltd. + * + * Author: LiLinling + * + * Maintainer: LiLinling + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include +#include +#include + +struct LauncherItemInfo { + QString Path; + QString Name; + QString ID; + QString Icon; + qint64 CategoryID; + qint64 TimeInstalled; + bool operator!=(const LauncherItemInfo &versionInfo); +}; + +Q_DECLARE_METATYPE(LauncherItemInfo) + +QDBusArgument &operator<<(QDBusArgument &argument, const LauncherItemInfo &versionInfo); +const QDBusArgument &operator>>(const QDBusArgument &argument, LauncherItemInfo &versionInfo); +void registerLauncherItemInfoMetaType(); diff --git a/src/frameworkdbus/types/launcheriteminfolist.cpp b/src/frameworkdbus/types/launcheriteminfolist.cpp new file mode 100644 index 0000000..939c226 --- /dev/null +++ b/src/frameworkdbus/types/launcheriteminfolist.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 ~ 2019 Deepin Technology Co., Ltd. + * + * Author: LiLinling + * + * Maintainer: LiLinling + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "launcheriteminfolist.h" + +void registerLauncherItemInfoListMetaType() +{ + qRegisterMetaType("ItemInfoList"); + qDBusRegisterMetaType(); +} diff --git a/src/frameworkdbus/types/launcheriteminfolist.h b/src/frameworkdbus/types/launcheriteminfolist.h new file mode 100644 index 0000000..daed7f4 --- /dev/null +++ b/src/frameworkdbus/types/launcheriteminfolist.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2017 ~ 2019 Deepin Technology Co., Ltd. + * + * Author: LiLinling + * + * Maintainer: LiLinling + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "launcheriteminfo.h" + +#include +#include + +typedef QList LauncherItemInfoList; + +Q_DECLARE_METATYPE(LauncherItemInfoList) + +void registerLauncherItemInfoListMetaType(); diff --git a/src/frameworkdbus/types/rect.cpp b/src/frameworkdbus/types/rect.cpp new file mode 100644 index 0000000..d0546f2 --- /dev/null +++ b/src/frameworkdbus/types/rect.cpp @@ -0,0 +1,50 @@ +#include "rect.h" +#include + +Rect::Rect() + : X(0) + , Y(0) + , Width(0) + , Height(0) +{ + +} + +QDebug operator<<(QDebug debug, const Rect &rect) +{ + debug << QString("Rect(%1, %2, %3, %4)").arg(rect.X) + .arg(rect.Y) + .arg(rect.Width) + .arg(rect.Height); + + return debug; +} + +Rect::operator QRect() const +{ + return QRect(X, Y, Width, Height); +} + +QDBusArgument &operator<<(QDBusArgument &arg, const Rect &rect) +{ + arg.beginStructure(); + arg << rect.X << rect.Y << rect.Width << rect.Height; + arg.endStructure(); + + return arg; +} + +const QDBusArgument &operator>>(const QDBusArgument &arg, Rect &rect) +{ + arg.beginStructure(); + arg >> rect.X >> rect.Y >> rect.Width >> rect.Height; + arg.endStructure(); + + return arg; +} + +void registerRectMetaType() +{ + qRegisterMetaType("Rect"); + qDBusRegisterMetaType(); +} diff --git a/src/frameworkdbus/types/rect.h b/src/frameworkdbus/types/rect.h new file mode 100644 index 0000000..98d682a --- /dev/null +++ b/src/frameworkdbus/types/rect.h @@ -0,0 +1,25 @@ +#ifndef DOCKRECT_H +#define DOCKRECT_H + +#include +#include + +struct Rect +{ +public: + Rect(); + operator QRect() const; + + friend QDebug operator<<(QDebug debug, const Rect &rect); + friend const QDBusArgument &operator>>(const QDBusArgument &arg, Rect &rect); + friend QDBusArgument &operator<<(QDBusArgument &arg, const Rect &rect); + +private: + qint32 X, Y, Width, Height; +}; + +Q_DECLARE_METATYPE(Rect) + +void registerRectMetaType(); + +#endif // DOCKRECT_H diff --git a/src/lib/basedir.cpp b/src/lib/basedir.cpp new file mode 100644 index 0000000..289f673 --- /dev/null +++ b/src/lib/basedir.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "basedir.h" +#include "dfile.h" +#include "dstring.h" + +#include + +BaseDir::BaseDir() +{ + +} + +std::string BaseDir::homeDir() +{ + char *home = getenv("HOME"); + if (!home) + return ""; + + return std::string(home) + "/"; +} + +std::string BaseDir::uerDataDir() +{ + // default $HOME/.local/share + std::string home = homeDir(); + std::string defaultDir = home.size() > 0 ? home + ".local/share/" : ""; + const char *xdgDataHomePtr = getenv("XDG_DATA_HOME"); + if (!xdgDataHomePtr) + return defaultDir; + + if (!DFile::isAbs(xdgDataHomePtr)) + return defaultDir; + + return std::string(xdgDataHomePtr) + "/"; +} + +std::vector BaseDir::sysDataDirs() +{ + std::vector defaultDirs {"/usr/local/share/", "/usr/share/"}; + const char *xdgDataDirsPtr = getenv("XDG_DATA_DIRS"); + if (!xdgDataDirsPtr) + return defaultDirs; + + std::string xdgDataDirsStr(xdgDataDirsPtr); + std::vector xdgDataDirs = DString::splitStr(xdgDataDirsStr, ':'); + if (xdgDataDirs.size() == 0) + return defaultDirs; + + filterNotAbs(xdgDataDirs); + addSuffixSlash(xdgDataDirs); + return xdgDataDirs; +} + +std::string BaseDir::userConfigDir() +{ + // default $HOME/.config + std::string defaultDir = homeDir() + ".config/"; + const char *xdgConfigHomePtr = getenv("XDG_CONFIG_HOME"); + if (!xdgConfigHomePtr) + return defaultDir; + + std::string xdgConfigHome(xdgConfigHomePtr); + if (!DFile::isAbs(xdgConfigHome)) + return defaultDir; + + return xdgConfigHome + "/"; +} + +std::vector BaseDir::sysConfigDirs() +{ + std::vector defaultDirs {"/etc/xdg/"}; + const char *xdgConfigDirsPtr = getenv("XDG_CONFIG_DIRS"); + if (!xdgConfigDirsPtr) + return defaultDirs; + + std::string xdgConfigDirsStr(xdgConfigDirsPtr); + std::vector xdgConfigDirs = DString::splitStr(xdgConfigDirsStr, ':'); + if (xdgConfigDirs.size() == 0) + return defaultDirs; + + filterNotAbs(xdgConfigDirs); + addSuffixSlash(xdgConfigDirs); + return xdgConfigDirs; +} + +std::string BaseDir::userCacheDir() +{ + std::string home = homeDir(); + std::string defaultDir = home.size() > 0 ? home + ".cache/" : ""; + const char *xdgCacheHomePtr = getenv("XDG_CACHE_HOME"); + if (!xdgCacheHomePtr) + return defaultDir; + + std::string xdgCacheHome(xdgCacheHomePtr); + if (!DFile::isAbs(xdgCacheHome)) + return defaultDir; + + return xdgCacheHome + "/"; +} + +std::string BaseDir::userAppDir() +{ + std::string dataDir = uerDataDir(); + return dataDir.size() > 0 ? dataDir + "appliations/" : ""; +} + +std::vector BaseDir::sysAppDirs() +{ + auto dataDirs = sysDataDirs(); + std::vector sysAppDirs(dataDirs.size()); + std::transform(dataDirs.begin(), dataDirs.end(), sysAppDirs.begin(), + [](std::string dir) -> std::string {return dir + "applications/";}); + return sysAppDirs; +} + +std::vector BaseDir::appDirs() +{ + std::vector appDirs = sysAppDirs(); + appDirs.push_back(userAppDir()); + return appDirs; +} + +std::vector BaseDir::autoStartDirs() +{ + std::vector autoStartDirs = sysConfigDirs(); + autoStartDirs.push_back(userConfigDir()); + std::transform(autoStartDirs.begin(), autoStartDirs.end(), autoStartDirs.begin(), + [](std::string dir) -> std::string {return dir + "autostart/";}); + + return autoStartDirs; +} + +void BaseDir::filterNotAbs(std::vector &dirs) +{ + for (auto iter = dirs.begin(); iter != dirs.end();) { // erase element in vector + if (!DFile::isAbs(*iter)) + iter = dirs.erase(iter); + else + iter++; + } +} + +void BaseDir::addSuffixSlash(std::vector &dirs) +{ + for (auto &dir : dirs) { + if (!DString::endWith(dir, "/")) + dir += "/"; + } +} diff --git a/src/lib/basedir.h b/src/lib/basedir.h new file mode 100644 index 0000000..f924c8c --- /dev/null +++ b/src/lib/basedir.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef BASEDIR_H +#define BASEDIR_H + +#include +#include + +// 基础目录类, 目录结尾统一包含斜杠/ +class BaseDir +{ +public: + BaseDir(); + + static std::string homeDir(); + static std::string uerDataDir(); + static std::vector sysDataDirs(); + static std::string userConfigDir(); + static std::vector sysConfigDirs(); + static std::string userCacheDir(); + static std::string userAppDir(); + static std::vector sysAppDirs(); + static std::vector appDirs(); + static std::vector autoStartDirs(); + +private: + static void filterNotAbs(std::vector &dirs); + static void addSuffixSlash(std::vector &dirs); +}; + +#endif // BASEDIR_H diff --git a/src/lib/desktopinfo.cpp b/src/lib/desktopinfo.cpp new file mode 100644 index 0000000..f0dbc5b --- /dev/null +++ b/src/lib/desktopinfo.cpp @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "desktopinfo.h" +#include "locale.h" +#include "unistd.h" +#include "dstring.h" +#include "dfile.h" +#include "basedir.h" + +#include +#include +#include +#include + +std::vector DesktopInfo::currentDesktops; + +DesktopInfo::DesktopInfo(const std::string &_fileName) + : kf(KeyFile()) + , fileName(_fileName) + , isValid(true) +{ + if (!DString::endWith(fileName, ".desktop")) + fileName += ".desktop"; + + if (!DFile::isAbs(fileName)) { + // fileName是文件名,增加目录 + bool isExisted = false; + for (const auto &dir : BaseDir::appDirs()) { + fileName = dir + fileName; + if (DFile::isExisted(fileName)) { + isExisted = true; + break; + } + } + + if (!isExisted) { + isValid = false; + return; + } + } + + kf.loadFile(fileName); + + // check DesktopInfo valid + if (fileName.find(".desktop") == std::string::npos) + isValid = false; + + std::vector mainKeys = kf.getMainKeys(); + if (mainKeys.size() == 0) + isValid = false; + + bool found = std::any_of(mainKeys.begin(), mainKeys.end(), + [](const auto &key) {return key == MainSection;}); + + if (!found) + isValid = false; + + if (kf.getStr(MainSection, KeyType) != TypeApplication) + isValid = false; + + name = kf.getLocaleStr(MainSection, KeyName, ""); + icon = kf.getStr(MainSection, KeyIcon); + id = getId(); +} + +DesktopInfo::~DesktopInfo() +{ + +} + +std::string DesktopInfo::getFileName() +{ + return fileName; +} + +bool DesktopInfo::isValidDesktop() +{ + return isValid; +} + +bool DesktopInfo::shouldShow() +{ + if (getNoDisplay() || getIsHidden()) + return false; + + std::vector desktopEnvs; + return getShowIn(desktopEnvs); +} + +bool DesktopInfo::getNoDisplay() +{ + return kf.getBool(MainSection, KeyNoDisplay); +} + +bool DesktopInfo::getIsHidden() +{ + return kf.getBool(MainSection, KeyHidden); +} + +bool DesktopInfo::getShowIn(std::vector desktopEnvs) +{ + if (desktopEnvs.size() == 0) { + if (currentDesktops.size() == 0) { + const char *env = getenv(envDesktopEnv.c_str()); + const auto &desktop = DString::splitChars(env, ':'); + currentDesktops.assign(desktop.begin(), desktop.end()); + } + desktopEnvs.assign(currentDesktops.begin(), currentDesktops.end()); + } + + std::vector onlyShowIn = kf.getStrList(MainSection, KeyOnlyShowIn); + std::vector notShowIn = kf.getStrList(MainSection, KeyNotShowIn); + + for (const auto &desktop : desktopEnvs) { + bool ret = std::any_of(onlyShowIn.begin(), onlyShowIn.end(), + [&desktop](const auto &d) {return d == desktop;}); + if (ret) + return true; + + ret = std::any_of(notShowIn.begin(), notShowIn.end(), + [&desktop](const auto &d) {return d == desktop;}); + if (ret) + return false; + } + + return onlyShowIn.size() == 0; +} + +std::string DesktopInfo::getExecutable() +{ + return kf.getStr(MainSection, KeyExec); +} + +bool DesktopInfo::isExecutableOk() +{ + // 检查TryExec字段 + std::string value = getTryExec(); + std::vector parts = DString::splitStr(value, ' '); + if (parts.size() > 0 ) { + value.assign(parts[0]); + DString::delQuote(value); + if (strstr(value.c_str(), "/") && DFile::isExisted(value)) + return true; + else + return findExecutable(value); + } + + // 检查Exec字段 + value.assign(getExecutable()); + parts.clear(); + parts = DString::splitStr(value, ' '); + if (parts.size() > 0) { + value.assign(parts[0]); + DString::delQuote(value); + if (strstr(value.c_str(), "/") && DFile::isExisted(value)) + return true; + else + return findExecutable(value); + } + + return false; +} + +bool DesktopInfo::isInstalled() +{ + const char *name = fileName.c_str(); + const char *found = strstr(name, "/applications/"); + if (!found) + return false; + + auto appDirs = BaseDir::appDirs(); + return std::any_of(appDirs.begin(), appDirs.end(), + [&name, &found] (std::string dir) -> bool {return strneq(dir.c_str(), name, size_t(found - name));}); +} + +std::vector DesktopInfo::getActions() +{ + std::vector actions; + for (const auto &mainKey : kf.getMainKeys()) { + if (DString::startWith(mainKey, "Desktop Action") + || DString::endWith(mainKey, "Shortcut Group")) { + DesktopAction action; + action.name = kf.getLocaleStr(mainKey, KeyName, ""); + action.exec = kf.getStr(mainKey, KeyExec); + actions.push_back(action); + } + } + + return actions; +} + +// 使用appId获取DesktopInfo需检查有效性 +DesktopInfo DesktopInfo::getDesktopInfoById(std::string appId) +{ + if (!DString::endWith(appId, ".desktop")) + appId += ".desktop"; + + for (const auto & dir : BaseDir::appDirs()) { + std::string filePath = dir + appId; + //检测文件有效性 + if (DFile::isExisted(filePath)) { + return DesktopInfo(filePath); + } + } + + return DesktopInfo(""); +} + +// TryExec is Path to an executable file on disk used to determine if the program is actually installed +std::string DesktopInfo::getTryExec() +{ + return kf.getStr(MainSection, KeyTryExec); +} + +// 按$PATH路径查找执行文件 +bool DesktopInfo::findExecutable(std::string &exec) +{ + static const char *path = getenv("PATH"); + static std::vector paths = DString::splitChars(path, ':'); + return std::any_of(paths.begin(), paths.end(), [&exec](std::string path) {return DFile::isExisted(path + "/" +exec);}); +} + +// filename must has suffix desktopExt +// example: +// /usr/share/applications/a.desktop -> a +// /usr/share/applications/kde4/a.desktop -> kde4/a +// /xxxx/dir/a.desktop -> /xxxx/dir/a +std::string DesktopInfo::getId() +{ + if (!id.empty()) + return id; + + std::string idStr; + auto const suffixPos = fileName.find(".desktop"); + if (suffixPos == std::string::npos) + return ""; + + idStr = fileName.substr(0, fileName.size() - 8); // trim suffix + size_t dirPos = idStr.find("/applications/"); + if (dirPos == std::string::npos) + return ""; + + std::string baseDir(idStr.substr(0, dirPos + 14)); // length of "/applications/" is 14 + std::vector appDirs = BaseDir::appDirs(); + bool installed = std::any_of(appDirs.begin(), appDirs.end(), + [&baseDir](const auto &dir) {return dir == baseDir;}); + + if (installed) { + id = idStr.substr(baseDir.size(), idStr.size()); + } + + return id; +} + +std::string DesktopInfo::getGenericName() +{ + return kf.getLocaleStr(MainSection, KeyGenericName, ""); +} + +std::string DesktopInfo::getName() +{ + return name; +} + +std::string DesktopInfo::getIcon() +{ + return icon; +} + +std::string DesktopInfo::getCommandLine() +{ + return kf.getStr(MainSection, KeyExec); +} + +std::vector DesktopInfo::getKeywords() +{ + return kf.getLocaleStrList(MainSection, KeyKeywords, ""); +} + +std::vector DesktopInfo::getCategories() +{ + return kf.getStrList(MainSection, KeyCategories); +} + +// class AppsDir +AppsDir::AppsDir(const std::string &dirPath) + : path(dirPath) +{ + +} + +AppsDir::~AppsDir() +{ + +} + +std::string AppsDir::getPath() +{ + return path; +} + + +// 获取目录对应的应用名称 +std::map AppsDir::getAppNames() +{ + DIR* dp; + struct dirent* ep; + + dp = opendir(path.c_str()); + if (dp == nullptr) + { + std::cout << "Couldn't open directory " << path << std::endl; + return appNames; + } + + while ((ep = readdir(dp))) { + if (ep->d_type != DT_REG && ep->d_type != DT_LNK) + continue; + + if (!DString::endWith(ep->d_name, ".desktop")) + continue; + + appNames.insert({ep->d_name, true}); + } + closedir(dp); + + return appNames; +} + +// 获取所有应用信息 +std::vector AppsDir::getAllDesktopInfos() +{ + std::map recoder; + std::vector desktopInfos; + + for (auto dir : BaseDir::appDirs()) { + AppsDir appsDir(dir); + std::map appNames = appsDir.getAppNames(); + if (appNames.size() == 0) + continue; + + for (const auto &iter : appNames) { + if (recoder.find(iter.first) != recoder.end()) + continue; + + std::string filePath = dir + iter.first; + DesktopInfo desktopInfo(filePath); + if (!desktopInfo.isValidDesktop()) + continue; + + if (!desktopInfo.shouldShow()) + continue; + + desktopInfos.push_back(std::move(desktopInfo)); + recoder[iter.first] = true; + } + } + + return desktopInfos; +} + diff --git a/src/lib/desktopinfo.h b/src/lib/desktopinfo.h new file mode 100644 index 0000000..b4f7aa3 --- /dev/null +++ b/src/lib/desktopinfo.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DESKTOPINFO_H +#define DESKTOPINFO_H + +#include "keyfile.h" + +#include +#include + +const std::string MainSection = "Desktop Entry"; +const std::string KeyType = "Type"; +const std::string KeyVersion = "Version"; +const std::string KeyName = "Name"; +const std::string KeyGenericName = "GenericName"; +const std::string KeyNoDisplay = "NoDisplay"; +const std::string KeyComment = "Comment"; +const std::string KeyIcon = "Icon"; +const std::string KeyHidden = "Hidden"; +const std::string KeyOnlyShowIn = "OnlyShowIn"; +const std::string KeyNotShowIn = "NotShowIn"; +const std::string KeyTryExec = "TryExec"; +const std::string KeyExec = "Exec"; +const std::string KeyPath = "Path"; +const std::string KeyTerminal = "Terminal"; +const std::string KeyMimeType = "MimeType"; +const std::string KeyCategories = "Categories"; +const std::string KeyKeywords = "Keywords"; +const std::string KeyStartupNotify = "StartupNotify"; +const std::string KeyStartupWMClass = "StartupWMClass"; +const std::string KeyURL = "URL"; +const std::string KeyActions = "Actions"; +const std::string KeyDBusActivatable = "DBusActivatable"; + +const std::string TypeApplication = "Application"; +const std::string TypeLink = "Link"; +const std::string TypeDirectory = "Directory"; + +const std::string envDesktopEnv = "XDG_CURRENT_DESKTOP"; + +typedef struct DesktopAction { + std::string section; + std::string name; + std::string exec; +} DesktopAction; + +// 应用Desktop信息类 +class DesktopInfo { +public: + explicit DesktopInfo(const std::string &_fileName); + ~DesktopInfo(); + + std::string getFileName(); + std::string getExecutable(); + bool isValidDesktop(); + bool shouldShow(); + bool getNoDisplay(); + bool getIsHidden(); + bool getShowIn(std::vector desktopEnvs); + bool isExecutableOk(); + bool isInstalled(); + std::vector getActions(); + static DesktopInfo getDesktopInfoById(std::string appId); + + std::string getId(); + std::string getGenericName(); + std::string getName(); + std::string getIcon(); + std::string getCommandLine(); + std::vector getKeywords(); + std::vector getCategories(); + + KeyFile kf; + +private: + std::string getTryExec(); + bool findExecutable(std::string &exec); + std::string fileName; + std::string id; + std::string name; + std::string icon; + std::string overRideExec; + bool isValid; + static std::vector currentDesktops; +}; + +// 应用目录类 +class AppsDir { +public: + explicit AppsDir(const std::string &dirPath); + ~AppsDir(); + + std::string getPath(); + std::map getAppNames(); + static std::vector getAllDesktopInfos(); + +private: + std::string path; + std::map appNames; +}; + +#endif // DESKTOPINFO_H diff --git a/src/lib/dfile.cpp b/src/lib/dfile.cpp new file mode 100644 index 0000000..3f63c12 --- /dev/null +++ b/src/lib/dfile.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dfile.h" +#include "macro.h" + +#include +#include + +DFile::DFile() +{ + +} + +bool DFile::isAbs(std::string file) +{ + char resolved_path[MAX_FILEPATH_LEN]; + if (realpath(file.c_str(), resolved_path)) { + std::string filePath(resolved_path); + if (filePath == file) + return true; + } + + return false; +} + +bool DFile::isExisted(std::string file) +{ + return !access(file.c_str(), F_OK); +} + +std::string DFile::dir(std::string file) +{ + std::string ret; + if (isAbs(file)) { + size_t pos = file.find_last_of("/"); + if (pos != std::string::npos) { + ret.assign(file, 0, pos + 1); // 包含结尾斜杠/ + } + } + + return ret; +} + +std::string DFile::base(std::string file) +{ + std::string ret; + if (strstr(file.c_str(), "/")) { // 包含路径 + size_t pos = file.find_last_of("/"); + if (pos != std::string::npos) { + ret.assign(file, pos + 1, file.size() - pos); // 去除路径 + } + } + + size_t pos = file.find_last_of("."); // 去除后缀 + if (pos != std::string::npos) { + ret.assign(file, 0, pos + 1); + } + + return ret; +} diff --git a/src/lib/dfile.h b/src/lib/dfile.h new file mode 100644 index 0000000..cb512fd --- /dev/null +++ b/src/lib/dfile.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DFILE_H +#define DFILE_H + +#include + +class DFile +{ +public: + explicit DFile(); + static bool isAbs(std::string file); + static bool isExisted(std::string file); + static std::string dir(std::string file); + static std::string base(std::string file); +}; + +#endif // DFILE_H diff --git a/src/lib/dlocale.cpp b/src/lib/dlocale.cpp new file mode 100644 index 0000000..300bdcc --- /dev/null +++ b/src/lib/dlocale.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dlocale.h" +#include "dstring.h" + +#include +#include + +#define ComponentCodeset 1 +#define ComponentTerritory 2 +#define ComponentModifier 4 + +#define MAXLINELEN 256 + +const char *aliasFile = "/usr/share/locale/locale.alias"; +const char charUscore = '_'; +const char charDot = '.'; +const char charAt = '@'; + +Locale::Locale() +{ + pthread_mutex_init(&languageNames.mutex, nullptr); + + // init aliases + FILE *fp = fopen(aliasFile, "r"); + if (fp) { + + char data[MAXLINELEN] = {0}; + std::string line; + std::vector parts; + while (fgets(data, MAXLINELEN, fp)) { + char *start = &data[0]; + char *end = start; + + // 移除行首 + while (strneq(start, " ", 1) || strneq(start, "\t", 1)) + start++; + + // 过滤注释行和空行 + if (strneq(start, "#", 1) || strneq(start, "\n", 1)) + continue; + + while (!strneq(end, "\n", 1)) + end++; + + // 移除行尾 + while (strneq(end, "\n", 1) || strneq(end, "\r", 1) + || strneq(end, " ", 1) || strneq(end, "\t", 1)) + end--; + + line.assign(start, ulong(end - start + 1)); + parts = DString::splitStr(line, ' '); + // 使用\t分割 + if (parts.size() != 2) + parts = DString::splitStr(line, '\t'); + + if (parts.size() == 2) { + aliases[parts[0]] = parts[1]; + } + } + fclose(fp); + } +} + +// wayland environment is useful? +// ExplodeLocale Break an X/Open style locale specification into components +Locale::Components Locale::explodeLocale(std::string locale) +{ + Components cmp; + std::vector parts; + if (locale.find(charAt) != std::string::npos) { + parts = DString::splitStr(locale, charAt); + if (parts.size() == 2) { + cmp.modifier = parts[1]; + locale = parts[0]; + cmp.mask |= ComponentModifier; + } + } + + if (locale.find(charDot) != std::string::npos) { + parts = DString::splitStr(locale, charDot); + if (parts.size() == 2) { + cmp.codeset = parts[1]; + locale = locale[0]; + cmp.mask |= ComponentCodeset; + } + } + + if (locale.find(charUscore) != std::string::npos) { + parts = DString::splitStr(locale, charUscore); + if (parts.size() == 2) { + cmp.territory = parts[1]; + locale = parts[0]; + cmp.mask |= ComponentTerritory; + } + } + + cmp.language = locale; + return cmp; +} + +std::string Locale::guessCategoryValue(std::string categoryName) +{ + // The highest priority value is the 'LANGUAGE' environment + // variable. This is a GNU extension. + const char *language = getenv("LANGUAGE"); + if (language) + return language; + + // Setting of LC_ALL overwrites all other. + const char *lcAll = getenv("LC_ALL"); + if (lcAll) + return lcAll; + + // Next comes the name of the desired category. + const char *name = getenv(categoryName.c_str()); + if (name) + return name; + + // Last possibility is the LANG environment variable. + const char *lang = getenv("LANG"); + if (lang) + return lang; + + return "C"; +} + +std::string Locale::unaliasLang(std::string lang) +{ + if (aliases.find(lang) != aliases.end()) + return aliases[lang]; + else + return lang; +} + +// wayland environment is useful? +/* + * Compute all interesting variants for a given locale name - + * by stripping off different components of the value. + * + * For simplicity, we assume that the locale is in + * X/Open format: language[_territory][.codeset][@modifier] + */ +std::vector Locale::getLocaleVariants(const std::string &locale) +{ + auto cmp = explodeLocale(locale); + uint mask = cmp.mask; + std::vector variants; + for (uint i = 0; i <= mask; i++) { + uint j = mask - i; + //if ((j & ^mask) == 0) { + std::string var(cmp.language); + if (j & ComponentTerritory) + var = var + charUscore + cmp.territory; + if (j & ComponentCodeset) + var = var + charDot + cmp.codeset; + if (j & ComponentModifier) + var = var + charAt + cmp.modifier; + + variants.push_back(var); + //} + } + + return variants; +} + +std::vector Locale::getLanguageNames() +{ + std::vector names; + std::string value(guessCategoryValue("LC_MESSAGES")); + if (value.empty()) { + names.push_back(value); + return names; + } + + pthread_mutex_lock(&languageNames.mutex); + if (languageNames.language != value) { + languageNames.language = value; + languageNames.names.clear(); + std::vector langs = DString::splitStr(value, ':'); + for (const auto & lang : langs) { + std::vector localeVariant = getLocaleVariants(unaliasLang(lang)); + for (const auto & var : localeVariant) + languageNames.names.push_back(var); + } + languageNames.names.push_back("C"); + } + pthread_mutex_unlock(&languageNames.mutex); + + return languageNames.names; +} diff --git a/src/lib/dlocale.h b/src/lib/dlocale.h new file mode 100644 index 0000000..3180f40 --- /dev/null +++ b/src/lib/dlocale.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LOCALE_H +#define LOCALE_H + +#include +#include +#include + +// 本地化类 +class Locale { + struct LanguageNameCache { + std::string language; + std::vector names; + pthread_mutex_t mutex; + }; + + struct Components { + Components() : mask(0) {} // 数字必须初始化 + std::string language; + std::string territory; + std::string codeset; + std::string modifier; + uint mask; + }; + +public: + std::vector getLocaleVariants(const std::string &locale); + std::vector getLanguageNames(); + static inline Locale *instance() { + static Locale instance; + return &instance; + } + +private: + Locale(); + Locale(const Locale &); + Locale& operator= (const Locale &); + + Components explodeLocale(std::string locale); + std::string guessCategoryValue(std::string categoryName); + std::string unaliasLang(std::string); + std::map aliases; + LanguageNameCache languageNames; +}; + +#endif diff --git a/src/lib/dstring.cpp b/src/lib/dstring.cpp new file mode 100644 index 0000000..9fdce72 --- /dev/null +++ b/src/lib/dstring.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dstring.h" + +#include + +DString::DString() +{ + +} + +DString::~DString() +{ + +} + +std::vector DString::splitChars(const char *cs, char c) +{ + assert(cs); + + std::vector ret; + unsigned long idx = 0; + unsigned long size = strlen(cs); + bool found = false; + std::string sub; + for (unsigned long i=0; i < size; i++) { + if (!strneq(&cs[i], &c, 1)) + continue; + + sub.assign(cs, found ? idx+1:idx, found ? i-idx-1:i-idx); + if (idx < i && !sub.empty()) { + ret.push_back(sub); + } + idx = i; + found = true; + } + sub.assign(cs, found ? idx+1:idx, found ? size-idx-1:size-idx); + if (idx < size && !sub.empty()) { + ret.push_back(sub); + } + + return ret; +} + +std::vector DString::splitStr(const std::string &str, char c) +{ + return splitChars(str.c_str(), c); +} + +std::vector DString::splitVectorChars(const std::vector &content, size_t length, char c) +{ + std::vector ret; + size_t pos = 0; + bool hasChar = true; + for (size_t i = 0; i < length; i++) { + if (content[i] == c && i > pos && hasChar) { + std::string str; + for (size_t j = pos; j <= i; j++) { + str += std::string(1, content[j]); + } + ret.push_back(str); + pos = i + 1; + hasChar = false; + } else { + hasChar = true; + } + } + + return ret; +} + +bool DString::startWith(const char *chars, const char *prefix) +{ + assert(chars); + assert(prefix); + + size_t len; + len = strlen(prefix); + return strneq(chars, prefix, len); +} + +bool DString::startWith(const std::string &str, const std::string &prefix) +{ + return startWith(str.c_str(), prefix.c_str()); +} + +bool DString::endWith(const char *chars, const char *suffix) +{ + assert(chars); + assert(suffix); + + size_t charsLen = strlen(chars); + size_t suffixLen = strlen(suffix); + + if (charsLen == 0 || charsLen < suffixLen) + return false; + + return memcmp(chars + charsLen - suffixLen, suffix, suffixLen) == 0; +} + +bool DString::endWith(const std::string &str, const std::string &suffix) +{ + return endWith(str.c_str(), suffix.c_str()); +} + +char *DString::delQuote(const char *chars) +{ + char *data = nullptr; + if (!chars) + return data; + + if (strneq(chars, "\"", 1) && strneq(chars + strlen(chars) - 1, "\"", 1)) { + data = static_cast(calloc(1, strlen(chars) - 2)); + memcpy(data, chars + 1, strlen(chars) - 1); + } else { + data = static_cast(calloc(1, strlen(chars) + 1)); + memcpy(data, chars, strlen(chars) + 1); + } + + return data; +} + +void DString::delQuote(std::string &str) +{ + while (*str.begin() == '\"' && *str.rbegin() == '\"') + str.assign(str.substr(1, str.size() - 2)); +} + diff --git a/src/lib/dstring.h b/src/lib/dstring.h new file mode 100644 index 0000000..71ed752 --- /dev/null +++ b/src/lib/dstring.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DSTRING_H +#define DSTRING_H + +#include +#include +#include + +#define streq(a,b) (strcmp((a),(b)) == 0) +#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) +#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) +#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) + +// 字符串操作 +class DString +{ +public: + DString(); + ~DString(); + + // 字符串拆分 + static std::vector splitChars(const char *cs, char c); + static std::vector splitStr(const std::string &str, char c); + static std::vector splitVectorChars(const std::vector &content, size_t length, char c); + // 字符串前缀判断 + static bool startWith(const char *chars, const char *prefix); + static bool startWith(const std::string &str, const std::string &prefix); + // 字符后缀判断 + static bool endWith(const char *chars, const char *suffix); + static bool endWith(const std::string &str, const std::string &suffix); + // 去除首尾引用 + static char *delQuote(const char *chars); + static void delQuote(std::string &str); +}; + +#endif // DSTRING_H diff --git a/src/lib/keyfile.cpp b/src/lib/keyfile.cpp new file mode 100644 index 0000000..b647b18 --- /dev/null +++ b/src/lib/keyfile.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "keyfile.h" +#include "dlocale.h" +#include "dstring.h" +#include "macro.h" + +#include +#include +#include + +KeyFile::KeyFile(char separtor) + : fp(nullptr) + , modified(false) + , listSeparator(separtor) +{ +} + +KeyFile::~KeyFile() +{ + if (fp) { + fclose(fp); + fp = nullptr; + } +} + +bool KeyFile::getBool(const std::string §ion, const std::string &key, bool defaultValue) +{ + if (mainKeyMap.find(section) == mainKeyMap.end()) + return false; + + std::string valueStr = mainKeyMap[section][key]; + bool value = defaultValue; + if (valueStr == "true") + value = true; + else if (valueStr == "false") + value = false; + + return value; +} + +// TODO +std::vector KeyFile::getBoolList(const std::string §ion, const std::string &key, bool defaultValue) +{ + std::vector tmp; + return tmp; +} + +int KeyFile::getInt(const std::string §ion, const std::string &key, int defaultValue) +{ + if (mainKeyMap.find(section) == mainKeyMap.end()) + return defaultValue; + + std::string valueStr = mainKeyMap[section][key]; + int value; + try { + value = std::stoi(valueStr); + } catch (std::invalid_argument&) { + value = defaultValue; + } + + return value; +} + +// TODO +std::vector KeyFile::getIntList(const std::string §ion, const std::string &key, int defaultValue) +{ + std::vector tmp; + return tmp; +} + +// TODO +int64_t KeyFile::getInt64(const std::string §ion, const std::string &key, int64_t defaultValue) +{ + return int64_t(0); +} + +// TODO +float KeyFile::getFloat(const std::string §ion, const std::string &key, float defaultValue) +{ + return 1.0; +} + +std::string KeyFile::getStr(const std::string §ion, const std::string &key, std::string defaultValue) +{ + if (mainKeyMap.find(section) == mainKeyMap.end()) + return defaultValue; + + std::string valueStr = mainKeyMap[section][key]; + if (valueStr.empty()) + valueStr = defaultValue; + + return valueStr; +} + +bool KeyFile::containKey(const std::string §ion, const std::string &key) +{ + if (mainKeyMap.find(section) == mainKeyMap.end()) + return false; + + return mainKeyMap[section].find(key) != mainKeyMap[section].end(); +} + +std::string KeyFile::getLocaleStr(const std::string §ion, const std::string &key, std::string defaultLocale) +{ + std::vector languages = defaultLocale.empty() + ? Locale::instance()->getLanguageNames() + : Locale::instance()->getLocaleVariants(defaultLocale); + + std::string translated; + for (const auto &lang : languages) { + translated.assign(getStr(section, key + "[" + lang + "]")); + if (!translated.empty()) + return translated; + } + + // NOTE: not support key Gettext-Domain + // fallback to default key + return getStr(section, key); +} + +std::vector KeyFile::getStrList(const std::string §ion, const std::string &key) +{ + std::string value = getStr(section, key); + return DString::splitStr(value, listSeparator); +} + +std::vector KeyFile::getLocaleStrList(const std::string §ion, const std::string &key, std::string defaultLocale) +{ + std::vector languages = defaultLocale.empty() + ? Locale::instance()->getLanguageNames() + : Locale::instance()->getLocaleVariants(defaultLocale); + + std::vector translated; + for (const auto &lang : languages) { + translated = getStrList(section, key + "[" + lang + "]"); + if (translated.size() > 0) + return translated; + } + + //fallback to default key + return getStrList(section, key); +} + +// 修改keyfile内容 +void KeyFile::setKey(const std::string §ion, const std::string &key, const std::string &value) +{ + if (mainKeyMap.find(section) == mainKeyMap.end()) + mainKeyMap.insert({section, KeyMap()}); + + mainKeyMap[section].insert({key, value}); +} + +// 写入文件 +bool KeyFile::saveToFile(const std::string &filePath) +{ + FILE *sfp = fopen(filePath.data(), "w+"); + if (!sfp) + return false; + + + for (const auto &im : mainKeyMap) { + const auto &keyMap = im.second; + std::string section = "[" + im.first + "]\n"; + fputs(section.c_str(), sfp); + for (const auto &ik : keyMap) { + std::string kv = ik.first + "=" + ik.second + "\n"; + fputs(kv.c_str(), sfp); + } + } + + fclose(sfp); + return true; +} + +bool KeyFile::loadFile(const std::string &filePath) +{ + mainKeyMap.clear(); + if (fp) { + fclose(fp); + fp = nullptr; + } + + std::string lastSection; + fp = fopen(filePath.data(), "r"); + if (!fp) + return false; + + char line[MAX_LINE_LEN] = {0}; + while (fgets(line, MAX_LINE_LEN, fp)) { + char *start = &line[0]; + char *end = start; + while (!strneq(end, "\0", 1)) + end++; + + end--; // 返回'\0'前一个字符 + + // 移除行首 + while (strneq(start, " ", 1) || strneq(start, "\t", 1)) + start++; + + // 过滤注释行 + if (strneq(start, "#", 1)) + continue; + + // 移除行尾 + while (strneq(end, "\n", 1) || strneq(end, "\r", 1) + || strneq(end, " ", 1) || strneq(end, "\t", 1)) + end--; + + char *lPos = strchr(start, '['); + char *rPos = strchr(start, ']'); + if (lPos && rPos && rPos - lPos > 0 && lPos == start && rPos == end) { + // 主键 + std::string section(lPos + 1, size_t(rPos - lPos - 1)); + mainKeyMap.insert({section, KeyMap()}); + lastSection = section; + } else { + char *equal = strchr(start, '='); + if (!equal) + continue; + + // 文件格式错误 + if (lastSection.empty()) { + std::cout << "failed to load file " << filePath << std::endl; + return false; + } + + // 子键 + std::string key(start, size_t(equal - start)); + std::string value(equal + 1, size_t(end - equal)); + for (auto &iter : mainKeyMap) { + if (iter.first != lastSection) + continue; + + iter.second[key] = value; + } + } + } + fclose(fp); + fp = nullptr; + + return true; +} + +std::vector KeyFile::getMainKeys() +{ + std::vector mainKeys; + for (const auto &iter : mainKeyMap) + mainKeys.push_back(iter.first); + + return mainKeys; +} + +void KeyFile::print() +{ + std::cout << "sectionMap: " << std::endl; + for (auto sectionMap : mainKeyMap) { + std::cout << "section=" << sectionMap.first << std::endl; + KeyMap keyMap = sectionMap.second; + + for (auto iter : keyMap) { + std::cout << iter.first << "=" << iter.second << std::endl; + } + + std::cout << std::endl; + } +} + + diff --git a/src/lib/keyfile.h b/src/lib/keyfile.h new file mode 100644 index 0000000..fe3bf49 --- /dev/null +++ b/src/lib/keyfile.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEYFILE_H +#define KEYFILE_H + +#include +#include +#include + +typedef std::map KeyMap; +typedef std::map MainKeyMap; + +// 解析ini、desktop文件类 +class KeyFile +{ +public: + explicit KeyFile(char separtor = ';'); + ~KeyFile(); + + bool getBool(const std::string §ion, const std::string &key, bool defaultValue = false); + std::vector getBoolList(const std::string §ion, const std::string &key, bool defaultValue = false); + int getInt(const std::string §ion, const std::string &key, int defaultValue = 0); + std::vector getIntList(const std::string §ion, const std::string &key, int defaultValue = 0); + int64_t getInt64(const std::string §ion, const std::string &key, int64_t defaultValue = 0); + float getFloat(const std::string §ion, const std::string &key, float defaultValue = 0); + std::string getStr(const std::string §ion, const std::string &key, std::string defaultValue = ""); + bool containKey(const std::string §ion, const std::string &key); + std::string getLocaleStr(const std::string §ion, const std::string &key, std::string defaultLocale = ""); + std::vector getStrList(const std::string §ion, const std::string &key); + std::vector getLocaleStrList(const std::string §ion, const std::string &key, std::string defaultLocale = ""); + + void setKey(const std::string §ion, const std::string &key, const std::string &value); + bool saveToFile(const std::string &filePath); + bool loadFile(const std::string &filePath); + std::vector getMainKeys(); + + // for test + void print(); + +private: + MainKeyMap mainKeyMap; // section -> key : value + std::string filePath; + FILE *fp; + bool modified; + char listSeparator; +}; + +#endif // KEYFILE_H diff --git a/src/lib/lang.h b/src/lib/lang.h new file mode 100644 index 0000000..07d2189 --- /dev/null +++ b/src/lib/lang.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LANG_H +#define LANG_H + +#include "dstring.h" + +#include +#include +#include +#include +#include + +// 返回用户语言,参见man gettext +inline std::vector queryLangs() { + std::vector ret; + const char *lcAll = getenv("LC_ALL"); + const char *lcMessage = getenv("LC_MESSAGE"); + const char *language = getenv("LANGUAGE"); + const char *lang = getenv("LANG"); + + auto cutOff = [](std::string str)->std::string { + size_t idx = str.find("."); + if (idx == std::string::npos) + return str; + + return std::string(str).substr(0, idx); + }; + + if (lcAll && std::string(lcAll) != "C" + && language && std::string(language) != "") + { + std::vector splits = DString::splitChars(language, ':'); + for (const auto &l : splits) { + ret.push_back(cutOff(l)); + } + return ret; + } + + if (lcAll && std::string(lcAll) != "") + ret.push_back(cutOff(lcAll)); + + if (lcMessage && std::string(lcMessage) != "") + ret.push_back(cutOff(lcMessage)); + + if (lang && std::string(lang) != "") + ret.push_back(cutOff(lang)); + + return ret; +} + + +#endif // LANG_H diff --git a/src/lib/lang.hpp b/src/lib/lang.hpp new file mode 100644 index 0000000..07d2189 --- /dev/null +++ b/src/lib/lang.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LANG_H +#define LANG_H + +#include "dstring.h" + +#include +#include +#include +#include +#include + +// 返回用户语言,参见man gettext +inline std::vector queryLangs() { + std::vector ret; + const char *lcAll = getenv("LC_ALL"); + const char *lcMessage = getenv("LC_MESSAGE"); + const char *language = getenv("LANGUAGE"); + const char *lang = getenv("LANG"); + + auto cutOff = [](std::string str)->std::string { + size_t idx = str.find("."); + if (idx == std::string::npos) + return str; + + return std::string(str).substr(0, idx); + }; + + if (lcAll && std::string(lcAll) != "C" + && language && std::string(language) != "") + { + std::vector splits = DString::splitChars(language, ':'); + for (const auto &l : splits) { + ret.push_back(cutOff(l)); + } + return ret; + } + + if (lcAll && std::string(lcAll) != "") + ret.push_back(cutOff(lcAll)); + + if (lcMessage && std::string(lcMessage) != "") + ret.push_back(cutOff(lcMessage)); + + if (lang && std::string(lang) != "") + ret.push_back(cutOff(lang)); + + return ret; +} + + +#endif // LANG_H diff --git a/src/lib/macro.h b/src/lib/macro.h new file mode 100644 index 0000000..8f3b585 --- /dev/null +++ b/src/lib/macro.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MACRO_H +#define MACRO_H + +#define _likely_(x) (__builtin_expect(!!(x), 1)) +#define _unlikely_(x) (__builtin_expect(!!(x), 0)) + +#define MAX_FILEPATH_LEN 256 +#define MAX_LINE_LEN 256 + +#endif // MACRO_H diff --git a/src/lib/process.cpp b/src/lib/process.cpp new file mode 100644 index 0000000..95e41f7 --- /dev/null +++ b/src/lib/process.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "process.h" +#include "macro.h" +#include "dstring.h" +#include "dfile.h" + +#include +#include +#include + +#define FILECONTENLEN 2048 + +Process::Process() + : pid(0) + , ppid(0) +{ + +} + +Process::Process(int _pid) + : pid(_pid) + , ppid(0) +{ + +} + +bool Process::isExist() +{ + std::string procDir = "/proc/" + std::to_string(pid); + return DFile::isExisted(procDir); +} + +std::vector Process::getCmdLine() +{ + if (cmdLine.size() == 0) { + std::string cmdlineFile = getFile("cmdline"); + cmdLine = readFile(cmdlineFile); + } + + return cmdLine; +} + +std::string Process::getCwd() +{ + if (cwd.empty()) { + std::string cwdFile = getFile("cwd"); + char path[MAX_FILEPATH_LEN] = {}; + ssize_t len = readlink(cwdFile.c_str(), path, MAX_FILEPATH_LEN); + if (len > 0 && len < MAX_FILEPATH_LEN) { + cwd = std::string(path) + "/"; + } + } + + return cwd; +} + +std::string Process::getExe() +{ + if (exe.empty()) { + std::string cmdLineFile = getFile("exe"); + char path[MAX_FILEPATH_LEN] = {}; + ssize_t len = readlink(cmdLineFile.c_str(), path, MAX_FILEPATH_LEN); + if (len > 0 && len < MAX_FILEPATH_LEN) { + exe = std::string(path); + } + } + + return exe; +} + +std::vector Process::getEnviron() +{ + if (environ.size() == 0) { + std::string envFile = getFile("environ"); + environ = readFile(envFile); + } + + return environ; +} + +std::string Process::getEnv(const std::string &key) +{ + if (environ.size() == 0) + environ = getEnviron(); + + std::string keyPrefix = key + "="; + for (auto & env : environ) { + if (DString::startWith(env, keyPrefix)) { + ulong len = keyPrefix.size(); + return env.substr(len, env.size() - len); + } + } + + return ""; +} + +Status Process::getStatus() +{ + if (status.size() == 0) { + std::string statusFile = getFile("status"); + FILE *fp = fopen(statusFile.c_str(), "r"); + if (!fp) + return status; + + char line[MAX_LINE_LEN] = {0}; + while (fgets(line, MAX_LINE_LEN, fp)) { + std::string info(line); + std::vector parts = DString::splitStr(info, ':'); + if (parts.size() == 2) + status[parts[0]] = parts[1]; + } + fclose(fp); + } + + return status; +} + +std::vector Process::getUids() +{ + if (uids.size() == 0) { + if (status.find("Uid") != status.end()) { + std::string uidGroup = status["Uid"]; + std::vector parts = DString::splitStr(uidGroup, '\t'); + uids.reserve(parts.size()); + std::transform(parts.begin(), parts.end(), uids.begin(), + [](std::string idStr) -> int {return std::stoi(idStr);}); + } + } + + return uids; +} + +int Process::getPid() +{ + return pid; +} + +int Process::getPpid() +{ + if (ppid == 0) { + if (status.find("PPid") != status.end()) { + ppid = std::stoi(status["PPid"]); + } + } + + return ppid; +} + +std::string Process::getFile(const std::string &name) +{ + return "/proc/" + std::to_string(pid) + "/" + name; +} + +// /proc is not real file system +std::vector Process::readFile(std::string fileName) +{ + std::vector ret; + std::FILE *fp = std::fopen(fileName.c_str(), "r"); + if (!fp) + return ret; + + std::vector content(FILECONTENLEN); + std::size_t len = std::fread(&content[0], 1, FILECONTENLEN, fp); + std::fclose(fp); + + ret = DString::splitVectorChars(content, len, '\0'); + return ret; +} diff --git a/src/lib/process.h b/src/lib/process.h new file mode 100644 index 0000000..4922caa --- /dev/null +++ b/src/lib/process.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PROCESS_H +#define PROCESS_H + +#include +#include +#include + +typedef std::map Status; + +class Process +{ +public: + Process(); + explicit Process(int _pid); + + bool isExist(); + std::vector getCmdLine(); + std::string getCwd(); + std::string getExe(); + std::vector getEnviron(); + std::string getEnv(const std::string &key); + Status getStatus(); + std::vector getUids(); + int getPid(); + int getPpid(); + +private: + std::string getFile(const std::string &name); + std::vector readFile(std::string fileName); + + int pid; + std::vector cmdLine; + std::string cwd; + std::string exe; + std::vector environ; + Status status; + std::vector uids; + int ppid; +}; + +#endif // PROCESS_H diff --git a/src/lib/xcbutils.cpp b/src/lib/xcbutils.cpp new file mode 100644 index 0000000..08eb029 --- /dev/null +++ b/src/lib/xcbutils.cpp @@ -0,0 +1,574 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "xcbutils.h" + +#include +#include + +XCBUtils::XCBUtils() +{ + connect = xcb_connect(nullptr, &screenNum); // nullptr表示默认使用环境变量$DISPLAY获取屏幕 + if (xcb_connection_has_error(connect)) { + std::cout << "XCBUtils: init xcb_connect error" << std::endl; + return; + } + + if (!xcb_ewmh_init_atoms_replies(&ewmh, + xcb_ewmh_init_atoms(connect, &ewmh), // 初始化Atom + nullptr)) + std::cout << "XCBUtils: init ewmh error" << std::endl; +} + +XCBUtils::~XCBUtils() +{ + if (connect) { + xcb_disconnect(connect); // 关闭连接并释放 + connect = nullptr; + } +} + +XWindow XCBUtils::allocId() +{ + return xcb_generate_id(connect); +} + +void XCBUtils::killClientChecked(XWindow xid) +{ + xcb_kill_client_checked(connect, xid); +} + +xcb_get_property_reply_t *XCBUtils::getPropertyValueReply(XWindow xid, XCBAtom property, XCBAtom type) +{ + xcb_get_property_cookie_t cookie = xcb_get_property(connect, + 0, + xid, + property, + type, + 0, + MAXLEN); + return xcb_get_property_reply(connect, cookie, nullptr); +} + +void *XCBUtils::getPropertyValue(XWindow xid, XCBAtom property, XCBAtom type) +{ + void *value = nullptr; + xcb_get_property_reply_t *reply = getPropertyValueReply(xid, property, type); + if (reply) { + if (xcb_get_property_value_length(reply) > 0) { + value = xcb_get_property_value(reply); + } + free(reply); + } + return value; +} + +std::string XCBUtils::getUTF8PropertyStr(XWindow xid, XCBAtom property) +{ + std::string ret; + xcb_get_property_reply_t *reply = getPropertyValueReply(xid, property, ewmh.UTF8_STRING); + if (reply) { + ret = getUTF8StrFromReply(reply); + + free(reply); + } + return ret; +} + +XCBAtom XCBUtils::getAtom(const char *name) +{ + XCBAtom ret = atomCache.getVal(name); + if (ret == ATOMNONE) { + xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connect, false, strlen(name), name); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply (connect, + cookie, + nullptr); + if (reply) { + atomCache.store(name, reply->atom); + ret = reply->atom; + + free(reply); + } + } + + return ret; +} + +std::string XCBUtils::getAtomName(XCBAtom atom) +{ + std::string ret = atomCache.getName(atom); + if (ret.empty()) { + xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(connect, atom); + xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(connect, + cookie, + nullptr); + if (reply) { + char *name = xcb_get_atom_name_name(reply); + if (name) { + atomCache.store(name, atom); + ret = name; + } + + free(reply); + } + } + + return ret; +} + +Geometry XCBUtils::getWindowGeometry(XWindow xid) +{ + Geometry ret; + xcb_get_geometry_cookie_t cookie = xcb_get_geometry(connect, xid); + xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(connect, cookie, nullptr); + if (reply) { + ret.x = reply->x; + ret.y = reply->y; + ret.width = reply->width; + ret.height = reply->height; + + free(reply); + } else { + std::cout << xid << " getWindowGeometry err" << std::endl; + } + + return ret; +} + +XWindow XCBUtils::getActiveWindow() +{ + XWindow ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_active_window(&ewmh, screenNum); + if (!xcb_ewmh_get_active_window_reply(&ewmh, cookie, &ret, nullptr)) + std::cout << "getActiveWindow error" << std::endl; + + return ret; +} + +void XCBUtils::setActiveWindow(XWindow xid) +{ + xcb_ewmh_set_active_window(&ewmh, screenNum, xid); +} + +std::list XCBUtils::getClientList() +{ + std::list ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_client_list(&ewmh, screenNum); + xcb_ewmh_get_windows_reply_t reply; + if (!xcb_ewmh_get_client_list_reply(&ewmh, cookie, &reply, nullptr)) + std::cout << "getClientList error" << std::endl; + + for (uint32_t i = 0; i < reply.windows_len; i++) + ret.push_back(reply.windows[i]); + + return ret; +} + +std::list XCBUtils::getClientListStacking() +{ + std::list ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_client_list_stacking(&ewmh, screenNum); + xcb_ewmh_get_windows_reply_t reply; + if (!xcb_ewmh_get_client_list_stacking_reply(&ewmh, cookie, &reply, nullptr)) + std::cout << "getClientListStacking error" << std::endl; + + for (uint32_t i = 0; i < reply.windows_len; i++) + ret.push_back(reply.windows[i]); + + return ret; +} + +std::vector XCBUtils::getWMState(XWindow xid) +{ + std::vector ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_state(&ewmh, xid); + xcb_ewmh_get_atoms_reply_t reply; // a list of Atom + if (xcb_ewmh_get_wm_state_reply(&ewmh, cookie, &reply, nullptr)) { + for (uint32_t i = 0; i < reply.atoms_len; i++) { + ret.push_back(reply.atoms[i]); + } + } else { + std::cout << xid << " getWMState error" << std::endl; + } + + return ret; +} + +std::vector XCBUtils::getWMWindoType(XWindow xid) +{ + std::vector ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_window_type(&ewmh, xid); + xcb_ewmh_get_atoms_reply_t reply; // a list of Atom + if (!xcb_ewmh_get_wm_window_type_reply(&ewmh, cookie, &reply, nullptr)) + std::cout << xid << " getWMWindoType error" << std::endl; + + return ret; +} + +std::vector XCBUtils::getWMAllowedActions(XWindow xid) +{ + std::vector ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_allowed_actions(&ewmh, xid); + xcb_ewmh_get_atoms_reply_t reply; // a list of Atoms + if (!xcb_ewmh_get_wm_allowed_actions_reply(&ewmh, cookie, &reply, nullptr)) + std::cout << xid << " getWMAllowedActions error" << std::endl; + + for (uint32_t i = 0; i < reply.atoms_len; i++) { + ret.push_back(reply.atoms[i]); + } + + return ret; +} + +void XCBUtils::setWMAllowedActions(XWindow xid, std::vector actions) +{ + XCBAtom list[MAXALLOWEDACTIONLEN] {0}; + for (size_t i = 0; i < actions.size(); i++) + list[i] = actions[i]; + + xcb_ewmh_set_wm_allowed_actions(&ewmh, xid, actions.size(), list); +} + +std::string XCBUtils::getWMName(XWindow xid) +{ + std::string ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_name(&ewmh, xid); + xcb_ewmh_get_utf8_strings_reply_t reply1; + if (!xcb_ewmh_get_wm_name_reply(&ewmh, cookie, &reply1, nullptr)) + std::cout << xid << " getWMName error" << std::endl; + + ret.assign(reply1.strings); + + return ret; +} + +uint32_t XCBUtils::getWMPid(XWindow xid) +{ + uint32_t ret = 0; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_pid(&ewmh, xid); + if (!xcb_ewmh_get_wm_pid_reply(&ewmh, cookie, &ret, nullptr)) + std::cout << xid << " getWMPid error" << std::endl; + + return ret; +} + +std::string XCBUtils::getWMIconName(XWindow xid) +{ + std::string ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_icon_name(&ewmh, xid); + xcb_ewmh_get_utf8_strings_reply_t reply; + if (!xcb_ewmh_get_wm_icon_name_reply(&ewmh, cookie, &reply, nullptr)) + std::cout << xid << " getWMIconName error" << std::endl; + + ret.assign(reply.strings); + + return ret; +} + +std::vector XCBUtils::getWMIcon(XWindow xid) +{ + std::vector ret; + /* + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_icon(&ewmh, xid); + xcb_ewmh_get_wm_icon_reply_t reply; + if (xcb_ewmh_get_wm_icon_reply(&ewmh, cookie, &reply, nullptr)) { + xcb_ewmh_wm_icon_iterator_t iter = xcb_ewmh_get_wm_icon_iterator(&reply); + auto fcn = [](xcb_ewmh_wm_icon_iterator_t it) { + std::vector data; + uint32_t *dat = it.data; + int area = it.width * it.height; + for (int i = 0; i < (2 + area) * 4; i++, dat++) { // TODO check data accuracy + data.push_back(*dat); + } + return data; + }; + + ret.push_back({iter.width, iter.height, fcn(iter)}); + + while (iter.rem >= 1) { + xcb_ewmh_get_wm_icon_next(&iter); + ret.push_back({iter.width, iter.height, fcn(iter)}); + } + + xcb_ewmh_get_wm_icon_reply_wipe(&reply); // clear + } +*/ + return ret; +} + +XWindow XCBUtils::getWMClientLeader(XWindow xid) +{ + XWindow ret; + XCBAtom atom = getAtom("WM_CLIENT_LEADER"); + void *value = getPropertyValue(xid, atom, XCB_ATOM_INTEGER); + std::cout << "getWMClientLeader:" << (char*)value << std::endl; + + return ret; +} + +void XCBUtils::requestCloseWindow(XWindow xid, uint32_t timestamp) +{ + xcb_ewmh_request_close_window(&ewmh, screenNum, xid, timestamp, XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER); +} + +uint32_t XCBUtils::getWMDesktop(XWindow xid) +{ + uint32_t ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_desktop(&ewmh, xid); + if (!xcb_ewmh_get_wm_desktop_reply(&ewmh, cookie, &ret, nullptr)) + std::cout << xid << " getWMDesktop error" << std::endl; + + return ret; +} + +void XCBUtils::setWMDesktop(XWindow xid, uint32_t desktop) +{ + xcb_ewmh_set_wm_desktop(&ewmh, xid, desktop); +} + +void XCBUtils::setCurrentWMDesktop(uint32_t desktop) +{ + xcb_ewmh_set_current_desktop(&ewmh, screenNum, desktop); +} + +uint32_t XCBUtils::getCurrentWMDesktop() +{ + uint32_t ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_current_desktop(&ewmh, screenNum); + if (!xcb_ewmh_get_current_desktop_reply(&ewmh, cookie, &ret, nullptr)) + std::cout << "getCurrentWMDesktop error" << std::endl; + + return ret; +} + +bool XCBUtils::isGoodWindow(XWindow xid) +{ + bool ret = false; + xcb_get_geometry_cookie_t cookie = xcb_get_geometry(connect, xid); + xcb_generic_error_t **errStore = nullptr; + xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(connect, cookie, errStore); + if (reply) { + if (!errStore) // 正常获取窗口geometry则判定为good + ret = true; + + free(reply); + } + return ret; +} + +// TODO XCB下无_MOTIF_WM_HINTS属性 +MotifWMHints XCBUtils::getWindowMotifWMHints(XWindow xid) +{ + MotifWMHints ret; + + return ret; +} + +bool XCBUtils::hasXEmbedInfo(XWindow xid) +{ + //XCBAtom atom = getAtom("_XEMBED_INFO"); + + return false; +} + +XWindow XCBUtils::getWMTransientFor(XWindow xid) +{ + XWindow ret; + xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_transient_for(connect, xid); + if (!xcb_icccm_get_wm_transient_for_reply(connect, cookie, &ret, nullptr)) + std::cout << xid << " getWMTransientFor error" << std::endl; + + return ret; +} + +uint32_t XCBUtils::getWMUserTime(XWindow xid) +{ + uint32_t ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_user_time(&ewmh, xid); + if (!xcb_ewmh_get_wm_user_time_reply(&ewmh, cookie, &ret, nullptr)) + std::cout << xid << " getWMUserTime error" << std::endl; + + return ret; +} + +int XCBUtils::getWMUserTimeWindow(XWindow xid) +{ + XCBAtom ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_user_time_window(&ewmh, xid); + if (!xcb_ewmh_get_wm_user_time_window_reply(&ewmh, cookie, &ret, NULL)) + std::cout << xid << " getWMUserTimeWindow error" << std::endl; + + return ret; +} + +WMClass XCBUtils::getWMClass(XWindow xid) +{ + WMClass ret; + xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_class(connect, xid); + xcb_icccm_get_wm_class_reply_t reply; + if (!xcb_icccm_get_wm_class_reply(connect, cookie, &reply, nullptr)) { + if (reply.class_name) + ret.className.assign(reply.class_name); + + if (reply.instance_name) + ret.instanceName.assign(reply.instance_name); + + //xcb_icccm_get_wm_class_reply_wipe(&reply); + } else { + std::cout << xid << " getWMClass error" << std::endl; + } + + return ret; +} + +// TODO +void XCBUtils::minimizeWindow(XWindow xid) +{ + xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints(connect, xid); + xcb_icccm_wm_hints_t *hints = new xcb_icccm_wm_hints_t; // 分配堆空间 + xcb_icccm_get_wm_hints_reply(connect, cookie, hints, nullptr); + xcb_icccm_wm_hints_set_iconic(hints); + xcb_icccm_set_wm_hints(connect, xid, hints); + free(hints); +} + +void XCBUtils::maxmizeWindow(XWindow xid) +{ + xcb_ewmh_request_change_wm_state(&ewmh + , screenNum + , xid + , XCB_EWMH_WM_STATE_ADD + , getAtom("_NET_WM_STATE_MAXIMIZED_VERT") + , getAtom("_NET_WM_STATE_MAXIMIZED_HORZ") + , XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER); +} + +// TODO +std::vector XCBUtils::getWMCommand(XWindow xid) +{ + std::vector ret; + xcb_get_property_reply_t *reply = getPropertyValueReply(xid, XCB_ATOM_WM_COMMAND, ewmh.UTF8_STRING); + if (reply) { + ret = getUTF8StrsFromReply(reply); + free(reply); + } + + return ret; +} + +std::string XCBUtils::getUTF8StrFromReply(xcb_get_property_reply_t *reply) +{ + std::string ret; + if (!reply || reply->format != 8) + return ret; + + char data[12] = {0}; + for (uint32_t i=0; i < reply->value_len; i++) { + data[i] = char(reply->pad0[i]); + } + ret.assign(data); + return ret; +} + +std::vector XCBUtils::getUTF8StrsFromReply(xcb_get_property_reply_t *reply) +{ + std::vector ret; + if (!reply) + return ret; + + if (reply->format != 8) + return ret; + + + // 字符串拆分 + uint32_t start = 0; + for (uint32_t i=0; i < reply->value_len; i++) { + if (reply->pad0[i] == 0) { + char data[12] = {0}; + int count = 0; + for (uint32_t j=start; j < i; j++) + data[count++] = char(reply->pad0[j]); + + data[count] = 0; + ret.push_back(data); + } + } + + return ret; +} + +XWindow XCBUtils::getRootWindow() +{ + XWindow rootWindow = 0; + /* Get the first screen */ + xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connect)).data; + if (screen) + rootWindow = screen->root; + + std::cout << "getRootWinodw: " << rootWindow << std::endl; + return rootWindow; +} + +void XCBUtils::registerEvents(XWindow xid, uint32_t eventMask) +{ + uint32_t value[1] = {eventMask}; + xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(connect, + xid, + XCB_CW_EVENT_MASK, + &value); + xcb_flush(connect); + + xcb_generic_error_t *error = xcb_request_check(connect, cookie); + if (error != nullptr) { + std::cout << "window " << xid << "registerEvents error" << std::endl; + } +} + + +AtomCache::AtomCache() +{ +} + +XCBAtom AtomCache::getVal(std::string name) +{ + XCBAtom atom = ATOMNONE; + auto search = atoms.find(name); + if (search != atoms.end()) + atom = search->second; + + return atom; +} + +std::string AtomCache::getName(XCBAtom atom) +{ + std::string ret; + auto search = atomNames.find(atom); + if (search != atomNames.end()) + ret = search->second; + + return ret; +} + +void AtomCache::store(std::string name, XCBAtom value) +{ + atoms[name] = value; + atomNames[value] = name; +} diff --git a/src/lib/xcbutils.h b/src/lib/xcbutils.h new file mode 100644 index 0000000..0f781fd --- /dev/null +++ b/src/lib/xcbutils.h @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XCBUTILS_H +#define XCBUTILS_H + +#include +#include +#include + +#include +#include +#include +#include + +#define MAXLEN 0xffff +#define MAXALLOWEDACTIONLEN 256 +#define ATOMNONE 0 + +typedef xcb_window_t XWindow ; +typedef xcb_atom_t XCBAtom; +typedef xcb_destroy_notify_event_t DestroyEvent; +typedef xcb_map_notify_event_t MapEvent; +typedef xcb_configure_notify_event_t ConfigureEvent; +typedef xcb_property_notify_event_t PropertyEvent; +typedef xcb_event_mask_t EventMask; +typedef struct { + std::string instanceName; + std::string className; +} WMClass; + +typedef struct { + int16_t x, y; + uint16_t width, height; +} Geometry; + +typedef struct { + uint32_t flags; + uint32_t functions; + uint32_t decorations; + int32_t inputMode; + uint32_t status; +} MotifWMHints; + +typedef unsigned char BYTE; +typedef struct { + uint32_t width; /** Icon width */ + uint32_t height; /** Icon height */ + std::vector data; /** Rows, left to right and top to bottom of the CARDINAL ARGB */ +} WMIcon; + +// 缓存atom,减少X访问 TODO 加读写锁 +class AtomCache { +public: + AtomCache(); + + XCBAtom getVal(std::string name); + std::string getName(XCBAtom atom); + void store(std::string name, XCBAtom value); + +public: + std::map atoms; + std::map atomNames; +}; + +// XCB接口封装, 参考getCurrentWMDesktop +class XCBUtils +{ + XCBUtils(); + XCBUtils(const XCBUtils &other); + XCBUtils & operator= (const XCBUtils &other); + ~XCBUtils(); + +public: + static XCBUtils *instance() { + static XCBUtils instance; + return &instance; + } + + // test + xcb_connection_t *getConnect() {return connect;} + + /************************* xcb method ***************************/ + // 分配XID + XWindow allocId(); + + /************************* xpropto method ***************************/ + // 杀掉进程 + void killClientChecked(XWindow xid); + + // 获取属性reply, 返回值必须free + xcb_get_property_reply_t *getPropertyValueReply(XWindow xid, XCBAtom property, XCBAtom type = XCB_ATOM_ATOM); + + // 获取属性 + void *getPropertyValue(XWindow xid, XCBAtom property, XCBAtom type = XCB_ATOM_ATOM); + + // 获取字符串属性 + std::string getUTF8PropertyStr(XWindow xid, XCBAtom property); + + // 获取名称对应的Atom + XCBAtom getAtom(const char *name); + + // 获取Atom对应的名称 + std::string getAtomName(XCBAtom atom); + + // 获取窗口矩形 + Geometry getWindowGeometry(XWindow xid); + + // 判断当前窗口是否正常 + bool isGoodWindow(XWindow xid); + + // 获取窗口 + MotifWMHints getWindowMotifWMHints(XWindow xid); + + bool hasXEmbedInfo(XWindow xid); + + /************************* ewmh method ***************************/ + + // 获取活动窗口 _NET_ACTIVE_WINDOW + XWindow getActiveWindow(); + + // 设置活动窗口 _NET_ACTIVE_WINDOW + void setActiveWindow(XWindow xid); + + // 获取窗口列表 _NET_CLIENT_LIST + std::list getClientList(); + + // 获取窗口列表 _NET_CLIENT_LIST_STACKING + std::list getClientListStacking(); + + // 获取窗口状态 _NET_WM_STATE + /* + _NET_WM_STATE_MODAL, ATOM + _NET_WM_STATE_STICKY, ATOM + _NET_WM_STATE_MAXIMIZED_VERT, ATOM + _NET_WM_STATE_MAXIMIZED_HORZ, ATOM + _NET_WM_STATE_SHADED, ATOM + _NET_WM_STATE_SKIP_TASKBAR, ATOM + _NET_WM_STATE_SKIP_PAGER, ATOM + _NET_WM_STATE_HIDDEN, ATOM + _NET_WM_STATE_FULLSCREEN, ATOM + _NET_WM_STATE_ABOVE, ATOM + _NET_WM_STATE_BELOW, ATOM + _NET_WM_STATE_DEMANDS_ATTENTION, ATOM + */ + std::vector getWMState(XWindow xid); + + // 获取窗口类型 _NET_WM_WINDOW_TYPE + // Rationale: This hint is intended to replace the MOTIF hints. + // One of the objections to the MOTIF hints is that they are a purely visual description of the window decoration. + // By describing the function of the window, the Window Manager can apply consistent decoration and behavior to windows of the same type. + // Possible examples of behavior include keeping dock/panels on top or allowing pinnable menus / toolbars to only be hidden + // when another window has focus + /* + _NET_WM_WINDOW_TYPE_DESKTOP, ATOM + _NET_WM_WINDOW_TYPE_DOCK, ATOM + _NET_WM_WINDOW_TYPE_TOOLBAR, ATOM + _NET_WM_WINDOW_TYPE_MENU, ATOM + _NET_WM_WINDOW_TYPE_UTILITY, ATOM + _NET_WM_WINDOW_TYPE_SPLASH, ATOM + _NET_WM_WINDOW_TYPE_DIALOG, ATOM + _NET_WM_WINDOW_TYPE_DROPDOWN_MENU, ATOM + _NET_WM_WINDOW_TYPE_POPUP_MENU, ATOM + _NET_WM_WINDOW_TYPE_TOOLTIP, ATOM + _NET_WM_WINDOW_TYPE_NOTIFICATION, ATOM + _NET_WM_WINDOW_TYPE_COMBO, ATOM + _NET_WM_WINDOW_TYPE_DND, ATOM + _NET_WM_WINDOW_TYPE_NORMAL, ATOM + * */ + std::vector getWMWindoType(XWindow xid); + + // 获取窗口许可动作 _NET_WM_ALLOWED_ACTIONS + std::vector getWMAllowedActions(XWindow xid); + + // 设置窗口许可动作 + void setWMAllowedActions(XWindow xid, std::vector actions); + + // 获取窗口名称 _NET_WM_NAME + std::string getWMName(XWindow xid); + + // 获取窗口所属进程 _NET_WM_PID + uint32_t getWMPid(XWindow xid); + + // 获取窗口图标 _NET_WM_ICON_NAME + std::string getWMIconName(XWindow xid); + + // _NET_WM_ICON + std::vector getWMIcon(XWindow xid); + + // WM_CLIENT_LEADER + XWindow getWMClientLeader(XWindow xid); + + // 关闭窗口 _NET_CLOSE_WINDOW + void requestCloseWindow(XWindow xid, uint32_t timestamp); + + // 获取窗口对应桌面 _NET_WM_DESKTOP + uint32_t getWMDesktop(XWindow xid); + + // 设置窗口当前桌面 + void setWMDesktop(XWindow xid, uint32_t desktop); + + // 设置桌面 + void setCurrentWMDesktop(uint32_t desktop); + + // 获取当前桌面 _NET_CURRENT_DESKTOP + uint32_t getCurrentWMDesktop(); + + + /************************* icccm method ***************************/ + // The WM_TRANSIENT_FOR hint of the ICCCM allows clients to specify that a toplevel window may be closed before the client finishes. + // A typical example of a transient window is a dialog. + // Some dialogs can be open for a long time, while the user continues to work in the main window. + // Other dialogs have to be closed before the user can continue to work in the main window + XWindow getWMTransientFor(XWindow xid); + + uint32_t getWMUserTime(XWindow xid); + + int getWMUserTimeWindow(XWindow xid); + + // 获取窗口类型 + WMClass getWMClass(XWindow xid); + + // 最小化窗口 + void minimizeWindow(XWindow xid); + + // 最大化窗口 + void maxmizeWindow(XWindow xid); + + /************************* other method ***************************/ + // 获取窗口command + std::vector getWMCommand(XWindow xid); + + // 解析属性为UTF8格式字符串 + std::string getUTF8StrFromReply(xcb_get_property_reply_t *reply); + + // 解析属性为UTF8格式字符串字符数组 + std::vector getUTF8StrsFromReply(xcb_get_property_reply_t *reply); + + // 获取根窗口 + XWindow getRootWindow(); + + // 注册事件 + void registerEvents(XWindow xid, uint32_t eventMask); + + +private: + xcb_connection_t *connect; + int screenNum; + + xcb_ewmh_connection_t ewmh; + AtomCache atomCache; // 和ewmh中Atom类型存在重复部分,扩张了自定义类型 +}; + +#endif // XCBUTILS_H diff --git a/src/loader/CMakeLists.txt b/src/loader/CMakeLists.txt index 0f75ace..6cd983d 100644 --- a/src/loader/CMakeLists.txt +++ b/src/loader/CMakeLists.txt @@ -12,7 +12,6 @@ set(SRCS ../modules/methods/registe.hpp ../modules/util/common.cpp ../modules/util/common.h - ../modules/util/debug ../modules/util/filesystem.cpp ../modules/util/filesystem.h ../modules/util/json.h diff --git a/src/modules/apps/alrecorder.cpp b/src/modules/apps/alrecorder.cpp new file mode 100644 index 0000000..a50a0b1 --- /dev/null +++ b/src/modules/apps/alrecorder.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "alrecorder.h" +#include "dfwatcher.h" + +#include +#include +#include +#include +#include + +const QString userAppsCfgDir = QDir::homePath() + "/.config/deepin/dde-daemon/apps/"; + +AlRecorder::AlRecorder(DFWatcher *_watcher, QObject *parent) + : QObject (parent) + , watcher(_watcher) + , mutex(QMutex(QMutex::NonRecursive)) +{ + QDBusConnection con = QDBusConnection::sessionBus(); + if (!con.registerService("org.deepin.daemon.AlRecorder1")) + { + qWarning() << "register service AlRecorder1 error:" << con.lastError().message(); + return; + } + + if (!con.registerObject("/org/deepin/daemon/AlRecorder1", this, QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals)) + { + qWarning() << "register object AlRecorder1 error:" << con.lastError().message(); + return; + } + + connect(watcher, &DFWatcher::Event, this, &AlRecorder::onDFChanged, Qt::QueuedConnection); + Q_EMIT ServiceRestarted(); +} + +AlRecorder::~AlRecorder() +{ + QDBusConnection::sessionBus().unregisterObject("/org/deepin/daemon/AlRecorder1"); +} + +// 获取未启动应用列表 +QMap AlRecorder::GetNew() +{ + QMap ret; + QMutexLocker locker(&mutex); + for (auto is = subRecoders.begin(); is != subRecoders.end(); is++) { + QStringList apps; + for (auto il = is.value().launchedMap.begin(); il != is.value().launchedMap.end(); il++) { + if (!il.value()) // 未启动应用 + apps.push_back(il.key()); + } + + if (apps.size() > 0) + ret[is.key()] = apps; + } + + return ret; +} + +// 标记应用已启动状态 +void AlRecorder::MarkLaunched(const QString &filePath) +{ + if (!filePath.endsWith(".desktop")) + return; + + QFileInfo info; + QMutexLocker locker(&mutex); + for (auto sri = subRecoders.begin(); sri != subRecoders.end(); sri++) { + if (!filePath.contains(sri.key())) + continue; + + info.setFile(filePath); + QString name = info.baseName(); + for (auto li = sri.value().launchedMap.begin(); li != sri.value().launchedMap.end(); li++) { + if (li.key() == name && !li.value()) { + li.value() = true; + goto end; + } + } + } + + // 根据filePath匹配到唯一应用 + end: + if (info.isDir()) { + saveStatusFile(info.absolutePath() + "/"); + Q_EMIT Launched(filePath); + } +} + +// 记录Launcher服务卸载应用信息, 终端卸载不会调用该函数, desktopFiles为绝对路径 +void AlRecorder::UninstallHints(const QStringList &desktopFiles) +{ + QMutexLocker locker(&mutex); + for (auto desktop : desktopFiles) { + for (auto sri = subRecoders.begin(); sri != subRecoders.end(); sri++) { + if (!desktop.contains(sri.key())) + continue; + + QFileInfo info(desktop); + sri.value().uninstallMap[info.baseName()] = true; + } + } +} + +// 监控目录 +void AlRecorder::WatchDirs(const QStringList &dataDirs) +{ + for (auto dirPath : dataDirs) { + if (subRecoders.contains(dirPath)) + continue; + + QDir dir(dirPath); + QStringList files = dir.entryList(QDir::Files); + for (auto &file : files) + file = dirPath + file; + + // 监听目录和文件 + watcher->addDir(dirPath); + if (files.size() > 0) + watcher->addPaths(files); + + // 初始化对应目录和应用信息 + initSubRecoder(dirPath); + } +} + +// 初始化应用目录记录 +void AlRecorder::initSubRecoder(const QString &dirPath) +{ + subRecorder sub; + QByteArray encryText = QCryptographicHash::hash(dirPath.toLatin1(), QCryptographicHash::Md5); + QString statusFile = userAppsCfgDir + "launched-" + encryText.toHex() + ".csv"; + + // 读取App状态记录 + QMap launchedApp; + QFile file(statusFile); + if (file.open(QIODevice::ReadWrite | QIODevice::Text)) { + while (!file.atEnd()){ + QString line(file.readLine()); + QStringList strs = line.split(","); + if (strs.length() != 2) + continue; + + if (strs[1].size() > 0 && strs[1][0] == 't') + launchedApp[strs[0]] = true; + else + launchedApp[strs[0]] = false; + } + file.close(); + } else { + // 读取app desktop + QDir dir(dirPath); + QStringList files = dir.entryList(QDir::Files); + QStringList apps; + for (QString file : files) { + if (!file.endsWith(".desktop")) + continue; + + int index = file.lastIndexOf("."); + file.truncate(index); + qInfo() << "entry =" << file; + apps.push_back(file); + } + + // fallback 都打开过 + for (auto app : apps) + launchedApp[app] = true; + } + + sub.statusFile = statusFile; + sub.launchedMap = launchedApp; + subRecoders[dirPath] = sub; +} + +void AlRecorder::onDFChanged(const QString &filePath, uint32_t op) +{ + QFileInfo info(filePath); + QString dirPath = info.absolutePath() + "/"; + QString name = info.baseName(); + subRecorder &sub = subRecoders[dirPath]; + QMap &launchedMap = sub.launchedMap; + + // 过滤文件, 仅保留.desktop类型 + if (!filePath.endsWith(".desktop")) + return; + + switch (op) { + case DFWatcher::event::Add: + qInfo() << "AlRecorder: Add " << filePath; + if (!launchedMap.contains(name)) { + bool launched = false; + if (sub.removedLaunchedMap.find(name) != sub.removedLaunchedMap.end()) { + launched = sub.removedLaunchedMap[name]; + sub.removedLaunchedMap.remove(name); + } + launchedMap[name] = launched; + } + sub.uninstallMap.remove(name); + saveStatusFile(dirPath); // 刷新状态文件 + break; + case DFWatcher::event::Del: + qInfo() << "AlRecorder: Del" << filePath; + if (launchedMap.contains(name)) { + if (!sub.uninstallMap.contains(name)) + sub.removedLaunchedMap[name] = launchedMap[name]; + + launchedMap.remove(name); + } + saveStatusFile(dirPath); //刷新状态文件 + break; + case DFWatcher::event::Mod: + break; + } +} + +void AlRecorder::saveStatusFile(const QString &dirPath) +{ + subRecorder sub = subRecoders[dirPath]; + QString tmpFile = sub.statusFile + "_tmp"; + QFile fp(tmpFile); + bool ok = false; + qInfo() << "saveStatusFile=" << dirPath << "create file=" << tmpFile; + if (fp.open(QIODevice::ReadWrite | QIODevice::Text)) { + QTextStream out(&fp); + out << "# " << dirPath << endl; + for (auto rl = sub.launchedMap.begin(); rl != sub.launchedMap.end(); rl++) { + out << rl.key() << "," << ((rl.value() == true) ? "t" : "f") << endl; + } + ok = true; + fp.close(); + } + + // 覆盖原文件 + QFile::remove(sub.statusFile); + QFile::rename(tmpFile, sub.statusFile); + Q_EMIT StatusSaved(dirPath, sub.statusFile, ok); +} + diff --git a/src/modules/apps/alrecorder.h b/src/modules/apps/alrecorder.h new file mode 100644 index 0000000..e56c31c --- /dev/null +++ b/src/modules/apps/alrecorder.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ALRECORDER_H +#define ALRECORDER_H + +#include +#include +#include + +class DFWatcher; + +// 记录应用状态信息 +class AlRecorder: public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.deepin.daemon.AlRecorder1") + +public: + struct subRecorder { + QString statusFile; // 应用目录状态文件 + QMap launchedMap; // 应用启动记录 + QMap removedLaunchedMap; // desktop文件卸载记录 + QMap uninstallMap; // 记录应用将被卸载状态 + }; + + AlRecorder(DFWatcher *_watcher, QObject *parent = nullptr); + ~AlRecorder(); + +Q_SIGNALS: + void Launched(const QString &file); + void StatusSaved(const QString &root, const QString &file, bool ok); + void ServiceRestarted(); + +private Q_SLOTS: + void onDFChanged(const QString &filePath, uint32_t op); + +public Q_SLOTS: + QMap GetNew(); + void MarkLaunched(const QString &filePath); + void UninstallHints(const QStringList &desktopFiles); + void WatchDirs(const QStringList &dataDirs); + +private: + void initSubRecoder(const QString &dirPath); + void saveStatusFile(const QString &dirPath); + + QMap subRecoders; // 记录不同应用目录的文件状态 + DFWatcher *watcher; + QMutex mutex; +}; + +#endif // ALRECODER_H diff --git a/src/modules/apps/appmanager.cpp b/src/modules/apps/appmanager.cpp new file mode 100644 index 0000000..0972b06 --- /dev/null +++ b/src/modules/apps/appmanager.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "appmanager.h" +#include "dfwatcher.h" +#include "alrecorder.h" +#include "basedir.h" + +#include +#include + +AppManager::AppManager(QObject *parent) + : QObject(parent) + , watcher(new DFWatcher(this)) + , recorder(new AlRecorder(watcher, this)) +{ + QStringList dataDirs; + dataDirs << BaseDir::userAppDir().c_str(); + for (auto &dir : BaseDir::sysAppDirs()) + dataDirs << dir.c_str(); + + recorder->WatchDirs(dataDirs); // 监控应用desktop +} + +AppManager::~AppManager() +{ + +} diff --git a/src/modules/apps/appmanager.h b/src/modules/apps/appmanager.h new file mode 100644 index 0000000..1402995 --- /dev/null +++ b/src/modules/apps/appmanager.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef APPMANAGER_H +#define APPMANAGER_H + +#include + +class DFWatcher; +class AlRecorder; +class AppManager: public QObject +{ + Q_OBJECT +public: + explicit AppManager(QObject *parent = nullptr); + ~AppManager(); + +private: + DFWatcher *watcher; + AlRecorder *recorder; +}; + +#endif // APPMANAGER_H diff --git a/src/modules/apps/dfwatcher.cpp b/src/modules/apps/dfwatcher.cpp new file mode 100644 index 0000000..ed5cba1 --- /dev/null +++ b/src/modules/apps/dfwatcher.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dfwatcher.h" + +#include +#include +#include +#include + +const QString dfSuffix = ".desktop"; +const QString configSuffix = ".json"; + + DFWatcher::DFWatcher(QObject *parent) + : QObject (parent) + , watcher(new QFileSystemWatcher(this)) + { + QDBusConnection con = QDBusConnection::sessionBus(); + if (!con.registerService("org.deepin.daemon.DFWatcher1")) + { + qInfo() << "register service app1 error:" << con.lastError().message(); + return; + } + + if (!con.registerObject("/org/deepin/daemon/DFWatcher1", this, QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals)) + { + qInfo() << "register object DFWatcher error:" << con.lastError().message(); + return; + } + + connect(watcher, &QFileSystemWatcher::fileChanged, this, &DFWatcher::fileUpdated, Qt::QueuedConnection); + connect(watcher, &QFileSystemWatcher::directoryChanged, this, &DFWatcher::directoryUpdated, Qt::QueuedConnection); + } + + DFWatcher::~DFWatcher() + { + QDBusConnection::sessionBus().unregisterObject("/org/deepin/daemon/DFWatcher1"); + } + + void DFWatcher::addDir(const QString &path) + { + // 记录当前目录内容 + qInfo() << "addDir :" << path; + const QDir dir(path); + dirContentMap[path] = dir.entryList(QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Files, QDir::DirsFirst); + + watcher->addPath(path); + } + + void DFWatcher::addPaths(const QStringList &paths) + { + watcher->addPaths(paths); + } + + QStringList DFWatcher::files() + { + return watcher->files(); + } + + void DFWatcher::removePath(const QString &filepath) + { + watcher->removePath(filepath); + } + + void DFWatcher::fileUpdated(const QString &filePath) + { + qInfo() << "event: modify filepath=" << filePath; + if (filePath.endsWith(dfSuffix) || filePath.endsWith(configSuffix)) + Q_EMIT Event(filePath, int(event::Mod)); + } + + void DFWatcher::directoryUpdated(const QString &dirPath) + { + QStringList recoderedContent = dirContentMap[dirPath]; + + const QDir dir(dirPath); + QStringList newEntries = dir.entryList(QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Files, QDir::DirsFirst); + + QSet newDirSet = QSet::fromList(newEntries); + QSet currentDirSet = QSet::fromList(recoderedContent); + + // 添加的文件 + QSet newFiles = newDirSet - currentDirSet; + QStringList newFile = newFiles.toList(); + + // 移除的文件 + QSet deletedFiles = currentDirSet - newDirSet; + QStringList deleteFile = deletedFiles.toList(); + + // 更新目录记录 + dirContentMap[dirPath] = newEntries; + + // 新增文件 + if (newFile.size() > 0) { + for (auto &file : newFile) { + //qInfo() << "event: add filepath=" << file; + if (file.endsWith(dfSuffix)) { + Q_EMIT Event(dirPath + file, event::Add); + } + } + } + + // 移除文件 + if (deleteFile.size() > 0) { + for (auto &file : deleteFile) { + //qInfo() << "event: del filepath=" << file; + if (file.endsWith(dfSuffix)) { + Q_EMIT Event(dirPath + file, event::Del); + } + } + } + } + + diff --git a/src/modules/apps/dfwatcher.h b/src/modules/apps/dfwatcher.h new file mode 100644 index 0000000..23c9022 --- /dev/null +++ b/src/modules/apps/dfwatcher.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DFWATCHER_H +#define DFWATCHER_H + +#include +#include +#include + +class DFWatcher: public QObject { + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.deepin.daemon.DFWatcher1") + +public: + enum event{ + Add, + Del, + Mod, + }; + + explicit DFWatcher(QObject *parent = nullptr); + ~DFWatcher(); + + void addDir(const QString & path); + void addPaths(const QStringList &paths); + QStringList files(); + void removePath(const QString &filepath); +Q_SIGNALS: + void Event(const QString &filepath, int op); + +private Q_SLOTS: + void fileUpdated(const QString &filePath); + void directoryUpdated(const QString &dirPath); + +private: + QFileSystemWatcher *watcher; + QMap dirContentMap; // 监控的目录内容列表 +}; + +#endif diff --git a/src/modules/dock/appinfo.cpp b/src/modules/dock/appinfo.cpp new file mode 100644 index 0000000..fa9f24b --- /dev/null +++ b/src/modules/dock/appinfo.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "appinfo.h" +#include "common.h" + +#include +#include +#include + +AppInfo::AppInfo(DesktopInfo &info) + : isValid(true) +{ + init(info); +} + +AppInfo::AppInfo(const QString &_fileName) + : isValid(true) +{ + DesktopInfo info(_fileName.toStdString()); + init(info); +} + +void AppInfo::init(DesktopInfo &info) +{ + if (!info.isValidDesktop()) { + isValid = false; + return; + } + + std::string xDeepinVendor= info.kf.getStr(MainSection, "X-Deepin-Vendor"); + if (xDeepinVendor == "deepin") { + name = info.getGenericName().c_str(); + if (name.isEmpty()) + name = info.getName().c_str(); + } else { + name = info.getName().c_str(); + } + + innerId = genInnerIdWithDesktopInfo(info); + fileName = info.getFileName().c_str(); + id = info.getId().c_str(); + icon = info.getIcon().c_str(); + installed = info.isInstalled(); + for (const auto & action : info.getActions()) { + actions.push_back(action); + } +} + +QString AppInfo::genInnerIdWithDesktopInfo(DesktopInfo &info) +{ + std::string cmdline = info.getCommandLine(); + QByteArray encryText = QCryptographicHash::hash(QString(cmdline.c_str()).toLatin1(), QCryptographicHash::Md5); + QString innerId = desktopHashPrefix + encryText.toHex(); + qInfo() << "app " << info.getId().c_str() << " generate innerId :" << innerId; + return innerId; +} diff --git a/src/modules/dock/appinfo.h b/src/modules/dock/appinfo.h new file mode 100644 index 0000000..93ca763 --- /dev/null +++ b/src/modules/dock/appinfo.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef APPINFO_H +#define APPINFO_H + +#include "desktopinfo.h" + +#include + +// 应用信息类 +class AppInfo +{ +public: + explicit AppInfo(DesktopInfo &info); + explicit AppInfo(const QString &_fileName); + + void init(DesktopInfo &info); + QString getFileName() {return fileName;} + QString getIcon() {return icon;} + QString getId() {return id;} + QString getInnerId() {return innerId;} + QString getName() {return name;} + QVector getActions() {return actions;} + QString getIdentifyMethod() {return identifyMethod;} + void setIdentifyMethod(QString method) {identifyMethod = method;} + bool isInstalled() {return installed;} + bool isValidApp() {return isValid;} + +private: + QString genInnerIdWithDesktopInfo(DesktopInfo &info); + + QString fileName; + QString id; + QString icon; + QString identifyMethod; + QString innerId; + QString name; + QVector actions; + bool installed; + bool isValid; +}; + +#endif // APPINFO_H diff --git a/src/modules/dock/appmenu.cpp b/src/modules/dock/appmenu.cpp new file mode 100644 index 0000000..87903f3 --- /dev/null +++ b/src/modules/dock/appmenu.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "appmenu.h" + +#include +#include + +AppMenu::AppMenu() + : checkableMenu(false) + , singleCheck(false) + , itemcount(0) + , dirty(false) +{ + +} + +// 增加菜单选项 +void AppMenu::appendItem(AppMenuItem item) +{ + if (!item.text.isEmpty()) { + item.id = allocateId(); + items.push_back(item); + } +} + +void AppMenu::handleAction(uint32_t timestamp, QString itemId) +{ + for (auto &item : items) { + if (item.id == itemId) { + item.action(timestamp); + break; + } + } +} + +void AppMenu::setDirtyStatus(bool isDirty) +{ + dirty = isDirty; +} + +QString AppMenu::getMenuJsonStr() +{ + QJsonObject obj; + QJsonArray array; + for (auto item : items) { + QJsonObject objItem; + objItem["itemId"] = item.id; + objItem["itemText"] = item.text; + objItem["isActive"] = item.isActive; + objItem["isCheckable"] = item.isCheckable; + objItem["checked"] = item.checked; + objItem["itemIcon"] = item.icon; + objItem["itemIconHover"] = item.iconHover; + objItem["itemIconInactive"] = item.iconInactive; + objItem["showCheckMark"] = item.showCheckMark; + objItem["itemSubMenu"] = item.subMenu ? item.subMenu->getMenuJsonStr() : ""; + array.push_back(QJsonValue(objItem)); + } + obj["items"] = QJsonValue(array); + obj["checkableMenu"] = checkableMenu; + obj["singleCheck"] = singleCheck; + + QString ret = QJsonDocument(obj).toJson(); + return ret; +} + +QString AppMenu::allocateId() +{ + return QString::number(itemcount++); +} + + diff --git a/src/modules/dock/appmenu.h b/src/modules/dock/appmenu.h new file mode 100644 index 0000000..7ae608f --- /dev/null +++ b/src/modules/dock/appmenu.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef APPMENU_H +#define APPMENU_H + +#include +#include +#include + +#include +#include +#include + +typedef std::function AppMenuAction; + +class AppMenu; + +// 应用菜单选项 +struct AppMenuItem { + QString id; + QString text; + bool isActive; + QString isCheckable; + QString checked; + QString icon; + QString iconHover; + QString iconInactive; + QString showCheckMark; + std::shared_ptr subMenu; + + int hint; + AppMenuAction action; +}; + + +// 应用菜单类 +class AppMenu +{ +public: + AppMenu(); + + void appendItem(AppMenuItem item); + void handleAction(uint32_t timestamp, QString itemId); + void setDirtyStatus(bool isDirty); + QString getMenuJsonStr(); + +private: + QString allocateId(); + + QVector items; // json:"items" + bool checkableMenu; // json:"checkableMenu" + bool singleCheck; // json:"singleCheck" + + int itemcount; + bool dirty; +}; + +#endif // APPMENU_H diff --git a/src/modules/dock/common.h b/src/modules/dock/common.h new file mode 100644 index 0000000..0104df7 --- /dev/null +++ b/src/modules/dock/common.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef COMMON_H +#define COMMON_H + +#include +#include +#include + +const QString configDock = "com.deepin.dde.dock"; +const QString configAppearance = "com.deepin.dde.appearance"; +const QString keyHideMode = "Hide_Mode"; +const QString keyDisplayMode = "Display_Mode"; +const QString keyPosition = "Position"; +const QString keyIconSize = "Icon_Size"; +const QString keyDockedApps = "Docked_Apps"; +const QString keyShowTimeout = "Show_Timeout"; +const QString keyHideTimeout = "Hide_Timeout"; +const QString keyWindowSizeFashion = "Window_Size_Fashion"; +const QString keyWindowSizeEfficient = "Window_Size_Efficient"; +const QString keyWinIconPreferredApps = "Win_Icon_Preferred_Apps"; +const QString keyOpacity = "Opacity"; +const QString keyPluginSettings = "Plugin_Settings"; +const QString keyForceQuitApp = "Force_Quit_App"; + +const QString scratchDir = QDir::homePath() + "/.local/dock/scratch/"; +const QMap pathDirCodeMap { + {"/usr/share/applications/", "/S@"}, + {"/usr/local/share/applications/", "/L@"}, + {QDir::homePath() + "/.local/share/applications", "/H@"}, + {QDir::homePath() + "/.local/dock/scratch", "/D@"}, +}; + +const QMap pathCodeDirMap { + {"/S@", "/usr/share/applications/"}, + {"/L@", "/usr/local/share/applications/"}, + {"/H@", QDir::homePath() + "/.local/share/applications"}, + {"/D@", QDir::homePath() + "/.local/dock/scratch"}, +}; + +// DBus服务、路径 +const QString dbusService = "org.deepin.dde.daemon.Dock1"; +const QString dbusPath = "/org/deepin/dde/daemon/Dock1"; +const QString dbusInterface = dbusService; + +const QString windowPatternsFile = "/usr/share/dde/data/window_patterns.json"; +const QString desktopHashPrefix = "d:"; +const QString windowHashPrefix = "w:"; + +const QString entryDBusObjPathPrefix = dbusPath + "/entries/"; +const QString entryDBusInterface = dbusInterface + ".Entry"; + +// 驻留应用desktop file模板 +const QString dockedItemTemplate = R"([Desktop Entry] +Name=%1 +Exec=%2 +Icon=%3 +Type=Application +Terminal=false +StartupNotify=false +)"; + +const QString frontendWindowWmClass = "dde-dock"; +const int configureNotifyDelay = 100; +const int smartHideTimerDelay = 400; + +const int bestIconSize = 48; +const int menuItemHintShowAllWindows = 1; + +const int MotifHintFunctions = 1; +const int MotifHintDecorations = 2; +const int MotifHintInputMode = 4; +const int MotifHintStatus = 8; + +const int MotifFunctionNone = 0; +const int MotifFunctionAll = 1; +const int MotifFunctionResize = 2; +const int MotifFunctionMove = 4; +const int MotifFunctionMinimize = 8; +const int MotifFunctionMaximize = 16; +const int MotifFunctionClose = 32; + +const QString ddeLauncherWMClass = "dde-launcher"; +#endif // COMMON_H diff --git a/src/modules/dock/dbusadaptordock.cpp b/src/modules/dock/dbusadaptordock.cpp new file mode 100644 index 0000000..a3b94d2 --- /dev/null +++ b/src/modules/dock/dbusadaptordock.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dbusadaptordock.h" + +DBusAdaptorDock::DBusAdaptorDock(QObject *parent) + : QDBusAbstractAdaptor(parent) +{ + // constructor + setAutoRelaySignals(true); + + Dock *dock = static_cast(QObject::parent()); + if (dock) { + connect(dock, &Dock::serviceRestarted, this, [&] { + Q_EMIT ServiceRestarted();}); + connect(dock, &Dock::entryAdded, this, [&](QString entryObjPath, int32_t index){ + Q_EMIT EntryAdded(QDBusObjectPath(entryObjPath), index);}); + connect(dock, &Dock::entryRemoved, this, &DBusAdaptorDock::EntryRemoved); + connect(dock, &Dock::hideStateChanged, this, &DBusAdaptorDock::HideStateChanged); + connect(dock, &Dock::frontendWindowRectChanged, this, &DBusAdaptorDock::FrontendWindowRectChanged); + } +} + +DBusAdaptorDock::~DBusAdaptorDock() +{ + // destructor +} + +int DBusAdaptorDock::displayMode() const +{ + return parent()->getDisplayMode(); +} + +void DBusAdaptorDock::setDisplayMode(int value) +{ + if (displayMode() != value) { + parent()->setDisplayMode(value); + Q_EMIT DisplayModeChanged(); + } +} + +QStringList DBusAdaptorDock::dockedApps() const +{ + return parent()->getDockedApps(); +} + +QList DBusAdaptorDock::entries() const +{ + QList ret; + for (auto path : parent()->getEntryPaths()) + ret.push_back(QDBusObjectPath(path)); + return ret; +} + +int DBusAdaptorDock::hideMode() const +{ + return int(parent()->getHideMode()); +} + +void DBusAdaptorDock::setHideMode(int value) +{ + if (hideMode() != value) { + parent()->setHideMode(HideMode(value)); + Q_EMIT HideModeChanged(); + } +} + +int DBusAdaptorDock::hideState() const +{ + return int(parent()->getHideState()); +} + +uint DBusAdaptorDock::hideTimeout() const +{ + return parent()->getHideTimeout(); +} + +void DBusAdaptorDock::setHideTimeout(uint value) +{ + if (hideTimeout() != value) { + parent()->setHideTimeout(value); + Q_EMIT HideTimeoutChanged(); + } +} + +uint DBusAdaptorDock::windowSizeEfficient() const +{ + return parent()->getWindowSizeEfficient(); +} + +void DBusAdaptorDock::setWindowSizeEfficient(uint value) +{ + if (windowSizeEfficient() != value) { + parent()->setWindowSizeEfficient(value); + Q_EMIT WindowSizeEfficientChanged(); + } +} + +uint DBusAdaptorDock::windowSizeFashion() const +{ + return parent()->getWindowSizeFashion(); +} + +void DBusAdaptorDock::setWindowSizeFashion(uint value) +{ + if (windowSizeFashion() != value) { + parent()->setWindowSizeFashion(value); + Q_EMIT WindowSizeFashionChanged(); + } +} + +QRect DBusAdaptorDock::frontendWindowRect() const +{ + return parent()->getFrontendWindowRect(); +} + +double DBusAdaptorDock::opacity() const +{ + return parent()->getOpacity(); +} + +uint DBusAdaptorDock::iconSize() const +{ + return parent()->getIconSize(); +} + +void DBusAdaptorDock::setIconSize(uint value) +{ + if (iconSize() != value) { + parent()->setIconSize(value); + Q_EMIT IconSizeChanged(); + } +} + +int DBusAdaptorDock::position() const +{ + return parent()->getPosition(); +} + +void DBusAdaptorDock::setPosition(int value) +{ + if (position() != value) { + parent()->setPosition(value); + Q_EMIT PositionChanged(); + } +} + +uint DBusAdaptorDock::showTimeout() const +{ + return parent()->getShowTimeout(); +} + +void DBusAdaptorDock::setShowTimeout(uint value) +{ + if (showTimeout() != value) { + parent()->setShowTimeout(value); + Q_EMIT ShowTimeoutChanged(); + } +} + +Dock *DBusAdaptorDock::parent() const +{ + return static_cast(QObject::parent()); +} + +void DBusAdaptorDock::CloseWindow(uint win) +{ + parent()->closeWindow(win); +} + +// for debug +QStringList DBusAdaptorDock::GetEntryIDs() +{ + return parent()->getEntryIDs(); +} + +bool DBusAdaptorDock::IsDocked(const QString &desktopFile) +{ + return parent()->isDocked(desktopFile); +} + +bool DBusAdaptorDock::IsOnDock(const QString &desktopFile) +{ + return parent()->isOnDock(desktopFile); +} + +void DBusAdaptorDock::MoveEntry(int index, int newIndex) +{ + parent()->moveEntry(index, newIndex); +} + +QString DBusAdaptorDock::QueryWindowIdentifyMethod(uint win) +{ + return parent()->queryWindowIdentifyMethod(win); +} + +bool DBusAdaptorDock::RequestDock(const QString &desktopFile, int index) +{ + return parent()->requestDock(desktopFile, index); +} + +bool DBusAdaptorDock::RequestUndock(const QString &desktopFile) +{ + return parent()->requestUndock(desktopFile); +} + +void DBusAdaptorDock::SetFrontendWindowRect(int x, int y, uint width, uint height) +{ + parent()->setFrontendWindowRect(x, y, width, height); +} + diff --git a/src/modules/dock/dbusadaptordock.h b/src/modules/dock/dbusadaptordock.h new file mode 100644 index 0000000..7315503 --- /dev/null +++ b/src/modules/dock/dbusadaptordock.h @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DBUSADAPTORDOCK_H +#define DBUSADAPTORDOCK_H + +#include "dock.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Adaptor class for interface org.deepin.dde.daemon.Dock1 + */ +class DBusAdaptorDock: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.deepin.dde.daemon.Dock1") + Q_CLASSINFO("D-Bus Introspection", "" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" + "") +public: + DBusAdaptorDock(QObject *parent); + virtual ~DBusAdaptorDock(); + +public: // PROPERTIES + Q_PROPERTY(int DisplayMode READ displayMode WRITE setDisplayMode NOTIFY DisplayModeChanged) + int displayMode() const; + void setDisplayMode(int value); + + Q_PROPERTY(QStringList DockedApps READ dockedApps NOTIFY DockedAppsChanged) + QStringList dockedApps() const; + + Q_PROPERTY(QList Entries READ entries NOTIFY EntriesChanged) + QList entries() const; + + Q_PROPERTY(int HideMode READ hideMode WRITE setHideMode NOTIFY HideModeChanged) + int hideMode() const; + void setHideMode(int value); + + Q_PROPERTY(int HideState READ hideState NOTIFY HideStateChanged) + int hideState() const; + + Q_PROPERTY(uint HideTimeout READ hideTimeout WRITE setHideTimeout NOTIFY HideTimeoutChanged) + uint hideTimeout() const; + void setHideTimeout(uint value); + + Q_PROPERTY(uint WindowSizeEfficient READ windowSizeEfficient WRITE setWindowSizeEfficient NOTIFY WindowSizeEfficientChanged) + uint windowSizeEfficient() const; + void setWindowSizeEfficient(uint value); + + Q_PROPERTY(uint WindowSizeFashion READ windowSizeFashion WRITE setWindowSizeFashion NOTIFY WindowSizeFashionChanged) + uint windowSizeFashion() const; + void setWindowSizeFashion(uint value); + + Q_PROPERTY(QRect FrontendWindowRect READ frontendWindowRect NOTIFY FrontendWindowRectChanged) + QRect frontendWindowRect() const; + + Q_PROPERTY(double Opacity READ opacity NOTIFY OpacityChanged) + double opacity() const; + + Q_PROPERTY(uint IconSize READ iconSize WRITE setIconSize NOTIFY IconSizeChanged) + uint iconSize() const; + void setIconSize(uint value); + + Q_PROPERTY(int Position READ position WRITE setPosition NOTIFY PositionChanged) + int position() const; + void setPosition(int value); + + Q_PROPERTY(uint ShowTimeout READ showTimeout WRITE setShowTimeout NOTIFY ShowTimeoutChanged) + uint showTimeout() const; + void setShowTimeout(uint value); + + Dock *parent() const; + +public Q_SLOTS: // METHODS + void CloseWindow(uint win); + QStringList GetEntryIDs(); + bool IsDocked(const QString &desktopFile); + bool IsOnDock(const QString &desktopFile); + void MoveEntry(int index, int newIndex); + QString QueryWindowIdentifyMethod(uint win); + bool RequestDock(const QString &desktopFile, int index); + bool RequestUndock(const QString &desktopFile); + void SetFrontendWindowRect(int x, int y, uint width, uint height); + +Q_SIGNALS: // SIGNALS + void ServiceRestarted(); + void EntryAdded(const QDBusObjectPath &path, int index); + void EntryRemoved(const QString &entryId); + + void DisplayModeChanged(); + void DockedAppsChanged(); + void OpacityChanged(); + void EntriesChanged(); + void HideModeChanged(); + void WindowSizeEfficientChanged(); + void WindowSizeFashionChanged(); + void HideStateChanged(); + void FrontendWindowRectChanged(); + void HideTimeoutChanged(); + void IconSizeChanged(); + void PositionChanged(); + void ShowTimeoutChanged(); +}; + +#endif diff --git a/src/modules/dock/dbusadaptorentry.cpp b/src/modules/dock/dbusadaptorentry.cpp new file mode 100644 index 0000000..0f11d57 --- /dev/null +++ b/src/modules/dock/dbusadaptorentry.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dbusadaptorentry.h" + +DBusAdaptorEntry::DBusAdaptorEntry(QObject *parent) + : QDBusAbstractAdaptor(parent) +{ + + // constructor + setAutoRelaySignals(true); + //qDBusRegisterMetaType(); + + Entry *entry = static_cast(QObject::parent()); + if (entry) { + connect(entry, &Entry::isActiveChanged, this, &DBusAdaptorEntry::IsActiveChanged); + connect(entry, &Entry::isDockedChanged, this, &DBusAdaptorEntry::IsDockedChanged); + connect(entry, &Entry::menuChanged, this, &DBusAdaptorEntry::MenuChanged); + connect(entry, &Entry::iconChanged, this, &DBusAdaptorEntry::IconChanged); + connect(entry, &Entry::nameChanged, this, &DBusAdaptorEntry::NameChanged); + connect(entry, &Entry::desktopFileChanged, this, &DBusAdaptorEntry::DesktopFileChanged); + connect(entry, &Entry::currentWindowChanged, this, &DBusAdaptorEntry::CurrentWindowChanged); + } +} + +DBusAdaptorEntry::~DBusAdaptorEntry() +{ + // destructor +} + +uint DBusAdaptorEntry::currentWindow() const +{ + return parent()->getCurrentWindow(); +} + +QString DBusAdaptorEntry::desktopFile() const +{ + return parent()->getDesktopFile(); +} + +QString DBusAdaptorEntry::icon() const +{ + return parent()->getIcon(); +} + +QString DBusAdaptorEntry::id() const +{ + return parent()->getId(); +} + +bool DBusAdaptorEntry::isActive() const +{ + return parent()->getIsActive(); +} + +bool DBusAdaptorEntry::isDocked() const +{ + return parent()->getIsDocked(); +} + +QString DBusAdaptorEntry::menu() const +{ + return parent()->getMenu(); +} + +QString DBusAdaptorEntry::name() const +{ + return parent()->getName(); +} + +/* +QList DBusAdaptorEntry::windowInfos() +{ + return parent()->getExportWindowInfos(); +} +*/ +Entry *DBusAdaptorEntry::parent() const +{ + return static_cast(QObject::parent()); +} + +void DBusAdaptorEntry::Activate(uint timestamp) +{ + parent()->active(timestamp); +} + +void DBusAdaptorEntry::Check() +{ + parent()->check(); +} + +void DBusAdaptorEntry::ForceQuit() +{ + parent()->forceQuit(); +} + +QList DBusAdaptorEntry::GetAllowedCloseWindows() +{ + auto ids = parent()->getAllowedClosedWindowIds(); + QList ret; + for (auto id : ids) + ret.push_back(id); + + return ret; +} + +void DBusAdaptorEntry::HandleDragDrop(uint timestamp, const QStringList &files) +{ + parent()->handleDragDrop(timestamp, files); +} + +void DBusAdaptorEntry::HandleMenuItem(uint timestamp, const QString &id) +{ + parent()->handleMenuItem(timestamp, id); +} + +void DBusAdaptorEntry::NewInstance(uint timestamp) +{ + parent()->newInstance(timestamp); +} + +void DBusAdaptorEntry::PresentWindows() +{ + parent()->presentWindows(); +} + +void DBusAdaptorEntry::RequestDock() +{ + parent()->requestDock(); +} + +void DBusAdaptorEntry::RequestUndock() +{ + parent()->requestUndock(); +} + + +QDBusArgument &operator <<(QDBusArgument &argument, const ExportWindowInfo &info) +{ + argument.beginStructure(); + argument << info.xid << info.title << info.flash; + argument.endStructure(); + return argument; +} + +const QDBusArgument &operator >>(const QDBusArgument &argument, ExportWindowInfo &info) +{ + argument.beginStructure(); + argument >> info.xid >> info.title >> info.flash; + argument.endStructure(); + return argument; +} + +QDebug operator<<(QDebug deg, const ExportWindowInfo &info) +{ + qDebug() << "xid: " << info.xid << " title:" << info.title << " flash:" << info.flash; + + return deg; +} diff --git a/src/modules/dock/dbusadaptorentry.h b/src/modules/dock/dbusadaptorentry.h new file mode 100644 index 0000000..d96f3a8 --- /dev/null +++ b/src/modules/dock/dbusadaptorentry.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DBUSADAPTORENTRY_H +#define DBUSADAPTORENTRY_H + +#include "entry.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +Q_DECLARE_METATYPE(ExportWindowInfo) + +QDBusArgument &operator <<(QDBusArgument &argument, const ExportWindowInfo &info); +const QDBusArgument &operator >>(const QDBusArgument &argument, ExportWindowInfo &info); +QDebug operator<<(QDebug deg, const ExportWindowInfo &info); + +/* + * Adaptor class for interface org.deepin.dde.daemon.Dock1.Entry + */ +class DBusAdaptorEntry: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.deepin.dde.daemon.Dock1.Entry") + Q_CLASSINFO("D-Bus Introspection", "" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" + "") + +public: + DBusAdaptorEntry(QObject *parent); + virtual ~DBusAdaptorEntry(); + +public: // PROPERTIES + Q_PROPERTY(uint CurrentWindow READ currentWindow NOTIFY CurrentWindowChanged) + uint currentWindow() const; + + Q_PROPERTY(QString DesktopFile READ desktopFile NOTIFY DesktopFileChanged) + QString desktopFile() const; + + Q_PROPERTY(QString Icon READ icon NOTIFY IconChanged) + QString icon() const; + + Q_PROPERTY(QString Id READ id) + QString id() const; + + Q_PROPERTY(bool IsActive READ isActive NOTIFY IsActiveChanged) + bool isActive() const; + + Q_PROPERTY(bool IsDocked READ isDocked NOTIFY IsDockedChanged) + bool isDocked() const; + + Q_PROPERTY(QString Menu READ menu NOTIFY MenuChanged) + QString menu() const; + + Q_PROPERTY(QString Name READ name NOTIFY NameChanged) + QString name() const; + + //Q_PROPERTY(QString WindowInfos READ windowInfos) + //QList windowInfos(); + + Entry *parent() const; + +public Q_SLOTS: // METHODS + void Activate(uint timestamp); + void Check(); + void ForceQuit(); + QList GetAllowedCloseWindows(); + void HandleDragDrop(uint timestamp, const QStringList &files); + void HandleMenuItem(uint timestamp, const QString &id); + void NewInstance(uint timestamp); + void PresentWindows(); + void RequestDock(); + void RequestUndock(); + +Q_SIGNALS: // SIGNALS + void IsActiveChanged(bool value); + void IsDockedChanged(bool value); + void MenuChanged(QString value); + void IconChanged(QString value); + void NameChanged(QString value); + void DesktopFileChanged(QString value); + void CurrentWindowChanged(uint32_t value); +}; + +#endif diff --git a/src/modules/dock/dbushandler.cpp b/src/modules/dock/dbushandler.cpp new file mode 100644 index 0000000..129132e --- /dev/null +++ b/src/modules/dock/dbushandler.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dbushandler.h" +#include "dock.h" +#include "windowinfok.h" +#include "dbusbamfapplication.h" + +DBusHandler::DBusHandler(Dock *_dock, QObject *parent) + : QObject(parent) + , dock(_dock) + , session(QDBusConnection::sessionBus()) + , launcherEnd(new LauncherBackEnd("org.deepin.dde.daemon.Launcher1", "/org/deepin/dde/daemon/Launcher1", session, this)) + , launcherFront(new LauncherFront("org.deepin.dde.Launcher1", "/org/deepin/dde/Launcher1", session, this)) + , wm(new com::deepin::WM("com.deepin.wm", "/com/deepin/wm", session, this)) + , wmSwitcher(new com::deepin::WMSwitcher("com.deepin.wmWMSwitcher", "/com/deepin/WMSwitcher", session, this)) + , kwaylandManager(nullptr) + , bamfMatcher(new org::ayatana::bamf::BamfMatcher("org.ayatana.bamf.matcher", "/org/ayatana/bamf/matcher", session, this)) +{ + // 关联org.deepin.dde.daemon.Launcher1事件 ItemChanged + connect(launcherEnd, &LauncherBackEnd::ItemChanged, this, &DBusHandler::handleLauncherItemChanged); + + // 关联org.deepin.dde.Launcher1事件 VisibleChanged + connect(launcherFront, &LauncherFront::VisibleChanged, this, [&](bool visible) { + dock->setDdeLauncherVisible(visible); + dock->updateHideState(false); + }); + + // 关联com.deepin.WMSwitcher事件 WMChanged + connect(wmSwitcher, &__WMSwitcher::WMChanged, this, [&](QString name) {dock->setWMName(name);}); +} + +// 关联com.deepin.daemon.KWayland.WindowManager事件 +void DBusHandler::listenWaylandWMSignals() +{ + kwaylandManager = new com::deepin::daemon::kwayland::WindowManager("com.deepin.daemon.KWayland", "/com/deepin/daemon/KWayland/WindowManager", session, this); + + // ActiveWindowchanged + connect(kwaylandManager, &__KwaylandManager::ActiveWindowChanged, this, &DBusHandler::handleWlActiveWindowchange); + // WindowCreated + connect(kwaylandManager, &__KwaylandManager::WindowCreated, this, [&] (const QString &ObjPath) { + dock->registerWindowWayland(ObjPath); + }); + // WindowRemove + connect(kwaylandManager, &__KwaylandManager::WindowRemove, this, [&] (const QString &ObjPath) { + dock->unRegisterWindowWayland(ObjPath); + }); +} + +void DBusHandler::handleLauncherItemChanged(const QString &status, LauncherItemInfo itemInfo, qlonglong categoryID) +{ + qInfo() << "handleLauncherItemChanged status:" << status << " Name:" << itemInfo.Name << " ID:" << itemInfo.ID; + if (status == "deleted") { + dock->handleLauncherItemDeleted(itemInfo.Path); + } else if (status == "created") { + // don't need to download to dock when app reinstall + } else if (status == "updated") { + dock->handleLauncherItemUpdated(itemInfo.Path); + } +} + +QString DBusHandler::getCurrentWM() +{ + return wmSwitcher->CurrentWM().value(); +} + +// TODO 扩展ApplicationManager Run接口,允许带参数启动应用,暂时调用StartManager接口 +void DBusHandler::launchApp(uint32_t timestamp, QStringList files) +{ + QDBusInterface interface = QDBusInterface("com.deepin.StartManager", "/com/deepin/StartManager", "com.deepin.StartManager"); + interface.call("LaunchApp", files, timestamp); +} + +void DBusHandler::launchAppAction(uint32_t timestamp, QString file, QString section) +{ + QDBusInterface interface = QDBusInterface("com.deepin.StartManager", "/com/deepin/StartManager", "com.deepin.StartManager"); + interface.call("LaunchAppAction", file, section, timestamp); +} + +void DBusHandler::markAppLaunched(const QString &filePath) +{ + QDBusInterface interface = QDBusInterface("org.deepin.daemon.AlRecorder1", "/org/deepin/daemon/AlRecorder1", "org.deepin.daemon.AlRecorder1"); + interface.call("MarkLaunched", filePath); +} + +bool DBusHandler::wlShowingDesktop() +{ + bool ret = false; + if (kwaylandManager) + ret = kwaylandManager->IsShowingDesktop().value(); + + return ret; +} + +uint DBusHandler::wlActiveWindow() +{ + uint ret = 0; + if (kwaylandManager) + ret = kwaylandManager->ActiveWindow().value(); + + return ret; +} + +void DBusHandler::handleWlActiveWindowchange() +{ + uint activeWinInternalId = wlActiveWindow(); + if (activeWinInternalId == 0) + return; + + WindowInfoK *info = dock->handleActiveWindowChangedK(activeWinInternalId); + if (info->getXid() != 0) { + dock->handleActiveWindowChanged(info); + } else { + dock->updateHideState(false); + } +} + +void DBusHandler::listenKWindowSignals(WindowInfoK *windowInfo) +{ + PlasmaWindow *window = windowInfo->getPlasmaWindow(); + if (!window) + return; + + // Title changed + connect(window, &PlasmaWindow::TitleChanged, this, [&] { + windowInfo->updateTitle(); + auto entry = dock->getEntryByWindowId(windowInfo->getXid()); + if (!entry) + return; + + if (entry->getCurrentWindowInfo() == windowInfo) + entry->updateName(); + + entry->updateWindowInfos(); + }); + + // Icon changed + connect(window, &PlasmaWindow::IconChanged, this, [&] { + windowInfo->updateIcon(); + auto entry = dock->getEntryByWindowId(windowInfo->getXid()); + if (!entry) + return; + + entry->updateIcon(); + }); + + // DemandingAttention changed + connect(window, &PlasmaWindow::DemandsAttentionChanged, this, [&] { + windowInfo->updateDemandingAttention(); + auto entry = dock->getEntryByWindowId(windowInfo->getXid()); + if (!entry) + return; + + entry->updateWindowInfos(); + }); + + // Geometry changed + connect(window, &PlasmaWindow::GeometryChanged, this, [&] { + if (!windowInfo->updateGeometry()) + return; + + dock->handleWindowGeometryChanged(); + }); +} + +PlasmaWindow *DBusHandler::createPlasmaWindow(QString objPath) +{ + return new PlasmaWindow("com.deepin.daemon.KWayland.PlasmaWindow", objPath, session, this); +} + +// 取消关联信号 +void DBusHandler::removePlasmaWindowHandler(PlasmaWindow *window) +{ + +} + +void DBusHandler::presentWindows(QList windows) +{ + wm->PresentWindows(windows); +} + +QString DBusHandler::getDesktopFromWindowByBamf(XWindow windowId) +{ + QDBusPendingReply reply = bamfMatcher->ApplicationForXid(windowId); + if (!reply.isValid()) + return ""; + + QString appObjPath = reply.value(); + + org::ayatana::bamf::BamfApplication bamfApp("org.ayatana.bamf.application", appObjPath, session, this); + if (bamfApp.isValid()) + return bamfApp.DesktopFile(); + + return ""; +} + diff --git a/src/modules/dock/dbushandler.h b/src/modules/dock/dbushandler.h new file mode 100644 index 0000000..db239a3 --- /dev/null +++ b/src/modules/dock/dbushandler.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DBUSHANDLER_H +#define DBUSHANDLER_H + +#include "dbuslauncher.h" +#include "dbuslauncherfront.h" +#include "dbuswm.h" +#include "dbuswmswitcher.h" +#include "dbuskwaylandwindowmanager.h" +#include "windowinfok.h" +#include "dbusplasmawindow.h" +#include "dbusbamfmatcher.h" + +#include +#include +#include + +class Dock; + +// 处理DBus交互 +class DBusHandler : public QObject +{ + Q_OBJECT +public: + explicit DBusHandler(Dock *_dock, QObject *parent = nullptr); + + /************************* KWayland/WindowManager ***************************/ + void listenWaylandWMSignals(); + bool wlShowingDesktop(); + uint wlActiveWindow(); + + /************************* daemon.Launcher1 ***************************/ + void handleLauncherItemChanged(const QString &status, LauncherItemInfo itemInfo, qlonglong categoryID); + + /************************* WMSwitcher ***************************/ + QString getCurrentWM(); + + /************************* StartManager ***************************/ + void launchApp(uint32_t timestamp, QStringList files); + void launchAppAction(uint32_t timestamp, QString file, QString section); + + /************************* AlRecorder1 ***************************/ + void markAppLaunched(const QString &filePath); + + /************************* KWayland.PlasmaWindow ***************************/ + void listenKWindowSignals(WindowInfoK *windowInfo); + PlasmaWindow *createPlasmaWindow(QString objPath); + void removePlasmaWindowHandler(PlasmaWindow *window); + + /************************* WM ***************************/ + void presentWindows(QList windows); + + /************************* bamf ***************************/ + // XWindow -> desktopFile + QString getDesktopFromWindowByBamf(XWindow windowId); + +private Q_SLOTS: + void handleWlActiveWindowchange(); + +private: + Dock *dock; + QDBusConnection session; + + LauncherBackEnd *launcherEnd; + LauncherFront *launcherFront; + com::deepin::WM *wm; + com::deepin::WMSwitcher *wmSwitcher; + com::deepin::daemon::kwayland::WindowManager *kwaylandManager; + org::ayatana::bamf::BamfMatcher *bamfMatcher; +}; + +#endif // DBUSHANDLER_H diff --git a/src/modules/dock/dock.cpp b/src/modules/dock/dock.cpp new file mode 100644 index 0000000..36f9951 --- /dev/null +++ b/src/modules/dock/dock.cpp @@ -0,0 +1,1045 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dock.h" +#include "windowidentify.h" +#include "common.h" +#include "windowinfok.h" +#include "xcbutils.h" +#include "dbushandler.h" +#include "appinfo.h" +#include "waylandmanager.h" +#include "x11manager.h" +#include "windowinfobase.h" +#include "dbusplasmawindow.h" + +#include +#include +#include + +#define SETTING DockSettings::instance() +#define XCB XCBUtils::instance() + +Dock::Dock(QObject *parent) + : SynModule(parent) + , windowIdentify(new WindowIdentify(this)) + , entries(new Entries(this)) + , ddeLauncherVisible(true) + , hideState(HideState::Unknown) + , activeWindow(nullptr) + , activeWindowOld(nullptr) + , dbusHandler(new DBusHandler(this)) + , windowOperateMutex(QMutex(QMutex::NonRecursive)) +{ + registeModule("dock"); + + QString sessionType {getenv("XDG_SESSION_TYPE")}; + if (sessionType.contains("wayland")) { + // wayland env + isWayland = true; + waylandManager = new WaylandManager(this); + dbusHandler->listenWaylandWMSignals(); + } else if (sessionType.contains("x11")) { + // x11 env + isWayland = false; + x11Manager = new X11Manager(this); + } + + initSettings(); + initEntries(); + + // 初始化智能隐藏定时器 + smartHideTimer = new QTimer(this); + smartHideTimer->setInterval(10 * 1000); + connect(smartHideTimer, SIGNAL(timeout()), this, SLOT(smartHideModeTimerExpired)); // 增加开始判断 + smartHideTimer->stop(); + + if (!isWayland) { + std::thread thread([&] { + // Xlib方式 + x11Manager->listenXEventUseXlib(); + // XCB方式 + //listenXEventUseXCB(); + }); + thread.detach(); + x11Manager->listenRootWindowXEvent(); + connect(x11Manager, SIGNAL(X11Manager::needUpdateHideState), this, SLOT(updateHideState)); + } + Q_EMIT serviceRestarted(); +} + +Dock::~Dock() +{ + +} + +// 驻留 +bool Dock::dockEntry(Entry *entry) +{ + if (entry->getIsDocked()) + return false; + + AppInfo *app = entry->getApp(); + auto needScratchDesktop = [&]{ + if (!app) { + qInfo() << "needScratchDesktop: yes, appInfo is nil"; + return true; + } + + if (app->isInstalled()) { + qInfo() << "needScratchDesktop: no, desktop is installed"; + return false; + } + + if (app->getFileName().contains(scratchDir)) { + qInfo() << "needScratchDesktop: no, desktop in scratchDir"; + return false; + } + + return true; + }; + + + if (needScratchDesktop()) { + // 创建scratch Desktop file + QDir dir; + if (!dir.mkpath(scratchDir)) { + qWarning() << "create scratch Desktopfile failed"; + return false; + } + + QFile file; + QString newDesktopFile; + if (app) { + QString newFile = scratchDir + app->getInnerId() + ".desktop"; + if (file.copy(app->getFileName(), newFile)) + newDesktopFile = newFile; + } else { + WindowInfoBase *current = entry->getCurrentWindowInfo(); + if (current) { + QString appId = current->getInnerId(); + QString title = current->getDisplayName(); + QString icon = current->getIcon(); + if (icon.isEmpty()) + icon = "application-default-icon"; + + QString scriptContent = entry->getExec(false); + QString scriptFile = scratchDir + appId + ".sh"; + file.setFileName(scriptFile); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + file.write(scriptContent.toStdString().c_str(), scriptContent.size()); + file.close(); + } + + // createScratchDesktopFile + QString cmd = scriptFile + " %U"; + QString fileNmae = scratchDir + appId + ".desktop"; + QString desktopContent = QString(dockedItemTemplate).arg(title).arg(cmd).arg(icon); + file.setFileName(fileNmae); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + file.write(desktopContent.toStdString().c_str(), desktopContent.size()); + file.close(); + newDesktopFile = fileNmae; + } + } + } + + if (newDesktopFile.isEmpty()) + return false; + + app = new AppInfo(newDesktopFile); + entry->setApp(app); + entry->updateIcon(); + entry->setInnerId(app->getInnerId()); + } + + entry->setPropIsDocked(true); + entry->updateMenu(); + return true; +} + +// 取消驻留 +void Dock::undockEntry(Entry *entry) +{ + if (!entry->getIsDocked()) { + qInfo() << "undockEntry: " << entry->getId() << " is not docked"; + return; + } + + if (!entry->getApp()) { + qInfo() << "undockEntry: entry appInfo is nullptr"; + return; + } + + // 移除scratchDir目录下相关文件 + QString desktopFile = entry->getFileName(); + QString filebase(desktopFile.data(), desktopFile.size() - 9); + if (desktopFile.contains(scratchDir)) { + for (auto &ext : QStringList() << ".desktop" << ".sh" << ".png") { + QString fileName = filebase + ext; + QFile file(fileName); + if (file.exists()) + file.remove(); + } + + } + + if (entry->hasWindow()) { + if (desktopFile.contains(scratchDir) && !!entry->getCurrentWindowInfo()) { + QFileInfo info(desktopFile); + QString baseName = info.baseName(); + if (baseName.startsWith(windowHashPrefix)) { + // desktop base starts with w: + // 由于有 Pid 识别方法在,在这里不能用 m.identifyWindow 再次识别 + entry->setInnerId(entry->getCurrentWindowInfo()->getInnerId()); + entry->setApp(nullptr); // 此处设置Entry的app为空, 在Entry中调用app相关信息前判断指针是否为空 + } else { + // desktop base starts with d: + QString innerId; + AppInfo *app = windowIdentify->identifyWindow(entry->getCurrentWindowInfo(), innerId); + // TODO update entry's innerId + entry->setApp(app); + entry->setInnerId(innerId); + } + } + entry->updateIcon(); + entry->setPropIsDocked(false); + entry->updateName(); + entry->updateMenu(); + } else { + // 直接移除 + removeAppEntry(entry); + } + + saveDockedApps(); +} + +QString Dock::allocEntryId() +{ + int num = entriesSum++; + return QString::number(num); +} + +bool Dock::shouldShowOnDock(WindowInfoBase *info) +{ + if (info->getWindowType() == "X11") { + XWindow winId = info->getXid(); + bool isReg = !!x11Manager->findWindowByXid(winId); + bool isContainedInClientList = clientList.indexOf(winId) != -1; + bool shouldSkip = info->shouldSkip(); + bool isGood = XCB->isGoodWindow(winId); + qInfo() << "shouldShowOnDock X11: isReg:" << isReg << " isContainedInClientList:" << isContainedInClientList << " shouldSkip:" << shouldSkip << " isGood:" << isGood; + + return isReg && isContainedInClientList && isGood && !shouldSkip; + } else if (info->getWindowType() == "Wayland") { + return !info->shouldSkip(); + } + + return false; +} + +void Dock::setDdeLauncherVisible(bool visible) +{ + ddeLauncherVisible = visible; +} + +QString Dock::getWMName() +{ + return wmName; +} + +void Dock::setWMName(QString name) +{ + wmName = name; +} + +void Dock::setSynConfig(QByteArray ba) +{ + +} + +QByteArray Dock::getSyncConfig() +{ + return QByteArray(); +} + +PlasmaWindow *Dock::createPlasmaWindow(QString objPath) +{ + return dbusHandler->createPlasmaWindow(objPath); +} + +void Dock::listenKWindowSignals(WindowInfoK *windowInfo) +{ + dbusHandler->listenKWindowSignals(windowInfo); +} + +void Dock::removePlasmaWindowHandler(PlasmaWindow *window) +{ + dbusHandler->removePlasmaWindowHandler(window); +} + +void Dock::presentWindows(QList windows) +{ + dbusHandler->presentWindows(windows); +} + +HideMode Dock::getDockHideMode() +{ + return SETTING->getHideMode(); +} + +WindowInfoBase *Dock::getActiveWindow() +{ + WindowInfoBase *ret = nullptr; + if (!activeWindow) + ret = activeWindowOld; + else + ret = activeWindow; + + return ret; +} + +QList Dock::getClientList() +{ + return QList(clientList); +} + +// 关闭窗口 +void Dock::closeWindow(uint32_t windowId) +{ + qInfo() << "Close Window " << windowId; + if (isWayland) { + WindowInfoK *info = waylandManager->findWindowByXid(windowId); + if (info) + info->close(0); + } else { + XCB->requestCloseWindow(windowId, 0); + } +} + +// 获取所有应用Id for debug +QStringList Dock::getEntryIDs() +{ + return entries->getEntryIDs(); +} + +// 设置任务栏Rect +void Dock::setFrontendWindowRect(int32_t x, int32_t y, uint width, uint height) +{ + if (frontendWindowRect == QRect(x, y, width, height)) { + qInfo() << "SetFrontendWindowRect: no changed"; + return; + } + + frontendWindowRect.setX(x); + frontendWindowRect.setY(y); + frontendWindowRect.setWidth(width); + frontendWindowRect.setHeight(height); + updateHideState(false); + + Q_EMIT frontendWindowRectChanged(); +} + +// 应用是否驻留 +bool Dock::isDocked(const QString desktopFile) +{ + auto entry = getDockedEntryByDesktopFile(desktopFile); + return !!entry; +} + +// 驻留应用 +bool Dock::requestDock(QString desktopFile, int index) +{ + qInfo() << "RequestDock: " << desktopFile; + AppInfo *app = new AppInfo(desktopFile); + if (!app || !app->isValidApp()) { + qInfo() << "RequestDock: invalid desktopFile"; + return false; + } + + bool newCreated = false; + Entry *entry = entries->getByInnerId(app->getInnerId()); + if (!entry) { + newCreated = true; + entry = new Entry(this, app, app->getInnerId()); + } + + if (!dockEntry(entry)) + return false; + + if (newCreated) { + entry->startExport(); + entries->append(entry); + } + + saveDockedApps(); + return true; +} + +bool Dock::requestUndock(QString desktopFile) +{ + auto entry = getDockedEntryByDesktopFile(desktopFile); + if (!entry) + return false; + + undockEntry(entry); + return true; +} + +// 移动驻留程序顺序 +void Dock::moveEntry(int oldIndex, int newIndex) +{ + entries->move(oldIndex, newIndex); + saveDockedApps(); +} + +// 是否在任务栏 +bool Dock::isOnDock(QString desktopFile) +{ + return !!getDockedEntryByDesktopFile(desktopFile); +} + +// 查询窗口识别方式 +QString Dock::queryWindowIdentifyMethod(XWindow windowId) +{ + return entries->queryWindowIdentifyMethod(windowId); +} + +// 获取驻留应用desktop文件 +QStringList Dock::getDockedAppsDesktopFiles() +{ + QStringList ret; + for (auto entry: entries->filterDockedEntries()) { + ret << entry->getFileName(); + } + + return ret; +} + +// 获取任务栏插件配置 +QString Dock::getPluginSettings() +{ + return SETTING->getPluginSettings(); +} + +// 设置任务栏插件配置 +void Dock::setPluginSettings(QString jsonStr) +{ + SETTING->setPluginSettings(jsonStr); +} + +// 合并任务栏插件配置 +void Dock::mergePluginSettings(QString jsonStr) +{ + SETTING->mergePluginSettings(jsonStr); +} + +// 移除任务栏插件配置 +void Dock::removePluginSettings(QString pluginName, QStringList settingkeys) +{ + SETTING->removePluginSettings(pluginName, settingkeys); +} + +// 智能隐藏 +void Dock::smartHideModeTimerExpired() +{ + HideState state = shouldHideOnSmartHideMode() ? HideState::Hide : HideState::Show; + qInfo() << "smartHideModeTimerExpired, is Hide? " << int(state); + setPropHideMode(state); +} + +void Dock::initSettings() +{ + SETTING->init(); + connect(SETTING, &DockSettings::hideModeChanged, this, [&](HideMode mode) { + this->updateHideState(false); + }); + connect(SETTING, &DockSettings::displayModeChanged, this, [](DisplayMode mode) { + qInfo() << "display mode change to " << static_cast(mode); + }); + connect(SETTING, &DockSettings::positionModeChanged, this, [](PositonMode mode) { + qInfo() << "position mode change to " << static_cast(mode); + }); + connect(SETTING, &DockSettings::forceQuitAppChanged, this, [&](bool mode) { + qInfo() << "forceQuitApp change to " << mode; + entries->updateEntriesMenu(); + }); +} + +// 更新所有应用菜单 +void Dock::updateMenu() +{ + +} + +// 初始化应用 +void Dock::initEntries() +{ + initDockedApps(); + if (!isWaylandEnv()) + initClientList(); +} + +void Dock::initDockedApps() +{ + // 初始化驻留应用信息 + for (const auto &app : SETTING->getDockedApps()) { + if (app.isEmpty() || app[0] != '/' || app.size() <= 3) + continue; + + QString prefix(app.data(), 3); + QString appId(app.data() + 3); + QString path; + if (pathCodeDirMap.find(prefix) != pathCodeDirMap.end()) + path = pathCodeDirMap[prefix] + appId + ".desktop"; + + DesktopInfo info(path.toStdString()); + if (!info.isValidDesktop()) + continue; + + AppInfo *appInfo = new AppInfo(info); + Entry *entryObj = new Entry(this, appInfo, appInfo->getInnerId()); + entryObj->setIsDocked(true); + entryObj->updateMenu(); + entryObj->startExport(); + entries->append(entryObj); + } + + saveDockedApps(); +} + +#include "processinfo.h" +void Dock::initClientList() +{ + QList clients; + for (auto c : XCB->instance()->getClientList()) + clients.push_back(c); + + // 依次注册窗口 + qSort(clients.begin(), clients.end()); + clientList = clients; + for (auto winId : clientList) { + WindowInfoX *winInfo = x11Manager->registerWindow(winId); + attachOrDetachWindow(static_cast(winInfo)); + } +} + +WindowInfoX *Dock::findWindowByXidX(XWindow xid) +{ + return x11Manager->findWindowByXid(xid); +} + +WindowInfoK *Dock::findWindowByXidK(XWindow xid) +{ + return waylandManager->findWindowByXid(xid); +} + +bool Dock::isWindowDockOverlapX(XWindow xid) +{ + + return false; +} + +// 判断窗口和任务栏是否重叠 +bool Dock::isWindowDockOverlapK(WindowInfoBase *info) +{ + if (!info) { + qInfo() << "isWindowDockOverlapK: info is nullptr"; + return false; + } + + //TODO check + + return false; +} + +Entry *Dock::getDockedEntryByDesktopFile(const QString &desktopFile) +{ + return entries->getDockedEntryByDesktopFile(desktopFile); +} + +bool Dock::shouldHideOnSmartHideMode() +{ + if (!activeWindow || ddeLauncherVisible) + return false; + + if (!isWayland) { + XWindow activeWinId = activeWindow->getXid(); + + // dde launcher is invisible, but it is still active window + WMClass winClass = XCB->getWMClass(activeWinId); + if (winClass.instanceName.size() > 0 && winClass.instanceName.c_str() == ddeLauncherWMClass) { + qInfo() << "shouldHideOnSmartHideMode: active window is dde launcher"; + return false; + } + + QVector list = getActiveWinGroup(activeWinId); + for (XWindow xid : list) { + if (isWindowDockOverlapX(xid)) + return true; + } + return false; + } else { + return isWindowDockOverlapK(activeWindow); + } +} + +QVector Dock::getActiveWinGroup(XWindow xid) +{ + QVector ret; + ret.push_back(xid); + + std::list winList = XCB->getClientListStacking(); + if (winList.empty() + || !std::any_of(winList.begin(), winList.end(), [&](XWindow id) { return id == xid;}) // not found active window in clientListStacking" + || *winList.begin() == 0) // root window + return ret; + + uint32_t apid = XCB->getWMPid(xid); + XWindow aleaderWin = XCB->getWMClientLeader(xid); + for (auto winId : winList) { + if (winId == xid) + break; + + uint32_t pid = XCB->getWMPid(winId); + // same pid + if (apid != 0 && pid == apid) { + // ok + ret.push_back(winId); + continue; + } + + WMClass wmClass = XCB->getWMClass(winId); + // same wmclass + if (wmClass.className.size() > 0 && wmClass.className.c_str() == frontendWindowWmClass) { + // skip over fronted window + continue; + } + + uint32_t leaderWin = XCB->getWMClientLeader(winId); + // same leaderWin + if (aleaderWin != 0 && aleaderWin == leaderWin) { + // ok + ret.push_back(winId); + continue; + } + + // above window + XWindow aboveWinId = 0; + for (auto iter = winList.begin(); iter != winList.end(); iter++) { + if (*iter == winId) { + aboveWinId = *++iter; + break; + } + } + + if (aboveWinId == 0) + continue; + + XWindow aboveWinTransientFor = XCB->getWMTransientFor(aboveWinId); + if (aboveWinTransientFor != 0 && aboveWinTransientFor == winId) { + // ok + ret.push_back(winId); + continue; + } + } + + return ret; +} + +// 更新任务栏隐藏状态 +void Dock::updateHideState(bool delay) +{ + if (ddeLauncherVisible) { + qInfo() << "updateHideState: dde launcher is visible, show dock"; + setPropHideMode(HideState::Show); + } + + HideMode mode = SETTING->getHideMode(); + switch (mode) { + case HideMode::KeepShowing: + setPropHideMode(HideState::Show); + break; + case HideMode::KeepHidden: + setPropHideMode(HideState::Hide); + break; + case HideMode::SmartHide: + qInfo() << "reset smart hide mode timer " << delay; + smartHideTimer->start(delay ? smartHideTimerDelay : 0); + break; + case HideMode::Unknown: + setPropHideMode(HideState::Unknown); + break; + } +} + +void Dock::setPropHideMode(HideState state) +{ + if (state == HideState::Unknown) { + qInfo() << "setPropHideState: unknown mode"; + return; + } + + if (state != hideState) { + hideState = state; + Q_EMIT hideStateChanged(); + } +} + +void Dock::attachOrDetachWindow(WindowInfoBase *info) +{ + if (!info) + return; + + XWindow winId = info->getXid(); + bool shouldDock = shouldShowOnDock(info); + qInfo() << "attachOrDetachWindow: shouldDock " << shouldDock; + + // 顺序解析窗口合并或分离操作 + QMutexLocker locker(&windowOperateMutex); + Entry *entry = info->getEntry(); + if (entry) { + // detach + if (!shouldDock) + detachWindow(info); + else + qInfo() << "detach operate: window " << winId << "don't need to detach"; + } else { + // attach + if (info->getEntryInnerId().isEmpty()) { + // 识别窗口并创建entryInnerId + qInfo() << "attach operate: window " << winId << " entryInnerId is empty, now call IdentifyWindow"; + QString innerId; + AppInfo *appInfo = windowIdentify->identifyWindow(info, innerId); + info->setEntryInnerId(innerId); // windowBaseInfo entryInnerId is AppInfo innerId, for binding window and appInfo + info->setAppInfo(appInfo); + markAppLaunched(appInfo); + } else { + qInfo() << "attach operate: window " << winId << "has been identified"; + } + + // winInfo初始化后影响判断是否在任务栏显示图标,需判断 + if (shouldShowOnDock(info)) + attachWindow(info); + } +} + +void Dock::attachWindow(WindowInfoBase *info) +{ + Entry *entry = entries->getByInnerId(info->getEntryInnerId()); + if (entry) { + // entry existed + entry->attachWindow(info); + } else { + entry = new Entry(this, info->getAppInfo(), info->getEntryInnerId()); + if (entry->attachWindow(info)) { + entry->startExport(); + entries->append(entry); + } + } +} + +void Dock::detachWindow(WindowInfoBase *info) +{ + auto entry = entries->getByWindowId(info->getXid()); + if (!entry) + return; + + bool needRemove = entry->detachWindow(info); + if (needRemove) + removeAppEntry(entry); +} + +void Dock::markAppLaunched(const QString &filePath) +{ + dbusHandler->markAppLaunched(filePath); +} + +void Dock::launchApp(uint32_t timestamp, QStringList files) +{ + dbusHandler->launchApp(timestamp, files); +} + +void Dock::launchAppAction(uint32_t timestamp, QString file, QString section) +{ + dbusHandler->launchAppAction(timestamp, file, section); +} + +bool Dock::is3DWM() +{ + bool ret = false; + if (wmName.isEmpty()) + wmName = dbusHandler->getCurrentWM(); + + if (wmName == "deepin wm") + ret = true; + + return ret; +} + +bool Dock::isWaylandEnv() +{ + return isWayland; +} + +WindowInfoK *Dock::handleActiveWindowChangedK(uint activeWin) +{ + return waylandManager->handleActiveWindowChangedK(activeWin); +} + +void Dock::handleActiveWindowChanged(WindowInfoBase *info) +{ + qInfo() << "handleActiveWindowChanged"; + if (!info) { + activeWindowOld = info; + activeWindow = nullptr; + return; + } + + activeWindow = info; + XWindow winId = activeWindow->getXid(); + entries->handleActiveWindowChanged(winId); + updateHideState(true); +} + +void Dock::saveDockedApps() +{ + // 保存驻留应用信息 + QList dockedApps; + for (auto entry : entries->filterDockedEntries()) { + QString path = entry->getApp()->getFileName(); + for (auto iter=pathDirCodeMap.begin(); iter != pathDirCodeMap.end(); iter++) { + if (path.startsWith(iter.key())) { + path = QString(path.data() + iter.key().size()); // 去头dir + path.truncate(path.size() - 8); // 去尾.desktop + dockedApps.push_back(iter.value() + path); + break; + } + } + } + SETTING->setDockedApps(dockedApps); +} + +void Dock::removeAppEntry(Entry *entry) +{ + if (entry) { + entries->remove(entry); + } +} + +void Dock::handleWindowGeometryChanged() +{ + if (SETTING->getHideMode() == HideMode::SmartHide) + return; + + updateHideState(false); +} + +Entry *Dock::getEntryByWindowId(XWindow windowId) +{ + return entries->getByWindowId(windowId); +} + +QString Dock::getDesktopFromWindowByBamf(XWindow windowId) +{ + return dbusHandler->getDesktopFromWindowByBamf(windowId); +} + +void Dock::registerWindowWayland(const QString &objPath) +{ + return waylandManager->registerWindow(objPath); +} + +void Dock::unRegisterWindowWayland(const QString &objPath) +{ + return waylandManager->unRegisterWindow(objPath); +} + +AppInfo *Dock::identifyWindow(WindowInfoBase *winInfo, QString &innerId) +{ + return windowIdentify->identifyWindow(winInfo, innerId); +} + +void Dock::markAppLaunched(AppInfo *appInfo) +{ + if (!appInfo || !appInfo->isValidApp()) + return; + + QString desktopFile = appInfo->getFileName(); + qInfo() << "markAppLaunched: desktopFile is " << desktopFile; + dbusHandler->markAppLaunched(desktopFile); +} + +void Dock::deleteWindow(XWindow xid) +{ + entries->deleteWindow(xid); +} + +ForceQuitAppMode Dock::getForceQuitAppStatus() +{ + return forceQuitAppStatus; +} + +QVector Dock::getWinIconPreferredApps() +{ + return SETTING->getWinIconPreferredApps(); +} + +void Dock::handleLauncherItemDeleted(QString itemPath) +{ + for (auto entry : entries->filterDockedEntries()) { + if (entry->getFileName() == itemPath) { + undockEntry(entry); + break; + } + } +} + +// 在收到 launcher item 更新的信号后,需要更新相关信息,包括 appInfo、innerId、名称、图标、菜单。 +void Dock::handleLauncherItemUpdated(QString itemPath) +{ + Entry * entry = entries->getByDesktopFilePath(itemPath); + if (!entry) + return; + + AppInfo *app = new AppInfo(itemPath); + entry->setApp(app); + entry->setInnerId(app->getInnerId()); + entry->updateName(); + entry->updateMenu(); + entry->forceUpdateIcon(); // 可能存在Icon图片改变,但Icon名称未改变的情况,因此强制发Icon的属性改变信号 +} + +double Dock::getOpacity() +{ + return SETTING->getOpacity(); +} + +QRect Dock::getFrontendWindowRect() +{ + return frontendWindowRect; +} + +int Dock::getDisplayMode() +{ + return int(SETTING->getDisplayMode()); +} + +void Dock::setDisplayMode(int mode) +{ + SETTING->setDisplayMode(DisplayMode(mode)); +} + +QStringList Dock::getDockedApps() +{ + return SETTING->getDockedApps(); +} + +QStringList Dock::getEntryPaths() +{ + QStringList ret; + for (auto id : entries->getEntryIDs()) { + ret.push_back(entryDBusObjPathPrefix + id); + } + + return ret; +} + +HideMode Dock::getHideMode() +{ + return SETTING->getHideMode(); +} + +void Dock::setHideMode(HideMode mode) +{ + SETTING->setHideMode(mode); +} + +Dock::HideState Dock::getHideState() +{ + return hideState; +} + +void Dock::setHideState(Dock::HideState state) +{ + hideState = state; +} + +uint Dock::getHideTimeout() +{ + return SETTING->getHideTimeout(); +} + +void Dock::setHideTimeout(uint timeout) +{ + SETTING->setHideTimeout(timeout); +} + +uint Dock::getIconSize() +{ + return SETTING->getIconSize(); +} + +void Dock::setIconSize(uint size) +{ + SETTING->setIconSize(size); +} + +int Dock::getPosition() +{ + return int(SETTING->getPositionMode()); +} + +void Dock::setPosition(int position) +{ + SETTING->setPositionMode(PositonMode(position)); +} + +uint Dock::getShowTimeout() +{ + return SETTING->getShowTimeout(); +} + +void Dock::setShowTimeout(uint timeout) +{ + return SETTING->setShowTimeout(timeout); +} + +uint Dock::getWindowSizeEfficient() +{ + return SETTING->getWindowSizeEfficient(); +} + +void Dock::setWindowSizeEfficient(uint size) +{ + SETTING->setWindowSizeEfficient(size); +} + +uint Dock::getWindowSizeFashion() +{ + return SETTING->getWindowSizeFashion(); +} + +void Dock::setWindowSizeFashion(uint size) +{ + SETTING->setWindowSizeFashion(size); +} + diff --git a/src/modules/dock/dock.h b/src/modules/dock/dock.h new file mode 100644 index 0000000..f8e73a2 --- /dev/null +++ b/src/modules/dock/dock.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DOCK_H +#define DOCK_H + +#include "synmodule.h" +#include "docksettings.h" +#include "entries.h" +#include "dbusplasmawindow.h" + +#include +#include +#include + +class WindowIdentify; +class DBusHandler; +class WaylandManager; +class X11Manager; +class WindowInfoK; +class WindowInfoX; + +// 任务栏 +class Dock : public SynModule +{ + Q_OBJECT + + enum class HideState + { + Unknown, + Show, + Hide, + }; + +public: + explicit Dock(QObject *parent = nullptr); + ~Dock(); + + bool dockEntry(Entry *entry); + void undockEntry(Entry *entry); + QString allocEntryId(); + bool shouldShowOnDock(WindowInfoBase *info); + void setDdeLauncherVisible(bool visible); + QString getWMName(); + void setWMName(QString name); + void setPropHideMode(HideState state); + void attachOrDetachWindow(WindowInfoBase *info); + void attachWindow(WindowInfoBase *info); + void detachWindow(WindowInfoBase *info); + void markAppLaunched(const QString &filePath); + void launchApp(uint32_t timestamp, QStringList files); + void launchAppAction(uint32_t timestamp, QString file, QString section); + bool is3DWM(); + bool isWaylandEnv(); + WindowInfoK *handleActiveWindowChangedK(uint activeWin); + void handleActiveWindowChanged(WindowInfoBase *info); + void saveDockedApps(); + void removeAppEntry(Entry *entry); + void handleWindowGeometryChanged(); + Entry *getEntryByWindowId(XWindow windowId); + QString getDesktopFromWindowByBamf(XWindow windowId); + + void registerWindowWayland(const QString &objPath); + void unRegisterWindowWayland(const QString &objPath); + + AppInfo *identifyWindow(WindowInfoBase *winInfo, QString &innerId); + void markAppLaunched(AppInfo *appInfo); + void deleteWindow(XWindow xid); + + ForceQuitAppMode getForceQuitAppStatus(); + QVector getWinIconPreferredApps(); + void handleLauncherItemDeleted(QString itemPath); + void handleLauncherItemUpdated(QString itemPath); + + double getOpacity(); + QRect getFrontendWindowRect(); + int getDisplayMode(); + void setDisplayMode(int mode); + QStringList getDockedApps(); + QStringList getEntryPaths(); + HideMode getHideMode(); + void setHideMode(HideMode mode); + HideState getHideState(); + void setHideState(HideState state); + uint getHideTimeout(); + void setHideTimeout(uint timeout); + uint getIconSize(); + void setIconSize(uint size); + int getPosition(); + void setPosition(int position); + uint getShowTimeout(); + void setShowTimeout(uint timeout); + uint getWindowSizeEfficient(); + void setWindowSizeEfficient(uint size); + uint getWindowSizeFashion(); + void setWindowSizeFashion(uint size); + + // 设置配置 + void setSynConfig(QByteArray ba); + QByteArray getSyncConfig(); + + /******************************** dbus handler ****************************/ + PlasmaWindow *createPlasmaWindow(QString objPath); + void listenKWindowSignals(WindowInfoK *windowInfo); + void removePlasmaWindowHandler(PlasmaWindow *window); + void presentWindows(QList windows); + + HideMode getDockHideMode(); + WindowInfoBase *getActiveWindow(); + QList getClientList(); + + void closeWindow(XWindow windowId); + QStringList getEntryIDs(); + void setFrontendWindowRect(int32_t x, int32_t y, uint width, uint height); + bool isDocked(const QString desktopFile); + bool requestDock(QString desktopFile, int index); + bool requestUndock(QString desktopFile); + void moveEntry(int oldIndex, int newIndex); + bool isOnDock(QString desktopFile); + QString queryWindowIdentifyMethod(XWindow windowId); + QStringList getDockedAppsDesktopFiles(); + QString getPluginSettings(); + void setPluginSettings(QString jsonStr); + void mergePluginSettings(QString jsonStr); + void removePluginSettings(QString pluginName, QStringList settingkeys); + + void updateHideState(bool delay); + +Q_SIGNALS: + void serviceRestarted(); + void entryAdded(QString entryObjPath, int32_t index); + void entryRemoved(QString id); + void hideStateChanged(); + void frontendWindowRectChanged(); + +private Q_SLOTS: + void smartHideModeTimerExpired(); + +private: + void initSettings(); + void updateMenu(); + void initEntries(); + void initDockedApps(); + void initClientList(); + WindowInfoX *findWindowByXidX(XWindow xid); + WindowInfoK *findWindowByXidK(XWindow xid); + bool isWindowDockOverlapX(XWindow xid); + bool isWindowDockOverlapK(WindowInfoBase *info); + Entry *getDockedEntryByDesktopFile(const QString &desktopFile); + bool shouldHideOnSmartHideMode(); + QVector getActiveWinGroup(XWindow xid); + + WindowIdentify *windowIdentify; // 窗口识别 + Entries *entries; // 所有应用实例 + int entriesSum; // 累计打开的应用数量 + bool ddeLauncherVisible; // 前端启动器是否可见 + QString wmName; // 窗管名称 + WaylandManager *waylandManager; // wayland窗口管理 + X11Manager *x11Manager; // X11窗口管理 + QList clientList; // 所有窗口 + QRect frontendWindowRect; // 前端任务栏大小, 用于智能隐藏时判断窗口是否重合 + HideState hideState; // 记录任务栏隐藏状态 + QTimer *smartHideTimer; // 任务栏智能隐藏定时器 + WindowInfoBase *activeWindow;// 记录当前活跃窗口信息 + WindowInfoBase *activeWindowOld;// 记录前一个活跃窗口信息 + bool isWayland; // 判断是否为wayland环境 + ForceQuitAppMode forceQuitAppStatus; // 强制退出应用状态 + DBusHandler *dbusHandler; // 处理dbus交互 + QMutex windowOperateMutex; // 窗口合并或拆分锁 +}; + + +#endif // DOCK_H diff --git a/src/modules/dock/dockmanager.cpp b/src/modules/dock/dockmanager.cpp new file mode 100644 index 0000000..0d392bf --- /dev/null +++ b/src/modules/dock/dockmanager.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dockmanager.h" +#include "dock.h" + +#include +#include +#include + +DockManager::DockManager(QObject *parent) + : QObject(parent) + , dock(new Dock(this)) +{ + adaptor = new DBusAdaptorDock(dock); + QDBusConnection con = QDBusConnection::sessionBus(); + if (!con.registerService(dbusService)) { + qWarning() << "register service Dock1 error:" << con.lastError().message(); + return; + } + + if (!con.registerObject(dbusPath, dock, QDBusConnection::ExportAdaptors)) + { + qWarning() << "register object Dock1 error:" << con.lastError().message(); + return; + } + + +} + +DockManager::~DockManager() +{ + +} diff --git a/src/modules/dock/dockmanager.h b/src/modules/dock/dockmanager.h new file mode 100644 index 0000000..96f645f --- /dev/null +++ b/src/modules/dock/dockmanager.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DOCKMANAGER_H +#define DOCKMANAGER_H + +#include "dbusadaptordock.h" + +#include + +class Dock; + +// 任务栏管理类 +class DockManager : public QObject +{ + Q_OBJECT +public: + explicit DockManager(QObject *parent = nullptr); + ~DockManager(); + +Q_SIGNALS: + +public Q_SLOTS: + +private: + Dock *dock; + DBusAdaptorDock *adaptor; +}; + +#endif // DOCKMANAGER_H diff --git a/src/modules/dock/docksettings.cpp b/src/modules/dock/docksettings.cpp new file mode 100644 index 0000000..7e0ebe7 --- /dev/null +++ b/src/modules/dock/docksettings.cpp @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "docksettings.h" +#include "settings.h" + +#include +#include +#include +#include + +DCORE_USE_NAMESPACE + +static DConfig *dockSettings = Settings::ConfigPtr(configDock); +static DConfig *appearanceSettings = Settings::ConfigPtr(configAppearance); + +DockSettings::DockSettings(QObject *parent) + : QObject (parent) +{ + init(); +} + +void DockSettings::init() +{ + // 绑定属性 + if (dockSettings) { + connect(dockSettings, &DConfig::valueChanged, this, [&] (const QString &key) { + if (key == keyHideMode) { + Q_EMIT hideModeChanged(HideMode(dockSettings->value(key).toInt())); + } else if(key == keyDisplayMode) { + Q_EMIT displayModeChanged(DisplayMode(dockSettings->value(key).toInt())); + } else if (key == keyPosition) { + Q_EMIT positionModeChanged(PositonMode(dockSettings->value(key).toInt())); + } else if (key == keyForceQuitApp){ + Q_EMIT forceQuitAppChanged(dockSettings->value(key).toBool()); + } + }); + } +} + +HideMode DockSettings::getHideMode() +{ + HideMode ret = HideMode::Unknown; + if (dockSettings) { + QString mode = dockSettings->value(keyHideMode).toString(); + HideModeHandler handler(mode); + ret = handler.toEnum(); + } + return ret; +} + +void DockSettings::setHideMode(HideMode mode) +{ + if (dockSettings) { + dockSettings->setValue(keyHideMode, HideModeHandler(mode).toString()); + } +} + +DisplayMode DockSettings::getDisplayMode() +{ + DisplayMode ret = DisplayMode::Unknown; + if (dockSettings) { + QString mode = dockSettings->value(keyDisplayMode).toString(); + DisplayModeHandler handler(mode); + ret = handler.toEnum(); + } + return ret; +} + +void DockSettings::setDisplayMode(DisplayMode mode) +{ + if (dockSettings) { + dockSettings->setValue(keyHideMode, DisplayModeHandler(mode).toString()); + } +} + +PositonMode DockSettings::getPositionMode() +{ + PositonMode ret = PositonMode::Unknown; + if (dockSettings) { + QString mode = dockSettings->value(keyPosition).toString(); + PositonModeHandler handler(mode); + ret = handler.toEnum(); + } + return ret; +} + +void DockSettings::setPositionMode(PositonMode mode) +{ + if (dockSettings) { + dockSettings->setValue(keyPosition, PositonModeHandler(mode).toString()); + } +} + +ForceQuitAppMode DockSettings::getForceQuitAppMode() +{ + ForceQuitAppMode ret = ForceQuitAppMode::Unknown; + if (dockSettings) { + QString mode = dockSettings->value(keyForceQuitApp).toString(); + ForceQuitAppModeHandler handler(mode); + ret = handler.toEnum(); + } + return ret; +} + +void DockSettings::setForceQuitAppMode(ForceQuitAppMode mode) +{ + if (dockSettings) { + dockSettings->setValue(keyForceQuitApp, ForceQuitAppModeHandler(mode).toString()); + } +} + +uint DockSettings::getIconSize() +{ + uint size = 36; + if (dockSettings) { + size = dockSettings->value(keyIconSize).toUInt(); + } + return size; +} + +void DockSettings::setIconSize(uint size) +{ + if (dockSettings) { + dockSettings->setValue(keyIconSize, size); + } +} + +uint DockSettings::getShowTimeout() +{ + uint time = 100; + if (dockSettings) { + time = dockSettings->value(keyShowTimeout).toUInt(); + } + return time; +} + +void DockSettings::setShowTimeout(uint time) +{ + if (dockSettings) { + dockSettings->setValue(keyShowTimeout, time); + } +} + +uint DockSettings::getHideTimeout() +{ + uint time = 0; + if (dockSettings) { + time = dockSettings->value(keyHideTimeout).toUInt(); + } + return time; +} + +void DockSettings::setHideTimeout(uint time) +{ + if (dockSettings) { + dockSettings->setValue(keyHideTimeout, time); + } +} + +uint DockSettings::getWindowSizeEfficient() +{ + uint size = 40; + if (dockSettings) { + size = dockSettings->value(keyWindowSizeEfficient).toUInt(); + } + return size; +} + +void DockSettings::setWindowSizeEfficient(uint size) +{ + if (dockSettings) { + dockSettings->setValue(keyWindowSizeEfficient, size); + } +} + +uint DockSettings::getWindowSizeFashion() +{ + uint size = 48; + if (dockSettings) { + size = dockSettings->value(keyWindowSizeFashion).toUInt(); + } + return size; +} + +void DockSettings::setWindowSizeFashion(uint size) +{ + if (dockSettings) { + dockSettings->setValue(keyWindowSizeFashion, size); + } +} + +QStringList DockSettings::getDockedApps() +{ + QStringList ret; + if (!dockSettings) + return ret; + + for(const auto &var : dockSettings->value(keyDockedApps).toList()) { + if (var.isValid()) + ret.push_back(var.toString()); + } + + return ret; +} + +void DockSettings::setDockedApps(QList &apps) +{ + if (!dockSettings) + return; + + qDebug() << "docked apps:" << apps; + QVariantList list; + for (auto app : apps) { + list << QVariant(app); + } + + dockSettings->setValue(keyDockedApps, list); +} + +double DockSettings::getOpacity() +{ + double opacity = 0.4; + if (appearanceSettings) { + opacity = appearanceSettings->value(keyOpacity).toDouble(); + } + return opacity; +} + +QVector DockSettings::getWinIconPreferredApps() +{ + QVector ret; + if (dockSettings) { + for(const auto &var : dockSettings->value(keyWinIconPreferredApps).toList()) { + if (var.isValid()) + ret.push_back(var.toString()); + } + } + + return ret; +} + +QString DockSettings::getPluginSettings() +{ + QString ret; + if (dockSettings) { + ret = dockSettings->value(keyPluginSettings).toString(); + } + + qInfo() << "getpluginsettings:" << ret; + return ret; +} + +void DockSettings::setPluginSettings(QString jsonStr) +{ + if (jsonStr.isEmpty()) + return; + + if (dockSettings) { + dockSettings->setValue(keyPluginSettings, jsonStr); + } +} + +void DockSettings::mergePluginSettings(QString jsonStr) +{ + QString origin = getPluginSettings(); + QJsonObject originSettings = plguinSettingsStrToObj(origin); + QJsonObject needMergeSettings = plguinSettingsStrToObj(jsonStr); + for (auto pluginsIt = needMergeSettings.begin(); pluginsIt != needMergeSettings.end(); pluginsIt++) { + const QString &pluginName = pluginsIt.key(); + const QJsonObject &needMergeSettingsObj = pluginsIt.value().toObject(); + QJsonObject originSettingsObj = originSettings.value(pluginName).toObject(); + for (auto settingsIt = needMergeSettingsObj.begin(); settingsIt != needMergeSettingsObj.end(); settingsIt++) { + originSettingsObj.insert(settingsIt.key(), settingsIt.value()); + } + + // 重写plugin对应的设置 + originSettings.remove(pluginName); + originSettings.insert(pluginName, originSettingsObj); + } + + setPluginSettings(QJsonDocument(originSettings).toJson(QJsonDocument::JsonFormat::Compact)); +} + +void DockSettings::removePluginSettings(QString pluginName, QStringList settingkeys) +{ + if (pluginName.isEmpty()) + return; + + QString origin = getPluginSettings(); + QJsonObject originSettings = plguinSettingsStrToObj(origin); + if (settingkeys.size() == 0) { + originSettings.remove(pluginName); + } else { + for (auto pluginsIt = originSettings.begin(); pluginsIt != originSettings.end(); pluginsIt++) { + const QString &pluginName = pluginsIt.key(); + if (pluginName != pluginName) + continue; + + QJsonObject originSettingsObj = originSettings.value(pluginName).toObject(); + for (const auto &key : settingkeys) { + originSettingsObj.remove(key); + } + + // 重写plugin对应的设置 + originSettings.remove(pluginName); + originSettings.insert(pluginName, originSettingsObj); + } + } + + setPluginSettings(QJsonDocument(originSettings).toJson(QJsonDocument::JsonFormat::Compact)); +} + +// 借鉴自dde-dock +QJsonObject DockSettings::plguinSettingsStrToObj(QString jsonStr) +{ + QJsonObject ret; + const QJsonObject &pluginSettingsObject = QJsonDocument::fromJson(jsonStr.toLocal8Bit()).object(); + if (pluginSettingsObject.isEmpty()) { + return ret; + } + + for (auto pluginsIt = pluginSettingsObject.constBegin(); pluginsIt != pluginSettingsObject.constEnd(); ++pluginsIt) { + const QString &pluginName = pluginsIt.key(); + const QJsonObject &settingsObject = pluginsIt.value().toObject(); + QJsonObject newSettingsObject = ret.value(pluginName).toObject(); + for (auto settingsIt = settingsObject.constBegin(); settingsIt != settingsObject.constEnd(); ++settingsIt) { + newSettingsObject.insert(settingsIt.key(), settingsIt.value()); + } + // TODO: remove not exists key-values + ret.insert(pluginName, newSettingsObject); + } + + return ret; +} + diff --git a/src/modules/dock/docksettings.h b/src/modules/dock/docksettings.h new file mode 100644 index 0000000..6a37f4e --- /dev/null +++ b/src/modules/dock/docksettings.h @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DOCKSETTINGS_H +#define DOCKSETTINGS_H + +#include "common.h" + +#include + +// 隐藏模式 +enum class HideMode { + KeepShowing, + KeepHidden, + SmartHide, + Unknown, +}; + +class HideModeHandler { + HideMode modeEnum; + QString modeStr; + +public: + HideModeHandler(HideMode mode) : modeEnum(mode), modeStr("") {} + HideModeHandler(QString mode) : modeEnum(HideMode::Unknown), modeStr(mode) {} + + bool equal(HideModeHandler hideMode) { + return toString() == hideMode.toString() || toEnum() == hideMode.toEnum(); + } + + QString toString() { + switch (modeEnum) { + case HideMode::KeepShowing: + return "keep-showing"; + case HideMode::KeepHidden: + return "keep-hidden"; + case HideMode::SmartHide: + return "smart-hide"; + case HideMode::Unknown: + default: + return "unknown"; + } + } + + HideMode toEnum() { + if (modeStr == "keep-showing") + return HideMode::KeepHidden; + else if (modeStr == "keep-hidden") + return HideMode::KeepHidden; + else if (modeStr == "smart-hide") + return HideMode::SmartHide; + else + return HideMode::Unknown; + } +}; + +// 显示样式 +enum class DisplayMode { + Fashion, + Efficient, + Unknown, +}; + +class DisplayModeHandler { + DisplayMode modeEnum; + QString modeStr; + +public: + DisplayModeHandler(DisplayMode mode) : modeEnum(mode), modeStr("") {} + DisplayModeHandler(QString mode) : modeEnum(DisplayMode::Unknown), modeStr(mode) {} + + bool equal(DisplayModeHandler displayMode) { + return toString() == displayMode.toString() || toEnum() == displayMode.toEnum(); + } + + QString toString() { + switch (modeEnum) { + case DisplayMode::Fashion: + return "fashion"; + case DisplayMode::Efficient: + return "efficient"; + case DisplayMode::Unknown: + default: + return "unknown"; + } + } + + DisplayMode toEnum() { + if (modeStr == "fashion") + return DisplayMode::Fashion; + else if (modeStr == "efficient") + return DisplayMode::Efficient; + else + return DisplayMode::Unknown; + } +}; + +// 显示位置 +enum class PositonMode { + TOP, + Right, + Bottom, + Left, + Unknown, +}; + +class PositonModeHandler { + PositonMode modeEnum; + QString modeStr; + +public: + PositonModeHandler(PositonMode mode) : modeEnum(mode), modeStr("") {} + PositonModeHandler(QString mode) : modeEnum(PositonMode::Unknown), modeStr(mode) {} + + bool equal(PositonModeHandler displayMode) { + return toString() == displayMode.toString() || toEnum() == displayMode.toEnum(); + } + + QString toString() { + switch (modeEnum) { + case PositonMode::TOP: + return "top"; + case PositonMode::Right: + return "right"; + case PositonMode::Bottom: + return "bottom"; + case PositonMode::Left: + return "left"; + case PositonMode::Unknown: + default: + return "unknown"; + } + } + + PositonMode toEnum() { + if (modeStr == "top") + return PositonMode::TOP; + else if (modeStr == "right") + return PositonMode::Right; + else if (modeStr == "bottom") + return PositonMode::Bottom; + else if (modeStr == "left") + return PositonMode::Left; + else + return PositonMode::Unknown; + } +}; + +// 强制退出应用菜单状态 +enum class ForceQuitAppMode { + Enabled, // 开启 + Disabled, // 关闭 + Deactivated, // 置灰 + Unknown +}; + +class ForceQuitAppModeHandler { + ForceQuitAppMode modeEnum; + QString modeStr; + +public: + ForceQuitAppModeHandler(ForceQuitAppMode mode) : modeEnum(mode), modeStr("") {} + ForceQuitAppModeHandler(QString mode) : modeEnum(ForceQuitAppMode::Unknown), modeStr(mode) {} + + bool equal(ForceQuitAppModeHandler displayMode) { + return toString() == displayMode.toString() || toEnum() == displayMode.toEnum(); + } + + QString toString() { + switch (modeEnum) { + case ForceQuitAppMode::Enabled: + return "enabled"; + case ForceQuitAppMode::Disabled: + return "disabled"; + case ForceQuitAppMode::Deactivated: + return "deactivated"; + case ForceQuitAppMode::Unknown: + default: + return "unknown"; + } + } + + ForceQuitAppMode toEnum() { + if (modeStr == "enabled") + return ForceQuitAppMode::Enabled; + else if (modeStr == "disabled") + return ForceQuitAppMode::Disabled; + else if (modeStr == "deactivated") + return ForceQuitAppMode::Deactivated; + else + return ForceQuitAppMode::Unknown; + } +}; + +class Settings; + +// 任务栏组策略配置类 +class DockSettings: public QObject +{ + Q_OBJECT + +public: + static inline DockSettings *instance() { + static DockSettings instance; + return &instance; + } + void init(); + + HideMode getHideMode(); + void setHideMode(HideMode mode); + DisplayMode getDisplayMode(); + void setDisplayMode(DisplayMode mode); + PositonMode getPositionMode(); + void setPositionMode(PositonMode mode); + ForceQuitAppMode getForceQuitAppMode(); + void setForceQuitAppMode(ForceQuitAppMode mode); + uint getIconSize(); + void setIconSize(uint size); + uint getShowTimeout(); + void setShowTimeout(uint time); + uint getHideTimeout(); + void setHideTimeout(uint time); + uint getWindowSizeEfficient(); + void setWindowSizeEfficient(uint size); + uint getWindowSizeFashion(); + void setWindowSizeFashion(uint size); + QStringList getDockedApps(); + void setDockedApps(QList &apps); + double getOpacity(); + QVector getWinIconPreferredApps(); + + // plugin settings + QString getPluginSettings(); + void setPluginSettings(QString jsonStr); + void mergePluginSettings(QString jsonStr); + void removePluginSettings(QString pluginName, QStringList settingkeys); + QJsonObject plguinSettingsStrToObj(QString jsonStr); + + +Q_SIGNALS: + // 隐藏模式改变 + void hideModeChanged(HideMode mode); + // 显示样式改变 + void displayModeChanged(DisplayMode mode); + // 显示位置改变 + void positionModeChanged(PositonMode mode); + // 强制退出应用开关改变 + void forceQuitAppChanged(bool forced); + + +private: + DockSettings(QObject *paret = nullptr); + DockSettings(const DockSettings &); + DockSettings& operator= (const DockSettings &); +}; + +#endif // DOCKSETTINGS_H diff --git a/src/modules/dock/entries.cpp b/src/modules/dock/entries.cpp new file mode 100644 index 0000000..ae4b15d --- /dev/null +++ b/src/modules/dock/entries.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "entries.h" +#include "dock.h" + +Entries::Entries(Dock *_dock) + : dock(_dock) +{ + +} + +QVector Entries::filterDockedEntries() +{ + QVector ret; + for (auto &entry : items) { + if (entry->isValid() && entry->getIsDocked()) + ret.push_back(entry); + } + + return ret; +} + +Entry *Entries::getByInnerId(QString innerId) +{ + Entry *ret = nullptr; + for (auto &entry : items) { + if (entry->getInnerId() == innerId) + ret = entry; + } + + return ret; +} + +void Entries::append(Entry *entry) +{ + insert(entry, -1); +} + +void Entries::insert(Entry *entry, int index) +{ + if (index < 0 || index >= items.size()) { + // append + items.push_back(entry); + } else { + // insert + items.insert(index, entry); + } + + insertCb(entry, index); +} + +void Entries::remove(Entry *entry) +{ + for (auto iter = items.begin(); iter != items.end(); iter++) { + if ((*iter)->getId() == entry->getId()) { + items.erase(iter); + removeCb(entry); + delete entry; + } + } +} + +void Entries::move(int oldIndex, int newIndex) +{ + if (oldIndex == newIndex || oldIndex < 0 || newIndex < 0 || oldIndex >= items.size() || newIndex >= items.size()) + return; + + items.swap(oldIndex, newIndex); +} + +Entry *Entries::getByWindowPid(int pid) +{ + Entry *ret = nullptr; + for (auto &entry : items) { + if (entry->getWindowInfoByPid(pid)) { + ret = entry; + break; + } + } + + return ret; +} + +Entry *Entries::getByWindowId(XWindow windowId) +{ + Entry *ret = nullptr; + for (auto &entry : items) { + if (entry->getWindowInfoByWinId(windowId)) { + ret = entry; + break; + } + } + + return ret; +} + +Entry *Entries::getByDesktopFilePath(QString filePath) +{ + Entry *ret = nullptr; + for (auto &entry : items) { + if (entry->getFileName() == filePath) { + ret = entry; + break; + } + } + + return ret; +} + +QStringList Entries::getEntryIDs() +{ + QStringList list; + for (auto item : items) + list.push_back(item->getId()); + + return list; +} + +Entry *Entries::getDockedEntryByDesktopFile(const QString &desktopFile) +{ + Entry *ret = nullptr; + for (auto entry : filterDockedEntries()) { + if (!entry->isValid()) + continue; + + if (desktopFile == entry->getFileName()) { + ret = entry; + break; + } + } + + return ret; +} + +QString Entries::queryWindowIdentifyMethod(XWindow windowId) +{ + QString ret; + for (auto entry : items) { + auto window = entry->getWindowInfoByWinId(windowId); + if (window) { + auto app = window->getAppInfo(); + if (app) { + ret = app->getIdentifyMethod(); + } else { + ret = "Failed"; + } + break; + } + } + + return ret; +} + +void Entries::handleActiveWindowChanged(XWindow activeWindId) +{ + for (auto entry : items) { + auto windowInfo = entry->getWindowInfoByWinId(activeWindId); + if (windowInfo) { + entry->setPropIsActive(true); + entry->setCurrentWindowInfo(windowInfo); + entry->updateName(); + entry->updateIcon(); + } else { + entry->setPropIsActive(false); + } + } +} + +void Entries::deleteWindow(XWindow xid) +{ + for (auto entry : items) { + if (entry->containsWindow(xid)) { + entry->deleteWindow(xid); + break; + } + } +} + +void Entries::updateEntriesMenu() +{ + for (auto entry : items) { + entry->updateMenu(); + } +} + +void Entries::insertCb(Entry *entry, int index) +{ + QString objPath = entryDBusObjPathPrefix + entry->getId(); + Q_EMIT dock->entryAdded(objPath, index); +} + +void Entries::removeCb(Entry *entry) +{ + Q_EMIT dock->entryRemoved(entry->getId()); + entry->stopExport(); +} diff --git a/src/modules/dock/entries.h b/src/modules/dock/entries.h new file mode 100644 index 0000000..a4b700c --- /dev/null +++ b/src/modules/dock/entries.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ENTRIES_H +#define ENTRIES_H + +#include "entry.h" +#include +#include + +class Dock; + +// 所有应用管理类 +class Entries +{ +public: + Entries(Dock *_dock); + + QVector filterDockedEntries(); + Entry *getByInnerId(QString innerId); + void append(Entry *entry); + void insert(Entry *entry, int index); + void remove(Entry *entry); + void move(int oldIndex, int newIndex); + Entry *getByWindowPid(int pid); + Entry *getByWindowId(XWindow windowId); + Entry *getByDesktopFilePath(QString filePath); + QStringList getEntryIDs(); + Entry *getDockedEntryByDesktopFile(const QString &desktopFile); + QString queryWindowIdentifyMethod(XWindow windowId); + void handleActiveWindowChanged(XWindow activeWindId); + void deleteWindow(XWindow xid); + void updateEntriesMenu(); + void insertCb(Entry *entry, int index); + void removeCb(Entry *entry); + +private: + QList items; + Dock *dock; +}; + +#endif // ENTRIES_H diff --git a/src/modules/dock/entry.cpp b/src/modules/dock/entry.cpp new file mode 100644 index 0000000..b5c8402 --- /dev/null +++ b/src/modules/dock/entry.cpp @@ -0,0 +1,787 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "entry.h" +#include "dock.h" +#include "processinfo.h" +#include "dbusadaptorentry.h" + +#include +#include + +#include + +Entry::Entry(Dock *_dock, AppInfo *_app, QString _innerId, QObject *parent) + : QObject(parent) + , dock(_dock) + , app(nullptr) + , menu(nullptr) + , isActive(false) + , isDocked(false) + , innerId(_innerId) + , current(nullptr) + , currentWindow(0) + , winIconPreferred(false) +{ + setApp(_app); + id = dock->allocEntryId(); + name = getName(); + icon = getIcon(); +} + +Entry::~Entry() +{ + for (auto winInfo : windowInfos) { + if (winInfo) + delete winInfo; + } + windowInfos.clear(); + + if (app) { + delete app; + app = nullptr; + } + + if (menu) { + delete menu; + menu = nullptr; + } +} + +bool Entry::isValid() +{ + bool valid = false; + if (app) + valid = app->isValidApp(); + + return valid; +} + +QString Entry::getId() +{ + return id; +} + +QString Entry::getName() +{ + QString ret; + if (app) + ret = app->getName(); + + if (ret.isEmpty() && !!current) + ret = current->getDisplayName(); + + return ret; +} + +void Entry::updateName() +{ + setPropName(getName()); +} + +QString Entry::getIcon() +{ + QString ret; + if (hasWindow()) { + if (!current) + return ret; + + // has window && current not nullptr + if (winIconPreferred) { + // try current window icon first + ret = current->getIcon(); + if (ret.size() > 0) + return ret; + } + + if (app) { + icon = app->getIcon(); + if (icon.size() > 0) + return ret; + } + ret = current->getIcon(); + } else if (app) { + // no window + ret = app->getIcon(); + } + + return ret; +} + +QString Entry::getInnerId() +{ + return innerId; +} + +void Entry::setInnerId(QString _innerId) +{ + innerId = _innerId; +} + +QString Entry::getFileName() +{ + QString fileName; + if (app) + fileName = app->getFileName(); + + return fileName; +} + +AppInfo *Entry::getApp() +{ + return app; +} + +void Entry::setApp(AppInfo *appinfo) +{ + if (app == appinfo) + return; + + if (app) + delete app; + + app = appinfo; + if (!appinfo) { + winIconPreferred = true; + setPropDesktopFile(""); + } else { + winIconPreferred = false; + setPropDesktopFile(appinfo->getFileName()); + QString id = app->getId(); + auto perferredApps = dock->getWinIconPreferredApps(); + if (perferredApps.contains(id)) { + winIconPreferred = true; + return; + } + + if (appinfo->getIcon().size() == 0) { + winIconPreferred = true; + } + } +} + +bool Entry::getIsDocked() +{ + return isDocked; +} + +void Entry::setIsDocked(bool value) +{ + if (value != isDocked) { + isDocked = value; + Q_EMIT isDockedChanged(value); + } +} + +// 导出Dbus服务 +void Entry::startExport() +{ + if (getId().isEmpty()) { + qWarning() << "startExport Entry " << getName() << " id is Empty"; + return; + } + + new DBusAdaptorEntry(this); // export dbus by Adaptor + QDBusConnection con = QDBusConnection::sessionBus(); + if (!con.registerService(dbusService)) { + qWarning() << "register service Dock1 error:" << con.lastError().message(); + return; + } + + objctPath = entryDBusObjPathPrefix + getId(); + if (!con.registerObject(objctPath, this)) + { + qWarning() << "register object Dock1 error:" << con.lastError().message(); + return; + } +} + +// 停止导出Dbus服务 +void Entry::stopExport() +{ + if (getId().isEmpty()) { + qWarning() << "stopExport Entry " << getName() << " id is Empty"; + return; + } + + QDBusConnection con = QDBusConnection::sessionBus(); + objctPath.clear(); + con.unregisterObject(entryDBusObjPathPrefix + getId()); +} + +void Entry::setMenu(AppMenu *_menu) +{ + _menu->setDirtyStatus(true); + if (menu) + delete menu; + + menu = _menu; + Q_EMIT menuChanged(menu->getMenuJsonStr()); +} + +void Entry::updateMenu() +{ + qInfo() <<"Entry: updateMenu"; + AppMenu *appMenu = new AppMenu(); + appMenu->appendItem(getMenuItemLaunch()); + + for (auto &item :getMenuItemDesktopActions()) + appMenu->appendItem(item); + + bool hasWin = hasWindow(); + if (hasWin) + appMenu->appendItem(getMenuItemAllWindows()); + + // menu item dock or undock + qInfo() << "entry " << id << " docked? " << isDocked; + if (isDocked) + appMenu->appendItem(getMenuItemUndock()); + else + appMenu->appendItem(getMenuItemDock()); + + if (hasWindow()) { + if (dock->getForceQuitAppStatus() != ForceQuitAppMode::Disabled) { + if (app && app->getIdentifyMethod() == "Andriod") + appMenu->appendItem(getMenuItemForceQuitAndroid()); + else + appMenu->appendItem(getMenuItemForceQuit()); + } + + if (getAllowedCloseWindows().size() > 0) + appMenu->appendItem(getMenuItemCloseAll()); + } + setMenu(appMenu); +} + +void Entry::updateIcon() +{ + setPropIcon(getIcon()); +} + +void Entry::forceUpdateIcon() +{ + icon = getIcon(); + Q_EMIT iconChanged(icon); +} + +void Entry::updateIsActive() +{ + bool isActive = false; + auto activeWin = dock->getActiveWindow(); + if (activeWin) + isActive = windowInfos.find(activeWin->getXid()) != windowInfos.end(); + + setPropIsActive(isActive); +} + +WindowInfoBase *Entry::getWindowInfoByPid(int pid) +{ + WindowInfoBase *ret = nullptr; + for (const auto &windowInfo : windowInfos) { + if (windowInfo->getPid() == pid) { + ret = windowInfo; + break; + } + } + + return ret; +} + +WindowInfoBase *Entry::getWindowInfoByWinId(XWindow windowId) +{ + WindowInfoBase *ret = nullptr; + if (windowInfos.find(windowId) != windowInfos.end()) { + ret = windowInfos[windowId]; + } + + return ret; +} + +void Entry::setPropIsDocked(bool docked) +{ + if (isDocked != docked) { + isDocked = docked; + Q_EMIT isDockedChanged(docked); + } +} + +void Entry::setPropIcon(QString value) +{ + if (value != icon) { + icon = value; + Q_EMIT iconChanged(value); + } +} + +void Entry::setPropName(QString value) +{ + if (value != name) { + name = value; + Q_EMIT nameChanged(value); + } +} + +void Entry::setPropIsActive(bool active) +{ + if (isActive != active) { + isActive = active; + Q_EMIT isActiveChanged(active); + } +} + +void Entry::setCurrentWindowInfo(WindowInfoBase *windowInfo) +{ + current = windowInfo; + setPropCurrentWindow(current ? current->getXid() : 0); +} + +void Entry::setPropCurrentWindow(XWindow value) +{ + if (value != currentWindow) { + currentWindow = value; + Q_EMIT currentWindowChanged(value); + } +} + +WindowInfoBase *Entry::getCurrentWindowInfo() +{ + return current; +} + +QString Entry::getExec(bool oneLine) +{ + QString ret; + if (!current) + return ret; + + ProcessInfo *process = current->getProcess(); + if (process) { + if (oneLine) + ret = process->getOneCommandLine().c_str(); + else + ret = process->getShellScriptLines().c_str(); + } + + return ret; +} + +bool Entry::hasWindow() +{ + return windowInfos.size() > 0; +} + +void Entry::updateWindowInfos() +{ + QList infos; + bool changed = false; + for (auto info : windowInfos) { + XWindow xid = info->getXid(); + QString title = info->getTitle(); + bool flash = info->isDemandingAttention(); + infos.push_back({xid, title, flash}); + if (!changed) { + for (auto info : exportWindowInfos) { + if (info.title != title || info.flash != flash) + changed = true; + } + } + } + + if (changed) { + exportWindowInfos = infos; + } +} + +// 分离窗口, 返回是否需要从任务栏remove +bool Entry::detachWindow(WindowInfoBase *info) +{ + info->setEntry(nullptr); + XWindow winId = info->getXid(); + deleteWindow(winId); + + if (windowInfos.size() == 0) { + if (!isDocked) // 既无窗口也非驻留应用,无需在任务栏显示 + return true; + + setCurrentWindowInfo(nullptr); + } else { + for (auto window : windowInfos) { + if (window) { // 选择第一个窗口作为当前窗口 + setCurrentWindowInfo(window); + break; + } + } + } + + updateWindowInfos(); + updateIcon(); + updateIsActive(); + updateMenu(); + + return false; +} + +bool Entry::attachWindow(WindowInfoBase *info) +{ + XWindow winId = info->getXid(); + qInfo() << "attatchWindow: window id:" << winId; + info->setEntry(this); + + if (windowInfos.find(winId) != windowInfos.end()) { + qInfo() << "attachWindow: window " << winId << " is already attached"; + return false; + } + + windowInfos[winId] = info; + updateWindowInfos(); + updateIsActive(); + + if (!current) { + // from no window to has window + setCurrentWindowInfo(info); + } + + updateIcon(); + updateMenu(); + return true; +} + +void Entry::launchApp(uint32_t timestamp) +{ + dock->launchApp(timestamp, QStringList() << app->getFileName()); +} + +bool Entry::containsWindow(XWindow xid) +{ + return windowInfos.find(xid) != windowInfos.end(); +} + +void Entry::deleteWindow(XWindow xid) +{ + WindowInfoBase *info = windowInfos[xid]; + windowInfos.remove(xid); + for (int i = 0; i < exportWindowInfos.size(); i++) { + if (exportWindowInfos[i].xid == xid) { + exportWindowInfos.removeAt(i); + break; + } + } + + if (info) { + delete info; + } +} + +// 处理菜单项 +void Entry::handleMenuItem(uint32_t timestamp, QString itemId) +{ + menu->handleAction(timestamp, itemId); +} + +// 处理拖拽事件 +void Entry::handleDragDrop(uint32_t timestamp, QStringList files) +{ + dock->launchApp(timestamp, files); +} + +// 驻留 +void Entry::requestDock() +{ + if (dock->dockEntry(this)) { + dock->saveDockedApps(); + } +} + +// 取消驻留 +void Entry::requestUndock() +{ + dock->undockEntry(this); +} + +void Entry::newInstance(uint32_t timestamp) +{ + QStringList files; + dock->launchApp(timestamp, files); +} + +// 检查应用窗口分离、合并状态 +void Entry::check() +{ + for (auto iter = windowInfos.begin(); iter != windowInfos.end(); iter++) { + dock->attachOrDetachWindow(iter.value()); + } +} + +// 强制退出 +void Entry::forceQuit() +{ + QMap> pidWinInfoMap; + for (auto iter = windowInfos.begin(); iter != windowInfos.end(); iter++) { + int pid = iter.value()->getPid(); + if (pid != 0) { + pidWinInfoMap[pid].push_back(iter.value()); + } else { + iter.value()->killClient(); + } + + for (auto iter = pidWinInfoMap.begin(); iter != pidWinInfoMap.end(); iter++) { + if (!killProcess(iter.key())) { // kill pid + for (auto &info : iter.value()) { // kill window + info->killClient(); + } + } + } + } +} + +void Entry::presentWindows() +{ + QList windows; + for (auto iter = windowInfos.begin(); iter != windowInfos.end(); iter++) + windows.push_back(iter.key()); + + dock->presentWindows(windows); +} + +void Entry::active(uint32_t timestamp) +{ + +} + +XWindow Entry::getCurrentWindow() +{ + return currentWindow; +} + +QString Entry::getDesktopFile() +{ + return desktopFile; +} + +bool Entry::getIsActive() +{ + return isActive; +} + +QString Entry::getMenu() +{ + return menu->getMenuJsonStr(); +} + +QVector Entry::getAllowedClosedWindowIds() +{ + QVector ret; + for (auto iter = windowInfos.begin(); iter != windowInfos.end(); iter++) { + WindowInfoBase *info = iter.value(); + if (info && info->allowClose()) + ret.push_back(iter.key()); + } + + return ret; +} + +QList Entry::getExportWindowInfos() +{ + return exportWindowInfos; +} + +QVector Entry::getAllowedCloseWindows() +{ + QVector ret; + for (auto iter = windowInfos.begin(); iter != windowInfos.end(); iter++) { + WindowInfoBase *info = iter.value(); + if (info && info->allowClose()) + ret.push_back(info); + } + + return ret; +} + +QVector Entry::getMenuItemDesktopActions() +{ + QVector ret; + if (!app) + return ret; + + for (auto action : app->getActions()) { + AppMenuAction fn = [&](uint32_t timestamp) { + qInfo() << "do MenuItem: " << action.name.c_str(); + dock->launchAppAction(timestamp, app->getFileName(), action.section.c_str()); + }; + + AppMenuItem item; + item.text = action.name.c_str(); + item.action = fn; + item.isActive = true; + ret.push_back(item); + } + + return ret; +} + +AppMenuItem Entry::getMenuItemLaunch() +{ + QString itemName; + if (hasWindow()) + itemName = getName(); + else + itemName = "Open"; + + AppMenuAction fn = [&](uint32_t timestamp) { + qInfo() << "do MenuItem: Open"; + this->launchApp(timestamp); + }; + + AppMenuItem item; + item.text = itemName; + item.action = fn; + item.isActive = true; + return item; +} + +AppMenuItem Entry::getMenuItemCloseAll() +{ + AppMenuAction fn = [&](uint32_t timestamp) { + qInfo() << "do MenuItem: Close All"; + auto winInfos = getAllowedCloseWindows(); + + // 从大到小排序, 方便后面关闭窗口 + for (int i = 0; i < winInfos.size() - 1; i++) { + for (int j = i + 1; j < winInfos.size(); j++) { + if (winInfos[i]->getCreatedTime() < winInfos[j]->getCreatedTime()) { + auto info = winInfos[i]; + winInfos[i] = winInfos[j]; + winInfos[j] = info; + } + } + } + + for (auto info : winInfos) { + qInfo() << "close WindowId " << info->getXid(); + info->close(timestamp); + } + }; + + AppMenuItem item; + item.text = "Close All"; + item.action = fn; + item.isActive = true; + return item; +} + +AppMenuItem Entry::getMenuItemForceQuit() +{ + bool active = dock->getForceQuitAppStatus() != ForceQuitAppMode::Deactivated; + AppMenuAction fn = [&](uint32_t) { + qInfo() << "do MenuItem: Force Quit"; + forceQuit(); + }; + + AppMenuItem item; + item.text = "Force Quit"; + item.action = fn; + item.isActive = active; + return item; +} + +//dock栏上Android程序的Force Quit功能 +AppMenuItem Entry::getMenuItemForceQuitAndroid() +{ + bool active = dock->getForceQuitAppStatus() != ForceQuitAppMode::Deactivated; + auto allowedCloseWindows = getAllowedCloseWindows(); + AppMenuAction fn = [](uint32_t){}; + if (allowedCloseWindows.size() > 0) { + qInfo() << "do MenuItem: Force Quit"; + AppMenuAction fn = [&](uint32_t timestamp) { + for (auto info : allowedCloseWindows) { + info->close(timestamp); + } + }; + } + + AppMenuItem item; + item.text = "Force Quit"; + item.action = fn; + item.isActive = active; + return item; +} + +AppMenuItem Entry::getMenuItemDock() +{ + AppMenuItem item; + item.text = "Dock"; + item.action = [&](uint32_t) { + qInfo() << "do MenuItem: Dock"; + requestDock(); + }; + item.isActive = true; + return item; +} + +AppMenuItem Entry::getMenuItemUndock() +{ + AppMenuItem item; + item.text = "Undock"; + item.action = [&](uint32_t) { + qInfo() << "do MenuItem: Undock"; + requestUndock(); + }; + item.isActive = true; + return item; +} + +AppMenuItem Entry::getMenuItemAllWindows() +{ + AppMenuItem item; + item.text = "All Windows"; + item.action = [&](uint32_t) { + qInfo() << "do MenuItem: All Windows"; + presentWindows(); + }; + item.isActive = true; + item.hint = menuItemHintShowAllWindows; + return item; +} + +bool Entry::killProcess(int pid) +{ + bool ret = true; + Process p(pid); + if (p.isExist()) { + ret = !kill(pid, SIGTERM); + } + + return ret; +} + +bool Entry::setPropDesktopFile(QString value) +{ + bool ret = false; + if (value != desktopFile) { + desktopFile = value; + ret = true; + Q_EMIT desktopFileChanged(value); + } + return ret; +} + + + diff --git a/src/modules/dock/entry.h b/src/modules/dock/entry.h new file mode 100644 index 0000000..8d0462a --- /dev/null +++ b/src/modules/dock/entry.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ENTRY_H +#define ENTRY_H + +#include "appinfo.h" +#include "appmenu.h" +#include "windowinfobase.h" + +#include +#include +#include + +struct ExportWindowInfo { + XWindow xid; + QString title; + bool flash; +}; + +// 单个应用类 +class Dock; +class Entry: public QObject +{ + Q_OBJECT +public: + Entry(Dock *_dock, AppInfo *_app, QString _innerId, QObject *parent = nullptr); + ~Entry(); + + bool isValid(); + QString getId(); + QString getName(); + void updateName(); + QString getIcon(); + QString getInnerId(); + void setInnerId(QString _innerId); + QString getFileName(); + AppInfo *getApp(); + void setApp(AppInfo *appinfo); + bool getIsDocked(); + void setIsDocked(bool value); + void startExport(); + void stopExport(); + void setMenu(AppMenu *_menu); + void updateMenu(); + void updateIcon(); + void forceUpdateIcon(); + void updateIsActive(); + WindowInfoBase *getWindowInfoByPid(int pid); + WindowInfoBase *getWindowInfoByWinId(XWindow windowId); + void setPropIsDocked(bool docked); + void setPropIcon(QString value); + void setPropName(QString value); + void setPropIsActive(bool active); + void setPropCurrentWindow(XWindow value); + void setCurrentWindowInfo(WindowInfoBase *windowInfo); + WindowInfoBase *getCurrentWindowInfo(); + QString getExec(bool oneLine); + bool hasWindow(); + void updateWindowInfos(); + bool detachWindow(WindowInfoBase *info); + bool attachWindow(WindowInfoBase *info); + void launchApp(uint32_t timestamp); + bool containsWindow(XWindow xid); + void deleteWindow(XWindow xid); + + void handleMenuItem(uint32_t timestamp, QString itemId); + void handleDragDrop(uint32_t timestamp, QStringList files); + void requestDock(); + void requestUndock(); + void newInstance(uint32_t timestamp); + void check(); + void forceQuit(); + void presentWindows(); + void active(uint32_t timestamp); + + XWindow getCurrentWindow(); + QString getDesktopFile(); + bool getIsActive(); + QString getMenu(); + QVector getAllowedClosedWindowIds(); + QList getExportWindowInfos(); + +public Q_SLOTS: + QVector getAllowedCloseWindows(); + +Q_SIGNALS: + void isActiveChanged(bool value); + void isDockedChanged(bool value); + void menuChanged(QString value); + void iconChanged(QString value); + void nameChanged(QString value); + void desktopFileChanged(QString value); + void currentWindowChanged(uint32_t value); + +private: + // 右键菜单项 + QVector getMenuItemDesktopActions(); + AppMenuItem getMenuItemLaunch(); + AppMenuItem getMenuItemCloseAll(); + AppMenuItem getMenuItemForceQuit(); + AppMenuItem getMenuItemForceQuitAndroid(); + AppMenuItem getMenuItemDock(); + AppMenuItem getMenuItemUndock(); + AppMenuItem getMenuItemAllWindows(); + bool killProcess(int pid); + bool setPropDesktopFile(QString value); + + Dock *dock; + AppInfo *app; + AppMenu *menu; + + bool isActive; + bool isDocked; + + QString id; + QString name; + QString icon; + QString innerId; + QString desktopFile; + + // Dbus属性直接放到interface上 + QMap windowInfos; // 该应用所有窗口 + QList exportWindowInfos; + WindowInfoBase *current; // 当前窗口 + XWindow currentWindow; //当前窗口Id + bool winIconPreferred; + QString objctPath; +}; + +#endif // ENTRY_H diff --git a/src/modules/dock/processinfo.cpp b/src/modules/dock/processinfo.cpp new file mode 100644 index 0000000..10ceb81 --- /dev/null +++ b/src/modules/dock/processinfo.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "processinfo.h" +#include "dstring.h" +#include "dfile.h" + +ProcessInfo::ProcessInfo(int pid) + : hasPid(true) + , process(Process(pid)) +{ + if (pid == 0) + return; + + // exe + exe = process.getExe(); + // cwd + cwd = process.getCwd(); + // cmdline + cmdLine = process.getCmdLine(); + // ppid + Status pstatus = process.getStatus(); + if (pstatus.size() > 0) { + int ppid = process.getPpid(); + } + // args + auto verifyExe = [](std::string exe, std::string cwd, std::string firstArg){ + if (DFile::base(firstArg) == firstArg) + return true; + + if (!DFile::isAbs(firstArg)) + firstArg = cwd + firstArg; + + return exe == firstArg; + }; + if (!verifyExe(exe, cwd, cmdLine[0])) { + auto parts = DString::splitStr(cmdLine[0], ' '); + // try again + if (verifyExe(exe, cwd, parts[0])) { + for (int j = 1; j < parts.size(); j++) { + args.push_back(parts[j]); + } + for (int i = 1; i < cmdLine.size(); i++) { + args.push_back(cmdLine[i]); + } + } + } else { + for (int i = 1; i < cmdLine.size(); i++) { + args.push_back(cmdLine[i]); + } + } +} + +ProcessInfo::ProcessInfo(std::vector &cmd) + : hasPid(false) + , process(Process()) +{ + if (cmd.size() == 0) + return; + + cmdLine = cmd; + exe = cmd[0]; + for (ulong i=0; i < cmd.size(); i++) { + if (i > 0) { + args.push_back(cmd[i]); + } + } +} + +std::string ProcessInfo::getEnv(std::string key) +{ + return process.getEnv(key); +} + +std::vector ProcessInfo::getCmdLine() +{ + return cmdLine; +} + +std::vector ProcessInfo::getArgs() +{ + return args; +} + +int ProcessInfo::getPid() +{ + return process.getPid(); +} + +int ProcessInfo::getPpid() +{ + return process.getPpid(); +} + +std::string ProcessInfo::getExe() +{ + return exe; +} + +std::string ProcessInfo::getOneCommandLine() +{ + std::string cmdline = getJoinedExeArgs(); + return "sh -c 'cd " + cwd + "; exec " + cmdline + ";'"; +} + +std::string ProcessInfo::getShellScriptLines() +{ + std::string cmdline = getJoinedExeArgs(); + return "#!/bin/sh\n cd " + cwd + "\n exec " + cmdline + "\n"; +} + +std::string ProcessInfo::getJoinedExeArgs() +{ + std::string ret = "\"" + exe + "\""; + for (auto arg : args) { + ret += " \"" + arg + "\""; + } + + ret += " $@"; + return ret; +} + + diff --git a/src/modules/dock/processinfo.h b/src/modules/dock/processinfo.h new file mode 100644 index 0000000..ab526fd --- /dev/null +++ b/src/modules/dock/processinfo.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PROCESSINFO_H +#define PROCESSINFO_H + +#include "process.h" + +#include +#include + +// 进程信息 +class ProcessInfo +{ +public: + ProcessInfo(int pid); + ProcessInfo(std::vector &cmd); + + std::string getEnv(std::string key); + std::vector getCmdLine(); + std::vector getArgs(); + int getPid(); + int getPpid(); + std::string getExe(); + std::string getOneCommandLine(); + std::string getShellScriptLines(); + +private: + std::string getJoinedExeArgs(); + + std::vector cmdLine; + std::vector args; + std::string exe; + std::string cwd; + + bool hasPid; + Process process; +}; + +#endif // PROCESSINFO_H diff --git a/src/modules/dock/waylandmanager.cpp b/src/modules/dock/waylandmanager.cpp new file mode 100644 index 0000000..4e74711 --- /dev/null +++ b/src/modules/dock/waylandmanager.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "waylandmanager.h" +#include "dock.h" +#include "xcbutils.h" + +#define XCB XCBUtils::instance() + +WaylandManager::WaylandManager(Dock *_dock, QObject *parent) + : QObject(parent) + , dock(_dock) + , mutex(QMutex(QMutex::NonRecursive)) +{ + +} + + +// 注册窗口 +void WaylandManager::registerWindow(const QString &objPath) +{ + qInfo() << "registerWindow: " << objPath; + if (findWindowByObjPath(objPath)) + return; + + PlasmaWindow *plasmaWindow = dock->createPlasmaWindow(objPath); + if (!plasmaWindow) { + qWarning() << "registerWindowWayland: createPlasmaWindow failed"; + return; + } + + QString appId = plasmaWindow->AppId(); + QStringList list {"dde-dock", "dde-launcher", "dde-clipboard", "dde-osd", "dde-polkit-agent", "dde-simple-egl", "dmcs"}; + if (list.indexOf(appId)) + return; + + XWindow winId = XCB->allocId(); // XCB中未发现释放XID接口 + XWindow realId = plasmaWindow->WindowId(); + if (!realId) + winId = realId; + + WindowInfoK *winInfo = new WindowInfoK(plasmaWindow, winId); + dock->listenKWindowSignals(winInfo); + insertWindow(objPath, winInfo); + dock->attachOrDetachWindow(winInfo); + if (realId) { + windowInfoMap[realId] = winInfo; + } +} + +// 取消注册窗口 +void WaylandManager::unRegisterWindow(const QString &objPath) +{ + qInfo() << "unRegisterWindow: " << objPath; + WindowInfoK *winInfo = findWindowByObjPath(objPath); + if (!winInfo) + return; + + dock->removePlasmaWindowHandler(winInfo->getPlasmaWindow()); + dock->detachWindow(winInfo); + deleteWindow(objPath); +} + +WindowInfoK *WaylandManager::handleActiveWindowChangedK(uint activeWin) +{ + WindowInfoK *winInfo = nullptr; + QMutexLocker locker(&mutex); + for (auto iter = kWinInfos.begin(); iter != kWinInfos.end(); iter++) { + if (iter.value()->getInnerId() == activeWin) { + winInfo = iter.value(); + break; + } + } + + return winInfo; +} + +WindowInfoK *WaylandManager::findWindowByXid(XWindow xid) +{ + WindowInfoK *winInfo = nullptr; + for (auto iter = kWinInfos.begin(); iter != kWinInfos.end(); iter++) { + if (iter.value()->getXid() == xid) { + winInfo = iter.value(); + break; + } + } + + return winInfo; +} + +WindowInfoK *WaylandManager::findWindowByObjPath(QString objPath) +{ + if (kWinInfos.find(objPath) == kWinInfos.end()) + return nullptr; + + return kWinInfos[objPath]; +} + +void WaylandManager::insertWindow(QString objPath, WindowInfoK *windowInfo) +{ + QMutexLocker locker(&mutex); + kWinInfos[objPath] = windowInfo; +} + +void WaylandManager::deleteWindow(QString objPath) +{ + kWinInfos.remove(objPath); +} + diff --git a/src/modules/dock/waylandmanager.h b/src/modules/dock/waylandmanager.h new file mode 100644 index 0000000..1c09720 --- /dev/null +++ b/src/modules/dock/waylandmanager.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef WAYLANDMANAGER_H +#define WAYLANDMANAGER_H + +#include "windowinfok.h" + +#include +#include +#include + +class Dock; + +// 管理wayland窗口 +class WaylandManager : public QObject +{ + Q_OBJECT +public: + explicit WaylandManager(Dock *_dock, QObject *parent = nullptr); + + void registerWindow(const QString &objPath); + void unRegisterWindow(const QString &objPath); + + WindowInfoK *handleActiveWindowChangedK(uint activeWin); + WindowInfoK *findWindowByXid(XWindow xid); + WindowInfoK *findWindowByObjPath(QString objPath); + void insertWindow(QString objPath, WindowInfoK *windowInfo); + void deleteWindow(QString objPath); + +private: + Dock *dock; + QMap kWinInfos; // dbusObjectPath -> kwayland window Info + QMap windowInfoMap; + QMutex mutex; +}; + +#endif // WAYLANDMANAGER_H diff --git a/src/modules/dock/windowidentify.cpp b/src/modules/dock/windowidentify.cpp new file mode 100644 index 0000000..c622ba5 --- /dev/null +++ b/src/modules/dock/windowidentify.cpp @@ -0,0 +1,545 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "windowidentify.h" +#include "common.h" +#include "appinfo.h" +#include "dock.h" +#include "processinfo.h" +#include "dstring.h" +#include "basedir.h" +#include "dfile.h" +#include "xcbutils.h" + +#include +#include + +#define XCB XCBUtils::instance() + +WindowPatterns WindowIdentify::patterns; + +static QMap crxAppIdMap = { + {"crx_onfalgmmmaighfmjgegnamdjmhpjpgpi", "apps.com.aiqiyi"}, + {"crx_gfhkopakpiiaeocgofdpcpjpdiglpkjl", "apps.cn.kugou.hd"}, + {"crx_gaoopbnflngfkoobibfgbhobdeiipcgh", "apps.cn.kuwo.kwmusic"}, + {"crx_jajaphleehpmpblokgighfjneejapnok", "apps.com.evernote"}, + {"crx_ebhffdbfjilfhahiinoijchmlceailfn", "apps.com.letv"}, + {"crx_almpoflgiciaanepplakjdkiaijmklld", "apps.com.tongyong.xxbox"}, + {"crx_heaphplipeblmpflpdcedfllmbehonfo", "apps.com.peashooter"}, + {"crx_dbngidmdhcooejaggjiochbafiaefndn", "apps.com.rovio.angrybirdsseasons"}, + {"crx_chfeacahlaknlmjhiagghobhkollfhip", "apps.com.sina.weibo"}, + {"crx_cpbmecbkmjjfemjiekledmejoakfkpec", "apps.com.openapp"}, + {"crx_lalomppgkdieklbppclocckjpibnlpjc", "apps.com.baidutieba"}, + {"crx_gejbkhjjmicgnhcdpgpggboldigfhgli", "apps.com.zhuishushenqi"}, + {"crx_gglenfcpioacendmikabbkecnfpanegk", "apps.com.duokan"}, + {"crx_nkmmgdfgabhefacpfdabadjfnpffhpio", "apps.com.zhihu.daily"}, + {"crx_ajkogonhhcighbinfgcgnjiadodpdicb", "apps.com.netease.newsreader"}, + {"crx_hgggjnaaklhemplabjhgpodlcnndhppo", "apps.com.baidu.music.pad"}, + {"crx_ebmgfebnlgilhandilnbmgadajhkkmob", "apps.cn.ibuka"}, + {"crx_nolebplcbgieabkblgiaacdpgehlopag", "apps.com.tianqitong"}, + {"crx_maghncnmccfbmkekccpmkjjfcmdnnlip", "apps.com.youjoy.strugglelandlord"}, + {"crx_heliimhfjgfabpgfecgdhackhelmocic", "apps.cn.emoney"}, + {"crx_jkgmneeafmgjillhgmjbaipnakfiidpm", "apps.com.instagram"}, + {"crx_cdbkhmfmikobpndfhiphdbkjklbmnakg", "apps.com.easymindmap"}, + {"crx_djflcciklfljleibeinjmjdnmenkciab", "apps.com.lgj.thunderbattle"}, + {"crx_ffdgbolnndgeflkapnmoefhjhkeilfff", "apps.com.qianlong"}, + {"crx_fmpniepgiofckbfgahajldgoelogdoap", "apps.com.windhd"}, + {"crx_dokjmallmkihbgefmladclcdcinjlnpj", "apps.com.youdao.hanyu"}, + {"crx_dicimeimfmbfcklbjdpnlmjgegcfilhm", "apps.com.ibookstar"}, + {"crx_cokkcjnpjfffianjbpjbcgjefningkjm", "apps.com.yidianzixun"}, + {"crx_ehflkacdpmeehailmcknlnkmjalehdah", "apps.com.xplane"}, + {"crx_iedokjbbjejfinokgifgecmboncmkbhb", "apps.com.wedevote"}, + {"crx_eaefcagiihjpndconigdpdmcbpcamaok", "apps.com.tongwei.blockbreaker"}, + {"crx_mkjjfibpccammnliaalefmlekiiikikj", "apps.com.dayima"}, + {"crx_gflkpppiigdigkemnjlonilmglokliol", "apps.com.cookpad"}, + {"crx_jfhpkchgedddadekfeganigbenbfaohe", "apps.com.issuu"}, + {"crx_ggkmfnbkldhmkehabgcbnmlccfbnoldo", "apps.bible.cbol"}, + {"crx_phlhkholfcljapmcidanddmhpcphlfng", "apps.com.kanjian.radio"}, + {"crx_bjgfcighhaahojkibojkdmpdihhcehfm", "apps.de.danoeh.antennapod"}, + {"crx_kldipknjommdfkifomkmcpbcnpmcnbfi", "apps.com.asoftmurmur"}, + {"crx_jfhlegimcipljdcionjbipealofoncmd", "apps.com.tencentnews"}, + {"crx_aikgmfkpmmclmpooohngmcdimgcocoaj", "apps.com.tonghuashun"}, + {"crx_ifimglalpdeoaffjmmihoofapmpflkad", "apps.com.letv.lecloud.disk"}, + {"crx_pllcekmbablpiogkinogefpdjkmgicbp", "apps.com.hwadzanebook"}, + {"crx_ohcknkkbjmgdfcejpbmhjbohnepcagkc", "apps.com.douban.radio"}, +}; + +WindowIdentify::WindowIdentify(Dock *_dock, QObject *parent) + : QObject(parent) + , dock(_dock) +{ + identifyWindowFuns["Android"] = identifyWindowAndroid; + identifyWindowFuns["PidEnv"] = identifyWindowByPidEnv; + identifyWindowFuns["CmdlineTurboBooster"] = identifyWindowByCmdlineTurboBooster; + identifyWindowFuns["Cmdline-XWalk"] = identifyWindowByCmdlineXWalk; + identifyWindowFuns["FlatpakAppID"] = identifyWindowByFlatpakAppID; + identifyWindowFuns["CrxId"] = identifyWindowByCrxId; + identifyWindowFuns["Rule"] = identifyWindowByRule; + identifyWindowFuns["Bamf"] = identifyWindowByBamf; + identifyWindowFuns["Pid"] = identifyWindowByPid; + identifyWindowFuns["Scratch"] = identifyWindowByScratch; + identifyWindowFuns["GtkAppId"] = identifyWindowByGtkAppId; + identifyWindowFuns["WmClass"] = identifyWindowByWmClass; + +} + +AppInfo *WindowIdentify::identifyWindow(WindowInfoBase *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + //qInfo() << "identifyWindow: window id " << winInfo->getXid() << " innerId " << winInfo->getInnerId(); + if (winInfo->getWindowType() == "X11") + ret = identifyWindowX11(static_cast(winInfo), innerId); + else if (winInfo->getWindowType() == "Wayland") + ret = identifyWindowWayland(static_cast(winInfo), innerId); + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowX11(WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *appInfo = nullptr; + if (winInfo->getInnerId() == "") { + qInfo() << "identify WindowX11: innerId is empty"; + return appInfo; + } + + for (auto iter = identifyWindowFuns.begin(); iter != identifyWindowFuns.end(); iter++) { + QString name = iter.key(); + IdentifyFunc func = iter.value(); + qInfo() << "identifyWindowX11: try " << name; + appInfo = func(dock, winInfo, innerId); + if (appInfo) { // TODO: if name == "Pid", appInfo may by nullptr + // 识别成功 + qInfo() << "identify Window by " << name << " innerId " << appInfo->getInnerId() << " success!"; + AppInfo *fixedAppInfo = fixAutostartAppInfo(appInfo->getFileName()); + if (fixedAppInfo) { + delete appInfo; + appInfo = fixedAppInfo; + appInfo->setIdentifyMethod(name + "+FixAutostart"); + innerId = appInfo->getInnerId(); + } else { + appInfo->setIdentifyMethod(name); + } + return appInfo; + } + } + + qInfo() << "identifyWindowX11: failed"; + return appInfo; +} + +AppInfo *WindowIdentify::identifyWindowWayland(WindowInfoK *winInfo, QString &innerId) +{ + // TODO: 对桌面调起的文管应用做规避处理,需要在此处添加,因为初始化时appId和title为空 + if (winInfo->getAppId() == "dde-desktop" && dock->shouldShowOnDock(winInfo)) { + winInfo->setAppId("dde-file-manager"); + } + + QString appId = winInfo->getAppId(); + if (appId.isEmpty()) { + QString title = winInfo->getTitle(); + // TODO: 对于appId为空的情况,使用title过滤,此项修改针对浏览器下载窗口 + + } + + // 先使用appId获取appInfo,如果不能成功获取再使用GIO_LAUNCHED_DESKTOP_FILE环境变量获取 + AppInfo *appInfo = new AppInfo(appId); + if (!appInfo->isValidApp() && winInfo->getProcess()) { + ProcessInfo *process = winInfo->getProcess(); + std::string desktopFilePath = process->getEnv("GIO_LAUNCHED_DESKTOP_FILE"); + if (DString::endWith(desktopFilePath, ".desktop")) { + appInfo = new AppInfo(desktopFilePath.c_str()); + } + } + + // autoStart + if (appInfo->isValidApp()) { + AppInfo *fixedAppInfo = fixAutostartAppInfo(appInfo->getFileName()); + if (fixedAppInfo) { + delete appInfo; + appInfo = fixedAppInfo; + appInfo->setIdentifyMethod("FixAutostart"); + } + } else { + // bamf + XWindow winId = winInfo->getXid(); + QString desktop = dock->getDesktopFromWindowByBamf(winId); + if (!desktop.isEmpty()) { + appInfo = new AppInfo(desktop); + } + + WMClass wmClass = XCB->getWMClass(winId); + if (wmClass.instanceName.size() > 0) { + QString instance(wmClass.instanceName.c_str()); + appInfo = new AppInfo("org.deepin.flatdeb." + instance); + if (appInfo) + return appInfo; + + appInfo = new AppInfo(instance); + if (appInfo) + return appInfo; + + if (wmClass.className.size() > 0) { + appInfo = new AppInfo(wmClass.className.c_str()); + if (appInfo) + return appInfo; + } + } + } + + if (appInfo) + innerId = appInfo->getInnerId(); + + return appInfo; +} + +AppInfo *WindowIdentify::identifyWindowAndroid(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + int32_t androidId = getAndroidUengineId(winInfo->getXid()); + QString androidName = getAndroidUengineName(winInfo->getXid()); + if (androidId != -1 && androidName != "") { + QString desktopPath = "/usr/share/applications/uengine." + androidName + ".desktop"; + DesktopInfo desktopInfo(desktopPath.toStdString()); + if (!desktopInfo.isValidDesktop()) { + qInfo() << "identifyWindowAndroid: not exist DesktopFile " << desktopPath; + return ret; + } + + ret = new AppInfo(desktopInfo); + ret->setIdentifyMethod("Android"); + innerId = ret->getInnerId(); + } + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByPidEnv(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + int pid = winInfo->getPid(); + auto process = winInfo->getProcess(); + qInfo() << "identifyWindowByPidEnv: pid=" << pid << " WindowId=" << winInfo->getXid(); + if (pid != 0 && process) { + QString launchedDesktopFile = process->getEnv("GIO_LAUNCHED_DESKTOP_FILE").c_str(); + QString launchedDesktopFilePidStr = process->getEnv("GIO_LAUNCHED_DESKTOP_FILE_PID").c_str(); + int launchedDesktopFilePid = launchedDesktopFilePidStr.toInt(); + qInfo() << "launchedDesktopFilePid=" << launchedDesktopFilePid << " launchedDesktopFile=" << launchedDesktopFile; + + // 以下 2 种情况下,才能信任环境变量 GIO_LAUNCHED_DESKTOP_FILE。 + // 1. 当窗口 pid 和 launchedDesktopFilePid 相同时; + // 2. 当窗口的进程的父进程 id(即 ppid)和 launchedDesktopFilePid 相同, + // 并且该父进程是 sh 或 bash 时。 + bool needTry = false; + if (pid == launchedDesktopFilePid) { + needTry = true; + } else if (process->getPpid() && process->getPpid() == launchedDesktopFilePid) { + Process parentProcess(launchedDesktopFilePid); + auto parentCmdLine = parentProcess.getCmdLine(); + if (parentCmdLine.size() > 0) { + qInfo() << "ppid equal " << "parentCmdLine[0]:" << parentCmdLine[0].c_str(); + QString cmd0 = parentCmdLine[0].c_str(); + int pos = cmd0.lastIndexOf('/'); + if (pos > 0) + cmd0 = cmd0.remove(0, pos + 1); + + if (cmd0 == "sh" || cmd0 == "bash") + needTry = true; + } + } + + if (needTry) { + ret = new AppInfo(launchedDesktopFile); + innerId = ret->getInnerId(); + } + } + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByCmdlineTurboBooster(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + int pid = winInfo->getPid(); + ProcessInfo *process = winInfo->getProcess(); + if (pid != 0 && process) { + auto cmdline = process->getCmdLine(); + if (cmdline.size() > 0) { + QString desktopFile; + if (DString::endWith(cmdline[0], ".desktop")) { + desktopFile = cmdline[0].c_str(); + } else if (QString(cmdline[0].c_str()).contains("/applications/")) { + QFileInfo fileInfo(cmdline[0].c_str()); + QString path = fileInfo.path(); + QString base = fileInfo.baseName(); + QDir dir(path); + QStringList files = dir.entryList(QDir::Files); + for (auto f : files) { + if (f.contains(path + "/" + base + ".desktop")) { + desktopFile = f; + break; + } + } + + qInfo() << "identifyWindowByCmdlineTurboBooster: desktopFile is " << desktopFile; + if (!desktopFile.isEmpty()) { + ret = new AppInfo(desktopFile); + innerId = ret->getInnerId(); + } + } + } + } + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByCmdlineXWalk(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + qInfo() << "identifyWindowByCmdlineXWalk: windowId=" << winInfo->getXid(); + AppInfo *ret = nullptr; + do { + auto process = winInfo->getProcess(); + if (!process || !winInfo->getPid()) + break; + + QString exe = process->getExe().c_str(); + QFileInfo file(exe); + QString exeBase = file.baseName(); + auto args = process->getArgs(); + if (exe != "xwalk" || args.size() == 0) + break; + + QString lastArg = args[args.size() - 1].c_str(); + file.setFile(lastArg); + if (file.baseName() == "manifest.json") { + auto strs = lastArg.split("/"); + if (strs.size() > 3 && strs[strs.size() - 2].size() > 0) { // appId为 strs倒数第二个字符串 + ret = new AppInfo(strs[strs.size() - 2]); + innerId = ret->getInnerId(); + break; + } + } + + qInfo() << "identifyWindowByCmdlineXWalk: failed"; + } while (0); + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByFlatpakAppID(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + QString flatpak = winInfo->getFlatpakAppId(); + qInfo() << "identifyWindowByFlatpakAppID: flatpak:" << flatpak; + if (flatpak.startsWith("app/")) { + auto parts = flatpak.split("/"); + if (parts.size() > 0) { + QString appId = parts[1]; + ret = new AppInfo(appId); + innerId = ret->getInnerId(); + } + } + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByCrxId(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + WMClass wmClass = XCB->getWMClass(winInfo->getXid()); + QString className, instanceName; + className.append(wmClass.className.c_str()); + instanceName.append(wmClass.instanceName.c_str()); + + if (className.toLower() == "chromium-browser" && instanceName.toLower().startsWith("crx_")) { + if (crxAppIdMap.find(instanceName.toLower()) != crxAppIdMap.end()) { + QString appId = crxAppIdMap[instanceName.toLower()]; + qInfo() << "identifyWindowByCrxId: appId " << appId; + ret = new AppInfo(appId); + innerId = ret->getInnerId(); + } + } + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByRule(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + qInfo() << "identifyWindowByRule: windowId=" << winInfo->getXid(); + AppInfo *ret = nullptr; + QString matchStr = patterns.match(winInfo); + if (matchStr.isEmpty()) + return ret; + + if (matchStr.size() > 4 && matchStr.startsWith("id=")) { + matchStr.remove(0, 3); + ret = new AppInfo(matchStr); + } else if (matchStr == "env") { + auto process = winInfo->getProcess(); + if (process) { + QString launchedDesktopFile = process->getEnv("GIO_LAUNCHED_DESKTOP_FILE").c_str(); + if (!launchedDesktopFile.isEmpty()) + ret = new AppInfo(launchedDesktopFile); + } + } else { + qInfo() << "patterns match bad result"; + } + + if (ret) + innerId = ret->getInnerId(); + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByBamf(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + XWindow xid = winInfo->getXid(); + qInfo() << "identifyWindowByBamf: windowId=" << xid; + QString desktopFile; + // 重试 bamf 识别,yozo office 的窗口经常要第二次时才能识别到。 + for (int i=0; i<3; i++) { + desktopFile = _dock->getDesktopFromWindowByBamf(xid); + if (!desktopFile.isEmpty()) + break; + + QThread::msleep(100); + } + + if (!desktopFile.isEmpty()) { + ret = new AppInfo(desktopFile); + innerId = ret->getInnerId(); + } + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByPid(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + if (winInfo->getPid() > 10) { + auto entry = _dock->getEntryByWindowId(winInfo->getPid()); + if (entry) { + ret = entry->getApp(); + innerId = ret->getInnerId(); + } + } + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByScratch(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + QString desktopFile = scratchDir + winInfo->getInnerId() + ".desktop"; + qInfo() << "identifyWindowByScratch: xid " << winInfo->getXid() << " desktopFile" << desktopFile; + QFile file(desktopFile); + + if (file.exists()) { + ret = new AppInfo(desktopFile); + innerId = ret->getInnerId(); + } + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByGtkAppId(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + QString gtkAppId = winInfo->getGtkAppId(); + if (!gtkAppId.isEmpty()) { + ret = new AppInfo(gtkAppId); + innerId = ret->getInnerId(); + } + + qInfo() << "identifyWindowByGtkAppId: gtkAppId:" << gtkAppId; + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByWmClass(Dock *_dock, WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + WMClass wmClass = winInfo->getWMClass(); + do { + if (wmClass.instanceName.size() > 0) { + // example: + // WM_CLASS(STRING) = "Brackets", "Brackets" + // wm class instance is Brackets + // try app id org.deepin.flatdeb.brackets + ret = new AppInfo("org.deepin.flatdeb." + QString(wmClass.instanceName.c_str()).toLower()); + if (ret) + break; + + ret = new AppInfo(wmClass.instanceName.c_str()); + if (ret) + break; + } + + if (wmClass.className.size() > 0) { + ret = new AppInfo(wmClass.className.c_str()); + if (ret) + break; + } + } while (0); + + if (ret) + innerId = ret->getInnerId(); + + return ret; +} + +AppInfo *WindowIdentify::fixAutostartAppInfo(QString fileName) +{ + QFileInfo file(fileName); + QString filePath = file.absolutePath(); + bool isAutoStart = false; + for (auto &dir : BaseDir::autoStartDirs()) { + if (QString(dir.c_str()).contains(filePath)) { + isAutoStart = true; + break; + } + } + + return isAutoStart ? new AppInfo(file.baseName()) : nullptr; +} + +int32_t WindowIdentify::getAndroidUengineId(XWindow winId) +{ + // TODO 获取AndroidUengineId + return 0; +} + +QString WindowIdentify::getAndroidUengineName(XWindow winId) +{ + // TODO 获取AndroidUengineName + return ""; +} + + + + + + + + + + + + diff --git a/src/modules/dock/windowidentify.h b/src/modules/dock/windowidentify.h new file mode 100644 index 0000000..cb48702 --- /dev/null +++ b/src/modules/dock/windowidentify.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef WINDOWIDENTIFY_H +#define WINDOWIDENTIFY_H + +#include "windowpatterns.h" +#include "windowinfok.h" +#include "windowinfox.h" + +#include +#include +#include + +class AppInfo; +class Dock; + +typedef AppInfo *(*IdentifyFunc)(Dock *, WindowInfoX*, QString &innerId); + +// 应用窗口识别类 +class WindowIdentify : public QObject +{ + Q_OBJECT + +public: + explicit WindowIdentify(Dock *_dock, QObject *parent = nullptr); + + AppInfo *identifyWindow(WindowInfoBase *winInfo, QString &innerId); + AppInfo *identifyWindowX11(WindowInfoX *winInfo, QString &innerId); + AppInfo *identifyWindowWayland(WindowInfoK *winInfo, QString &innerId); + + static AppInfo *identifyWindowAndroid(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByPidEnv(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByCmdlineTurboBooster(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByCmdlineXWalk(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByFlatpakAppID(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByCrxId(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByRule(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByBamf(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByPid(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByScratch(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByGtkAppId(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByWmClass(Dock *_dock, WindowInfoX *winInfo, QString &innerId); + +public Q_SLOTS: + +private: + AppInfo *fixAutostartAppInfo(QString fileName); + static int32_t getAndroidUengineId(XWindow winId); + static QString getAndroidUengineName(XWindow winId); + + static WindowPatterns patterns; // 根据rule识别 + Dock *dock; + QMap identifyWindowFuns; +}; + +#endif // IDENTIFYWINDOW_H diff --git a/src/modules/dock/windowinfobase.h b/src/modules/dock/windowinfobase.h new file mode 100644 index 0000000..067dd84 --- /dev/null +++ b/src/modules/dock/windowinfobase.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef WINDOWINFOBASE_H +#define WINDOWINFOBASE_H + +#include "xcbutils.h" + +#include +#include + +class Entry; +class AppInfo; +class ProcessInfo; +class WindowInfoBase +{ +public: + WindowInfoBase() : entry(nullptr), app(nullptr), processInfo(nullptr) {} + virtual ~WindowInfoBase() {} + + + virtual bool shouldSkip() = 0; + virtual QString getIcon() = 0; + virtual QString getTitle() = 0; + virtual bool isDemandingAttention() = 0; + virtual void close(uint32_t timestamp) = 0; + virtual void activate() = 0; + virtual void minimize() = 0; + virtual bool isMinimized() = 0; + virtual int64_t getCreatedTime() = 0; + virtual QString getWindowType() = 0; + virtual QString getDisplayName() = 0; + virtual bool allowClose() = 0; + virtual void update() = 0; + virtual void killClient() = 0; + + XWindow getXid() {return xid;} + void setEntry(Entry *value) {entry = value;} + Entry *getEntry() {return entry;} + QString getEntryInnerId() {return entryInnerId;} + QString getInnerId() {return innerId;} + void setEntryInnerId(QString value) {entryInnerId = value;} + AppInfo *getAppInfo() {return app;} + void setAppInfo(AppInfo *value) {app = value;} + int getPid() {return pid;} + ProcessInfo *getProcess() {return processInfo;} + bool containAtom(QVector supports, XCBAtom ty) {return supports.indexOf(ty) != -1;} + +protected: + XWindow xid; + QString title; + QString icon; + int pid; + QString entryInnerId; + QString innerId; + Entry *entry; + AppInfo *app; + ProcessInfo *processInfo; + int64_t createdTime; +}; + +#endif // WINDOWINFOBASE_H diff --git a/src/modules/dock/windowinfok.cpp b/src/modules/dock/windowinfok.cpp new file mode 100644 index 0000000..9d98f39 --- /dev/null +++ b/src/modules/dock/windowinfok.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "windowinfok.h" +#include "entry.h" +#include "processinfo.h" +#include "appinfo.h" + +#include + +WindowInfoK::WindowInfoK(PlasmaWindow *window, XWindow _xid) + : WindowInfoBase () + , updateCalled(false) + , internalId(0) + , demaningAttention(false) + , closeable(true) + , minimized(true) + , plasmaWindow(window) +{ + xid = _xid; + createdTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); // 获取当前时间,精确到纳秒 +} + +WindowInfoK::~WindowInfoK() +{ + +} + +bool WindowInfoK::shouldSkip() +{ + if (!updateCalled) { + update(); + updateCalled = true; + } + + bool skip = plasmaWindow->SkipTaskbar(); + + // 添加窗口能否最小化判断, 如果窗口不能最小化则隐藏任务栏图标 + bool canMinimize = false; + canMinimize = plasmaWindow->IsMinimizeable(); + if (!canMinimize) + skip = true; + + if (skip) { + // 白名单, 过滤类似“欢迎应用”, 没有最小化窗口但是需要在任务栏显示图标 + QStringList list { "dde-introduction"}; + if (list.indexOf(appId) != -1) + skip = false; + } + + return skip; +} + +QString WindowInfoK::getIcon() +{ + return icon; +} + +QString WindowInfoK::getTitle() +{ + return title; +} + +bool WindowInfoK::isDemandingAttention() +{ + return demaningAttention; +} + +bool WindowInfoK::allowClose() +{ + return closeable; +} + +void WindowInfoK::close(uint32_t timestamp) +{ + plasmaWindow->RequestClose(); +} + +QString WindowInfoK::getAppId() +{ + return appId; +} + +void WindowInfoK::setAppId(QString _appId) +{ + appId = _appId; +} + +void WindowInfoK::activate() +{ + plasmaWindow->RequestActivate(); +} + +void WindowInfoK::minimize() +{ + plasmaWindow->RequestToggleMinimized(); +} + +bool WindowInfoK::isMinimized() +{ + return minimized; +} + +bool WindowInfoK::changeXid(XWindow _xid) +{ + xid = _xid; + return true; +} + +PlasmaWindow *WindowInfoK::getPlasmaWindow() +{ + return plasmaWindow; +} + +bool WindowInfoK::updateGeometry() +{ + Rect rect = plasmaWindow->Geometry(); + if (geometry == rect) + return false; + + geometry = rect; + return true; +} + +void WindowInfoK::updateTitle() +{ + title = plasmaWindow->Title(); +} + +void WindowInfoK::updateDemandingAttention() +{ + demaningAttention = plasmaWindow->IsDemandingAttention(); +} + +void WindowInfoK::updateIcon() +{ + icon = plasmaWindow->Icon(); +} + +void WindowInfoK::updateAppId() +{ + appId = plasmaWindow->AppId(); +} + +void WindowInfoK::updateInternalId() +{ + internalId = plasmaWindow->InternalId(); +} + +void WindowInfoK::updateCloseable() +{ + closeable = plasmaWindow->IsCloseable(); +} + +void WindowInfoK::updateProcessInfo() +{ + pid = plasmaWindow->Pid(); + processInfo = new ProcessInfo(pid); +} + +int64_t WindowInfoK::getCreatedTime() +{ + return createdTime; +} + +// 主要是为兼容X11 +QString WindowInfoK::getDisplayName() +{ + return ""; +} + +QString WindowInfoK::getWindowType() +{ + return "Wayland"; +} + +void WindowInfoK::update() +{ + updateInternalId(); + updateAppId(); + updateIcon(); + updateTitle(); + updateGeometry(); + updateDemandingAttention(); + updateCloseable(); + updateProcessInfo(); +} + +void WindowInfoK::killClient() +{ +} + diff --git a/src/modules/dock/windowinfok.h b/src/modules/dock/windowinfok.h new file mode 100644 index 0000000..d5cb3d0 --- /dev/null +++ b/src/modules/dock/windowinfok.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef WINDOWINFOK_H +#define WINDOWINFOK_H + +#include "windowinfobase.h" +#include "dbusplasmawindow.h" + +#include + +class Entry; +class ProcessInfo; + +// wayland下窗口信息 +class WindowInfoK: public WindowInfoBase +{ +public: + WindowInfoK(PlasmaWindow *window, XWindow _xid = 0); + virtual ~WindowInfoK(); + + virtual bool shouldSkip(); + virtual QString getIcon(); + virtual QString getTitle(); + virtual bool isDemandingAttention(); + virtual bool allowClose(); + virtual void close(uint32_t timestamp); + virtual void activate(); + virtual void minimize(); + virtual bool isMinimized(); + virtual int64_t getCreatedTime(); + virtual QString getDisplayName(); + virtual QString getWindowType(); + virtual void update(); + virtual void killClient(); + + QString getAppId(); + void setAppId(QString _appId); + bool changeXid(XWindow _xid); + PlasmaWindow *getPlasmaWindow(); + bool updateGeometry(); + void updateTitle(); + void updateDemandingAttention(); + void updateIcon(); + void updateAppId(); + void updateInternalId(); + void updateCloseable(); + void updateProcessInfo(); + +private: + bool updateCalled; + QString appId; + uint32_t internalId; + bool demaningAttention; + bool closeable; + bool minimized; + PlasmaWindow *plasmaWindow; + Rect geometry; +}; + +#endif // WINDOWINFOK_H diff --git a/src/modules/dock/windowinfox.cpp b/src/modules/dock/windowinfox.cpp new file mode 100644 index 0000000..294cb1d --- /dev/null +++ b/src/modules/dock/windowinfox.cpp @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "windowinfox.h" +#include "appinfo.h" +#include "xcbutils.h" +#include "dstring.h" +#include "common.h" +#include "processinfo.h" + +#include +#include + +#define XCB XCBUtils::instance() + +WindowInfoX::WindowInfoX(XWindow _xid) + : WindowInfoBase () + , x(0) + , y(0) + , width(0) + , height(0) + , hasWMTransientFor(false) + , hasXEmbedInfo(false) + , updateCalled(false) +{ + xid = _xid; + createdTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); // 获取当前时间,精确到纳秒 +} + +WindowInfoX::~WindowInfoX() +{ + +} + +bool WindowInfoX::shouldSkip() +{ + qInfo() << "window " << xid << " shouldSkip?"; + if (!updateCalled) { + update(); + updateCalled = true; + } + + if (hasWmStateSkipTaskBar() || isValidModal() || shouldSkipWithWMClass()) + return true; + + for (auto atom : wmWindowType) { + if (atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_DIALOG") && !isActionMinimizeAllowed()) + return true; + + if (atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_UTILITY") + || atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_COMBO") + || atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_DESKTOP") + || atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_DND") + || atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_DOCK") + || atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU") + || atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_MENU") + || atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION") + || atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_POPUP_MENU") + || atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_SPLASH") + || atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_TOOLBAR") + || atom == XCB->getAtom("_NET_WM_WINDOW_TYPE_TOOLTIP")) + return true; + } + + return false; +} + +QString WindowInfoX::getIcon() +{ + if (icon.isEmpty()) + icon = getIconFromWindow(); + + return icon; +} + +void WindowInfoX::activate() +{ + XCB->setActiveWindow(xid); +} + +void WindowInfoX::minimize() +{ + XCB->minimizeWindow(xid); +} + +bool WindowInfoX::isMinimized() +{ + return containAtom(wmState, XCB->getAtom("_NET_WM_STATE_HIDDEN")); +} + +int64_t WindowInfoX::getCreatedTime() +{ + return createdTime; +} + +QString WindowInfoX::getWindowType() +{ + return "X11"; +} + +bool WindowInfoX::allowClose() +{ + // 允许关闭的条件: + // 1. 不设置 functions 字段,即MotifHintFunctions 标志位; + // 2. 或者设置了 functions 字段并且 设置了 MotifFunctionAll 标志位; + // 3. 或者设置了 functions 字段并且 设置了 MotifFunctionClose 标志位。 + // 相关定义在 motif-2.3.8/lib/Xm/MwmUtil.h 。 + if ((motifWmHints.flags & MotifHintFunctions) == 0 + || (motifWmHints.functions & MotifFunctionAll) != 0 + || (motifWmHints.functions & MotifFunctionClose) != 0) + return true; + + for (auto action : wmAllowedActions) { + if (action == XCB->getAtom("_NET_WM_ACTION_CLOSE")) { + return true; + } + } + + return false; +} + +QString WindowInfoX::getDisplayName() +{ + XWindow winId = xid; + //QString role = wmRole; + QString className(wmClass.className.c_str()); + QString instance; + if (wmClass.instanceName.size() > 0) { + int pos = QString(wmClass.instanceName.c_str()).lastIndexOf('/'); + if (pos != -1) + instance.remove(0, pos + 1); + } + qInfo() << "getDisplayName class:" << className << " ,instance:" << instance; + + //if (!role.isEmpty() && !className.isEmpty()) + // return className + " " + role; + + if (!className.isEmpty()) + return className; + + if (!instance.isEmpty()) + return instance; + + + QString _wmName = wmName; + if (!_wmName.isEmpty()) { + int pos = _wmName.lastIndexOf('-'); + if (pos != -1 && !_wmName.startsWith("-")) { + _wmName.truncate(pos); + return _wmName; + } + } + + if (processInfo) { + QString exe {processInfo->getEnv("exe").c_str()}; + if (!exe.isEmpty()) + return exe; + } + + return QString("window:%1").arg(winId); +} + +void WindowInfoX::killClient() +{ + XCB->killClientChecked(xid); +} + +QString WindowInfoX::getGtkAppId() +{ + return gtkAppId; +} + +QString WindowInfoX::getFlatpakAppId() +{ + return flatpakAppId; +} + +QString WindowInfoX::getWmRole() +{ + return wmRole; +} + +WMClass WindowInfoX::getWMClass() +{ + return wmClass; +} + +QString WindowInfoX::getWMName() +{ + return wmName; +} + +ConfigureEvent *WindowInfoX::getLastConfigureEvent() +{ + return lastConfigureNotifyEvent; +} + +void WindowInfoX::setLastConfigureEvent(ConfigureEvent *event) +{ + lastConfigureNotifyEvent = event; +} + +bool WindowInfoX::isGeometryChanged(int _x, int _y, int _width, int _height) +{ + return !(_x == x && _y == y && _width == width && _height == height); +} + +void WindowInfoX::setGtkAppId(QString _gtkAppId) +{ + gtkAppId = _gtkAppId; +} + +void WindowInfoX::updateMotifWmHints() +{ + // get from XCB + motifWmHints = XCB->getWindowMotifWMHints(xid); +} + +// XEmbed info +// 一般 tray icon 会带有 _XEMBED_INFO 属性 +void WindowInfoX::updateHasXEmbedInfo() +{ + hasXEmbedInfo = XCB->hasXEmbedInfo(xid); +} + +QString WindowInfoX::genInnerId(WindowInfoX *winInfo) +{ + XWindow winId = winInfo->getXid(); + QString wmClassName, wmInstance; + WMClass wmClass = winInfo->getWMClass(); + if (wmClass.className.size() > 0) + wmClassName = wmClass.className.c_str(); + + if (wmClass.instanceName.size() > 0) { + QString instanceName(wmClass.instanceName.c_str()); + instanceName.remove(0, instanceName.lastIndexOf('/') + 1); + wmInstance = instanceName; + } + + QString exe, args; + if (winInfo->getProcess()) { + exe = winInfo->getProcess()->getExe().c_str(); + for (auto arg : winInfo->getProcess()->getArgs()) { + QString argStr(arg.c_str()); + if (argStr.contains("/") || argStr == "." || argStr == "..") { + args += "%F "; + } else { + args += argStr + " "; + } + } + + if (args.size() > 0) + args.remove(args.size() - 2, 1); + } + + bool hasPid = winInfo->getPid() != 0; + QString str; + // NOTE: 不要使用 wmRole,有些程序总会改变这个值比如 GVim + if (wmInstance.isEmpty() && wmClassName.isEmpty() && exe.isEmpty() && winInfo->getGtkAppId().isEmpty()) { + if (!winInfo->getWMName().isEmpty()) + str = QString("wmName:%1").arg(winInfo->getWMName()); + else + str = QString("windowId:%1").arg(winInfo->getXid()); + } else { + str = QString("wmInstance:%1,wmClass:%2,exe:%3,args:%4,hasPid:%5,gtkAppId:%6").arg(wmInstance).arg(wmClassName).arg(exe).arg(args).arg(hasPid).arg(winInfo->getGtkAppId()); + } + + QByteArray encryText = QCryptographicHash::hash(str.toLatin1(), QCryptographicHash::Md5); + QString innerId = windowHashPrefix + encryText.toHex(); + qInfo() << "genInnerId window " << winId << " innerId :" << innerId; + return innerId; +} + +// 更新窗口类型 +void WindowInfoX::updateWmWindowType() +{ + wmWindowType.clear(); + for (auto ty : XCB->getWMWindoType(xid)) { + wmWindowType.push_back(ty); + } +} + +// 更新窗口许可动作 +void WindowInfoX::updateWmAllowedActions() +{ + wmAllowedActions.clear(); + for (auto action : XCB->getWMAllowedActions(xid)) { + wmAllowedActions.push_back(action); + } +} + +void WindowInfoX::updateWmState() +{ + wmState.clear(); + for (auto a : XCB->getWMState(xid)) { + wmState.push_back(a); + } +} + +void WindowInfoX::updateWmClass() +{ + wmClass = XCB->getWMClass(xid); +} + +void WindowInfoX::updateWmName() +{ + auto name = XCB->getWMName(xid); + if (!name.empty()) + wmName = name.c_str(); + + title = getTitle(); +} + +void WindowInfoX::updateIcon() +{ + icon = getIconFromWindow(); +} + +void WindowInfoX::updateHasWmTransientFor() +{ + if (XCB->getWMTransientFor(xid) == 1) + hasWMTransientFor = true; +} + +void WindowInfoX::update() +{ + updateWmClass(); + updateWmState(); + updateWmWindowType(); + updateWmAllowedActions(); + updateHasWmTransientFor(); + updateProcessInfo(); + updateWmName(); + innerId = genInnerId(this); +} + +// TODO 从窗口中获取图标, 并设置best size be used in Entry +QString WindowInfoX::getIconFromWindow() +{ + QString ret; + + return ret; +} + +bool WindowInfoX::isActionMinimizeAllowed() +{ + return containAtom(wmAllowedActions, XCB->getAtom("_NET_WM_ACTION_MINIMIZE")); +} + +bool WindowInfoX::hasWmStateDemandsAttention() +{ + return containAtom(wmState, XCB->getAtom("_NET_WM_STATE_DEMANDS_ATTENTION")); +} + +bool WindowInfoX::hasWmStateSkipTaskBar() +{ + return containAtom(wmState, XCB->getAtom("_NET_WM_STATE_SKIP_TASKBAR")); +} + +bool WindowInfoX::hasWmStateModal() +{ + return containAtom(wmState, XCB->getAtom("_NET_WM_STATE_MODAL")); +} + +bool WindowInfoX::isValidModal() +{ + return hasWmStateModal() && hasWmStateModal(); +} + +// 通过WMClass判断是否需要隐藏此窗口 +bool WindowInfoX::shouldSkipWithWMClass() +{ + bool ret = false; + if (wmClass.instanceName == "explorer.exe" && wmClass.className == "Wine") + ret = true; + else if (wmClass.className == "dde-launcher") + ret = true; + + return ret; +} + +void WindowInfoX::updateProcessInfo() +{ + XWindow winId = xid; + pid = XCB->getWMPid(winId); + if (processInfo) + delete processInfo; + + processInfo = new ProcessInfo(pid); + if (!processInfo) { + // try WM_COMMAND + auto wmComand = XCB->getWMCommand(winId); + if (wmComand.size() > 0) + processInfo = new ProcessInfo(wmComand); + } + + qInfo() << "updateProcessInfo: pid is " << pid; +} + +bool WindowInfoX::getUpdateCalled() +{ + return updateCalled; +} + +void WindowInfoX::setInnerId(QString _innerId) +{ + innerId = _innerId; +} + +QString WindowInfoX::getTitle() +{ + QString name = wmName; + if (name.isEmpty()) + name = getDisplayName(); + + return name; +} + +bool WindowInfoX::isDemandingAttention() +{ + return hasWmStateDemandsAttention(); +} + +void WindowInfoX::close(uint32_t timestamp) +{ + XCB->requestCloseWindow(xid, timestamp); +} + + diff --git a/src/modules/dock/windowinfox.h b/src/modules/dock/windowinfox.h new file mode 100644 index 0000000..9563026 --- /dev/null +++ b/src/modules/dock/windowinfox.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef WINDOWINFOX_H +#define WINDOWINFOX_H + +#include "windowinfobase.h" +#include "xcbutils.h" + +#include + +class AppInfo; + +// X11下窗口信息 在明确X11环境下使用 +class WindowInfoX: public WindowInfoBase +{ +public: + WindowInfoX(XWindow _xid = 0); + virtual ~WindowInfoX(); + + virtual bool shouldSkip(); + virtual QString getIcon(); + virtual QString getTitle(); + virtual bool isDemandingAttention(); + virtual void close(uint32_t timestamp); + virtual void activate(); + virtual void minimize(); + virtual bool isMinimized(); + virtual int64_t getCreatedTime(); + virtual QString getDisplayName(); + virtual QString getWindowType(); + virtual bool allowClose(); + virtual void update(); + virtual void killClient(); + + QString genInnerId(WindowInfoX *winInfo); + QString getGtkAppId(); + QString getFlatpakAppId(); + QString getWmRole(); + WMClass getWMClass(); + QString getWMName(); + void updateProcessInfo(); + bool getUpdateCalled(); + void setInnerId(QString _innerId); + ConfigureEvent *getLastConfigureEvent(); + void setLastConfigureEvent(ConfigureEvent *event); + bool isGeometryChanged(int _x, int _y, int _width, int _height); + void setGtkAppId(QString _gtkAppId); + + /************************更新XCB窗口属性*********************/ + void updateWmWindowType(); + void updateWmAllowedActions(); + void updateWmState(); + void updateWmClass(); + void updateMotifWmHints(); + void updateWmName(); + void updateIcon(); + void updateHasXEmbedInfo(); + void updateHasWmTransientFor(); + +private: + QString getIconFromWindow(); + bool isActionMinimizeAllowed(); + bool hasWmStateDemandsAttention(); + bool hasWmStateSkipTaskBar(); + bool hasWmStateModal(); + bool isValidModal(); + bool shouldSkipWithWMClass(); + + int16_t x, y; + uint16_t width, height; + QVector wmState; + QVector wmWindowType; + QVector wmAllowedActions; + bool hasWMTransientFor; + WMClass wmClass; + QString wmName; + bool hasXEmbedInfo; + + // 自定义atom属性 + QString gtkAppId; + QString flatpakAppId; + QString wmRole; + MotifWMHints motifWmHints; + + bool updateCalled; + ConfigureEvent *lastConfigureNotifyEvent; +}; + +#endif // WINDOWINFOX_H diff --git a/src/modules/dock/windowpatterns.cpp b/src/modules/dock/windowpatterns.cpp new file mode 100644 index 0000000..18aaef1 --- /dev/null +++ b/src/modules/dock/windowpatterns.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "windowpatterns.h" +#include "common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const int parsedFlagNegative = 0x001; +const int parsedFlagIgnoreCase = 0x010; + +bool contains(QString key, QString value) { + return key.contains(value); +} + +bool containsIgnoreCase(QString key, QString value) { + QString _key = key.toLower(); + QString _value = value.toLower(); + return _key.contains(_value); +} + +bool equal(QString key, QString value) { + return key == value; +} + +bool equalIgnoreCase(QString key, QString value) { + return key.toLower() == value.toLower(); +} + +bool regexMatch(QString key, QString value) { + QRegExp ruleRegex(value); + return ruleRegex.exactMatch(key); +} + +bool regexMatchIgnoreCase(QString key, QString value) { + QRegExp ruleRegex(value, Qt::CaseInsensitive); + return ruleRegex.exactMatch(key); +} + + +RuleValueParse::RuleValueParse() + : negative(0) + , type(0) + , flags(0) +{ +} + +bool RuleValueParse::parse(QString parsedKey) +{ + if (!fn) + return false; + + return negative ? fn(parsedKey, value) : !fn(parsedKey, value); +} + +bool RuleValueParse::match(const WindowInfoX *winInfo) +{ + QString parsedKey; + + return parse(parsedKey); +} + + +WindowPatterns::WindowPatterns() +{ + +} + +QString WindowPatterns::match(WindowInfoX *winInfo) +{ + + return ""; +} + +void WindowPatterns::loadWindowPatterns() +{ + qInfo() << "---loadWindowPatterns"; + QFile file(windowPatternsFile); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); + file.close(); + if (!doc.isArray()) + return; + + QJsonArray arr = doc.array(); + if (arr.size() == 0) + return; + + patterns.clear(); + for (auto iterp = arr.begin(); iterp != arr.end(); iterp++) { + // 过滤非Object + if (!(*iterp).isObject()) + continue; + + QJsonObject patternObj = (*iterp).toObject(); + QVariantMap patternMap = patternObj.toVariantMap(); + WindowPattern pattern; + for (auto infoIter = patternMap.begin(); infoIter != patternMap.end(); infoIter++) { + QString ret = infoIter.key(); + QVariant value = infoIter.value(); + + if (ret == "ret") { + pattern.result = value.toString(); + } else if (ret == "rules") { + for (auto &item : value.toList()) { + if (!item.isValid()) + continue; + + if (item.toList().size() != 2) + continue; + + pattern.rules.push_back({item.toList()[0].toString(), item.toList()[1].toString()}); + } + } + } + qInfo() << pattern.result; + for (const auto &item : pattern.rules) { + qInfo() << item[0] << " " << item[1]; + } + patterns.push_back(pattern); + } + + // 解析patterns + for (auto &pattern : patterns) { + for (int i=0; i < pattern.rules.size(); i++) { + RuleValueParse ruleValue = parseRule(pattern.rules[i]); + pattern.parseRules.push_back(ruleValue); + } + } +} + +// "=:XXX" equal XXX +// "=!XXX" not equal XXX + +// "c:XXX" contains XXX +// "c!XXX" not contains XXX + +// "r:XXX" match regexp XXX +// "r!XXX" not match regexp XXX + +// e c r ignore case +// = E C R not ignore case +// 解析窗口类型规则 +RuleValueParse WindowPatterns::parseRule(QVector rule) +{ + RuleValueParse ret; + ret.key = rule[0]; + ret.original = rule[1]; + if (rule[1].size() < 2) + return ret; + + int len = ret.original.size() + 1; + char *orig = static_cast(calloc(1, size_t(len))); + if (!orig) + return ret; + + strncpy(orig, ret.original.toStdString().c_str(), size_t(len)); + switch (orig[1]) { + case ':': + case '!': + ret.flags |= parsedFlagNegative; + ret.negative = true; + break; + default: + return ret; + } + + ret.value = QString(&orig[2]); + ret.type = uint8_t(orig[0]); + switch (orig[0]) { + case 'C': + ret.fn = contains; + break; + case 'c': + ret.flags |= parsedFlagIgnoreCase; + ret.fn = containsIgnoreCase; + break; + case '=': + case 'E': + ret.fn = equal; + break; + case 'e': + ret.flags |= parsedFlagIgnoreCase; + ret.fn = equalIgnoreCase; + break; + case 'R': + ret.fn = regexMatch; + break; + case 'r': + ret.flags |= parsedFlagIgnoreCase; + ret.fn = regexMatchIgnoreCase; + break; + default: + return ret; + } + + return ret; +} + + diff --git a/src/modules/dock/windowpatterns.h b/src/modules/dock/windowpatterns.h new file mode 100644 index 0000000..290a068 --- /dev/null +++ b/src/modules/dock/windowpatterns.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef WINDOWPATTERNS_H +#define WINDOWPATTERNS_H + +#include "windowinfox.h" + +#include +#include + + +struct RuleValueParse { + RuleValueParse(); + bool parse(QString parsedKey); + bool match(const WindowInfoX *winInfo); + QString key; + bool negative; + bool (*fn)(QString, QString); + uint8_t type; + uint flags; + QString original; + QString value; +}; + +class WindowPatterns +{ + // 窗口类型匹配 + struct WindowPattern { + QVector> rules; // rules + QString result; // ret + QVector< RuleValueParse> parseRules; + }; + +public: + WindowPatterns(); + + QString match(WindowInfoX *winInfo); + +private: + void loadWindowPatterns(); + RuleValueParse parseRule(QVector rule); + QVector patterns; + +}; + +#endif // WINDOWPATTERNS_H diff --git a/src/modules/dock/x11manager.cpp b/src/modules/dock/x11manager.cpp new file mode 100644 index 0000000..6d11c59 --- /dev/null +++ b/src/modules/dock/x11manager.cpp @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "x11manager.h" +#include "dock.h" +#include "common.h" + +#include +#include + +/* + * 使用Xlib监听X Events + * 使用XCB接口与X进行交互 + * */ + +#include +#include +#include +#include +#include + +#define XCB XCBUtils::instance() + +X11Manager::X11Manager(Dock *_dock, QObject *parent) + : QObject(parent) + , dock(_dock) + , mutex(QMutex(QMutex::NonRecursive)) + , listenXEvent(true) +{ + rootWindow = XCB->getRootWindow(); +} + +void X11Manager::listenXEventUseXlib() +{ + + Display *dpy; + int screen; + char *displayname = nullptr; + Window w; + XSetWindowAttributes attr; + XWindowAttributes wattr; + + dpy = XOpenDisplay (displayname); + if (!dpy) { + exit (1); + } + + screen = DefaultScreen (dpy); + w = RootWindow(dpy, screen); + + const struct { + const char *name; + long mask; + } events[] = { + { "keyboard", KeyPressMask | KeyReleaseMask | KeymapStateMask }, + { "mouse", ButtonPressMask | ButtonReleaseMask | EnterWindowMask | + LeaveWindowMask | PointerMotionMask | Button1MotionMask | + Button2MotionMask | Button3MotionMask | Button4MotionMask | + Button5MotionMask | ButtonMotionMask }, + { "button", ButtonPressMask | ButtonReleaseMask }, + { "expose", ExposureMask }, + { "visibility", VisibilityChangeMask }, + { "structure", StructureNotifyMask }, + { "substructure", SubstructureNotifyMask | SubstructureRedirectMask }, + { "focus", FocusChangeMask }, + { "property", PropertyChangeMask }, + { "colormap", ColormapChangeMask }, + { "owner_grab_button", OwnerGrabButtonMask }, + { nullptr, 0 } + }; + + long mask = 0; + for (int i = 0; events[i].name; i++) + mask |= events[i].mask; + + attr.event_mask = mask; + + XGetWindowAttributes(dpy, w, &wattr); + + attr.event_mask &= ~SubstructureRedirectMask; + XSelectInput(dpy, w, attr.event_mask); + + while (listenXEvent) { + XEvent event; + XNextEvent (dpy, &event); + + if (event.type == DestroyNotify) { + XDestroyWindowEvent *eD = (XDestroyWindowEvent *) (&event); + //qInfo() << "DestroyNotify windowId=" << eD->window; + + handleDestroyNotifyEvent(XWindow(eD->window)); + } else if (event.type == MapNotify) { + XMapEvent *eM = (XMapEvent *)(&event); + //qInfo() << "MapNotify windowId=" << eM->window; + + handleMapNotifyEvent(XWindow(eM->window)); + } else if (event.type == ConfigureNotify ) { + XConfigureEvent *eC = (XConfigureEvent *) (&event); + //qInfo() << "ConfigureNotify windowId=" << eC->window; + + handleConfigureNotifyEvent(XWindow(eC->window), eC->x, eC->y, eC->width, eC->height); + } else if (event.type == PropertyNotify) { + XPropertyEvent *eP = (XPropertyEvent *) (&event); + //qInfo() << "PropertyNotify windowId=" << eP->window; + + handlePropertyNotifyEvent(XWindow(eP->window), XCBAtom(eP->atom)); + } else { + //qInfo() << "Unknown event type " << event.type; + } + + } + + XCloseDisplay (dpy); +} + +void X11Manager::listenXEventUseXCB() +{ + /* + xcb_get_window_attributes_cookie_t cookie = xcb_get_window_attributes(XCB->getConnect(), XCB->getRootWindow()); + xcb_get_window_attributes_reply_t *reply = xcb_get_window_attributes_reply(XCB->getConnect(), cookie, NULL); + if (reply) { + uint32_t valueMask = reply->your_event_mask; + valueMask &= ~XCB_CW_OVERRIDE_REDIRECT; + uint32_t mask[2] = {0}; + mask[0] = valueMask; + //xcb_change_window_attributes(XCB->getConnect(), XCB->getRootWindow(), valueMask, mask); + + free(reply); + } + + xcb_generic_event_t *event; + while ( (event = xcb_wait_for_event (XCB->getConnect())) ) { + eventHandler(event->response_type & ~0x80, event); + } + */ +} + +// 注册X11窗口 +WindowInfoX *X11Manager::registerWindow(XWindow xid) +{ + qInfo() << "registWindow: windowId=" << xid; + WindowInfoX *ret = nullptr; + do { + if (windowInfoMap.find(xid) != windowInfoMap.end()) { + ret = windowInfoMap[xid]; + break; + } + + WindowInfoX *winInfo = new WindowInfoX(xid); + if (!winInfo) + break; + + listenWindowXEvent(winInfo); + windowInfoMap[xid] = winInfo; + ret = winInfo; + } while (0); + + return ret; +} + +// 取消注册X11窗口 +void X11Manager::unregisterWindow(XWindow xid) +{ + qInfo() << "unregisterWindow: windowId=" << xid; + if (windowInfoMap.find(xid) != windowInfoMap.end()) { + windowInfoMap.remove(xid); + } +} + +WindowInfoX *X11Manager::findWindowByXid(XWindow xid) +{ + WindowInfoX *ret = nullptr; + if (windowInfoMap.find(xid) != windowInfoMap.end()) + ret = windowInfoMap[xid]; + + return ret; +} + +void X11Manager::handleClientListChanged() +{ + QSet newClientList, oldClientList, addClientList, rmClientList; + for (auto atom : XCB->getClientList()) + newClientList.insert(atom); + + for (auto atom : dock->getClientList()) + oldClientList.insert(atom); + + addClientList = newClientList - oldClientList; + rmClientList = oldClientList - newClientList; + + for (auto xid : addClientList) { + WindowInfoX *info = registerWindow(xid); + if (!XCB->isGoodWindow(xid)) + continue; + + uint32_t pid = XCB->getWMPid(xid); + WMClass wmClass = XCB->getWMClass(xid); + QString wmName(XCB->getWMName(xid).c_str()); + if (pid != 0 || (wmClass.className.size() > 0 && wmClass.instanceName.size() > 0) + || wmName.size() > 0 || XCB->getWMCommand(xid).size() > 0) + dock->attachWindow(info); + } + + for (auto xid : rmClientList) { + WindowInfoX *info = windowInfoMap[xid]; + if (info) { + dock->detachWindow(info); + unregisterWindow(xid); + } else { + // no window + auto entry = dock->getEntryByWindowId(xid); + if (entry && !dock->isDocked(entry->getFileName())) { + dock->removeAppEntry(entry); + } + } + } +} + +void X11Manager::handleActiveWindowChangedX() +{ + XWindow active = XCB->getActiveWindow(); + WindowInfoX *info = findWindowByXid(active); + dock->handleActiveWindowChanged(info); +} + +void X11Manager::listenRootWindowXEvent() +{ + uint32_t eventMask = EventMask::XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY; + XCB->registerEvents(rootWindow, eventMask); + handleActiveWindowChangedX(); + handleClientListChanged(); +} + +void X11Manager::listenWindowXEvent(WindowInfoX *winInfo) +{ + uint32_t eventMask = EventMask::XCB_EVENT_MASK_PROPERTY_CHANGE | EventMask::XCB_EVENT_MASK_STRUCTURE_NOTIFY | EventMask::XCB_EVENT_MASK_VISIBILITY_CHANGE; + XCB->registerEvents(winInfo->getXid(), eventMask); +} + +void X11Manager::handleRootWindowPropertyNotifyEvent(XCBAtom atom) +{ + if (atom == XCB->getAtom("_NET_CLIENT_LIST")) + handleClientListChanged(); + else if (atom == XCB->getAtom("_NET_ACTIVE_WINDOW")) + handleActiveWindowChangedX(); + else if (atom == XCB->getAtom("_NET_SHOWING_DESKTOP")) + Q_EMIT needUpdateHideState(false); +} + +// destory event +void X11Manager::handleDestroyNotifyEvent(XWindow xid) +{ + WindowInfoX *winInfo = findWindowByXid(xid); + if (!winInfo) + return; + + dock->detachWindow(winInfo); + unregisterWindow(xid); +} + +// map event +void X11Manager::handleMapNotifyEvent(XWindow xid) +{ + WindowInfoX *winInfo = registerWindow(xid); + if (!winInfo) + return; + + QTimer::singleShot(2 * 1000, this, [&] { + qInfo() << "handleMapNotifyEvent: pass 2s, now call idnetifyWindow, windowId=" << winInfo->getXid(); + QString innerId; + AppInfo *appInfo = dock->identifyWindow(winInfo, innerId); + dock->markAppLaunched(appInfo); + }); +} + +// config changed event 检测窗口大小调整和重绘应用 +void X11Manager::handleConfigureNotifyEvent(XWindow xid, int x, int y, int width, int height) +{ + WindowInfoX *winInfo = findWindowByXid(xid); + if (!winInfo || dock->getDockHideMode() != HideMode::SmartHide) + return; + + WMClass wmClass = winInfo->getWMClass(); + if (wmClass.className.c_str() == frontendWindowWmClass) + return; // ignore frontend window ConfigureNotify event + + Q_EMIT needUpdateHideState(winInfo->isGeometryChanged(x, y, width, height)); +} + +// property changed event +void X11Manager::handlePropertyNotifyEvent(XWindow xid, XCBAtom atom) +{ + if (xid == rootWindow) { + handleRootWindowPropertyNotifyEvent(atom); + return; + } + + WindowInfoX *winInfo = findWindowByXid(xid); + if (!winInfo) + return; + + QString newInnerId; + bool needAttachOrDetach = false; + if (atom == XCB->getAtom("_NET_WM_STATE")) { + winInfo->updateWmState(); + needAttachOrDetach = true; + } else if (atom == XCB->getAtom("_GTK_APPLICATION_ID")) { + QString gtkAppId; + winInfo->setGtkAppId(gtkAppId); + newInnerId = winInfo->genInnerId(winInfo); + } else if (atom == XCB->getAtom("_NET_WM_PID")) { + winInfo->updateProcessInfo(); + newInnerId = winInfo->genInnerId(winInfo); + } else if (atom == XCB->getAtom("_NET_WM_NAME")) { + winInfo->updateWmName(); + newInnerId = winInfo->genInnerId(winInfo); + } else if (atom == XCB->getAtom("_NET_WM_ICON")) { + winInfo->updateIcon(); + } else if (atom == XCB->getAtom("_NET_WM_ALLOWED_ACTIONS")) { + winInfo->updateWmAllowedActions(); + } else if (atom == XCB->getAtom("_MOTIF_WM_HINTS")) { + winInfo->updateMotifWmHints(); + } else if (atom == XCB_ATOM_WM_CLASS) { + winInfo->updateWmClass(); + newInnerId = winInfo->genInnerId(winInfo); + needAttachOrDetach = true; + } else if (atom == XCB->getAtom("_XEMBED_INFO")) { + winInfo->updateHasXEmbedInfo(); + needAttachOrDetach = true; + } else if (atom == XCB->getAtom("_NET_WM_WINDOW_TYPE")) { + winInfo->updateWmWindowType(); + needAttachOrDetach = true; + } else if (atom == XCB_ATOM_WM_TRANSIENT_FOR) { + winInfo->updateHasWmTransientFor(); + needAttachOrDetach = true; + } + + if (!newInnerId.isEmpty() && winInfo->getUpdateCalled() && winInfo->getInnerId() != newInnerId) { + // winInfo.innerId changed + dock->detachWindow(winInfo); + winInfo->setInnerId(newInnerId); + needAttachOrDetach = true; + } + + if (needAttachOrDetach) + dock->attachWindow(winInfo); + + Entry *entry = dock->getEntryByWindowId(xid); + if (!entry) + return; + + if (atom == XCB->getAtom("_NET_WM_STATE")) { + entry->updateWindowInfos(); + } else if (atom == XCB->getAtom("_NET_WM_ICON")) { + if (entry->getCurrentWindowInfo() == winInfo) { + entry->updateIcon(); + } + } else if (atom == XCB->getAtom("_NET_WM_NAME")) { + if (entry->getCurrentWindowInfo() == winInfo) { + entry->updateName(); + } + entry->updateWindowInfos(); + } else if (atom == XCB->getAtom("_NET_WM_ALLOWED_ACTIONS")) { + entry->updateMenu(); + } +} + +void X11Manager::eventHandler(uint8_t type, void *event) +{ + qInfo() << "eventHandler" << "type = " << type; + switch (type) { + case XCB_MAP_NOTIFY: // 17 注册新窗口 + qInfo() << "eventHandler: XCB_MAP_NOTIFY"; + break; + case XCB_DESTROY_NOTIFY: // 19 销毁窗口 + qInfo() << "eventHandler: XCB_DESTROY_NOTIFY"; + break; + case XCB_CONFIGURE_NOTIFY: // 22 窗口变化 + qInfo() << "eventHandler: XCB_CONFIGURE_NOTIFY"; + break; + case XCB_PROPERTY_NOTIFY: // 28 窗口属性改变 + qInfo() << "eventHandler: XCB_PROPERTY_NOTIFY"; + break; + } +} + +void X11Manager::addWindowLastConfigureEvent(XWindow xid, ConfigureEvent *event) +{ + delWindowLastConfigureEvent(xid); + + QMutexLocker locker(&mutex); + QTimer *timer = new QTimer(); + timer->setInterval(configureNotifyDelay); + windowLastConfigureEventMap[xid] = QPair(event, timer); +} + +QPair X11Manager::getWindowLastConfigureEvent(XWindow xid) +{ + QPair ret; + QMutexLocker locker(&mutex); + if (windowLastConfigureEventMap.find(xid) != windowLastConfigureEventMap.end()) + ret = windowLastConfigureEventMap[xid]; + + return ret; +} + +void X11Manager::delWindowLastConfigureEvent(XWindow xid) +{ + QMutexLocker locker(&mutex); + if (windowLastConfigureEventMap.find(xid) != windowLastConfigureEventMap.end()) { + QPair item = windowLastConfigureEventMap[xid]; + windowLastConfigureEventMap.remove(xid); + delete item.first; + item.second->deleteLater(); + } +} + + + + diff --git a/src/modules/dock/x11manager.h b/src/modules/dock/x11manager.h new file mode 100644 index 0000000..00ddec1 --- /dev/null +++ b/src/modules/dock/x11manager.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef X11MANAGER_H +#define X11MANAGER_H + +#include "windowinfox.h" +#include "xcbutils.h" + +#include +#include +#include +#include + +class Dock; + +class X11Manager : public QObject +{ + Q_OBJECT +public: + explicit X11Manager(Dock *_dock, QObject *parent = nullptr); + + WindowInfoX *findWindowByXid(XWindow xid); + WindowInfoX *registerWindow(XWindow xid); + void unregisterWindow(XWindow xid); + + void handleClientListChanged(); + void handleActiveWindowChangedX(); + void listenRootWindowXEvent(); + void listenWindowXEvent(WindowInfoX *winInfo); + + void handleRootWindowPropertyNotifyEvent(XCBAtom atom); + void handleDestroyNotifyEvent(XWindow xid); + void handleMapNotifyEvent(XWindow xid); + void handleConfigureNotifyEvent(XWindow xid, int x, int y, int width, int height); + void handlePropertyNotifyEvent(XWindow xid, XCBAtom atom); + + void eventHandler(uint8_t type, void *event); + void listenWindowEvent(WindowInfoX *winInfo); + void listenXEventUseXlib(); + void listenXEventUseXCB(); + +signals: + void needUpdateHideState(bool delay); + +private: + void addWindowLastConfigureEvent(XWindow xid, ConfigureEvent* event); + QPair getWindowLastConfigureEvent(XWindow xid); + void delWindowLastConfigureEvent(XWindow xid); + + QMap windowInfoMap; + Dock *dock; + QMap> windowLastConfigureEventMap; // 手动回收ConfigureEvent和QTimer + QMutex mutex; + XWindow rootWindow; // 根窗口 + bool listenXEvent; // 监听X事件 +}; + +#endif // X11MANAGER_H diff --git a/src/modules/launcher/category.cpp b/src/modules/launcher/category.cpp new file mode 100644 index 0000000..6ee640a --- /dev/null +++ b/src/modules/launcher/category.cpp @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "category.h" + +Category::Category() +{ + +} + +Category::~Category() +{ + +} + +QString Category::getStr(Categorytype ty) { + QMap ty2str = { + {Categorytype::CategoryInternet, "Internet"}, + {Categorytype::CategoryChat, "Chat"}, + {Categorytype::CategoryMusic, "Music"}, + {Categorytype::CategoryVideo, "Video"}, + {Categorytype::CategoryGraphics, "Graphics"}, + {Categorytype::CategoryOffice, "Office"}, + {Categorytype::CategoryGame, "Game"}, + {Categorytype::CategoryReading, "Reading"}, + {Categorytype::CategoryDevelopment, "Development"}, + {Categorytype::CategorySystem, "System"}, + {Categorytype::CategoryOthers, "Others"}, + }; + return ty2str.find(ty) != ty2str.end() ? ty2str[ty] : "Others"; +} + +QString Category::pinYin(Categorytype ty) { + QMap ty2py = { + {Categorytype::CategoryInternet, "wangluo"}, + {Categorytype::CategoryChat, "shejiaogoutong"}, + {Categorytype::CategoryMusic, "yinyuexinshang"}, + {Categorytype::CategoryVideo, "shipinbofang"}, + {Categorytype::CategoryGraphics, "tuxintuxiang"}, + {Categorytype::CategoryOffice, "bangongxuexi"}, + {Categorytype::CategoryGame, "youxiyule"}, + {Categorytype::CategoryReading, "yuedufanyi"}, + {Categorytype::CategoryDevelopment, "bianchengkaifai"}, + {Categorytype::CategorySystem, "xitongguanli"}, + {Categorytype::CategoryOthers, "qita"}, + }; + return ty2py.find(ty) != ty2py.end() ? ty2py[ty] : "qita"; +} + +Categorytype Category::parseCategoryString(QString str) { + QMap name2ty { + {"internet", Categorytype::CategoryInternet}, + {"chat", Categorytype::CategoryChat}, + {"music", Categorytype::CategoryMusic}, + {"video", Categorytype::CategoryVideo}, + {"graphics", Categorytype::CategoryGraphics}, + {"office", Categorytype::CategoryOffice}, + {"game", Categorytype::CategoryGame}, + {"reading", Categorytype::CategoryReading}, + {"development", Categorytype::CategoryDevelopment}, + {"system", Categorytype::CategorySystem}, + {"others", Categorytype::CategoryOthers}, + }; + return name2ty.find(str) != name2ty.end() ? name2ty[str] : Categorytype::CategoryErr; +} + +QList Category::parseXCategoryString(QString str) { + QMultiMap xname2ty { + {"2dgraphics", Categorytype::CategoryGraphics}, + {"3dgraphics", Categorytype::CategoryGraphics}, + {"accessibility", Categorytype::CategorySystem}, + {"accessories", Categorytype::CategoryOthers}, + {"actiongame", Categorytype::CategoryGame}, + {"advancedsettings", Categorytype::CategorySystem}, + {"adventuregame", Categorytype::CategoryGame}, + {"amusement", Categorytype::CategoryGame}, + {"applet", Categorytype::CategoryOthers}, + {"arcadegame", Categorytype::CategoryGame}, + {"archiving", Categorytype::CategorySystem}, + {"art", Categorytype::CategoryOffice}, + {"artificialintelligence", Categorytype::CategoryOffice}, + {"astronomy", Categorytype::CategoryOffice}, + {"audio", Categorytype::CategoryMusic}, + {"audiovideo", Categorytype::CategoryMusic}, + {"audiovideo", Categorytype::CategoryVideo}, + {"audiovideoediting", Categorytype::CategoryMusic}, + {"audiovideoediting", Categorytype::CategoryVideo}, + {"biology", Categorytype::CategoryOffice}, + {"blocksgame", Categorytype::CategoryGame}, + {"boardgame", Categorytype::CategoryGame}, + {"building", Categorytype::CategoryDevelopment}, + {"calculator", Categorytype::CategorySystem}, + {"calendar", Categorytype::CategorySystem}, + {"cardgame", Categorytype::CategoryGame}, + {"cd", Categorytype::CategoryMusic}, + {"chart", Categorytype::CategoryOffice}, + {"chat", Categorytype::CategoryChat}, + {"chemistry", Categorytype::CategoryOffice}, + {"clock", Categorytype::CategorySystem}, + {"compiz", Categorytype::CategorySystem}, + {"compression", Categorytype::CategorySystem}, + {"computerscience", Categorytype::CategoryOffice}, + {"consoleonly", Categorytype::CategoryOthers}, + {"contactmanagement", Categorytype::CategoryChat}, + {"core", Categorytype::CategoryOthers}, + {"debugger", Categorytype::CategoryDevelopment}, + {"desktopsettings", Categorytype::CategorySystem}, + {"desktoputility", Categorytype::CategorySystem}, + {"development", Categorytype::CategoryDevelopment}, + {"dialup", Categorytype::CategorySystem}, + {"dictionary", Categorytype::CategoryOffice}, + {"discburning", Categorytype::CategorySystem}, + {"documentation", Categorytype::CategoryOffice}, + {"editors", Categorytype::CategoryOthers}, + {"education", Categorytype::CategoryOffice}, + {"electricity", Categorytype::CategoryOffice}, + {"electronics", Categorytype::CategoryOffice}, + {"email", Categorytype::CategoryInternet}, + {"emulator", Categorytype::CategoryGame}, + {"engineering", Categorytype::CategorySystem}, + {"favorites", Categorytype::CategoryOthers}, + {"filemanager", Categorytype::CategorySystem}, + {"filesystem", Categorytype::CategorySystem}, + {"filetools", Categorytype::CategorySystem}, + {"filetransfer", Categorytype::CategoryInternet}, + {"finance", Categorytype::CategoryOffice}, + {"game", Categorytype::CategoryGame}, + {"geography", Categorytype::CategoryOffice}, + {"geology", Categorytype::CategoryOffice}, + {"geoscience", Categorytype::CategoryOthers}, + {"gnome", Categorytype::CategorySystem}, + {"gpe", Categorytype::CategoryOthers}, + {"graphics", Categorytype::CategoryGraphics}, + {"guidesigner", Categorytype::CategoryDevelopment}, + {"hamradio", Categorytype::CategoryOffice}, + {"hardwaresettings", Categorytype::CategorySystem}, + {"ide", Categorytype::CategoryDevelopment}, + {"imageprocessing", Categorytype::CategoryGraphics}, + {"instantmessaging", Categorytype::CategoryChat}, + {"internet", Categorytype::CategoryInternet}, + {"ircclient", Categorytype::CategoryChat}, + {"kde", Categorytype::CategorySystem}, + {"kidsgame", Categorytype::CategoryGame}, + {"literature", Categorytype::CategoryOffice}, + {"logicgame", Categorytype::CategoryGame}, + {"math", Categorytype::CategoryOffice}, + {"medicalsoftware", Categorytype::CategoryOffice}, + {"meteorology", Categorytype::CategoryOthers}, + {"midi", Categorytype::CategoryMusic}, + {"mixer", Categorytype::CategoryMusic}, + {"monitor", Categorytype::CategorySystem}, + {"motif", Categorytype::CategoryOthers}, + {"multimedia", Categorytype::CategoryVideo}, + {"music", Categorytype::CategoryMusic}, + {"network", Categorytype::CategoryInternet}, + {"news", Categorytype::CategoryReading}, + {"numericalanalysis", Categorytype::CategoryOffice}, + {"ocr", Categorytype::CategoryGraphics}, + {"office", Categorytype::CategoryOffice}, + {"p2p", Categorytype::CategoryInternet}, + {"packagemanager", Categorytype::CategorySystem}, + {"panel", Categorytype::CategorySystem}, + {"pda", Categorytype::CategorySystem}, + {"photography", Categorytype::CategoryGraphics}, + {"physics", Categorytype::CategoryOffice}, + {"pim", Categorytype::CategoryOthers}, + {"player", Categorytype::CategoryMusic}, + {"player", Categorytype::CategoryVideo}, + {"playonlinux", Categorytype::CategoryOthers}, + {"presentation", Categorytype::CategoryOffice}, + {"printing", Categorytype::CategoryOffice}, + {"profiling", Categorytype::CategoryDevelopment}, + {"projectmanagement", Categorytype::CategoryOffice}, + {"publishing", Categorytype::CategoryOffice}, + {"puzzlegame", Categorytype::CategoryGame}, + {"rastergraphics", Categorytype::CategoryGraphics}, + {"recorder", Categorytype::CategoryMusic}, + {"recorder", Categorytype::CategoryVideo}, + {"remoteaccess", Categorytype::CategorySystem}, + {"revisioncontrol", Categorytype::CategoryDevelopment}, + {"robotics", Categorytype::CategoryOffice}, + {"roleplaying", Categorytype::CategoryGame}, + {"scanning", Categorytype::CategoryOffice}, + {"science", Categorytype::CategoryOffice}, + {"screensaver", Categorytype::CategoryOthers}, + {"sequencer", Categorytype::CategoryMusic}, + {"settings", Categorytype::CategorySystem}, + {"security", Categorytype::CategorySystem}, + {"simulation", Categorytype::CategoryGame}, + {"sportsgame", Categorytype::CategoryGame}, + {"spreadsheet", Categorytype::CategoryOffice}, + {"strategygame", Categorytype::CategoryGame}, + {"system", Categorytype::CategorySystem}, + {"systemsettings", Categorytype::CategorySystem}, + {"technical", Categorytype::CategoryOthers}, + {"telephony", Categorytype::CategorySystem}, + {"telephonytools", Categorytype::CategorySystem}, + {"terminalemulator", Categorytype::CategorySystem}, + {"texteditor", Categorytype::CategoryOffice}, + {"texttools", Categorytype::CategoryOffice}, + {"transiation", Categorytype::CategoryDevelopment}, + {"translation", Categorytype::CategoryReading}, + {"trayicon", Categorytype::CategorySystem}, + {"tuner", Categorytype::CategoryMusic}, + {"tv", Categorytype::CategoryVideo}, + {"utility", Categorytype::CategorySystem}, + {"vectorgraphics", Categorytype::CategoryGraphics}, + {"video", Categorytype::CategoryVideo}, + {"videoconference", Categorytype::CategoryInternet}, + {"viewer", Categorytype::CategoryGraphics}, + {"webbrowser", Categorytype::CategoryInternet}, + {"webdevelopment", Categorytype::CategoryDevelopment}, + {"wine", Categorytype::CategoryOthers}, + {"wine-programs-accessories", Categorytype::CategoryOthers}, + {"wordprocessor", Categorytype::CategoryOffice}, + {"x-alsa", Categorytype::CategoryMusic}, + {"x-bible", Categorytype::CategoryReading}, + {"x-bluetooth", Categorytype::CategorySystem}, + {"x-debian-applications-emulators", Categorytype::CategoryGame}, + {"x-digital_processing", Categorytype::CategorySystem}, + {"x-enlightenment", Categorytype::CategorySystem}, + {"x-geeqie", Categorytype::CategoryGraphics}, + {"x-gnome-networksettings", Categorytype::CategorySystem}, + {"x-gnome-personalsettings", Categorytype::CategorySystem}, + {"x-gnome-settings-panel", Categorytype::CategorySystem}, + {"x-gnome-systemsettings", Categorytype::CategorySystem}, + {"x-gnustep", Categorytype::CategorySystem}, + {"x-islamic-software", Categorytype::CategoryReading}, + {"x-jack", Categorytype::CategoryMusic}, + {"x-kde-edu-misc", Categorytype::CategoryReading}, + {"x-kde-internet", Categorytype::CategorySystem}, + {"x-kde-more", Categorytype::CategorySystem}, + {"x-kde-utilities-desktop", Categorytype::CategorySystem}, + {"x-kde-utilities-file", Categorytype::CategorySystem}, + {"x-kde-utilities-peripherals", Categorytype::CategorySystem}, + {"x-kde-utilities-pim", Categorytype::CategorySystem}, + {"x-lxde-settings", Categorytype::CategorySystem}, + {"x-mandriva-office-publishing", Categorytype::CategoryOthers}, + {"x-mandrivalinux-internet-other", Categorytype::CategorySystem}, + {"x-mandrivalinux-office-other", Categorytype::CategoryOffice}, + {"x-mandrivalinux-system-archiving-backup", Categorytype::CategorySystem}, + {"x-midi", Categorytype::CategoryMusic}, + {"x-misc", Categorytype::CategorySystem}, + {"x-multitrack", Categorytype::CategoryMusic}, + {"x-novell-main", Categorytype::CategorySystem}, + {"x-quran", Categorytype::CategoryReading}, + {"x-red-hat-base", Categorytype::CategorySystem}, + {"x-red-hat-base-only", Categorytype::CategorySystem}, + {"x-red-hat-extra", Categorytype::CategorySystem}, + {"x-red-hat-serverconfig", Categorytype::CategorySystem}, + {"x-religion", Categorytype::CategoryReading}, + {"x-sequencers", Categorytype::CategoryMusic}, + {"x-sound", Categorytype::CategoryMusic}, + {"x-sun-supported", Categorytype::CategorySystem}, + {"x-suse-backup", Categorytype::CategorySystem}, + {"x-suse-controlcenter-lookandfeel", Categorytype::CategorySystem}, + {"x-suse-controlcenter-system", Categorytype::CategorySystem}, + {"x-suse-core", Categorytype::CategorySystem}, + {"x-suse-core-game", Categorytype::CategoryGame}, + {"x-suse-core-office", Categorytype::CategoryOffice}, + {"x-suse-sequencer", Categorytype::CategoryMusic}, + {"x-suse-yast", Categorytype::CategorySystem}, + {"x-suse-yast-high_availability", Categorytype::CategorySystem}, + {"x-synthesis", Categorytype::CategorySystem}, + {"x-turbolinux-office", Categorytype::CategoryOffice}, + {"x-xfce", Categorytype::CategorySystem}, + {"x-xfce-toplevel", Categorytype::CategorySystem}, + {"x-xfcesettingsdialog", Categorytype::CategorySystem}, + {"x-ximian-main", Categorytype::CategorySystem}, + }; + + return {xname2ty.values(str)}; +} diff --git a/src/modules/launcher/category.h b/src/modules/launcher/category.h new file mode 100644 index 0000000..329e4c2 --- /dev/null +++ b/src/modules/launcher/category.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CATEGORY_H +#define CATEGORY_H + +#include "common.h" + +#include +#include + +// 应用类型 +enum class Categorytype { + CategoryInternet, + CategoryChat, + CategoryMusic, + CategoryVideo, + CategoryGraphics, + CategoryGame, + CategoryOffice, + CategoryReading, + CategoryDevelopment, + CategorySystem, + CategoryOthers, + CategoryErr, +}; + +class Category +{ +public: + Category(); + ~Category(); + + // 类型转字符串 + static QString getStr(Categorytype ty); + // 类型转拼音 + static QString pinYin(Categorytype ty); + // 字符串转类型 + static Categorytype parseCategoryString(QString str); + // Xorg类型字符串转类型列表 + static QList parseXCategoryString(QString str); +}; + +#endif // CATEGORY_H diff --git a/src/modules/launcher/common.h b/src/modules/launcher/common.h new file mode 100644 index 0000000..aebc7cc --- /dev/null +++ b/src/modules/launcher/common.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef COMMON_H +#define COMMON_H + +#include +#include + +// DBus服务、路径名 +const QString dbusService = "org.deepin.dde.daemon.Launcher1"; +const QString dbusPath = "/org/deepin/dde/daemon/Launcher1"; + +// 组策略配置 +const QString configLauncher = "com.deepin.dde.launcher"; +const QString keyDisplayMode = "Display_Mode"; +const QString keyFullscreen = "Fullscreen"; +const QString keyAppsUseProxy = "Apps_Use_Proxy"; +const QString keyAppsDisableScaling = "Apps_Disable_Scaling"; +const QString keyAppsHidden = "Apps_Hidden"; +const QString keyPackageNameSearch = "Search_Package_Name"; + +// 应用配置 +const QString lastoreDataDir = "/var/lib/lastore"; +const QString desktopPkgMapFile = lastoreDataDir + "/desktop_package.json"; +const QString applicationsFile = lastoreDataDir + "/applications.json"; + +const QString ddeDataDir = "/usr/share/dde/data/"; +const QString appNameTranslationsFile = ddeDataDir + "app_name_translations.json"; + +// 应用状态 +const QString appStatusCreated = "created"; +const QString appStatusModified = "updated"; +const QString appStatusDeleted = "deleted"; + +// flatpak应用 +const QString flatpakBin = "flatpak"; + +// 启动器执行程序 +const QString launcherExe = "/usr/bin/dde-launcher"; +#endif // COMMON_H diff --git a/src/modules/launcher/dbusadaptorlauncher.cpp b/src/modules/launcher/dbusadaptorlauncher.cpp new file mode 100644 index 0000000..d8bcd8b --- /dev/null +++ b/src/modules/launcher/dbusadaptorlauncher.cpp @@ -0,0 +1,126 @@ +#include "dbusadaptorlauncher.h" + +DBusAdaptorLauncher::DBusAdaptorLauncher(QObject *parent) + : QDBusAbstractAdaptor(parent) +{ + // constructor + setAutoRelaySignals(true); + + Launcher *launcher = static_cast(QObject::parent()); + if (launcher) { + connect(launcher, &Launcher::displayModeChanged, this, &DBusAdaptorLauncher::DisplayModeChanged); + connect(launcher, &Launcher::fullScreenChanged, this, &DBusAdaptorLauncher::FullScreenChanged); + } +} + +DBusAdaptorLauncher::~DBusAdaptorLauncher() +{ + // destructor +} + +Launcher *DBusAdaptorLauncher::parent() const +{ + return static_cast(QObject::parent()); +} + +int DBusAdaptorLauncher::displayMode() const +{ + return parent()->getDisplayMode(); +} + +void DBusAdaptorLauncher::setDisplayMode(int value) +{ + parent()->setDisplayMode(value); +} + +bool DBusAdaptorLauncher::fullscreen() const +{ + return parent()->getFullScreen(); +} + +void DBusAdaptorLauncher::setFullscreen(bool value) +{ + parent()->setFullScreen(value); +} + +bool DBusAdaptorLauncher::AddAutostart(const QString &desktopFile) +{ + QDBusInterface interface = QDBusInterface("com.deepin.daemon.Display", "/com/deepin/StartManager", "com.deepin.StartManager"); + QDBusReply reply = interface.call("AddAutostart", desktopFile); + return reply.isValid() ? reply.value() : false; +} + +// TODO +QString DBusAdaptorLauncher::GetAllItemInfos() +{ + // return parent()->getAllItemInfos(); + return ""; +} + +QStringList DBusAdaptorLauncher::GetAllNewInstalledApps() +{ + return parent()->getAllNewInstalledApps(); +} + +bool DBusAdaptorLauncher::GetDisableScaling(const QString &id) +{ + return parent()->getDisableScaling(id); +} + +// TODO +QString DBusAdaptorLauncher::GetItemInfo(const QString &id) +{ + //return parent()->getItemInfo(); + return ""; +} + +bool DBusAdaptorLauncher::GetUseProxy(const QString &id) +{ + return parent()->getUseProxy(id); +} + +bool DBusAdaptorLauncher::IsItemOnDesktop(const QString &id) +{ + return parent()->isItemOnDesktop(id); +} + +bool DBusAdaptorLauncher::LaunchWithTimestamp(const QString &desktopFile, int time) +{ + + QDBusInterface interface = QDBusInterface("com.deepin.daemon.Display", "/com/deepin/StartManager", "com.deepin.StartManager"); + QDBusReply reply = interface.call("LaunchWithTimestamp", desktopFile, time); + return reply.isValid() ? reply.value() : false; +} + +bool DBusAdaptorLauncher::RemoveAutostart(const QString &desktopFile) +{ + QDBusInterface interface = QDBusInterface("com.deepin.daemon.Display", "/com/deepin/StartManager", "com.deepin.StartManager"); + QDBusReply reply = interface.call("RemoveAutostart", desktopFile); + return reply.isValid() ? reply.value() : false; +} + +bool DBusAdaptorLauncher::RequestRemoveFromDesktop(const QString &id) +{ + return parent()->requestRemoveFromDesktop(id); +} + +bool DBusAdaptorLauncher::RequestSendToDesktop(const QString &id) +{ + return parent()->requestSendToDesktop(id); +} + +void DBusAdaptorLauncher::RequestUninstall(const QString &id) +{ + parent()->requestUninstall(id); +} + +void DBusAdaptorLauncher::SetDisableScaling(const QString &id, bool value) +{ + parent()->setDisableScaling(id, value); +} + +void DBusAdaptorLauncher::SetUseProxy(const QString &id, bool value) +{ + parent()->setUseProxy(id, value); +} + diff --git a/src/modules/launcher/dbusadaptorlauncher.h b/src/modules/launcher/dbusadaptorlauncher.h new file mode 100644 index 0000000..b28e95f --- /dev/null +++ b/src/modules/launcher/dbusadaptorlauncher.h @@ -0,0 +1,139 @@ +#ifndef DBUSADAPTORLAUNCHER_H +#define DBUSADAPTORLAUNCHER_H + +#include "launcher.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Adaptor class for interface org.deepin.dde.daemon.Launcher1 + */ +class DBusAdaptorLauncher: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.deepin.dde.daemon.Launcher1") + Q_CLASSINFO("D-Bus Introspection", "" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" + "") +public: + DBusAdaptorLauncher(QObject *parent); + virtual ~DBusAdaptorLauncher(); + + Launcher *parent() const; + +public: // PROPERTIES + Q_PROPERTY(int DisplayMode READ displayMode WRITE setDisplayMode NOTIFY DisplayModeChanged) + int displayMode() const; + void setDisplayMode(int value); + + Q_PROPERTY(bool Fullscreen READ fullscreen WRITE setFullscreen NOTIFY FullScreenChanged) + bool fullscreen() const; + void setFullscreen(bool value); + +public Q_SLOTS: // METHODS + bool AddAutostart(const QString &desktopFile); + QString GetAllItemInfos(); + QStringList GetAllNewInstalledApps(); + bool GetDisableScaling(const QString &id); + QString GetItemInfo(const QString &id); + bool GetUseProxy(const QString &id); + bool IsItemOnDesktop(const QString &id); + bool LaunchWithTimestamp(const QString &desktopFile, int time); + bool RemoveAutostart(const QString &desktopFile); + bool RequestRemoveFromDesktop(const QString &id); + bool RequestSendToDesktop(const QString &id); + void RequestUninstall(const QString &id); + void SetDisableScaling(const QString &id, bool value); + void SetUseProxy(const QString &id, bool value); +Q_SIGNALS: // SIGNALS + void ItemChanged(const QString &status, const QString &itemInfo, qlonglong categoryID); + void NewAppLaunched(const QString &appID); + void UninstallFailed(const QString &appId, const QString &errMsg); + void UninstallSuccess(const QString &appID); + + void DisplayModeChanged(int mode); + void FullScreenChanged(bool isFull); +}; + +#endif diff --git a/src/modules/launcher/launcher.cpp b/src/modules/launcher/launcher.cpp new file mode 100644 index 0000000..8b9bdfe --- /dev/null +++ b/src/modules/launcher/launcher.cpp @@ -0,0 +1,1111 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "launcher.h" +#include "lang.h" +#include "desktopinfo.h" +#include "settings.h" +#include "basedir.h" +#include "launchersettings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +DCORE_USE_NAMESPACE + +#define SETTING LauncherSettings::instance() + +Launcher::Launcher(QObject *parent) + : SynModule(parent) +{ + registeModule("launcher"); + initSettings(); + + for (auto dir : BaseDir::appDirs()) { + appDirs.push_back(dir.c_str()); + } + + loadDesktopPkgMap(); + loadPkgCategoryMap(); + loadNameMap(); + initItems(); + + // 关联org.deepin.daemon.DFWatcher1接口事件Event + QDBusConnection::sessionBus().connect("org.deepin.daemon.DFWatcher1", + "/org/deepin/daemon/DFWatcher1", + "org.deepin.daemon.DFWatcher1", + "Event", "", // TODO 修正事件参数 + this, SLOT(handleFSWatcherEvents(QDBusMessage))); + + // 关联org.deepin.daemon.LRecorder1接口事件ServiceRestarted + watchDataDirs(); // 监控应用目录 + QDBusConnection::sessionBus().connect("org.deepin.daemon.AlRecoder1", + "/org/deepin/daemon/AlRecoder1", + "org.deepin.daemon.AlRecoder1", + "ServiceRestarted", + this, SLOT(handleLRecoderRestart(QDBusMessage))); + + + QDBusConnectionInterface *ifc = QDBusConnection::sessionBus().interface(); + connect(ifc, &QDBusConnectionInterface::serviceOwnerChanged, this, [ & ](const QString &name, const QString &oldOwner, const QString &newOwner) { + Q_UNUSED(name) + Q_UNUSED(oldOwner) + Q_UNUSED(newOwner) + watchDataDirs(); + }); + + // 关联org.deepin.daemon.LRecorder1接口事件Launched + QDBusConnection::sessionBus().connect("org.deepin.daemon.AlRecoder1", + "/org/deepin/daemon/AlRecoder1", + "org.deepin.daemon.AlRecoder1", + "Launched", "sa", + this, SLOT([&](QDBusMessage msg) { + QString path = msg.arguments().at(0).toString(); + Item item = getItemByPath(path); + if (item.isValid()) + Q_EMIT NewAppLaunched(item.id); + })); +} + +Launcher::~Launcher() +{ + QDBusConnection::sessionBus().unregisterObject(dbusPath); +} + +void Launcher::setSynConfig(QByteArray ba) +{ + if (!SETTING) + return; + + QJsonDocument doc = QJsonDocument::fromJson(ba); + QJsonObject obj = doc.object(); + SETTING->setDisplayMode(obj["display_mode"].toInt() == 1 ? "category" : "free"); + SETTING->setFullscreenMode(obj["fullscreen"].toBool()); +} + +QByteArray Launcher::getSyncConfig() +{ + QJsonObject obj; + obj["version"] = "1.0"; + obj["display_mode"] = SETTING->getDisplayMode(); + obj["fullscreen"] = SETTING->getFullscreenMode(); + QJsonDocument doc(obj); + return doc.toJson(); +} + +const QMap *Launcher::getItems() +{ + return &itemsMap; +} + +int Launcher::getDisplayMode() +{ + return SETTING->getDisplayMode() == "category" ? 1 : 0; +} + +bool Launcher::getFullScreen() +{ + return SETTING->getFullscreenMode(); +} + +void Launcher::setDisplayMode(int value) +{ + SETTING->setDisplayMode(value == 1 ? "category" : "free"); +} + +void Launcher::setFullScreen(bool isFull) +{ + SETTING->setFullscreenMode(isFull); +} + +// 获取所有应用信息 +QVector Launcher::getAllItemInfos() +{ + QVector ret; + for (auto item : itemsMap) { + ret.push_back(item.info); + } + return ret; +} + +// 获取未打开的应用 + QStringList Launcher::getAllNewInstalledApps() +{ + QStringList ret; + QMap newApps; + QDBusInterface interface = QDBusInterface("org.deepin.daemon.AlRecoder1", "/org/deepin/daemon/AlRecoder1", "org.deepin.daemon.AlRecoder1"); + QDBusReply> reply = interface.call("GetNew"); + if (reply.isValid()) + newApps = reply; + + for (auto iter = newApps.begin(); iter != newApps.end(); iter++) { + if (iter.value().size() > 0) { + ret << iter.value(); + } + } + return ret; +} + +// 获取应用是否缩放 +bool Launcher::getDisableScaling(QString appId) +{ + if (itemsMap.find(appId) == itemsMap.end()) + return false; + + for (const auto &app : SETTING->getDisableScalingApps()) { + if (app == appId) + return true; + } + return false; +} + +// 获取应用信息 +ItemInfo Launcher::getItemInfo(QString appId) +{ + ItemInfo info; + if (itemsMap.find(appId) == itemsMap.end()) + return info; + + info = itemsMap[appId].info; + return info; +} + +// 获取应用是否代理 +bool Launcher::getUseProxy(QString appId) +{ + if (itemsMap.find(appId) == itemsMap.end()) + return false; + + for (const auto &app : SETTING->getUseProxyApps()) { + if (app == appId) + return true; + } + return false; +} + +// 桌面是否存在应用desktop文件 +bool Launcher::isItemOnDesktop(QString appId) +{ + if (itemsMap.find(appId) == itemsMap.end()) + return false; + + QString filePath(QDir::homePath() + "/Desktop/" + appId + ".desktop"); + QFileInfo info(filePath); + return info.exists(); +} + +// 移除桌面快捷方式 +bool Launcher::requestRemoveFromDesktop(QString appId) +{ + if (itemsMap.find(appId) == itemsMap.end()) + return false; + + QString filePath(QDir::homePath() + "/Desktop/" + appId + ".desktop"); + QFileInfo info(filePath); + if (!info.exists()) + return true; + + QFile file(filePath); + return file.remove(); +} + +// 发送应用到桌面 +bool Launcher::requestSendToDesktop(QString appId) +{ + if (itemsMap.find(appId) == itemsMap.end()) + return false; + + QString filePath(QDir::homePath() + "/Desktop/" + appId + ".desktop"); + QFileInfo info(filePath); + if (info.exists()) // 已经存在 + return false; + + // 创建桌面快捷方式文件 + DesktopInfo dinfo(itemsMap[appId].info.path.toStdString()); + dinfo.kf.setKey(MainSection, dbusService.toStdString(), "X-Deepin-CreatedBy"); + dinfo.kf.setKey(MainSection, appId.toStdString(), "X-Deepin-AppID"); + if (!dinfo.kf.saveToFile(filePath.toStdString())) + return false; + + std::thread thread([]() { + // TODO 播放系统音效 + + }); + thread.detach(); + + return true; +} + +// 卸载应用 +void Launcher::requestUninstall(QString appId) +{ + if (itemsMap.find(appId) == itemsMap.end()) + return; + + // 限制调用方 + QString cmd = QString("cat /proc/%1/cmdline").arg(QString::number(QDBusConnection::sessionBus().interface()->servicePid(message().service()))); + QProcess process; + QStringList args {"-c", cmd}; + process.start("sh", args); + process.waitForReadyRead(); + QString result = QString::fromUtf8(process.readAllStandardOutput()); + qInfo() << "RequestUninstall fucntion called by :" << result; + process.close(); + if (result == launcherExe) { + qWarning() << result << " has no right to uninstall " << appId; + return; + } + + // 执行卸载动作 + std::thread thread([&](QString appId) { + const auto &item = itemsMap[appId]; + DesktopInfo info(item.info.path.toStdString()); + if (!info.isValidDesktop()) + return; + + // 即将卸载appId + QDBusInterface interface = QDBusInterface("org.deepin.daemon.AlRecoder1", "/org/deepin/daemon/AlRecoder1", "org.deepin.daemon.AlRecoder1"); + interface.call("UninstallHints", item.info.path); + + bool ret = doUninstall(info, item); // 阻塞等待 + if (!ret) { + QString msg = QString("uninstall %1 result %2").arg(info.getName().c_str()).arg(ret); + Q_EMIT UninstallFailed(appId, msg); + qInfo() << msg; + return; + } + + // 从自动启动目录中移除 + QString filePath(QDir::homePath() + "/.config/autostart/" + appId + ".desktop"); + QFile file(filePath); + file.remove(); + Q_EMIT UninstallSuccess(appId); + }, appId); + thread.detach(); +} + +// 设置应用禁用缩放 +void Launcher::setDisableScaling(QString appId, bool value) +{ + if (itemsMap.find(appId) == itemsMap.end()) + return; + + QVector apps = SETTING->getDisableScalingApps(); + if (value) { + for (const auto &app : apps) { + if (app == appId) { + return; + } + } + apps.append(appId); + } else { + bool found = false; + for (auto iter = apps.begin(); iter != apps.end(); iter++) { + if (*iter == appId) { + found = true; + apps.erase(iter); + break; + } + } + if (!found) + return; + } + + SETTING->setDisableScalingApps(apps); +} + +// 设置用户代理 +void Launcher::setUseProxy(QString appId, bool value) +{ + if (itemsMap.find(appId) == itemsMap.end()) + return; + + + QVector apps = SETTING->getUseProxyApps(); + if (value) { + for (const auto &app : apps) { + if (app == appId) { + return; + } + } + apps.append(appId); + } else { + bool found = false; + for (auto iter = apps.begin(); iter != apps.end(); iter++) { + if (*iter == appId) { + found = true; + apps.erase(iter); + break; + } + } + if (!found) + return; + } + SETTING->setUseProxy(apps); +} + +void Launcher::handleFSWatcherEvents(QDBusMessage msg) +{ + QList ret = msg.arguments(); + if (ret.size() != 2) + return; + + QString filePath = ret[0].toString(); + int op = ret[0].toInt(); + + // desktop包文件变化 + if (filePath == desktopPkgMapFile) { + loadDesktopPkgMap(); + + // retry queryPkgName for m.noPkgItemIDs + for (auto iter = noPkgItemIds.begin(); iter != noPkgItemIds.end(); iter++) { + QString id = iter.key(); + QString pkg = queryPkgName(id, ""); + if (pkg.isEmpty()) + continue; + + Item &item = itemsMap[id]; + Categorytype ty = queryCategoryId(&item); + if (ty != item.info.categoryId) { + item.info.categoryId = ty; + emitItemChanged(&item, appStatusModified); + } + noPkgItemIds.remove(id); + } + } else if (filePath == applicationsFile) { // 应用信息文件变化 + loadPkgCategoryMap(); + } else if (filePath.endsWith(".desktop")){ // desktop文件变化 + checkDesktopFile(filePath); + } +} + +void Launcher:: handleLRecoderRestart(QDBusMessage msg) +{ + Q_UNUSED(msg) + watchDataDirs(); +} + +void Launcher::initSettings() +{ + connect(SETTING, &LauncherSettings::displayModeChanged, this, [&](QString mode) { + Q_EMIT displayModeChanged(mode == "category" ? 1 : 0); + }); + connect(SETTING, &LauncherSettings::fullscreenChanged, this, &Launcher::fullScreenChanged); + connect(SETTING, &LauncherSettings::hiddenAppsChanged, this, &Launcher::handleAppHiddenChanged); + + appsHidden = SETTING->getHiddenApps(); +} + +// 加载应用包信息 +void Launcher::loadDesktopPkgMap() +{ + QFile file(desktopPkgMapFile); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); + file.close(); + if (!doc.isObject()) + return; + + QJsonObject obj = doc.object(); + QVariantMap varMap = obj.toVariantMap(); + desktopPkgMap.clear(); + for (auto iter = varMap.begin(); iter != varMap.end(); iter++) { + if (!QDir::isAbsolutePath(iter.key())) + continue; + + QString appId = getAppIdByFilePath(iter.key(), appDirs); + if (appId == "") + continue; + + desktopPkgMap[appId] = iter.value().toString(); + } +} + +// 加载应用类型信息 +void Launcher::loadPkgCategoryMap() +{ + QFile file(applicationsFile); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); + file.close(); + if (!doc.isObject()) + return; + + QJsonObject obj = doc.object(); + QVariantMap varMap = obj.toVariantMap(); + pkgCategoryMap.clear(); + for (auto iter = varMap.begin(); iter != varMap.end(); iter++) { + if (!iter.value().toJsonValue().isObject()) + continue; + + QJsonObject infoObj = iter.value().toJsonObject(); + QVariantMap infoMap = infoObj.toVariantMap(); + QString category = infoMap["category"].toString(); + pkgCategoryMap[iter.key()] = Category::parseCategoryString(category); + } +} + +void Launcher::checkDesktopFile(QString filePath) +{ + QString appId = getAppIdByFilePath(filePath, appDirs); + if (appId.isEmpty()) + return; + + DesktopInfo info(filePath.toStdString()); + if (info.isValidDesktop()) { + Item newItem = NewItemWithDesktopInfo(info); + newItem.info.id = getAppIdByFilePath(newItem.info.path, appDirs); + bool shouldShow = info.shouldShow() && + !isDeepinCustomDesktopFile(newItem.info.path) && + !appsHidden.contains(newItem.info.id); + + // update item + if (itemsMap.find(appId) != itemsMap.end()) { + if (shouldShow) { + addItem(newItem); + emitItemChanged(&newItem, appStatusModified); + } else { + itemsMap.remove(appId); + emitItemChanged(&newItem, appStatusDeleted); + } + } else if (shouldShow){ // add item + if (info.isExecutableOk()) { + addItem(newItem); + emitItemChanged(&newItem, appStatusCreated); + } + } + } else { + if (itemsMap.find(appId) != itemsMap.end()) { + Item item = itemsMap[appId]; + emitItemChanged(&item, appStatusDeleted); + itemsMap.remove(appId); + + // 移除桌面上对应文件 + QFile file(QDir::homePath() + "/Desktop" + appId + ".desktop"); + file.remove(); + } + } +} + +// 响应DConfig中隐藏应用配置变化 +void Launcher::handleAppHiddenChanged() +{ + auto hiddenApps = SETTING->getHiddenApps(); + QSet newSet, oldSet; + for (const auto &app : hiddenApps) + newSet.insert(app); + + for (const auto &app : appsHidden) + oldSet.insert(app); + + // 处理新增隐藏应用 + for (const auto &app : newSet - oldSet) { + if (itemsMap.find(app) == itemsMap.end()) + continue; + + emitItemChanged(&itemsMap[app], appStatusDeleted); + itemsMap.remove(app); + } + + // 处理显示应用 + for (const auto &appId : oldSet - newSet) { + if (itemsMap.find(appId) == itemsMap.end()) + continue; + + DesktopInfo info = DesktopInfo(appId.toStdString()); + if (!info.isValidDesktop()) { + qInfo() << "appId " << appId << "is invalid app"; + } + + Item item = NewItemWithDesktopInfo(info); + item.info.id = getAppIdByFilePath(item.info.path, appDirs); + + if (!(info.shouldShow() && !isDeepinCustomDesktopFile(info.getFileName().c_str()))) + continue; + + addItem(item); + emitItemChanged(&item, appStatusCreated); + } + + appsHidden.clear(); + for (const auto &appId : hiddenApps) { + appsHidden.push_back(appId); + } +} + +// 加载翻译应用信息 +void Launcher::loadNameMap() +{ + QFile file(appNameTranslationsFile); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); + file.close(); + if (!doc.isObject()) + return; + + QJsonObject obj = doc.object(); + QVariantMap varMap = obj.toVariantMap(); + nameMap.clear(); + + QString lang(queryLangs()[0].data()); + for (auto iter = varMap.begin(); iter != varMap.end(); iter++) { + // 过滤非Object + if (!iter.value().toJsonValue().isObject()) + continue; + + // 过滤非本地语言 + if (iter.key() != lang) + continue; + + QJsonObject infoObj = iter.value().toJsonObject(); + QVariantMap infoMap = infoObj.toVariantMap(); + for (auto infoIter = infoMap.begin(); infoIter != infoMap.end(); infoIter++) { + // 过滤Object + if (infoIter.value().toJsonValue().isObject()) + continue; + + nameMap[infoIter.key()] = infoIter.value().toString(); + } + } +} + +// 初始化应用信息 +void Launcher::initItems() +{ + std::vector infos = AppsDir::getAllDesktopInfos(); + for (auto &app : infos) { + if (!app.isExecutableOk() + || app.getId().empty() + || isDeepinCustomDesktopFile(app.getFileName().c_str())) + { + continue; + } + + Item item = NewItemWithDesktopInfo(app); + if (appsHidden.contains(item.info.id)) + continue; + + addItem(item); + } +} + +void Launcher::addItem(Item item) +{ + if (!item.isValid()) + return; + + if (nameMap.size() > 0 && nameMap.find(item.info.id) != nameMap.end()) { + QString name = nameMap[item.info.id]; + if (!name.isEmpty()) + item.info.name = name; + } + + item.info.categoryId = queryCategoryId(&item); + itemsMap[item.info.id] = item; +} + +Categorytype Launcher::queryCategoryId(const Item *item) +{ + QString pkg = queryPkgName(item->info.id, item->info.path); + if (pkg.isEmpty()) { + noPkgItemIds[item->info.id] = 1; + + if (pkgCategoryMap.find(pkg) != pkgCategoryMap.end()) + return pkgCategoryMap[pkg]; + } + + Categorytype category = Category::parseCategoryString(item->xDeepinCategory); + if (category != Categorytype::CategoryErr) + return category; + + + return getXCategory(item); +} + +// 获取应用类型 +Categorytype Launcher::getXCategory(const Item *item) +{ + // 统计应用类型 + QMap categoriesMap; + for (const auto &category : item->categories) { + QString lCategory = category.toLower(); + QList tys; + Categorytype ty = Category::parseCategoryString(lCategory); + if (ty != Categorytype::CategoryErr) + tys.push_back(ty); + else if (Category::parseXCategoryString(lCategory).size() > 0) { + tys.append(Category::parseXCategoryString(lCategory)); + } + + for (const auto & ty : tys) + categoriesMap[ty]++; + } + + categoriesMap.remove(Categorytype::CategoryOthers); + if (categoriesMap.size() == 0) + return Categorytype::CategoryOthers; + + // 计算最多的类型 + int max = 0; + Categorytype ty {Categorytype::CategoryOthers}; + for (auto iter = categoriesMap.begin(); iter != categoriesMap.end(); iter++) { + if (iter.value() > max) { + max = iter.value(); + ty = iter.key(); + } + } + + QList maxCatogories {ty}; + for (auto iter = categoriesMap.begin(); iter != categoriesMap.end(); iter++) { + if (iter.key() != ty && iter.value() == max) { + maxCatogories.push_back(iter.key()); + } + } + + if (maxCatogories.size() == 1) + return maxCatogories[0]; + + qSort(maxCatogories.begin(), maxCatogories.end()); + + // 检查是否同时存在音乐和视频播放器 + QPair found; + for (auto iter = maxCatogories.begin(); iter != maxCatogories.end(); iter++) { + if (*iter == Categorytype::CategoryMusic) + found.first = true; + else if (*iter == Categorytype::CategoryVideo) + found.second = true; + } + + if (found.first && found.second) + return Categorytype::CategoryVideo; + + return maxCatogories[0]; +} + +// 使用dpkg -S,通过文件路径查包 +QString Launcher::queryPkgNameWithDpkg(const QString &itemPath) +{ + QProcess process; + process.start("dpkg -S " + itemPath); + if (!process.waitForFinished()) + return ""; + + QByteArray output = process.readAllStandardOutput(); + if (output.size() == 0) + return ""; + + std::vector splits = DString::splitChars(output.data(), '\n'); + if (splits.size() > 0) { + std::vector parts = DString::splitStr(splits[0], ':'); + if (parts.size() == 2) + return parts[0].c_str(); + } + return ""; +} + +// 通过id、path查询包名 +QString Launcher::queryPkgName(const QString &itemID, const QString &itemPath) +{ + if (!itemPath.isEmpty()) { + QFileInfo itemInfo(itemPath); + if (!itemInfo.isFile()) + return ""; + + // 处理desktop文件是软连接的情况 + if (itemInfo.isSymLink()) { + std::string path = itemInfo.symLinkTarget().toStdString(); + std::smatch result; + const std::regex e("^/opt/apps/([^/]+)/entries/applications/.*"); + if (std::regex_match(path, result, e) && result.size() == 2) { + // dpkg命令检查通过路径匹配的包是否存在 + QString pkgName(result[1].str().c_str()); + QProcess process; + process.start("dpkg -s " + pkgName); + if (process.waitForFinished()) + return pkgName; + + // 当包不存在则使用dpkg -S来查找包 + process.start("dpkg -S" + pkgName); + if (!process.waitForFinished()) + return ""; + + QByteArray output = process.readAllStandardOutput(); + if (output.size() == 0) + return ""; + + std::vector splits = DString::splitChars(output.data(), ':'); + if (splits.size() < 2) + return ""; + + return splits[0].c_str(); + } + } + } + + if (DString::startWith(itemID.toStdString(), "org.deepin.flatdeb.")) + return "deepin-fpapp-" + itemID; + + if (desktopPkgMap.find(itemID) != desktopPkgMap.end()) + return desktopPkgMap[itemID]; + + return ""; +} + +// 根据desktop路径获取Item信息 +Item Launcher::getItemByPath(QString itemPath) +{ + QString appId = getAppIdByFilePath(itemPath, appDirs); + if (itemsMap.find(appId) == itemsMap.end()) + return Item(); + + if (itemsMap[appId].info.path == itemPath) + return itemsMap[appId]; + + return Item(); +} + +// 监控应用数据目录 +void Launcher::watchDataDirs() +{ + QStringList dataDirs; + dataDirs << QDir::homePath() + ".local/share"; + dataDirs << "/usr/local/share" << "/usr/share"; + QDBusInterface interface = QDBusInterface("org.deepin.daemon.AlRecoder1", "/org/deepin/daemon/AlRecoder1", "org.deepin.daemon.AlRecoder1"); + interface.call("WatchDirs", dataDirs); +} + +void Launcher::emitItemChanged(const Item *item, QString status) +{ + ItemInfo info(item->info); + Q_EMIT ItemChanged(status, info, info.categoryId); +} + +AppType Launcher::getAppType(DesktopInfo &info, const Item &item) +{ + AppType ty = AppType::Default; + QFileInfo fileInfo; + // 判断是否为flatpak应用 + do { + if (!info.kf.containKey(MainSection, "X-Flatpak")) + break; + + std::vector parts = DString::splitStr(info.getCommandLine(), ' '); + if (parts.size() == 0) + break; + + fileInfo.setFile(parts[0].c_str()); + if (flatpakBin != fileInfo.baseName()) + break; + + ty = AppType::Flatpak; + goto end; + } while (0); + + // 判断是否为ChromeShortcut + do { + if (!DString::startWith(item.info.id.toStdString(), "chrome-")) + break; + + if (!std::regex_match(item.exec.toStdString(), std::regex("google-chrome.*--app-id="))) + break; + + ty = AppType::ChromeShortcut; + goto end; + } while (0); + + // 判断是否为CrossOver + do { + fileInfo.setFile(info.getExecutable().c_str()); + QString execBase(fileInfo.baseName()); + if (execBase.contains("CrossOver") && (execBase.contains("crossover") || execBase.contains("cxuninstall"))) { + ty = AppType::CrossOver; + goto end; + } + } while (0); + + // 判断是否为wineApp + do { + std::string createdBy = info.kf.getStr(MainSection, "X-Created-By"); + if (DString::startWith(createdBy, "cxoffice-") || strstr(info.getCommandLine().c_str(), "env WINEPREFIX=")) { + ty = AppType::WineApp; + goto end; + } + } while (0); + + +end: + return ty; +} + +bool Launcher::doUninstall(DesktopInfo &info, const Item &item) +{ + bool ret = false; + // 查询包名 + QString pkg = queryPkgName(item.info.id, item.info.path); + if (pkg.isEmpty()) + pkg = queryPkgNameWithDpkg(item.info.path); + + if (!pkg.isEmpty()) { + // 检测包是否安装 + QDBusInterface lastoreDbus = QDBusInterface("com.deepin.lastore", "/com/deepin/lastore", "com.deepin.lastore.Manager", QDBusConnection::systemBus()); + QDBusReply reply = lastoreDbus.call("PackageExists", pkg); + if (!(reply.isValid() && reply.value())) // 包未安装 + return false; + else + return uninstallSysApp(item.info.name, pkg); // 卸载系统应用 + } + + switch (getAppType(info, item)) { + case (AppType::Flatpak): + ret = uninstallFlatpak(info, item); // 待测 + break; + case (AppType::ChromeShortcut): + ret = removeDesktop(item); + break; + case (AppType::CrossOver): + ret = uninstallSysApp(item.info.name, "crossvoer"); // 待测 + break; + case (AppType::WineApp): + ret = uninstallWineApp(item); // 待测 + break; + case (AppType::Default): + ret = removeDesktop(item); + break; + default: + break; + } + + return ret; +} + +// 卸载flatpak应用 +bool Launcher::uninstallFlatpak(DesktopInfo &info, const Item &item) +{ + struct FlatpakApp { + std::string name; + std::string arch; + std::string branch; + } flat; + std::vector parts = DString::splitStr(info.getCommandLine(), ' '); + for (unsigned long idx = 0; idx < parts.size(); idx++) { + if (flat.branch.empty() && DString::startWith(parts[idx], "--branch=")) + flat.branch.assign(parts[idx].c_str() + strlen("--branch=")); + + if (flat.arch.empty() && DString::startWith(parts[idx], "--arch=")) + flat.arch.assign(parts[idx].c_str() + strlen("--arch=")); + + if (flat.name.empty() && idx != 0 && !DString::startWith(parts[idx], "--") && strstr(parts[idx].c_str(), ".")) + flat.name.assign(parts[idx]); + + if (!flat.branch.empty() && !flat.arch.empty() && !flat.name.empty()) + break; + } + + if (flat.branch.empty() || flat.arch.empty() || flat.name.empty()) { + qInfo() << "uninstall Flatpak failed"; + return false; + } + + bool userApp = item.info.path.startsWith(QDir::homePath()); + QString sysOrUser = "--user"; + if (!userApp) { + sysOrUser = "--system"; + QString pkgFile = QString("/usr/share/deepin-flatpak/app/%1/%2/%3/pkg").arg(flat.name.c_str()).arg(flat.arch.c_str()).arg(flat.branch.c_str()); + QFile file(pkgFile); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return false; + + QString content(file.readAll()); + QString pkgName = content.trimmed(); + return uninstallSysApp(item.info.name, pkgName); + } else { + QString ref = QString("app/%1/%2/%3").arg(flat.name.c_str()).arg(flat.arch.c_str()).arg(flat.branch.c_str()); + qInfo() << "uninstall flatpak ref= " << ref; + QProcess process; + process.start("flatpak " + sysOrUser + " uninstall " + ref); + bool res = process.waitForFinished(); + std::thread thread([&] { + notifyUninstallDone(item, res); + }); + thread.detach(); + } + + return true; +} + +// 卸载wine应用 +bool Launcher::uninstallWineApp(const Item &item) +{ + QProcess process; + process.start("/opt/deepinwine/tools/uninstall.sh" + item.info.path); + bool res = process.waitForFinished(); + std::thread thread([&] { + notifyUninstallDone(item, res); + }); + return res; +} + +// 卸载 +bool Launcher::uninstallSysApp(const QString &name, const QString &pkg) +{ + QDBusInterface lastoreDbus = QDBusInterface("com.deepin.lastore", "/com/deepin/lastore", "com.deepin.lastore.Manager", QDBusConnection::systemBus()); + QDBusReply reply = lastoreDbus.call("RemovePackage", name, pkg); // TODO replay为空? + QString jobPath = reply.isValid() ? reply.value() : ""; + if (jobPath.isEmpty()) + return false; + + QEventLoop loop; + bool ret = false; + QDBusConnection::sessionBus().connect("com.deepin.lastore", + jobPath, + "com.deepin.lastore.Job", + "Status", + "sa", + this, + SLOT([&](QDBusMessage msg) { + QString status = msg.arguments().at(0).toString(); + if (status == "succeed" || status == "end") + ret = true; + else if (status == "failed") + ret = false; + + loop.quit(); + })); + loop.exec(); // 阻塞等待任务结束 + + qInfo() << "uninstall app " << name << "result is " << ret; + return ret; +} + +// 移除desktop文件 +bool Launcher::removeDesktop(const Item &item) +{ + // 移除desktop文件 + QFile file(item.info.path); + bool ret = file.remove(); + std::thread thread([&] { + notifyUninstallDone(item, ret); + }); + thread.detach(); + + return ret; +} + +// 发送卸载结果 +void Launcher::notifyUninstallDone(const Item &item, bool result) +{ + QString msg; + if (result) + msg = QString("%1 removed successfully").arg(item.info.name); + else + msg = QString("Failed to uninstall %1").arg(item.info.name); + + QDBusInterface interface = QDBusInterface("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications"); + interface.call("Notify", "deepin-app-store", 0, "deepin-appstore", msg, "", QVariant(), QVariant(), -1); +} + +// deepin custom app +bool Launcher::isDeepinCustomDesktopFile(QString fileName) +{ + QFileInfo fileInfo(fileName); + return fileInfo.dir() == QDir::homePath() + ".local/share/applications" + && fileInfo.baseName().startsWith("deepin-custom-"); +} + +Item Launcher:: NewItemWithDesktopInfo(DesktopInfo &info) +{ + QString enName(info.kf.getStr(MainSection, KeyName).c_str()); + QString enComment(info.kf.getStr(MainSection, KeyComment).c_str()); + QString xDeepinCategory(info.kf.getStr(MainSection, "X-Deepin-Category").c_str()); + QString xDeepinVendor(info.kf.getStr(MainSection, "X-Deepin-Vendor").c_str()); + + QString appName; + if (xDeepinVendor == "deepin") + appName = info.getGenericName().c_str(); + + if (appName.isEmpty()) + appName = info.getName().c_str(); + + if (appName.isEmpty()) + appName = info.getId().c_str(); + + QString appFileName(info.getFileName().c_str()); + QFileInfo fileInfo(appFileName); + int64_t ctime = fileInfo.birthTime().toSecsSinceEpoch(); + + Item item; + item.info.path = appFileName; + item.info.name = appName; + item.info.enName = enName; + item.info.id = getAppIdByFilePath(item.info.path, appDirs); + item.info.timeInstalled = ctime; + item.exec = info.getCommandLine().c_str(); + item.genericName = info.getGenericName().c_str(); + item.comment = enComment; + xDeepinCategory = xDeepinCategory.toLower(); + + for (auto &keyWord : info.getKeywords()) { + item.keywords.push_back(QString(keyWord.c_str()).toLower()); + } + + for (auto &category : info.getCategories()) { + item.categories.push_back(QString(category.c_str()).toLower()); + } + return item; +} + +QString Launcher::getAppIdByFilePath(QString filePath, QStringList dirs) +{ + QString path = QDir::cleanPath(filePath); + QString appId; + for (auto dir : dirs) { + if (path.startsWith(dir)) { + appId = QDir(dir).relativeFilePath(path); + break; + } + } + + return appId.isEmpty() ? "" : appId.split(".")[0]; +} + + + + diff --git a/src/modules/launcher/launcher.h b/src/modules/launcher/launcher.h new file mode 100644 index 0000000..2871b91 --- /dev/null +++ b/src/modules/launcher/launcher.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LAUNCHER_H +#define LAUNCHER_H + +#include "common.h" +#include "synmodule.h" +#include "category.h" + +#include +#include +#include +#include +#include + +// 同步数据 +struct SyncData { + QString version; + QString display_mode; + bool fullscreen; +}; + +// 应用类型 +enum class AppType { + Flatpak, + ChromeShortcut, + CrossOver, + WineApp, + Default +}; + +// 应用基本信息 +struct ItemInfo +{ + QString path; + QString name; + QString enName; + QString id; + QString icon; + Categorytype categoryId; + int64_t timeInstalled; +}; + +// 应用信息类 +struct Item { + inline bool isValid() {return !info.path.isEmpty();} + + ItemInfo info; + QStringList keywords; + QStringList categories; + QString xDeepinCategory; + QString exec; + QString genericName; + QString comment; + std::map searchTargets; +}; + + +class DesktopInfo; +class Launcher : public SynModule, public QDBusContext +{ + Q_OBJECT +public: + explicit Launcher(QObject *parent); + ~Launcher(); + + // 设置配置 + void setSynConfig(QByteArray ba); + QByteArray getSyncConfig(); + const QMap *getItems(); + + int getDisplayMode(); + bool getFullScreen(); + void setDisplayMode(int value); + void setFullScreen(bool isFull); + + QVector getAllItemInfos(); + QStringList getAllNewInstalledApps(); + bool getDisableScaling(QString appId); + ItemInfo getItemInfo(QString appId); + bool getUseProxy(QString appId); + bool isItemOnDesktop(QString appId); + bool requestRemoveFromDesktop(QString appId); + bool requestSendToDesktop(QString appId); + void requestUninstall(QString appId); + void setDisableScaling(QString appId, bool value); + void setUseProxy(QString appId, bool value); + +Q_SIGNALS: + void ItemChanged(QString status, ItemInfo itemInfo, Categorytype ty); + void NewAppLaunched(QString appId); + void UninstallSuccess(QString appId); + void UninstallFailed(QString appId, QString errMsg); + + void displayModeChanged(int mode); + void fullScreenChanged(bool isFull); + +private Q_SLOTS: + void handleFSWatcherEvents(QDBusMessage msg); + void handleLRecoderRestart(QDBusMessage msg); + +private: + void initSettings(); + void loadDesktopPkgMap(); + void loadPkgCategoryMap(); + void checkDesktopFile(QString filePath); + void handleAppHiddenChanged(); + void loadNameMap(); + void initItems(); + QString getAppIdByFilePath(QString filePath, QStringList dirs); + bool isDeepinCustomDesktopFile(QString fileName); + Item NewItemWithDesktopInfo(DesktopInfo &info); + void addItem(Item item); + Categorytype queryCategoryId(const Item *item); + Categorytype getXCategory(const Item *item); + QString queryPkgName(const QString &itemID, const QString &itemPath); + QString queryPkgNameWithDpkg(const QString &itemPath); + Item getItemByPath(QString itemPath); + void watchDataDirs(); + void emitItemChanged(const Item *item, QString status); + AppType getAppType(DesktopInfo &info, const Item &item); + bool doUninstall(DesktopInfo &info, const Item &item); + bool uninstallFlatpak(DesktopInfo &info, const Item &item); + bool uninstallWineApp(const Item &item); + bool uninstallSysApp(const QString &name, const QString &pkg); + bool removeDesktop(const Item &item); + void notifyUninstallDone(const Item &item, bool result); + + + QMap itemsMap; + QMap desktopPkgMap; + QMap pkgCategoryMap; + QMap nameMap; + QMap noPkgItemIds; + QVector appsHidden; + QStringList appDirs; +}; + +#endif // LAUNCHER_H diff --git a/src/modules/launcher/launchermanager.cpp b/src/modules/launcher/launchermanager.cpp new file mode 100644 index 0000000..e1ae5e3 --- /dev/null +++ b/src/modules/launcher/launchermanager.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "launchermanager.h" +#include "launcher.h" +#include "dbusadaptorlauncher.h" + +LauncherManager::LauncherManager(QObject *parent) + : QObject(parent) + , launcher(new Launcher(this)) +{ + new DBusAdaptorLauncher(launcher); + QDBusConnection con = QDBusConnection::sessionBus(); + if (!con.registerService(dbusService)) + { + qInfo() << "register service Launcher1 error:" << con.lastError().message(); + } + + if (!con.registerObject(dbusPath, launcher)) + { + qInfo() << "register object Launcher1 error:" << con.lastError().message(); + } + +} + +LauncherManager::~LauncherManager() +{ + +} diff --git a/src/modules/launcher/launchermanager.h b/src/modules/launcher/launchermanager.h new file mode 100644 index 0000000..9cf3458 --- /dev/null +++ b/src/modules/launcher/launchermanager.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LAUNCHERMANAGER_H +#define LAUNCHERMANAGER_H + +#include + +class Launcher; +class LauncherManager : public QObject +{ + Q_OBJECT +public: + explicit LauncherManager(QObject *parent = nullptr); + ~LauncherManager(); + +private: + Launcher *launcher; +}; + +#endif // LAUNCHERMANAGER_H diff --git a/src/modules/launcher/launchersettings.cpp b/src/modules/launcher/launchersettings.cpp new file mode 100644 index 0000000..85f2c05 --- /dev/null +++ b/src/modules/launcher/launchersettings.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "launchersettings.h" +#include "settings.h" + +#include +#include +#include +#include + +DCORE_USE_NAMESPACE + +static DConfig *dconfig = Settings::ConfigPtr(configLauncher); + +QString LauncherSettings::getDisplayMode() +{ + return dconfig ? dconfig->value(keyDisplayMode).toString() : ""; +} + +void LauncherSettings::setDisplayMode(QString value) +{ + if (dconfig) { + dconfig->setValue(keyDisplayMode, value); + } +} + +int LauncherSettings::getFullscreenMode() +{ + return dconfig ? dconfig->value(keyFullscreen).toBool() : false; +} + +void LauncherSettings::setFullscreenMode(int value) +{ + if (dconfig) { + dconfig->setValue(keyFullscreen, value); + } +} + +QVector LauncherSettings::getDisableScalingApps() +{ + QVector ret; + if (dconfig) { + QList apps = dconfig->value(keyAppsDisableScaling).toList(); + for (auto app : apps) { + ret.push_back(app.toString()); + } + } + return ret; +} + +void LauncherSettings::setDisableScalingApps(const QVector &value) +{ + if (dconfig) { + QList apps; + for (const auto &app : value) + apps.push_back(app); + + dconfig->setValue(keyAppsDisableScaling, apps); + } +} + +QVector LauncherSettings::getUseProxyApps() +{ + QVector ret; + if (dconfig) { + QList apps = dconfig->value(keyAppsUseProxy).toList(); + for (auto app : apps) { + ret.push_back(app.toString()); + } + } + return ret; +} + +void LauncherSettings::setUseProxy(const QVector &value) +{ + if (dconfig) { + QList apps; + for (const auto &app : value) + apps.push_back(app); + + dconfig->setValue(keyAppsUseProxy, apps); + } +} + +QVector LauncherSettings::getHiddenApps() +{ + QVector ret; + if (dconfig) { + QList hiddenApps = dconfig->value(keyAppsHidden).toList(); + for (auto app : hiddenApps) { + ret.push_back(app.toString()); + } + } + return ret; +} + +LauncherSettings::LauncherSettings(QObject *parent) : QObject(parent) +{ + // 绑定属性 + connect(dconfig, &DConfig::valueChanged, this, [&] (const QString &key) { + if (key == keyDisplayMode) { + Q_EMIT displayModeChanged(dconfig->value(key).toString()); + } else if (key == keyFullscreen) { + Q_EMIT fullscreenChanged(dconfig->value(key).toBool()); + } else if (key == keyAppsHidden) { + Q_EMIT hiddenAppsChanged(); + } + }); +} diff --git a/src/modules/launcher/launchersettings.h b/src/modules/launcher/launchersettings.h new file mode 100644 index 0000000..bdf70a9 --- /dev/null +++ b/src/modules/launcher/launchersettings.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LAUNCHERSETTINGS_H +#define LAUNCHERSETTINGS_H + +#include "common.h" + +#include +#include + +class LauncherSettings : public QObject +{ + Q_OBJECT +public: + static inline LauncherSettings *instance() { + static LauncherSettings instance; + return &instance; + } + + QString getDisplayMode(); + void setDisplayMode(QString value); + + int getFullscreenMode(); + void setFullscreenMode(int value); + + QVector getDisableScalingApps(); + void setDisableScalingApps(const QVector &value); + + QVector getUseProxyApps(); + void setUseProxy(const QVector &value); + + QVector getHiddenApps(); + +Q_SIGNALS: + void displayModeChanged(QString mode); + void fullscreenChanged(bool isFull); + void hiddenAppsChanged(); + +private: + LauncherSettings(QObject *paret = nullptr); + LauncherSettings(const LauncherSettings &); + LauncherSettings& operator= (const LauncherSettings &); +}; + +#endif // LAUNCHERSETTINGS_H diff --git a/src/service/CMakeLists.txt b/src/service/CMakeLists.txt index bc40932..3b4880d 100644 --- a/src/service/CMakeLists.txt +++ b/src/service/CMakeLists.txt @@ -2,6 +2,12 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) +find_package(Qt5 REQUIRED COMPONENTS Core DBus Concurrent) +find_package(DtkCore REQUIRED) + +pkg_check_modules(XCB REQUIRED IMPORTED_TARGET xcb-icccm xcb-ewmh xcb) +pkg_check_modules(X11 REQUIRED IMPORTED_TARGET x11) + qt5_add_dbus_adaptor(ADAPTER_SOURCES ../../DBus/org.desktopspec.ApplicationManager.xml impl/application_manager.h @@ -16,6 +22,7 @@ qt5_add_dbus_adaptor(ADAPTER_SOURCES ../../DBus/org.desktopspec.ApplicationInstance.xml impl/application_instance.h ApplicationInstance) + add_definitions(-DUSE_QT) set(SRCS ${PROJECT_BINARY_DIR}/src/define.h) @@ -37,6 +44,115 @@ set(SRCS ../modules/methods/instance.hpp ../modules/methods/quit.hpp ../modules/methods/registe.hpp + + ../lib/desktopinfo.h + ../lib/desktopinfo.cpp + ../lib/dlocale.h + ../lib/dlocale.cpp + ../lib/dstring.h + ../lib/dstring.cpp + ../lib/keyfile.h + ../lib/keyfile.cpp + ../lib/lang.h + ../lib/macro.h + ../lib/process.h + ../lib/process.cpp + ../lib/dfile.h + ../lib/dfile.cpp + ../lib/basedir.h + ../lib/basedir.cpp + ../lib/xcbutils.h + ../lib/xcbutils.cpp + ../utils/settings.h + ../utils/settings.cpp + ../utils/synmodulebase.h + ../utils/synmodule.h + ../utils/synconfig.h + ../utils/synconfig.cpp + ../modules/apps/alrecorder.h + ../modules/apps/alrecorder.cpp + ../modules/apps/appmanager.h + ../modules/apps/appmanager.cpp + ../modules/apps/dfwatcher.h + ../modules/apps/dfwatcher.cpp + ../modules/launcher/common.h + ../modules/launcher/launcher.h + ../modules/launcher/launcher.cpp + ../modules/launcher/launchermanager.h + ../modules/launcher/launchermanager.cpp + ../modules/launcher/category.h + ../modules/launcher/category.cpp + ../modules/launcher/launchersettings.h + ../modules/launcher/launchersettings.cpp + ../modules/launcher/dbusadaptorlauncher.h + ../modules/launcher/dbusadaptorlauncher.cpp + ../modules/dock/dock.h + ../modules/dock/dock.cpp + ../modules/dock/dockmanager.h + ../modules/dock/dockmanager.cpp + ../modules/dock/windowidentify.h + ../modules/dock/windowidentify.cpp + ../modules/dock/windowinfobase.h + ../modules/dock/windowinfox.h + ../modules/dock/windowinfox.cpp + ../modules/dock/windowinfok.h + ../modules/dock/windowinfok.cpp + ../modules/dock/dbushandler.h + ../modules/dock/dbushandler.cpp + ../modules/dock/docksettings.h + ../modules/dock/docksettings.cpp + ../modules/dock/common.h + ../modules/dock/appinfo.h + ../modules/dock/appinfo.cpp + ../modules/dock/entry.h + ../modules/dock/entry.cpp + ../modules/dock/entries.h + ../modules/dock/entries.cpp + ../modules/dock/appmenu.h + ../modules/dock/appmenu.cpp + ../modules/dock/processinfo.h + ../modules/dock/processinfo.cpp + ../modules/dock/windowpatterns.h + ../modules/dock/windowpatterns.cpp + ../modules/dock/waylandmanager.h + ../modules/dock/waylandmanager.cpp + ../modules/dock/x11manager.h + ../modules/dock/x11manager.cpp + ../modules/dock/dbusadaptordock.h + ../modules/dock/dbusadaptordock.cpp + ../modules/dock/dbusadaptorentry.h + ../modules/dock/dbusadaptorentry.cpp + ../frameworkdbus/types/launcheriteminfo.h + ../frameworkdbus/types/launcheriteminfo.cpp + ../frameworkdbus/types/launcheriteminfolist.h + ../frameworkdbus/types/launcheriteminfolist.cpp + ../frameworkdbus/types/rect.h + ../frameworkdbus/types/rect.cpp + ../frameworkdbus/dbuslauncherfront.h + ../frameworkdbus/dbuslauncherfront.cpp + ../frameworkdbus/dbuslauncher.h + ../frameworkdbus/dbuslauncher.cpp + ../frameworkdbus/dbuswm.h + ../frameworkdbus/dbuswm.cpp + ../frameworkdbus/dbuswmswitcher.h + ../frameworkdbus/dbuswmswitcher.cpp + ../frameworkdbus/dbuskwaylandwindowmanager.h + ../frameworkdbus/dbuskwaylandwindowmanager.cpp + ../frameworkdbus/dbusplasmawindow.h + ../frameworkdbus/dbusplasmawindow.cpp + ../frameworkdbus/dbuskwaylandoutput.h + ../frameworkdbus/dbuskwaylandoutput.cpp + ../frameworkdbus/dbusbamfapplication.h + ../frameworkdbus/dbusbamfapplication.cpp + ../frameworkdbus/dbusbamfmatcher.h + ../frameworkdbus/dbusbamfmatcher.cpp + ../frameworkdbus/qtdbusextended/dbusextended.h + ../frameworkdbus/qtdbusextended/dbusextendedabstractinterface.h + ../frameworkdbus/qtdbusextended/dbusextendedpendingcallwatcher_p.h + ../frameworkdbus/qtdbusextended/dbusextendedabstractinterface.cpp + ../frameworkdbus/qtdbusextended/dbusextendedpendingcallwatcher.cpp + ../frameworkdbus/qtdbusextended/DBusExtended + ../frameworkdbus/qtdbusextended/DBusExtendedAbstractInterface ) add_executable(deepin-application-manager @@ -48,6 +164,18 @@ target_link_libraries(deepin-application-manager Qt5::Core Qt5::DBus Qt5::Concurrent + ${DtkCore_LIBRARIES} + pthread + PkgConfig::XCB + PkgConfig::X11 +) + +target_include_directories(deepin-application-manager PUBLIC + PkgConfig::XCB + ../lib + ../utils + ../frameworkdbus + ../frameworkdbus/qtdbusextended ) install(TARGETS deepin-application-manager DESTINATION bin) diff --git a/src/service/main.cpp b/src/service/main.cpp index 6b6e8b6..9779fd0 100644 --- a/src/service/main.cpp +++ b/src/service/main.cpp @@ -5,10 +5,16 @@ #include "applicationmanageradaptor.h" #include "applicationadaptor.h" #include "../modules/applicationhelper/helper.h" +#include "../modules/apps/appmanager.h" +#include "../modules/launcher/launchermanager.h" +#include "../modules/dock/dockmanager.h" #include +#include #include +DCORE_USE_NAMESPACE + QFileInfoList scan(const QString &path) { QDir dir(path); @@ -56,11 +62,18 @@ QList> scanFiles() return applications; } - int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); + app.setOrganizationName("deepin"); + app.setApplicationName("dde-application-manager"); + DLogManager::registerConsoleAppender(); + DLogManager::registerFileAppender(); + + new AppManager(ApplicationManager::Instance()); + new LauncherManager(ApplicationManager::Instance()); + new DockManager(ApplicationManager::Instance()); new ApplicationManagerAdaptor(ApplicationManager::Instance()); QDBusConnection::sessionBus().registerService("org.desktopspec.Application"); diff --git a/src/utils/settings.cpp b/src/utils/settings.cpp new file mode 100644 index 0000000..c5c4f27 --- /dev/null +++ b/src/utils/settings.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "settings.h" + +#include +#include + +Settings::Settings() +{ + +} + +Settings::~Settings() +{ + +} + +DConfig *Settings::ConfigPtr(const QString &name, const QString &subpath, QObject *parent) +{ + DConfig *config = DConfig::create("dde-application-manager", name, subpath, parent); + if (!config) + return nullptr; + + if (config->isValid()) + return config; + + delete config; + qDebug() << "Cannot find dconfigs, name:" << name; + return nullptr; +} + +const QVariant Settings::ConfigValue(const QString &name, const QString &subPath, const QString &key, const QVariant &fallback) +{ + QSharedPointer config(ConfigPtr(name, subPath)); + if (config && config->isValid() && config->keyList().contains(key)) { + QVariant v = config->value(key); + return v; + } + + qDebug() << "Cannot find dconfigs, name:" << name + << " subPath:" << subPath << " key:" << key + << "Use fallback value:" << fallback; + return fallback; +} + +bool Settings::ConfigSaveValue(const QString &name, const QString &subPath, const QString &key, const QVariant &value) +{ + QSharedPointer config(ConfigPtr(name, subPath)); + if (config && config->isValid() && config->keyList().contains(key)) { + config->setValue(key, value); + return true; + } + + qDebug() << "Cannot find dconfigs, name:" << name + << " subPath:" << subPath << " key:" << key; + return false; +} diff --git a/src/utils/settings.h b/src/utils/settings.h new file mode 100644 index 0000000..8d7b87a --- /dev/null +++ b/src/utils/settings.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SETTINGS_H +#define SETTINGS_H + +#include + +#include +#include + +DCORE_USE_NAMESPACE + +// Dconfig 配置类 +class Settings +{ +public: + Settings(); + ~Settings(); + + static DConfig *ConfigPtr(const QString &name, const QString &subpath = QString(), QObject *parent = nullptr); + static const QVariant ConfigValue(const QString &name, const QString &subPath = QString(), const QString &key = QString(), const QVariant &fallback = QVariant()); + static bool ConfigSaveValue(const QString &name, const QString &subPath, const QString &key, const QVariant &value); +}; + +#endif // SETTINGS_H diff --git a/src/utils/synconfig.cpp b/src/utils/synconfig.cpp new file mode 100644 index 0000000..cbf09c5 --- /dev/null +++ b/src/utils/synconfig.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "synconfig.h" + +#include +#include +#include +#include +#include + +const QString syncDBusService = "org.deepin.sync.Config1"; +const QString syncDBusObject = "/org/deepin/sync/Config1"; +const QString syncDBusDaemonService = "com.deepin.sync.Daemon"; +const QString syncDBusDaemonObject = "/com/deepin/sync/Daemon"; +const QString syncDBusDaemonInterface = syncDBusDaemonService; + +QMap SynConfig::synModulesMap; + +SynConfig *SynConfig::instance(QObject *parent) +{ + static SynConfig synConfig(parent); + + return &synConfig; +} + +bool SynConfig::registe(QString moduleName, SynModuleBase *module) +{ + bool registed = false; + if (moduleName.size() > 0 && module) { + synModulesMap[moduleName] = module; + registed = true; + } + + return registed; +} + +QByteArray SynConfig::GetSyncConfig(QString moduleName) +{ + if (synModulesMap.find(moduleName) == synModulesMap.end()) + return {}; + + SynModuleBase *module = synModulesMap[moduleName]; + if (module) + return module->getSyncConfig(); + else + return {}; +} + +void SynConfig::SetSynConfig(QString moduleName, QByteArray ba) +{ + if (synModulesMap.find(moduleName) == synModulesMap.end()) + return; + + SynModuleBase *module = synModulesMap[moduleName]; + if (module) { + module->setSynConfig(ba); + } +} + +SynConfig::SynConfig(QObject *parent) + : QObject(parent) +{ + QDBusConnection con = QDBusConnection::sessionBus(); + if (!con.registerService(syncDBusService)) + { + qCritical() << "register service org.deepin.sync.Config1 error:" << con.lastError().message(); + return; + } + + if (!con.registerObject(syncDBusObject, this, QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals)) + { + qCritical() << "register object /org/deepin/sync/Config1 error:" << con.lastError().message(); + return; + } + + // 只注册一次 + registerOnSyncDaemon(); + // 关联com.deepin.sync.Daemon所有者变化 + QDBusConnectionInterface *ifc = QDBusConnection::sessionBus().interface(); + connect(ifc, &QDBusConnectionInterface::serviceOwnerChanged, this, [ & ](const QString & name, const QString & oldOwner, const QString & newOwner) { + Q_UNUSED(oldOwner) + if (name == syncDBusDaemonService && !newOwner.isEmpty()) { + this->registerOnSyncDaemon(); + } + }); +} + +SynConfig::~SynConfig() +{ + +} + +void SynConfig::registerOnSyncDaemon() +{ + QDBusInterface interface = QDBusInterface(syncDBusDaemonService, syncDBusDaemonObject, syncDBusDaemonInterface); + // 修改V20注册方式,需同步到deepin-deepinid-daemon + interface.call("Register", syncDBusService, syncDBusObject); +} + diff --git a/src/utils/synconfig.h b/src/utils/synconfig.h new file mode 100644 index 0000000..2e13811 --- /dev/null +++ b/src/utils/synconfig.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SYNCONFIG_H +#define SYNCONFIG_H + +#include "synmodulebase.h" + +#include +#include + +class SynConfig final : public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.deepin.sync.Config1") +public: + // 实例 + static SynConfig *instance(QObject *parent = nullptr); + // 记录模块对应类信息 + static bool registe(QString moduleName, SynModuleBase *module); + +public slots: + // 获取配置信息 + QByteArray GetSyncConfig(QString moduleName); + // 设置配置信息 + void SetSynConfig(QString moduleName, QByteArray ba); + +private: + explicit SynConfig(QObject *parent = nullptr); + ~SynConfig(); + + // 将本服务注册到com.deepin.sync.Daemon + void registerOnSyncDaemon(); + + static QMap synModulesMap; // 记录模块对应类 +}; + +#endif // SYNCONFIG_H diff --git a/src/utils/synmodule.h b/src/utils/synmodule.h new file mode 100644 index 0000000..ff17f4d --- /dev/null +++ b/src/utils/synmodule.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SYNMODULE_H +#define SYNMODULE_H + +#include "synconfig.h" +#include + +class SynModule : public SynModuleBase, public QObject +{ +public: + explicit SynModule(QObject *parent = nullptr) : QObject(parent) {} + virtual ~SynModule() {} + + // 获取配置信息 + virtual QByteArray getSyncConfig() = 0; + // 设置配置信息 + virtual void setSynConfig(QByteArray ba) = 0; + // 注册配置模块 + virtual bool registeModule(QString moduleName) final {return SynConfig::instance(this)->registe(moduleName, this);} +}; + +#endif // SYNMODULE_H diff --git a/src/utils/synmodulebase.h b/src/utils/synmodulebase.h new file mode 100644 index 0000000..6647baf --- /dev/null +++ b/src/utils/synmodulebase.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 ~ 2023 Deepin Technology Co., Ltd. + * + * Author: weizhixiang + * + * Maintainer: weizhixiang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SYNMODULEBASE_H +#define SYNMODULEBASE_H + +#include +#include +#include + +// 同步配置基类 +class SynModuleBase +{ +public: + SynModuleBase() {} + virtual ~SynModuleBase() {} + + // 获取配置信息 + virtual QByteArray getSyncConfig() = 0; + // 设置配置信息 + virtual void setSynConfig(QByteArray ba) = 0; +}; + + + +#endif // SYNCONFIGBASE_H