From 56c3019a5c7262732110729ec13bbfd0fd1939b1 Mon Sep 17 00:00:00 2001 From: donghualin Date: Thu, 18 Aug 2022 15:41:46 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E5=A4=9A=E5=BC=80=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加窗口多开的窗口类,用于绘制应用图标和打开窗口的图标,根据实际情况让其显示到正确的位置 Log: 增加窗口多开的功能 Influence: 控制中心开启多开窗口显示,观察应用打开的窗口是否在对应的位置显示 Task: https://pms.uniontech.com/task-view-170977.html Change-Id: I96371b1304f5373f17dad95893ee656056e5f457 --- frame/controller/dockitemmanager.cpp | 146 ++++++++++++- frame/controller/dockitemmanager.h | 12 ++ frame/controller/multiwindowhelper.cpp | 154 +++++++++++++ frame/controller/multiwindowhelper.h | 58 +++++ frame/dbus/dockinterface.cpp | 5 + frame/dbus/dockinterface.h | 4 + frame/dbus/entryinterface.h | 7 + frame/item/appitem.cpp | 67 ++++-- frame/item/appitem.h | 7 +- frame/item/appmultiitem.cpp | 286 +++++++++++++++++++++++++ frame/item/appmultiitem.h | 74 +++++++ frame/item/dockitem.h | 3 +- frame/window/mainpanelcontrol.cpp | 152 +++++++++---- frame/window/mainpanelcontrol.h | 10 +- 14 files changed, 922 insertions(+), 63 deletions(-) create mode 100644 frame/controller/multiwindowhelper.cpp create mode 100644 frame/controller/multiwindowhelper.h create mode 100644 frame/item/appmultiitem.cpp create mode 100644 frame/item/appmultiitem.h diff --git a/frame/controller/dockitemmanager.cpp b/frame/controller/dockitemmanager.cpp index e31714dd2..c773fb16e 100644 --- a/frame/controller/dockitemmanager.cpp +++ b/frame/controller/dockitemmanager.cpp @@ -25,6 +25,7 @@ #include "pluginsitem.h" #include "traypluginitem.h" #include "utils.h" +#include "appmultiitem.h" #include #include @@ -47,16 +48,23 @@ DockItemManager::DockItemManager(QObject *parent) // 应用区域 for (auto entry : m_appInter->entries()) { - AppItem *it = new AppItem(m_appSettings, m_activeSettings, m_dockedSettings, entry); + AppItem *it = new AppItem(m_appInter, 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); +#ifdef USE_AM + connect(it, &AppItem::windowCountChanged, this, &DockItemManager::onAppWindowCountChanged); +#endif + connect(this, &DockItemManager::requestUpdateDockItem, it, &AppItem::requestUpdateEntryGeometries); m_itemList.append(it); +#ifdef USE_AM + updateMultiItems(it); +#endif } // 托盘区域和插件区域 由DockPluginsController获取 @@ -65,6 +73,9 @@ DockItemManager::DockItemManager(QObject *parent) 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); +#ifdef USE_AM + connect(m_appInter, &DockInter::ShowMultiWindowChanged, this, &DockItemManager::onShowMultiWindowChanged); +#endif // 插件信号 connect(m_pluginsInter, &DockPluginsController::pluginItemInserted, this, &DockItemManager::pluginItemInserted, Qt::QueuedConnection); @@ -194,7 +205,7 @@ 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_appInter, m_appSettings, m_activeSettings, m_dockedSettings, path); if (m_appIDist.contains(item->appId())) { delete item; @@ -206,17 +217,24 @@ void DockItemManager::appItemAdded(const QDBusObjectPath &path, const int index) 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); +#ifdef USE_AM + connect(item, &AppItem::windowCountChanged, this, &DockItemManager::onAppWindowCountChanged); +#endif connect(this, &DockItemManager::requestUpdateDockItem, item, &AppItem::requestUpdateEntryGeometries); m_itemList.insert(insertIndex, item); m_appIDist.append(item->appId()); - if (index != -1) { - emit itemInserted(insertIndex - 1, item); - return; - } + int itemIndex = insertIndex; + if (index != -1) + itemIndex = insertIndex - 1; - emit itemInserted(insertIndex, item); + // 插入dockItem + emit itemInserted(itemIndex, item); +#ifdef USE_AM + // 向后插入多开窗口 + updateMultiItems(item, true); +#endif } void DockItemManager::appItemRemoved(const QString &appId) @@ -299,9 +317,7 @@ void DockItemManager::pluginItemInserted(PluginsItem *item) m_itemList.insert(insertIndex, item); if(pluginType == DockItem::FixedPlugin) - { insertIndex ++; - } if (!Utils::SettingValue(QString("com.deepin.dde.dock.module.") + item->pluginName(), QByteArray(), "enable", true).toBool()) item->setVisible(false); @@ -345,3 +361,115 @@ void DockItemManager::onPluginLoadFinished() updatePluginsItemOrderKey(); m_loadFinished = true; } + +#ifdef USE_AM +void DockItemManager::onAppWindowCountChanged() +{ + AppItem *appItem = static_cast(sender()); + updateMultiItems(appItem, true); +} + +void DockItemManager::updateMultiItems(AppItem *appItem, bool emitSignal) +{ + // 如果系统设置不开启应用多窗口拆分,则无需之后的操作 + if (!m_appInter->showMultiWindow()) + return; + + // 如果开启了多窗口拆分,则同步窗口和多窗口应用的信息 + const WindowInfoMap &windowInfoMap = appItem->windowsMap(); + QList removeItems; + // 同步当前已经存在的多开窗口的列表,删除不存在的多开窗口 + for (int i = 0; i < m_itemList.size(); i++) { + QPointer dockItem = m_itemList[i]; + AppMultiItem *multiItem = qobject_cast(dockItem.data()); + if (!multiItem || multiItem->appItem() != appItem) + continue; + + // 如果查找到的当前的应用的窗口不需要移除,则继续下一个循环 + if (!needRemoveMultiWindow(multiItem)) + continue; + + removeItems << multiItem; + } + // 从itemList中移除多开窗口 + for (AppMultiItem *dockItem : removeItems) + m_itemList.removeOne(dockItem); + if (emitSignal) { + // 移除发送每个多开窗口的移除信号 + for (AppMultiItem *dockItem : removeItems) + Q_EMIT itemRemoved(dockItem); + } + qDeleteAll(removeItems); + + // 遍历当前APP打开的所有窗口的列表,如果不存在多开窗口的应用,则新增,同时发送信号 + for (auto it = windowInfoMap.begin(); it != windowInfoMap.end(); it++) { + if (multiWindowExist(it.key())) + continue; + + const WindowInfo &windowInfo = it.value(); + // 如果不存在这个窗口对应的多开窗口,则新建一个窗口,同时发送窗口新增的信号 + AppMultiItem *multiItem = new AppMultiItem(appItem, it.key(), windowInfo); + m_itemList << multiItem; + if (emitSignal) + Q_EMIT itemInserted(-1, multiItem); + } +} + +// 检查对应的窗口是否存在多开窗口 +bool DockItemManager::multiWindowExist(quint32 winId) const +{ + for (QPointer dockItem : m_itemList) { + AppMultiItem *multiItem = qobject_cast(dockItem.data()); + if (!multiItem) + continue; + + if (multiItem->winId() == winId) + return true; + } + + return false; +} + +// 检查当前多开窗口是否需要移除 +// 如果当前多开窗口图标对应的窗口在这个窗口所属的APP中所有打开窗口中不存在,那么则认为该多窗口已经被关闭 +bool DockItemManager::needRemoveMultiWindow(AppMultiItem *multiItem) const +{ + // 查找多分窗口对应的窗口在应用所有的打开的窗口中是否存在,只要它对应的窗口存在,就无需删除 + // 只要不存在,就需要删除 + AppItem *appItem = multiItem->appItem(); + const WindowInfoMap &windowInfoMap = appItem->windowsMap(); + for (auto it = windowInfoMap.begin(); it != windowInfoMap.end(); it++) { + if (it.key() == multiItem->winId()) + return false; + } + + return true; +} + +void DockItemManager::onShowMultiWindowChanged() +{ + if (m_appInter->showMultiWindow()) { + // 如果当前设置支持窗口多开,那么就依次对每个APPItem加载多开窗口 + for (const QPointer &dockItem : m_itemList) { + if (dockItem->itemType() != DockItem::ItemType::App) + continue; + + updateMultiItems(static_cast(dockItem.data()), true); + } + } else { + // 如果当前设置不支持窗口多开,则删除所有的多开窗口 + QList multiWindows; + for (const QPointer &dockItem : m_itemList) { + if (dockItem->itemType() != DockItem::AppMultiWindow) + continue; + + multiWindows << dockItem.data(); + } + for (DockItem *multiItem : multiWindows) { + m_itemList.removeOne(multiItem); + Q_EMIT itemRemoved(multiItem); + multiItem->deleteLater(); + } + } +} +#endif diff --git a/frame/controller/dockitemmanager.h b/frame/controller/dockitemmanager.h index 0887bd9e9..961229b47 100644 --- a/frame/controller/dockitemmanager.h +++ b/frame/controller/dockitemmanager.h @@ -31,6 +31,7 @@ #include +class AppMultiItem; /** * @brief The DockItemManager class * 管理类,管理所有的应用数据,插件数据 @@ -64,6 +65,11 @@ public slots: private Q_SLOTS: void onPluginLoadFinished(); +#ifdef USE_AM + void onAppWindowCountChanged(); + void onShowMultiWindowChanged(); +#endif + private: explicit DockItemManager(QObject *parent = nullptr); void appItemAdded(const QDBusObjectPath &path, const int index); @@ -75,6 +81,12 @@ private: void reloadAppItems(); void manageItem(DockItem *item); +#ifdef USE_AM + void updateMultiItems(AppItem *appItem, bool emitSignal = false); + bool multiWindowExist(quint32 winId) const; + bool needRemoveMultiWindow(AppMultiItem *multiItem) const; +#endif + private: DockInter *m_appInter; DockPluginsController *m_pluginsInter; diff --git a/frame/controller/multiwindowhelper.cpp b/frame/controller/multiwindowhelper.cpp new file mode 100644 index 000000000..953389a53 --- /dev/null +++ b/frame/controller/multiwindowhelper.cpp @@ -0,0 +1,154 @@ +/* + * 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 "multiwindowhelper.h" +#include "appmultiitem.h" +#include "appitem.h" + +MultiWindowHelper::MultiWindowHelper(QWidget *appWidget, QWidget *multiWindowWidget, QObject *parent) + : QObject(parent) + , m_appWidget(appWidget) + , m_multiWindowWidget(multiWindowWidget) + , m_displayMode(Dock::DisplayMode::Efficient) +{ + m_appWidget->installEventFilter(this); + m_multiWindowWidget->installEventFilter(this); +} + +void MultiWindowHelper::setDisplayMode(Dock::DisplayMode displayMode) +{ + if (m_displayMode == displayMode) + return; + + m_displayMode = displayMode; + resetMultiItemPosition(); +} + +void MultiWindowHelper::addMultiWindow(int, AppMultiItem *item) +{ + int index = itemIndex(item); + if (m_displayMode == Dock::DisplayMode::Efficient) { + // 将多开窗口项目插入到对应的APP的后面 + insertChildWidget(m_appWidget, index, item); + } else { + // 将多开窗口插入到工具区域的前面 + insertChildWidget(m_multiWindowWidget, index, item); + } +} + +void MultiWindowHelper::removeMultiWindow(AppMultiItem *item) +{ + if (m_appWidget->children().contains(item)) + m_appWidget->layout()->removeWidget(item); + else + m_multiWindowWidget->layout()->removeWidget(item); +} + +bool MultiWindowHelper::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == m_appWidget || watched == m_multiWindowWidget) { + switch(event->type()) { + case QEvent::ChildAdded: + case QEvent::ChildRemoved: { + /* 这里用异步的方式,因为收到QEvent::ChildAdded信号的时候, + 此时应用还没有插入到Widget中,收到QEvent::ChildRemoved信号的时候, + 此时应用还未从任务栏上移除,通过异步的方式保证同步新增或移除成功后才执行,这样更新的界面才是最准确的 + */ + QMetaObject::invokeMethod(this, &MultiWindowHelper::requestUpdate, Qt::QueuedConnection); + break; + } + default: + break; + } + } + + return QObject::eventFilter(watched, event); +} + +int MultiWindowHelper::itemIndex(AppMultiItem *item) +{ + if (m_displayMode != Dock::DisplayMode::Efficient) + return -1; + + // 高效模式,查找对应的应用或者这个应用所有的子窗口所在的位置,然后插入到最大的值的后面 + int lastIndex = -1; + for (int i = 0; i < m_appWidget->layout()->count(); i++) { + DockItem *dockItem = qobject_cast(m_appWidget->layout()->itemAt(i)->widget()); + if (!dockItem) + continue; + + if (dockItem != item->appItem()) { + AppMultiItem *multiItem = qobject_cast(dockItem); + if (!multiItem || multiItem->appItem() != item->appItem()) + continue; + } + + lastIndex = i; + } + + if (lastIndex >= 0) + return ++lastIndex; + + return -1; +} + +void MultiWindowHelper::insertChildWidget(QWidget *parentWidget, int index, AppMultiItem *item) +{ + QBoxLayout *layout = static_cast(parentWidget->layout()); + if (index >= 0) + layout->insertWidget(index, item); + else + layout->addWidget(item); +} + +void MultiWindowHelper::resetMultiItemPosition() +{ + QWidget *fromWidget = nullptr; + QWidget *toWidget = nullptr; + + if (m_displayMode == Dock::DisplayMode::Efficient) { + // 从时尚模式变换为高效模式 + fromWidget = m_multiWindowWidget; + toWidget = m_appWidget; + } else { + // 从高效模式变换到时尚模式 + fromWidget = m_appWidget; + toWidget = m_multiWindowWidget; + } + + QList moveWidgetItem; + for (int i = 0; i < fromWidget->layout()->count(); i++) { + AppMultiItem *multiItem = qobject_cast(fromWidget->layout()->itemAt(i)->widget()); + if (!multiItem) + continue; + + moveWidgetItem << multiItem; + } + + QBoxLayout *toLayout = static_cast(toWidget->layout()); + for (AppMultiItem *item : moveWidgetItem) { + fromWidget->layout()->removeWidget(item); + int index = itemIndex(item); + if (index >= 0) + toLayout->insertWidget(index, item); + else + toLayout->addWidget(item); + } +} diff --git a/frame/controller/multiwindowhelper.h b/frame/controller/multiwindowhelper.h new file mode 100644 index 000000000..b13fc8b7e --- /dev/null +++ b/frame/controller/multiwindowhelper.h @@ -0,0 +1,58 @@ +/* + * 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 MULTIWINDOWHELPER_H +#define MULTIWINDOWHELPER_H + +#include "constants.h" + +#include + +class AppMultiItem; + +class MultiWindowHelper : public QObject +{ + Q_OBJECT + +public: + explicit MultiWindowHelper(QWidget *appWidget, QWidget *multiWindowWidget, QObject *parent = nullptr); + + void setDisplayMode(Dock::DisplayMode displayMode); + void addMultiWindow(int, AppMultiItem *item); + void removeMultiWindow(AppMultiItem *item); + +Q_SIGNALS: + void requestUpdate(); + +protected: + bool eventFilter(QObject *watched, QEvent *event) override; + +private: + int itemIndex(AppMultiItem *item); + void insertChildWidget(QWidget *parentWidget, int index, AppMultiItem *item); + void resetMultiItemPosition(); + +private: + QWidget *m_appWidget; + QWidget *m_multiWindowWidget; + Dock::DisplayMode m_displayMode; +}; + +#endif // MULTIWINDOWHELPER_H diff --git a/frame/dbus/dockinterface.cpp b/frame/dbus/dockinterface.cpp index dfdb7b98b..f2f222920 100644 --- a/frame/dbus/dockinterface.cpp +++ b/frame/dbus/dockinterface.cpp @@ -328,6 +328,11 @@ 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); diff --git a/frame/dbus/dockinterface.h b/frame/dbus/dockinterface.h index 5f04ccd3c..70aaf9bee 100644 --- a/frame/dbus/dockinterface.h +++ b/frame/dbus/dockinterface.h @@ -128,6 +128,9 @@ public: 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); @@ -326,6 +329,7 @@ Q_SIGNALS: // SIGNALS 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); diff --git a/frame/dbus/entryinterface.h b/frame/dbus/entryinterface.h index cc9ad3ccf..08f81640c 100644 --- a/frame/dbus/entryinterface.h +++ b/frame/dbus/entryinterface.h @@ -145,6 +145,13 @@ public Q_SLOTS: // METHODS return asyncCallWithArgumentList(QStringLiteral("ForceQuit"), argumentList); } + inline QDBusPendingReply<> ActiveWindow(quint32 in0) + { + QList argumentList; + argumentList << in0; + return asyncCallWithArgumentList(QStringLiteral("ActiveWindow"), argumentList); + } + inline void ForceQuitQueued() { QList argumentList; diff --git a/frame/item/appitem.cpp b/frame/item/appitem.cpp index b02a97e8f..f6775bce8 100644 --- a/frame/item/appitem.cpp +++ b/frame/item/appitem.cpp @@ -50,7 +50,7 @@ DCORE_USE_NAMESPACE QPoint AppItem::MousePressPos; -AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSettings, const QGSettings *dockedAppSettings, const QDBusObjectPath &entry, QWidget *parent) +AppItem::AppItem(DockInter *dockInter, const QGSettings *appSettings, const QGSettings *activeAppSettings, const QGSettings *dockedAppSettings, const QDBusObjectPath &entry, QWidget *parent) : DockItem(parent) , m_appSettings(appSettings) , m_activeAppSettings(activeAppSettings) @@ -72,6 +72,7 @@ AppItem::AppItem(const QGSettings *appSettings, const QGSettings *activeAppSetti , m_themeType(DGuiApplicationHelper::instance()->themeType()) , m_createMSecs(QDateTime::currentMSecsSinceEpoch()) , m_screenSpliter(ScreenSpliterFactory::createScreenSpliter(this, m_itemEntryInter)) + , m_dockInter(dockInter) { QHBoxLayout *centralLayout = new QHBoxLayout; centralLayout->setMargin(0); @@ -135,6 +136,11 @@ const QString AppItem::appId() const return m_id; } +QString AppItem::name() const +{ + return m_itemEntryInter->name(); +} + bool AppItem::isValid() const { return m_itemEntryInter->isValid() && !m_itemEntryInter->id().isEmpty(); @@ -216,8 +222,14 @@ int AppItem::mode() const { return m_itemEntryInter->mode(); } + #endif +DockEntryInter *AppItem::itemEntryInter() const +{ + return m_itemEntryInter; +} + QString AppItem::accessibleName() { return m_itemEntryInter->name(); @@ -243,6 +255,11 @@ void AppItem::updateMSecs() m_createMSecs = QDateTime::currentMSecsSinceEpoch(); } +const WindowInfoMap &AppItem::windowsMap() const +{ + return m_windowInfos; +} + void AppItem::moveEvent(QMoveEvent *e) { DockItem::moveEvent(e); @@ -281,14 +298,26 @@ void AppItem::paintEvent(QPaintEvent *e) QPainterPath path; path.addRoundedRect(backgroundRect, 8, 8); - if (m_active) { - painter.fillPath(path, QColor(0, 0, 0, 255 * 0.8)); - } else if (!m_windowInfos.isEmpty()) { - if (hasAttention()) - painter.fillPath(path, QColor(241, 138, 46, 255 * .8)); - else - painter.fillPath(path, QColor(0, 0, 0, 255 * 0.3)); + // 在没有开启窗口多开的情况下,显示背景色 +#ifdef USE_AM + if (!m_dockInter->showMultiWindow()) { +#endif + if (m_active) { + QColor color = Qt::black; + color.setAlpha(255 * 0.8); + painter.fillPath(path, color); + } else if (!m_windowInfos.isEmpty()) { + if (hasAttention()) { + painter.fillPath(path, QColor(241, 138, 46, 255 * .8)); + } else { + QColor color = Qt::black; + color.setAlpha(255 * 0.3); + painter.fillPath(path, color); + } + } +#ifdef USE_AM } +#endif } else { if (!m_windowInfos.isEmpty()) { QPoint p; @@ -381,12 +410,21 @@ void AppItem::mouseReleaseEvent(QMouseEvent *e) qDebug() << "app item clicked, name:" << m_itemEntryInter->name() << "id:" << m_itemEntryInter->id() << "my-id:" << m_id << "icon:" << m_itemEntryInter->icon(); - m_itemEntryInter->Activate(QX11Info::getTimestamp()); - - // play launch effect - if (m_windowInfos.isEmpty() && DGuiApplicationHelper::isSpecialEffectsEnvironment()) - playSwingEffect(); +#ifdef USE_AM + if (m_dockInter->showMultiWindow()) { + // 如果开启了多窗口显示,则直接新建一个窗口 + m_itemEntryInter->NewInstance(QX11Info::getTimestamp()); + } else { +#endif + // 如果没有开启新窗口显示,则 + m_itemEntryInter->Activate(QX11Info::getTimestamp()); + // play launch effect + if (m_windowInfos.isEmpty() && DGuiApplicationHelper::isSpecialEffectsEnvironment()) + playSwingEffect(); + } +#ifdef USE_AM } +#endif } void AppItem::mousePressEvent(QMouseEvent *e) @@ -640,6 +678,9 @@ void AppItem::updateWindowInfos(const WindowInfoMap &info) } update(); + + // 通知外面窗体数量发生变化,需要更新多开窗口的信息 + Q_EMIT windowCountChanged(); } void AppItem::refreshIcon() diff --git a/frame/item/appitem.h b/frame/item/appitem.h index 0414a3499..afa9ae9c9 100644 --- a/frame/item/appitem.h +++ b/frame/item/appitem.h @@ -43,11 +43,12 @@ 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(DockInter *dockInter, const QGSettings *appSettings, const QGSettings *activeAppSettings, const QGSettings *dockedAppSettings, const QDBusObjectPath &entry, QWidget *parent = nullptr); ~AppItem() override; void checkEntry() override; const QString appId() const; + QString name() const; bool isValid() const; void updateWindowIconGeometries(); void undock(); @@ -61,6 +62,7 @@ public: #ifdef USE_AM int mode() const; #endif + DockEntryInter *itemEntryInter() const; inline ItemType itemType() const override { return App; } QPixmap appIcon(){ return m_appIcon; } virtual QString accessibleName() override; @@ -68,6 +70,7 @@ public: bool isDocked() const; qint64 appOpenMSecs() const; void updateMSecs(); + const WindowInfoMap &windowsMap() const; signals: void requestActivateWindow(const WId wid) const; @@ -76,6 +79,7 @@ signals: void dragReady(QWidget *dragWidget); void requestUpdateEntryGeometries() const; + void windowCountChanged() const; #ifdef USE_AM void modeChanged(int) const; #else @@ -161,6 +165,7 @@ private: static QPoint MousePressPos; ScreenSpliter *m_screenSpliter; + DockInter *m_dockInter; }; #endif // APPITEM_H diff --git a/frame/item/appmultiitem.cpp b/frame/item/appmultiitem.cpp new file mode 100644 index 000000000..02f89f79b --- /dev/null +++ b/frame/item/appmultiitem.cpp @@ -0,0 +1,286 @@ +/* + * 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 "appitem.h" +#include "appmultiitem.h" +#include "imageutil.h" +#include "themeappicon.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct SHMInfo { + long shmid; + long width; + long height; + long bytesPerLine; + long format; + + struct Rect { + long x; + long y; + long width; + long height; + } rect; +}; + +AppMultiItem::AppMultiItem(AppItem *appItem, WId winId, const WindowInfo &windowInfo, QWidget *parent) + : DockItem(parent) + , m_appItem(appItem) + , m_windowInfo(windowInfo) + , m_entryInter(appItem->itemEntryInter()) + , m_winId(winId) + , m_menu(new QMenu(this)) +{ + initMenu(); + initConnection(); +} + +AppMultiItem::~AppMultiItem() +{ +} + +QSize AppMultiItem::suitableSize(int size) const +{ + return QSize(size, size); +} + +AppItem *AppMultiItem::appItem() const +{ + return m_appItem; +} + +quint32 AppMultiItem::winId() const +{ + return m_winId; +} + +const WindowInfo &AppMultiItem::windowInfo() const +{ + return m_windowInfo; +} + +DockItem::ItemType AppMultiItem::itemType() const +{ + return DockItem::AppMultiWindow; +} + +bool AppMultiItem::isKWinAvailable() const +{ + if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.KWin"))) { + QDBusInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Effects"), QStringLiteral("org.kde.kwin.Effects")); + QDBusReply reply = interface.call(QStringLiteral("isEffectLoaded"), "screenshot"); + + return reply.value(); + } + return false; +} + +QImage AppMultiItem::snapImage() const +{ + // 优先使用窗管进行窗口截图 + if (isKWinAvailable()) { + QDBusInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"), QStringLiteral("org.kde.kwin.Screenshot")); + + QList args; + args << QVariant::fromValue(m_winId); + args << QVariant::fromValue(quint32(width() - 20)); + args << QVariant::fromValue(quint32(height() - 20)); + + QImage image; + QDBusReply reply = interface.callWithArgumentList(QDBus::Block, QStringLiteral("screenshotForWindowExtend"), args); + if(reply.isValid()){ + const QString tmpFile = reply.value(); + if (QFile::exists(tmpFile)) { + image.load(tmpFile); + qDebug() << "reply: " << tmpFile; + QFile::remove(tmpFile); + } else { + qDebug() << "get current workspace bckground error, file does not exist : " << tmpFile; + } + } else { + qDebug() << "get current workspace bckground error: "<< reply.error().message(); + } + return image; + } + + // get window image from shm(only for deepin app) + SHMInfo *info = getImageDSHM(); + QImage image; + uchar *image_data = 0; + if (info) { + qDebug() << "get Image from dxcbplugin SHM..."; + image_data = (uchar *)shmat(info->shmid, 0, 0); + if ((qint64)image_data != -1) + return QImage(image_data, info->width, info->height, info->bytesPerLine, (QImage::Format)info->format); + + qDebug() << "invalid pointer of shm!"; + image_data = nullptr; + } + + QImage qimage; + XImage *ximage; + if (!image_data || qimage.isNull()) { + ximage = getImageXlib(); + if (!ximage) + return QImage(); + + qimage = QImage((const uchar *)(ximage->data), ximage->width, ximage->height, ximage->bytes_per_line, QImage::Format_RGB32); + } + + return image; +} + +SHMInfo *AppMultiItem::getImageDSHM() const +{ + const auto display = Utils::IS_WAYLAND_DISPLAY ? XOpenDisplay(nullptr) : QX11Info::display(); + if (!display) { + qWarning() << "Error: get display failed!"; + return nullptr; + } + + Atom atom_prop = XInternAtom(display, "_DEEPIN_DXCB_SHM_INFO", true); + if (!atom_prop) { + return nullptr; + } + + Atom actual_type_return_deepin_shm; + int actual_format_return_deepin_shm; + unsigned long nitems_return_deepin_shm; + unsigned long bytes_after_return_deepin_shm; + unsigned char *prop_return_deepin_shm; + + XGetWindowProperty(display, m_winId, atom_prop, 0, 32 * 9, false, AnyPropertyType, + &actual_type_return_deepin_shm, &actual_format_return_deepin_shm, &nitems_return_deepin_shm, + &bytes_after_return_deepin_shm, &prop_return_deepin_shm); + + return reinterpret_cast(prop_return_deepin_shm); +} + +XImage *AppMultiItem::getImageXlib() const +{ + const auto display = Utils::IS_WAYLAND_DISPLAY ? XOpenDisplay(nullptr) : QX11Info::display(); + if (!display) { + qWarning() << "Error: get display failed!"; + return nullptr; + } + + Window unused_window; + int unused_int; + unsigned unused_uint, w, h; + XGetGeometry(display, m_winId, &unused_window, &unused_int, &unused_int, &w, &h, &unused_uint, &unused_uint); + return XGetImage(display, m_winId, 0, 0, w, h, AllPlanes, ZPixmap); +} + +void AppMultiItem::initMenu() +{ + QAction *actionOpen = new QAction(m_menu); + actionOpen->setText(tr("Open")); + connect(actionOpen, &QAction::triggered, this, &AppMultiItem::onOpen); + m_menu->addAction(actionOpen); +} + +void AppMultiItem::initConnection() +{ + connect(m_entryInter, &DockEntryInter::CurrentWindowChanged, this, &AppMultiItem::onCurrentWindowChanged); +} + +void AppMultiItem::onOpen() +{ +#ifdef USE_AM + m_entryInter->ActiveWindow(m_winId); +#endif +} + +void AppMultiItem::onCurrentWindowChanged(uint32_t value) +{ + if (value != m_winId) + return; + + update(); +} + +void AppMultiItem::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setRenderHint(QPainter::SmoothPixmapTransform, true); + + if (m_snapImage.isNull()) { + m_snapImage = snapImage(); + } + + DStyleHelper dstyle(style()); + const int radius = dstyle.pixelMetric(DStyle::PM_FrameRadius); + QRect itemRect = rect(); + itemRect.marginsRemoved(QMargins(6, 6, 6, 6)); + QPixmap pixmapWindowIcon = QPixmap::fromImage(m_snapImage); + QPainterPath path; + path.addRoundedRect(rect(), radius, radius); + painter.fillPath(path, Qt::transparent); + + if (m_entryInter->currentWindow() == m_winId) { + QColor backColor = Qt::black; + backColor.setAlpha(255 * 0.8); + painter.fillPath(path, backColor); + } + + itemRect = m_snapImage.rect(); + int itemWidth = itemRect.width(); + int itemHeight = itemRect.height(); + int x = (rect().width() - itemWidth) / 2; + int y = (rect().height() - itemHeight) / 2; + painter.drawPixmap(QRect(x, y, itemWidth, itemHeight), pixmapWindowIcon); + + QPixmap pixmapAppIcon; + ThemeAppIcon::getIcon(pixmapAppIcon, m_entryInter->icon(), qMin(width(), height()) * 0.8); + if (!pixmapAppIcon.isNull()) { + // 绘制下方的图标,下方的小图标大约为应用图标的三分之一的大小 + //pixmap = pixmap.scaled(pixmap.width() * 0.3, pixmap.height() * 0.3); + QRect rectIcon = rect(); + int iconWidth = rectIcon.width() * 0.3; + int iconHeight = rectIcon.height() * 0.3; + rectIcon.setX((rect().width() - iconWidth) * 0.5); + rectIcon.setY(rect().height() - iconHeight); + rectIcon.setWidth(iconWidth); + rectIcon.setHeight(iconHeight); + painter.drawPixmap(rectIcon, pixmapAppIcon); + } +} + +void AppMultiItem::mouseReleaseEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { +#ifdef USE_AM + m_entryInter->ActiveWindow(m_winId); +#endif + } else { + QPoint currentPoint = QCursor::pos(); + m_menu->exec(currentPoint); + } +} diff --git a/frame/item/appmultiitem.h b/frame/item/appmultiitem.h new file mode 100644 index 000000000..36e261a89 --- /dev/null +++ b/frame/item/appmultiitem.h @@ -0,0 +1,74 @@ +/* + * 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 APPMULTIITEM_H +#define APPMULTIITEM_H + +#include "dockitem.h" +#include "dbusutil.h" + +struct SHMInfo; +struct _XImage; +typedef _XImage XImage; +class AppItem; + +class AppMultiItem : public DockItem +{ + Q_OBJECT + + friend class AppItem; + +public: + AppMultiItem(AppItem *appItem, WId winId, const WindowInfo &windowInfo, QWidget *parent = Q_NULLPTR); + ~AppMultiItem() override; + + QSize suitableSize(int size) const; + AppItem *appItem() const; + quint32 winId() const; + const WindowInfo &windowInfo() const; + + ItemType itemType() const override; + +protected: + void paintEvent(QPaintEvent *) override; + void mouseReleaseEvent(QMouseEvent *event) override; + +private: + bool isKWinAvailable() const; + QImage snapImage() const; + SHMInfo *getImageDSHM() const; + XImage *getImageXlib() const; + void initMenu(); + void initConnection(); + +private Q_SLOTS: + void onOpen(); + void onCurrentWindowChanged(uint32_t value); + +private: + AppItem *m_appItem; + WindowInfo m_windowInfo; + DockEntryInter *m_entryInter; + QImage m_snapImage; + WId m_winId; + QMenu *m_menu; +}; + +#endif // APPMULTIITEM_H diff --git a/frame/item/dockitem.h b/frame/item/dockitem.h index 922a9c38c..22b3badf4 100644 --- a/frame/item/dockitem.h +++ b/frame/item/dockitem.h @@ -48,7 +48,8 @@ public: Placeholder, TrayPlugin, // 托盘插件 QuickSettingPlugin, // 快捷设置区域插件 - StretchPlugin // 时尚模式下的固定在最右侧的插件,例如开关机插件 + StretchPlugin, // 时尚模式下的固定在最右侧的插件,例如开关机插件 + AppMultiWindow // APP的多开应用的窗口 }; public: diff --git a/frame/window/mainpanelcontrol.cpp b/frame/window/mainpanelcontrol.cpp index cd7e78da7..b67544204 100755 --- a/frame/window/mainpanelcontrol.cpp +++ b/frame/window/mainpanelcontrol.cpp @@ -36,6 +36,10 @@ #include "displaymanager.h" #include "recentapphelper.h" #include "toolapphelper.h" +#include "multiwindowhelper.h" +#include "mainwindow.h" +#include "appmultiitem.h" +#include "multiwindowhelper.h" #include #include @@ -89,7 +93,11 @@ MainPanelControl::MainPanelControl(QWidget *parent) , m_recentLayout(new QBoxLayout(QBoxLayout::LeftToRight, this)) , m_recentSpliter(new QLabel(this)) , m_toolAreaWidget(new QWidget(this)) - , m_toolLayout(new QBoxLayout(QBoxLayout::LeftToRight, m_toolAreaWidget)) + , m_toolAreaLayout(new QBoxLayout(QBoxLayout::LeftToRight, m_toolAreaWidget)) + , m_multiWindowWidget(new QWidget(m_toolAreaWidget)) + , m_multiWindowLayout(new QBoxLayout(QBoxLayout::LeftToRight, m_multiWindowWidget)) + , m_toolSonAreaWidget(new QWidget(m_toolAreaWidget)) + , m_toolSonLayout(new QBoxLayout(QBoxLayout::LeftToRight, m_toolSonAreaWidget)) , m_trayManagerWidget(new TrayManagerWindow(this)) , m_pluginLayout(new QBoxLayout(QBoxLayout::LeftToRight, this)) , m_desktopWidget(new DesktopWidget(this)) @@ -102,6 +110,7 @@ MainPanelControl::MainPanelControl(QWidget *parent) , m_dockInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this)) , m_recentHelper(new RecentAppHelper(m_appAreaSonWidget, m_recentAreaWidget, m_dockInter, this)) , m_toolHelper(new ToolAppHelper(m_pluginAreaWidget, m_toolAreaWidget, this)) + , m_multiHelper(new MultiWindowHelper(m_appAreaSonWidget, m_multiWindowWidget, this)) { initUI(); initConnection(); @@ -158,12 +167,27 @@ void MainPanelControl::initUI() m_mainPanelLayout->addWidget(m_recentSpliter); /* 工具应用 */ - m_toolAreaWidget->setObjectName("toolarea"); - m_toolAreaWidget->setAccessibleName("toolarea"); - m_toolAreaWidget->setLayout(m_toolLayout); - m_toolLayout->setSpacing(0); - m_toolLayout->setContentsMargins(0, 0, 0, 0); + // 包含窗口多开和工具组合 + m_toolAreaWidget->setObjectName("toolArea"); + m_toolAreaWidget->setAccessibleName("toolArea"); + m_toolAreaWidget->setLayout(m_toolAreaLayout); + m_toolAreaLayout->setContentsMargins(0, 0, 0, 0); + m_toolAreaLayout->setSpacing(0); m_mainPanelLayout->addWidget(m_toolAreaWidget); + // 多开窗口区域 + m_multiWindowWidget->setObjectName("multiWindow"); + m_multiWindowWidget->setAccessibleName("multiWindow"); + m_multiWindowWidget->setLayout(m_multiWindowLayout); + m_multiWindowLayout->setContentsMargins(0, 2, 0, 2); + m_multiWindowLayout->setSpacing(0); + m_toolAreaLayout->addWidget(m_multiWindowWidget); + // 工具应用区域-包含打开窗口区域和回收站区域 + m_toolSonAreaWidget->setObjectName("toolsonarea"); + m_toolSonAreaWidget->setAccessibleName("toolsonarea"); + m_toolSonAreaWidget->setLayout(m_toolSonLayout); + m_toolSonLayout->setSpacing(0); + m_toolSonLayout->setContentsMargins(0, 0, 0, 0); + m_toolAreaLayout->addWidget(m_toolSonAreaWidget); /* 托盘区域 */ m_trayAreaWidget->setObjectName("trayarea"); @@ -206,6 +230,7 @@ void MainPanelControl::initConnection() connect(m_recentHelper, &RecentAppHelper::dockAppVisibleChanged, this, &MainPanelControl::onDockAppVisibleChanged); connect(m_toolHelper, &ToolAppHelper::requestUpdate, this, &MainPanelControl::requestUpdate); connect(m_toolHelper, &ToolAppHelper::toolVisibleChanged, this, &MainPanelControl::onToolVisibleChanged); + connect(m_multiHelper, &MultiWindowHelper::requestUpdate, this, &MainPanelControl::requestUpdate); } /** @@ -220,6 +245,7 @@ void MainPanelControl::setDisplayMode(DisplayMode dislayMode) m_displayMode = dislayMode; m_recentHelper->setDisplayMode(dislayMode); m_toolHelper->setDisplayMode(dislayMode); + m_multiHelper->setDisplayMode(dislayMode); updateDisplayMode(); } @@ -244,6 +270,7 @@ void MainPanelControl::updateMainPanelLayout() m_recentLayout->setDirection(QBoxLayout::LeftToRight); m_trayAreaLayout->setContentsMargins(0, 10, 0, 10); m_pluginLayout->setContentsMargins(10, 0, 10, 0); + m_multiWindowLayout->setContentsMargins(0, 2, 0, 2); break; case Position::Right: case Position::Left: @@ -260,6 +287,7 @@ void MainPanelControl::updateMainPanelLayout() m_recentLayout->setDirection(QBoxLayout::TopToBottom); m_trayAreaLayout->setContentsMargins(10, 0, 10, 0); m_pluginLayout->setContentsMargins(0, 10, 0, 10); + m_multiWindowLayout->setContentsMargins(2, 0, 2, 0); break; } @@ -379,12 +407,12 @@ void MainPanelControl::updateAppAreaSonWidgetSize() m_appAreaSonWidget->setMaximumHeight(height()); m_appAreaSonWidget->setMaximumWidth(m_appAreaWidget->width()); m_recentAreaWidget->setFixedHeight(height()); - m_toolAreaWidget->setFixedHeight(height()); + //m_toolAreaWidget->setFixedHeight(height()); } else { m_appAreaSonWidget->setMaximumWidth(width()); m_appAreaSonWidget->setMaximumHeight(m_appAreaWidget->height()); m_recentAreaWidget->setFixedWidth(width()); - m_toolAreaWidget->setFixedWidth(width()); + //m_toolAreaWidget->setFixedWidth(width()); } m_appAreaSonWidget->adjustSize(); @@ -434,10 +462,13 @@ void MainPanelControl::insertItem(int index, DockItem *item) addTrayAreaItem(index, item); break; case DockItem::Plugins: - //addPluginAreaItem(index, item); m_toolHelper->addPluginItem(index, item); break; - default: break; + case DockItem::AppMultiWindow: + m_multiHelper->addMultiWindow(index, static_cast(item)); + break; + default: + break; } // 同removeItem处 注意:不能屏蔽此接口,否则会造成插件插入时无法显示 @@ -469,7 +500,11 @@ void MainPanelControl::removeItem(DockItem *item) case DockItem::Plugins: m_toolHelper->removePluginItem(item); break; - default: break; + case DockItem::AppMultiWindow: + m_multiHelper->removeMultiWindow(static_cast(item)); + break; + default: + break; } item->removeEventFilter(this); @@ -954,7 +989,7 @@ void MainPanelControl::updateModeChange() m_trayAreaWidget->setVisible(m_displayMode == DisplayMode::Efficient); m_traySpliter->setVisible(m_displayMode == DisplayMode::Efficient); m_pluginAreaWidget->setVisible(m_displayMode == DisplayMode::Efficient); - m_trayManagerWidget->setVisible(m_displayMode != DisplayMode::Efficient); + m_toolAreaWidget->setVisible(m_displayMode == DisplayMode::Fashion); onRecentVisibleChanged(m_recentHelper->recentIsVisible()); onDockAppVisibleChanged(m_recentHelper->dockAppIsVisible()); onToolVisibleChanged(m_toolHelper->toolIsVisible()); @@ -969,20 +1004,11 @@ void MainPanelControl::moveAppSonWidget() { QRect rect(QPoint(0, 0), m_appAreaSonWidget->size()); if (DisplayMode::Efficient == m_displayMode) { - switch (m_position) { - case Top: - case Bottom : - rect.moveTo(m_appAreaWidget->pos()); - break; - case Right: - case Left: - rect.moveTo(m_appAreaWidget->pos()); - break; - } + rect.moveTo(m_appAreaWidget->pos()); } else { switch (m_position) { case Top: - case Bottom : + case Bottom: rect.moveCenter(this->rect().center()); if (rect.right() > m_appAreaWidget->geometry().right()) { rect.moveRight(m_appAreaWidget->geometry().right()); @@ -1041,7 +1067,7 @@ QPainterPath MainPanelControl::areaPath() if (m_recentLayout->count() > 0) leftWidth += m_recentAreaWidget->width(); - if (m_toolLayout->count() > 0) + if (m_toolAreaLayout->count() > 0) leftWidth += m_toolAreaWidget->width(); int roundHeight = height(); @@ -1053,7 +1079,7 @@ QPainterPath MainPanelControl::areaPath() if (m_recentLayout->count() > 0) topHeight += m_recentAreaWidget->height(); - if (m_toolLayout->count() > 0) + if (m_toolAreaLayout->count() > 0) topHeight += m_toolAreaWidget->height(); path.addRoundedRect(QRect(0, 0, roundWidth, topHeight), radius, radius); @@ -1086,7 +1112,7 @@ QSize MainPanelControl::suitableSize(int screenSize, double deviceRatio) const // 减去右侧托盘和快捷设置还有插件区域的尺寸 totalLength -= (((m_position == Position::Top || m_position == Position::Bottom) ? traySuitableSize.width() : traySuitableSize.height()) / ratio); // 需要参与计算的图标的总数 - int iconCount = m_fixedAreaLayout->count() + m_appAreaSonLayout->count() + m_recentLayout->count() + m_toolLayout->count(); + int iconCount = m_fixedAreaLayout->count() + m_appAreaSonLayout->count() + m_recentLayout->count() + m_toolAreaLayout->count(); if (iconCount <= 0) { if (m_position == Position::Top || m_position == Position::Bottom) return QSize((static_cast((traySuitableSize.width() + 20) / ratio)), height()); @@ -1195,7 +1221,12 @@ void MainPanelControl::resizeDockIcon() // 减去右侧托盘和插件区域的宽度 totalLength -= ((m_position == Position::Top) || (m_position == Position::Bottom)) ? trayManagerSize.width() : trayManagerSize.height(); - iconCount = m_fixedAreaLayout->count() + m_appAreaSonLayout->count() + m_recentLayout->count(); + iconCount = m_fixedAreaLayout->count() + m_appAreaSonLayout->count(); + if (m_recentAreaWidget->isVisible()) + iconCount += m_recentLayout->count(); + + if (m_toolAreaWidget->isVisible()) + iconCount += m_toolSonLayout->count(); if (iconCount <= 0) return; @@ -1333,11 +1364,11 @@ void MainPanelControl::calcuDockIconSize(int w, int h, int traySize) m_recentSpliter->setFixedSize(int(h * 0.6), SPLITER_SIZE); } - for (int i = 0; i < m_appAreaSonLayout->count(); ++i) - m_appAreaSonLayout->itemAt(i)->widget()->setFixedSize(appItemSize, appItemSize); - // 时尚模式下判断是否需要显示最近打开的应用区域 if (m_displayMode == Dock::DisplayMode::Fashion) { + for (int i = 0; i < m_appAreaSonLayout->count(); ++i) + m_appAreaSonLayout->itemAt(i)->widget()->setFixedSize(appItemSize, appItemSize); + if (m_recentLayout->count() > 0) { for (int i = 0; i < m_recentLayout->count(); ++i) m_recentLayout->itemAt(i)->widget()->setFixedSize(appItemSize, appItemSize); @@ -1349,14 +1380,61 @@ void MainPanelControl::calcuDockIconSize(int w, int h, int traySize) m_recentAreaWidget->setFixedHeight(appItemSize * m_recentLayout->count()); } - if (m_toolLayout->count() > 0) { - for (int i = 0; i < m_toolLayout->count(); i++) - m_toolLayout->itemAt(i)->widget()->setFixedSize(appItemSize, appItemSize); + if (m_multiWindowLayout->count() > 0) { + QList multiSizes; + for (int i = 0; i < m_multiWindowLayout->count(); i++) { + // 因为多开窗口的长宽会不一样,因此,需要将当前的尺寸传入 + // 由它自己来计算自己的长宽尺寸 + AppMultiItem *appMultiItem = qobject_cast(m_multiWindowLayout->itemAt(i)->widget()); + if (!appMultiItem) + continue; - if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) - m_toolAreaWidget->setFixedWidth(appItemSize * m_toolLayout->count()); - else - m_toolAreaWidget->setFixedHeight(appItemSize * m_toolLayout->count()); + QSize size = appMultiItem->suitableSize(appItemSize); + appMultiItem->setFixedSize(size); + multiSizes << size; + } + // 计算多开窗口的尺寸 + int totalSize = 0; + if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) { + for (QSize size : multiSizes) + totalSize += size.width(); + + m_multiWindowWidget->setFixedSize(totalSize, appItemSize); + } else { + for (QSize size : multiSizes) + totalSize += size.height(); + + m_multiWindowWidget->setFixedSize(appItemSize, totalSize); + } + } else { + m_multiWindowWidget->setFixedSize(0, 0); + } + if (m_toolSonLayout->count() > 0) { + for (int i = 0; i < m_toolSonLayout->count(); i++) + m_toolSonLayout->itemAt(i)->widget()->setFixedSize(appItemSize, appItemSize); + + if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) { + m_toolSonAreaWidget->setFixedWidth(appItemSize * m_toolSonLayout->count()); + } else { + m_toolSonAreaWidget->setFixedHeight(appItemSize * m_toolSonLayout->count()); + } + } + + if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) + m_toolAreaWidget->setFixedWidth(m_multiWindowWidget->width() + m_toolSonAreaWidget->width()); + else + m_toolAreaWidget->setFixedHeight(m_multiWindowWidget->height() + m_toolSonAreaWidget->height()); + } else { + for (int i = 0; i < m_appAreaSonLayout->count(); ++i) { + DockItem *dockItem = qobject_cast(m_appAreaSonLayout->itemAt(i)->widget()); + if (!dockItem) + continue; + if (dockItem->itemType() == DockItem::ItemType::AppMultiWindow) { + AppMultiItem *appMultiItem = qobject_cast(dockItem); + dockItem->setFixedSize(appMultiItem->suitableSize(appItemSize)); + } else { + dockItem->setFixedSize(appItemSize, appItemSize); + } } } diff --git a/frame/window/mainpanelcontrol.h b/frame/window/mainpanelcontrol.h index 35c0bdd9f..ef13a72c9 100755 --- a/frame/window/mainpanelcontrol.h +++ b/frame/window/mainpanelcontrol.h @@ -43,6 +43,7 @@ class TrayManagerWindow; class DockScreen; class RecentAppHelper; class ToolAppHelper; +class MultiWindowHelper; class MainPanelControl : public QWidget { @@ -132,8 +133,12 @@ private: QWidget *m_recentAreaWidget; // 最近打开应用 QBoxLayout *m_recentLayout; QLabel *m_recentSpliter; // 最近打开应用区域分割线 - QWidget *m_toolAreaWidget; // 工具区域 - QBoxLayout *m_toolLayout; // 工具区域布局 + QWidget *m_toolAreaWidget; // 工具区域,用来存放多开窗口和回收站等 + QBoxLayout *m_toolAreaLayout; // 工具区域的布局 + QWidget *m_multiWindowWidget; // 多开窗口区域,用来存放多开窗口 + QBoxLayout *m_multiWindowLayout;// 用来存放多开窗口的布局 + QWidget *m_toolSonAreaWidget; // 工具区域,用来存放回收站等工具 + QBoxLayout *m_toolSonLayout; // 工具区域布局 TrayManagerWindow *m_trayManagerWidget; QBoxLayout *m_pluginLayout; // 插件区域布局 @@ -152,6 +157,7 @@ private: DockInter *m_dockInter; RecentAppHelper *m_recentHelper; ToolAppHelper *m_toolHelper; + MultiWindowHelper *m_multiHelper; }; #endif // MAINPANELCONTROL_H