From 9de057e2cc20117597024c3271eda2e4ba8117c5 Mon Sep 17 00:00:00 2001 From: tsic404 Date: Tue, 13 Jun 2023 15:05:44 +0800 Subject: [PATCH] refactor: add taskmanager from dde-application-manager 1. taskmanager used to identify which entry should map to window in x11 environmrnt, listen to xevent in anohter thread, and handle those event when window create, destory, changed. use some way to identify which entry(desktopfile) should mapped to changed window. in wayland, connected plsamawindow signal(window created destoried. 2. use taskmanager instead of dbus in old dock code log: as title --- configs/com.deepin.dde.dock.json | 2 +- frame/CMakeLists.txt | 4 +- frame/controller/dockitemmanager.cpp | 48 +- frame/controller/dockitemmanager.h | 6 +- frame/controller/recentapphelper.cpp | 4 +- frame/controller/recentapphelper.h | 1 - frame/dbus/dde-dock-ClientManager.xml | 16 - frame/dbus/dde-dock-entry-v1.xml | 13 - frame/dbus/dockdaemonadaptors.cpp | 235 +++ frame/dbus/dockdaemonadaptors.h | 203 +++ frame/dbus/dockinterface.cpp | 339 ---- frame/dbus/dockinterface.h | 338 ---- frame/dbus/entryinterface.cpp | 295 --- frame/dbus/entryinterface.h | 282 --- frame/dbus/org.deepin.dde.daemon.Dock1.xml | 31 - frame/dbusinterface/types/dockrect.h | 1 - frame/dbusinterface/xml/com.deepin.wm.xml | 166 ++ .../xml/org.deepin.dde.WMSwitcher1.xml | 12 + .../xml/org.deepin.dde.daemon.Dock1.xml | 100 -- .../org.deepin.dde.kwayland.PlasmaWindow.xml | 146 ++ .../org.deepin.dde.kwayland.WindowManager.xml | 31 + frame/item/appitem.cpp | 84 +- frame/item/appitem.h | 10 +- frame/item/appmultiitem.h | 1 + frame/item/components/appsnapshot.cpp | 10 +- frame/item/components/appsnapshot.h | 2 +- frame/item/components/previewcontainer.cpp | 4 +- frame/item/components/previewcontainer.h | 2 +- frame/item/launcheritem.cpp | 13 +- frame/main.cpp | 7 +- frame/screenspliter/screenspliter_wayland.cpp | 4 +- frame/screenspliter/screenspliter_wayland.h | 1 + frame/screenspliter/screenspliter_xcb.cpp | 6 +- frame/taskmanager/appinfo.cpp | 58 + frame/taskmanager/appinfo.h | 53 + frame/taskmanager/appmenu.cpp | 80 + frame/taskmanager/appmenu.h | 67 + frame/taskmanager/bamfdesktop.cpp | 89 + frame/taskmanager/bamfdesktop.h | 37 + frame/taskmanager/common.h | 85 + frame/taskmanager/dbushandler.cpp | 211 +++ frame/taskmanager/dbushandler.h | 75 + frame/taskmanager/desktopinfo.cpp | 247 +++ frame/taskmanager/desktopinfo.h | 108 ++ frame/taskmanager/entries.cpp | 349 ++++ frame/taskmanager/entries.h | 62 + frame/taskmanager/entry.cpp | 883 +++++++++ frame/taskmanager/entry.h | 156 ++ frame/taskmanager/processinfo.cpp | 214 +++ frame/taskmanager/processinfo.h | 59 + frame/taskmanager/taskmanager.cpp | 1588 +++++++++++++++++ frame/taskmanager/taskmanager.h | 191 ++ frame/taskmanager/waylandmanager.cpp | 119 ++ frame/taskmanager/waylandmanager.h | 40 + frame/taskmanager/window_patterns.json | 246 +++ frame/taskmanager/windowidentify.cpp | 531 ++++++ frame/taskmanager/windowidentify.h | 57 + frame/taskmanager/windowinfobase.h | 68 + frame/taskmanager/windowinfok.cpp | 210 +++ frame/taskmanager/windowinfok.h | 68 + frame/taskmanager/windowinfomap.cpp | 37 + frame/taskmanager/windowinfomap.h | 28 + frame/taskmanager/windowinfox.cpp | 470 +++++ frame/taskmanager/windowinfox.h | 98 + frame/taskmanager/windowpatterns.cpp | 299 ++++ frame/taskmanager/windowpatterns.h | 50 + frame/taskmanager/x11manager.cpp | 455 +++++ frame/taskmanager/x11manager.h | 63 + frame/taskmanager/xcbutils.cpp | 760 ++++++++ frame/taskmanager/xcbutils.h | 276 +++ frame/util/dbusutil.h | 17 +- frame/util/docksettings.cpp | 16 +- frame/util/docksettings.h | 3 - frame/util/multiscreenworker.cpp | 15 +- frame/window/mainpanelcontrol.cpp | 4 +- .../window/tray/widgets/expandiconwidget.cpp | 8 +- frame/window/tray/widgets/expandiconwidget.h | 1 - frame/window/windowmanager.cpp | 4 +- plugins/onboard/CMakeLists.txt | 5 +- .../onboard/dbusinterface/types/arealist.cpp | 38 - .../onboard/dbusinterface/types/arealist.h | 32 - .../xml/org.deepin.dde.daemon.Dock1.Entry.xml | 8 - .../xml/org.deepin.dde.daemon.Dock1.xml | 3 - plugins/onboard/onboardplugin.cpp | 18 - .../pluginmanager/dockplugincontroller.cpp | 16 +- plugins/pluginmanager/dockplugincontroller.h | 1 - 86 files changed, 9421 insertions(+), 1672 deletions(-) delete mode 100644 frame/dbus/dde-dock-ClientManager.xml delete mode 100644 frame/dbus/dde-dock-entry-v1.xml create mode 100644 frame/dbus/dockdaemonadaptors.cpp create mode 100644 frame/dbus/dockdaemonadaptors.h delete mode 100644 frame/dbus/dockinterface.cpp delete mode 100644 frame/dbus/dockinterface.h delete mode 100644 frame/dbus/entryinterface.cpp delete mode 100644 frame/dbus/entryinterface.h delete mode 100644 frame/dbus/org.deepin.dde.daemon.Dock1.xml create mode 100644 frame/dbusinterface/xml/com.deepin.wm.xml create mode 100644 frame/dbusinterface/xml/org.deepin.dde.WMSwitcher1.xml delete mode 100644 frame/dbusinterface/xml/org.deepin.dde.daemon.Dock1.xml create mode 100644 frame/dbusinterface/xml/org.deepin.dde.kwayland.PlasmaWindow.xml create mode 100644 frame/dbusinterface/xml/org.deepin.dde.kwayland.WindowManager.xml create mode 100644 frame/taskmanager/appinfo.cpp create mode 100644 frame/taskmanager/appinfo.h create mode 100644 frame/taskmanager/appmenu.cpp create mode 100644 frame/taskmanager/appmenu.h create mode 100644 frame/taskmanager/bamfdesktop.cpp create mode 100644 frame/taskmanager/bamfdesktop.h create mode 100644 frame/taskmanager/common.h create mode 100644 frame/taskmanager/dbushandler.cpp create mode 100644 frame/taskmanager/dbushandler.h create mode 100644 frame/taskmanager/desktopinfo.cpp create mode 100644 frame/taskmanager/desktopinfo.h create mode 100644 frame/taskmanager/entries.cpp create mode 100644 frame/taskmanager/entries.h create mode 100644 frame/taskmanager/entry.cpp create mode 100644 frame/taskmanager/entry.h create mode 100644 frame/taskmanager/processinfo.cpp create mode 100644 frame/taskmanager/processinfo.h create mode 100644 frame/taskmanager/taskmanager.cpp create mode 100644 frame/taskmanager/taskmanager.h create mode 100644 frame/taskmanager/waylandmanager.cpp create mode 100644 frame/taskmanager/waylandmanager.h create mode 100644 frame/taskmanager/window_patterns.json create mode 100644 frame/taskmanager/windowidentify.cpp create mode 100644 frame/taskmanager/windowidentify.h create mode 100644 frame/taskmanager/windowinfobase.h create mode 100644 frame/taskmanager/windowinfok.cpp create mode 100644 frame/taskmanager/windowinfok.h create mode 100644 frame/taskmanager/windowinfomap.cpp create mode 100644 frame/taskmanager/windowinfomap.h create mode 100644 frame/taskmanager/windowinfox.cpp create mode 100644 frame/taskmanager/windowinfox.h create mode 100644 frame/taskmanager/windowpatterns.cpp create mode 100644 frame/taskmanager/windowpatterns.h create mode 100644 frame/taskmanager/x11manager.cpp create mode 100644 frame/taskmanager/x11manager.h create mode 100644 frame/taskmanager/xcbutils.cpp create mode 100644 frame/taskmanager/xcbutils.h delete mode 100644 plugins/onboard/dbusinterface/types/arealist.cpp delete mode 100644 plugins/onboard/dbusinterface/types/arealist.h delete mode 100644 plugins/onboard/dbusinterface/xml/org.deepin.dde.daemon.Dock1.Entry.xml delete mode 100644 plugins/onboard/dbusinterface/xml/org.deepin.dde.daemon.Dock1.xml diff --git a/configs/com.deepin.dde.dock.json b/configs/com.deepin.dde.dock.json index c91ea6768..dfc97fc5c 100644 --- a/configs/com.deepin.dde.dock.json +++ b/configs/com.deepin.dde.dock.json @@ -123,7 +123,7 @@ "visibility": "private" }, "Display_Mode": { - "value": "", + "value": "fashion", "serial": 0, "flags": [], "name": "Display_Mode", diff --git a/frame/CMakeLists.txt b/frame/CMakeLists.txt index 0894c2b38..707a29da5 100644 --- a/frame/CMakeLists.txt +++ b/frame/CMakeLists.txt @@ -34,7 +34,7 @@ find_package(DWayland REQUIRED) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) -pkg_check_modules(XCB_EWMH REQUIRED IMPORTED_TARGET xcb-image xcb-ewmh xcb-composite xtst x11 dbusmenu-qt5 xext xcursor xkbcommon) +pkg_check_modules(XCB_EWMH REQUIRED IMPORTED_TARGET x11 xcb xcb-icccm xcb-image xcb-ewmh xcb-composite xtst dbusmenu-qt5 xext xcursor xkbcommon xres) pkg_check_modules(QGSettings REQUIRED IMPORTED_TARGET gsettings-qt) pkg_check_modules(WAYLAND REQUIRED IMPORTED_TARGET wayland-client wayland-cursor wayland-egl) @@ -113,3 +113,5 @@ endif() # bin install(TARGETS ${BIN_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) +# window_patterns +install(FILES taskmanager/window_patterns.json DESTINATION ${CMAKE_INSTALL_DATADIR}/dde-dock/) diff --git a/frame/controller/dockitemmanager.cpp b/frame/controller/dockitemmanager.cpp index ac5e7d089..2195ba10e 100644 --- a/frame/controller/dockitemmanager.cpp +++ b/frame/controller/dockitemmanager.cpp @@ -7,6 +7,9 @@ #include "appitem.h" #include "launcheritem.h" #include "pluginsitem.h" +#include "taskmanager/entry.h" +#include "taskmanager/taskmanager.h" +#include "taskmanager/windowinfobase.h" #include "traypluginitem.h" #include "utils.h" #include "docksettings.h" @@ -25,24 +28,24 @@ const QGSettings *DockItemManager::m_dockedSettings = Utils::ModuleSettingsPtr(" DockItemManager::DockItemManager(QObject *parent) : QObject(parent) - , m_appInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this)) + , m_taskmanager(TaskManager::instance()) , m_loadFinished(false) { //固定区域:启动器 m_itemList.append(new LauncherItem); // 应用区域 - for (auto entry : m_appInter->entries()) { + for (auto entry : m_taskmanager->getEntries()) { AppItem *it = new AppItem(m_appSettings, m_activeSettings, m_dockedSettings, entry); manageItem(it); - connect(it, &AppItem::requestActivateWindow, m_appInter, &DockInter::ActivateWindow, Qt::QueuedConnection); - connect(it, &AppItem::requestPreviewWindow, m_appInter, &DockInter::PreviewWindow); - connect(it, &AppItem::requestCancelPreview, m_appInter, &DockInter::CancelPreviewWindow); + connect(it, &AppItem::requestPreviewWindow, m_taskmanager, &TaskManager::previewWindow); + connect(it, &AppItem::requestCancelPreview, m_taskmanager, &TaskManager::cancelPreviewWindow); connect(it, &AppItem::windowCountChanged, this, &DockItemManager::onAppWindowCountChanged); connect(this, &DockItemManager::requestUpdateDockItem, it, &AppItem::requestUpdateEntryGeometries); m_itemList.append(it); + m_appIDist.append(it->appId()); updateMultiItems(it); } @@ -61,9 +64,9 @@ DockItemManager::DockItemManager(QObject *parent) connect(quickController, &QuickSettingController::pluginLoaderFinished, this, &DockItemManager::onPluginLoadFinished, Qt::QueuedConnection); // 应用信号 - connect(m_appInter, &DockInter::EntryAdded, this, &DockItemManager::appItemAdded); - connect(m_appInter, &DockInter::EntryRemoved, this, static_cast(&DockItemManager::appItemRemoved), Qt::QueuedConnection); - connect(m_appInter, &DockInter::ServiceRestarted, this, &DockItemManager::reloadAppItems); + connect(m_taskmanager, &TaskManager::entryAdded, this, &DockItemManager::appItemAdded); + connect(m_taskmanager, &TaskManager::entryRemoved, this, static_cast(&DockItemManager::appItemRemoved), Qt::QueuedConnection); + connect(m_taskmanager, &TaskManager::serviceRestarted, this, &DockItemManager::reloadAppItems); connect(DockSettings::instance(), &DockSettings::showMultiWindowChanged, this, &DockItemManager::onShowMultiWindowChanged); DApplication *app = qobject_cast(qApp); @@ -99,7 +102,7 @@ const QList> DockItemManager::itemList() const bool DockItemManager::appIsOnDock(const QString &appDesktop) const { - return m_appInter->IsOnDock(appDesktop); + return m_taskmanager->isOnDock(appDesktop); } void DockItemManager::refreshItemsIcon() @@ -167,15 +170,15 @@ void DockItemManager::itemMoved(DockItem *const sourceItem, DockItem *const targ // for app move, index 0 is launcher item, need to pass it. if (moveType == DockItem::App && replaceType == DockItem::App) - m_appInter->MoveEntry(moveIndex - 1, replaceIndex - 1); + m_taskmanager->moveEntry(moveIndex - 1, replaceIndex - 1); } void DockItemManager::itemAdded(const QString &appDesktop, int idx) { - m_appInter->RequestDock(appDesktop, idx); + m_taskmanager->requestDock(appDesktop, idx); } -void DockItemManager::appItemAdded(const QDBusObjectPath &path, const int index) +void DockItemManager::appItemAdded(const Entry *entry, const int index) { // 第一个是启动器 int insertIndex = 1; @@ -189,18 +192,17 @@ void DockItemManager::appItemAdded(const QDBusObjectPath &path, const int index) ++insertIndex; } - AppItem *item = new AppItem(m_appSettings, m_activeSettings, m_dockedSettings, path); + AppItem *item = new AppItem(m_appSettings, m_activeSettings, m_dockedSettings, entry); if (m_appIDist.contains(item->appId())) { - delete item; + item->deleteLater(); return; } manageItem(item); - connect(item, &AppItem::requestActivateWindow, m_appInter, &DockInter::ActivateWindow, Qt::QueuedConnection); - connect(item, &AppItem::requestPreviewWindow, m_appInter, &DockInter::PreviewWindow); - connect(item, &AppItem::requestCancelPreview, m_appInter, &DockInter::CancelPreviewWindow); + connect(item, &AppItem::requestPreviewWindow, m_taskmanager, &TaskManager::previewWindow); + connect(item, &AppItem::requestCancelPreview, m_taskmanager, &TaskManager::cancelPreviewWindow); connect(item, &AppItem::windowCountChanged, this, &DockItemManager::onAppWindowCountChanged); connect(this, &DockItemManager::requestUpdateDockItem, item, &AppItem::requestUpdateEntryGeometries); @@ -256,8 +258,8 @@ void DockItemManager::reloadAppItems() appItemRemoved(static_cast(item.data())); // append new item - for (auto path : m_appInter->entries()) - appItemAdded(path, -1); + for (Entry* entry : m_taskmanager->getEntries()) + appItemAdded(entry, -1); } void DockItemManager::manageItem(DockItem *item) @@ -366,11 +368,11 @@ void DockItemManager::onAppWindowCountChanged() void DockItemManager::updateMultiItems(AppItem *appItem, bool emitSignal) { // 如果系统设置不开启应用多窗口拆分,则无需之后的操作 - if (!m_appInter->showMultiWindow()) + if (!m_taskmanager->showMultiWindow()) return; // 如果开启了多窗口拆分,则同步窗口和多窗口应用的信息 - const WindowInfoMap &windowInfoMap = appItem->windowsMap(); + const WindowInfoMap &windowInfoMap = appItem->windowsInfos(); QList removeItems; // 同步当前已经存在的多开窗口的列表,删除不存在的多开窗口 for (int i = 0; i < m_itemList.size(); i++) { @@ -431,7 +433,7 @@ bool DockItemManager::needRemoveMultiWindow(AppMultiItem *multiItem) const // 查找多分窗口对应的窗口在应用所有的打开的窗口中是否存在,只要它对应的窗口存在,就无需删除 // 只要不存在,就需要删除 AppItem *appItem = multiItem->appItem(); - const WindowInfoMap &windowInfoMap = appItem->windowsMap(); + const WindowInfoMap &windowInfoMap = appItem->windowsInfos(); for (auto it = windowInfoMap.begin(); it != windowInfoMap.end(); it++) { if (it.key() == multiItem->winId()) return false; @@ -442,7 +444,7 @@ bool DockItemManager::needRemoveMultiWindow(AppMultiItem *multiItem) const void DockItemManager::onShowMultiWindowChanged() { - if (m_appInter->showMultiWindow()) { + if (m_taskmanager->showMultiWindow()) { // 如果当前设置支持窗口多开,那么就依次对每个APPItem加载多开窗口 for (int i = 0; i < m_itemList.size(); i++) { const QPointer &dockItem = m_itemList[i]; diff --git a/frame/controller/dockitemmanager.h b/frame/controller/dockitemmanager.h index 2314d47d5..71342c75f 100644 --- a/frame/controller/dockitemmanager.h +++ b/frame/controller/dockitemmanager.h @@ -11,6 +11,8 @@ #include "appitem.h" #include "placeholderitem.h" #include "dbusutil.h" +#include "taskmanager/taskmanager.h" +#include "taskmanager/windowinfobase.h" #include @@ -56,7 +58,7 @@ private Q_SLOTS: private: explicit DockItemManager(QObject *parent = nullptr); - void appItemAdded(const QDBusObjectPath &path, const int index); + void appItemAdded(const Entry *entry, const int index); void appItemRemoved(const QString &appId); void appItemRemoved(AppItem *appItem); void updatePluginsItemOrderKey(); @@ -69,7 +71,7 @@ private: bool needRemoveMultiWindow(AppMultiItem *multiItem) const; private: - DockInter *m_appInter; + TaskManager *m_taskmanager; static DockItemManager *INSTANCE; diff --git a/frame/controller/recentapphelper.cpp b/frame/controller/recentapphelper.cpp index 2ecce01f5..d3c406a95 100644 --- a/frame/controller/recentapphelper.cpp +++ b/frame/controller/recentapphelper.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "recentapphelper.h" +#include "dockitemmanager.h" #include "appitem.h" #include @@ -16,7 +17,6 @@ RecentAppHelper::RecentAppHelper(QWidget *appWidget, QWidget *recentWidget, QObj : QObject(parent) , m_appWidget(appWidget) , m_recentWidget(recentWidget) - , m_dockInter(new DockInter("org.deepin.dde.daemon.Dock1", "/org/deepin/dde/daemon/Dock1", QDBusConnection::sessionBus(), this)) { m_appWidget->installEventFilter(this); m_recentWidget->installEventFilter(this); @@ -188,7 +188,7 @@ int RecentAppHelper::getEntryIndex(DockItem *dockItem, QWidget *widget) const return -1; // 查找当前的应用在所有的应用中的排序 - QStringList entryIds = m_dockInter->GetEntryIDs(); + QStringList entryIds = TaskManager::instance()->getEntryIDs(); int index = entryIds.indexOf(appItem->appId()); if (index < 0) return -1; diff --git a/frame/controller/recentapphelper.h b/frame/controller/recentapphelper.h index 39f9b38a1..547b8fae0 100644 --- a/frame/controller/recentapphelper.h +++ b/frame/controller/recentapphelper.h @@ -61,7 +61,6 @@ private: QWidget *m_appWidget; QWidget *m_recentWidget; Dock::DisplayMode m_displayMode; - DockInter *m_dockInter; }; #endif // RECENTAPPHELPER_H diff --git a/frame/dbus/dde-dock-ClientManager.xml b/frame/dbus/dde-dock-ClientManager.xml deleted file mode 100644 index 59680d745..000000000 --- a/frame/dbus/dde-dock-ClientManager.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/frame/dbus/dde-dock-entry-v1.xml b/frame/dbus/dde-dock-entry-v1.xml deleted file mode 100644 index eaad21d72..000000000 --- a/frame/dbus/dde-dock-entry-v1.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/frame/dbus/dockdaemonadaptors.cpp b/frame/dbus/dockdaemonadaptors.cpp new file mode 100644 index 000000000..f8351d2c1 --- /dev/null +++ b/frame/dbus/dockdaemonadaptors.cpp @@ -0,0 +1,235 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dockdaemonadaptors.h" +#include "docksettings.h" +#include "taskmanager/taskmanager.h" + +DockDaemonDBusAdaptor::DockDaemonDBusAdaptor(QObject *parent) + : QDBusAbstractAdaptor(parent) +{ + // constructor + setAutoRelaySignals(true); + connect(TaskManager::instance(), &TaskManager::entryAdded, this, &DockDaemonDBusAdaptor::EntryAdded); + connect(TaskManager::instance(), &TaskManager::entryRemoved, this, &DockDaemonDBusAdaptor::EntryRemoved); + connect(TaskManager::instance(), &TaskManager::hideStateChanged, this, &DockDaemonDBusAdaptor::HideStateChanged); + connect(TaskManager::instance(), &TaskManager::frontendWindowRectChanged, this, &DockDaemonDBusAdaptor::FrontendWindowRectChanged); + connect(TaskManager::instance(), &TaskManager::showRecentChanged, this, &DockDaemonDBusAdaptor::showRecentChanged); + connect(TaskManager::instance(), &TaskManager::showMultiWindowChanged, this, &DockDaemonDBusAdaptor::ShowMultiWindowChanged); +} + +DockDaemonDBusAdaptor::~DockDaemonDBusAdaptor() +{ + // destructor +} + +int DockDaemonDBusAdaptor::displayMode() const +{ + return TaskManager::instance()->getDisplayMode(); +} + +void DockDaemonDBusAdaptor::setDisplayMode(int value) +{ + if (displayMode() != value) { + TaskManager::instance()->setDisplayMode(value); + Q_EMIT DisplayModeChanged(value); + } +} + +QStringList DockDaemonDBusAdaptor::dockedApps() const +{ + return TaskManager::instance()->getDockedApps(); +} + +int DockDaemonDBusAdaptor::hideMode() const +{ + return TaskManager::instance()->getHideMode(); +} + +void DockDaemonDBusAdaptor::setHideMode(int value) +{ + if (hideMode() != value) { + TaskManager::instance()->setHideMode(static_cast(value)); + Q_EMIT HideModeChanged(value); + } +} + +int DockDaemonDBusAdaptor::hideState() const +{ + return TaskManager::instance()->getHideState(); +} + +uint DockDaemonDBusAdaptor::hideTimeout() const +{ + return TaskManager::instance()->getHideTimeout(); +} + +void DockDaemonDBusAdaptor::setHideTimeout(uint value) +{ + if (hideTimeout() != value) { + TaskManager::instance()->setHideTimeout(value); + Q_EMIT HideTimeoutChanged(value); + } +} + +uint DockDaemonDBusAdaptor::windowSizeEfficient() const +{ + return TaskManager::instance()->getWindowSizeEfficient(); +} + +void DockDaemonDBusAdaptor::setWindowSizeEfficient(uint value) +{ + if (windowSizeEfficient() != value) { + TaskManager::instance()->setWindowSizeEfficient(value); + Q_EMIT WindowSizeEfficientChanged(value); + } +} + +uint DockDaemonDBusAdaptor::windowSizeFashion() const +{ + return TaskManager::instance()->getWindowSizeFashion(); +} + +void DockDaemonDBusAdaptor::setWindowSizeFashion(uint value) +{ + if (windowSizeFashion() != value) { + TaskManager::instance()->setWindowSizeFashion(value); + Q_EMIT WindowSizeFashionChanged(value); + } +} + +QRect DockDaemonDBusAdaptor::frontendWindowRect() const +{ + return TaskManager::instance()->getFrontendWindowRect(); +} + +uint DockDaemonDBusAdaptor::iconSize() const +{ + return TaskManager::instance()->getIconSize(); +} + +void DockDaemonDBusAdaptor::setIconSize(uint value) +{ + if (iconSize() != value) { + TaskManager::instance()->setIconSize(value); + Q_EMIT IconSizeChanged(value); + } +} + +int DockDaemonDBusAdaptor::position() const +{ + return TaskManager::instance()->getPosition(); +} + +void DockDaemonDBusAdaptor::setPosition(int value) +{ + if (position() != value) { + TaskManager::instance()->setPosition(value); + Q_EMIT PositionChanged(value); + } +} + +uint DockDaemonDBusAdaptor::showTimeout() const +{ + return TaskManager::instance()->getShowTimeout(); +} + +void DockDaemonDBusAdaptor::setShowTimeout(uint value) +{ + if (showTimeout() != value) { + TaskManager::instance()->setShowTimeout(value); + Q_EMIT ShowTimeoutChanged(value); + } +} + +bool DockDaemonDBusAdaptor::showRecent() const +{ + return DockSettings::instance()->showRecent(); +} + +bool DockDaemonDBusAdaptor::showMultiWindow() const +{ + return TaskManager::instance()->showMultiWindow(); +} + +void DockDaemonDBusAdaptor::CloseWindow(uint win) +{ + TaskManager::instance()->closeWindow(win); +} + +// for debug +QStringList DockDaemonDBusAdaptor::GetEntryIDs() +{ + return TaskManager::instance()->getEntryIDs(); +} + +bool DockDaemonDBusAdaptor::IsDocked(const QString &desktopFile) +{ + return TaskManager::instance()->isDocked(desktopFile); +} + +bool DockDaemonDBusAdaptor::IsOnDock(const QString &desktopFile) +{ + return TaskManager::instance()->isOnDock(desktopFile); +} + +void DockDaemonDBusAdaptor::MoveEntry(int index, int newIndex) +{ + TaskManager::instance()->moveEntry(index, newIndex); +} + +QString DockDaemonDBusAdaptor::QueryWindowIdentifyMethod(uint win) +{ + return TaskManager::instance()->queryWindowIdentifyMethod(win); +} + +QStringList DockDaemonDBusAdaptor::GetDockedAppsDesktopFiles() +{ + return TaskManager::instance()->getDockedAppsDesktopFiles(); +} + +QString DockDaemonDBusAdaptor::GetPluginSettings() +{ + return TaskManager::instance()->getPluginSettings(); +} + +void DockDaemonDBusAdaptor::SetPluginSettings(QString jsonStr) +{ + TaskManager::instance()->setPluginSettings(jsonStr); +} + +void DockDaemonDBusAdaptor::MergePluginSettings(QString jsonStr) +{ + TaskManager::instance()->mergePluginSettings(jsonStr); +} + +void DockDaemonDBusAdaptor::RemovePluginSettings(QString key1, QStringList key2List) +{ + TaskManager::instance()->removePluginSettings(key1, key2List); +} + +bool DockDaemonDBusAdaptor::RequestDock(const QString &desktopFile, int index) +{ + return TaskManager::instance()->requestDock(desktopFile, index); +} + +bool DockDaemonDBusAdaptor::RequestUndock(const QString &desktopFile) +{ + return TaskManager::instance()->requestUndock(desktopFile); +} + +void DockDaemonDBusAdaptor::SetShowRecent(bool visible) +{ + DockSettings::instance()->setShowRecent(visible); +} + +void DockDaemonDBusAdaptor::SetShowMultiWindow(bool showMultiWindow) +{ + TaskManager::instance()->setShowMultiWindow(showMultiWindow); +} + +void DockDaemonDBusAdaptor::SetFrontendWindowRect(int x, int y, uint width, uint height) +{ + TaskManager::instance()->setFrontendWindowRect(x, y, width, height); +} diff --git a/frame/dbus/dockdaemonadaptors.h b/frame/dbus/dockdaemonadaptors.h new file mode 100644 index 000000000..8538d4086 --- /dev/null +++ b/frame/dbus/dockdaemonadaptors.h @@ -0,0 +1,203 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "taskmanager/entry.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Adaptor class for interface org.deepin.dde.daemon.Dock1 + */ + +class Entry; +class DockDaemonDBusAdaptor: 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" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "") +public: + DockDaemonDBusAdaptor(QObject *parent); + virtual ~DockDaemonDBusAdaptor(); + +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(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(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); + + Q_PROPERTY(bool ShowRecent READ showRecent NOTIFY showRecentChanged) + bool showRecent() const; + + Q_PROPERTY(bool ShowMultiWindow READ showMultiWindow NOTIFY ShowMultiWindowChanged) + bool showMultiWindow() 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); + QStringList GetDockedAppsDesktopFiles(); + QString GetPluginSettings(); + void SetPluginSettings(QString jsonStr); + void MergePluginSettings(QString jsonStr); + void RemovePluginSettings(QString key1, QStringList key2List); + bool RequestDock(const QString &desktopFile, int index); + bool RequestUndock(const QString &desktopFile); + void SetShowRecent(bool visible); + void SetShowMultiWindow(bool showMultiWindow); + void SetFrontendWindowRect(int x, int y, uint width, uint height); + +Q_SIGNALS: // SIGNALS + void ServiceRestarted(); + void EntryAdded(const Entry *entry, int index); + void EntryRemoved(const QString &entryId); + + void DisplayModeChanged(int value) const; + void DockedAppsChanged(const QStringList &value) const; + void EntriesChanged(const QList &value) const; + void FrontendWindowRectChanged(const QRect &dockRect) const; + void HideModeChanged(int value) const; + void HideStateChanged(int value) const; + void HideTimeoutChanged(uint value) const; + void IconSizeChanged(uint value) const; + void PositionChanged(int value) const; + void ShowTimeoutChanged(uint value) const; + void WindowSizeEfficientChanged(uint value) const; + void WindowSizeFashionChanged(uint value) const; + void showRecentChanged(bool) const; + void ShowMultiWindowChanged(bool) const; +}; \ No newline at end of file diff --git a/frame/dbus/dockinterface.cpp b/frame/dbus/dockinterface.cpp deleted file mode 100644 index b89b108cb..000000000 --- a/frame/dbus/dockinterface.cpp +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. - * - * Author: donghualin - * - * Maintainer: donghualin - * - * 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 "dockinterface.h" - -#include "org_deepin_dde_daemon_dock1.h" - -// 因为 types/dockrect.h 文件中定义了DockRect类,而在此处也定义了DockRect, -// 所以在此处先加上DOCKRECT_H宏(types/dockrect.h文件中定义的宏)来禁止包含types/dockrect.h头文件 -// 否则会出现重复定义的错误 -#define DOCKRECT_H - -/* - * Implementation of interface class __Dock - */ - -class DockPrivate -{ -public: - DockPrivate() = default; - - // begin member variables - int DisplayMode; - QStringList DockedApps; - QList Entries; - DockRect FrontendWindowRect; - int HideMode; - int HideState; - uint HideTimeout; - uint IconSize; - double Opacity; - int Position; - uint ShowTimeout; - uint WindowSize; - uint WindowSizeEfficient; - uint WindowSizeFashion; - -public: - QMap m_processingCalls; - QMap> m_waittingCalls; -}; - -// 窗管中提供的ActiveWindow接口,MinimizeWindow目前还在开发过程中,因此,关于这两个接口暂时使用v23的后端接口 -// 等窗管完成了这几个接口后,删除此处v20的接口,改成v23提供的新接口即可 -using DockInter = org::deepin::dde::daemon::Dock1; -/** - * @brief 任务栏的部分DBUS接口是通过窗管获取的,由于AM后端并未提供窗管的相关接口,因此, - * 此处先将窗管的接口集成进来,作为私有类,只提供任务栏接口使用 - */ -class WM : public QDBusAbstractInterface -{ -public: - static inline const char *staticInterfaceName() - { return "com.deepin.wm"; } - -public: - explicit WM(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = Q_NULLPTR); - ~WM(); - -public Q_SLOTS: // METHODS - - inline QDBusPendingReply<> ActivateWindow(uint in0) - { - return m_dockInter->ActivateWindow(in0); - } - - QDBusPendingReply<> MinimizeWindow(uint in0) - { - return m_dockInter->MinimizeWindow(in0); - } - - inline QDBusPendingReply<> CancelPreviewWindow() - { - return asyncCallWithArgumentList(QStringLiteral("CancelPreviewWindow"), QList()); - } - - inline QDBusPendingReply<> PreviewWindow(uint in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QStringLiteral("PreviewWindow"), argumentList); - } - -private: - DockInter *m_dockInter; -}; - -WM::WM(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) - : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) - , m_dockInter(new DockInter("org.deepin.dde.daemon.Dock1", "/org/deepin/dde/daemon/Dock1", QDBusConnection::sessionBus(), this)) -{ -} - -WM::~WM() -{ -} - -Dde_Dock::Dde_Dock(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) - : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) - , d_ptr(new DockPrivate) - , m_wm(new WM("com.deepin.wm", "/com/deepin/wm", QDBusConnection::sessionBus(), this)) -{ - QDBusConnection::sessionBus().connect(this->service(), this->path(), - "org.freedesktop.DBus.Properties", - "PropertiesChanged","sa{sv}as", - this, - SLOT(onPropertyChanged(const QDBusMessage &))); - - if (QMetaType::type("DockRect") == QMetaType::UnknownType) - registerDockRectMetaType(); -} - -Dde_Dock::~Dde_Dock() -{ - qDeleteAll(d_ptr->m_processingCalls.values()); - delete d_ptr; -} - -void Dde_Dock::onPropertyChanged(const QDBusMessage& msg) -{ - QList arguments = msg.arguments(); - if (3 != arguments.count()) - return; - - QString interfaceName = msg.arguments().at(0).toString(); - if (interfaceName != staticInterfaceName()) - return; - - QVariantMap changedProps = qdbus_cast(arguments.at(1).value()); - QStringList keys = changedProps.keys(); - foreach(const QString &prop, keys) { - const QMetaObject* self = metaObject(); - for (int i=self->propertyOffset(); i < self->propertyCount(); ++i) { - QMetaProperty p = self->property(i); - if (p.name() == prop) - Q_EMIT p.notifySignal().invoke(this); - } - } -} - -int Dde_Dock::displayMode() -{ - return qvariant_cast(property("DisplayMode")); -} - -void Dde_Dock::setDisplayMode(int value) -{ - setProperty("DisplayMode", QVariant::fromValue(value)); -} - -QStringList Dde_Dock::dockedApps() -{ - return qvariant_cast(property("DockedApps")); -} - -QList Dde_Dock::entries() -{ - return qvariant_cast>(property("Entries")); -} - -DockRect Dde_Dock::frontendWindowRect() -{ - return qvariant_cast(property("FrontendWindowRect")); -} - -int Dde_Dock::hideMode() -{ - return qvariant_cast(property("HideMode")); -} - -void Dde_Dock::setHideMode(int value) -{ - internalPropSet("HideMode", QVariant::fromValue(value)); -} - -int Dde_Dock::hideState() -{ - return qvariant_cast(property("HideState")); -} - -uint Dde_Dock::hideTimeout() -{ - return qvariant_cast(property("HideTimeout")); -} - -void Dde_Dock::setHideTimeout(uint value) -{ - setProperty("HideTimeout", QVariant::fromValue(value)); -} - -uint Dde_Dock::iconSize() -{ - return qvariant_cast(property("IconSize")); -} - -void Dde_Dock::setIconSize(uint value) -{ - setProperty("IconSize", QVariant::fromValue(value)); -} - -double Dde_Dock::opacity() -{ - return qvariant_cast(property("Opacity")); -} - -void Dde_Dock::setOpacity(double value) -{ - setProperty("Opacity", QVariant::fromValue(value)); -} - -int Dde_Dock::position() -{ - return qvariant_cast(property("Position")); -} - -void Dde_Dock::setPosition(int value) -{ - setProperty("Position", QVariant::fromValue(value)); -} - -uint Dde_Dock::showTimeout() -{ - return qvariant_cast(property("ShowTimeout")); -} - -void Dde_Dock::setShowTimeout(uint value) -{ - setProperty("ShowTimeout", QVariant::fromValue(value)); -} - -uint Dde_Dock::windowSize() -{ - return qvariant_cast(property("WindowSize")); -} - -void Dde_Dock::setWindowSize(uint value) -{ - setProperty("WindowSize", QVariant::fromValue(value)); -} - -uint Dde_Dock::windowSizeEfficient() -{ - return qvariant_cast(property("WindowSizeEfficient")); -} - -void Dde_Dock::setWindowSizeEfficient(uint value) -{ - setProperty("WindowSizeEfficient", QVariant::fromValue(value)); -} - -uint Dde_Dock::windowSizeFashion() -{ - return qvariant_cast(property("WindowSizeFashion")); -} - -void Dde_Dock::setWindowSizeFashion(uint value) -{ - setProperty("WindowSizeFashion", QVariant::fromValue(value)); -} - -bool Dde_Dock::showRecent() const -{ - return qvariant_cast(property("ShowRecent")); -} - -bool Dde_Dock::showMultiWindow() const -{ - return qvariant_cast(property("ShowMultiWindow")); -} - -QDBusPendingReply<> Dde_Dock::ActivateWindow(uint in0) -{ - return m_wm->ActivateWindow(in0); -} - -QDBusPendingReply<> Dde_Dock::PreviewWindow(uint in0) -{ - return m_wm->PreviewWindow(in0); -} - -QDBusPendingReply<> Dde_Dock::CancelPreviewWindow() -{ - return m_wm->CancelPreviewWindow(); -} - -QDBusPendingReply<> Dde_Dock::MinimizeWindow(uint in0) -{ - return m_wm->MinimizeWindow(in0); -} - -void Dde_Dock::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, &Dde_Dock::onPendingCallFinished); - d_ptr->m_processingCalls.insert(callName, watcher); - } -} - -void Dde_Dock::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); -} \ No newline at end of file diff --git a/frame/dbus/dockinterface.h b/frame/dbus/dockinterface.h deleted file mode 100644 index 44530470a..000000000 --- a/frame/dbus/dockinterface.h +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. - * - * Author: donghualin - * - * Maintainer: donghualin - * - * 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_INTERFACE -#define DOCK_INTERFACE - -#include "types/dockrect.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Proxy class for interface org.deepin.dde.daemon.Dock1 - */ -class DockPrivate; -class WM; - -void registerDockRectMetaType(); - -class Dde_Dock : public QDBusAbstractInterface -{ - Q_OBJECT - -public: - static inline const char *staticInterfaceName() - { return "org.deepin.dde.daemon.Dock1"; } - -public: - explicit Dde_Dock(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); - - ~Dde_Dock(); - - Q_PROPERTY(int DisplayMode READ displayMode WRITE setDisplayMode NOTIFY DisplayModeChanged) - int displayMode(); - void setDisplayMode(int value); - - Q_PROPERTY(QStringList DockedApps READ dockedApps NOTIFY DockedAppsChanged) - QStringList dockedApps(); - - Q_PROPERTY(QList Entries READ entries NOTIFY EntriesChanged) - QList entries(); - - Q_PROPERTY(DockRect FrontendWindowRect READ frontendWindowRect NOTIFY FrontendWindowRectChanged) - DockRect frontendWindowRect(); - - Q_PROPERTY(int HideMode READ hideMode WRITE setHideMode NOTIFY HideModeChanged) - int hideMode(); - void setHideMode(int value); - - Q_PROPERTY(int HideState READ hideState NOTIFY HideStateChanged) - int hideState(); - - Q_PROPERTY(uint HideTimeout READ hideTimeout WRITE setHideTimeout NOTIFY HideTimeoutChanged) - uint hideTimeout(); - void setHideTimeout(uint value); - - Q_PROPERTY(uint IconSize READ iconSize WRITE setIconSize NOTIFY IconSizeChanged) - uint iconSize(); - void setIconSize(uint value); - - Q_PROPERTY(double Opacity READ opacity WRITE setOpacity NOTIFY OpacityChanged) - double opacity(); - void setOpacity(double value); - - Q_PROPERTY(int Position READ position WRITE setPosition NOTIFY PositionChanged) - int position(); - void setPosition(int value); - - Q_PROPERTY(uint ShowTimeout READ showTimeout WRITE setShowTimeout NOTIFY ShowTimeoutChanged) - uint showTimeout(); - void setShowTimeout(uint value); - - Q_PROPERTY(uint WindowSize READ windowSize WRITE setWindowSize NOTIFY WindowSizeChanged) - uint windowSize(); - void setWindowSize(uint value); - - Q_PROPERTY(uint WindowSizeEfficient READ windowSizeEfficient WRITE setWindowSizeEfficient NOTIFY WindowSizeEfficientChanged) - uint windowSizeEfficient(); - void setWindowSizeEfficient(uint value); - - Q_PROPERTY(uint WindowSizeFashion READ windowSizeFashion WRITE setWindowSizeFashion NOTIFY WindowSizeFashionChanged) - uint windowSizeFashion(); - void setWindowSizeFashion(uint value); - - Q_PROPERTY(bool ShowRecent READ showRecent NOTIFY showRecentChanged) - bool showRecent() const; - - Q_PROPERTY(bool ShowMultiWindow READ showMultiWindow NOTIFY ShowMultiWindowChanged) - bool showMultiWindow() const; - -public Q_SLOTS: // METHODS - QDBusPendingReply<> ActivateWindow(uint in0); - - QDBusPendingReply<> PreviewWindow(uint in0); - - QDBusPendingReply<> CancelPreviewWindow(); - - QDBusPendingReply<> MinimizeWindow(uint in0); - - inline void ActivateWindowQueued(uint in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - - CallQueued(QStringLiteral("ActivateWindow"), argumentList); - } - - inline QDBusPendingReply<> CloseWindow(uint in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QStringLiteral("CloseWindow"), argumentList); - } - - inline void CloseWindowQueued(uint in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - - CallQueued(QStringLiteral("CloseWindow"), argumentList); - } - - inline QDBusPendingReply GetDockedAppsDesktopFiles() - { - QList argumentList; - return asyncCallWithArgumentList(QStringLiteral("GetDockedAppsDesktopFiles"), argumentList); - } - - inline QDBusPendingReply GetEntryIDs() - { - QList argumentList; - return asyncCallWithArgumentList(QStringLiteral("GetEntryIDs"), argumentList); - } - - inline QDBusPendingReply GetPluginSettings() - { - QList argumentList; - return asyncCallWithArgumentList(QStringLiteral("GetPluginSettings"), argumentList); - } - - inline QDBusPendingReply IsDocked(const QString &in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QStringLiteral("IsDocked"), argumentList); - } - - inline QDBusPendingReply IsOnDock(const QString &in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QStringLiteral("IsOnDock"), argumentList); - } - - inline QDBusPendingReply<> MergePluginSettings(const QString &in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QStringLiteral("MergePluginSettings"), argumentList); - } - - inline void MergePluginSettingsQueued(const QString &in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - - CallQueued(QStringLiteral("MergePluginSettings"), argumentList); - } - - inline QDBusPendingReply<> MoveEntry(int in0, int in1) - { - QList argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); - return asyncCallWithArgumentList(QStringLiteral("MoveEntry"), argumentList); - } - - inline void MoveEntryQueued(int in0, int in1) - { - QList argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); - - CallQueued(QStringLiteral("MoveEntry"), argumentList); - } - - inline void MoveWindowQueued(uint in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - - CallQueued(QStringLiteral("MoveWindow"), argumentList); - } - - inline QDBusPendingReply QueryWindowIdentifyMethod(uint in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QStringLiteral("QueryWindowIdentifyMethod"), argumentList); - } - - inline QDBusPendingReply<> RemovePluginSettings(const QString &in0, const QStringList &in1) - { - QList argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); - return asyncCallWithArgumentList(QStringLiteral("RemovePluginSettings"), argumentList); - } - - inline void RemovePluginSettingsQueued(const QString &in0, const QStringList &in1) - { - QList argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); - - CallQueued(QStringLiteral("RemovePluginSettings"), argumentList); - } - - inline QDBusPendingReply RequestDock(const QString &in0, int in1) - { - QList argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); - return asyncCallWithArgumentList(QStringLiteral("RequestDock"), argumentList); - } - - inline QDBusPendingReply RequestUndock(const QString &in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QStringLiteral("RequestUndock"), argumentList); - } - - inline void SetShowRecent(bool in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - - CallQueued(QStringLiteral("SetShowRecent"), argumentList); - } - - inline QDBusPendingReply<> SetFrontendWindowRect(int in0, int in1, uint in2, uint in3) - { - QList argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1) << QVariant::fromValue(in2) << QVariant::fromValue(in3); - return asyncCallWithArgumentList(QStringLiteral("SetFrontendWindowRect"), argumentList); - } - - inline void SetFrontendWindowRectQueued(int in0, int in1, uint in2, uint in3) - { - QList argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1) << QVariant::fromValue(in2) << QVariant::fromValue(in3); - - CallQueued(QStringLiteral("SetFrontendWindowRect"), argumentList); - } - - inline QDBusPendingReply<> SetPluginSettings(const QString &in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QStringLiteral("SetPluginSettings"), argumentList); - } - - inline void SetPluginSettingsQueued(const QString &in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - - CallQueued(QStringLiteral("SetPluginSettings"), argumentList); - } - -Q_SIGNALS: // SIGNALS - void DockAppSettingsSynced(); - void EntryAdded(const QDBusObjectPath &in0, int in1); - void EntryRemoved(const QString &in0); - void PluginSettingsSynced(); - void ServiceRestarted(); - // begin property changed signals - void DisplayModeChanged(int value) const; - void DockedAppsChanged(const QStringList &value) const; - void EntriesChanged(const QList &value) const; - void FrontendWindowRectChanged(DockRect value) const; - void HideModeChanged(int value) const; - void HideStateChanged(int value) const; - void HideTimeoutChanged(uint value) const; - void IconSizeChanged(uint value) const; - void OpacityChanged(double value) const; - void PositionChanged(int value) const; - void ShowTimeoutChanged(uint value) const; - void WindowSizeChanged(uint value) const; - void WindowSizeEfficientChanged(uint value) const; - void WindowSizeFashionChanged(uint value) const; - void showRecentChanged(bool) const; - void ShowMultiWindowChanged(bool) const; - -public Q_SLOTS: - void CallQueued(const QString &callName, const QList &args); - -private Q_SLOTS: - void onPendingCallFinished(QDBusPendingCallWatcher *w); - void onPropertyChanged(const QDBusMessage& msg); - -private: - DockPrivate *d_ptr; - WM *m_wm; -}; - -namespace org { - namespace deepin { - namespace dde { - namespace daemon { - typedef ::Dde_Dock DdeDock; - } - } - } -} - - -#endif // DOCK_INTERFACE diff --git a/frame/dbus/entryinterface.cpp b/frame/dbus/entryinterface.cpp deleted file mode 100644 index 3d7e1e276..000000000 --- a/frame/dbus/entryinterface.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. - * - * Author: donghualin - * - * Maintainer: donghualin - * - * 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 "entryinterface.h" - -/* - * Implementation of interface class __Entry - */ -void registerWindowListMetaType() -{ - qRegisterMetaType(); - qDBusRegisterMetaType(); -} - -void registerWindowInfoMapMetaType() -{ - registerWindowInfoMetaType(); - - qRegisterMetaType("WindowInfoMap"); - qDBusRegisterMetaType(); -} - -void registerWindowInfoMetaType() -{ - qRegisterMetaType("WindowInfo"); - qDBusRegisterMetaType(); -} - -QDebug operator<<(QDebug argument, const WindowInfo &info) -{ - argument << '(' << info.title << ',' << info.attention << info.uuid << ')'; - - return argument; -} - -QDBusArgument &operator<<(QDBusArgument &argument, const WindowInfo &info) -{ - argument.beginStructure(); - argument << info.title << info.attention << info.uuid; - argument.endStructure(); - - return argument; -} - -const QDBusArgument &operator>>(const QDBusArgument &argument, WindowInfo &info) -{ - argument.beginStructure(); - argument >> info.title >> info.attention >> info.uuid; - argument.endStructure(); - - return argument; -} - -bool WindowInfo::operator==(const WindowInfo &rhs) const -{ - return (attention == rhs.attention && - title == rhs.title && - uuid == rhs.uuid); -} - -class EntryPrivate -{ -public: - EntryPrivate() - : CurrentWindow(0) - , IsActive(false) - , IsDocked(false) - , mode(0) - {} - - // begin member variables - uint CurrentWindow; - QString DesktopFile; - QString Icon; - QString Id; - bool IsActive; - bool IsDocked; - QString Menu; - QString Name; - - WindowInfoMap WindowInfos; - int mode; - -public: - QMap m_processingCalls; - QMap> m_waittingCalls; -}; - -Dock_Entry::Dock_Entry(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) - : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) - , d_ptr(new EntryPrivate) -{ - QDBusConnection::sessionBus().connect(this->service(), this->path(), - "org.freedesktop.DBus.Properties", - "PropertiesChanged","sa{sv}as", - this, - SLOT(onPropertyChanged(const QDBusMessage &))); - - if (QMetaType::type("WindowList") == QMetaType::UnknownType) - registerWindowListMetaType(); - if (QMetaType::type("WindowInfoMap") == QMetaType::UnknownType) - registerWindowInfoMapMetaType(); -} - -Dock_Entry::~Dock_Entry() -{ - qDeleteAll(d_ptr->m_processingCalls.values()); - delete d_ptr; -} - -void Dock_Entry::onPropertyChanged(const QString &propName, const QVariant &value) -{ - if (propName == QStringLiteral("CurrentWindow")) { - const uint &CurrentWindow = qvariant_cast(value); - if (d_ptr->CurrentWindow != CurrentWindow) { - d_ptr->CurrentWindow = CurrentWindow; - Q_EMIT CurrentWindowChanged(d_ptr->CurrentWindow); - } - return; - } - - if (propName == QStringLiteral("DesktopFile")) { - const QString &DesktopFile = qvariant_cast(value); - if (d_ptr->DesktopFile != DesktopFile) { - d_ptr->DesktopFile = DesktopFile; - Q_EMIT DesktopFileChanged(d_ptr->DesktopFile); - } - return; - } - - if (propName == QStringLiteral("Icon")) { - const QString &Icon = qvariant_cast(value); - if (d_ptr->Icon != Icon) - { - d_ptr->Icon = Icon; - Q_EMIT IconChanged(d_ptr->Icon); - } - return; - } - - if (propName == QStringLiteral("IsActive")) { - const bool &IsActive = qvariant_cast(value); - if (d_ptr->IsActive != IsActive) { - d_ptr->IsActive = IsActive; - Q_EMIT IsActiveChanged(d_ptr->IsActive); - } - return; - } - - if (propName == QStringLiteral("IsDocked")) { - const bool &IsDocked = qvariant_cast(value); - if (d_ptr->IsDocked != IsDocked) { - d_ptr->IsDocked = IsDocked; - Q_EMIT IsDockedChanged(d_ptr->IsDocked); - } - return; - } - - if (propName == QStringLiteral("Menu")) { - const QString &Menu = qvariant_cast(value); - if (d_ptr->Menu != Menu) { - d_ptr->Menu = Menu; - Q_EMIT MenuChanged(d_ptr->Menu); - } - return; - } - - if (propName == QStringLiteral("Name")) { - const QString &Name = qvariant_cast(value); - if (d_ptr->Name != Name) { - d_ptr->Name = Name; - Q_EMIT NameChanged(d_ptr->Name); - } - return; - } - - if (propName == QStringLiteral("WindowInfos")) { - const WindowInfoMap &WindowInfos = qvariant_cast(value); - if (d_ptr->WindowInfos != WindowInfos) { - d_ptr->WindowInfos = WindowInfos; - Q_EMIT WindowInfosChanged(d_ptr->WindowInfos); - } - return; - } - - if (propName == QStringLiteral("Mode")) { - const int mode = qvariant_cast(value); - if (d_ptr->mode != mode) { - d_ptr->mode = mode; - Q_EMIT ModeChanged(d_ptr->mode); - } - } - - qWarning() << "property not handle: " << propName; - return; -} - -uint Dock_Entry::currentWindow() -{ - return qvariant_cast(property("CurrentWindow")); -} - -QString Dock_Entry::desktopFile() -{ - return qvariant_cast(property("DesktopFile")); -} - -QString Dock_Entry::icon() -{ - return qvariant_cast(property("Icon")); -} - -QString Dock_Entry::id() -{ - return qvariant_cast(property("Id")); -} - -bool Dock_Entry::isActive() -{ - return qvariant_cast(property("IsActive")); -} - -bool Dock_Entry::isDocked() -{ - return qvariant_cast(property("IsDocked")); -} - -int Dock_Entry::mode() const -{ - return qvariant_cast(property("Mode")); -} - -QString Dock_Entry::menu() -{ - return qvariant_cast(property("Menu")); -} - -QString Dock_Entry::name() -{ - return qvariant_cast(property("Name")); -} - -WindowInfoMap Dock_Entry::windowInfos() -{ - return qvariant_cast(property("WindowInfos")); -} - -void Dock_Entry::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, &Dock_Entry::onPendingCallFinished); - d_ptr->m_processingCalls.insert(callName, watcher); - } -} - -void Dock_Entry::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/frame/dbus/entryinterface.h b/frame/dbus/entryinterface.h deleted file mode 100644 index e0af4497e..000000000 --- a/frame/dbus/entryinterface.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. - * - * Author: donghualin - * - * Maintainer: donghualin - * - * 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_ENTRY_H -#define DOCK_ENTRY_H - -#define WINDOWLIST_H -#define WINDOWINFOLIST_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef QList WindowList; - -void registerWindowListMetaType(); - -class WindowInfo -{ -public: - friend QDebug operator<<(QDebug argument, const WindowInfo &info); - friend QDBusArgument &operator<<(QDBusArgument &argument, const WindowInfo &info); - friend const QDBusArgument &operator>>(const QDBusArgument &argument, WindowInfo &info); - - bool operator==(const WindowInfo &rhs) const; - -public: - bool attention; - QString title; - QString uuid; -}; - -Q_DECLARE_METATYPE(WindowInfo) - -typedef QMap WindowInfoMap; -Q_DECLARE_METATYPE(WindowInfoMap) - -void registerWindowInfoMetaType(); -void registerWindowInfoMapMetaType(); - -/* - * Proxy class for interface org.deepin.dde.daemon.Dock1.Entry - */ -class EntryPrivate; - -class Dock_Entry : public QDBusAbstractInterface -{ - Q_OBJECT - -public: - static inline const char *staticInterfaceName() - { return "org.deepin.dde.daemon.Dock1.Entry"; } - -public: - explicit Dock_Entry(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); - - ~Dock_Entry(); - - Q_PROPERTY(uint CurrentWindow READ currentWindow NOTIFY CurrentWindowChanged) - uint currentWindow(); - - Q_PROPERTY(QString DesktopFile READ desktopFile NOTIFY DesktopFileChanged) - QString desktopFile(); - - Q_PROPERTY(QString Icon READ icon NOTIFY IconChanged) - QString icon(); - - Q_PROPERTY(QString Id READ id) - QString id(); - - Q_PROPERTY(bool IsActive READ isActive NOTIFY IsActiveChanged) - bool isActive(); - - Q_PROPERTY(bool IsDocked READ isDocked NOTIFY IsDockedChanged) - bool isDocked(); - - Q_PROPERTY(QString Menu READ menu NOTIFY MenuChanged) - QString menu(); - - Q_PROPERTY(QString Name READ name NOTIFY NameChanged) - QString name(); - - Q_PROPERTY(WindowInfoMap WindowInfos READ windowInfos NOTIFY WindowInfosChanged) - WindowInfoMap windowInfos(); - - Q_PROPERTY(int Mode READ mode NOTIFY ModeChanged) - int mode() const; - -public Q_SLOTS: // METHODS - inline QDBusPendingReply<> Activate(uint in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QStringLiteral("Activate"), argumentList); - } - - inline void ActivateQueued(uint in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - CallQueued(QStringLiteral("Activate"), argumentList); - } - - inline QDBusPendingReply<> Check() - { - QList argumentList; - return asyncCallWithArgumentList(QStringLiteral("Check"), argumentList); - } - - inline void CheckQueued() - { - QList argumentList; - CallQueued(QStringLiteral("Check"), argumentList); - } - - inline QDBusPendingReply<> ForceQuit() - { - QList argumentList; - return asyncCallWithArgumentList(QStringLiteral("ForceQuit"), argumentList); - } - - inline QDBusPendingReply<> ActiveWindow(quint32 in0) - { - QList argumentList; - argumentList << in0; - return asyncCallWithArgumentList(QStringLiteral("ActiveWindow"), argumentList); - } - - inline void ForceQuitQueued() - { - QList argumentList; - CallQueued(QStringLiteral("ForceQuit"), argumentList); - } - - inline QDBusPendingReply GetAllowedCloseWindows() - { - QList argumentList; - return asyncCallWithArgumentList(QStringLiteral("GetAllowedCloseWindows"), argumentList); - } - - inline QDBusPendingReply<> HandleDragDrop(uint in0, const QStringList &in1) - { - QList argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); - return asyncCallWithArgumentList(QStringLiteral("HandleDragDrop"), argumentList); - } - - inline void HandleDragDropQueued(uint in0, const QStringList &in1) - { - QList argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); - CallQueued(QStringLiteral("HandleDragDrop"), argumentList); - } - - inline QDBusPendingReply<> HandleMenuItem(uint in0, const QString &in1) - { - QList argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); - return asyncCallWithArgumentList(QStringLiteral("HandleMenuItem"), argumentList); - } - - inline void HandleMenuItemQueued(uint in0, const QString &in1) - { - QList argumentList; - argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1); - CallQueued(QStringLiteral("HandleMenuItem"), argumentList); - } - - inline QDBusPendingReply<> NewInstance(uint in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - return asyncCallWithArgumentList(QStringLiteral("NewInstance"), argumentList); - } - - inline void NewInstanceQueued(uint in0) - { - QList argumentList; - argumentList << QVariant::fromValue(in0); - CallQueued(QStringLiteral("NewInstance"), argumentList); - } - - inline QDBusPendingReply<> PresentWindows() - { - QList argumentList; - return asyncCallWithArgumentList(QStringLiteral("PresentWindows"), argumentList); - } - - inline void PresentWindowsQueued() - { - QList argumentList; - CallQueued(QStringLiteral("PresentWindows"), argumentList); - } - - inline QDBusPendingReply<> RequestDock() - { - QList argumentList; - return asyncCallWithArgumentList(QStringLiteral("RequestDock"), argumentList); - } - - inline void RequestDockQueued() - { - QList argumentList; - CallQueued(QStringLiteral("RequestDock"), argumentList); - } - - inline QDBusPendingReply<> RequestUndock() - { - QList argumentList; - return asyncCallWithArgumentList(QStringLiteral("RequestUndock"), argumentList); - } - - inline void RequestUndockQueued() - { - QList argumentList; - CallQueued(QStringLiteral("RequestUndock"), argumentList); - } - -Q_SIGNALS: // SIGNALS - // begin property changed signals - void IsActiveChanged(bool value) const; - void IsDockedChanged(bool value) const; - void MenuChanged(const QString &value) const; - void IconChanged(const QString &value) const; - void NameChanged(const QString &value) const; - void DesktopFileChanged(const QString &value) const; - void CurrentWindowChanged(uint32_t value) const; - - void WindowInfosChanged(WindowInfoMap value) const; - void ModeChanged(int value) const; - -private: - QVariant asyncProperty(const QString &propertyName); - -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: - EntryPrivate *d_ptr; -}; - -namespace org { - namespace deepin { - namespace dde { - namespace daemon { - namespace dock { - typedef ::Dock_Entry DockEntry; - } - } - } - } -} - -#endif // DOCK_ENTRY_H diff --git a/frame/dbus/org.deepin.dde.daemon.Dock1.xml b/frame/dbus/org.deepin.dde.daemon.Dock1.xml deleted file mode 100644 index 4b81b9dea..000000000 --- a/frame/dbus/org.deepin.dde.daemon.Dock1.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frame/dbusinterface/types/dockrect.h b/frame/dbusinterface/types/dockrect.h index 1f18dc718..198ef2280 100644 --- a/frame/dbusinterface/types/dockrect.h +++ b/frame/dbusinterface/types/dockrect.h @@ -18,7 +18,6 @@ public: friend const QDBusArgument &operator>>(const QDBusArgument &arg, DockRect &rect); friend QDBusArgument &operator<<(QDBusArgument &arg, const DockRect &rect); -private: int x; int y; uint w; diff --git a/frame/dbusinterface/xml/com.deepin.wm.xml b/frame/dbusinterface/xml/com.deepin.wm.xml new file mode 100644 index 000000000..2fb84f747 --- /dev/null +++ b/frame/dbusinterface/xml/com.deepin.wm.xml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frame/dbusinterface/xml/org.deepin.dde.WMSwitcher1.xml b/frame/dbusinterface/xml/org.deepin.dde.WMSwitcher1.xml new file mode 100644 index 000000000..9b2f82c67 --- /dev/null +++ b/frame/dbusinterface/xml/org.deepin.dde.WMSwitcher1.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frame/dbusinterface/xml/org.deepin.dde.daemon.Dock1.xml b/frame/dbusinterface/xml/org.deepin.dde.daemon.Dock1.xml deleted file mode 100644 index e41888c48..000000000 --- a/frame/dbusinterface/xml/org.deepin.dde.daemon.Dock1.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frame/dbusinterface/xml/org.deepin.dde.kwayland.PlasmaWindow.xml b/frame/dbusinterface/xml/org.deepin.dde.kwayland.PlasmaWindow.xml new file mode 100644 index 000000000..121e238cb --- /dev/null +++ b/frame/dbusinterface/xml/org.deepin.dde.kwayland.PlasmaWindow.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frame/dbusinterface/xml/org.deepin.dde.kwayland.WindowManager.xml b/frame/dbusinterface/xml/org.deepin.dde.kwayland.WindowManager.xml new file mode 100644 index 000000000..e76c1990b --- /dev/null +++ b/frame/dbusinterface/xml/org.deepin.dde.kwayland.WindowManager.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frame/item/appitem.cpp b/frame/item/appitem.cpp index 598f986e1..3167bfcc0 100644 --- a/frame/item/appitem.cpp +++ b/frame/item/appitem.cpp @@ -5,6 +5,7 @@ #include "appitem.h" #include "docksettings.h" +#include "taskmanager/windowinfobase.h" #include "themeappicon.h" #include "xcb_misc.h" #include "appswingeffectbuilder.h" @@ -27,8 +28,8 @@ #include #include #include + #include -#include #include DGUI_USE_NAMESPACE @@ -38,13 +39,13 @@ DCORE_USE_NAMESPACE QPoint AppItem::MousePressPos; -AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSettings, const QGSettings *dockedAppSettings, const QDBusObjectPath &entry, QWidget *parent) +AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSettings, const QGSettings *dockedAppSettings, const Entry *entry, QWidget *parent) : DockItem(parent) , m_appSettings(appSettings) , m_activeAppSettings(activeAppSettings) , m_dockedAppSettings(dockedAppSettings) + , m_itemEntry(const_cast(entry)) , m_appPreviewTips(nullptr) - , m_itemEntryInter(new DockEntryInter(dockServiceName(), entry.path(), QDBusConnection::sessionBus(), this)) , m_swingEffectView(nullptr) , m_itemAnimation(nullptr) , m_wmHelper(DWindowManagerHelper::instance()) @@ -69,13 +70,13 @@ AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSetti setAcceptDrops(true); setLayout(centralLayout); - m_id = m_itemEntryInter->id(); - m_active = m_itemEntryInter->isActive(); - m_name = m_itemEntryInter->name(); - m_icon = m_itemEntryInter->icon(); - m_mode = m_itemEntryInter->mode(); - m_isDocked = m_itemEntryInter->isDocked(); - m_menu = m_itemEntryInter->menu(); + m_id = m_itemEntry->getId(); + m_active = m_itemEntry->getIsActive(); + m_name = m_itemEntry->getName(); + m_icon = m_itemEntry->getIcon(); + m_mode = m_itemEntry->mode(); + m_isDocked = m_itemEntry->getIsDocked(); + m_menu = m_itemEntry->getMenu(); setObjectName(m_name); @@ -88,32 +89,32 @@ AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSetti m_refershIconTimer->setInterval(1000); m_refershIconTimer->setSingleShot(false); - connect(m_itemEntryInter, &DockEntryInter::IsActiveChanged, this, &AppItem::activeChanged); - connect(m_itemEntryInter, &DockEntryInter::IsActiveChanged, this, static_cast(&AppItem::update)); - connect(m_itemEntryInter, &DockEntryInter::WindowInfosChanged, this, &AppItem::updateWindowInfos, Qt::QueuedConnection); - connect(m_itemEntryInter, &DockEntryInter::IconChanged, this, [=](QString icon) { + connect(m_itemEntry, &Entry::isActiveChanged, this, &AppItem::activeChanged); + connect(m_itemEntry, &Entry::isActiveChanged, this, static_cast(&AppItem::update)); + connect(m_itemEntry, &Entry::windowInfosChanged, this, &AppItem::updateWindowInfos, Qt::QueuedConnection); + connect(m_itemEntry, &Entry::iconChanged, this, [=](QString icon) { if (!icon.isEmpty() && icon != m_icon) m_icon = icon; }); - connect(m_itemEntryInter, &DockEntryInter::IconChanged, this, &AppItem::refreshIcon); - connect(m_itemEntryInter, &DockEntryInter::ModeChanged, this, [=] (int32_t mode) { m_mode = mode; Q_EMIT modeChanged(m_mode);}); + connect(m_itemEntry, &Entry::iconChanged, this, &AppItem::refreshIcon); + connect(m_itemEntry, &Entry::modeChanged, this, [=] (int32_t mode) { m_mode = mode; Q_EMIT modeChanged(m_mode);}); connect(m_updateIconGeometryTimer, &QTimer::timeout, this, &AppItem::updateWindowIconGeometries, Qt::QueuedConnection); connect(m_retryObtainIconTimer, &QTimer::timeout, this, &AppItem::refreshIcon, Qt::QueuedConnection); connect(DockSettings::instance(), &DockSettings::showMultiWindowChanged, this, [=] (bool show) { m_showMultiWindow = show; }); - connect(m_itemEntryInter, &DockEntryInter::NameChanged, this, [=](const QString& name){ m_name = name; }); - connect(m_itemEntryInter, &DockEntryInter::DesktopFileChanged, this, [=](const QString& desktopfile){ m_desktopfile = desktopfile; }); - connect(m_itemEntryInter, &DockEntryInter::IsDockedChanged, this, [=](bool docked){ m_isDocked = docked; }); - connect(m_itemEntryInter, &DockEntryInter::MenuChanged, this, [=](const QString& menu){ m_menu = menu; }); - connect(m_itemEntryInter, &DockEntryInter::CurrentWindowChanged, this, [=](uint32_t currentWindow){ + connect(m_itemEntry, &Entry::nameChanged, this, [=](const QString& name){ m_name = name; }); + connect(m_itemEntry, &Entry::desktopFileChanged, this, [=](const QString& desktopfile){ m_desktopfile = desktopfile; }); + connect(m_itemEntry, &Entry::isDockedChanged, this, [=](bool docked){ m_isDocked = docked; }); + connect(m_itemEntry, &Entry::menuChanged, this, [=](const QString& menu){ m_menu = menu; }); + connect(m_itemEntry, &Entry::currentWindowChanged, this, [=](uint32_t currentWindow){ m_currentWindow = currentWindow; Q_EMIT onCurrentWindowChanged(m_currentWindow); }); connect(this, &AppItem::requestUpdateEntryGeometries, this, &AppItem::updateWindowIconGeometries); - updateWindowInfos(m_itemEntryInter->windowInfos()); + updateWindowInfos(m_itemEntry->getExportWindowInfos()); if (m_appSettings) connect(m_appSettings, &QGSettings::changed, this, &AppItem::onGSettingsChanged); @@ -135,7 +136,7 @@ AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSetti */ void AppItem::checkEntry() { - m_itemEntryInter->Check(); + m_itemEntry->check(); } const QString AppItem::appId() const @@ -150,7 +151,7 @@ QString AppItem::name() const bool AppItem::isValid() const { - return m_itemEntryInter->isValid() && !m_id.isEmpty(); + return m_itemEntry->isValid() && !m_id.isEmpty(); } // Update _NET_WM_ICON_GEOMETRY property for windows that every item @@ -180,7 +181,7 @@ void AppItem::updateWindowIconGeometries() */ void AppItem::undock() { - m_itemEntryInter->RequestUndock(); + m_itemEntry->requestUndock(); } QWidget *AppItem::appDragWidget() @@ -230,9 +231,9 @@ int AppItem::mode() const } -DockEntryInter *AppItem::itemEntryInter() const +Entry *AppItem::itemEntry() const { - return m_itemEntryInter; + return m_itemEntry; } QString AppItem::accessibleName() @@ -242,7 +243,7 @@ QString AppItem::accessibleName() void AppItem::requestDock() { - m_itemEntryInter->RequestDock(); + m_itemEntry->requestDock(); } bool AppItem::isDocked() const @@ -260,7 +261,7 @@ void AppItem::updateMSecs() m_createMSecs = QDateTime::currentMSecsSinceEpoch(); } -const WindowInfoMap &AppItem::windowsMap() const +const WindowInfoMap &AppItem::windowsInfos() const { return m_windowInfos; } @@ -396,7 +397,7 @@ void AppItem::mouseReleaseEvent(QMouseEvent *e) return; if (e->button() == Qt::MiddleButton) { - m_itemEntryInter->NewInstance(QX11Info::getTimestamp()); + m_itemEntry->newInstance(QX11Info::getTimestamp()); // play launch effect if (m_windowInfos.isEmpty()) @@ -408,15 +409,12 @@ void AppItem::mouseReleaseEvent(QMouseEvent *e) return; } - qDebug() << "app item clicked, name:" << m_name - << "id:" << m_id << "my-id:" << m_id << "icon:" << m_icon; - if (m_showMultiWindow) { // 如果开启了多窗口显示,则直接新建一个窗口 - m_itemEntryInter->NewInstance(QX11Info::getTimestamp()); + m_itemEntry->newInstance(QX11Info::getTimestamp()); } else { // 如果没有开启新窗口显示,则 - m_itemEntryInter->Activate(QX11Info::getTimestamp()); + m_itemEntry->active(QX11Info::getTimestamp()); // play launch effect if (m_windowInfos.isEmpty() && DGuiApplicationHelper::isSpecialEffectsEnvironment()) playSwingEffect(); @@ -469,7 +467,7 @@ void AppItem::wheelEvent(QWheelEvent *e) QWidget::wheelEvent(e); if (qAbs(e->angleDelta().y()) > 20) { - m_itemEntryInter->PresentWindows(); + m_itemEntry->presentWindows(); } } @@ -523,7 +521,7 @@ void AppItem::dropEvent(QDropEvent *e) } qDebug() << "accept drop event with URIs: " << uriList; - m_itemEntryInter->HandleDragDrop(QX11Info::getTimestamp(), uriList); + m_itemEntry->handleDragDrop(QX11Info::getTimestamp(), uriList); } void AppItem::leaveEvent(QEvent *e) @@ -553,7 +551,7 @@ void AppItem::invokedMenuItem(const QString &itemId, const bool checked) { Q_UNUSED(checked); - m_itemEntryInter->HandleMenuItem(QX11Info::getTimestamp(), itemId); + m_itemEntry->handleMenuItem(QX11Info::getTimestamp(), itemId); } const QString AppItem::contextMenu() const @@ -663,7 +661,7 @@ void AppItem::updateWindowInfos(const WindowInfoMap &info) m_windowInfos = info; if (m_appPreviewTips) - m_appPreviewTips->setWindowInfos(m_windowInfos, m_itemEntryInter->GetAllowedCloseWindows().value()); + m_appPreviewTips->setWindowInfos(m_windowInfos, m_itemEntry->getAllowedClosedWindowIds().toList()); m_updateIconGeometryTimer->start(); // process attention effect @@ -754,14 +752,14 @@ void AppItem::showPreview() return; m_appPreviewTips = new PreviewContainer; - m_appPreviewTips->setWindowInfos(m_windowInfos, m_itemEntryInter->GetAllowedCloseWindows().value()); + m_appPreviewTips->setWindowInfos(m_windowInfos, m_itemEntry->getAllowedClosedWindowIds().toList()); m_appPreviewTips->updateLayoutDirection(DockPosition); connect(m_appPreviewTips, &PreviewContainer::requestActivateWindow, this, &AppItem::requestActivateWindow, Qt::QueuedConnection); connect(m_appPreviewTips, &PreviewContainer::requestPreviewWindow, this, &AppItem::requestPreviewWindow, Qt::QueuedConnection); connect(m_appPreviewTips, &PreviewContainer::requestCancelPreviewWindow, this, &AppItem::requestCancelPreview); connect(m_appPreviewTips, &PreviewContainer::requestHidePopup, this, &AppItem::hidePopup); - connect(m_appPreviewTips, &PreviewContainer::requestCheckWindows, m_itemEntryInter, &DockEntryInter::Check); + connect(m_appPreviewTips, &PreviewContainer::requestCheckWindows, m_itemEntry, &Entry::check); connect(m_appPreviewTips, &PreviewContainer::requestActivateWindow, this, &AppItem::onResetPreview); connect(m_appPreviewTips, &PreviewContainer::requestCancelPreviewWindow, this, &AppItem::onResetPreview); @@ -878,5 +876,5 @@ void AppItem::showEvent(QShowEvent *e) void AppItem::activeWindow(WId wid) { - m_itemEntryInter->ActiveWindow(wid); -} \ No newline at end of file + m_itemEntry->activeWindow(wid); +} diff --git a/frame/item/appitem.h b/frame/item/appitem.h index 67d1a9b34..4251108fc 100644 --- a/frame/item/appitem.h +++ b/frame/item/appitem.h @@ -11,11 +11,13 @@ #include "appdrag.h" #include "../widgets/tipswidget.h" #include "dbusutil.h" +#include "taskmanager/entry.h" #include #include #include #include + #include class QGSettings; @@ -26,7 +28,7 @@ class AppItem : public DockItem Q_OBJECT public: - explicit AppItem(const QGSettings *appSettings, const QGSettings *activeAppSettings, const QGSettings *dockedAppSettings, const QDBusObjectPath &entry, QWidget *parent = nullptr); + explicit AppItem(const QGSettings *appSettings, const QGSettings *activeAppSettings, const QGSettings *dockedAppSettings, const Entry *entry, QWidget *parent = nullptr); ~AppItem() override; void checkEntry() override; @@ -43,7 +45,7 @@ public: bool supportSplitWindow(); bool splitWindowOnScreen(ScreenSpliter::SplitDirection direction); int mode() const; - DockEntryInter *itemEntryInter() const; + Entry *itemEntry() const; inline ItemType itemType() const override { return App; } QPixmap appIcon(){ return m_appIcon; } uint32_t currentWindow(){ return m_currentWindow; } @@ -52,7 +54,7 @@ public: bool isDocked() const; qint64 appOpenMSecs() const; void updateMSecs(); - const WindowInfoMap &windowsMap() const; + const WindowInfoMap &windowsInfos() const; void activeWindow(WId wid); signals: @@ -108,9 +110,9 @@ private: const QGSettings *m_appSettings; const QGSettings *m_activeAppSettings; const QGSettings *m_dockedAppSettings; + Entry *m_itemEntry; PreviewContainer *m_appPreviewTips; - DockEntryInter *m_itemEntryInter; QGraphicsView *m_swingEffectView; QGraphicsItemAnimation *m_itemAnimation; diff --git a/frame/item/appmultiitem.h b/frame/item/appmultiitem.h index e1d4b46ca..73b1a714f 100644 --- a/frame/item/appmultiitem.h +++ b/frame/item/appmultiitem.h @@ -8,6 +8,7 @@ #include "dockitem.h" #include "dbusutil.h" +#include "taskmanager/windowinfomap.h" class AppItem; diff --git a/frame/item/components/appsnapshot.cpp b/frame/item/components/appsnapshot.cpp index 80710afc4..91d45f450 100644 --- a/frame/item/components/appsnapshot.cpp +++ b/frame/item/components/appsnapshot.cpp @@ -6,6 +6,8 @@ #include "appsnapshot.h" #include "previewcontainer.h" #include "../widgets/tipswidget.h" +#include "taskmanager/taskmanager.h" +#include "taskmanager/xcbutils.h" #include "utils.h" #include "imageutil.h" @@ -23,6 +25,9 @@ #include #include #include +#include +#include +#include struct SHMInfo { long shmid; @@ -51,7 +56,6 @@ AppSnapshot::AppSnapshot(const WId wid, QWidget *parent) , m_waitLeaveTimer(new QTimer(this)) , m_closeBtn2D(new DIconButton(this)) , m_wmHelper(DWindowManagerHelper::instance()) - , m_dockDaemonInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this)) { m_closeBtn2D->setFixedSize(SNAP_CLOSE_BTN_WIDTH, SNAP_CLOSE_BTN_WIDTH); m_closeBtn2D->setIconSize(QSize(SNAP_CLOSE_BTN_WIDTH, SNAP_CLOSE_BTN_WIDTH)); @@ -79,7 +83,7 @@ AppSnapshot::AppSnapshot(const WId wid, QWidget *parent) void AppSnapshot::setWindowState() { if (m_isWidowHidden) { - m_dockDaemonInter->MinimizeWindow(m_wid); + TaskManager::instance()->MinimizeWindow(m_wid); } } @@ -130,7 +134,7 @@ void AppSnapshot::setTitleVisible(bool bVisible) void AppSnapshot::closeWindow() const { if (Utils::IS_WAYLAND_DISPLAY) { - m_dockDaemonInter->CloseWindow(static_cast(m_wid)); + TaskManager::instance()->closeWindow(static_cast(m_wid)); } else { const auto display = QX11Info::display(); if (!display) { diff --git a/frame/item/components/appsnapshot.h b/frame/item/components/appsnapshot.h index bccc9beb9..8691e34b7 100644 --- a/frame/item/components/appsnapshot.h +++ b/frame/item/components/appsnapshot.h @@ -7,6 +7,7 @@ #define APPSNAPSHOT_H #include "dbusutil.h" +#include "taskmanager/windowinfomap.h" #include #include @@ -99,7 +100,6 @@ private: QTimer *m_waitLeaveTimer; DIconButton *m_closeBtn2D; DWindowManagerHelper *m_wmHelper; - DockInter *m_dockDaemonInter; }; #endif // APPSNAPSHOT_H diff --git a/frame/item/components/previewcontainer.cpp b/frame/item/components/previewcontainer.cpp index 425186278..c4982919d 100644 --- a/frame/item/components/previewcontainer.cpp +++ b/frame/item/components/previewcontainer.cpp @@ -68,9 +68,7 @@ void PreviewContainer::setWindowInfos(const WindowInfoMap &infos, const WindowLi if (!m_snapshots.contains(key)) appendSnapWidget(key); m_snapshots[key]->setWindowInfo(it.value()); - // FIXME: "GetAllowedCloseWindows" has remove form dde-daemon - // 由于相关接口被移除,暂时无法正确设置 m_closeAble 属性,暂改为默认 true - // m_snapshots[key]->setCloseAble(allowClose.contains(key)); + m_snapshots[key]->setCloseAble(allowClose.contains(key)); } if (m_snapshots.isEmpty()) { diff --git a/frame/item/components/previewcontainer.h b/frame/item/components/previewcontainer.h index 9194e8468..bf0494edf 100644 --- a/frame/item/components/previewcontainer.h +++ b/frame/item/components/previewcontainer.h @@ -17,7 +17,7 @@ #include DWIDGET_USE_NAMESPACE - +typedef QList WindowList; class PreviewContainer : public QWidget { Q_OBJECT diff --git a/frame/item/launcheritem.cpp b/frame/item/launcheritem.cpp index 497db223b..c4a9fc5e6 100644 --- a/frame/item/launcheritem.cpp +++ b/frame/item/launcheritem.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -84,15 +85,17 @@ void LauncherItem::mouseReleaseEvent(QMouseEvent *e) if (e->button() != Qt::LeftButton) return; - - DDBusSender dbusSender = DDBusSender() + + QtConcurrent::run([=] { + DDBusSender dbusSender = DDBusSender() .service(launcherService) .path(launcherPath) .interface(launcherInterface); - QDBusPendingReply visibleReply = dbusSender.property("Visible").get(); - if (!visibleReply.value()) - dbusSender.method("Toggle").call(); + QDBusPendingReply visibleReply = dbusSender.property("Visible").get(); + if (!visibleReply.value()) + dbusSender.method("Toggle").call(); + }); } QWidget *LauncherItem::popupTips() diff --git a/frame/main.cpp b/frame/main.cpp index 9c9273c07..12959eba6 100644 --- a/frame/main.cpp +++ b/frame/main.cpp @@ -5,9 +5,9 @@ #include "mainwindow.h" #include "dbusdockadaptors.h" +#include "dockdaemonadaptors.h" #include "utils.h" #include "themeappicon.h" -#include "dockitemmanager.h" #include "dockapplication.h" #include "traymainwindow.h" #include "windowmanager.h" @@ -221,10 +221,15 @@ int main(int argc, char *argv[]) // 注册任务栏的DBus服务 DBusDockAdaptors adaptor(&windowManager); + DockDaemonDBusAdaptor daemonAdaptor(&windowManager); QDBusConnection::sessionBus().registerService("org.deepin.dde.Dock1"); QDBusConnection::sessionBus().registerObject("/org/deepin/dde/Dock1", "org.deepin.dde.Dock1", &windowManager); + //保证dock daemon接口兼容性,dde-desktop,dde-clipboard,deepin-system-monitor,dde-osd等在调用。 + QDBusConnection::sessionBus().registerService("org.deepin.dde.daemon.Dock1"); + QDBusConnection::sessionBus().registerObject("/org/deepin/dde/daemon/Dock1", "org.deepin.dde.daemon.Dock1", &windowManager); + // 当任务栏以-r参数启动时,设置CANSHOW未false,之后调用launch不显示任务栏 qApp->setProperty("CANSHOW", !parser.isSet(runOption)); diff --git a/frame/screenspliter/screenspliter_wayland.cpp b/frame/screenspliter/screenspliter_wayland.cpp index f13b243d9..dc56ea422 100644 --- a/frame/screenspliter/screenspliter_wayland.cpp +++ b/frame/screenspliter/screenspliter_wayland.cpp @@ -68,7 +68,7 @@ bool ScreenSpliter_Wayland::split(SplitDirection direction) if (!suportSplitScreen()) return false; - WindowInfoMap windowInfos = appItem()->windowsMap(); + WindowInfoMap windowInfos = appItem()->windowsInfos(); m_splitManager->requestSplitWindow(windowInfos.first().uuid.toStdString().c_str(), direction); return true; @@ -82,7 +82,7 @@ bool ScreenSpliter_Wayland::windowSupportSplit(const QString &uuid) const bool ScreenSpliter_Wayland::suportSplitScreen() { // 判断所有打开的窗口列表,只要有一个窗口支持分屏,就认为它支持分屏 - const WindowInfoMap &windowsInfo = appItem()->windowsMap(); + const WindowInfoMap &windowsInfo = appItem()->windowsInfos(); for (const WindowInfo &windowInfo : windowsInfo) { if (windowSupportSplit(windowInfo.uuid)) return true; diff --git a/frame/screenspliter/screenspliter_wayland.h b/frame/screenspliter/screenspliter_wayland.h index 6ee488c3d..a1b903215 100644 --- a/frame/screenspliter/screenspliter_wayland.h +++ b/frame/screenspliter/screenspliter_wayland.h @@ -9,6 +9,7 @@ #include "screenspliter.h" #include +#include namespace KWayland { namespace Client { diff --git a/frame/screenspliter/screenspliter_xcb.cpp b/frame/screenspliter/screenspliter_xcb.cpp index 1c663405d..5903fbcec 100644 --- a/frame/screenspliter/screenspliter_xcb.cpp +++ b/frame/screenspliter/screenspliter_xcb.cpp @@ -79,7 +79,7 @@ bool ScreenSpliter_Xcb::split(ScreenSpliter::SplitDirection direction) if (!suportSplitScreen()) return false; - quint32 WId = appItem()->windowsMap().keys().first(); + quint32 WId = appItem()->windowsInfos().keys().first(); xcb_client_message_event_t xev; xev.response_type = XCB_CLIENT_MESSAGE; xev.type = internAtom("_DEEPIN_SPLIT_WINDOW", false); @@ -116,7 +116,7 @@ void ScreenSpliter_Xcb::showSplitScreenEffect(const QRect &rect, bool visible) if (!suportSplitScreen()) return; - quint32 WId = appItem()->windowsMap().keys().first(); + quint32 WId = appItem()->windowsInfos().keys().first(); // 触发分屏的效果 xcb_client_message_event_t xev; xev.response_type = XCB_CLIENT_MESSAGE; @@ -137,7 +137,7 @@ void ScreenSpliter_Xcb::showSplitScreenEffect(const QRect &rect, bool visible) bool ScreenSpliter_Xcb::suportSplitScreen() { // 判断所有的窗口,只要有一个窗口支持分屏,就认为它支持分屏 - QList winIds = appItem()->windowsMap().keys(); + QList winIds = appItem()->windowsInfos().keys(); for (const quint32 &winId : winIds) { if (windowSupportSplit(winId)) return true; diff --git a/frame/taskmanager/appinfo.cpp b/frame/taskmanager/appinfo.cpp new file mode 100644 index 000000000..898184017 --- /dev/null +++ b/frame/taskmanager/appinfo.cpp @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "appinfo.h" +#include "common.h" + +#include +#include +#include + +AppInfo::AppInfo(DesktopInfo &info) + : m_isValid(true) +{ + init(info); +} + +AppInfo::AppInfo(const QString &_fileName) + : m_isValid(true) +{ + DesktopInfo info(_fileName); + init(info); +} + +void AppInfo::init(DesktopInfo &info) +{ + if (!info.isValidDesktop()) { + m_isValid = false; + return; + } + + QString xDeepinVendor = info.getDesktopFile()->value(MainSection + "/X-Deepin-Vendor").toString(); + if (xDeepinVendor == "deepin") { + m_name = info.getGenericName(); + if (m_name.isEmpty()) { + m_name = info.getName(); + } + } else { + m_name = info.getName(); + } + + m_innerId = genInnerIdWithDesktopInfo(info); + m_fileName = info.getDesktopFilePath(); + m_id = info.getId(); + m_icon = info.getIcon(); + for (const auto & action : info.getActions()) { + m_actions.push_back(action); + } +} + +QString AppInfo::genInnerIdWithDesktopInfo(DesktopInfo &info) +{ + QString cmdline = info.getCommandLine(); + QByteArray encryText = QCryptographicHash::hash(QString(cmdline).toLatin1(), QCryptographicHash::Md5); + QString innerId = desktopHashPrefix + encryText.toHex(); + qInfo() << "app: " << info.getId() << " generate innerId: " << innerId; + return innerId; +} diff --git a/frame/taskmanager/appinfo.h b/frame/taskmanager/appinfo.h new file mode 100644 index 000000000..663a5ab92 --- /dev/null +++ b/frame/taskmanager/appinfo.h @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#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); + void setIdentifyMethod(QString method) {m_identifyMethod = method;} + + bool isValidApp() {return m_isValid;} + bool isInstalled() {return m_installed;} + + + QString getId() {return m_id;} + QString getIcon() {return m_icon;} + QString getName() {return m_name;} + QString getInnerId() {return m_innerId;} + QString getFileName() {return m_fileName;} + QString getIdentifyMethod() {return m_identifyMethod;} + + QVector getActions() {return m_actions;} + +private: + QString genInnerIdWithDesktopInfo(DesktopInfo &info); + +private: + + bool m_installed; + bool m_isValid; + + QString m_id; + QString m_name; + QString m_icon; + QString m_innerId; + QString m_fileName; + QString m_identifyMethod; + QVector m_actions; + +}; + +#endif // APPINFO_H diff --git a/frame/taskmanager/appmenu.cpp b/frame/taskmanager/appmenu.cpp new file mode 100644 index 000000000..e8426f2bf --- /dev/null +++ b/frame/taskmanager/appmenu.cpp @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "appmenu.h" + +#include +#include + +AppMenu::AppMenu() + : m_itemCount(0) + , m_dirty(false) + , m_checkableMenu(false) + , m_singleCheck(false) +{ + +} + +/** + * @brief AppMenu::appendItem 增加菜单选项 + * @param item + */ +void AppMenu::appendItem(AppMenuItem item) +{ + if (!item.text.isEmpty()) { + item.id = allocateId(); + m_items.push_back(item); + } +} + +/** + * @brief AppMenu::handleAction 响应应用菜单项 + * @param timestamp + * @param itemId + */ +void AppMenu::handleAction(uint32_t timestamp, QString itemId) +{ + for (auto &item : m_items) { + if (item.id == itemId) { + item.action(timestamp); + break; + } + } +} + +void AppMenu::setDirtyStatus(bool isDirty) +{ + m_dirty = isDirty; +} + +QString AppMenu::getMenuJsonStr() +{ + QJsonObject obj; + QJsonArray array; + for (auto item : m_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(objItem); + } + obj["items"] = QJsonValue(array); + obj["checkableMenu"] = m_checkableMenu; + obj["singleCheck"] = m_singleCheck; + + QString ret = QJsonDocument(obj).toJson(); + return ret; +} + +QString AppMenu::allocateId() +{ + return QString::number(m_itemCount++); +} diff --git a/frame/taskmanager/appmenu.h b/frame/taskmanager/appmenu.h new file mode 100644 index 000000000..ce2f16434 --- /dev/null +++ b/frame/taskmanager/appmenu.h @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef APPMENU_H +#define APPMENU_H + +#include +#include +#include + +#include +#include +#include + +typedef std::function AppMenuAction; + +class AppMenu; + +// 应用菜单选项 +struct AppMenuItem +{ + AppMenuItem() + : isActive(true) + , hint(0) + { + } + + QString id; + QString text; + QString isCheckable; + QString checked; + QString icon; + QString iconHover; + QString iconInactive; + QString showCheckMark; + std::shared_ptr subMenu; + + bool isActive; + int hint; + AppMenuAction action; +}; + +// 应用菜单类 +class AppMenu +{ +public: + AppMenu(); + + void appendItem(AppMenuItem item); + void setDirtyStatus(bool isDirty); + void handleAction(uint32_t timestamp, QString itemId); + + QString getMenuJsonStr(); + +private: + QString allocateId(); + +private: + int m_itemCount; + bool m_dirty; + bool m_checkableMenu; // json:"checkableMenu" + bool m_singleCheck; // json:"singleCheck" + QVector m_items; // json:"items" +}; + +#endif // APPMENU_H diff --git a/frame/taskmanager/bamfdesktop.cpp b/frame/taskmanager/bamfdesktop.cpp new file mode 100644 index 000000000..a14b0d397 --- /dev/null +++ b/frame/taskmanager/bamfdesktop.cpp @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2022 ~ 2022 Deepin Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "bamfdesktop.h" + +#include +#include + +#define BAMF_INDEX_NAME "bamf-2.index" + +BamfDesktop *BamfDesktop::instance() +{ + static BamfDesktop instance; + return &instance; +} + +QString BamfDesktop::fileName(const QString &instanceName) const +{ + for (const BamfData &lineData: m_bamfLineData) { + if (lineData.instanceName.toLower() == instanceName.toLower()) { + QString name = lineData.lineData.split("\t").first(); + return QString("%1%2").arg(lineData.directory).arg(name); + } + } + + // 如果根据instanceName没有找到,则根据空格来进行分隔 + for (const BamfData &lineData: m_bamfLineData) { + QStringList lines = lineData.lineData.split("\t"); + if (lines.size() < 2) + continue; + + QStringList cmds = lines[2].split(" "); + if (cmds.size() > 1 && cmds[1].toLower() == instanceName.toLower()) + return QString("%1%2").arg(lineData.directory).arg(lines.first()); + } + + return instanceName; +} + +BamfDesktop::BamfDesktop() +{ + loadDesktopFiles(); +} + +BamfDesktop::~BamfDesktop() +{ +} + +QStringList BamfDesktop::applicationDirs() const +{ + QStringList appDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); + QStringList directions; + for (auto appDir : appDirs) + directions << appDir; + + return directions; +} + +void BamfDesktop::loadDesktopFiles() +{ + QStringList directions = applicationDirs(); + for (const QString &direction : directions) { + // 读取后缀名为 + QDir dir(direction); + dir.setNameFilters(QStringList() << BAMF_INDEX_NAME); + QFileInfoList fileList = dir.entryInfoList(); + if (fileList.size() == 0) + continue; + + QFileInfo fileInfo = fileList.at(0); + QFile file(fileInfo.absoluteFilePath()); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + continue; + + QList> bamfLine; + while (!file.atEnd()) { + QString line = file.readLine(); + QStringList part = line.split("\t"); + BamfData bamf; + bamf.directory = direction; + if (part.size() > 2) + bamf.instanceName = part[2].trimmed(); + bamf.lineData = line; + m_bamfLineData << bamf; + } + } +} diff --git a/frame/taskmanager/bamfdesktop.h b/frame/taskmanager/bamfdesktop.h new file mode 100644 index 000000000..00ac1e133 --- /dev/null +++ b/frame/taskmanager/bamfdesktop.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2022 ~ 2022 Deepin Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef BAMFDESKTOP_H +#define BAMFDESKTOP_H + +#include +#include + +struct BamfData { + QString directory; + QString instanceName; + QString lineData; +}; + +class BamfDesktop +{ +public: + static BamfDesktop *instance(); + QString fileName(const QString &instanceName) const; + +protected: + BamfDesktop(); + ~BamfDesktop(); + +private: + QStringList applicationDirs() const; + + void loadDesktopFiles(); + +private: + QList m_bamfLineData; +}; + +#endif // BAMFDESKTOP_H diff --git a/frame/taskmanager/common.h b/frame/taskmanager/common.h new file mode 100644 index 000000000..57ffd453a --- /dev/null +++ b/frame/taskmanager/common.h @@ -0,0 +1,85 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef COMMON_H +#define COMMON_H + +#include +#include +#include +#include + +const QString configDock = "com.deepin.dde.dock"; +const QString configAppearance = "com.deepin.dde.appearance"; + +const QString keyOpacity = "Opacity"; +const QString keyPosition = "Position"; +const QString keyIconSize = "Icon_Size"; +const QString keyHideMode = "Hide_Mode"; +const QString keyRecentApp = "Recent_App"; +const QString keyShowRecent = "Show_Recent"; +const QString keyDockedApps = "Docked_Apps"; +const QString keyDisplayMode = "Display_Mode"; +const QString keyShowTimeout = "Show_Timeout"; +const QString keyHideTimeout = "Hide_Timeout"; +const QString keyForceQuitApp = "Force_Quit_App"; +const QString keyPluginSettings = "Plugin_Settings"; +const QString keyShowMultiWindow = "Show_MultiWindow"; +const QString keyWindowSizeFashion = "Window_Size_Fashion"; +const QString keyWindowSizeEfficient = "Window_Size_Efficient"; +const QString keyWinIconPreferredApps = "Win_Icon_Preferred_Apps"; + +static const QString scratchDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation).append("/deepin/dde-dock/scratch/"); + +const QString desktopHashPrefix = "d:"; +const QString windowHashPrefix = "w:"; + +// 驻留应用desktop file模板 +// 由于Icon存储的直接是icon base64压缩后的数据需要“”,防止被desktopfile当成stringlist,从而导致获取icon失败 +const QString dockedItemTemplate = R"([Desktop Entry] +Name=%1 +Exec=%2 +Icon="%3" +Type=Application +Terminal=false +StartupNotify=false +)"; + +const QString frontendWindowWmClass = "dde-dock"; +const QString ddeLauncherWMClass = "dde-launcher"; + +const int smartHideTimerDelay = 400; +const int configureNotifyDelay = 100; + +const int bestIconSize = 48; +const int menuItemHintShowAllWindows = 1; + +const int MotifHintStatus = 8; +const int MotifHintFunctions = 1; +const int MotifHintInputMode = 4; +const int MotifHintDecorations = 2; + +const int MotifFunctionNone = 0; +const int MotifFunctionAll = 1; +const int MotifFunctionMove = 4; +const int MotifFunctionClose = 32; +const int MotifFunctionResize = 2; +const int MotifFunctionMinimize = 8; +const int MotifFunctionMaximize = 16; + + +static inline QByteArray sessionType() { + static QByteArray type = qgetenv("XDG_SESSION_TYPE"); + return type; +} + +static inline bool isWaylandSession() { + return sessionType().compare("wayland") == 0; +} + +static inline bool isX11Session() { + return sessionType().compare("x11") == 0; +} + +#endif // COMMON_H diff --git a/frame/taskmanager/dbushandler.cpp b/frame/taskmanager/dbushandler.cpp new file mode 100644 index 000000000..f2c7b18a1 --- /dev/null +++ b/frame/taskmanager/dbushandler.cpp @@ -0,0 +1,211 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "dbushandler.h" +#include "taskmanager.h" +#include "common.h" +#include "entry.h" +#include "windowinfok.h" + +DBusHandler::DBusHandler(TaskManager *taskmanager, QObject *parent) + : QObject(parent) + , m_taskmanager(taskmanager) + , m_wm(new com::deepin::wm("com.deepin.wm", "/com/deepin/wm", QDBusConnection::sessionBus(), this)) + , m_wmSwitcher(new org::deepin::dde::WMSwitcher1("org.deepin.dde.WMSwitcher1", "/org/deepin/dde/WMSwitcher1", QDBusConnection::sessionBus(), this)) + , m_kwaylandManager(nullptr) + , m_xEventMonitor(nullptr) +{ + connect(m_wmSwitcher, &org::deepin::dde::WMSwitcher1::WMChanged, this, [&](QString name) {m_taskmanager->setWMName(name);}); + if (!isWaylandSession()) { + m_xEventMonitor = new org::deepin::dde::XEventMonitor1("org.deepin.dde.XEventMonitor1", "/org/deepin/dde/XEventMonitor1", QDBusConnection::sessionBus(), this); + m_activeWindowMonitorKey = m_xEventMonitor->RegisterFullScreen(); + connect(m_xEventMonitor, &org::deepin::dde::XEventMonitor1::ButtonRelease, this, &DBusHandler::onActiveWindowButtonRelease); + } +} + +void DBusHandler::listenWaylandWMSignals() +{ + m_kwaylandManager = new org::deepin::dde::kwayland1::WindowManager("org.deepin.dde.KWayland1", "/org/deepin/dde/KWayland1/WindowManager", QDBusConnection::sessionBus(), this); + connect(m_kwaylandManager, &org::deepin::dde::kwayland1::WindowManager::ActiveWindowChanged, this, &DBusHandler::handleWlActiveWindowChange); + connect(m_kwaylandManager, &org::deepin::dde::kwayland1::WindowManager::WindowCreated, this, [&] (const QString &ObjPath) { + m_taskmanager->registerWindowWayland(ObjPath); + }); + connect(m_kwaylandManager, &org::deepin::dde::kwayland1::WindowManager::WindowRemove, this, [&] (const QString &ObjPath) { + m_taskmanager->unRegisterWindowWayland(ObjPath); + }); +} + +void DBusHandler::loadClientList() +{ + if (!m_kwaylandManager) + return; + + QDBusPendingReply windowList = m_kwaylandManager->Windows(); + QVariantList windows = windowList.value(); + for (QVariant windowPath : windows) + m_taskmanager->registerWindowWayland(windowPath.toString()); +} + +QString DBusHandler::getCurrentWM() +{ + return m_wmSwitcher->CurrentWM().value(); +} + +void DBusHandler::launchApp(QString desktopFile, uint32_t timestamp, QStringList files) +{ + QDBusInterface interface = QDBusInterface("org.deepin.dde.Application1.Manager", "/org/deepin/dde/Application1/Manager", "org.deepin.dde.Application1.Manager"); + interface.call("LaunchApp", desktopFile, timestamp, files); +} + +void DBusHandler::launchAppAction(QString desktopFile, QString action, uint32_t timestamp) +{ + QDBusInterface interface = QDBusInterface("org.deepin.dde.Application1.Manager", "/org/deepin/dde/Application1/Manager", "org.deepin.dde.Application1.Manager"); + interface.call("LaunchAppAction", desktopFile, action, timestamp); +} + +void DBusHandler::markAppLaunched(const QString &filePath) +{ + QDBusInterface interface = QDBusInterface("org.deepin.dde.AlRecorder1", "/org/deepin/dde/AlRecorder1", "org.deepin.dde.AlRecorder1"); + interface.call("MarkLaunched", filePath); +} + +bool DBusHandler::wlShowingDesktop() +{ + bool ret = false; + if (m_kwaylandManager) + ret = m_kwaylandManager->IsShowingDesktop().value(); + + return ret; +} + +uint DBusHandler::wlActiveWindow() +{ + uint ret = 0; + if (m_kwaylandManager) + ret = m_kwaylandManager->ActiveWindow().value(); + + return ret; +} + +void DBusHandler::handleWlActiveWindowChange() +{ + uint activeWinInternalId = wlActiveWindow(); + if (activeWinInternalId == 0) + return; + + WindowInfoK *info = m_taskmanager->handleActiveWindowChangedK(activeWinInternalId); + if (info && info->getXid() != 0) { + m_taskmanager->handleActiveWindowChanged(info); + } else { + m_taskmanager->updateHideState(false); + } +} + +void DBusHandler::onActiveWindowButtonRelease(int type, int x, int y, const QString &key) +{ + // 当鼠标松开区域事件的时候,取消注册,同时调用激活窗口的方法来触发智能隐藏的相关信号 + if (key != m_activeWindowMonitorKey) + return; + + uint activeWinInternalId = wlActiveWindow(); + if (activeWinInternalId == 0) + return; + + WindowInfoK *info = m_taskmanager->handleActiveWindowChangedK(activeWinInternalId); + if (!info) + return; + + // 如果是在当前激活窗口区域内释放的,则触发检测智能隐藏的方法 + DockRect dockRect = info->getGeometry(); + if (dockRect.x <= x && x <= int(dockRect.x + dockRect.w) && dockRect.y <= y && y <= int(dockRect.y + dockRect.h)) { + // 取消智能隐藏 + m_taskmanager->updateHideState(false); + } +} + +void DBusHandler::listenKWindowSignals(WindowInfoK *windowInfo) +{ + PlasmaWindow *window = windowInfo->getPlasmaWindow(); + if (!window) + return; + + connect(window, &PlasmaWindow::TitleChanged, this, [=] { + windowInfo->updateTitle(); + auto entry = m_taskmanager->getEntryByWindowId(windowInfo->getXid()); + if (entry && entry->getCurrentWindowInfo() == windowInfo) + entry->updateName(); + }); + connect(window, &PlasmaWindow::IconChanged, this, [=] { + windowInfo->updateIcon(); + auto entry = m_taskmanager->getEntryByWindowId(windowInfo->getXid()); + if (!entry) return; + + entry->updateIcon(); + }); + + // DemandingAttention changed + connect(window, &PlasmaWindow::DemandsAttentionChanged, this, [=] { + windowInfo->updateDemandingAttention(); + auto entry = m_taskmanager->getEntryByWindowId(windowInfo->getXid()); + if (!entry) return; + + entry->updateExportWindowInfos(); + }); + + // Geometry changed + connect(window, &PlasmaWindow::GeometryChanged, this, [=] { + if (!windowInfo->updateGeometry()) return; + + m_taskmanager->handleWindowGeometryChanged(); + }); +} + +PlasmaWindow *DBusHandler::createPlasmaWindow(QString objPath) +{ + return new PlasmaWindow("org.deepin.dde.KWayland1", objPath, QDBusConnection::sessionBus(), this); +} + +/** + * @brief DBusHandler::removePlasmaWindowHandler 取消关联信号 TODO + * @param window + */ +void DBusHandler::removePlasmaWindowHandler(PlasmaWindow *window) +{ + +} + +void DBusHandler::presentWindows(QList windows) +{ + m_wm->PresentWindows(windows); +} + +void DBusHandler::previewWindow(uint xid) +{ + m_wm->PreviewWindow(xid); +} + +void DBusHandler::cancelPreviewWindow() +{ + m_wm->CancelPreviewWindow(); +} + +// TODO: 待优化点, 查看Bamf根据windowId获取对应应用desktopFile路径实现方式, 移除bamf依赖 +QString DBusHandler::getDesktopFromWindowByBamf(XWindow windowId) +{ + QDBusInterface interface0 = QDBusInterface("org.ayatana.bamf", "/org/ayatana/bamf/matcher", "org.ayatana.bamf.matcher"); + QDBusReply replyApplication = interface0.call("ApplicationForXid", windowId); + QString appObjPath = replyApplication.value(); + if (!replyApplication.isValid() || appObjPath.isEmpty()) + return ""; + + + QDBusInterface interface = QDBusInterface("org.ayatana.bamf", appObjPath, "org.ayatana.bamf.application"); + QDBusReply replyDesktopFile = interface.call("DesktopFile"); + + if (replyDesktopFile.isValid()) + return replyDesktopFile.value(); + + + return ""; +} diff --git a/frame/taskmanager/dbushandler.h b/frame/taskmanager/dbushandler.h new file mode 100644 index 000000000..dedd50ae4 --- /dev/null +++ b/frame/taskmanager/dbushandler.h @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef DBUSHANDLER_H +#define DBUSHANDLER_H + +#include "com_deepin_wm.h" +#include "org_deepin_dde_wmswitcher1.h" +#include "org_deepin_dde_xeventmonitor1.h" +#include "org_deepin_dde_kwayland_windowmanager.h" +#include "org_deepin_dde_kwayland_plasmawindow.h" + +#include "windowinfok.h" + +#include +#include +#include + +class TaskManager; + +// 处理DBus交互 +class DBusHandler : public QObject +{ + Q_OBJECT +public: + explicit DBusHandler(TaskManager *taskmanager, QObject *parent = nullptr); + + /************************* KWayland/WindowManager ***************************/ + void listenWaylandWMSignals(); + void loadClientList(); + + bool wlShowingDesktop(); + uint wlActiveWindow(); + + /************************* WMSwitcher ***************************/ + QString getCurrentWM(); + + /************************* StartManager ***************************/ + void launchApp(QString desktopFile, uint32_t timestamp, QStringList files); + void launchAppAction(QString desktopFile, QString action, uint32_t timestamp); + + /************************* AlRecorder1 ***************************/ + void markAppLaunched(const QString &filePath); + + /************************* KWayland.PlasmaWindow ***************************/ + void listenKWindowSignals(WindowInfoK *windowInfo); + void removePlasmaWindowHandler(PlasmaWindow *window); + + PlasmaWindow *createPlasmaWindow(QString objPath); + + /************************* WM ***************************/ + void presentWindows(QList windows); + void previewWindow(uint xid); + void cancelPreviewWindow(); + + /************************* bamf ***************************/ + // XWindow -> desktopFile + QString getDesktopFromWindowByBamf(XWindow windowId); + +private Q_SLOTS: + void handleWlActiveWindowChange(); + void onActiveWindowButtonRelease(int type, int x, int y, const QString &key); + +private: + QString m_activeWindowMonitorKey; + TaskManager *m_taskmanager; + + com::deepin::wm *m_wm; + org::deepin::dde::WMSwitcher1 *m_wmSwitcher; + org::deepin::dde::kwayland1::WindowManager *m_kwaylandManager; + org::deepin::dde::XEventMonitor1 *m_xEventMonitor; +}; + +#endif // DBUSHANDLER_H diff --git a/frame/taskmanager/desktopinfo.cpp b/frame/taskmanager/desktopinfo.cpp new file mode 100644 index 000000000..9a8586f93 --- /dev/null +++ b/frame/taskmanager/desktopinfo.cpp @@ -0,0 +1,247 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "desktopinfo.h" +#include "locale.h" +#include "unistd.h" + +#include + +#include +#include +#include +#include +#include +#include + +QStringList DesktopInfo::currentDesktops; +static QString desktopFileSuffix = ".desktop"; + +DesktopInfo::DesktopInfo(const QString &desktopfile) + : m_isValid(true) +{ + QString desktopfilepath(desktopfile); + QFileInfo desktopFileInfo(desktopfilepath); + if (!(desktopfilepath.endsWith(desktopFileSuffix))) { + desktopfilepath = desktopfilepath + desktopFileSuffix; + desktopFileInfo.setFile(desktopfilepath); + } + + if (!desktopFileInfo.isAbsolute()) { + for (auto dir: QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation)) { + QString path = dir.append("/").append(desktopfilepath); + if (QFile::exists(path)) desktopFileInfo.setFile(path); + } + } + + m_desktopFilePath = desktopFileInfo.absoluteFilePath(); + m_isValid = desktopFileInfo.isAbsolute() && QFile::exists(desktopFileInfo.absoluteFilePath()); + m_desktopFile.reset(new QSettings(m_desktopFilePath, QSettings::IniFormat)); + m_desktopFile->setIniCodec("utf-8"); + // check DesktopInfo valid + QStringList mainKeys = m_desktopFile->childGroups(); + if (mainKeys.size() == 0) + m_isValid = false; + + bool found = std::any_of(mainKeys.begin(), mainKeys.end(), + [](const auto &key) {return key == MainSection;}); + + if (!found) + m_isValid = false; + + if (m_desktopFile->value(MainSection + '/' + KeyType).toString() != TypeApplication) + m_isValid = false; + + m_name = getLocaleStr(MainSection, KeyName); + m_icon = m_desktopFile->value(MainSection + '/' + KeyIcon).toString(); + m_id = getId(); +} + +DesktopInfo::~DesktopInfo() +{ + +} + +QString DesktopInfo::getDesktopFilePath() +{ + return m_desktopFilePath; +} + +bool DesktopInfo::isValidDesktop() +{ + return m_isValid; +} + +/** if return true, item is shown + * @brief DesktopInfo::shouldShow + * @return + */ +bool DesktopInfo::shouldShow() +{ + if (getNoDisplay() || getIsHidden()) { + qDebug() << "hidden desktop file path: " << m_desktopFilePath; + return false; + } + + QStringList desktopEnvs; + return getShowIn(desktopEnvs); +} + +bool DesktopInfo::getNoDisplay() +{ + return m_desktopFile->value(MainSection + '/' + KeyNoDisplay).toBool(); +} + +bool DesktopInfo::getIsHidden() +{ + return m_desktopFile->value(MainSection + '/' + KeyHidden).toBool(); +} + +bool DesktopInfo::getShowIn(QStringList desktopEnvs) +{ +#ifdef QT_DEBUG + qDebug() << "desktop file path: " << m_desktopFilePath; +#endif + + if (desktopEnvs.size() == 0) { + const QString env = getenv("XDG_CURRENT_DESKTOP"); + QVector desktops = env.split(":").toVector(); + currentDesktops.fromVector(desktops); + desktopEnvs.fromVector(desktops); + } + + QStringList onlyShowIn = m_desktopFile->value(MainSection + '/' + KeyOnlyShowIn).toStringList(); + QStringList notShowIn = m_desktopFile->value(MainSection + '/' + KeyNotShowIn).toStringList(); + +#ifdef QT_DEBUG + qDebug() << "onlyShowIn:" << onlyShowIn << + ", notShowIn:" << notShowIn << + ", desktopEnvs:" << desktopEnvs; +#endif + + for (const auto &desktop : desktopEnvs) { + bool ret = std::any_of(onlyShowIn.begin(), onlyShowIn.end(), + [&desktop](const auto &d) {return d == desktop;}); +#ifdef QT_DEBUG + qInfo() << Q_FUNC_INFO << "onlyShowIn, result:" << ret; +#endif + if (ret) + return true; + + ret = std::any_of(notShowIn.begin(), notShowIn.end(), + [&desktop](const auto &d) {return d == desktop;}); +#ifdef QT_DEBUG + qInfo() << Q_FUNC_INFO << "notShowIn, result:" << ret; +#endif + if (ret) + return false; + } + + return onlyShowIn.size() == 0; +} + +QString DesktopInfo::getExecutable() +{ + return m_desktopFile->value(MainSection + '/' + KeyExec).toString(); +} + +QList DesktopInfo::getActions() +{ + QList actions; + for (const auto &mainKey : m_desktopFile->childGroups()) { + if (mainKey.startsWith("Desktop Action") + || mainKey.endsWith("Shortcut Group")) { + DesktopAction action; + action.name = getLocaleStr(mainKey, KeyName); + action.exec = m_desktopFile->value(mainKey + '/' + KeyExec).toString(); + action.section = mainKey; + actions.push_back(action); + } + } + + return actions; +} + +// 使用appId获取DesktopInfo需检查有效性 +DesktopInfo DesktopInfo::getDesktopInfoById(const QString &appId) +{ + QString desktopfile(appId); + if (!desktopfile.endsWith(".desktop")) desktopfile.append(".desktop"); + for (const auto & dir : QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation)) { + QString filePath = dir + desktopfile; + //检测文件有效性 + if (QFile::exists(filePath)) { + return DesktopInfo(filePath); + } + } + + return DesktopInfo(""); +} + +bool DesktopInfo::getTerminal() +{ + return m_desktopFile->value(MainSection + '/' + KeyTerminal).toBool(); +} + +// TryExec is Path to an executable file on disk used to determine if the program is actually installed +QString DesktopInfo::getTryExec() +{ + return m_desktopFile->value(MainSection + '/' + KeyTryExec).toString(); +} + +// 按$PATH路径查找执行文件 +bool DesktopInfo::findExecutable(const QString &exec) +{ + static const char *path = getenv("PATH"); + static QStringList paths = QString(path).split(':'); + return std::any_of(paths.begin(), paths.end(), [&exec](QString path) {return QFile::exists(path + '/' + exec);}); +} + +QString DesktopInfo::getGenericName() +{ + return getLocaleStr(MainSection, KeyGenericName); +} + +QString DesktopInfo::getName() +{ + return m_name; +} + +QString DesktopInfo::getIcon() +{ + return m_icon; +} + +QString DesktopInfo::getCommandLine() +{ + return m_desktopFile->value(MainSection + '/' + KeyExec).toString(); +} + +QStringList DesktopInfo::getKeywords() +{ + return m_desktopFile->value(MainSection + '/' + KeyKeywords).toStringList(); +} + +QStringList DesktopInfo::getCategories() +{ + return m_desktopFile->value(MainSection + '/' + KeyCategories).toStringList(); +} + +QSettings *DesktopInfo::getDesktopFile() +{ + return m_desktopFile.data(); +} + +QString DesktopInfo::getId() +{ + return m_id; +} + +QString DesktopInfo::getLocaleStr(const QString §ion, const QString &key) +{ + QString currentLanguageCode = QLocale::system().name(); + QString res = m_desktopFile->value(section + '/' + key + QString("[%1]").arg(currentLanguageCode)).toString(); + if (res.isEmpty()) res = m_desktopFile->value(section + '/' + key).toString(); + return res; +} diff --git a/frame/taskmanager/desktopinfo.h b/frame/taskmanager/desktopinfo.h new file mode 100644 index 000000000..9eedfe79c --- /dev/null +++ b/frame/taskmanager/desktopinfo.h @@ -0,0 +1,108 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef DESKTOPINFO_H +#define DESKTOPINFO_H + +#include +#include +#include +#include + +const QString MainSection = "Desktop Entry"; +const QString KeyType = "Type"; +const QString KeyVersion = "Version"; +const QString KeyName = "Name"; +const QString KeyGenericName = "GenericName"; +const QString KeyNoDisplay = "NoDisplay"; +const QString KeyComment = "Comment"; +const QString KeyIcon = "Icon"; +const QString KeyHidden = "Hidden"; +const QString KeyOnlyShowIn = "OnlyShowIn"; +const QString KeyNotShowIn = "NotShowIn"; +const QString KeyTryExec = "TryExec"; +const QString KeyExec = "Exec"; +const QString KeyPath = "Path"; +const QString KeyTerminal = "Terminal"; +const QString KeyMimeType = "MimeType"; +const QString KeyCategories = "Categories"; +const QString KeyKeywords = "Keywords"; +const QString KeyStartupNotify = "StartupNotify"; +const QString KeyStartupWMClass = "StartupWMClass"; +const QString KeyURL = "URL"; +const QString KeyActions = "Actions"; +const QString KeyDBusActivatable = "DBusActivatable"; + +const QString TypeApplication = "Application"; +const QString TypeLink = "Link"; +const QString TypeDirectory = "Directory"; + +typedef struct DesktopAction +{ + DesktopAction() + : section("") + , name("") + , exec("") + { + } + QString section; + QString name; + QString exec; +} DesktopAction; + +// 应用Desktop信息类 +class DesktopInfo { +public: + explicit DesktopInfo(const QString &desktopfile); + ~DesktopInfo(); + + static bool isDesktopAction(const QString &name); + static DesktopInfo getDesktopInfoById(const QString &appId); + + bool shouldShow(); + bool getIsHidden(); + bool isInstalled(); + bool getTerminal(); + bool getNoDisplay(); + bool isExecutableOk(); + bool isValidDesktop(); + bool getShowIn(QStringList desktopEnvs); + + void setDesktopOverrideExec(const QString &execStr); + + QString getId(); + QString getName(); + QString getIcon(); + QString getExecutable(); + QString getGenericName(); + QString getCommandLine(); + QString getDesktopFilePath(); + + QStringList getKeywords(); + QStringList getCategories(); + + QList getActions(); + + QSettings *getDesktopFile(); + +private: + bool findExecutable(const QString &exec); + QString getTryExec(); + QString getLocaleStr(const QString §ion, const QString &key); + +private: + static QStringList currentDesktops; + + bool m_isValid; + + QString m_id; + QString m_name; + QString m_icon; + QString m_desktopFilePath; + + // Desktopfile ini format + QScopedPointer m_desktopFile; + +}; +#endif // DESKTOPINFO_H diff --git a/frame/taskmanager/entries.cpp b/frame/taskmanager/entries.cpp new file mode 100644 index 000000000..19d17a0b0 --- /dev/null +++ b/frame/taskmanager/entries.cpp @@ -0,0 +1,349 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "entries.h" +#include "taskmanager.h" +#include "docksettings.h" +#include "taskmanager/windowinfobase.h" + +#include +#include +#include + +Entries::Entries(TaskManager *_taskmanager) + : m_taskmanager(_taskmanager) +{ + +} + +QVector Entries::filterDockedEntries() +{ + QVector ret; + for (auto entry : m_items) { + if (entry->isValid() && entry->getIsDocked()) ret.push_back(entry); + } + return ret; +} + +Entry *Entries::getByInnerId(QString innerId) +{ + Entry *ret = nullptr; + for (auto &entry : m_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 (m_items.contains(entry)) + m_items.removeOne(entry); + + if (index < 0 || index >= m_items.size()) { + // append + index = m_items.size(); + m_items.push_back(entry); + } else { + // insert + m_items.insert(index, entry); + } + + insertCb(entry, index); +} + +void Entries::remove(Entry *entry) +{ + for (auto iter = m_items.begin(); iter != m_items.end();) { + if ((*iter)->getId() == entry->getId()) { + iter = m_items.erase(iter); + } else { + iter++; + } + } + + removeCb(entry); + entry->deleteLater(); +} + +void Entries::move(int oldIndex, int newIndex) +{ + if (oldIndex == newIndex || oldIndex < 0 || newIndex < 0 || oldIndex >= m_items.size() || newIndex >= m_items.size()) + return; + + m_items.swapItemsAt(oldIndex, newIndex); +} + +Entry *Entries::getByWindowPid(int pid) +{ + Entry *ret = nullptr; + for (auto &entry : m_items) { + if (entry->getWindowInfoByPid(pid)) { + ret = entry; + break; + } + } + + return ret; +} + +QStringList Entries::getEntryIDs() +{ + QStringList list; + if (m_taskmanager->getDisplayMode() == DisplayMode::Fashion + && DockSettings::instance()->showRecent()) { + for (Entry *item : m_items) list << item->getId(); + } else { + // 如果是高效模式或者没有开启显示最近应用的功能,那么未驻留并且没有子窗口的就不显示 + // 换句话说,只显示已经驻留或者有子窗口的应用 + for (Entry *item : m_items) { + if (item->getIsDocked() || item->hasWindow()) + list << item->getId(); + } + } + + return list; +} + +Entry *Entries::getByWindowId(XWindow windowId) +{ + Entry *ret = nullptr; + for (auto &entry : m_items) { + if (entry->getWindowInfoByWinId(windowId)) { + ret = entry; + break; + } + } + + return ret; +} + +Entry *Entries::getByDesktopFilePath(const QString &filePath) +{ + Entry *ret = nullptr; + for (auto &entry : m_items) { + qDebug() << entry->getName(); + if (entry->getFileName() == filePath) { + ret = entry; + break; + } + } + + return ret; +} + +QList Entries::getEntries() +{ + QList list; + if (static_cast(m_taskmanager->getDisplayMode()) == DisplayMode::Fashion + && DockSettings::instance()->showRecent()) { + for (Entry *item : m_items) + list << item; + } else { + // 如果是高效模式或者没有开启显示最近应用的功能,那么未驻留并且没有子窗口的就不显示 + // 换句话说,只显示已经驻留或者有子窗口的应用 + for (Entry *item : m_items) { + if (!item->getIsDocked() && !item->hasWindow()) + continue; + list << item; + } + } + + return list; +} + +Entry *Entries::getDockedEntryByDesktopFile(const QString &desktopFile) +{ + Entry *ret = nullptr; + for (auto entry : filterDockedEntries()) { + if ((entry->isValid()) && desktopFile == entry->getFileName()) { + ret = entry; + break; + } + } + + return ret; +} + +QString Entries::queryWindowIdentifyMethod(XWindow windowId) +{ + QString ret; + for (auto entry : m_items) { + auto window = entry->getWindowInfoByWinId(windowId); + if (window) { + auto app = window->getAppInfo(); + ret = app ? app->getIdentifyMethod() : "Failed"; + break; + } + } + + return ret; +} + +void Entries::handleActiveWindowChanged(XWindow activeWindId) +{ + for (auto entry : m_items) { + auto windowInfo = entry->getWindowInfoByWinId(activeWindId); + if (windowInfo) { + entry->setPropIsActive(true); + entry->setCurrentWindowInfo(windowInfo); + entry->updateName(); + entry->updateIcon(); + } else { + entry->setPropIsActive(false); + } + } +} + +void Entries::updateEntriesMenu() +{ + for (auto entry : m_items) { + entry->updateMenu(); + } +} + +const QList Entries::unDockedEntries() const +{ + QList entrys; + for (Entry *entry : m_items) { + if (!entry->isValid() || entry->getIsDocked()) + continue; + + entrys << entry; + } + + return entrys; +} + +void Entries::moveEntryToLast(Entry *entry) +{ + if (m_items.contains(entry)) { + m_items.removeOne(entry); + m_items << entry; + } +} + +void Entries::insertCb(Entry *entry, int index) +{ + if (entry->getIsDocked() || entry->hasWindow() || + ((m_taskmanager->getDisplayMode() == DisplayMode::Fashion) && DockSettings::instance()->showRecent())){ + Q_EMIT m_taskmanager->entryAdded(entry, index); + } +} + +void Entries::removeCb(Entry *entry) +{ + Q_EMIT m_taskmanager->entryRemoved(entry->getId()); +} + +bool Entries::shouldInRecent() +{ + // 如果当前移除的应用是未驻留应用,则判断未驻留应用的数量是否小于等于3,则让其始终显示 + QList unDocktrys; + for (Entry *entry : m_items) { + if (entry->isValid() && !entry->getIsDocked()) + unDocktrys << entry; + } + + // 如果当前未驻留应用的数量小于3个,则认为后续的应用应该显示到最近打开应用 + return (unDocktrys.size() <= MAX_UNOPEN_RECENT_COUNT); +} + +void Entries::removeLastRecent() +{ + // 先查找最近使用的应用,删除没有使用的 + int unDockCount = 0; + QList unDockEntrys; + QList removeEntrys; + + for (Entry *entry : m_items) { + if (entry->getIsDocked()) + continue; + + // 此处只移除没有子窗口的图标 + if (!entry->hasWindow()) { + if (!entry->isValid()) + removeEntrys << entry; // 如果应用已经被卸载,那么需要删除 + else + unDockEntrys << entry; + } + + unDockCount++; + } + if (unDockCount >= MAX_UNOPEN_RECENT_COUNT && unDockEntrys.size() > 0) { + // 只有当最近使用区域的图标大于等于某个数值(3)的时候,并且存在没有子窗口的Entry,那么就移除该Entry + Entry *entry = unDockEntrys[0]; + removeEntrys << entry; + } + for (Entry *entry : removeEntrys) { + m_items.removeOne(entry); + removeCb(entry); + entry->deleteLater(); + } +} + +void Entries::setDisplayMode(DisplayMode displayMode) +{ + if (!DockSettings::instance()->showRecent()) + return; + + // 如果从时尚模式变成高效模式,对列表中所有的没有打开窗口的应用发送移除信号 + if (displayMode == DisplayMode::Efficient) { + for (Entry *entry : m_items) { + entry->updateMode(); + if (!entry->getIsDocked() && !entry->hasWindow()) + Q_EMIT m_taskmanager->entryRemoved(entry->getId()); + } + } else { + // 如果从高效模式变成时尚模式,列表中所有的未驻留且不存在打开窗口的应用认为是最近打开应用,发送新增信号 + for (Entry *entry : m_items) { + entry->updateMode(); + if (!entry->getIsDocked() && !entry->hasWindow()) { + // QString objPath = entry->path(); + int index = m_items.indexOf(entry); + Q_EMIT m_taskmanager->entryAdded(entry, index); + qDebug() << entry->getName(); + } + } + } +} + +void Entries::updateShowRecent() +{ + // 高效模式无需做任何操作 + if (static_cast(m_taskmanager->getDisplayMode()) != DisplayMode::Fashion) + return; + + bool showRecent = DockSettings::instance()->showRecent(); + if (showRecent) { + // 如果显示最近打开应用,则发送新增信号 + for (Entry *entry : m_items) { + // 已经驻留的或者有子窗口的本来就在任务栏上面,无需发送信号 + entry->updateMode(); + if (entry->getIsDocked() || entry->hasWindow()) + continue; + + // QString objPath = entry->path(); + int index = m_items.indexOf(entry); + Q_EMIT m_taskmanager->entryAdded(entry, index); + } + } else { + // 如果是隐藏最近打开的应用,则发送移除的信号 + for (Entry *entry : m_items) { + // 已经驻留的或者有子窗口的本来就在任务栏上面,无需发送信号 + entry->updateMode(); + if (entry->getIsDocked() || entry->hasWindow()) + continue; + + Q_EMIT m_taskmanager->entryRemoved(entry->getId()); + } + } +} diff --git a/frame/taskmanager/entries.h b/frame/taskmanager/entries.h new file mode 100644 index 000000000..f9c305b72 --- /dev/null +++ b/frame/taskmanager/entries.h @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef ENTRIES_H +#define ENTRIES_H + +#include "entry.h" +#include "constants.h" +#include "taskmanager/windowinfobase.h" + +#include +#include +#include + +#define MAX_UNOPEN_RECENT_COUNT 3 + +class TaskManager; + +// 所有应用管理类 +class Entries +{ +public: + Entries(TaskManager *_taskmanager); + + const QList unDockedEntries() const; + + bool shouldInRecent(); + + void removeLastRecent(); + void updateShowRecent(); + void updateEntriesMenu(); + void append(Entry *entry); + void remove(Entry *entry); + void moveEntryToLast(Entry *entry); + void insert(Entry *entry, int index); + void move(int oldIndex, int newIndex); + void setDisplayMode(Dock::DisplayMode displayMode); + void handleActiveWindowChanged(XWindow activeWindId); + + QString queryWindowIdentifyMethod(XWindow windowId); + QStringList getEntryIDs(); + + Entry *getByWindowPid(int pid); + Entry *getByInnerId(QString innerId); + Entry *getByWindowId(XWindow windowId); + Entry *getByDesktopFilePath(const QString &filePath); + Entry *getDockedEntryByDesktopFile(const QString &desktopFile); + + QList getEntries(); + QVector filterDockedEntries(); + +private: + void insertCb(Entry *entry, int index); + void removeCb(Entry *entry); + +private: + QList m_items; + TaskManager *m_taskmanager; +}; + +#endif // ENTRIES_H diff --git a/frame/taskmanager/entry.cpp b/frame/taskmanager/entry.cpp new file mode 100644 index 000000000..a2f0bfbde --- /dev/null +++ b/frame/taskmanager/entry.cpp @@ -0,0 +1,883 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "entry.h" +#include "docksettings.h" +#include "xcbutils.h" +#include "taskmanager.h" +#include "processinfo.h" +#include "windowinfomap.h" + +#include +#include + +#include +#include + +#define XCB XCBUtils::instance() + +Entry::Entry(TaskManager *_taskmanager, AppInfo *_app, QString _innerId, QObject *parent) + : QObject(parent) + , m_isActive(false) + , m_isDocked(false) + , m_winIconPreferred(false) + , m_innerId(_innerId) + , m_adapterEntry(nullptr) + , m_taskmanager(_taskmanager) + , m_current(nullptr) + , m_currentWindow(0) +{ + setAppInfo(_app); + m_id = m_taskmanager->allocEntryId(); + m_mode = getCurrentMode(); + m_name = getName(); + m_icon = getIcon(); +} + +Entry::~Entry() +{ + for (auto winInfo : m_windowInfoMap) { + if (winInfo) winInfo->deleteLater(); + } + m_windowInfoMap.clear(); + +} + +bool Entry::isValid() +{ + // desktopfile 无效时且没有窗口时,该entry是无效的 + // 虽然也就是desktop是无效时,但是当前存在窗口,该entry也是有效的。 + return m_isValid || m_current; +} + +QString Entry::getId() const +{ + return m_id; +} + +QString Entry::getName() +{ + QString ret = m_current ? m_current->getDisplayName() : QString(); + if (m_appInfo.isNull()) return ret; + ret = m_appInfo->getName(); + return ret; +} + +void Entry::updateName() +{ + setPropName(getName()); +} + +QString Entry::getIcon() +{ + QString ret; + if (hasWindow()) { + if (!m_current) { + return ret; + } + + // has window && current not nullptr + if (m_winIconPreferred) { + // try current window icon first + ret = m_current->getIcon(); + if (ret.size() > 0) { + return ret; + } + } + + if (m_appInfo) { + m_icon = m_appInfo->getIcon(); + if (m_icon.size() > 0) { + return m_icon; + } + } + + return m_current->getIcon(); + } + + if (m_appInfo) { + // no window + return m_appInfo->getIcon(); + } + + return ret; +} + +QString Entry::getInnerId() +{ + return m_innerId; +} + +void Entry::setInnerId(QString _innerId) +{ + qDebug() << "setting innerID from: " << m_innerId << " to: " << _innerId; + m_innerId = _innerId; +} + +QString Entry::getFileName() +{ + return m_appInfo.isNull() ? QString() : m_appInfo->getFileName(); +} + +AppInfo *Entry::getAppInfo() +{ + return m_appInfo.data(); +} + +void Entry::setAppInfo(AppInfo *appinfo) +{ + if (m_appInfo.data() == appinfo) { + return; + } + + m_appInfo.reset(appinfo); + m_isValid = appinfo->isValidApp(); + m_winIconPreferred = !appinfo; + setPropDesktopFile(appinfo ? appinfo->getFileName(): ""); + if (!m_winIconPreferred) { + QString id = m_appInfo->getId(); + auto perferredApps = m_taskmanager->getWinIconPreferredApps(); + if (perferredApps.contains(id)|| appinfo->getIcon().size() == 0) { + m_winIconPreferred = true; + return; + } + } +} + +bool Entry::getIsDocked() const +{ + return m_isDocked; +} + +void Entry::setIsDocked(bool value) +{ + if (value != m_isDocked) { + m_isDocked = value; + Q_EMIT isDockedChanged(value); + } +} + +void Entry::setMenu(AppMenu *_menu) +{ + _menu->setDirtyStatus(true); + m_appMenu.reset(_menu); + Q_EMIT menuChanged(m_appMenu->getMenuJsonStr()); +} + +void Entry::updateMenu() +{ + qInfo() <<"Entry: updateMenu"; + AppMenu *appMenu = new AppMenu(); + appMenu->appendItem(getMenuItemLaunch()); + + for (auto &item :getMenuItemDesktopActions()) + appMenu->appendItem(item); + + if (hasWindow()) + appMenu->appendItem(getMenuItemAllWindows()); + + // menu item dock or undock + qInfo() << "entry " << m_id << " docked? " << m_isDocked; + appMenu->appendItem(m_isDocked? getMenuItemUndock(): getMenuItemDock()); + + if (hasWindow()) { + if (m_taskmanager->getForceQuitAppStatus() != ForceQuitAppMode::Disabled) { + appMenu->appendItem(m_appInfo && m_appInfo->getIdentifyMethod() == "Andriod" ? + getMenuItemForceQuitAndroid() : getMenuItemForceQuit()); + } + + if (getAllowedCloseWindows().size() > 0) + appMenu->appendItem(getMenuItemCloseAll()); + } + + setMenu(appMenu); +} + +void Entry::updateIcon() +{ + setPropIcon(getIcon()); +} + +int Entry::getCurrentMode() +{ + // 只要当前应用是已经驻留的应用,则让其显示为Normal + if (getIsDocked()) + return ENTRY_NORMAL; + + // 对于未驻留的应用则做如下处理 + if (m_taskmanager->getDisplayMode() == DisplayMode::Efficient) { + // 高效模式下,只有存在子窗口的,则让其为nornal,没有子窗口的,一般不让其显示 + return hasWindow() ? ENTRY_NORMAL : ENTRY_NONE; + } + // 时尚模式下对未驻留应用做如下处理 + // 如果开启了最近打开应用的功能,则显示到最近打开区域(ENTRY_RECENT) + if (DockSettings::instance()->showRecent()) + return ENTRY_RECENT; + + // 未开启最近使用应用的功能,如果有子窗口,则显示成通用的(ENTRY_NORMAL),如果没有子窗口,则不显示(ENTRY_NONE) + return hasWindow() ? ENTRY_NORMAL : ENTRY_NONE; +} + +void Entry::updateMode() +{ + int currentMode = getCurrentMode(); + if (m_mode != currentMode) { + m_mode = currentMode; + Q_EMIT modeChanged(m_mode); + } +} + +void Entry::forceUpdateIcon() +{ + m_icon = getIcon(); + Q_EMIT iconChanged(m_icon); +} + +void Entry::updateIsActive() +{ + bool isActive = false; + auto activeWin = m_taskmanager->getActiveWindow(); + if (activeWin) { + // 判断活跃窗口是否属于当前应用 + isActive = m_windowInfoMap.find(activeWin->getXid()) != m_windowInfoMap.end(); + } + + setPropIsActive(isActive); +} + +WindowInfoBase *Entry::getWindowInfoByPid(int pid) +{ + for (const auto &windowInfo : m_windowInfoMap) { + if (windowInfo->getPid() == pid) + return windowInfo; + } + + return nullptr; +} + +WindowInfoBase *Entry::getWindowInfoByWinId(XWindow windowId) +{ + if (m_windowInfoMap.find(windowId) != m_windowInfoMap.end()) + return m_windowInfoMap[windowId]; + + return nullptr; +} + +void Entry::setPropIcon(QString value) +{ + if (value != m_icon) { + m_icon = value; + Q_EMIT iconChanged(value); + } +} + +void Entry::setPropName(QString value) +{ + if (value != m_name) { + m_name = value; + Q_EMIT nameChanged(value); + } +} + +void Entry::setPropIsActive(bool active) +{ + if (m_isActive != active) { + m_isActive = active; + Q_EMIT isActiveChanged(active); + } +} + +void Entry::setCurrentWindowInfo(WindowInfoBase *windowInfo) +{ + m_current = windowInfo; + setPropCurrentWindow(m_current ? m_current->getXid() : 0); +} + +void Entry::setPropCurrentWindow(XWindow value) +{ + if (value != m_currentWindow) { + m_currentWindow = value; + Q_EMIT currentWindowChanged(value); + } +} + +WindowInfoBase *Entry::getCurrentWindowInfo() +{ + return m_current; +} + +/** + * @brief Entry::findNextLeader + * @return + */ +WindowInfoBase *Entry::findNextLeader() +{ + auto xids = m_windowInfoMap.keys(); + std::sort(xids.begin(), xids.end()); + XWindow curWinId = m_current->getXid(); + int index = xids.indexOf(curWinId); + if (index < 0) + return nullptr; + + // 如果当前窗口是最大, 返回xids[0], 否则返回xids[index + 1] + int nextIndex = 0; + if (index < xids.size() - 1) + nextIndex = index + 1; + + return m_windowInfoMap[xids[nextIndex]]; +} + +QString Entry::getExec() +{ + if (!m_current) + return ""; + + ProcessInfo *process = m_current->getProcess(); + return process->getExe(); +} + +QString Entry::getCmdLine() +{ + QString ret; + if (!m_current) return ret; + + ProcessInfo *process = m_current->getProcess(); + for (auto i : process->getCmdLine()) ret += i + " "; + return ret; + +} + +bool Entry::hasWindow() +{ + return m_windowInfoMap.size() > 0; +} + +/** + * @brief Entry::updateExportWindowInfos 同步更新导出窗口信息 + */ +void Entry::updateExportWindowInfos() +{ + WindowInfoMap infos; + for (auto info : m_windowInfoMap) { + WindowInfo winInfo; + XWindow xid = info->getXid(); + winInfo.title = info->getTitle(); + winInfo.attention = info->isDemandingAttention(); + winInfo.uuid = info->uuid(); + infos[xid] = winInfo; + } + + bool changed = true; + if (infos.size() == m_exportWindowInfos.size()) { + changed = false; + for (auto iter = infos.begin(); iter != infos.end(); iter++) { + XWindow xid = iter.key(); + if (infos[xid].title != m_exportWindowInfos[xid].title || + infos[xid].attention != m_exportWindowInfos[xid].attention || + infos[xid].uuid != m_exportWindowInfos[xid].uuid) { + changed = true; + break; + } + } + } + + if (changed) { + Q_EMIT windowInfosChanged(infos); + } + + // 更新导出的窗口信息 + m_exportWindowInfos = infos; +} + +// 分离窗口, 返回是否需要从任务栏remove +bool Entry::detachWindow(WindowInfoBase *info) +{ + info->setEntry(nullptr); + XWindow winId = info->getXid(); + if (m_windowInfoMap.contains(winId)) { + m_windowInfoMap.remove(winId); + info->deleteLater(); + } + + if (m_windowInfoMap.isEmpty()) { + if (!m_isDocked) { + // 既无窗口也非驻留应用,并且不是最近打开,无需在任务栏显示 + return true; + } + + Q_EMIT windowInfosChanged(WindowInfoMap()); + setCurrentWindowInfo(nullptr); + } else { + for (auto window : m_windowInfoMap) { + if (window) { // 选择第一个窗口作为当前窗口 + setCurrentWindowInfo(window); + break; + } + } + } + + updateExportWindowInfos(); + updateIcon(); + updateMenu(); + + return false; +} + +bool Entry::isShowOnDock() const +{ + // 当前应用显示图标的条件是 + // 如果该图标已经固定在任务栏上,则始终显示 + if (getIsDocked()) + return true; + + // 1.时尚模式下,如果开启了显示最近使用,则不管是否有子窗口,都在任务栏上显示 + // 如果没有开启显示最近使用,则只显示有子窗口的 + if (m_taskmanager->getDisplayMode() == DisplayMode::Fashion) + return (DockSettings::instance()->showRecent() || m_exportWindowInfos.size() > 0); + + // 2.高效模式下,只有该应用有打开窗口才显示 + return m_exportWindowInfos.size() > 0; +} + +bool Entry::attachWindow(WindowInfoBase *info) +{ + XWindow winId = info->getXid(); + qInfo() << "attatchWindow: window id:" << winId; + info->setEntry(this); + + if (m_windowInfoMap.find(winId) != m_windowInfoMap.end()) { + qInfo() << "attachWindow: window " << winId << " is already attached"; + return false; + } + + bool lastShowOnDock = isShowOnDock(); + m_windowInfoMap[winId] = info; + updateExportWindowInfos(); + updateIsActive(); + + if (!m_current) { + // from no window to has window + setCurrentWindowInfo(info); + } + + updateIcon(); + updateMenu(); + + if (!lastShowOnDock && isShowOnDock()) { + // 新打开的窗口始终显示到最后 + Q_EMIT m_taskmanager->entryAdded(this, -1); + } + + return true; +} + +void Entry::launchApp(uint32_t timestamp) +{ + if (m_appInfo) + m_taskmanager->launchApp(m_appInfo->getFileName(), timestamp, QStringList()); +} + +bool Entry::containsWindow(XWindow xid) +{ + return m_windowInfoMap.find(xid) != m_windowInfoMap.end(); +} + +// 处理菜单项 +void Entry::handleMenuItem(uint32_t timestamp, QString itemId) +{ + m_appMenu->handleAction(timestamp, itemId); +} + +// 处理拖拽事件 +void Entry::handleDragDrop(uint32_t timestamp, QStringList files) +{ + m_taskmanager->launchApp(m_appInfo->getFileName(), timestamp, files); +} + +// 驻留 +void Entry::requestDock(bool dockToEnd) +{ + if (m_taskmanager->dockEntry(this, dockToEnd)) { + m_taskmanager->saveDockedApps(); + } +} + +// 取消驻留 +void Entry::requestUndock(bool dockToEnd) +{ + m_taskmanager->undockEntry(this, dockToEnd); +} + +void Entry::newInstance(uint32_t timestamp) +{ + QStringList files; + m_taskmanager->launchApp(m_appInfo->getFileName(), timestamp, files); +} + +// 检查应用窗口分离、合并状态 +void Entry::check() +{ + QList windows = m_windowInfoMap.values(); + for (WindowInfoBase *window : windows) { + m_taskmanager->attachOrDetachWindow(window); + } +} + +// 强制退出 +void Entry::forceQuit() +{ + QMap> pidWinInfoMap; + QList windows = m_windowInfoMap.values(); + for (WindowInfoBase *window : windows) { + int pid = window->getPid(); + if (pid != 0) { + pidWinInfoMap[pid].push_back(window); + } else { + window->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(); + } + } + } + // 所有的窗口已经退出后,清空m_windowInfoMap内容 + m_windowInfoMap.clear(); + // 退出所有的进程后,及时更新当前剩余的窗口数量 + updateExportWindowInfos(); + m_taskmanager->removeEntryFromDock(this); +} + +void Entry::presentWindows() +{ + QList windows = m_windowInfoMap.keys(); + m_taskmanager->presentWindows(windows); +} + +/** + * @brief Entry::active 激活窗口 + * @param timestamp + */ +void Entry::active(uint32_t timestamp) +{ + if (m_taskmanager->getHideMode() == HideMode::SmartHide) { + m_taskmanager->setPropHideState(HideState::Show); + m_taskmanager->updateHideState(false); + } + + // 无窗口则直接启动 + if (!hasWindow()) { + launchApp(timestamp); + return; + } + + if (!m_current) { + qWarning() << "active: current window is nullptr"; + return; + } + + WindowInfoBase *winInfo = m_current; + if (m_taskmanager->isWaylandEnv()) { + // wayland环境 + if (!m_taskmanager->isActiveWindow(winInfo)) { + winInfo->activate(); + } else { + bool showing = m_taskmanager->isShowingDesktop(); + if (showing || winInfo->isMinimized()) { + winInfo->activate(); + } else if (m_windowInfoMap.size() == 1) { + winInfo->minimize(); + } else { + WindowInfoBase *nextWin = findNextLeader(); + if (nextWin) { + nextWin->activate(); + } + } + } + } else { + // X11环境 + XWindow xid = winInfo->getXid(); + WindowInfoBase *activeWin = m_taskmanager->getActiveWindow(); + if (activeWin && xid != activeWin->getXid()) { + m_taskmanager->doActiveWindow(xid); + } else { + bool found = false; + XWindow hiddenAtom = XCB->getAtom("_NET_WM_STATE_HIDDEN"); + for (auto state : XCB->getWMState(xid)) { + if (hiddenAtom == state) { + found = true; + break; + } + } + + if (found) { + // 激活隐藏窗口 + m_taskmanager->doActiveWindow(xid); + } else if (m_windowInfoMap.size() == 1) { + // 窗口图标化 + XCB->minimizeWindow(xid); + } else if (m_taskmanager->getActiveWindow() && m_taskmanager->getActiveWindow()->getXid() == xid) { + WindowInfoBase *nextWin = findNextLeader(); + if (nextWin) { + nextWin->activate(); + } + } + } + } +} + +void Entry::activeWindow(quint32 winId) +{ + if (m_taskmanager->isWaylandEnv()) { + if (!m_windowInfoMap.contains(winId)) + return; + + WindowInfoBase *winInfo = m_windowInfoMap[winId]; + if (m_taskmanager->isActiveWindow(winInfo)) { + bool showing = m_taskmanager->isShowingDesktop(); + if (showing || winInfo->isMinimized()) { + winInfo->activate(); + } else if (m_windowInfoMap.size() == 1) { + winInfo->minimize(); + } else { + WindowInfoBase *nextWin = findNextLeader(); + if (nextWin) { + nextWin->activate(); + } + } + } else { + winInfo->activate(); + } + } else { + m_taskmanager->doActiveWindow(winId); + } +} + +int Entry::mode() +{ + return m_mode; +} + +XWindow Entry::getCurrentWindow() +{ + return m_currentWindow; +} + +QString Entry::getDesktopFile() +{ + return m_desktopFile; +} + +bool Entry::getIsActive() const +{ + return m_isActive; +} + +QString Entry::getMenu() const +{ + return m_appMenu->getMenuJsonStr(); +} + +QVector Entry::getAllowedClosedWindowIds() +{ + QVector ret; + for (auto iter = m_windowInfoMap.begin(); iter != m_windowInfoMap.end(); iter++) { + WindowInfoBase *info = iter.value(); + if (info && info->allowClose()) + ret.push_back(iter.key()); + } + + return ret; +} + +WindowInfoMap Entry::getExportWindowInfos() +{ + return m_exportWindowInfos; +} + +QVector Entry::getAllowedCloseWindows() +{ + QVector ret; + for (auto iter = m_windowInfoMap.begin(); iter != m_windowInfoMap.end(); iter++) { + WindowInfoBase *info = iter.value(); + if (info && info->allowClose()) { + ret.push_back(info); + } + } + + return ret; +} + +QVector Entry::getMenuItemDesktopActions() +{ + QVector ret; + if (!m_appInfo) { + return ret; + } + + for (auto action : m_appInfo->getActions()) { + AppMenuAction fn = [=](uint32_t timestamp) { + qInfo() << "do MenuItem: " << action.name; + m_taskmanager->launchAppAction(m_appInfo->getFileName(), action.section, timestamp); + }; + + AppMenuItem item; + item.text = action.name; + item.action = fn; + item.isActive = true; + ret.push_back(item); + } + + return ret; +} + +AppMenuItem Entry::getMenuItemLaunch() +{ + QString itemName; + if (hasWindow()) { + itemName = getName(); + } else { + itemName = tr("Open"); + } + + AppMenuAction fn = [this](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 = [this](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); + } + + // 关闭窗口后,主动刷新事件 + XCB->flush(); + }; + + AppMenuItem item; + item.text = tr("Close All"); + item.action = fn; + item.isActive = true; + return item; +} + +AppMenuItem Entry::getMenuItemForceQuit() +{ + bool active = m_taskmanager->getForceQuitAppStatus() != ForceQuitAppMode::Deactivated; + AppMenuAction fn = [this](uint32_t) { + qInfo() << "do MenuItem: Force Quit"; + forceQuit(); + }; + + AppMenuItem item; + item.text = tr("Force Quit"); + item.action = fn; + item.isActive = active; + return item; +} + +//dock栏上Android程序的Force Quit功能 +AppMenuItem Entry::getMenuItemForceQuitAndroid() +{ + bool active = m_taskmanager->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 = tr("Force Quit"); + item.action = fn; + item.isActive = active; + return item; +} + +AppMenuItem Entry::getMenuItemDock() +{ + AppMenuItem item; + item.text = tr("Dock"); + item.action = [this](uint32_t) { + qInfo() << "do MenuItem: Dock"; + requestDock(true); + }; + + item.isActive = true; + return item; +} + +AppMenuItem Entry::getMenuItemUndock() +{ + AppMenuItem item; + item.text = tr("Undock"); + item.action = [this](uint32_t) { + qInfo() << "do MenuItem: Undock"; + requestUndock(true); + }; + + item.isActive = true; + return item; +} + +AppMenuItem Entry::getMenuItemAllWindows() +{ + AppMenuItem item; + item.text = tr("All Windows"); + item.action = [this](uint32_t) { + qInfo() << "do MenuItem: All Windows"; + presentWindows(); + }; + + item.isActive = true; + item.hint = 1; + return item; +} + +bool Entry::killProcess(int pid) +{ + return !kill(pid, SIGTERM); +} + +bool Entry::setPropDesktopFile(QString value) +{ + if (value != m_desktopFile) { + m_desktopFile = value; + Q_EMIT desktopFileChanged(value); + return true; + } + + return false; +} diff --git a/frame/taskmanager/entry.h b/frame/taskmanager/entry.h new file mode 100644 index 000000000..0e5f44018 --- /dev/null +++ b/frame/taskmanager/entry.h @@ -0,0 +1,156 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef ENTRY_H +#define ENTRY_H + +#include "appinfo.h" +#include "appmenu.h" +#include "windowinfomap.h" +#include "windowinfobase.h" + +#include +#include +#include +#include + +#define ENTRY_NONE 0 +#define ENTRY_NORMAL 1 +#define ENTRY_RECENT 2 + +// 单个应用类 +class TaskManager; +class DBusAdaptorEntry; +class WindowInfo; + +typedef QMap WindowInfoMap; + +class Entry: public QObject +{ + Q_OBJECT +public: + Entry(TaskManager *_taskmanager, AppInfo *_app, QString _innerId, QObject *parent = nullptr); + ~Entry(); + + void updateName(); + void updateMenu(); + void updateIcon(); + void updateMode(); + void updateIsActive(); + void forceUpdateIcon(); + void updateExportWindowInfos(); + void launchApp(uint32_t timestamp); + + void setIsDocked(bool value); + void setMenu(AppMenu *_menu); + void setPropIcon(QString value); + void setPropName(QString value); + void setPropIsActive(bool active); + void setInnerId(QString _innerId); + void setAppInfo(AppInfo *appinfo); + void setPropCurrentWindow(XWindow value); + void setCurrentWindowInfo(WindowInfoBase *windowInfo); + + void check(); + void forceQuit(); + void presentWindows(); + void active(uint32_t timestamp); + void activeWindow(quint32 winId); + void newInstance(uint32_t timestamp); + void requestDock(bool dockToEnd = false); + void requestUndock(bool dockToEnd = false); + void handleMenuItem(uint32_t timestamp, QString itemId); + void handleDragDrop(uint32_t timestamp, QStringList files); + + bool containsWindow(XWindow xid); + bool detachWindow(WindowInfoBase *info); + bool attachWindow(WindowInfoBase *info); + + bool getIsDocked() const; + bool getIsActive() const; + + QString getId() const; + QString getMenu() const; + + bool isValid(); + bool hasWindow(); + + int mode(); + + QString getName(); + QString getIcon(); + QString getInnerId(); + QString getFileName(); + QString getDesktopFile(); + QString getExec(); + QString getCmdLine(); + + XWindow getCurrentWindow(); + + AppInfo *getAppInfo(); + + WindowInfoBase *findNextLeader(); + WindowInfoBase *getCurrentWindowInfo(); + WindowInfoBase *getWindowInfoByPid(int pid); + WindowInfoBase *getWindowInfoByWinId(XWindow windowId); + + WindowInfoMap getExportWindowInfos(); + QVector getAllowedClosedWindowIds(); + +public Q_SLOTS: + QVector getAllowedCloseWindows(); + +Q_SIGNALS: + void modeChanged(int); + void isActiveChanged(bool); + void isDockedChanged(bool); + void menuChanged(QString); + void iconChanged(QString); + void nameChanged(QString); + void desktopFileChanged(QString); + void currentWindowChanged(uint32_t); + void windowInfosChanged(const WindowInfoMap&); + +private: + // 右键菜单项 + bool killProcess(int pid); + bool setPropDesktopFile(QString value); + bool isShowOnDock() const; + int getCurrentMode(); + + AppMenuItem getMenuItemLaunch(); + AppMenuItem getMenuItemCloseAll(); + AppMenuItem getMenuItemForceQuit(); + + AppMenuItem getMenuItemDock(); + AppMenuItem getMenuItemUndock(); + AppMenuItem getMenuItemAllWindows(); + AppMenuItem getMenuItemForceQuitAndroid(); + QVector getMenuItemDesktopActions(); + +private: + bool m_isActive; + bool m_isValid; + bool m_isDocked; + bool m_winIconPreferred; + int m_mode; + + QString m_id; + QString m_name; + QString m_icon; + QString m_innerId; + QString m_desktopFile; + + DBusAdaptorEntry *m_adapterEntry; + TaskManager *m_taskmanager; + WindowInfoMap m_exportWindowInfos; // 该应用导出的窗口属性 + WindowInfoBase *m_current; // 当前窗口 + XWindow m_currentWindow; //当前窗口Id + + QScopedPointer m_appInfo; + QScopedPointer m_appMenu; + QMap m_windowInfoMap; // 该应用所有窗口 +}; + +#endif // ENTRY_H diff --git a/frame/taskmanager/processinfo.cpp b/frame/taskmanager/processinfo.cpp new file mode 100644 index 000000000..7443efe33 --- /dev/null +++ b/frame/taskmanager/processinfo.cpp @@ -0,0 +1,214 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "processinfo.h" + +#include +#include +#include + +#include +#include +#include + +ProcessInfo::ProcessInfo(int pid) + : m_pid(pid) + , m_ppid(0) + +{ + if (pid == 0) + return; + m_exe = getExe(); + m_cwd = getCwd(); + m_cmdLine = getCmdLine(); + getStatus(); + // 部分root进程在/proc文件系统查找不到exe、cwd、cmdline信息 + if (m_exe.isEmpty() || m_cwd.isEmpty() || m_cmdLine.size() == 0) { + m_isValid = false; + return; + } + + // args + qInfo() << "ProcessInfo: exe=" << m_exe << " cwd=" << m_cwd << " cmdLine=" << (m_cmdLine[0].isEmpty() ? " " : m_cmdLine[0]); + auto verifyExe = [](QString exe, QString cwd, QString firstArg){ + if (firstArg.size() == 0) return false; + + QFileInfo info(firstArg); + if (info.completeBaseName() == firstArg) return true; + + if (!QDir::isAbsolutePath(firstArg)) + firstArg = cwd + firstArg; + + return exe == firstArg; + }; + + if (!m_cmdLine[0].isEmpty()) { + if (!verifyExe(m_exe, m_cwd, m_cmdLine[0])) { + auto parts = m_cmdLine[0].split(' '); + // try again + if (verifyExe(m_exe, m_cwd, parts[0])) { + m_args.append(parts.mid(1, parts.size() - 1)); + m_args.append(m_cmdLine.mid(1, m_cmdLine.size() - 1)); + } + } else { + m_args.append(m_cmdLine.mid(1, m_cmdLine.size() - 1)); + } + } +} + +ProcessInfo::ProcessInfo(QStringList cmd) + : m_hasPid(false) + , m_isValid(true) +{ + if (cmd.size() == 0) { + m_isValid = false; + return; + } + + m_cmdLine = cmd; + m_exe = cmd[0]; + m_args.append(cmd.mid(1, cmd.size() - 1)); +} + +ProcessInfo::~ProcessInfo() +{ +} + +QString ProcessInfo::getEnv(const QString &key) +{ + if (m_environ.size() == 0) getEnviron(); + return m_environ[key]; +} + +Status ProcessInfo::getStatus() +{ + if (!m_status.empty()){ + return m_status; + } + + QString statusFile = getFile("status"); + + std::ifstream fs(statusFile.toStdString()); + if (!fs.is_open()) { + return m_status; + } + + std::string tmp = ""; + while (std::getline(fs, tmp)) { + auto pos = tmp.find_first_of(':'); + if (pos == std::string::npos) { + continue; + } + + QString value; + if (pos + 1 < tmp.length()) { + value = QString::fromStdString(tmp.substr(pos + 1)); + } + + m_status[QString::fromStdString(tmp.substr(0, pos))] = value; + } + + return m_status; +} + +QStringList ProcessInfo::getCmdLine() +{ + if (m_cmdLine.size() == 0) { + QString cmdlineFile = getFile("cmdline"); + m_cmdLine = readFile(cmdlineFile); + } + + return m_cmdLine; +} + +QStringList ProcessInfo::getArgs() +{ + return m_args; +} + +int ProcessInfo::getPid() +{ + + return m_pid; +} + +int ProcessInfo::getPpid() +{ + if (m_ppid == 0) { + if (m_status.find("PPid") != m_status.end()) { + m_ppid = std::stoi(m_status["PPid"].toStdString()); + } + } + return m_ppid; +} + +bool ProcessInfo::initWithPid() +{ + return m_hasPid; +} + +bool ProcessInfo::isValid() +{ + return m_isValid; +} + +QString ProcessInfo::getExe() +{ + if (m_exe.isEmpty()) { + QString cmdLineFile = getFile("exe"); + QFileInfo path(cmdLineFile); + m_exe = path.canonicalFilePath(); + } + + return m_exe; +} + +bool ProcessInfo::isExist() +{ + QString procDir = "/proc/" + QString(m_pid); + return QFile::exists(procDir); +} + +QStringList ProcessInfo::readFile(const QString &filePath) +{ + QStringList ret; + std::ifstream fs(filePath.toStdString()); + if (!fs.is_open()) { + return ret; + } + + std::string tmp; + while (std::getline(fs, tmp, '\0')) { + ret.append(QString::fromStdString(tmp)); + } + return ret; +} + +QString ProcessInfo::getFile(const QString &file) +{ + return QString("/proc/").append(QString::number(m_pid).append('/').append(file)); +} + +QString ProcessInfo::getCwd() +{ + if (m_cwd.isEmpty()) { + QString cwdFile = getFile("cwd"); + QFileInfo path(cwdFile); + m_cwd = path.canonicalFilePath(); + } + return m_cwd; +} + +QMap ProcessInfo::getEnviron() +{ + if (m_environ.size() == 0) { + QString envFile = getFile("environ"); + QStringList contents = readFile(envFile); + for (auto line : contents){ + int index = line.indexOf('='); + m_environ.insert(line.left(index), line.right(line.size() - index - 1)); + } + } + return m_environ; +} \ No newline at end of file diff --git a/frame/taskmanager/processinfo.h b/frame/taskmanager/processinfo.h new file mode 100644 index 000000000..541a8a5d1 --- /dev/null +++ b/frame/taskmanager/processinfo.h @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef PROCESSINFO_H +#define PROCESSINFO_H + +#include +#include +#include + +typedef QMap Status; + +// 进程信息 +class ProcessInfo +{ +public: + explicit ProcessInfo(int pid); + explicit ProcessInfo(QStringList cmd); + virtual ~ProcessInfo(); + + bool isValid(); + bool initWithPid(); + + int getPid(); + int getPpid(); + + QString getExe(); + QString getCwd(); + Status getStatus(); + QString getEnv(const QString &key); + + QStringList getArgs(); + QStringList getCmdLine(); + QMap getEnviron(); + +private: + bool isExist(); + QString getJoinedExeArgs(); + QString getFile(const QString &file); + QStringList readFile(const QString &filePath); + +private: + + int m_pid; + int m_ppid; + bool m_hasPid; + bool m_isValid; + + Status m_status; + QString m_exe; + QString m_cwd; + QStringList m_args; + QStringList m_cmdLine; + QVector m_uids; + QMap m_environ; +}; + +#endif // PROCESSINFO_H diff --git a/frame/taskmanager/taskmanager.cpp b/frame/taskmanager/taskmanager.cpp new file mode 100644 index 000000000..e15cb75b3 --- /dev/null +++ b/frame/taskmanager/taskmanager.cpp @@ -0,0 +1,1588 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "entry.h" +#include "common.h" +#include "appinfo.h" +#include "xcbutils.h" +#include "constants.h" +#include "x11manager.h" +#include "taskmanager.h" +#include "windowinfok.h" +#include "dbushandler.h" +#include "windowinfomap.h" +#include "windowidentify.h" +#include "waylandmanager.h" +#include "windowinfobase.h" + +#include "org_deepin_dde_kwayland_plasmawindow.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define SETTING DockSettings::instance() +#define XCB XCBUtils::instance() +bool shouldShowEntry(Entry *entry) +{ + auto appInfo = entry->getAppInfo(); + if (appInfo && appInfo->isValidApp()) { + QString path = entry->getAppInfo()->getFileName(); + DesktopInfo desktopInfo(path); + return desktopInfo.shouldShow(); + } + return false; +} + +TaskManager::TaskManager(QObject *parent) + : m_showRecent(DockSettings::instance()->showRecent()) + , m_entriesSum(0) + , m_hideState(HideState::Unknown) + , m_entries(new Entries(this)) + , m_windowIdentify(new WindowIdentify(this)) + , m_dbusHandler(new DBusHandler(this)) + , m_activeWindow(nullptr) + , m_activeWindowOld(nullptr) +{ + qRegisterMetaType("WindowInfoMap"); + qRegisterMetaType("uint32_t"); + if (isWaylandSession()) { + m_isWayland = true; + m_waylandManager = new WaylandManager(this); + m_dbusHandler->listenWaylandWMSignals(); + } else if (isX11Session()) { + m_isWayland = false; + m_x11Manager = new X11Manager(this); + } else { + qFatal("Unknown XDG_SESSION_TYPE '%s'", sessionType().constData()); + } + + initSettings(); + initEntries(); + + // 初始化智能隐藏定时器 + m_smartHideTimer = new QTimer(this); + m_smartHideTimer->setSingleShot(true); + connect(m_smartHideTimer, &QTimer::timeout, this, &TaskManager::smartHideModeTimerExpired); + + if (!m_isWayland) { + std::thread thread([&] { + // Xlib方式 + m_x11Manager->listenXEventUseXlib(); + // XCB方式 + //listenXEventUseXCB(); + }); + thread.detach(); + m_x11Manager->listenRootWindowXEvent(); + connect(m_x11Manager, &X11Manager::requestUpdateHideState, this, &TaskManager::updateHideState); + connect(m_x11Manager, &X11Manager::requestHandleActiveWindowChange, this, &TaskManager::handleActiveWindowChanged); + connect(m_x11Manager, &X11Manager::requestAttachOrDetachWindow, this, &TaskManager::attachOrDetachWindow); + } +} + +TaskManager::~TaskManager() +{ + +} + +/** + * @brief TaskManager::dockEntry 驻留应用 + * @param entry 应用实例 + * @return + */ +bool TaskManager::dockEntry(Entry *entry, bool moveToEnd) +{ + if (entry->getIsDocked()) + return false; + + AppInfo *appInfo = entry->getAppInfo(); + auto needScratchDesktop = [&]{ + if (!appInfo) { + qInfo() << "needScratchDesktop: yes, appInfo is nil"; + return true; + } + + if (appInfo->isInstalled()) { + qInfo() << "needScratchDesktop: no, desktop is installed"; + return false; + } + + if (appInfo->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 (appInfo) { + QString newFile = scratchDir + appInfo->getInnerId() + ".desktop"; + // 在目标文件存在的情况下,先删除,防止出现驻留不成功的情况 + if (QFile::exists(newFile)) QFile::remove(newFile); + if (file.copy(appInfo->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 cmd = entry->getCmdLine() + "%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; + + appInfo = new AppInfo(newDesktopFile); + entry->setAppInfo(appInfo); + entry->updateIcon(); + entry->setInnerId(appInfo->getInnerId()); + } + + // 如果是最近打开应用,通过右键菜单的方式驻留,且当前是时尚模式,那么就让entry驻留到末尾 + if (moveToEnd && SETTING->getDisplayMode() == DisplayMode::Fashion) + m_entries->moveEntryToLast(entry); + + entry->setIsDocked(true); + entry->updateMenu(); + entry->updateMode(); + return true; +} + +/** + * @brief TaskManager::undockEntry 取消驻留 + * @param entry 应用实例 + */ +void TaskManager::undockEntry(Entry *entry, bool moveToEnd) +{ + if (!entry->getIsDocked()) { + qInfo() << "undockEntry: " << entry->getId() << " is not docked"; + // 当应用图标在最近打开区域的时候,此时该应用是未驻留的应用,如果该最近打开应用没有打开窗口,将这个图标 + // 拖动到回收站了,此时调用的是undock方法,根据需求,需要将该图标删除 + if (!entry->hasWindow()) { + // 没有子窗口的情况下,从列表中移除 + removeAppEntry(entry); + saveDockedApps(); + } + return; + } + + if (!entry->getAppInfo()) { + qInfo() << "undockEntry: entry appInfo is nullptr"; + return; + } + + // 移除scratchDir目录下相关文件 + QString desktopFile = entry->getFileName(); + QString filebase(desktopFile.data(), desktopFile.size() - 9); + if (desktopFile.contains(scratchDir)) { + QStringList suffixs {".desktop", ".sh", ".png"}; + for (auto &ext : suffixs) { + QFile file(filebase + ext); + if (file.exists()) file.remove(); + } + } + + if (entry->hasWindow()) { + // 移除驻留后,如果当前应用存在子窗口,那么会将移除最近使用应用中最后一个没有子窗口的窗口 + m_entries->removeLastRecent(); + if (desktopFile.contains(scratchDir) && entry->getCurrentWindowInfo()) { + QFileInfo info(desktopFile); + QString baseName = info.completeBaseName(); + if (baseName.startsWith(windowHashPrefix)) { + // desktop base starts with w: + // 由于有 Pid 识别方法在,在这里不能用 m.identifyWindow 再次识别 + entry->setInnerId(entry->getCurrentWindowInfo()->getInnerId()); + entry->setAppInfo(nullptr); // 此处设置Entry的app为空, 在Entry中调用app相关信息前判断指针是否为空 + } else { + // desktop base starts with d: + QString innerId; + AppInfo *app = m_windowIdentify->identifyWindow(entry->getCurrentWindowInfo(), innerId); + // TODO update entry's innerId + entry->setAppInfo(app); + entry->setInnerId(innerId); + } + } + // 如果存在窗口,在时尚模式下,就会移动到最近打开区域,此时让它移动到最后 + if (moveToEnd && SETTING->getDisplayMode() == DisplayMode::Fashion) + m_entries->moveEntryToLast(entry); + + entry->updateIcon(); + entry->setIsDocked(false); + entry->updateName(); + entry->updateMenu(); + // 更新模式, 是在应用区域还是在最近打开区域 + entry->updateMode(); + } else { + // 直接移除 + removeAppEntry(entry); + } + + saveDockedApps(); +} + +/** + * @brief TaskManager::allocEntryId 分配应用实例id + * @return + */ +QString TaskManager::allocEntryId() +{ + return QString("e%1T%2").arg(++m_entriesSum).arg(QString::number(QDateTime::currentSecsSinceEpoch(), 16)); +} + +/** + * @brief TaskManager::shouldShowOnDock 判断是否应该显示到任务栏 + * @param info + * @return + */ +bool TaskManager::shouldShowOnDock(WindowInfoBase *info) +{ + if (info->getWindowType() == "X11") { + XWindow winId = info->getXid(); + bool isReg = m_x11Manager->findWindowByXid(winId); + bool isContainedInClientList = m_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; +} + +/** + * @brief TaskManager::getWMName 获取窗管名称 + * @return + */ +QString TaskManager::getWMName() +{ + return m_wmName; +} + +/** + * @brief TaskManager::setWMName 设置窗管名称 + * @param name 窗管名称 + */ +void TaskManager::setWMName(QString name) +{ + m_wmName = name; +} + +/** + * @brief TaskManager::createPlasmaWindow 创建wayland下窗口 + * @param objPath + * @return + */ +PlasmaWindow *TaskManager::createPlasmaWindow(QString objPath) +{ + return m_dbusHandler->createPlasmaWindow(objPath); +} + +/** + * @brief TaskManager::listenKWindowSignals + * @param windowInfo + */ +void TaskManager::listenKWindowSignals(WindowInfoK *windowInfo) +{ + m_dbusHandler->listenKWindowSignals(windowInfo); +} + +/** + * @brief TaskManager::removePlasmaWindowHandler 关闭窗口后需求对应的connect + * @param window + */ +void TaskManager::removePlasmaWindowHandler(PlasmaWindow *window) +{ + m_dbusHandler->removePlasmaWindowHandler(window); +} + +/** + * @brief TaskManager::presentWindows 显示窗口 + * @param windows 窗口id + */ +void TaskManager::presentWindows(QList windows) +{ + m_dbusHandler->presentWindows(windows); +} + +/** + * @brief TaskManager::getDockHideMode 获取任务栏隐藏模式 一直显示/一直隐藏/智能隐藏 + * @return + */ +HideMode TaskManager::getDockHideMode() +{ + return SETTING->getHideMode(); +} + +/** + * @brief TaskManager::isActiveWindow 判断是否为活动窗口 + * @param win + * @return + */ +bool TaskManager::isActiveWindow(const WindowInfoBase *win) +{ + if (!win) + return false; + + return win == getActiveWindow(); +} + +/** + * @brief TaskManager::getActiveWindow 获取当前活跃窗口 + * @return + */ +WindowInfoBase *TaskManager::getActiveWindow() +{ + if (!m_activeWindow) + return m_activeWindowOld; + + return m_activeWindow; + +} + +void TaskManager::doActiveWindow(XWindow xid) +{ + // 修改当前工作区为指定窗口的工作区 + XWindow winWorkspace = XCB->getWMDesktop(xid); + XWindow currentWorkspace = XCB->getCurrentWMDesktop(); + if (winWorkspace != currentWorkspace) { + qInfo() << "doActiveWindow: change currentWorkspace " << currentWorkspace << " to winWorkspace " << winWorkspace; + + // 获取窗口时间 + uint32_t timestamp = XCB->getWMUserTime(xid); + // 修改当前桌面工作区 + XCB->changeCurrentDesktop(winWorkspace, timestamp); + } + + XCB->changeActiveWindow(xid); + QTimer::singleShot(50, [&] { + XCB->restackWindow(xid); + }); +} + +/** + * @brief TaskManager::getClientList 获取窗口client列表 + * @return + */ +QList TaskManager::getClientList() +{ + return QList(m_clientList); +} + +/** + * @brief TaskManager::setClientList 设置窗口client列表 + */ +void TaskManager::setClientList(QList value) +{ + m_clientList = value; +} + +/** + * @brief TaskManager::closeWindow 关闭窗口 + * @param windowId 窗口id + */ +void TaskManager::closeWindow(uint32_t windowId) +{ + qInfo() << "Close Window " << windowId; + if (m_isWayland) { + WindowInfoK *info = m_waylandManager->findWindowByXid(windowId); + if (info) + info->close(0); + } else { + XCB->requestCloseWindow(windowId, 0); + } +} + +/** + * @brief TaskManager::MinimizeWindow 最小化窗口 + * @param windowId 窗口id + */ +void TaskManager::MinimizeWindow(XWindow windowId) +{ + qInfo() << "Minimize Window " << windowId; + if (m_isWayland) { + WindowInfoK *info = m_waylandManager->findWindowByXid(windowId); + if (info) + info->minimize(); + } else { + XCB->minimizeWindow(windowId); + } +} + +/** + * @brief TaskManager::getEntryIDs 获取所有应用Id + * @return + */ +QStringList TaskManager::getEntryIDs() +{ + return m_entries->getEntryIDs(); +} + +/** + * @brief TaskManager::setFrontendWindowRect 设置任务栏Rect + * @param x + * @param y + * @param width + * @param height + */ +void TaskManager::setFrontendWindowRect(int32_t x, int32_t y, uint width, uint height) +{ + if (m_frontendWindowRect == QRect(x, y, width, height)) { + qInfo() << "SetFrontendWindowRect: no changed"; + return; + } + + m_frontendWindowRect.setX(x); + m_frontendWindowRect.setY(y); + m_frontendWindowRect.setWidth(width); + m_frontendWindowRect.setHeight(height); + updateHideState(false); + + Q_EMIT frontendWindowRectChanged(m_frontendWindowRect); +} + +/** + * @brief TaskManager::isDocked 应用是否驻留 + * @param desktopFile + * @return + */ +bool TaskManager::isDocked(const QString desktopFile) +{ + auto entry = getDockedEntryByDesktopFile(desktopFile); + return !!entry; +} + +/** + * @brief TaskManager::requestDock 驻留应用 + * @param desktopFile desktopFile全路径 + * @param index + * @return + */ +bool TaskManager::requestDock(QString desktopFile, int index) +{ + qInfo() << "RequestDock: " << desktopFile; + AppInfo *app = new AppInfo(desktopFile); + if (!app || !app->isValidApp()) { + qInfo() << "RequestDock: invalid desktopFile"; + return false; + } + + Entry *entry = m_entries->getByInnerId(app->getInnerId()); + if (!entry) + entry = new Entry(this, app, app->getInnerId()); + + if (!dockEntry(entry)) + return false; + + m_entries->insert(entry, index); + + saveDockedApps(); + return true; +} + +/** + * @brief TaskManager::requestUndock 取消驻留应用 + * @param desktopFile desktopFile文件全路径 + * @return + */ +bool TaskManager::requestUndock(QString desktopFile) +{ + auto entry = getDockedEntryByDesktopFile(desktopFile); + if (!entry) + return false; + + undockEntry(entry); + return true; +} + +/** + * @brief TaskManager::moveEntry 移动驻留程序顺序 + * @param oldIndex + * @param newIndex + */ +void TaskManager::moveEntry(int oldIndex, int newIndex) +{ + m_entries->move(oldIndex, newIndex); + saveDockedApps(); +} + +/** + * @brief TaskManager::isOnDock 是否在任务栏 + * @param desktopFile desktopFile文件全路径 + * @return + */ +bool TaskManager::isOnDock(QString desktopFile) +{ + return m_entries->getByDesktopFilePath(desktopFile); +} + +/** + * @brief TaskManager::queryWindowIdentifyMethod 查询窗口识别方式 + * @param windowId 窗口id + * @return + */ +QString TaskManager::queryWindowIdentifyMethod(XWindow windowId) +{ + return m_entries->queryWindowIdentifyMethod(windowId); +} + +/** + * @brief TaskManager::getDockedAppsDesktopFiles 获取驻留应用desktop文件 + * @return + */ +QStringList TaskManager::getDockedAppsDesktopFiles() +{ + QStringList ret; + for (auto entry: m_entries->filterDockedEntries()) { + ret << entry->getFileName(); + } + + return ret; +} + +void TaskManager::setShowMultiWindow(bool visible) +{ + if (m_showMultiWindow == visible) + return; + + SETTING->setShowMultiWindow(visible); + onShowMultiWindowChanged(visible); +} + +/** + * @brief TaskManager::getPluginSettings 获取任务栏插件配置 + * @return + */ +QString TaskManager::getPluginSettings() +{ + return SETTING->getPluginSettings(); +} + +/** + * @brief TaskManager::setPluginSettings 设置任务栏插件配置 + * @param jsonStr + */ +void TaskManager::setPluginSettings(QString jsonStr) +{ + SETTING->setPluginSettings(jsonStr); +} + +/** + * @brief TaskManager::mergePluginSettings 合并任务栏插件配置 + * @param jsonStr + */ +void TaskManager::mergePluginSettings(QString jsonStr) +{ + SETTING->mergePluginSettings(jsonStr); +} + +/** + * @brief TaskManager::removePluginSettings 移除任务栏插件配置 + * @param pluginName + * @param settingkeys + */ +void TaskManager::removePluginSettings(QString pluginName, QStringList settingkeys) +{ + SETTING->removePluginSettings(pluginName, settingkeys); +} + +/** + * @brief TaskManager::smartHideModeTimerExpired 设置智能隐藏 + */ +void TaskManager::smartHideModeTimerExpired() +{ + HideState state = shouldHideOnSmartHideMode() ? HideState::Hide : HideState::Show; + qInfo() << "smartHideModeTimerExpired, should hide ? " << int(state); + setPropHideState(state); +} + +/** + * @brief TaskManager::initSettings 初始化配置 + */ +void TaskManager::initSettings() +{ + qInfo() << "init dock settings"; + m_forceQuitAppStatus = SETTING->getForceQuitAppMode(); + connect(SETTING, &DockSettings::hideModeChanged, this, [ 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, [](Position mode) { + qInfo() << "position mode change to " << static_cast(mode); + }); + connect(SETTING, &DockSettings::forceQuitAppChanged, this, [ this ](ForceQuitAppMode mode) { + qInfo() << "forceQuitApp change to " << int(mode); + m_forceQuitAppStatus = mode; + m_entries->updateEntriesMenu(); + }); + connect(SETTING, &DockSettings::showRecentChanged, this, &TaskManager::onShowRecentChanged); + connect(SETTING, &DockSettings::showMultiWindowChanged, this, &TaskManager::onShowMultiWindowChanged); +} + +/** + * @brief TaskManager::initEntries 初始化应用 + */ +void TaskManager::initEntries() +{ + loadAppInfos(); + initClientList(); +} + +/** + * @brief TaskManager::loadAppInfos 加载本地驻留和最近使用的应用信息 + */ +void TaskManager::loadAppInfos() +{ + // 初始化驻留应用信息和最近使用的应用的信息 + auto loadApps = [ this ](const QStringList &apps, bool isDocked) { + for (const QString &app : apps) { + QString path = app; + DesktopInfo info(path); + if (!info.isValidDesktop()) + continue; + + AppInfo *appInfo = new AppInfo(info); + Entry *entryObj = new Entry(this, appInfo, appInfo->getInnerId()); + entryObj->setIsDocked(isDocked); + entryObj->updateMode(); + entryObj->updateMenu(); + m_entries->append(entryObj); + } + }; + + loadApps(SETTING->getDockedApps(), true); + QStringList recentApps = SETTING->getRecentApps(); + if (recentApps.size() > MAX_UNOPEN_RECENT_COUNT) { + QStringList tempApps = recentApps; + recentApps.clear(); + for (int i = 0; i < MAX_UNOPEN_RECENT_COUNT; i++) + recentApps << tempApps[i]; + } + loadApps(recentApps, false); + saveDockedApps(); +} + +/** + * @brief TaskManager::initClientList 初始化窗口列表,关联到对应应用 + */ +void TaskManager::initClientList() +{ + if (m_isWayland) { + m_dbusHandler->loadClientList(); + } else { + QList clients; + for (auto c : XCB->instance()->getClientList()) + clients.push_back(c); + + // 依次注册窗口 + std::sort(clients.begin(), clients.end()); + m_clientList = clients; + for (auto winId : m_clientList) { + WindowInfoX *winInfo = m_x11Manager->registerWindow(winId); + attachOrDetachWindow(static_cast(winInfo)); + } + } +} + +/** + * @brief TaskManager::findWindowByXidX 通过id获取窗口信息 + * @param xid + * @return + */ +WindowInfoX *TaskManager::findWindowByXidX(XWindow xid) +{ + return m_x11Manager->findWindowByXid(xid); +} + +/** + * @brief TaskManager::findWindowByXidK 通过xid获取窗口 TODO wayland和x11下窗口尽量完全剥离, 不应该存在通过xid查询wayland窗口的情况 + * @param xid + * @return + */ +WindowInfoK *TaskManager::findWindowByXidK(XWindow xid) +{ + return m_waylandManager->findWindowByXid(xid); +} + +/** + * @brief TaskManager::isWindowDockOverlapX 判断X环境下窗口和任务栏是否重叠 + * @param xid + * @return + * 计算重叠条件: + * 1 窗口类型非桌面desktop + * 2 窗口透明度非0 + * 3 窗口显示在当前工作区域 + * 4 窗口和任务栏rect存在重叠区域 + */ +bool TaskManager::isWindowDockOverlapX(XWindow xid) +{ + // 检查窗口类型 + auto desktopType = XCB->getAtom("_NET_WM_WINDOW_TYPE_DESKTOP"); + for (auto ty : XCB->getWMWindoType(xid)) { + if (ty == desktopType) { + // 不处理桌面窗口属性 + return false; + } + } + + // TODO 检查窗口透明度 + // 检查窗口是否显示 + auto wmHiddenType = XCB->getAtom("_NET_WM_STATE_HIDDEN"); + for (auto ty : XCB->getWMState(xid)) { + if (ty == wmHiddenType) { + // 不处理隐藏的窗口属性 + return false; + } + } + + // 检查窗口是否在当前工作区 + uint32_t wmDesktop = XCB->getWMDesktop(xid); + uint32_t currentDesktop = XCB->getCurrentWMDesktop(); + if (wmDesktop != currentDesktop) { + qInfo() << "isWindowDockOverlapX: wmDesktop:" << wmDesktop << " is not equal to currentDesktop:" << currentDesktop; + return false; + } + + // 检查窗口和任务栏窗口是否存在重叠 + auto winRect = XCB->getWindowGeometry(xid); + return hasInterSectionX(winRect, m_frontendWindowRect); +} + +/** + * @brief TaskManager::hasInterSectionX 检查窗口重叠区域 + * @param windowRect 活动窗口 + * @param dockRect 任务栏窗口 + * @return + */ +bool TaskManager::hasInterSectionX(const Geometry &windowRect, QRect dockRect) +{ + int ltX = std::max(int(windowRect.x), dockRect.x()); + int ltY = std::max(int(windowRect.y), dockRect.y()); + int rbX = std::min(windowRect.x + windowRect.width, dockRect.x() + dockRect.width()); + int rbY = std::min(windowRect.y + windowRect.height, dockRect.y() + dockRect.height()); + + return (ltX < rbX) && (ltY < rbY); +} + +/** + * @brief TaskManager::isWindowDockOverlapK 判断Wayland环境下窗口和任务栏是否重叠 + * @param info + * @return + */ +bool TaskManager::isWindowDockOverlapK(WindowInfoBase *info) +{ + WindowInfoK *infoK = static_cast(info); + if (!infoK) { + qInfo() << "isWindowDockOverlapK: infoK is nullptr"; + return false; + } + + DockRect rect = infoK->getGeometry(); + bool isActiveWin = infoK->getPlasmaWindow()->IsActive(); + QString appId = infoK->getAppId(); + if (!isActiveWin) { + qInfo() << "isWindowDockOverlapK: check window " << appId << " is not active"; + return false; + } + + QStringList appList = {"dde-desktop", "dde-lock", "dde-shutdown"}; + if (appList.contains(appId)) { + qInfo() << "isWindowDockOverlapK: appId in white list"; + return false; + } + + return hasInterSectionK(rect, m_frontendWindowRect); +} + +/** + * @brief TaskManager::hasInterSectionK Wayland环境下判断活动窗口和任务栏区域是否重叠 + * @param windowRect 活动窗口 + * @param dockRect 任务栏窗口 + * @return + */ +bool TaskManager::hasInterSectionK(const DockRect &windowRect, QRect dockRect) +{ + int position = getPosition(); + int ltX = std::max(windowRect.x, dockRect.x()); + int ltY = std::max(windowRect.y, dockRect.y()); + int rbX = std::min(int(windowRect.x + windowRect.w), dockRect.x() + dockRect.width()); + int rbY = std::min(int(windowRect.y + windowRect.h), dockRect.y() + dockRect.height()); + + if (position == int(Position::Left) || position == int(Position::Right)) + return ltX <= rbX && ltY < rbY; + + if (position == int(Position::Top) || position == int(Position::Bottom)) + return ltX < rbX && ltY <= rbY; + + return ltX < rbX && ltY < rbY; +} + +/** + * @brief TaskManager::getDockedEntryByDesktopFile 获取应用实例 + * @param desktopFile desktopFile文件全路径 + * @return + */ +Entry *TaskManager::getDockedEntryByDesktopFile(const QString &desktopFile) +{ + return m_entries->getDockedEntryByDesktopFile(desktopFile); +} + +/** + * @brief TaskManager::shouldHideOnSmartHideMode 判断智能隐藏模式下当前任务栏是否应该隐藏 + * @return + */ +bool TaskManager::shouldHideOnSmartHideMode() +{ + if (!m_activeWindow) + return false; + + if (!m_isWayland) { + XWindow activeWinId = m_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)) { + qInfo() << "shouldHideOnSmartHideMode: window has overlap"; + return true; + } + } + return false; + } + + return isWindowDockOverlapK(m_activeWindow); +} + +/** + * @brief TaskManager::getActiveWinGroup + * @param xid + * @return + */ +QVector TaskManager::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; +} + +/** + * @brief TaskManager::updateHideState 更新任务栏隐藏状态 + * @param delay + */ +void TaskManager::updateHideState(bool delay) +{ + HideMode mode = SETTING->getHideMode(); + switch (mode) { + case HideMode::KeepShowing: + setPropHideState(HideState::Show); + break; + case HideMode::KeepHidden: + setPropHideState(HideState::Hide); + break; + case HideMode::SmartHide: + qInfo() << "reset smart hide mode timer " << delay; + m_smartHideTimer->start(delay ? smartHideTimerDelay : 0); + break; + } +} + +/** + * @brief TaskManager::setPropHideMode 设置隐藏属性 + * @param state + */ +void TaskManager::setPropHideState(HideState state) +{ + if (state == HideState::Unknown) { + qInfo() << "setPropHideState: unknown mode"; + return; + } + + if (state != m_hideState) { + qDebug() << "current hide state: " << m_hideState; + m_hideState = state; + Q_EMIT hideStateChanged(static_cast(m_hideState)); + } +} + +/** + * @brief TaskManager::attachOrDetachWindow 关联或分离窗口 + * @param info + */ +void TaskManager::attachOrDetachWindow(WindowInfoBase *info) +{ + if (!info) + return; + + XWindow winId = info->getXid(); + bool shouldDock = shouldShowOnDock(info); + qInfo() << "attachOrDetachWindow: shouldDock " << shouldDock; + + // 顺序解析窗口合并或分离操作 + 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为空表示未识别,需要识别窗口并创建entryInnerId + qInfo() << "attach operate: window " << winId << " entryInnerId is empty, now call IdentifyWindow"; + QString innerId; + AppInfo *appInfo = m_windowIdentify->identifyWindow(info, innerId); + // 窗口entryInnerId即AppInfo的innerId, 用来将窗口和应用绑定关系 + info->setEntryInnerId(innerId); + info->setAppInfo(appInfo); + markAppLaunched(appInfo); + } else { + qInfo() << "attach operate: window " << winId << "has been identified"; + } + + // winInfo初始化后影响判断是否在任务栏显示图标,需判断 + if (shouldShowOnDock(info)) + attachWindow(info); + } + + // 在新增窗口后,同步最近打开应用到com.deepin.dde.dock.json的DConfig配置文件中 + updateRecentApps(); +} + +/** + * @brief TaskManager::attachWindow 关联窗口 + * @param info 窗口信息 + */ +void TaskManager::attachWindow(WindowInfoBase *info) +{ + // TODO: entries中存在innerid为空的entry, 导致后续新应用通过innerid获取应用一直能获取到 + Entry *entry = m_entries->getByInnerId(info->getEntryInnerId()); + if (entry) { + // entry existed + entry->attachWindow(info); + } else { + m_entries->removeLastRecent(); + entry = new Entry(this, info->getAppInfo(), info->getEntryInnerId()); + if (entry->attachWindow(info)) { + m_entries->append(entry); + } + } +} + +/** + * @brief TaskManager::detachWindow 分离窗口 + * @param info 窗口信息 + */ +void TaskManager::detachWindow(WindowInfoBase *info) +{ + Entry *entry = m_entries->getByWindowId(info->getXid()); + if (!entry) + return; + + if (entry->detachWindow(info)) + removeEntryFromDock(entry); +} + +/** + * @brief TaskManager::launchApp 启动应用 + * @param timestamp 时间 + * @param files 应用打开文件 + */ +void TaskManager::launchApp(const QString desktopFile, uint32_t timestamp, QStringList files) +{ + m_dbusHandler->launchApp(desktopFile, timestamp, files); +} + +/** + * @brief TaskManager::launchAppAction 启动应用响应 + * @param timestamp + * @param file + * @param section + */ +void TaskManager::launchAppAction(const QString desktopFile, QString action, uint32_t timestamp) +{ + m_dbusHandler->launchAppAction(desktopFile, action, timestamp); +} + +/** + * @brief TaskManager::is3DWM 当前窗口模式 2D/3D + * @return + */ +bool TaskManager::is3DWM() +{ + bool ret = false; + if (m_wmName.isEmpty()) + m_wmName = m_dbusHandler->getCurrentWM(); + + if (m_wmName == "deepin wm") + ret = true; + + return ret; +} + +/** + * @brief TaskManager::isWaylandEnv 当前环境 + * @return + */ +bool TaskManager::isWaylandEnv() +{ + return m_isWayland; +} + +/** + * @brief TaskManager::handleActiveWindowChangedK 处理活动窗口改变事件 wayland环境 + * @param activeWin + * @return + */ +WindowInfoK *TaskManager::handleActiveWindowChangedK(uint activeWin) +{ + return m_waylandManager->findWindowById(activeWin); +} + +/** + * @brief TaskManager::handleActiveWindowChanged 处理活动窗口改变事件 X11环境 + * @param info + */ +void TaskManager::handleActiveWindowChanged(WindowInfoBase *info) +{ + qInfo() << "handleActiveWindowChanged"; + if (!info) { + m_activeWindowOld = info; + m_activeWindow = nullptr; + return; + } + + m_activeWindow = info; + XWindow winId = m_activeWindow->getXid(); + m_entries->handleActiveWindowChanged(winId); + updateHideState(true); +} + +/** + * @brief Dock::saveDockedApps 保存驻留应用信息 + */ +void TaskManager::saveDockedApps() +{ + QStringList dockedApps; + for (auto entry : m_entries->filterDockedEntries()) { + QString path = entry->getAppInfo()->getFileName(); + dockedApps << path; + } + + SETTING->setDockedApps(dockedApps); + + // 在驻留任务栏的时候,同时更新最近打开应用的信息 + updateRecentApps(); +} + +void TaskManager::updateRecentApps() +{ + QStringList unDockedApps; + QList recentEntrys = m_entries->unDockedEntries(); + for (Entry *entry : recentEntrys) { + if (shouldShowEntry(entry)) { + unDockedApps << entry->getAppInfo()->getFileName(); + } + } + + // 保存未驻留的应用作为最近打开的应用 + SETTING->setRecentApps(unDockedApps); +} + +void TaskManager::removeEntryFromDock(Entry *entry) +{ + // 如果是最近打开应用 + if (m_entries->shouldInRecent()) { + // 更新entry的导出窗口信息 + entry->updateExportWindowInfos(); + // 更新entry的右键菜单的信息 + entry->updateMenu(); + // 更新entry的当前窗口的信息 + entry->setCurrentWindowInfo(nullptr); + updateRecentApps(); + // 如果是高效模式,则发送消息或者关闭了显示最近应用的功能,则从任务栏移除 + // 或者时尚模式显示最近应用时,当前应用不应该驻留最近应用时,需要移除 + if ((SETTING->getDisplayMode() == DisplayMode::Efficient + || !m_showRecent) && !entry->getIsDocked()) { + Q_EMIT entryRemoved(entry->getId()); + } else if (SETTING->getDisplayMode() == DisplayMode::Fashion && m_showRecent && !entry->getIsDocked()) { + if (shouldShowEntry(entry)) { + return; + } + removeAppEntry(entry); + updateRecentApps(); + } + } else { + removeAppEntry(entry); + updateRecentApps(); + } +} + +void TaskManager::onShowRecentChanged(bool visible) +{ + if (m_showRecent == visible) + return; + + m_showRecent = visible; + m_entries->updateShowRecent(); + Q_EMIT showRecentChanged(visible); +} + +void TaskManager::onShowMultiWindowChanged(bool visible) +{ + if (m_showMultiWindow == visible) + return; + + m_showMultiWindow = visible; + Q_EMIT showMultiWindowChanged(visible); +} + +/** 移除应用实例 + * @brief TaskManager::removeAppEntry + * @param entry + */ +void TaskManager::removeAppEntry(Entry *entry) +{ + if (entry) { + m_entries->remove(entry); + } +} + +/** + * @brief TaskManager::handleWindowGeometryChanged 智能隐藏模式下窗口矩形变化,同步更新任务栏隐藏状态 + */ +void TaskManager::handleWindowGeometryChanged() +{ + if (SETTING->getHideMode() == HideMode::SmartHide) + return; + + updateHideState(false); +} + +/** + * @brief TaskManager::getEntryByWindowId 根据窗口id获取应用实例 + * @param windowId + * @return + */ +Entry *TaskManager::getEntryByWindowId(XWindow windowId) +{ + return m_entries->getByWindowId(windowId); +} + +/** + * @brief TaskManager::getDesktopFromWindowByBamf 通过bamf软件服务获取指定窗口的desktop文件 + * @param windowId + * @return + */ +QString TaskManager::getDesktopFromWindowByBamf(XWindow windowId) +{ + return m_dbusHandler->getDesktopFromWindowByBamf(windowId); +} + +/** + * @brief TaskManager::registerWindowWayland 注册wayland窗口 + * @param objPath + */ +void TaskManager::registerWindowWayland(const QString &objPath) +{ + return m_waylandManager->registerWindow(objPath); +} + +/** + * @brief TaskManager::unRegisterWindowWayland 取消注册wayland窗口 + * @param objPath + */ +void TaskManager::unRegisterWindowWayland(const QString &objPath) +{ + return m_waylandManager->unRegisterWindow(objPath); +} + +/** + * @brief TaskManager::isShowingDesktop + * @return + */ +bool TaskManager::isShowingDesktop() +{ + return m_dbusHandler->wlShowingDesktop(); +} + +/** + * @brief TaskManager::identifyWindow 识别窗口 + * @param winInfo + * @param innerId + * @return + */ +AppInfo *TaskManager::identifyWindow(WindowInfoBase *winInfo, QString &innerId) +{ + return m_windowIdentify->identifyWindow(winInfo, innerId); +} + +/** + * @brief TaskManager::markAppLaunched 标识应用已启动 + * @param appInfo + */ +void TaskManager::markAppLaunched(AppInfo *appInfo) +{ + if (!appInfo || !appInfo->isValidApp()) + return; + + QString desktopFile = appInfo->getFileName(); + qInfo() << "markAppLaunched: desktopFile is " << desktopFile; +} + +/** + * @brief TaskManager::getForceQuitAppStatus 获取强制关闭应用状态 + * @return + */ +ForceQuitAppMode TaskManager::getForceQuitAppStatus() +{ + return m_forceQuitAppStatus; +} + +/** + * @brief TaskManager::getWinIconPreferredApps 获取推荐的应用窗口图标 + * @return + */ +QVector TaskManager::getWinIconPreferredApps() +{ + return SETTING->getWinIconPreferredApps(); +} + +/** + * @brief TaskManager::handleLauncherItemDeleted 处理launcher item被删除信号 + * @param itemPath + */ +void TaskManager::handleLauncherItemDeleted(QString itemPath) +{ + for (auto entry : m_entries->filterDockedEntries()) { + if (entry->getFileName() == itemPath) { + undockEntry(entry); + break; + } + } +} + +/** + * @brief TaskManager::handleLauncherItemUpdated 在收到 launcher item 更新的信号后,需要更新相关信息,包括 appInfo、innerId、名称、图标、菜单。 + * @param itemPath + */ +void TaskManager::handleLauncherItemUpdated(QString itemPath) +{ + Entry *entry = m_entries->getByDesktopFilePath(itemPath); + if (!entry) + return; + + AppInfo *app = new AppInfo(itemPath); + entry->setAppInfo(app); + entry->setInnerId(app->getInnerId()); + entry->updateName(); + entry->updateMenu(); + entry->forceUpdateIcon(); // 可能存在Icon图片改变,但Icon名称未改变的情况,因此强制发Icon的属性改变信号 +} + +/** + * @brief TaskManager::getFrontendWindowRect 获取任务栏rect + * @return + */ +QRect TaskManager::getFrontendWindowRect() +{ + return m_frontendWindowRect; +} + +/** + * @brief TaskManager::getDisplayMode 获取显示模式 + * @return + */ +DisplayMode TaskManager::getDisplayMode() +{ + return SETTING->getDisplayMode(); +} + +/** + * @brief TaskManager::setDisplayMode 设置显示模式 + * @param mode + */ +void TaskManager::setDisplayMode(int mode) +{ + DisplayMode displayMode = static_cast(mode); + SETTING->setDisplayMode(displayMode); + // m_entries->setDisplayMode(displayMode); +} + +/** + * @brief TaskManager::getDockedApps 获取驻留应用 + * @return + */ +QStringList TaskManager::getDockedApps() +{ + return SETTING->getDockedApps(); +} + +/** + * @brief TaskManager::getEntries 获取驻留应用 + * @return + */ +QList TaskManager::getEntries() +{ + QList ret; + bool showRecent = getDisplayMode() == DisplayMode::Fashion && DockSettings::instance()->showRecent(); + for (auto entry : m_entries->getEntries()) { + if (showRecent || entry->getIsDocked() || entry->hasWindow()) ret << entry; + } + return ret; +} + +/** + * @brief TaskManager::getHideMode 获取隐藏模式 + * @return + */ +HideMode TaskManager::getHideMode() +{ + return SETTING->getHideMode(); +} + +/** + * @brief TaskManager::setHideMode 设置隐藏模式 + * @param mode + */ +void TaskManager::setHideMode(HideMode mode) +{ + SETTING->setHideMode(mode); +} + +/** + * @brief TaskManager::getHideState 获取隐藏状态 + * @return + */ +HideState TaskManager::getHideState() +{ + return m_hideState; +} + +/** + * @brief TaskManager::setHideState 设置任务栏隐藏状态 + * @param state + */ +void TaskManager::setHideState(HideState state) +{ + m_hideState = state; +} + +/** + * @brief TaskManager::getHideTimeout 获取执行隐藏动作超时时间 + * @return + */ +uint TaskManager::getHideTimeout() +{ + return SETTING->getHideTimeout(); +} + +/** + * @brief TaskManager::setHideTimeout 设置执行隐藏动作超时时间 + * @param timeout + */ +void TaskManager::setHideTimeout(uint timeout) +{ + SETTING->setHideTimeout(timeout); +} + +/** + * @brief TaskManager::getIconSize 获取应用图标大小 + * @return + */ +uint TaskManager::getIconSize() +{ + return SETTING->getIconSize(); +} + +/** + * @brief TaskManager::setIconSize 设置应用图标大小 + * @param size + */ +void TaskManager::setIconSize(uint size) +{ + SETTING->setIconSize(size); +} + +/** + * @brief TaskManager::getPosition 获取当前任务栏位置 + * @return + */ +int TaskManager::getPosition() +{ + return int(SETTING->getPositionMode()); +} + +/** + * @brief TaskManager::setPosition 设置任务栏位置 + * @param position + */ +void TaskManager::setPosition(int position) +{ + SETTING->setPositionMode(Position(position)); +} + +/** + * @brief TaskManager::getShowTimeout 获取显示超时接口 + * @return + */ +uint TaskManager::getShowTimeout() +{ + return SETTING->getShowTimeout(); +} + +/** + * @brief TaskManager::setShowTimeout 设置显示超时 + * @param timeout + */ +void TaskManager::setShowTimeout(uint timeout) +{ + return SETTING->setShowTimeout(timeout); +} + +/** + * @brief TaskManager::getWindowSizeEfficient 获取任务栏高效模式大小 + * @return + */ +uint TaskManager::getWindowSizeEfficient() +{ + return SETTING->getWindowSizeEfficient(); +} + +/** + * @brief TaskManager::setWindowSizeEfficient 设置任务栏高效模式大小 + * @param size + */ +void TaskManager::setWindowSizeEfficient(uint size) +{ + SETTING->setWindowSizeEfficient(size); +} + +/** + * @brief TaskManager::getWindowSizeFashion 获取任务栏时尚模式大小 + * @return + */ +uint TaskManager::getWindowSizeFashion() +{ + return SETTING->getWindowSizeFashion(); +} + +/** + * @brief TaskManager::setWindowSizeFashion 设置任务栏时尚模式大小 + * @param size + */ +void TaskManager::setWindowSizeFashion(uint size) +{ + SETTING->setWindowSizeFashion(size); +} + +void TaskManager::previewWindow(uint xid) +{ + m_dbusHandler->previewWindow(xid); +} + +void TaskManager::cancelPreviewWindow() +{ + m_dbusHandler->cancelPreviewWindow(); +} + +bool TaskManager::showMultiWindow() const +{ + return m_showMultiWindow; +} \ No newline at end of file diff --git a/frame/taskmanager/taskmanager.h b/frame/taskmanager/taskmanager.h new file mode 100644 index 000000000..c5ba5d60c --- /dev/null +++ b/frame/taskmanager/taskmanager.h @@ -0,0 +1,191 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef DOCK_H +#define DOCK_H + +#include "docksettings.h" +#include "entries.h" +#include "org_deepin_dde_kwayland_plasmawindow.h" + +#include +#include +#include +#include + +class WindowIdentify; +class DBusHandler; +class WaylandManager; +class X11Manager; +class WindowInfoK; +class WindowInfoX; + +using PlasmaWindow = org::deepin::dde::kwayland1::PlasmaWindow; + +// 任务管理 +class TaskManager : public QObject +{ + Q_OBJECT +public: + static inline TaskManager *instance() { + static TaskManager instance; + return &instance; + } + + // 将Entry dock在任务栏上 + bool dockEntry(Entry *entry, bool moveToEnd = false); + void undockEntry(Entry *entry, bool moveToEnd = false); + + QString allocEntryId(); + bool shouldShowOnDock(WindowInfoBase *info); + void setDdeLauncherVisible(bool visible); + QString getWMName(); + void setWMName(QString name); + void setPropHideState(HideState state); + void attachWindow(WindowInfoBase *info); + void detachWindow(WindowInfoBase *info); + + void launchApp(const QString desktopFile, uint32_t timestamp, QStringList files); + void launchAppAction(const QString desktopFile, QString action, uint32_t timestamp); + + bool is3DWM(); + bool isWaylandEnv(); + WindowInfoK *handleActiveWindowChangedK(uint activeWin); + 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); + bool isShowingDesktop(); + + AppInfo *identifyWindow(WindowInfoBase *winInfo, QString &innerId); + void markAppLaunched(AppInfo *appInfo); + + ForceQuitAppMode getForceQuitAppStatus(); + QVector getWinIconPreferredApps(); + void handleLauncherItemDeleted(QString itemPath); + void handleLauncherItemUpdated(QString itemPath); + + QRect getFrontendWindowRect(); + DisplayMode getDisplayMode(); + void setDisplayMode(int mode); + QStringList getDockedApps(); + QList getEntries(); + 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); + + /******************************** dbus handler ****************************/ + PlasmaWindow *createPlasmaWindow(QString objPath); + void listenKWindowSignals(WindowInfoK *windowInfo); + void removePlasmaWindowHandler(PlasmaWindow *window); + void presentWindows(QList windows); + + HideMode getDockHideMode(); + bool isActiveWindow(const WindowInfoBase *win); + WindowInfoBase *getActiveWindow(); + void doActiveWindow(XWindow xid); + QList getClientList(); + void setClientList(QList value); + + void closeWindow(XWindow windowId); + void MinimizeWindow(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 setShowMultiWindow(bool visible); + bool showMultiWindow() const; + 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 removeEntryFromDock(Entry *entry); + + void previewWindow(uint xid); + void cancelPreviewWindow(); + +Q_SIGNALS: + void serviceRestarted(); + void entryAdded(const Entry* entry, int index); + void entryRemoved(QString id); + void hideStateChanged(int); + void frontendWindowRectChanged(const QRect &dockRect); + void showRecentChanged(bool); + void showMultiWindowChanged(bool); + +public Q_SLOTS: + void updateHideState(bool delay); + void handleActiveWindowChanged(WindowInfoBase *info); + void smartHideModeTimerExpired(); + void attachOrDetachWindow(WindowInfoBase *info); + +private: + explicit TaskManager(QObject *parent = nullptr); + ~TaskManager(); + void initSettings(); + void initEntries(); + void loadAppInfos(); + void initClientList(); + WindowInfoX *findWindowByXidX(XWindow xid); + WindowInfoK *findWindowByXidK(XWindow xid); + bool isWindowDockOverlapX(XWindow xid); + bool hasInterSectionX(const Geometry &windowRect, QRect dockRect); + bool isWindowDockOverlapK(WindowInfoBase *info); + bool hasInterSectionK(const DockRect &windowRect, QRect dockRect); + Entry *getDockedEntryByDesktopFile(const QString &desktopFile); + bool shouldHideOnSmartHideMode(); + QVector getActiveWinGroup(XWindow xid); + void updateRecentApps(); + +private: + void onShowRecentChanged(bool visible); + void onShowMultiWindowChanged(bool visible); + +private: + bool m_isWayland; // 判断是否为wayland环境 + bool m_showRecent; + bool m_showMultiWindow; + int m_entriesSum; // 累计打开的应用数量 + + QString m_wmName; // 窗管名称 + HideState m_hideState; // 记录任务栏隐藏状态 + QRect m_frontendWindowRect; // 前端任务栏大小, 用于智能隐藏时判断窗口是否重合 + ForceQuitAppMode m_forceQuitAppStatus; // 强制退出应用状态 + + Entries *m_entries; // 所有应用实例 + X11Manager *m_x11Manager; // X11窗口管理 + WaylandManager *m_waylandManager; // wayland窗口管理 + WindowIdentify *m_windowIdentify; // 窗口识别 + + QTimer *m_smartHideTimer; // 任务栏智能隐藏定时器 + DBusHandler *m_dbusHandler; // 处理dbus交互 + WindowInfoBase *m_activeWindow;// 记录当前活跃窗口信息 + WindowInfoBase *m_activeWindowOld;// 记录前一个活跃窗口信息 + + QList m_clientList; // 所有窗口 +}; + +#endif // TASKMANAGER_H diff --git a/frame/taskmanager/waylandmanager.cpp b/frame/taskmanager/waylandmanager.cpp new file mode 100644 index 000000000..d79a92db9 --- /dev/null +++ b/frame/taskmanager/waylandmanager.cpp @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "waylandmanager.h" +#include "taskmanager.h" +#include "taskmanager/entry.h" +#include "xcbutils.h" + +#define XCB XCBUtils::instance() + +WaylandManager::WaylandManager(TaskManager *_taskmanager, QObject *parent) + : QObject(parent) + , m_taskmanager(_taskmanager) + , m_mutex(QMutex(QMutex::NonRecursive)) +{ + +} + + +/** + * @brief WaylandManager::registerWindow 注册窗口 + * @param objPath + */ +void WaylandManager::registerWindow(const QString &objPath) +{ + qInfo() << "registerWindow: " << objPath; + if (findWindowByObjPath(objPath)) + return; + + PlasmaWindow *plasmaWindow = m_taskmanager->createPlasmaWindow(objPath); + if (!plasmaWindow) { + qWarning() << "registerWindowWayland: createPlasmaWindow failed"; + return; + } + + if (!plasmaWindow->IsValid() || !plasmaWindow->isValid()) { + qWarning() << "PlasmaWindow is not valid:" << objPath; + plasmaWindow->deleteLater(); + return; + } + + QString appId = plasmaWindow->AppId(); + QStringList list {"dde-dock", "dde-launcher", "dde-clipboard", "dde-osd", "dde-polkit-agent", "dde-simple-egl", "dmcs", "dde-lock"}; + if (list.indexOf(appId) >= 0 || appId.startsWith("No such object path")) { + plasmaWindow->deleteLater(); + return; + } + + XWindow winId = XCB->allocId(); // XCB中未发现释放XID接口 + XWindow realId = plasmaWindow->WindowId(); + if (realId) + winId = realId; + + WindowInfoK *winInfo = new WindowInfoK(plasmaWindow, winId); + m_taskmanager->listenKWindowSignals(winInfo); + insertWindow(objPath, winInfo); + m_taskmanager->attachOrDetachWindow(winInfo); + if (winId) { + m_windowInfoMap[winId] = winInfo; + } +} + +// 取消注册窗口 +void WaylandManager::unRegisterWindow(const QString &objPath) +{ + qInfo() << "unRegisterWindow: " << objPath; + WindowInfoK *winInfo = findWindowByObjPath(objPath); + if (!winInfo) + return; + + m_taskmanager->removePlasmaWindowHandler(winInfo->getPlasmaWindow()); + m_taskmanager->detachWindow(winInfo); + deleteWindow(objPath); +} + +WindowInfoK *WaylandManager::findWindowById(uint activeWin) +{ + QMutexLocker locker(&m_mutex); + for (auto iter = m_kWinInfos.begin(); iter != m_kWinInfos.end(); iter++) { + if (iter.value()->getInnerId() == QString::number(activeWin)) { + return iter.value(); + } + } + + return nullptr; +} + +WindowInfoK *WaylandManager::findWindowByXid(XWindow xid) +{ + WindowInfoK *winInfo = nullptr; + for (auto iter = m_kWinInfos.begin(); iter != m_kWinInfos.end(); iter++) { + if (iter.value()->getXid() == xid) { + winInfo = iter.value(); + break; + } + } + + return winInfo; +} + +WindowInfoK *WaylandManager::findWindowByObjPath(QString objPath) +{ + if (m_kWinInfos.find(objPath) == m_kWinInfos.end()) + return nullptr; + + return m_kWinInfos[objPath]; +} + +void WaylandManager::insertWindow(QString objPath, WindowInfoK *windowInfo) +{ + QMutexLocker locker(&m_mutex); + m_kWinInfos[objPath] = windowInfo; +} + +void WaylandManager::deleteWindow(QString objPath) +{ + m_kWinInfos.remove(objPath); +} diff --git a/frame/taskmanager/waylandmanager.h b/frame/taskmanager/waylandmanager.h new file mode 100644 index 000000000..e0f51e395 --- /dev/null +++ b/frame/taskmanager/waylandmanager.h @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef WAYLANDMANAGER_H +#define WAYLANDMANAGER_H + +#include "taskmanager/entry.h" +#include "windowinfok.h" + +#include +#include +#include + +class TaskManager; + +// 管理wayland窗口 +class WaylandManager : public QObject +{ + Q_OBJECT +public: + explicit WaylandManager(TaskManager *_taskmanager, QObject *parent = nullptr); + + void registerWindow(const QString &objPath); + void unRegisterWindow(const QString &objPath); + + WindowInfoK *findWindowById(uint activeWin); + WindowInfoK *findWindowByXid(XWindow xid); + WindowInfoK *findWindowByObjPath(QString objPath); + void insertWindow(QString objPath, WindowInfoK *windowInfo); + void deleteWindow(QString objPath); + +private: + TaskManager *m_taskmanager; + QMap m_kWinInfos; // dbusObjectPath -> kwayland window Info + QMap m_windowInfoMap; + QMutex m_mutex; +}; + +#endif // WAYLANDMANAGER_H diff --git a/frame/taskmanager/window_patterns.json b/frame/taskmanager/window_patterns.json new file mode 100644 index 000000000..a92675fa7 --- /dev/null +++ b/frame/taskmanager/window_patterns.json @@ -0,0 +1,246 @@ +[ + { + "ret": "id=jftp", + "rules": [ + [ + "exec", + "=:java" + ], + [ + "arg", + "c:jftp.jar" + ] + ] + }, + { + "ret": "env", + "rules": [ + [ + "wmi", + "=:dman" + ], + [ + "wmc", + "=:DManual" + ] + ] + }, + { + "ret": "env", + "rules": [ + [ + "wmi", + "r:\\.exe$" + ], + [ + "wmi", + "=!iesetup.exe" + ], + [ + "wmc", + "=:Wine" + ] + ] + }, + { + "ret": "id=netbeans", + "rules": [ + [ + "wmc", + "c:netbeans" + ], + [ + "exec", + "=:java" + ], + [ + "arg", + "c:netbeans" + ] + ] + }, + { + "ret": "id=jabref", + "rules": [ + [ + "wmc", + "c:jabref" + ], + [ + "exec", + "=:java" + ], + [ + "arg", + "c:jabref" + ] + ] + }, + { + "ret": "env", + "rules": [ + [ + "wmi", + "=:player" + ], + [ + "wmc", + "c:genymotion" + ] + ] + }, + { + "ret": "id=xdemineur", + "rules": [ + [ + "wmi", + "c:xdemineur" + ], + [ + "exec", + "=:xdemineur" + ] + ] + }, + { + "ret": "id=minecraft", + "rules": [ + [ + "wmi", + "c:minecraft" + ], + [ + "wmc", + "c:minecraft" + ] + ] + }, + { + "ret": "id=steam", + "rules": [ + [ + "hasPid", + "=:f" + ], + [ + "wmi", + "=:" + ], + [ + "wmc", + "=:" + ], + [ + "wmn", + "e:steam" + ] + ] + }, + { + "ret": "id=mintdrivers", + "rules": [ + [ + "wmi", + "e:mintdrivers.py" + ], + [ + "wmc", + "e:mintdrivers.py" + ] + ] + }, + { + "ret": "id=google-earth", + "rules": [ + [ + "wmi", + "c:googleearth" + ], + [ + "wmc", + "c:googleearth" + ] + ] + }, + { + "ret": "id=the-powder-toy", + "rules": [ + [ + "wmi", + "e:powder" + ], + [ + "wmc", + "e:powder" + ], + [ + "hasPid", + "=:t" + ] + ] + }, + { + "ret": "id=cn.google.chrome", + "rules": [ + [ + "wmi", + "e:google-chrome" + ], + [ + "wmc", + "e:google-chrome" + ] + ] + }, + { + "ret": "id=ganttproject", + "rules": [ + [ + "wmi", + "R:^sun-awt-X11" + ], + [ + "exec", + "=:java" + ], + [ + "env.CLASSPATH", + "c:ganttproject" + ], + [ + "arg", + "c:ganttproject" + ] + ] + }, + { + "ret": "id=gdevelop", + "rules": [ + [ + "wmi", + "c:gdevelop" + ], + [ + "wmc", + "c:gdevelop" + ], + [ + "exec", + "=:gdevelop" + ] + ] + }, + { + "ret": "id=apps.com.wechat.web", + "rules": [ + [ + "wmi", + "e:wx2.qq.com" + ], + [ + "wmc", + "e:google-chrome" + ] + ] + } +] diff --git a/frame/taskmanager/windowidentify.cpp b/frame/taskmanager/windowidentify.cpp new file mode 100644 index 000000000..b5477833d --- /dev/null +++ b/frame/taskmanager/windowidentify.cpp @@ -0,0 +1,531 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "windowidentify.h" +#include "common.h" +#include "appinfo.h" +#include "taskmanager.h" +#include "processinfo.h" +#include "taskmanager/desktopinfo.h" +#include "xcbutils.h" +#include "bamfdesktop.h" + +#include +#include +#include + +#define XCB XCBUtils::instance() + +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(TaskManager *_taskmanager, QObject *parent) + : QObject(parent) + , m_taskmanager(_taskmanager) +{ + m_identifyWindowFuns << qMakePair(QString("Android") , &identifyWindowAndroid); + m_identifyWindowFuns << qMakePair(QString("PidEnv"), &identifyWindowByPidEnv); + m_identifyWindowFuns << qMakePair(QString("CmdlineTurboBooster"), &identifyWindowByCmdlineTurboBooster); + m_identifyWindowFuns << qMakePair(QString("Cmdline-XWalk"), &identifyWindowByCmdlineXWalk); + m_identifyWindowFuns << qMakePair(QString("FlatpakAppID"), &identifyWindowByFlatpakAppID); + m_identifyWindowFuns << qMakePair(QString("CrxId"), &identifyWindowByCrxId); + m_identifyWindowFuns << qMakePair(QString("Rule"), &identifyWindowByRule); + m_identifyWindowFuns << qMakePair(QString("Bamf"), &identifyWindowByBamf); + m_identifyWindowFuns << qMakePair(QString("Pid"), &identifyWindowByPid); + m_identifyWindowFuns << qMakePair(QString("Scratch"), &identifyWindowByScratch); + m_identifyWindowFuns << qMakePair(QString("GtkAppId"), &identifyWindowByGtkAppId); + m_identifyWindowFuns << qMakePair(QString("WmClass"), &identifyWindowByWmClass); +} + +AppInfo *WindowIdentify::identifyWindow(WindowInfoBase *winInfo, QString &innerId) +{ + if (!winInfo) + return nullptr; + + qInfo() << "identifyWindow: window id " << winInfo->getXid() << " innerId " << winInfo->getInnerId(); + if (winInfo->getWindowType() == "X11") + return identifyWindowX11(static_cast(winInfo), innerId); + if (winInfo->getWindowType() == "Wayland") + return identifyWindowWayland(static_cast(winInfo), innerId); + + return nullptr; +} + +AppInfo *WindowIdentify::identifyWindowX11(WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *appInfo = nullptr; + if (winInfo->getInnerId().isEmpty()) { + qInfo() << "identifyWindowX11: window innerId is empty"; + return appInfo; + } + + for (auto iter = m_identifyWindowFuns.begin(); iter != m_identifyWindowFuns.end(); iter++) { + QString name = iter->first; + IdentifyFunc func = iter->second; + qInfo() << "identifyWindowX11: try " << name; + appInfo = func(m_taskmanager, 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"; + // 如果识别窗口失败,则该app的entryInnerId使用当前窗口的innerId + innerId = winInfo->getInnerId(); + return appInfo; +} + +AppInfo *WindowIdentify::identifyWindowWayland(WindowInfoK *winInfo, QString &innerId) +{ + // TODO: 对桌面调起的文管应用做规避处理,需要在此处添加,因为初始化时appId和title为空 + if (winInfo->getAppId() == "dde-desktop" && m_taskmanager->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(); + QString desktopFilePath = process->getEnv("GIO_LAUNCHED_DESKTOP_FILE"); + if ((desktopFilePath.endsWith(".desktop"))) { + appInfo = new AppInfo(desktopFilePath); + } + } + + // autoStart + if (appInfo->isValidApp()) { + AppInfo *fixedAppInfo = fixAutostartAppInfo(appInfo->getFileName()); + if (fixedAppInfo) { + delete appInfo; + appInfo = fixedAppInfo; + appInfo->setIdentifyMethod("FixAutostart"); + } + } + + if (appInfo) + innerId = appInfo->getInnerId(); + + return appInfo; +} + +AppInfo *WindowIdentify::identifyWindowAndroid(TaskManager *_taskmanager, 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); + 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(TaskManager *_taskmanager, 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) { + return ret; + } + + QString launchedDesktopFile = process->getEnv("GIO_LAUNCHED_DESKTOP_FILE"); + QString launchedDesktopFilePidStr = process->getEnv("GIO_LAUNCHED_DESKTOP_FILE_PID"); + int launchedDesktopFilePid = launchedDesktopFilePidStr.toInt(); + qInfo() << "launchedDesktopFilePid=" << launchedDesktopFilePid << " launchedDesktopFile=" << launchedDesktopFile; + + if (launchedDesktopFile.isEmpty()) { + return ret; + } + + auto pidIsSh = [](int pid) -> bool { + ProcessInfo parentProcess(pid); + auto parentCmdLine = parentProcess.getCmdLine(); + if (parentCmdLine.size() <= 0) { + return false; + } + + qInfo() << "ppid equal" << "parentCmdLine[0]:" << parentCmdLine[0]; + QString cmd0 = parentCmdLine[0]; + int pos = cmd0.lastIndexOf('/'); + if (pos > 0) + cmd0 = cmd0.remove(0, pos + 1); + + if (cmd0 == "sh" || cmd0 == "bash"){ + return true; + } + + return false; + }; + + auto processInLinglong = [](ProcessInfo* const process) -> bool { + for (ProcessInfo p(process->getPpid()); p.getPid() != 0; p = ProcessInfo(p.getPpid())) { + if (!p.getCmdLine().size()){ + qWarning() << "Failed to get command line of" << p.getPid() << " SKIP it."; + continue; + } + if (p.getCmdLine()[0].indexOf("ll-box") != -1) { + qDebug() << "process ID" << process->getPid() << "is in linglong container," + <<"ll-box PID" << p.getPid(); + return true; + } + } + return false; + }; + + // 以下几种情况下,才能信任环境变量 GIO_LAUNCHED_DESKTOP_FILE。 + if (pid == launchedDesktopFilePid || // 当窗口pid和launchedDesktopFilePid相同时 + ( process->getPpid() && + process->getPpid() == launchedDesktopFilePid && + pidIsSh(process->getPpid()) + ) || // 当窗口的进程的父进程id(即ppid)和launchedDesktopFilePid相同,并且该父进程是sh或bash时。 + processInLinglong(process) // 当窗口pid在玲珑容器中 + ) { + + ret = new AppInfo(launchedDesktopFile); + innerId = ret->getInnerId(); + } + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByCmdlineTurboBooster(TaskManager *_taskmanager, 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 (cmdline[0].startsWith(".desktop")) { + desktopFile = cmdline[0]; + } else if (QString(cmdline[0]).contains("/applications/")) { + QFileInfo fileInfo(cmdline[0]); + QString path = fileInfo.path(); + QString base = fileInfo.completeBaseName(); + 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(TaskManager *_taskmanager, 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(); + QFileInfo file(exe); + QString exeBase = file.completeBaseName(); + auto args = process->getArgs(); + if (exe != "xwalk" || args.size() == 0) + break; + + QString lastArg = args[args.size() - 1]; + file.setFile(lastArg); + if (file.completeBaseName() == "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(TaskManager *_taskmanager, 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(TaskManager *_taskmanager, 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(TaskManager *_taskmanager, WindowInfoX *winInfo, QString &innerId) +{ + static WindowPatterns patterns; + 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"); + if (!launchedDesktopFile.isEmpty()) + ret = new AppInfo(launchedDesktopFile); + } + } else { + qInfo() << "patterns match bad result"; + } + + if (ret) + innerId = ret->getInnerId(); + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByBamf(TaskManager *_taskmanager, WindowInfoX *winInfo, QString &innerId) +{ + if (_taskmanager->isWaylandEnv()) { + return nullptr; + } + + AppInfo *ret = nullptr; + XWindow xid = winInfo->getXid(); + qInfo() << "identifyWindowByBamf: windowId=" << xid; + QString desktopFile; + // 重试 bamf 识别,部分的窗口经常要多次调用才能识别到。 + for (int i = 0; i < 3; i++) { + desktopFile = _taskmanager->getDesktopFromWindowByBamf(xid); + if (!desktopFile.isEmpty()) + break; + } + + if (!desktopFile.isEmpty()) { + ret = new AppInfo(desktopFile); + innerId = ret->getInnerId(); + } + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByPid(TaskManager *_taskmanager, WindowInfoX *winInfo, QString &innerId) +{ + AppInfo *ret = nullptr; + if (winInfo->getPid() > 10) { + auto entry = _taskmanager->getEntryByWindowId(winInfo->getPid()); + if (entry) { + ret = entry->getAppInfo(); + innerId = ret->getInnerId(); + } + } + + return ret; +} + +AppInfo *WindowIdentify::identifyWindowByScratch(TaskManager *_taskmanager, 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(TaskManager *_taskmanager, 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(TaskManager *_taskmanager, WindowInfoX *winInfo, QString &innerId) +{ + WMClass wmClass = winInfo->getWMClass(); + 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 (DesktopInfo("org.deepin.flatdeb." + QString(wmClass.instanceName.c_str()).toLower()).isValidDesktop()) { + AppInfo *appInfo = new AppInfo("org.deepin.flatdeb." + QString(wmClass.instanceName.c_str()).toLower()); + innerId = appInfo->getInnerId(); + return appInfo; + } + + if (DesktopInfo(QString::fromStdString(wmClass.instanceName)).isValidDesktop()) { + AppInfo *appInfo = new AppInfo(wmClass.instanceName.c_str()); + innerId = appInfo->getInnerId(); + return appInfo; + } + } + + if (wmClass.className.size() > 0) { + QString filename = QString::fromStdString(wmClass.className); + bool isValid = DesktopInfo(filename).isValidDesktop(); + if (!isValid) { + filename = BamfDesktop::instance()->fileName(wmClass.instanceName.c_str()); + isValid = DesktopInfo(filename).isValidDesktop(); + } + + if (isValid) { + AppInfo *appInfo = new AppInfo(filename); + innerId = appInfo->getInnerId(); + return appInfo; + } + } + + return nullptr; +} + +AppInfo *WindowIdentify::fixAutostartAppInfo(QString fileName) +{ + QFileInfo file(fileName); + QString filePath = file.absolutePath(); + bool isAutoStart = false; + for (auto dir : QStandardPaths::standardLocations(QStandardPaths::ConfigLocation)) { + if (dir.contains(filePath)) { + isAutoStart = true; + break; + } + } + + return isAutoStart ? new AppInfo(file.completeBaseName()) : nullptr; +} + +int32_t WindowIdentify::getAndroidUengineId(XWindow winId) +{ + // TODO 获取AndroidUengineId + return 0; +} + +QString WindowIdentify::getAndroidUengineName(XWindow winId) +{ + // TODO 获取AndroidUengineName + return ""; +} diff --git a/frame/taskmanager/windowidentify.h b/frame/taskmanager/windowidentify.h new file mode 100644 index 000000000..aaccb01b2 --- /dev/null +++ b/frame/taskmanager/windowidentify.h @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef WINDOWIDENTIFY_H +#define WINDOWIDENTIFY_H + +#include "taskmanager/entry.h" +#include "windowpatterns.h" +#include "windowinfok.h" +#include "windowinfox.h" + +#include +#include +#include + +class AppInfo; +class TaskManager; + +typedef AppInfo *(*IdentifyFunc)(TaskManager *, WindowInfoX*, QString &innerId); + +// 应用窗口识别类 +class WindowIdentify : public QObject +{ + Q_OBJECT + +public: + explicit WindowIdentify(TaskManager *_taskmanager, QObject *parent = nullptr); + + AppInfo *identifyWindow(WindowInfoBase *winInfo, QString &innerId); + AppInfo *identifyWindowX11(WindowInfoX *winInfo, QString &innerId); + AppInfo *identifyWindowWayland(WindowInfoK *winInfo, QString &innerId); + + static AppInfo *identifyWindowAndroid(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByPidEnv(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByCmdlineTurboBooster(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByCmdlineXWalk(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByFlatpakAppID(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByCrxId(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByRule(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByBamf(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByPid(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByScratch(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByGtkAppId(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + static AppInfo *identifyWindowByWmClass(TaskManager *_dock, WindowInfoX *winInfo, QString &innerId); + +private: + AppInfo *fixAutostartAppInfo(QString fileName); + static int32_t getAndroidUengineId(XWindow winId); + static QString getAndroidUengineName(XWindow winId); + +private: + TaskManager *m_taskmanager; + QList> m_identifyWindowFuns; +}; + +#endif // IDENTIFYWINDOW_H diff --git a/frame/taskmanager/windowinfobase.h b/frame/taskmanager/windowinfobase.h new file mode 100644 index 000000000..0ea79b597 --- /dev/null +++ b/frame/taskmanager/windowinfobase.h @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef WINDOWINFOBASE_H +#define WINDOWINFOBASE_H + +#include "processinfo.h" +#include "xcbutils.h" + +#include +#include +#include +#include +#include + +class Entry; +class AppInfo; + +class WindowInfoBase : public QObject +{ + Q_OBJECT +public: + WindowInfoBase(QObject *parent = nullptr) : QObject(parent), entry(nullptr), app(nullptr), m_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; + virtual QString uuid() = 0; + virtual QString getInnerId() { return innerId; } + + XWindow getXid() {return xid;} + void setEntry(Entry *value) { entry = value; } + Entry *getEntry() { return entry; } + QString getEntryInnerId() { return entryInnerId; } + void setEntryInnerId(QString value) { entryInnerId = value; } + AppInfo *getAppInfo() { return app; } + void setAppInfo(AppInfo *value) { app = value; } + int getPid() { return pid; } + ProcessInfo *getProcess() { return m_processInfo.data(); } + bool containAtom(QVector supports, XCBAtom ty) {return supports.indexOf(ty) != -1;} + +protected: + XWindow xid; // 窗口id + QString title; // 窗口标题 + QString icon; // 窗口图标 + int pid; // 窗口所属应用进程 + QString entryInnerId; // 窗口所属应用对应的innerId + QString innerId; // 窗口对应的innerId + Entry *entry; // 窗口所属应用 + AppInfo *app; // 窗口所属应用对应的desktopFile信息 + int64_t m_createdTime; // 创建时间 + QScopedPointer m_processInfo; // 窗口所属应用的进程信息 +}; + +#endif // WINDOWINFOBASE_H diff --git a/frame/taskmanager/windowinfok.cpp b/frame/taskmanager/windowinfok.cpp new file mode 100644 index 000000000..b9932210c --- /dev/null +++ b/frame/taskmanager/windowinfok.cpp @@ -0,0 +1,210 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "windowinfok.h" +#include "entry.h" +#include "processinfo.h" +#include "appinfo.h" + +#include +#include + +WindowInfoK::WindowInfoK(PlasmaWindow *window, XWindow _xid, QObject *parent) + : WindowInfoBase (parent) + , m_updateCalled(false) + , m_internalId(0) + , m_demaningAttention(false) + , m_closeable(true) + , m_plasmaWindow(window) +{ + xid = _xid; + m_createdTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); // 获取当前时间,精确到纳秒 +} + +WindowInfoK::~WindowInfoK() +{ +} + +bool WindowInfoK::shouldSkip() +{ + if (!m_updateCalled) { + update(); + m_updateCalled = true; + } + + bool skip = m_plasmaWindow->SkipTaskbar(); + + // 添加窗口能否最小化判断, 如果窗口不能最小化则隐藏任务栏图标 + bool canMinimize = false; + canMinimize = m_plasmaWindow->IsMinimizeable(); + if (!canMinimize) + skip = true; + + if (skip) { + // 白名单, 过滤类似“欢迎应用”, 没有最小化窗口但是需要在任务栏显示图标 + QStringList list { "dde-introduction"}; + if (list.indexOf(m_appId) != -1) + skip = false; + } + + return skip; +} + +QString WindowInfoK::getIcon() +{ + return icon; +} + +QString WindowInfoK::getTitle() +{ + return title; +} + +bool WindowInfoK::isDemandingAttention() +{ + return m_demaningAttention; +} + +bool WindowInfoK::allowClose() +{ + return m_closeable; +} + +void WindowInfoK::close(uint32_t timestamp) +{ + m_plasmaWindow->RequestClose(); +} + +QString WindowInfoK::getAppId() +{ + return m_appId; +} + +void WindowInfoK::setAppId(QString _appId) +{ + m_appId = _appId; +} + +void WindowInfoK::activate() +{ + m_plasmaWindow->RequestActivate(); +} + +void WindowInfoK::minimize() +{ + m_plasmaWindow->RequestToggleMinimized(); +} + +bool WindowInfoK::isMinimized() +{ + return m_plasmaWindow->IsMinimized(); +} + +bool WindowInfoK::changeXid(XWindow _xid) +{ + xid = _xid; + return true; +} + +PlasmaWindow *WindowInfoK::getPlasmaWindow() +{ + return m_plasmaWindow.data(); +} + +bool WindowInfoK::updateGeometry() +{ + DockRect rect = m_plasmaWindow->Geometry(); + if (m_geometry == rect) + return false; + + m_geometry = rect; + return true; +} + +void WindowInfoK::updateTitle() +{ + title = m_plasmaWindow->Title(); +} + +void WindowInfoK::updateDemandingAttention() +{ + m_demaningAttention = m_plasmaWindow->IsDemandingAttention(); +} + +void WindowInfoK::updateIcon() +{ + icon = m_plasmaWindow->Icon(); +} + +void WindowInfoK::updateAppId() +{ + m_appId = m_plasmaWindow->AppId(); +} + +void WindowInfoK::updateInternalId() +{ + m_internalId = m_plasmaWindow->InternalId(); +} + +void WindowInfoK::updateCloseable() +{ + m_closeable = m_plasmaWindow->IsCloseable(); +} + +void WindowInfoK::updateProcessInfo() +{ + pid = m_plasmaWindow->Pid(); + m_processInfo.reset(new ProcessInfo(pid)); +} + +/** + * @brief WindowInfoK::getGeometry 获取窗口大小 + * @return + */ +DockRect WindowInfoK::getGeometry() +{ + return m_geometry; +} + +int64_t WindowInfoK::getCreatedTime() +{ + return m_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() +{ +} + +QString WindowInfoK::uuid() +{ + return QString(m_plasmaWindow->uuid()); +} + +QString WindowInfoK::getInnerId() +{ + return QString::number(m_internalId); +} diff --git a/frame/taskmanager/windowinfok.h b/frame/taskmanager/windowinfok.h new file mode 100644 index 000000000..398199060 --- /dev/null +++ b/frame/taskmanager/windowinfok.h @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef WINDOWINFOK_H +#define WINDOWINFOK_H + +#include "windowinfobase.h" +#include "org_deepin_dde_kwayland_plasmawindow.h" + +#include +#include +#include + +using PlasmaWindow = org::deepin::dde::kwayland1::PlasmaWindow; + +class Entry; +class ProcessInfo; + +// wayland下窗口信息 +class WindowInfoK: public WindowInfoBase +{ +public: + explicit WindowInfoK(PlasmaWindow *window, XWindow _xid = 0, QObject *parent = nullptr); + virtual ~WindowInfoK() override; + + virtual bool shouldSkip() override; + virtual QString getIcon() override; + virtual QString getTitle() override; + virtual bool isDemandingAttention() override; + virtual bool allowClose() override; + virtual void close(uint32_t timestamp) override; + virtual void activate() override; + virtual void minimize() override; + virtual bool isMinimized() override; + virtual int64_t getCreatedTime() override; + virtual QString getDisplayName() override; + virtual QString getWindowType() override; + virtual void update() override; + virtual void killClient() override; + virtual QString uuid() override; + QString getInnerId() override; + + 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(); + DockRect getGeometry(); + +private: + bool m_updateCalled; + QString m_appId; + uint32_t m_internalId; + bool m_demaningAttention; + bool m_closeable; + DockRect m_geometry; + QScopedPointer m_plasmaWindow; +}; + +#endif // WINDOWINFOK_H diff --git a/frame/taskmanager/windowinfomap.cpp b/frame/taskmanager/windowinfomap.cpp new file mode 100644 index 000000000..4f12a44a2 --- /dev/null +++ b/frame/taskmanager/windowinfomap.cpp @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "windowinfomap.h" + +QDebug operator<<(QDebug argument, const WindowInfo &info) +{ + argument << '(' << info.title << ',' << info.attention << info.uuid << ')'; + + return argument; +} + +QDBusArgument &operator<<(QDBusArgument &argument, const WindowInfo &info) +{ + argument.beginStructure(); + argument << info.title << info.attention << info.uuid; + argument.endStructure(); + + return argument; +} + +const QDBusArgument &operator>>(const QDBusArgument &argument, WindowInfo &info) +{ + argument.beginStructure(); + argument >> info.title >> info.attention >> info.uuid; + argument.endStructure(); + + return argument; +} + +bool WindowInfo::operator==(const WindowInfo &rhs) const +{ + return attention == rhs.attention && + title == rhs.title && + uuid == rhs.uuid; +} diff --git a/frame/taskmanager/windowinfomap.h b/frame/taskmanager/windowinfomap.h new file mode 100644 index 000000000..f28f6423a --- /dev/null +++ b/frame/taskmanager/windowinfomap.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef WINDOWINFOLIST_H +#define WINDOWINFOLIST_H + +#include +#include +#include + +class WindowInfo +{ +public: + friend QDebug operator<<(QDebug argument, const WindowInfo &info); + friend QDBusArgument &operator<<(QDBusArgument &argument, const WindowInfo &info); + friend const QDBusArgument &operator>>(const QDBusArgument &argument, WindowInfo &info); + + bool operator==(const WindowInfo &rhs) const; + +public: + bool attention; + QString title; + QString uuid; +}; +typedef QMap WindowInfoMap; + +#endif // WINDOWINFOLIST_H diff --git a/frame/taskmanager/windowinfox.cpp b/frame/taskmanager/windowinfox.cpp new file mode 100644 index 000000000..e29986d26 --- /dev/null +++ b/frame/taskmanager/windowinfox.cpp @@ -0,0 +1,470 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "windowinfox.h" +#include "appinfo.h" +#include "xcbutils.h" +#include "common.h" +#include "processinfo.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define XCB XCBUtils::instance() + +WindowInfoX::WindowInfoX(XWindow _xid, QObject *parent) + : WindowInfoBase (parent) + , m_x(0) + , m_y(0) + , m_width(0) + , m_height(0) + , m_hasWMTransientFor(false) + , m_hasXEmbedInfo(false) + , m_updateCalled(false) +{ + xid = _xid; + m_createdTime = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); // 获取当前时间,精确到纳秒 +} + +WindowInfoX::~WindowInfoX() +{ + +} + +bool WindowInfoX::shouldSkip() +{ + qInfo() << "window " << xid << " shouldSkip?"; + if (!m_updateCalled) { + update(); + m_updateCalled = true; + } + + if (hasWmStateSkipTaskBar() || isValidModal() || shouldSkipWithWMClass()) + return true; + + for (auto atom : m_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->changeActiveWindow(xid); + QTimer::singleShot(50, [&] { + XCB->restackWindow(xid); + }); +} + +void WindowInfoX::minimize() +{ + XCB->minimizeWindow(xid); +} + +bool WindowInfoX::isMinimized() +{ + return containAtom(m_wmState, XCB->getAtom("_NET_WM_STATE_HIDDEN")); +} + +int64_t WindowInfoX::getCreatedTime() +{ + return m_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 ((m_motifWmHints.flags & MotifHintFunctions) == 0 + || (m_motifWmHints.functions & MotifFunctionAll) != 0 + || (m_motifWmHints.functions & MotifFunctionClose) != 0) + return true; + + for (auto action : m_wmAllowedActions) { + if (action == XCB->getAtom("_NET_WM_ACTION_CLOSE")) { + return true; + } + } + + return false; +} + +QString WindowInfoX::getDisplayName() +{ + XWindow winId = xid; + //QString role = wmRole; + QString className(m_wmClass.className.c_str()); + QString instance; + if (m_wmClass.instanceName.size() > 0) { + int pos = QString(m_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 = m_wmName; + if (!_wmName.isEmpty()) { + int pos = _wmName.lastIndexOf('-'); + if (pos != -1 && !_wmName.startsWith("-")) { + _wmName.truncate(pos); + return _wmName; + } + } + + if (m_processInfo) { + QString exe {m_processInfo->getEnv("exe")}; + if (!exe.isEmpty()) + return exe; + } + + return QString("window:%1").arg(winId); +} + +void WindowInfoX::killClient() +{ + XCB->killClientChecked(xid); +} + +QString WindowInfoX::uuid() +{ + return QString(); +} + +QString WindowInfoX::getGtkAppId() +{ + return m_gtkAppId; +} + +QString WindowInfoX::getFlatpakAppId() +{ + return m_flatpakAppId; +} + +QString WindowInfoX::getWmRole() +{ + return m_wmRole; +} + +WMClass WindowInfoX::getWMClass() +{ + return m_wmClass; +} + +QString WindowInfoX::getWMName() +{ + return m_wmName; +} + +ConfigureEvent *WindowInfoX::getLastConfigureEvent() +{ + return m_lastConfigureNotifyEvent; +} + +void WindowInfoX::setLastConfigureEvent(ConfigureEvent *event) +{ + m_lastConfigureNotifyEvent = event; +} + +bool WindowInfoX::isGeometryChanged(int _x, int _y, int _width, int _height) +{ + return !(_x == m_x && _y == m_y && _width == m_width && _height == m_height); +} + +void WindowInfoX::setGtkAppId(QString _gtkAppId) +{ + m_gtkAppId = _gtkAppId; +} + +void WindowInfoX::updateMotifWmHints() +{ + // get from XCB + m_motifWmHints = XCB->getWindowMotifWMHints(xid); +} + +// XEmbed info +// 一般 tray icon 会带有 _XEMBED_INFO 属性 +void WindowInfoX::updateHasXEmbedInfo() +{ + m_hasXEmbedInfo = XCB->hasXEmbedInfo(xid); +} + +/** + * @brief WindowInfoX::genInnerId 生成innerId + * @param winInfo + * @return + */ +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(); + for (auto arg : winInfo->getProcess()->getArgs()) { + if (arg.contains("/") || arg == "." || arg == "..") { + args += "%F "; + } else { + args += arg + " "; + } + } + + 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() +{ + m_wmWindowType.clear(); + for (auto ty : XCB->getWMWindoType(xid)) { + m_wmWindowType.push_back(ty); + } +} + +// 更新窗口许可动作 +void WindowInfoX::updateWmAllowedActions() +{ + m_wmAllowedActions.clear(); + for (auto action : XCB->getWMAllowedActions(xid)) { + m_wmAllowedActions.push_back(action); + } +} + +void WindowInfoX::updateWmState() +{ + m_wmState.clear(); + for (auto a : XCB->getWMState(xid)) { + m_wmState.push_back(a); + } +} + +void WindowInfoX::updateWmClass() +{ + m_wmClass = XCB->getWMClass(xid); +} + +void WindowInfoX::updateWmName() +{ + auto name = XCB->getWMName(xid); + if (!name.empty()) + m_wmName = name.c_str(); + + title = getTitle(); +} + +void WindowInfoX::updateIcon() +{ + icon = getIconFromWindow(); +} + +void WindowInfoX::updateHasWmTransientFor() +{ + if (XCB->getWMTransientFor(xid) == 1) + m_hasWMTransientFor = true; +} + +/** + * @brief WindowInfoX::update 更新窗口信息(在识别窗口时执行一次) + */ +void WindowInfoX::update() +{ + updateWmClass(); + updateWmState(); + updateWmWindowType(); + updateWmAllowedActions(); + updateHasWmTransientFor(); + updateProcessInfo(); + updateWmName(); + innerId = genInnerId(this); +} + +QString WindowInfoX::getIconFromWindow() +{ + WMIcon icon = XCB->getWMIcon(xid); + + // invalid icon + if (icon.width == 0) { + return QString(); + } + + QImage img = QImage((uchar *)icon.data.data(), icon.width, icon.width, QImage::Format_ARGB32); + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + img.scaled(48, 48, Qt::KeepAspectRatio, Qt::SmoothTransformation); + img.save(&buffer, "PNG"); + + // convert to base64 + QString encode = buffer.data().toBase64(); + QString iconPath = QString("%1,%2").arg("data:image/png:base64").arg(encode); + buffer.close(); + + return iconPath; +} + +bool WindowInfoX::isActionMinimizeAllowed() +{ + return containAtom(m_wmAllowedActions, XCB->getAtom("_NET_WM_ACTION_MINIMIZE")); +} + +bool WindowInfoX::hasWmStateDemandsAttention() +{ + return containAtom(m_wmState, XCB->getAtom("_NET_WM_STATE_DEMANDS_ATTENTION")); +} + +bool WindowInfoX::hasWmStateSkipTaskBar() +{ + return containAtom(m_wmState, XCB->getAtom("_NET_WM_STATE_SKIP_TASKBAR")); +} + +bool WindowInfoX::hasWmStateModal() +{ + return containAtom(m_wmState, XCB->getAtom("_NET_WM_STATE_MODAL")); +} + +bool WindowInfoX::isValidModal() +{ + return hasWmStateModal() && hasWmStateModal(); +} + +// 通过WMClass判断是否需要隐藏此窗口 +bool WindowInfoX::shouldSkipWithWMClass() +{ + bool ret = false; + if (m_wmClass.instanceName == "explorer.exe" && m_wmClass.className == "Wine") + ret = true; + else if (m_wmClass.className == "dde-launcher" || + m_wmClass.className == "dde-dock" || + m_wmClass.className == "dde-lock") { + ret = true; + } + + return ret; +} + +void WindowInfoX::updateProcessInfo() +{ + XWindow winId = xid; + pid = XCB->getWMPid(winId); + qInfo() << "updateProcessInfo: pid=" << pid; + m_processInfo.reset(new ProcessInfo(pid)); + if (!m_processInfo->isValid()) { + // try WM_COMMAND + auto wmComand = XCB->getWMCommand(winId); + if (wmComand.size() > 0) { + QStringList cmds; + std::transform(wmComand.begin(), wmComand.end(), std::back_inserter(cmds), [=] (std::string cmd){ return QString::fromStdString(cmd);}); + m_processInfo.reset(new ProcessInfo(cmds)); + } + } + + qInfo() << "updateProcessInfo: pid is " << pid; +} + +bool WindowInfoX::getUpdateCalled() +{ + return m_updateCalled; +} + +void WindowInfoX::setInnerId(QString _innerId) +{ + innerId = _innerId; +} + +QString WindowInfoX::getTitle() +{ + QString name = m_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/frame/taskmanager/windowinfox.h b/frame/taskmanager/windowinfox.h new file mode 100644 index 000000000..84bb3e93d --- /dev/null +++ b/frame/taskmanager/windowinfox.h @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef WINDOWINFOX_H +#define WINDOWINFOX_H + +#include "windowinfobase.h" +#include "xcbutils.h" + +#include +#include +#include + +class AppInfo; + +// X11下窗口信息 在明确X11环境下使用 +class WindowInfoX: public WindowInfoBase +{ + Q_OBJECT +public: + WindowInfoX(XWindow _xid = 0, QObject *parent = nullptr); + virtual ~WindowInfoX() override; + + virtual bool shouldSkip() override; + virtual QString getIcon() override; + virtual QString getTitle() override; + virtual bool isDemandingAttention() override; + virtual void close(uint32_t timestamp) override; + virtual void activate() override; + virtual void minimize() override; + virtual bool isMinimized() override; + virtual int64_t getCreatedTime() override; + virtual QString getDisplayName() override; + virtual QString getWindowType() override; + virtual bool allowClose() override; + virtual void update() override; + virtual void killClient() override; + virtual QString uuid() override; + + 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(); + +private: + int16_t m_x; + int16_t m_y; + uint16_t m_width; + uint16_t m_height; + QVector m_wmState; + QVector m_wmWindowType; + QVector m_wmAllowedActions; + bool m_hasWMTransientFor; + WMClass m_wmClass; + QString m_wmName; + bool m_hasXEmbedInfo; + + // 自定义atom属性 + QString m_gtkAppId; + QString m_flatpakAppId; + QString m_wmRole; + MotifWMHints m_motifWmHints; + + bool m_updateCalled; + ConfigureEvent *m_lastConfigureNotifyEvent; +}; + +#endif // WINDOWINFOX_H diff --git a/frame/taskmanager/windowpatterns.cpp b/frame/taskmanager/windowpatterns.cpp new file mode 100644 index 000000000..82d510cdb --- /dev/null +++ b/frame/taskmanager/windowpatterns.cpp @@ -0,0 +1,299 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "windowpatterns.h" +#include "processinfo.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const int parsedFlagNegative = 0x001; +const int parsedFlagIgnoreCase = 0x010; + +const QString getWindowPatternsFile(){ + for (auto dataLocation : QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) { + QString targetFilePath = dataLocation.append("/dde-dock/window_patterns.json"); + if (QFile::exists(targetFilePath)) return targetFilePath; + } + + return QString(); +} + +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); + bool ret = ruleRegex.exactMatch(key); + + // 配置中\.exe$ 在V20中go代码可以匹配以.exe结尾的字符串, Qt中使用\.*exe$匹配以.exe结尾字符串失败,暂时做兼容处理 + if (!ret && value == "\\.exe$") { + ret = key.endsWith(".exe"); + } + return ret; +} + +bool regexMatchIgnoreCase(QString key, QString value) { + QRegExp ruleRegex(value, Qt::CaseInsensitive); + bool ret = ruleRegex.exactMatch(key); + + // 配置中\.exe$ 在V20中go代码可以匹配以.exe结尾的字符串, Qt中使用\.*exe$匹配以.exe结尾字符串失败,暂时做兼容处理 + if (!ret && value == "\\.exe$") { + QString _key = key.toLower(); + ret = _key.endsWith(".exe"); + } + return ret; +} + +RuleValueParse::RuleValueParse() + : negative(false) + , type(0) + , flags(0) +{ +} + +bool RuleValueParse::match(const WindowInfoX *winInfo) +{ + QString parsedKey = parseRuleKey(const_cast(winInfo), key); + if (!fn) + return false; + + bool ret = fn(parsedKey, value); + return negative ? !ret : ret; +} + +QString RuleValueParse::parseRuleKey(WindowInfoX *winInfo, const QString &ruleKey) +{ + ProcessInfo * process = winInfo->getProcess(); + if (ruleKey == "hasPid") { + if (process && process->initWithPid()) { + return "t"; + } + return "f"; + } else if (ruleKey == "exec") { + if (process) { + // 返回执行文件baseName + auto baseName = QFileInfo(process->getExe()).completeBaseName(); + return baseName.isEmpty() ? "" : baseName; + } + } else if (ruleKey == "arg") { + if (process) { + // 返回命令行参数 + auto ret = process->getArgs().join(""); + return ret.isEmpty() ? "" : ret; + } + } else if (ruleKey == "wmi") { + // 窗口实例 + auto wmClass = winInfo->getWMClass(); + if (!wmClass.instanceName.empty()) + return wmClass.instanceName.c_str(); + } else if (ruleKey == "wmc") { + // 窗口类型 + auto wmClass = winInfo->getWMClass(); + if (!wmClass.className.empty()) + return wmClass.className.c_str(); + } else if (ruleKey == "wmn") { + // 窗口名称 + return winInfo->getWMName(); + } else if (ruleKey == "wmrole") { + // 窗口角色 + return winInfo->getWmRole(); + } else { + const QString envPrefix = "env."; + if (ruleKey.startsWith(envPrefix)) { + QString envName = ruleKey.mid(envPrefix.size()); + if (winInfo->getProcess()) { + auto ret = process->getEnv(envName); + return ret.isEmpty() ? "" : ret; + } + } + } + + return ""; +} + + +WindowPatterns::WindowPatterns() +{ + loadWindowPatterns(); +} + +/** + * @brief WindowPatterns::match 匹配窗口类型 + * @param winInfo + * @return + */ +QString WindowPatterns::match(WindowInfoX *winInfo) +{ + for (auto pattern : m_patterns) { + bool patternOk = true; + for (auto rule : pattern.parseRules) { + if (!rule.match(winInfo)) { + patternOk = false; + break; + } + } + + if (patternOk) { + // 匹配成功 + return pattern.result; + } + } + + // 匹配失败 + return ""; +} + +void WindowPatterns::loadWindowPatterns() +{ + qInfo() << "---loadWindowPatterns"; + QFile file(getWindowPatternsFile()); + 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; + + m_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]; + } + m_patterns.push_back(pattern); + } + + // 解析patterns + for (auto &pattern : m_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 ':': + break; + 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: + break; + } + + free(orig); + return ret; +} diff --git a/frame/taskmanager/windowpatterns.h b/frame/taskmanager/windowpatterns.h new file mode 100644 index 000000000..d9d396de1 --- /dev/null +++ b/frame/taskmanager/windowpatterns.h @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef WINDOWPATTERNS_H +#define WINDOWPATTERNS_H + +#include "windowinfox.h" + +#include +#include + + +struct RuleValueParse { + RuleValueParse(); + bool match(const WindowInfoX *winInfo); + static QString parseRuleKey(WindowInfoX *winInfo, const QString &ruleKey); + 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 parseRules; + }; + +public: + WindowPatterns(); + + QString match(WindowInfoX *winInfo); + +private: + void loadWindowPatterns(); + RuleValueParse parseRule(QVector rule); + +private: + QVector m_patterns; + +}; + +#endif // WINDOWPATTERNS_H diff --git a/frame/taskmanager/x11manager.cpp b/frame/taskmanager/x11manager.cpp new file mode 100644 index 000000000..7814710cc --- /dev/null +++ b/frame/taskmanager/x11manager.cpp @@ -0,0 +1,455 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "x11manager.h" +#include "taskmanager.h" +#include "common.h" + +#include +#include + +/* + * 使用Xlib监听X Events + * 使用XCB接口与X进行交互 + * */ + +#include +#include +#include +#include +#include + +#define XCB XCBUtils::instance() + +X11Manager::X11Manager(TaskManager *_taskmanager, QObject *parent) + : QObject(parent) + , m_taskmanager(_taskmanager) + , m_mutex(QMutex(QMutex::NonRecursive)) + , m_listenXEvent(true) +{ + m_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 (m_listenXEvent) { + XEvent event; + XNextEvent (dpy, &event); + + switch (event.type) { + case DestroyNotify: { + XDestroyWindowEvent *eD = (XDestroyWindowEvent *)(&event); + // qDebug() << "DestroyNotify windowId=" << eD->window; + + handleDestroyNotifyEvent(XWindow(eD->window)); + break; + } + case MapNotify: { + XMapEvent *eM = (XMapEvent *)(&event); + // qDebug() << "MapNotify windowId=" << eM->window; + + handleMapNotifyEvent(XWindow(eM->window)); + break; + } + case ConfigureNotify: { + XConfigureEvent *eC = (XConfigureEvent *)(&event); + // qDebug() << "ConfigureNotify windowId=" << eC->window; + + handleConfigureNotifyEvent(XWindow(eC->window), eC->x, eC->y, eC->width, eC->height); + break; + } + case PropertyNotify: { + XPropertyEvent *eP = (XPropertyEvent *)(&event); + // qDebug() << "PropertyNotify windowId=" << eP->window; + + handlePropertyNotifyEvent(XWindow(eP->window), XCBAtom(eP->atom)); + break; + } + case UnmapNotify: { + // 当松开鼠标的时候会触发该事件,在松开鼠标的时候,需要检测当前窗口是否符合智能隐藏的条件,因此在此处加上该功能 + // 如果不加上该处理,那么就会出现将窗口从任务栏下方移动到屏幕中央的时候,任务栏不隐藏 + handleActiveWindowChangedX(); + break; + } + default: + qDebug() << "unused event type " << event.type; + break; + } + } + + 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); + } + */ +} + +/** + * @brief X11Manager::registerWindow 注册X11窗口 + * @param xid + * @return + */ +WindowInfoX *X11Manager::registerWindow(XWindow xid) +{ + qInfo() << "registWindow: windowId=" << xid; + WindowInfoX *ret = nullptr; + do { + if (m_windowInfoMap.find(xid) != m_windowInfoMap.end()) { + ret = m_windowInfoMap[xid]; + break; + } + + WindowInfoX *winInfo = new WindowInfoX(xid); + if (!winInfo) + break; + + listenWindowXEvent(winInfo); + m_windowInfoMap[xid] = winInfo; + ret = winInfo; + } while (0); + + return ret; +} + +// 取消注册X11窗口 +void X11Manager::unregisterWindow(XWindow xid) +{ + qInfo() << "unregisterWindow: windowId=" << xid; + if (m_windowInfoMap.find(xid) != m_windowInfoMap.end()) { + m_windowInfoMap.remove(xid); + } +} + +WindowInfoX *X11Manager::findWindowByXid(XWindow xid) +{ + WindowInfoX *ret = nullptr; + if (m_windowInfoMap.find(xid) != m_windowInfoMap.end()) + ret = m_windowInfoMap[xid]; + + return ret; +} + +void X11Manager::handleClientListChanged() +{ + QSet newClientList, oldClientList, addClientList, rmClientList; + for (auto atom : XCB->getClientList()) + newClientList.insert(atom); + + for (auto atom : m_taskmanager->getClientList()) + oldClientList.insert(atom); + + addClientList = newClientList - oldClientList; + rmClientList = oldClientList - newClientList; + m_taskmanager->setClientList(newClientList.values()); + + // 处理新增窗口 + 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) { + + if (info) { + Q_EMIT requestAttachOrDetachWindow(info); + } + } + } + + // 处理需要移除的窗口 + for (auto xid : rmClientList) { + WindowInfoX *info = m_windowInfoMap[xid]; + if (info) { + m_taskmanager->detachWindow(info); + unregisterWindow(xid); + } else { + // no window + auto entry = m_taskmanager->getEntryByWindowId(xid); + if (entry && !m_taskmanager->isDocked(entry->getFileName())) { + m_taskmanager->removeAppEntry(entry); + } + } + } +} + +void X11Manager::handleActiveWindowChangedX() +{ + XWindow active = XCB->getActiveWindow(); + WindowInfoX *info = findWindowByXid(active); + if (info) { + Q_EMIT requestHandleActiveWindowChange(info); + } +} + +void X11Manager::listenRootWindowXEvent() +{ + uint32_t eventMask = EventMask::XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY; + XCB->registerEvents(m_rootWindow, eventMask); + handleActiveWindowChangedX(); + handleClientListChanged(); +} + +/** + * @brief X11Manager::listenWindowXEvent 监听窗口事件 + * @param winInfo + */ +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 requestUpdateHideState(false); + } +} + +// destory event +void X11Manager::handleDestroyNotifyEvent(XWindow xid) +{ + WindowInfoX *winInfo = findWindowByXid(xid); + if (!winInfo) + return; + + m_taskmanager->detachWindow(winInfo); + unregisterWindow(xid); +} + +// map event +void X11Manager::handleMapNotifyEvent(XWindow xid) +{ + WindowInfoX *winInfo = registerWindow(xid); + if (!winInfo) + return; + + // TODO QTimer不能在非主线程执行,使用单独线程开发定时器处理非主线程类似定时任务 + //QTimer::singleShot(2 * 1000, this, [=] { + qInfo() << "handleMapNotifyEvent: pass 2s, now call idnetifyWindow, windowId=" << winInfo->getXid(); + QString innerId; + AppInfo *appInfo = m_taskmanager->identifyWindow(winInfo, innerId); + m_taskmanager->markAppLaunched(appInfo); + //}); +} + +// config changed event 检测窗口大小调整和重绘应用,触发智能隐藏更新 +void X11Manager::handleConfigureNotifyEvent(XWindow xid, int x, int y, int width, int height) +{ + WindowInfoX *winInfo = findWindowByXid(xid); + if (!winInfo || m_taskmanager->getDockHideMode() != HideMode::SmartHide) + return; + + WMClass wmClass = winInfo->getWMClass(); + if (wmClass.className.c_str() == frontendWindowWmClass) + return; // ignore frontend window ConfigureNotify event + + Q_EMIT requestUpdateHideState(winInfo->isGeometryChanged(x, y, width, height)); +} + +// property changed event +void X11Manager::handlePropertyNotifyEvent(XWindow xid, XCBAtom atom) +{ + if (xid == m_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 + m_taskmanager->detachWindow(winInfo); + winInfo->setInnerId(newInnerId); + needAttachOrDetach = true; + } + + if (needAttachOrDetach && winInfo) { + Q_EMIT requestAttachOrDetachWindow(winInfo); + } + + Entry *entry = m_taskmanager->getEntryByWindowId(xid); + if (!entry) + return; + + if (atom == XCB->getAtom("_NET_WM_STATE")) { + // entry->updateExportWindowInfos(); + } 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->updateExportWindowInfos(); + } 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(&m_mutex); + QTimer *timer = new QTimer(); + timer->setInterval(configureNotifyDelay); + m_windowLastConfigureEventMap[xid] = QPair(event, timer); +} + +QPair X11Manager::getWindowLastConfigureEvent(XWindow xid) +{ + QPair ret; + QMutexLocker locker(&m_mutex); + if (m_windowLastConfigureEventMap.find(xid) != m_windowLastConfigureEventMap.end()) + ret = m_windowLastConfigureEventMap[xid]; + + return ret; +} + +void X11Manager::delWindowLastConfigureEvent(XWindow xid) +{ + QMutexLocker locker(&m_mutex); + if (m_windowLastConfigureEventMap.find(xid) != m_windowLastConfigureEventMap.end()) { + QPair item = m_windowLastConfigureEventMap[xid]; + m_windowLastConfigureEventMap.remove(xid); + delete item.first; + item.second->deleteLater(); + } +} diff --git a/frame/taskmanager/x11manager.h b/frame/taskmanager/x11manager.h new file mode 100644 index 000000000..8de68f417 --- /dev/null +++ b/frame/taskmanager/x11manager.h @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef X11MANAGER_H +#define X11MANAGER_H + +#include "windowinfox.h" +#include "xcbutils.h" + +#include +#include +#include +#include + +class TaskManager; + +class X11Manager : public QObject +{ + Q_OBJECT +public: + explicit X11Manager(TaskManager *_taskmanager, 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(); + +Q_SIGNALS: + void requestUpdateHideState(bool delay); + void requestHandleActiveWindowChange(WindowInfoBase *info); + void requestAttachOrDetachWindow(WindowInfoBase *info); + +private: + void addWindowLastConfigureEvent(XWindow xid, ConfigureEvent* event); + QPair getWindowLastConfigureEvent(XWindow xid); + void delWindowLastConfigureEvent(XWindow xid); + +private: + QMap m_windowInfoMap; + TaskManager *m_taskmanager; + QMap> m_windowLastConfigureEventMap; // 手动回收ConfigureEvent和QTimer + QMutex m_mutex; + XWindow m_rootWindow; // 根窗口 + bool m_listenXEvent; // 监听X事件 +}; + +#endif // X11MANAGER_H diff --git a/frame/taskmanager/xcbutils.cpp b/frame/taskmanager/xcbutils.cpp new file mode 100644 index 000000000..b6f86ba84 --- /dev/null +++ b/frame/taskmanager/xcbutils.cpp @@ -0,0 +1,760 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "xcbutils.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +XCBUtils::XCBUtils() +{ + m_connect = xcb_connect(nullptr, &m_screenNum); // nullptr表示默认使用环境变量$DISPLAY获取屏幕 + if (xcb_connection_has_error(m_connect)) { + std::cout << "XCBUtils: init xcb_connect error" << std::endl; + return; + } + + if (!xcb_ewmh_init_atoms_replies(&m_ewmh, + xcb_ewmh_init_atoms(m_connect, &m_ewmh), // 初始化Atom + nullptr)) + std::cout << "XCBUtils: init ewmh error" << std::endl; +} + +XCBUtils::~XCBUtils() +{ + if (m_connect) { + xcb_disconnect(m_connect); // 关闭连接并释放 + m_connect = nullptr; + } +} + +XWindow XCBUtils::allocId() +{ + return xcb_generate_id(m_connect); +} + +void XCBUtils::flush() +{ + xcb_flush(m_connect); +} + +void XCBUtils::killClientChecked(XWindow xid) +{ + xcb_kill_client_checked(m_connect, xid); +} + +xcb_get_property_reply_t *XCBUtils::getPropertyValueReply(XWindow xid, XCBAtom property, XCBAtom type) +{ + xcb_get_property_cookie_t cookie = xcb_get_property(m_connect, + 0, + xid, + property, + type, + 0, + MAXLEN); + return xcb_get_property_reply(m_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, m_ewmh.UTF8_STRING); + if (reply) { + ret = getUTF8StrFromReply(reply); + free(reply); + } + return ret; +} + +XCBAtom XCBUtils::getAtom(const char *name) +{ + XCBAtom ret = m_atomCache.getVal(name); + if (ret == ATOMNONE) { + xcb_intern_atom_cookie_t cookie = xcb_intern_atom(m_connect, false, strlen(name), name); + std::shared_ptr reply(xcb_intern_atom_reply(m_connect, cookie, nullptr), [=](xcb_intern_atom_reply_t* reply){ + free(reply);} + ); + if (reply) { + m_atomCache.store(name, xcb_atom_t(reply->atom)); + ret = reply->atom; + } + } + + return ret; +} + +std::string XCBUtils::getAtomName(XCBAtom atom) +{ + std::string ret = m_atomCache.getName(atom); + if (ret.empty()) { + xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(m_connect, atom); + std::shared_ptr reply( + xcb_get_atom_name_reply(m_connect, cookie, nullptr), + [=](xcb_get_atom_name_reply_t* reply) {free(reply);}); + if (reply) { + char *name = xcb_get_atom_name_name(reply.get()); + if (name) { + m_atomCache.store(name, atom); + ret = name; + } + } + } + + return ret; +} + +Geometry XCBUtils::getWindowGeometry(XWindow xid) +{ + xcb_get_geometry_cookie_t cookie = xcb_get_geometry(m_connect, xcb_drawable_t(xid)); + std::shared_ptr reply( + xcb_get_geometry_reply(m_connect, cookie, nullptr), + [=](xcb_get_geometry_reply_t* reply){free(reply);} + ); + if (!reply) { + std::cout << xid << " getWindowGeometry err" << std::endl; + return Geometry(); + } + + Geometry ret; + ret.x = reply->x; + ret.y = reply->y; + ret.width = reply->width; + ret.height = reply->height; + + const xcb_setup_t *xcbSetup = xcb_get_setup(m_connect); + if (!xcbSetup) + return Geometry(); + + xcb_screen_iterator_t xcbScreenIterator = xcb_setup_roots_iterator(xcbSetup); + std::shared_ptr translateReply( + xcb_translate_coordinates_reply(m_connect, + xcb_translate_coordinates(m_connect, xid, xcbScreenIterator.data->root, 0, 0), + nullptr), + [=](xcb_translate_coordinates_reply_t* translateReply){free(translateReply);}); + + if (translateReply) { + ret.x = translateReply->dst_x; + ret.y = translateReply->dst_y; + } + + XWindow dWin = getDecorativeWindow(xid); + reply.reset(xcb_get_geometry_reply(m_connect, xcb_get_geometry(m_connect, xcb_drawable_t(dWin)), nullptr), + [=](xcb_get_geometry_reply_t* reply){free(reply);}); + if (!reply) + return ret; + + if (reply->x == ret.x && reply->y == ret.y) { + // 无标题的窗口,比如deepin-editor, dconf-editor等 + WindowFrameExtents windowFrameRect = getWindowFrameExtents(xid); + if (!windowFrameRect.isNull()) { + int x = ret.x + windowFrameRect.Left; + int y = ret.y + windowFrameRect.Top; + int width = ret.width - (windowFrameRect.Left + windowFrameRect.Right); + int height = ret.height - (windowFrameRect.Top + windowFrameRect.Bottom); + ret.x = x; + ret.y = y; + ret.width = width; + ret.height = height; + } + } + + return ret; +} + +XWindow XCBUtils::getDecorativeWindow(XWindow xid) +{ + XWindow winId = xid; + for (int i = 0; i < 10; i++) { + xcb_query_tree_cookie_t cookie = xcb_query_tree(m_connect, winId); + std::shared_ptr reply( + xcb_query_tree_reply(m_connect, cookie, nullptr), + [=](xcb_query_tree_reply_t* reply){free(reply);} + ); + if (!reply) return 0; + if (reply->root == reply->parent) return winId; + + winId = reply->parent; + } + + return 0; +} + +WindowFrameExtents XCBUtils::getWindowFrameExtents(XWindow xid) +{ + xcb_atom_t perp = getAtom("_NET_FRAME_EXTENTS"); + xcb_get_property_cookie_t cookie = xcb_get_property(m_connect, false, xid, perp, XCB_ATOM_CARDINAL, 0, 4); + std::shared_ptr reply( + xcb_get_property_reply(m_connect, cookie, nullptr), + [=](xcb_get_property_reply_t* reply){free(reply);} + ); + if (!reply || reply->format == 0) { + perp = getAtom("_GTK_FRAME_EXTENTS"); + cookie = xcb_get_property(m_connect, false, xid, perp, XCB_ATOM_CARDINAL, 0, 4); + reply.reset(xcb_get_property_reply(m_connect, cookie, nullptr), [=](xcb_get_property_reply_t* reply){free(reply);}); + if (!reply) + return WindowFrameExtents(); + } + + if (reply->format != 32 || reply->value_len != 4) { + return WindowFrameExtents(); + } + uint32_t *data = static_cast(xcb_get_property_value(reply.get())); + + if (!data) + return WindowFrameExtents(); + + WindowFrameExtents winFrame(data[0], data[1], data[2], data[3]); + return winFrame; +} + +XWindow XCBUtils::getActiveWindow() +{ + XWindow ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_active_window(&m_ewmh, m_screenNum); + if (!xcb_ewmh_get_active_window_reply(&m_ewmh, cookie, &ret, nullptr)) { + std::cout << "getActiveWindow error" << std::endl; + } + + return ret; +} + +void XCBUtils::setActiveWindow(XWindow xid) +{ + xcb_ewmh_set_active_window(&m_ewmh, m_screenNum, xid); +} + +void XCBUtils::changeActiveWindow(XWindow newActiveXid) +{ + xcb_ewmh_request_change_active_window(&m_ewmh, m_screenNum, newActiveXid, XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER, XCB_CURRENT_TIME, XCB_WINDOW_NONE); + flush(); +} + +void XCBUtils::restackWindow(XWindow xid) +{ + xcb_ewmh_request_restack_window(&m_ewmh, m_screenNum, xid, 0, XCB_STACK_MODE_ABOVE); +} + +std::list XCBUtils::getClientList() +{ + std::list ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_client_list(&m_ewmh, m_screenNum); + xcb_ewmh_get_windows_reply_t reply; + if (xcb_ewmh_get_client_list_reply(&m_ewmh, cookie, &reply, nullptr)) { + for (uint32_t i = 0; i < reply.windows_len; i++) { + ret.push_back(reply.windows[i]); + } + + xcb_ewmh_get_windows_reply_wipe(&reply); + } else { + std::cout << "getClientList error" << std::endl; + } + + return ret; +} + +std::list XCBUtils::getClientListStacking() +{ + std::list ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_client_list_stacking(&m_ewmh, m_screenNum); + xcb_ewmh_get_windows_reply_t reply; + if (xcb_ewmh_get_client_list_stacking_reply(&m_ewmh, cookie, &reply, nullptr)) { + for (uint32_t i = 0; i < reply.windows_len; i++) { + ret.push_back(reply.windows[i]); + } + + xcb_ewmh_get_windows_reply_wipe(&reply); + } else { + std::cout << "getClientListStacking error" << std::endl; + } + + return ret; +} + +std::vector XCBUtils::getWMState(XWindow xid) +{ + std::vector ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_state(&m_ewmh, xid); + xcb_ewmh_get_atoms_reply_t reply; // a list of Atom + if (xcb_ewmh_get_wm_state_reply(&m_ewmh, cookie, &reply, nullptr)) { + for (uint32_t i = 0; i < reply.atoms_len; i++) { + ret.push_back(reply.atoms[i]); + } + + xcb_ewmh_get_atoms_reply_wipe(&reply); + } 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(&m_ewmh, xid); + xcb_ewmh_get_atoms_reply_t reply; // a list of Atom + if (xcb_ewmh_get_wm_window_type_reply(&m_ewmh, cookie, &reply, nullptr)) { + for (uint32_t i = 0; i < reply.atoms_len; i++) { + ret.push_back(reply.atoms[i]); + } + + xcb_ewmh_get_atoms_reply_wipe(&reply); + } else { + 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(&m_ewmh, xid); + xcb_ewmh_get_atoms_reply_t reply; // a list of Atoms + if (xcb_ewmh_get_wm_allowed_actions_reply(&m_ewmh, cookie, &reply, nullptr)) { + for (uint32_t i = 0; i < reply.atoms_len; i++) { + ret.push_back(reply.atoms[i]); + } + + xcb_ewmh_get_atoms_reply_wipe(&reply); + } else { + std::cout << xid << " getWMAllowedActions error" << std::endl; + } + + 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(&m_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(&m_ewmh, xid); + xcb_ewmh_get_utf8_strings_reply_t reply; + if (xcb_ewmh_get_wm_name_reply(&m_ewmh, cookie, &reply, nullptr)) { + ret.assign(reply.strings, reply.strings_len); + // 释放utf8_strings_reply分配的内存 + xcb_ewmh_get_utf8_strings_reply_wipe(&reply); + } else { + std::cout << xid << " getWMName error" << std::endl; + } + + return ret; +} + +uint32_t XCBUtils::getWMPid(XWindow xid) +{ + // NOTE(black_desk): code copy from https://gitlab.gnome.org/GNOME/metacity/-/merge_requests/13/diffs + + XResClientIdSpec spec = { + .client = xid, + .mask = XRES_CLIENT_ID_PID_MASK, + }; + + std::shared_ptr dpy = { + XOpenDisplay(nullptr), + [](Display *p){ XCloseDisplay(p); }, + }; + + long num_ids; + XResClientIdValue *client_ids; + XResQueryClientIds(dpy.get(), + 1, + &spec, + &num_ids, + &client_ids); + + pid_t pid = -1; + for (long i = 0; i < num_ids; i++) { + if (client_ids[i].spec.mask == XRES_CLIENT_ID_PID_MASK) { + pid = XResGetClientPid(&client_ids[i]); + break; + } + } + + XResClientIdsDestroy(num_ids, client_ids); + return pid; +} + +std::string XCBUtils::getWMIconName(XWindow xid) +{ + std::string ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_icon_name(&m_ewmh, xid); + xcb_ewmh_get_utf8_strings_reply_t reply; + if (!xcb_ewmh_get_wm_icon_name_reply(&m_ewmh, cookie, &reply, nullptr)) { + std::cout << xid << " getWMIconName error" << std::endl; + } + + ret.assign(reply.strings); + + return ret; +} + +WMIcon XCBUtils::getWMIcon(XWindow xid) +{ + WMIcon wmIcon{}; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_icon(&m_ewmh, xid); + xcb_ewmh_get_wm_icon_reply_t reply; + xcb_generic_error_t* error; + + auto ret = xcb_ewmh_get_wm_icon_reply(&m_ewmh, cookie, &reply, &error); + + if (error) { + std::cout << "failed to get wm icon" << error->error_code; + std::free(error); + return wmIcon; + } + + if (ret) { + auto fcn = [](xcb_ewmh_wm_icon_iterator_t it) { + // https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html#idm45582154990752 + // The first two cardinals are width, height. Data is in rows, left to right and top to bottom + // Two cardinals means width and heighr, not offset. + const auto size = it.width * it.height; + std::vector ret(size); + // data数据是按行从左至右,从上至下排列 + uint32_t *data = it.data; + if (!data) { + return ret; + } + + std::copy_n(data, size, ret.begin()); + return ret; + }; + + // 获取icon中size最大的图标 + xcb_ewmh_wm_icon_iterator_t iter = xcb_ewmh_get_wm_icon_iterator(&reply); + xcb_ewmh_wm_icon_iterator_t wmIconIt{0, 0, nullptr}; + for (; iter.rem; xcb_ewmh_get_wm_icon_next(&iter)) { + const uint32_t size = iter.width * iter.height; + if (size > 0 && size > wmIconIt.width * wmIconIt.height) { + wmIconIt = iter; + } + } + + wmIcon = WMIcon{wmIconIt.width, wmIconIt.height, fcn(wmIconIt)}; + + xcb_ewmh_get_wm_icon_reply_wipe(&reply); // clear + } + + return wmIcon; +} + +XWindow XCBUtils::getWMClientLeader(XWindow xid) +{ + XWindow ret = 0; + XCBAtom atom = getAtom("WM_CLIENT_LEADER"); + void *value = getPropertyValue(xid, atom, XCB_ATOM_INTEGER); + if (value) { + ret = *(XWindow*)(value); + } + return ret; +} + +void XCBUtils::requestCloseWindow(XWindow xid, uint32_t timestamp) +{ + xcb_ewmh_request_close_window(&m_ewmh, m_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(&m_ewmh, xid); + if (!xcb_ewmh_get_wm_desktop_reply(&m_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(&m_ewmh, xid, desktop); +} + +void XCBUtils::setCurrentWMDesktop(uint32_t desktop) +{ + xcb_ewmh_set_current_desktop(&m_ewmh, m_screenNum, desktop); +} + +void XCBUtils::changeCurrentDesktop(uint32_t newDesktop, uint32_t timestamp) +{ + xcb_ewmh_request_change_current_desktop(&m_ewmh, m_screenNum, newDesktop, timestamp); +} + +uint32_t XCBUtils::getCurrentWMDesktop() +{ + uint32_t ret; + xcb_get_property_cookie_t cookie = xcb_ewmh_get_current_desktop(&m_ewmh, m_screenNum); + if (!xcb_ewmh_get_current_desktop_reply(&m_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(m_connect, xid); + xcb_generic_error_t **errStore = nullptr; + xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(m_connect, cookie, errStore); + if (reply) { + // 正常获取窗口geometry则判定为good + if (!errStore) { + ret = true; + } else { + free(errStore); + } + + free(reply); + } + return ret; +} + +// TODO XCB下无_MOTIF_WM_HINTS属性 +MotifWMHints XCBUtils::getWindowMotifWMHints(XWindow xid) +{ + XCBAtom atomWmHints = getAtom("_MOTIF_WM_HINTS"); + xcb_get_property_cookie_t cookie = xcb_get_property(m_connect, false, xid, atomWmHints, atomWmHints, 0, 5); + std::unique_ptr reply(xcb_get_property_reply(m_connect, cookie, nullptr)); + if (!reply || reply->format != 32 || reply->value_len != 5) + return MotifWMHints{0, 0, 0, 0, 0}; + + uint32_t *data = static_cast(xcb_get_property_value(reply.get())); + MotifWMHints ret; + ret.flags = data[0]; + ret.functions = data[1]; + ret.decorations = data[2]; + ret.inputMode = data[3]; + ret.status = data[4]; + 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(m_connect, xid); + if (!xcb_icccm_get_wm_transient_for_reply(m_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(&m_ewmh, xid); + if (!xcb_ewmh_get_wm_user_time_reply(&m_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(&m_ewmh, xid); + if (!xcb_ewmh_get_wm_user_time_window_reply(&m_ewmh, cookie, &ret, nullptr)) { + 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(m_connect, xid); + xcb_icccm_get_wm_class_reply_t reply; + reply.instance_name = nullptr; + reply.class_name = nullptr; + xcb_icccm_get_wm_class_reply(m_connect, cookie, &reply, nullptr); // 返回值为0不一定表示失败, 故不做返回值判断 + if (reply.class_name) + ret.className.assign(reply.class_name); + + if (reply.instance_name) + ret.instanceName.assign(reply.instance_name); + + if (reply.class_name || reply.instance_name) { + xcb_icccm_get_wm_class_reply_wipe(&reply); + } + + return ret; +} + +void XCBUtils::minimizeWindow(XWindow xid) +{ + uint32_t data[2]; + data[0] = XCB_ICCCM_WM_STATE_ICONIC; + data[1] = XCB_NONE; + xcb_ewmh_send_client_message(m_connect, xid, getRootWindow(),getAtom("WM_CHANGE_STATE"), 2, data); + flush(); +} + +void XCBUtils::maxmizeWindow(XWindow xid) +{ + xcb_ewmh_request_change_wm_state(&m_ewmh + , m_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, m_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(m_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(m_connect, + xid, + XCB_CW_EVENT_MASK, + &value); + flush(); + + xcb_generic_error_t *error = xcb_request_check(m_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 = m_atoms.find(name); + if (search != m_atoms.end()) { + atom = search->second; + } + + return atom; +} + +std::string AtomCache::getName(XCBAtom atom) +{ + std::string ret; + auto search = m_atomNames.find(atom); + if (search != m_atomNames.end()) { + ret = search->second; + } + + return ret; +} + +void AtomCache::store(std::string name, XCBAtom value) +{ + m_atoms[name] = value; + m_atomNames[value] = name; +} diff --git a/frame/taskmanager/xcbutils.h b/frame/taskmanager/xcbutils.h new file mode 100644 index 000000000..f069dc393 --- /dev/null +++ b/frame/taskmanager/xcbutils.h @@ -0,0 +1,276 @@ +// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#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 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; + +typedef struct WindowFrameExtents { + uint32_t Left; + uint32_t Right; + uint32_t Top; + uint32_t Bottom; + WindowFrameExtents(int left = 0, int right = 0, int top = 0, int bottom = 0): Left(left), Right(right), Top(top), Bottom(bottom) {} + bool isNull() { return Left == 0 && Right == 0 && Top == 0 && Bottom == 0;} +} WindowFrameExtents; + +// 缓存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 m_atoms; + std::map m_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; + } + + /************************* xcb method ***************************/ + // 分配XID + XWindow allocId(); + + // 刷新 + void flush(); + + /************************* 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); + + // 改变活动窗口 + void changeActiveWindow(XWindow newActiveXid); + + // 重新排列窗口 + void restackWindow(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 + WMIcon 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); + + // 请求改变当前桌面 + void changeCurrentDesktop(uint32_t newDesktop, uint32_t timestamp); + + // 获取当前桌面 _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: + XWindow getDecorativeWindow(XWindow xid); + WindowFrameExtents getWindowFrameExtents(XWindow xid); + +private: + xcb_connection_t *m_connect; + int m_screenNum; + + xcb_ewmh_connection_t m_ewmh; + AtomCache m_atomCache; // 和ewmh中Atom类型存在重复部分,扩张了自定义类型 +}; + +#endif // XCBUTILS_H diff --git a/frame/util/dbusutil.h b/frame/util/dbusutil.h index 27f611b9c..61e44e0bf 100644 --- a/frame/util/dbusutil.h +++ b/frame/util/dbusutil.h @@ -5,12 +5,7 @@ #ifndef DBUSUTIL_H #define DBUSUTIL_H - -#include "dockinterface.h" -#include "entryinterface.h" - -using DockInter = org::deepin::dde::daemon::DdeDock; -using DockEntryInter = org::deepin::dde::daemon::dock::DockEntry; +#include const QString xEventMonitorService = "org.deepin.dde.XEventMonitor1"; const QString xEventMonitorPath = "/org/deepin/dde/XEventMonitor1"; @@ -31,14 +26,4 @@ const QString sessionManagerService = "org.deepin.dde.SessionManager1"; const QString sessionManagerPath = "/org/deepin/dde/SessionManager1"; const QString sessionManagerInterface = "org.deepin.dde.SessionManager1"; -inline const QString dockServiceName() -{ - return QString("org.deepin.dde.daemon.Dock1"); -} - -inline const QString dockServicePath() -{ - return QString("/org/deepin/dde/daemon/Dock1"); -} - #endif // DBUSUTIL_H diff --git a/frame/util/docksettings.cpp b/frame/util/docksettings.cpp index 78afe22a6..e4f505f77 100644 --- a/frame/util/docksettings.cpp +++ b/frame/util/docksettings.cpp @@ -28,14 +28,13 @@ void DockSettings::init() if (m_dockSettings) { connect(m_dockSettings, &DConfig::valueChanged, this, [&] (const QString &key) { if (key == keyHideMode) { - Q_EMIT + Q_EMIT hideModeChanged(HideModeHandler(m_dockSettings->value(keyHideMode).toString()).toEnum()); } else if(key == keyDisplayMode) { Q_EMIT displayModeChanged(DisplayMode(DisplayModeHandler(m_dockSettings->value(key).toString()).toEnum())); } else if (key == keyPosition) { Q_EMIT positionModeChanged(Position(PositionModeHandler(m_dockSettings->value(key).toString()).toEnum())); } else if (key == keyForceQuitApp){ - QString mode = m_dockSettings->value(key).toString(); - Q_EMIT forceQuitAppChanged(ForceQuitAppModeHandler(mode).toEnum()); + Q_EMIT forceQuitAppChanged(ForceQuitAppModeHandler(m_dockSettings->value(key).toString()).toEnum()); } else if (key == keyShowRecent) { Q_EMIT showRecentChanged(m_dockSettings->value(key).toBool()); } else if (key == keyShowMultiWindow) { @@ -50,8 +49,6 @@ void DockSettings::init() Q_EMIT windowSizeFashionChanged(m_dockSettings->value(keyWindowSizeFashion).toUInt()); } else if ( key == keyWindowSizeEfficient) { Q_EMIT windowSizeEfficientChanged(m_dockSettings->value(keyWindowSizeEfficient).toUInt()); - } else if ( key == keyOpacity) { - Q_EMIT opacityChanged(m_dockSettings->value(keyOpacity).toDouble()); } }); } @@ -249,15 +246,6 @@ void DockSettings::setRecentApps(const QStringList &apps) saveStringList(keyRecentApp, apps); } -double DockSettings::getOpacity() -{ - double opacity = 0.4; - // if (m_appearanceSettings) { - // opacity = m_appearanceSettings->value(keyOpacity).toDouble(); - // } - return opacity; -} - QVector DockSettings::getWinIconPreferredApps() { QVector ret; diff --git a/frame/util/docksettings.h b/frame/util/docksettings.h index 34fdb9534..e9ea38fbe 100644 --- a/frame/util/docksettings.h +++ b/frame/util/docksettings.h @@ -205,7 +205,6 @@ public: void setDockedApps(const QStringList &apps); QStringList getRecentApps() const; void setRecentApps(const QStringList &apps); - double getOpacity(); QVector getWinIconPreferredApps(); void setShowRecent(bool visible); bool showRecent() const; @@ -257,8 +256,6 @@ Q_SIGNALS: void windowSizeFashionChanged(uint size); // 高效模式dock尺寸改变 void windowSizeEfficientChanged(uint size); - // 透明度改变 - void opacityChanged(double opacity); private: DockSettings(QObject *paret = nullptr); diff --git a/frame/util/multiscreenworker.cpp b/frame/util/multiscreenworker.cpp index 1c5cb2b1f..9728ab3a1 100644 --- a/frame/util/multiscreenworker.cpp +++ b/frame/util/multiscreenworker.cpp @@ -31,6 +31,7 @@ const QString MonitorsSwitchTime = "monitorsSwitchTime"; const QString OnlyShowPrimary = "onlyShowPrimary"; +const double DEFAULTOPACITY = 0.4; #define DIS_INS DisplayManager::instance() #define DOCK_SCREEN DockScreen::instance() @@ -306,7 +307,7 @@ void MultiScreenWorker::onRequestUpdateRegionMonitor() const static int flags = Motion | Button | Key; const static int monitorHeight = static_cast(15 * qApp->devicePixelRatio()); // 后端认为的任务栏大小(无缩放因素影响) - const int realDockSize = int((m_displayMode == DisplayMode::Fashion ? (int)m_windowFashionSize + 2 * 10 /*上下的边距各10像素*/ : (int)m_windowFashionSize) * qApp->devicePixelRatio()); + const int realDockSize = int((m_displayMode == DisplayMode::Fashion ? m_windowFashionSize + 20 : m_windowEfficientSize) * qApp->devicePixelRatio()); // 任务栏唤起区域 m_monitorRectList.clear(); @@ -541,6 +542,9 @@ void MultiScreenWorker::initMembers() m_delayWakeTimer->setSingleShot(true); + m_windowFashionSize = int(DockSettings::instance()->getWindowSizeFashion() * qApp->devicePixelRatio()); + m_windowEfficientSize = int(DockSettings::instance()->getWindowSizeEfficient() * qApp->devicePixelRatio()); + setStates(LauncherDisplay, m_launcherInter->isValid() ? m_launcherInter->visible() : false); // init check @@ -553,6 +557,7 @@ void MultiScreenWorker::initConnection() connect(DIS_INS, &DisplayManager::screenInfoChanged, this, &MultiScreenWorker::requestUpdateMonitorInfo); connect(m_launcherInter, static_cast(&DBusLuncher::VisibleChanged), this, [ = ](bool value) { setStates(LauncherDisplay, value); }); + connect(m_appearanceInter, &Appearance::OpacityChanged, this, &MultiScreenWorker::onOpacityChanged); connect(this, &MultiScreenWorker::requestUpdatePosition, this, &MultiScreenWorker::onRequestUpdatePosition); connect(this, &MultiScreenWorker::requestUpdateMonitorInfo, this, &MultiScreenWorker::onRequestUpdateMonitorInfo); @@ -570,7 +575,7 @@ void MultiScreenWorker::initConnection() connect(DockSettings::instance(), &DockSettings::positionModeChanged, this, &MultiScreenWorker::onPositionChanged); connect(DockSettings::instance(), &DockSettings::displayModeChanged, this, &MultiScreenWorker::onDisplayModeChanged); connect(DockSettings::instance(), &DockSettings::hideModeChanged, this, &MultiScreenWorker::onHideModeChanged); - // connect(DockSettings::instance(), &DockSettings::hideStateChange, this, &MultiScreenWorker::onHideStateChanged); + connect(TaskManager::instance(), &TaskManager::hideStateChanged, this, &MultiScreenWorker::onHideStateChanged); } void MultiScreenWorker::initDockMode() @@ -578,8 +583,8 @@ void MultiScreenWorker::initDockMode() onPositionChanged(DockSettings::instance()->getPositionMode()); onDisplayModeChanged(DockSettings::instance()->getDisplayMode()); onHideModeChanged(DockSettings::instance()->getHideMode()); - // onHideStateChanged(m_dockInter->hideState()); - onOpacityChanged(DockSettings::instance()->getOpacity()); + onHideStateChanged(TaskManager::instance()->getHideState()); + onOpacityChanged(m_appearanceInter? m_appearanceInter->opacity(): DEFAULTOPACITY); DockItem::setDockPosition(m_position); qApp->setProperty(PROP_POSITION, QVariant::fromValue(m_position)); @@ -674,7 +679,7 @@ void MultiScreenWorker::resetDockScreen() bool MultiScreenWorker::isCursorOut(int x, int y) { - const int realDockSize = int((m_displayMode == DisplayMode::Fashion ? (int)m_windowFashionSize + 2 * 10 /*上下的边距各10像素*/ : (int)m_windowEfficientSize) * qApp->devicePixelRatio()); + const int realDockSize = int((m_displayMode == DisplayMode::Fashion ? m_windowFashionSize : m_windowEfficientSize) * qApp->devicePixelRatio()); for (auto s : DIS_INS->screens()) { // 屏幕此位置不可停靠时,不用监听这块区域 if (!DIS_INS->canDock(s, m_position)) diff --git a/frame/window/mainpanelcontrol.cpp b/frame/window/mainpanelcontrol.cpp index 2c60476da..93614eadd 100644 --- a/frame/window/mainpanelcontrol.cpp +++ b/frame/window/mainpanelcontrol.cpp @@ -83,7 +83,7 @@ MainPanelControl::MainPanelControl(QWidget *parent) , m_recentHelper(new RecentAppHelper(m_appAreaSonWidget, m_recentAreaWidget, this)) , m_toolHelper(new ToolAppHelper(m_toolSonAreaWidget, this)) , m_multiHelper(new MultiWindowHelper(m_appAreaSonWidget, m_multiWindowWidget, this)) - , m_showRecent(false) + , m_showRecent(DockSettings::instance()->showRecent()) { initUI(); initConnection(); @@ -723,6 +723,8 @@ void MainPanelControl::mousePressEvent(QMouseEvent *e) void MainPanelControl::startDrag(DockItem *dockItem) { + // 每次拖动使m_dragIndex==-1, 表明当前item的位置未发生变化 + m_dragIndex = -1; QPointer item = dockItem; const QPixmap pixmap = item->grab(); diff --git a/frame/window/tray/widgets/expandiconwidget.cpp b/frame/window/tray/widgets/expandiconwidget.cpp index 82e04d68e..fc503de53 100644 --- a/frame/window/tray/widgets/expandiconwidget.cpp +++ b/frame/window/tray/widgets/expandiconwidget.cpp @@ -186,12 +186,6 @@ TrayGridWidget::TrayGridWidget(QWidget *parent) { initMember(); setAttribute(Qt::WA_TranslucentBackground); - connect(DockSettings::instance(), &DockSettings::opacityChanged, this, [=] (double opacity) { - m_maskAlpha = static_cast (opacity); - }); - QMetaObject::invokeMethod(this, [=] { - m_maskAlpha = static_cast (DockSettings::instance()->getOpacity()); - }); } void TrayGridWidget::setPosition(const Dock::Position &position) @@ -313,7 +307,7 @@ void TrayGridWidget::initMember() QColor TrayGridWidget::maskColor() const { QColor color = DGuiApplicationHelper::standardPalette(DGuiApplicationHelper::instance()->themeType()).window().color(); - color.setAlpha(m_maskAlpha); + color.setAlpha(0); return color; } diff --git a/frame/window/tray/widgets/expandiconwidget.h b/frame/window/tray/widgets/expandiconwidget.h index 09a1928d9..b4f08ef2e 100644 --- a/frame/window/tray/widgets/expandiconwidget.h +++ b/frame/window/tray/widgets/expandiconwidget.h @@ -75,7 +75,6 @@ private: TrayGridView *m_referGridView; Dtk::Gui::DRegionMonitor *m_regionInter; static Dock::Position m_position; - int m_maskAlpha; }; #endif // EXPANDICONWIDGET_H diff --git a/frame/window/windowmanager.cpp b/frame/window/windowmanager.cpp index a4980f7c4..c247a1c37 100644 --- a/frame/window/windowmanager.cpp +++ b/frame/window/windowmanager.cpp @@ -4,6 +4,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "mainwindow.h" +#include "taskmanager/entry.h" #include "windowmanager.h" #include "traymainwindow.h" #include "multiscreenworker.h" @@ -675,8 +676,7 @@ void WindowManager::onRequestUpdateFrontendGeometry() } } - DockInter dockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus()); - dockInter.SetFrontendWindowRect(x, y, uint(rect.width()), uint(rect.height())); + TaskManager::instance()->setFrontendWindowRect(x, y, uint(rect.width()), uint(rect.height())); } void WindowManager::onRequestNotifyWindowManager() diff --git a/plugins/onboard/CMakeLists.txt b/plugins/onboard/CMakeLists.txt index ef639cca5..2204d2fab 100644 --- a/plugins/onboard/CMakeLists.txt +++ b/plugins/onboard/CMakeLists.txt @@ -3,8 +3,6 @@ set(PLUGIN_NAME "onboard") project(${PLUGIN_NAME}) -generation_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/xml ${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/generation_dbus_interface) - # Sources files file(GLOB_RECURSE SRCS "*.h" "*.cpp" @@ -25,8 +23,7 @@ set_target_properties(${PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../) target_include_directories(${PLUGIN_NAME} PUBLIC ${Qt5DBus_INCLUDE_DIRS} ../../interfaces - ../../frame/qtdbusextended - ./dbusinterface/generation_dbus_interface) + ../../frame/qtdbusextended) target_link_libraries(${PLUGIN_NAME} PRIVATE ${DtkWidget_LIBRARIES} diff --git a/plugins/onboard/dbusinterface/types/arealist.cpp b/plugins/onboard/dbusinterface/types/arealist.cpp deleted file mode 100644 index 0b3ed4f15..000000000 --- a/plugins/onboard/dbusinterface/types/arealist.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2011 ~ 2017 Deepin Technology Co., Ltd. -// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include "arealist.h" - -bool MonitRect::operator ==(const MonitRect &rect) -{ - return x1 == rect.x1 && y1 == rect.y1 && x2 == rect.x2 && y2 == rect.y2; -} - -QDBusArgument &operator<<(QDBusArgument &arg, const MonitRect &rect) -{ - arg.beginStructure(); - arg << rect.x1 << rect.y1 << rect.x2 << rect.y2; - arg.endStructure(); - - return arg; -} - -const QDBusArgument &operator>>(const QDBusArgument &arg, MonitRect &rect) -{ - arg.beginStructure(); - arg >> rect.x1 >> rect.y1 >> rect.x2 >> rect.y2; - arg.endStructure(); - - return arg; -} - -void registerAreaListMetaType() -{ - qRegisterMetaType("MonitRect"); - qDBusRegisterMetaType(); - - qRegisterMetaType("AreaList"); - qDBusRegisterMetaType(); -} diff --git a/plugins/onboard/dbusinterface/types/arealist.h b/plugins/onboard/dbusinterface/types/arealist.h deleted file mode 100644 index f75a0e53f..000000000 --- a/plugins/onboard/dbusinterface/types/arealist.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2011 ~ 2017 Deepin Technology Co., Ltd. -// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#ifndef AREALIST_H -#define AREALIST_H - -#include -#include -#include - -struct MonitRect { - int x1; - int y1; - int x2; - int y2; - - bool operator ==(const MonitRect& rect); -}; - -typedef QList AreaList; - -Q_DECLARE_METATYPE(MonitRect) -Q_DECLARE_METATYPE(AreaList) - -QDBusArgument &operator<<(QDBusArgument &arg, const MonitRect &rect); -const QDBusArgument &operator>>(const QDBusArgument &arg, MonitRect &rect); - -void registerAreaListMetaType(); - -#endif // AREALIST_H diff --git a/plugins/onboard/dbusinterface/xml/org.deepin.dde.daemon.Dock1.Entry.xml b/plugins/onboard/dbusinterface/xml/org.deepin.dde.daemon.Dock1.Entry.xml deleted file mode 100644 index 89b665e41..000000000 --- a/plugins/onboard/dbusinterface/xml/org.deepin.dde.daemon.Dock1.Entry.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/plugins/onboard/dbusinterface/xml/org.deepin.dde.daemon.Dock1.xml b/plugins/onboard/dbusinterface/xml/org.deepin.dde.daemon.Dock1.xml deleted file mode 100644 index 08573ed35..000000000 --- a/plugins/onboard/dbusinterface/xml/org.deepin.dde.daemon.Dock1.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/plugins/onboard/onboardplugin.cpp b/plugins/onboard/onboardplugin.cpp index c57b74e9d..f24d3a154 100644 --- a/plugins/onboard/onboardplugin.cpp +++ b/plugins/onboard/onboardplugin.cpp @@ -6,9 +6,6 @@ #include "onboardplugin.h" #include "../widgets/tipswidget.h" -#include "org_deepin_dde_daemon_dock1.h" -#include "org_deepin_dde_daemon_dock1_entry.h" - #include #include @@ -19,12 +16,6 @@ DGUI_USE_NAMESPACE -using DBusDock = org::deepin::dde::daemon::Dock1; -using DockEntryInter = org::deepin::dde::daemon::dock1::Entry; - -static const QString serviceName = QString("org.deepin.dde.daemon.Dock1"); -static const QString servicePath = QString("/org/deepin/dde/daemon/Dock1"); - using namespace Dock; OnboardPlugin::OnboardPlugin(QObject *parent) : QObject(parent) @@ -117,15 +108,6 @@ void OnboardPlugin::invokedMenuItem(const QString &itemKey, const QString &menuI process->start("onboard-settings", QStringList()); } - DBusDock DockInter(serviceName, servicePath, QDBusConnection::sessionBus(), this); - - for (auto entry : DockInter.entries()) { - DockEntryInter AppInter(serviceName, entry.path(), QDBusConnection::sessionBus(), this); - if(AppInter.name() == "Onboard-Settings" && !AppInter.isActive()) { - AppInter.Activate(0); - break; - } - } } void OnboardPlugin::displayModeChanged(const Dock::DisplayMode displayMode) diff --git a/plugins/pluginmanager/dockplugincontroller.cpp b/plugins/pluginmanager/dockplugincontroller.cpp index 55fe0111c..efdc6fe31 100644 --- a/plugins/pluginmanager/dockplugincontroller.cpp +++ b/plugins/pluginmanager/dockplugincontroller.cpp @@ -40,7 +40,7 @@ public: DockPluginController::DockPluginController(PluginProxyInterface *proxyInter, QObject *parent) : QObject(parent) , m_dbusDaemonInterface(QDBusConnection::sessionBus().interface()) - , m_dockDaemonInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this)) + // , m_dockDaemonInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this)) , m_proxyInter(proxyInter) { qApp->installEventFilter(this); @@ -48,7 +48,7 @@ DockPluginController::DockPluginController(PluginProxyInterface *proxyInter, QOb refreshPluginSettings(); connect(DockSettings::instance(), &DockSettings::quickPluginsChanged, this, &DockPluginController::onConfigChanged); - connect(m_dockDaemonInter, &DockInter::PluginSettingsSynced, this, &DockPluginController::refreshPluginSettings, Qt::QueuedConnection); + // connect(m_dockDaemonInter, &DockInter::PluginSettingsSynced, this, &DockPluginController::refreshPluginSettings, Qt::QueuedConnection); } DockPluginController::~DockPluginController() @@ -327,7 +327,7 @@ void DockPluginController::savePluginValue(PluginsItemInterface * const itemInte } m_pluginSettingsObject.insert(itemInter->pluginName(), localObject); - m_dockDaemonInter->MergePluginSettings(QJsonDocument(remoteObject).toJson(QJsonDocument::JsonFormat::Compact)); + DockSettings::instance()->mergePluginSettings(QJsonDocument(remoteObject).toJson(QJsonDocument::JsonFormat::Compact)); } const QVariant DockPluginController::getPluginValue(PluginsItemInterface * const itemInter, const QString &key, const QVariant &fallback) @@ -353,7 +353,7 @@ void DockPluginController::removePluginValue(PluginsItemInterface * const itemIn m_pluginSettingsObject.insert(itemInter->pluginName(), localObject); } - m_dockDaemonInter->RemovePluginSettings(itemInter->pluginName(), keyList); + DockSettings::instance()->removePluginSettings(itemInter->pluginName(), keyList); } void DockPluginController::startLoadPlugin(const QStringList &dirs) @@ -576,7 +576,7 @@ void DockPluginController::initPlugin(PluginsItemInterface *interface) void DockPluginController::refreshPluginSettings() { - const QString &pluginSettings = m_dockDaemonInter->GetPluginSettings().value(); + const QString &pluginSettings = DockSettings::instance()->getPluginSettings(); if (pluginSettings.isEmpty()) { qDebug() << "Error! get plugin settings from dbus failed!"; return; @@ -604,9 +604,9 @@ void DockPluginController::refreshPluginSettings() } // not notify plugins to refresh settings if this update is not emit by dock daemon - if (sender() != m_dockDaemonInter) { - return; - } + // if (sender() != m_dockDaemonInter) { + // return; + // } // notify all plugins to reload plugin settings for (PluginsItemInterface *pluginInter : m_pluginsMap.keys()) { diff --git a/plugins/pluginmanager/dockplugincontroller.h b/plugins/pluginmanager/dockplugincontroller.h index 4059514ca..c9fbff745 100644 --- a/plugins/pluginmanager/dockplugincontroller.h +++ b/plugins/pluginmanager/dockplugincontroller.h @@ -84,7 +84,6 @@ private Q_SLOTS: private: QDBusConnectionInterface *m_dbusDaemonInterface; - DockInter *m_dockDaemonInter; // interface, "pluginloader", PluginLoader指针对象 QMap> m_pluginsMap;