fix: 任务栏代码结构优化解耦

原来的TrayManagerWindow的类是放到MainPanelWindow类里面作为它的一部分,导致窗管在显示的时候有很多问题
修改方案:
1、将左右侧区域拆分成两个窗体,让它们继承自相同的基类MainWindowBase。
2、左右区域公共的部分,例如圆角、展示区域、动画获取等,都在基类中实现或者通过接口返回
3、增加WindowManager类,管理所有的界面,WindowManager类无需知道具体子类的指针,只需要根据相应的接口来获取即可
4、所有的界面类在main.cpp中创建,调用WindowManager对象设置
5、拆分MultiScreenWorker类,使MultiScreenWorker类只关心任务栏相关的逻辑,无需关心窗体或界面

Log: 优化任务栏的显示问题
Influence: 打开任务栏,观察时尚模式下圆角,左右侧区域中间是否连接在一起等
Bug: https://pms.uniontech.com/bug-view-137267.html
Bug: https://pms.uniontech.com/bug-view-140029.html
Bug: https://pms.uniontech.com/bug-view-134527.html
Bug: https://pms.uniontech.com/bug-view-146743.html
Bug: https://pms.uniontech.com/bug-view-150293.html
Change-Id: I4266f6f8c983f61258b92834d93cdacd0221d7de
This commit is contained in:
donghualin 2022-08-25 19:31:31 +00:00
parent fc8294c46c
commit 1691e7188c
33 changed files with 2711 additions and 2017 deletions

View File

@ -5,6 +5,7 @@
#include "desktop_widget.h"
#include "tipswidget.h"
#include "dockpopupwindow.h"
#include "dragwidget.h"
#include "launcheritem.h"
#include "appitem.h"

View File

@ -22,16 +22,19 @@
#include "dbusdockadaptors.h"
#include "utils.h"
#include "dockitemmanager.h"
#include "windowmanager.h"
#include "proxyplugincontroller.h"
#include <QScreen>
#include <QDebug>
#include <QGSettings>
DBusDockAdaptors::DBusDockAdaptors(MainWindow* parent)
DBusDockAdaptors::DBusDockAdaptors(WindowManager* parent)
: QDBusAbstractAdaptor(parent)
, m_gsettings(Utils::SettingsPtr("com.deepin.dde.dock.mainwindow", QByteArray(), this))
, m_windowManager(parent)
{
connect(parent, &MainWindow::panelGeometryChanged, this, [=] {
connect(parent, &WindowManager::panelGeometryChanged, this, [ = ] {
emit DBusDockAdaptors::geometryChanged(geometry());
});
@ -74,19 +77,23 @@ DBusDockAdaptors::~DBusDockAdaptors()
}
MainWindow *DBusDockAdaptors::parent() const
{
return static_cast<MainWindow *>(QObject::parent());
}
void DBusDockAdaptors::callShow()
{
return parent()->callShow();
m_windowManager->callShow();
}
void DBusDockAdaptors::ReloadPlugins()
{
return parent()->reloadPlugins();
if (qApp->property("PLUGINSLOADED").toBool())
return;
// 发送事件,通知代理来加载插件
PluginLoadEvent event;
QCoreApplication::sendEvent(qApp, &event);
qApp->setProperty("PLUGINSLOADED", true);
// 退出安全模式
qApp->setProperty("safeMode", false);
}
QStringList DBusDockAdaptors::GetLoadedPlugins()
@ -120,7 +127,7 @@ QStringList DBusDockAdaptors::GetLoadedPlugins()
void DBusDockAdaptors::resizeDock(int offset, bool dragging)
{
parent()->resizeDock(offset, dragging);
m_windowManager->resizeDock(offset, dragging);
}
// 返回每个插件的识别Key(所以此值应始终不变)供个性化插件根据key去匹配每个插件对应的图标
@ -181,7 +188,7 @@ void DBusDockAdaptors::setPluginVisible(const QString &pluginName, bool visible)
QRect DBusDockAdaptors::geometry() const
{
return parent()->geometry();
return m_windowManager->geometry();
}
bool DBusDockAdaptors::showInPrimary() const

View File

@ -30,6 +30,8 @@
* Adaptor class for interface com.deepin.dde.Dock
*/
class QGSettings;
class WindowManager;
class DBusDockAdaptors: public QDBusAbstractAdaptor
{
Q_OBJECT
@ -69,11 +71,9 @@ class DBusDockAdaptors: public QDBusAbstractAdaptor
Q_PROPERTY(bool showInPrimary READ showInPrimary WRITE setShowInPrimary NOTIFY showInPrimaryChanged)
public:
explicit DBusDockAdaptors(MainWindow *parent);
explicit DBusDockAdaptors(WindowManager *parent);
virtual ~DBusDockAdaptors();
MainWindow *parent() const;
public Q_SLOTS: // METHODS
void callShow();
void ReloadPlugins();
@ -103,6 +103,7 @@ private:
private:
QGSettings *m_gsettings;
WindowManager *m_windowManager;
};
#endif //DBUSDOCKADAPTORS

View File

@ -26,6 +26,8 @@
#include "themeappicon.h"
#include "dockitemmanager.h"
#include "dockapplication.h"
#include "traymainwindow.h"
#include "windowmanager.h"
#include <QAccessible>
#include <QDir>
@ -221,30 +223,37 @@ int main(int argc, char *argv[])
// 在qApp中记录当前是否为安全模式如果为安全模式则无需加载插件在退出安全模式下才正常加载插件
// 此处设置这个属性必须在MainWindow创建之前因为在mainWindow中会创建加载插件的代理会在代理中根据这个属性来判断是否需要加载插件
bool isSafeMode = IsSaveMode();
qApp->setProperty("safeMode", isSafeMode);
bool disablePlugin = parser.isSet(disablePlugOption);
qApp->setProperty("safeMode", (isSafeMode || disablePlugin));
MultiScreenWorker multiScreenWorker;
MainWindow mainWindow(&multiScreenWorker);
TrayMainWindow trayMainWindow(&multiScreenWorker);
WindowManager windowManager(&multiScreenWorker);
// 保证添加窗口的先后顺序,先添加的窗口显示在左边,后添加的窗口显示在右边
windowManager.addWindow(&mainWindow);
windowManager.addWindow(&trayMainWindow);
// 注册任务栏的DBus服务
MainWindow mw;
DBusDockAdaptors adaptor(&mw);
if(Utils::IS_WAYLAND_DISPLAY) {
mw.setAttribute(Qt::WA_NativeWindow);
mw.windowHandle()->setProperty("_d_dwayland_window-type", "dock");
}
DBusDockAdaptors adaptor(&windowManager);
QDBusConnection::sessionBus().registerService("com.deepin.dde.Dock");
QDBusConnection::sessionBus().registerObject("/com/deepin/dde/Dock", "com.deepin.dde.Dock", &mw);
QDBusConnection::sessionBus().registerObject("/com/deepin/dde/Dock", "com.deepin.dde.Dock", &windowManager);
// 当任务栏以-r参数启动时设置CANSHOW未false之后调用launch不显示任务栏
qApp->setProperty("CANSHOW", !parser.isSet(runOption));
mw.launch();
windowManager.launch();
mainWindow.setVisible(true);
// 判断是否进入安全模式,是否带有入参 -x
if (!isSafeMode && !parser.isSet(disablePlugOption)) {
if (!isSafeMode && !disablePlugin) {
qApp->setProperty("PLUGINSLOADED", true);
} else {
mw.sendNotifications();
windowManager.sendNotifications();
}
return app.exec();

64
frame/util/dockscreen.cpp Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "dockscreen.h"
#include "displaymanager.h"
DockScreen::DockScreen()
: m_primary(DisplayManager::instance()->primary())
, m_currentScreen(m_primary)
, m_lastScreen(m_primary)
{
}
DockScreen *DockScreen::instance()
{
static DockScreen instance;
return &instance;
}
const QString &DockScreen::current() const
{
return m_currentScreen;
}
const QString &DockScreen::last() const
{
return m_lastScreen;
}
const QString &DockScreen::primary() const
{
return m_primary;
}
void DockScreen::updateDockedScreen(const QString &screenName)
{
m_lastScreen = m_currentScreen;
m_currentScreen = screenName;
}
void DockScreen::updatePrimary(const QString &primary)
{
m_primary = primary;
if (m_currentScreen.isEmpty()) {
updateDockedScreen(primary);
}
}

50
frame/util/dockscreen.h Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef DOCKSCREEN_H
#define DOCKSCREEN_H
#include <QString>
/**
* @brief The DockScreen class
*
*/
class DockScreen
{
public:
static DockScreen *instance();
const QString &current() const;
const QString &last() const;
const QString &primary() const;
void updateDockedScreen(const QString &screenName);
void updatePrimary(const QString &primary);
private:
explicit DockScreen();
private:
QString m_primary;
QString m_currentScreen;
QString m_lastScreen;
};
#endif // DOCKSCREEN_H

View File

@ -32,14 +32,13 @@
#define DIS_INS DisplayManager::instance()
MenuWorker::MenuWorker(DockInter *dockInter,QWidget *parent)
MenuWorker::MenuWorker(QObject *parent)
: QObject(parent)
, m_dockInter(dockInter)
, m_autoHide(true)
, m_dockInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this))
{
}
QMenu *MenuWorker::createMenu(QMenu *settingsMenu)
void MenuWorker::createMenu(QMenu *settingsMenu)
{
settingsMenu->setAccessibleName("settingsmenu");
settingsMenu->setTitle("Settings Menu");
@ -152,8 +151,6 @@ QMenu *MenuWorker::createMenu(QMenu *settingsMenu)
}
delete menuSettings;
menuSettings = nullptr;
return settingsMenu;
}
void MenuWorker::onDockSettingsTriggered()
@ -175,31 +172,17 @@ void MenuWorker::onDockSettingsTriggered()
#endif
}
void MenuWorker::showDockSettingsMenu(QMenu *menu)
void MenuWorker::exec()
{
// 菜单功能被禁用
static const QGSettings *setting = Utils::ModuleSettingsPtr("menu", QByteArray(), this);
static const QGSettings *setting = Utils::ModuleSettingsPtr("menu", QByteArray());
if (setting && setting->keys().contains("enable") && !setting->get("enable").toBool()) {
return;
}
// 菜单将要被打开
setAutoHide(false);
menu = createMenu(menu);
menu->exec(QCursor::pos());
// 菜单已经关闭
setAutoHide(true);
delete menu;
menu = nullptr;
}
void MenuWorker::setAutoHide(const bool autoHide)
{
if (m_autoHide == autoHide)
return;
m_autoHide = autoHide;
emit autoHideChanged(m_autoHide);
QMenu menu;
if (Utils::IS_WAYLAND_DISPLAY)
menu.setWindowFlag(Qt::FramelessWindowHint);
createMenu(&menu);
menu.exec(QCursor::pos());
}

View File

@ -20,11 +20,12 @@
*/
#ifndef MENUWORKER_H
#define MENUWORKER_H
#include <QObject>
#include "constants.h"
#include "dbusutil.h"
#include <QObject>
class QMenu;
class QGSettings;
/**
@ -34,25 +35,18 @@ class MenuWorker : public QObject
{
Q_OBJECT
public:
explicit MenuWorker(DockInter *dockInter,QWidget *parent = nullptr);
explicit MenuWorker(QObject *parent = nullptr);
void showDockSettingsMenu(QMenu *menu);
signals:
void autoHideChanged(const bool autoHide) const;
public slots:
void setAutoHide(const bool autoHide);
void exec();
private:
QMenu *createMenu(QMenu *settingsMenu);
void createMenu(QMenu *settingsMenu);
private slots:
void onDockSettingsTriggered();
private:
DockInter *m_dockInter;
bool m_autoHide;
};
#endif // MENUWORKER_H

File diff suppressed because it is too large Load Diff

View File

@ -50,6 +50,9 @@ DGUI_USE_NAMESPACE
*
*/
#define DRAG_AREA_SIZE (5)
#define DOCKSPACE (WINDOWMARGIN * 2)
using XEventMonitor = ::com::deepin::api::XEventMonitor;
using DBusLuncher = ::com::deepin::dde::Launcher;
@ -59,46 +62,13 @@ class QWidget;
class QTimer;
class MainWindow;
class QGSettings;
/**
* @brief The DockScreen class
*
*/
class DockScreen
{
public:
explicit DockScreen(const QString &primary)
: m_currentScreen(primary)
, m_lastScreen(primary)
, m_primary(primary)
{}
inline const QString &current() const {return m_currentScreen;}
inline const QString &last() const {return m_lastScreen;}
inline const QString &primary() const {return m_primary;}
void updateDockedScreen(const QString &screenName)
{
m_lastScreen = m_currentScreen;
m_currentScreen = screenName;
}
void updatePrimary(const QString &primary)
{
m_primary = primary;
if (m_currentScreen.isEmpty()) {
updateDockedScreen(primary);
}
}
private:
QString m_currentScreen;
QString m_lastScreen;
QString m_primary;
};
class TrayMainWindow;
class MenuWorker;
class MultiScreenWorker : public QObject
{
Q_OBJECT
public:
enum Flag {
Motion = 1 << 0,
@ -106,11 +76,6 @@ public:
Key = 1 << 2
};
enum AniAction {
Show = 0,
Hide
};
enum RunState {
ShowAnimationStart = 0x1, // 单次显示动画正在运行状态
HideAnimationStart = 0x2, // 单次隐藏动画正在运行状态
@ -119,8 +84,7 @@ public:
MousePress = 0x10, // 当前鼠标是否被按下
TouchPress = 0x20, // 当前触摸屏下是否按下
LauncherDisplay = 0x40, // 启动器是否显示
DockIsShowing = 0x80, // 任务栏正在显示
DockIsDraging = 0x100, // 任务栏正在拖拽
DockIsDraging = 0x80, // 任务栏正在拖拽
// 如果要添加新的状态,可以在上面添加
RunState_Mask = 0xffffffff,
@ -128,48 +92,41 @@ public:
typedef QFlags<RunState> RunStates;
MultiScreenWorker(QWidget *parent, DWindowManagerHelper *helper);
void initShow();
explicit MultiScreenWorker(QObject *parent = Q_NULLPTR);
~MultiScreenWorker() override;
DockInter *dockInter() { return m_dockInter; }
void updateDaemonDockSize(const int &dockSize);
inline bool testState(RunState state) { return (m_state & state); }
void setStates(RunStates state, bool on = true);
inline const QString &lastScreen() { return m_ds.last(); }
inline const QString &deskScreen() { return m_ds.current(); }
inline const Position &position() { return m_position; }
inline const DisplayMode &displayMode() { return m_displayMode; }
inline const HideMode &hideMode() { return m_hideMode; }
inline const HideState &hideState() { return m_hideState; }
inline quint8 opacity() { return m_opacity * 255; }
QRect dockRect(const QString &screenName, const Position &pos, const HideMode &hideMode, const DisplayMode &displayMode);
QRect dockRect(const QString &screenName);
QRect getDockShowMinGeometry(const QString &screenName, bool withoutScale = false);
signals:
void opacityChanged(const quint8 value) const;
void displayModeChanegd();
void displayModeChanged(const Dock::DisplayMode &);
// 更新监视区域
void requestUpdateRegionMonitor(); // 更新监听区域
void requestUpdateFrontendGeometry(); //!!! 给后端的区域不能为是或宽度为0的区域,否则会带来HideState死循环切换的bug
void requestNotifyWindowManager();
void requestUpdatePosition(const Position &fromPos, const Position &toPos);
void requestUpdateLayout(); // 界面需要根据任务栏更新布局的方向
void requestUpdateDragArea(); // 更新拖拽区域
void requestUpdateMonitorInfo(); // 屏幕信息发生变化,需要更新任务栏大小,拖拽区域,所在屏幕,监控区域,通知窗管,通知后端,
void requestStopShowAni();
void requestStopHideAni();
// 用来通知WindowManager的信号
void requestUpdateDockGeometry(const Dock::HideMode &hideMode);
void positionChanged(const Dock::Position &position);
void requestUpdateDockEntry();
void requestPlayAnimation(const QString &screenName, const Position &position, const Dock::AniAction &animation, bool containMouse = false, bool updatePos = false);
void requestChangeDockPosition(const QString &fromScreen, const QString &toScreen, const Position &fromPos, const Position &toPos);
public slots:
void onAutoHideChanged(bool autoHide);
void updateDaemonDockSize(int dockSize);
void onAutoHideChanged(const bool autoHide);
void onRequestUpdateRegionMonitor();
#ifndef USE_AM
@ -181,16 +138,10 @@ private slots:
void onRegionMonitorChanged(int x, int y, const QString &key);
void onExtralRegionMonitorChanged(int x, int y, const QString &key);
// Animation
void showAniFinished();
void hideAniFinished();
void updateDisplay();
void onWindowSizeChanged(uint value);
void primaryScreenChanged();
void updateParentGeometry(const QVariant &value, const Position &pos);
void updateParentGeometry(const QVariant &value);
void onPrimaryScreenChanged();
// 任务栏属性变化
void onPositionChanged(int position);
@ -199,11 +150,6 @@ private slots:
void onHideStateChanged(int state);
void onOpacityChanged(const double value);
// 通知后端任务栏所在位置
void onRequestUpdateFrontendGeometry();
void onRequestUpdateLayout();
void onRequestNotifyWindowManager();
void onRequestUpdatePosition(const Position &fromPos, const Position &toPos);
void onRequestUpdateMonitorInfo();
void onRequestDelayShowDock();
@ -214,46 +160,33 @@ private slots:
void onDelayAutoHideChanged();
// 子部件尺寸发生变化
void onChildSizeChanged();
private:
MainWindow *parent();
// 初始化数据信息
void initMembers();
void initDockMode();
void initConnection();
void initUI();
void initDisplayData();
void reInitDisplayData();
void displayAnimation(const QString &screen, const Position &pos, AniAction act);
void displayAnimation(const QString &screen, AniAction act);
void tryToShowDock(int eventX, int eventY);
void changeDockPosition(QString fromScreen, QString toScreen, const Position &fromPos, const Position &toPos);
QString getValidScreen(const Position &pos);
void resetDockScreen();
void checkDaemonDockService();
void checkXEventMonitorService();
QRect dockRectWithoutScale(const QString &screenName, const Position &pos, const HideMode &hideMode, const DisplayMode &displayMode);
QString getValidScreen(const Position &pos);
QRect getDockShowGeometry(const QString &screenName, const Position &pos, const DisplayMode &displaymode, bool withoutScale = false);
QRect getDockHideGeometry(const QString &screenName, const Position &pos, const DisplayMode &displaymode, bool withoutScale = false);
bool isCursorOut(int x, int y);
QScreen *screenByName(const QString &screenName);
bool onScreenEdge(const QString &screenName, const QPoint &point);
const QPoint rawXPosition(const QPoint &scaledPos);
static bool isCopyMode();
private:
QWidget *m_parent;
DWindowManagerHelper *m_wmHelper;
// monitor screen
XEventMonitor *m_eventInter;
XEventMonitor *m_extralEventInter;
@ -267,8 +200,6 @@ private:
QTimer *m_monitorUpdateTimer;
QTimer *m_delayWakeTimer; // sp3需求切换屏幕显示延时默认2秒唤起任务栏
DockScreen m_ds; // 屏幕名称信息
// 任务栏属性
double m_opacity;
Position m_position;

View File

@ -122,10 +122,15 @@ void DateTimeDisplayer::updatePolicy()
}
}
QSize DateTimeDisplayer::suitableSize()
QSize DateTimeDisplayer::suitableSize() const
{
DateTimeInfo info = dateTimeInfo();
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) {
return suitableSize(m_position);
}
QSize DateTimeDisplayer::suitableSize(const Dock::Position &position) const
{
DateTimeInfo info = dateTimeInfo(position);
if (position == Dock::Position::Top || position == Dock::Position::Bottom) {
int width = info.m_timeRect.width() + info.m_dateRect.width() + 16;
return QSize(width, height());
}
@ -151,7 +156,7 @@ void DateTimeDisplayer::mouseReleaseEvent(QMouseEvent *event)
.method("Toggle").call();
}
QString DateTimeDisplayer::getTimeString() const
QString DateTimeDisplayer::getTimeString(const Dock::Position &position) const
{
QString tFormat = QString("hh:mm");
int type = m_timedateInter->shortTimeFormat();
@ -159,7 +164,7 @@ QString DateTimeDisplayer::getTimeString() const
tFormat = timeFormat[type];
if (!m_timedateInter->use24HourFormat()) {
if (m_position == Dock::Top || m_position == Dock::Bottom)
if (position == Dock::Top || position == Dock::Bottom)
tFormat = tFormat.append(" AP");
else
tFormat = tFormat.append("\nAP");
@ -169,13 +174,18 @@ QString DateTimeDisplayer::getTimeString() const
}
QString DateTimeDisplayer::getDateString() const
{
return getDateString(m_position);
}
QString DateTimeDisplayer::getDateString(const Dock::Position &position) const
{
int type = m_timedateInter->shortDateFormat();
QString shortDateFormat = "yyyy-MM-dd";
if (dateFormat.contains(type))
shortDateFormat = dateFormat.value(type);
// 如果是左右方向,则不显示年份
if (m_position == Dock::Position::Left || m_position == Dock::Position::Right) {
if (position == Dock::Position::Left || position == Dock::Position::Right) {
static QStringList yearStrList{"yyyy/", "yyyy-", "yyyy.", "yy/", "yy-", "yy."};
for (int i = 0; i < yearStrList.size() ; i++) {
const QString &yearStr = yearStrList[i];
@ -189,16 +199,16 @@ QString DateTimeDisplayer::getDateString() const
return QDateTime::currentDateTime().toString(shortDateFormat);
}
DateTimeDisplayer::DateTimeInfo DateTimeDisplayer::dateTimeInfo()
DateTimeDisplayer::DateTimeInfo DateTimeDisplayer::dateTimeInfo(const Dock::Position &position) const
{
DateTimeInfo info;
info.m_timeRect = rect();
info.m_dateRect = rect();
info.m_time = getTimeString();
info.m_date = getDateString();
info.m_time = getTimeString(position);
info.m_date = getDateString(position);
if (m_position == Dock::Top || m_position == Dock::Bottom) {
if (position == Dock::Top || position == Dock::Bottom) {
int timeWidth = QFontMetrics(timeFont()).boundingRect(info.m_time).width() + 3;
int dateWidth = QFontMetrics(m_dateFont).boundingRect(info.m_date).width() + 2;
info.m_timeRect = QRect(ITEMSPACE, 0, timeWidth, height());
@ -243,7 +253,7 @@ void DateTimeDisplayer::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e);
DateTimeInfo info = dateTimeInfo();
DateTimeInfo info = dateTimeInfo(m_position);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
@ -383,3 +393,8 @@ void DateTimeDisplayer::updateLastData(const DateTimeInfo &info)
else
m_currentSize = dateTimeSize.height();
}
QString DateTimeDisplayer::getTimeString() const
{
return getTimeString(m_position);
}

View File

@ -52,7 +52,8 @@ public:
~DateTimeDisplayer() override;
void setPositon(Dock::Position position);
void setOneRow(bool oneRow);
QSize suitableSize();
QSize suitableSize() const;
QSize suitableSize(const Dock::Position &position) const;
Q_SIGNALS:
void requestUpdate(); // 当日期时间格式发生变化的时候,需要通知外面来更新窗口尺寸
@ -67,11 +68,13 @@ protected:
private:
void updatePolicy();
DateTimeInfo dateTimeInfo();
DateTimeInfo dateTimeInfo(const Dock::Position &position) const;
void updateLastData(const DateTimeInfo &info);
QString getTimeString() const;
QString getTimeString(const Dock::Position &position) const;
QString getDateString() const;
QString getDateString(const Dock::Position &position) const;
QPoint tipsPoint() const;
QFont timeFont() const;

View File

@ -0,0 +1,125 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "dragwidget.h"
#include "utils.h"
#include "constants.h"
#include <QCoreApplication>
#include <QMouseEvent>
DragWidget::DragWidget(QWidget *parent)
: QWidget(parent)
, m_dragStatus(false)
{
setObjectName("DragWidget");
}
bool DragWidget::isDraging() const
{
return m_dragStatus;
}
void DragWidget::onTouchMove(double scaleX, double scaleY)
{
Q_UNUSED(scaleX);
Q_UNUSED(scaleY);
static QPoint lastPos;
QPoint curPos = QCursor::pos();
if (lastPos == curPos) {
return;
}
lastPos = curPos;
qApp->postEvent(this, new QMouseEvent(QEvent::MouseMove, mapFromGlobal(curPos)
, QPoint(), curPos, Qt::LeftButton, Qt::LeftButton
, Qt::NoModifier, Qt::MouseEventSynthesizedByApplication));
}
void DragWidget::mousePressEvent(QMouseEvent *event)
{
// qt转发的触屏按下信号不进行响应
if (event->source() == Qt::MouseEventSynthesizedByQt)
return;
if (event->button() == Qt::LeftButton) {
m_resizePoint = event->globalPos();
m_dragStatus = true;
this->grabMouse();
}
}
void DragWidget::mouseMoveEvent(QMouseEvent *)
{
if (m_dragStatus) {
QPoint offset = QPoint(QCursor::pos() - m_resizePoint);
emit dragPointOffset(offset);
}
}
void DragWidget::mouseReleaseEvent(QMouseEvent *)
{
if (!m_dragStatus)
return;
m_dragStatus = false;
releaseMouse();
emit dragFinished();
}
void DragWidget::enterEvent(QEvent *)
{
if (Utils::IS_WAYLAND_DISPLAY)
updateCursor();
else
QApplication::setOverrideCursor(cursor());
}
void DragWidget::leaveEvent(QEvent *)
{
QApplication::setOverrideCursor(Qt::ArrowCursor);
}
void DragWidget::updateCursor()
{
QString theme = Utils::SettingValue("com.deepin.xsettings", "/com/deepin/xsettings/", "gtk-cursor-theme-name", "bloom").toString();
int cursorSize = Utils::SettingValue("com.deepin.xsettings", "/com/deepin/xsettings/", "gtk-cursor-theme-size", 24).toInt();
Dock::Position position = static_cast<Dock::Position>(qApp->property("position").toInt());
static QString lastTheme;
static int lastPosition = -1;
static int lastCursorSize = -1;
if (theme != lastTheme || position != lastPosition || cursorSize != lastCursorSize) {
lastTheme = theme;
lastPosition = position;
lastCursorSize = cursorSize;
const char* cursorName = (position == Dock::Position::Bottom || position == Dock::Position::Top) ? "v_double_arrow" : "h_double_arrow";
QCursor *newCursor = ImageUtil::loadQCursorFromX11Cursor(theme.toStdString().c_str(), cursorName, cursorSize);
if (!newCursor)
return;
setCursor(*newCursor);
static QCursor *lastCursor = nullptr;
if (lastCursor)
delete lastCursor;
lastCursor = newCursor;
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef DRAGWIDGET_H
#define DRAGWIDGET_H
#include <QWidget>
class DragWidget : public QWidget
{
Q_OBJECT
public:
explicit DragWidget(QWidget *parent = nullptr);
bool isDraging() const;
public Q_SLOTS:
void onTouchMove(double scaleX, double scaleY);
Q_SIGNALS:
void dragPointOffset(QPoint);
void dragFinished();
protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *) override;
void mouseReleaseEvent(QMouseEvent *) override;
void enterEvent(QEvent *) override;
void leaveEvent(QEvent *) override;
private:
void updateCursor();
private:
bool m_dragStatus;
QPoint m_resizePoint;
};
#endif // DRAGWIDGET_H

View File

@ -31,7 +31,6 @@
#include "utils.h"
#include "desktop_widget.h"
#include "imageutil.h"
#include "traymanagerwindow.h"
#include "multiscreenworker.h"
#include "displaymanager.h"
#include "recentapphelper.h"
@ -39,7 +38,7 @@
#include "multiwindowhelper.h"
#include "mainwindow.h"
#include "appmultiitem.h"
#include "multiwindowhelper.h"
#include "dockscreen.h"
#include <QDrag>
#include <QTimer>
@ -66,16 +65,10 @@
#define PLUGIN_MAX_SIZE 40
#define PLUGIN_MIN_SIZE 20
#define DESKTOP_SIZE 10
// 任务栏圆角最小的时候,任务栏的高度值
#define MINRADIUSSIZE 46
// 任务栏圆角最小值和最大值的差值
#define MAXDIFFVALUE 6
// 最小圆角值
#define MINRADIUS 12
DWIDGET_USE_NAMESPACE
MainPanelControl::MainPanelControl(QWidget *parent)
MainPanelControl::MainPanelControl(DockInter *dockInter, QWidget *parent)
: QWidget(parent)
, m_mainPanelLayout(new QBoxLayout(QBoxLayout::LeftToRight, this))
, m_fixedAreaWidget(new QWidget(this))
@ -98,7 +91,6 @@ MainPanelControl::MainPanelControl(QWidget *parent)
, 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))
, m_position(Position::Bottom)
@ -106,10 +98,9 @@ MainPanelControl::MainPanelControl(QWidget *parent)
, m_appDragWidget(nullptr)
, m_displayMode(Efficient)
, m_tray(nullptr)
, m_dockScreen(nullptr)
, m_dockInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this))
, m_dockInter(dockInter)
, m_recentHelper(new RecentAppHelper(m_appAreaSonWidget, m_recentAreaWidget, m_dockInter, this))
, m_toolHelper(new ToolAppHelper(m_pluginAreaWidget, m_toolAreaWidget, this))
, m_toolHelper(new ToolAppHelper(m_pluginAreaWidget, m_toolSonAreaWidget, this))
, m_multiHelper(new MultiWindowHelper(m_appAreaSonWidget, m_multiWindowWidget, this))
{
initUI();
@ -161,6 +152,7 @@ void MainPanelControl::initUI()
m_recentAreaWidget->setLayout(m_recentLayout);
m_recentLayout->setSpacing(0);
m_recentLayout->setContentsMargins(0, 0, 0, 0);
m_recentLayout->setAlignment(Qt::AlignCenter);
m_mainPanelLayout->addWidget(m_recentAreaWidget);
m_recentSpliter->setObjectName("spliter_recent");
@ -206,10 +198,6 @@ void MainPanelControl::initUI()
m_pluginLayout->setContentsMargins(0, 0, 0, 0);
m_mainPanelLayout->addWidget(m_pluginAreaWidget, 0, Qt::AlignCenter);
/* 时尚模式下右侧的插件区域 */
m_mainPanelLayout->addSpacing(15);
m_mainPanelLayout->addWidget(m_trayManagerWidget);
/* 桌面预览 */
m_desktopWidget->setObjectName("showdesktoparea");
m_mainPanelLayout->addWidget(m_desktopWidget);
@ -224,7 +212,6 @@ void MainPanelControl::initUI()
void MainPanelControl::initConnection()
{
connect(m_trayManagerWidget, &TrayManagerWindow::requestUpdate, this, &MainPanelControl::onRequestUpdate);
connect(m_recentHelper, &RecentAppHelper::requestUpdate, this, &MainPanelControl::requestUpdate);
connect(m_recentHelper, &RecentAppHelper::recentVisibleChanged, this, &MainPanelControl::onRecentVisibleChanged);
connect(m_recentHelper, &RecentAppHelper::dockAppVisibleChanged, this, &MainPanelControl::onDockAppVisibleChanged);
@ -261,13 +248,15 @@ void MainPanelControl::updateMainPanelLayout()
m_appAreaWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_pluginAreaWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_trayAreaWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
m_trayManagerWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
m_mainPanelLayout->setDirection(QBoxLayout::LeftToRight);
m_fixedAreaLayout->setDirection(QBoxLayout::LeftToRight);
m_pluginLayout->setDirection(QBoxLayout::LeftToRight);
m_trayAreaLayout->setDirection(QBoxLayout::LeftToRight);
m_appAreaSonLayout->setDirection(QBoxLayout::LeftToRight);
m_recentLayout->setDirection(QBoxLayout::LeftToRight);
m_multiWindowLayout->setDirection(QBoxLayout::LeftToRight);
m_toolAreaLayout->setDirection(QBoxLayout::LeftToRight);
m_toolSonLayout->setDirection(QBoxLayout::LeftToRight);
m_trayAreaLayout->setContentsMargins(0, 10, 0, 10);
m_pluginLayout->setContentsMargins(10, 0, 10, 0);
m_multiWindowLayout->setContentsMargins(0, 2, 0, 2);
@ -278,13 +267,15 @@ void MainPanelControl::updateMainPanelLayout()
m_appAreaWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_pluginAreaWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_trayAreaWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_trayManagerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_mainPanelLayout->setDirection(QBoxLayout::TopToBottom);
m_fixedAreaLayout->setDirection(QBoxLayout::TopToBottom);
m_pluginLayout->setDirection(QBoxLayout::TopToBottom);
m_trayAreaLayout->setDirection(QBoxLayout::TopToBottom);
m_appAreaSonLayout->setDirection(QBoxLayout::TopToBottom);
m_recentLayout->setDirection(QBoxLayout::TopToBottom);
m_multiWindowLayout->setDirection(QBoxLayout::TopToBottom);
m_toolAreaLayout->setDirection(QBoxLayout::TopToBottom);
m_toolSonLayout->setDirection(QBoxLayout::TopToBottom);
m_trayAreaLayout->setContentsMargins(10, 0, 10, 0);
m_pluginLayout->setContentsMargins(0, 10, 0, 10);
m_multiWindowLayout->setContentsMargins(2, 0, 2, 0);
@ -364,14 +355,6 @@ void MainPanelControl::resizeEvent(QResizeEvent *event)
QWidget::resizeEvent(event);
resizeDesktopWidget();
resizeDockIcon();
resetRadius();
}
void MainPanelControl::resetRadius()
{
int size = ((m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) ? height() : width());
int radius = qMin(MAXDIFFVALUE, qMax(size - MINRADIUSSIZE, 0)) + MINRADIUS;
qApp->setProperty("EffectBorderRadius", radius);
}
/** 当用户从最近使用区域拖动应用到左侧应用区域的时候,将该应用驻留
@ -407,12 +390,10 @@ void MainPanelControl::updateAppAreaSonWidgetSize()
m_appAreaSonWidget->setMaximumHeight(height());
m_appAreaSonWidget->setMaximumWidth(m_appAreaWidget->width());
m_recentAreaWidget->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_appAreaSonWidget->adjustSize();
@ -429,10 +410,7 @@ void MainPanelControl::setPositonValue(Dock::Position position)
return;
m_position = position;
QMetaObject::invokeMethod(this, [ this ] {
m_trayManagerWidget->setPositon(m_position);
updateMainPanelLayout();
}, Qt::QueuedConnection);
QMetaObject::invokeMethod(this, &MainPanelControl::updateMainPanelLayout, Qt::QueuedConnection);
}
/**向任务栏插入各类应用,并将属于同一个应用的窗口合并到同一个应用图标
@ -903,7 +881,6 @@ void MainPanelControl::startDrag(DockItem *dockItem)
if (item->itemType() == DockItem::App) {
// 判断是否在回收站区域, 如果在回收站区域,则移除驻留
PluginsItem *trashItem = m_toolHelper->trashPlugin();
if (!trashItem)
return;
@ -1060,49 +1037,9 @@ void MainPanelControl::updatePluginsLayout()
}
}
}
m_trayManagerWidget->updateLayout();
}
void MainPanelControl::setDockScreen(DockScreen *dockScreen)
{
m_dockScreen = dockScreen;
}
QPainterPath MainPanelControl::areaPath()
{
if (m_displayMode == DisplayMode::Efficient)
return QPainterPath();
int radius = qApp->property("EffectBorderRadius").toInt();
QPainterPath path;
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) {
int leftWidth = m_fixedAreaWidget->width() + m_fixedSpliter->width() + m_appAreaWidget->width();
if (m_recentLayout->count() > 0)
leftWidth += m_recentAreaWidget->width();
if (m_toolAreaLayout->count() > 0)
leftWidth += m_toolAreaWidget->width();
int roundHeight = height();
path.addRoundedRect(QRect(0, 0, leftWidth, roundHeight), radius, radius);
path.addRoundedRect(QRect(m_trayManagerWidget->x(), 0, m_trayManagerWidget->width(), roundHeight), radius, radius);
} else {
int roundWidth = width();
int topHeight = m_fixedAreaWidget->height() + m_fixedSpliter->height() + m_appAreaWidget->height();
if (m_recentLayout->count() > 0)
topHeight += m_recentAreaWidget->height();
if (m_toolAreaLayout->count() > 0)
topHeight += m_toolAreaWidget->height();
path.addRoundedRect(QRect(0, 0, roundWidth, topHeight), radius, radius);
path.addRoundedRect(QRect(0, m_trayManagerWidget->y(), roundWidth, m_trayManagerWidget->height()), radius, radius);
}
return path;
}
QSize MainPanelControl::suitableSize(int screenSize, double deviceRatio) const
QSize MainPanelControl::suitableSize(const Position &position, int screenSize, double deviceRatio) const
{
if (screenSize <= 0)
return QSize(-1, -1);
@ -1111,60 +1048,85 @@ QSize MainPanelControl::suitableSize(int screenSize, double deviceRatio) const
if (ratio <= 0)
ratio = qApp->devicePixelRatio();
int dockSize = ((position == Position::Top || position == Position::Bottom) ? height() : width());
// 如果实际的尺寸超过了任务栏允许的最大尺寸,此时可能是在发生位置变换,这个时候使用接口获取的尺寸即可
// 如果任务栏在隐藏状态那么此时获取到的高度为0此时从后端获取任务栏的实际高度
HideState hideState = static_cast<HideState>(qApp->property(PROP_HIDE_STATE).toInt());
if (dockSize > DOCK_MAX_SIZE || hideState == HideState::Hide)
dockSize = static_cast<int>((m_displayMode == DisplayMode::Efficient ? m_dockInter->windowSizeEfficient() : m_dockInter->windowSizeFashion()) * qApp->devicePixelRatio());
if (m_displayMode == DisplayMode::Efficient) {
// 如果是高效模式
if (m_position == Position::Top || m_position == Position::Bottom)
return QSize(static_cast<int>(screenSize / ratio), height());
if (position == Position::Top || position == Position::Bottom)
return QSize(static_cast<int>(screenSize / ratio), dockSize);
return QSize(width(), static_cast<int>(screenSize / ratio));
return QSize(dockSize, static_cast<int>(screenSize / ratio));
}
QSize traySuitableSize = m_trayManagerWidget->suitableSize();
// 如果是特效模式
int totalLength = static_cast<int>(screenSize / ratio);
// 减去右侧托盘和快捷设置还有插件区域的尺寸
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_toolAreaLayout->count();
if (iconCount <= 0) {
if (m_position == Position::Top || m_position == Position::Bottom)
return QSize((static_cast<int>((traySuitableSize.width() + 20) / ratio)), height());
int iconCount = m_fixedAreaLayout->count() + m_appAreaSonLayout->count() + m_recentLayout->count() + m_toolSonLayout->count();
int multiWindowCount = m_multiWindowLayout->count();
if (iconCount <= 0 && multiWindowCount <= 0) {
if (position == Position::Top || position == Position::Bottom)
return QSize((static_cast<int>(dockSize / ratio)), dockSize);
return QSize(width(), static_cast<int>((traySuitableSize.height() + 20) / ratio));
return QSize(dockSize, static_cast<int>(dockSize / ratio));
}
int redundantLength = (totalLength % iconCount);
// icon宽度 = (总宽度-余数)/icon个数
int iconSize = (totalLength - redundantLength) / iconCount;
int iconSize = qMin(((totalLength - redundantLength) / iconCount), dockSize);
if (m_position == Position::Top || m_position == Position::Bottom) {
iconSize = qMin(iconSize, height());
int spliterWidth = m_fixedSpliter->isVisible() ? m_fixedSpliter->width() : 0;
if (position == Position::Top || position == Position::Bottom) {
int spliterWidth = m_fixedSpliter->isVisible() ? SPLITER_SIZE : 0;
if (m_appSpliter->isVisible())
spliterWidth += m_appSpliter->width();
spliterWidth += SPLITER_SIZE;
if (m_recentSpliter->isVisible())
spliterWidth += m_recentSpliter->isVisible();
spliterWidth += SPLITER_SIZE;
int panelWidth = qMin(iconSize * iconCount + static_cast<int>((spliterWidth + traySuitableSize.width() + 20) / ratio),
static_cast<int>(screenSize / deviceRatio));
int multiSize = 0;
// 计算每个多开窗口的尺寸
if (multiWindowCount > 0) {
for (int i = 0; i < multiWindowCount; i++) {
AppMultiItem *multiItem = qobject_cast<AppMultiItem *>(m_multiWindowLayout->itemAt(i)->widget());
if (!multiItem)
continue;
return QSize(panelWidth, static_cast<int>(height() / ratio));
multiSize += multiItem->width();
}
}
int panelWidth = qMin(iconSize * iconCount + multiSize + static_cast<int>(spliterWidth / ratio),
static_cast<int>((screenSize - DOCKSPACE) / deviceRatio));
return QSize(panelWidth, static_cast<int>(dockSize / ratio));
}
iconSize = iconSize < width() ? iconSize : width();
int spliterHeight = m_fixedSpliter->isVisible() ? m_fixedSpliter->height() : 0;
int spliterHeight = m_fixedSpliter->isVisible() ? SPLITER_SIZE : 0;
if (m_appSpliter->isVisible())
spliterHeight += m_appSpliter->height();
spliterHeight += SPLITER_SIZE;
if (m_recentSpliter->isVisible())
spliterHeight += m_recentSpliter->height();
spliterHeight += SPLITER_SIZE;
int panelHeight = qMin(iconSize * iconCount + static_cast<int>((spliterHeight + traySuitableSize.height() + 20) / ratio),
static_cast<int>(screenSize / deviceRatio));
int multiSize = 0;
// 计算每个多开窗口的尺寸
if (multiWindowCount > 0) {
for (int i = 0; i < multiWindowCount; i++) {
AppMultiItem *multiItem = qobject_cast<AppMultiItem *>(m_multiWindowLayout->itemAt(i)->widget());
if (!multiItem)
continue;
return QSize(width(), panelHeight);
multiSize += multiItem->height();
}
}
int panelHeight = qMin(iconSize * iconCount + multiSize + static_cast<int>(spliterHeight / ratio),
static_cast<int>((screenSize - DOCKSPACE)/ deviceRatio));
return QSize(dockSize, panelHeight);
}
void MainPanelControl::itemUpdated(DockItem *item)
@ -1204,12 +1166,10 @@ void MainPanelControl::paintEvent(QPaintEvent *event)
int MainPanelControl::getScreenSize() const
{
QScreen *currentScreen = qApp->primaryScreen();
if (m_dockScreen) {
DisplayManager *displayManager = DisplayManager::instance();
QScreen *screen = displayManager->screen(m_dockScreen->current());
if (screen)
currentScreen = screen;
}
DisplayManager *displayManager = DisplayManager::instance();
QScreen *screen = displayManager->screen(DockScreen::instance()->current());
if (screen)
currentScreen = screen;
QRect screenRect = currentScreen->handle()->geometry();
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom)
@ -1225,15 +1185,11 @@ void MainPanelControl::resizeDockIcon()
{
int iconSize = 0;
int tray_item_size = 0;
int iconCount = 0;
// 总宽度
if (m_displayMode == DisplayMode::Fashion) {
int iconCount = 0;
// 时尚模式
int totalLength = getScreenSize();
QSize trayManagerSize = m_trayManagerWidget->suitableSize();
// 减去右侧托盘和插件区域的宽度
totalLength -= ((m_position == Position::Top) || (m_position == Position::Bottom)) ? trayManagerSize.width() : trayManagerSize.height();
iconCount = m_fixedAreaLayout->count() + m_appAreaSonLayout->count();
if (m_recentAreaWidget->isVisible())
iconCount += m_recentLayout->count();
@ -1251,7 +1207,7 @@ void MainPanelControl::resizeDockIcon()
// 计算插件图标的最大或最小值
tray_item_size = qBound(20, iconSize, 40);
if ((m_position == Position::Top) || (m_position == Position::Bottom)) {
tray_item_size = qMin(tray_item_size,height());
tray_item_size = qMin(tray_item_size, height());
tray_item_size = std::min(tray_item_size, height() - 20);
} else {
tray_item_size = qMin(tray_item_size,width());
@ -1356,12 +1312,13 @@ void MainPanelControl::resizeDockIcon()
calcuDockIconSize(width(), iconSize, tray_item_size);
}
}
Q_EMIT requestUpdate();
}
void MainPanelControl::calcuDockIconSize(int w, int h, int traySize)
{
int appItemSize = qMin(w, h);
for (int i = 0; i < m_fixedAreaLayout->count(); ++i)
m_fixedAreaLayout->itemAt(i)->widget()->setFixedSize(appItemSize, appItemSize);
@ -1552,20 +1509,8 @@ void MainPanelControl::resizeDesktopWidget()
{
if (m_position == Position::Right || m_position == Position::Left) {
m_desktopWidget->setFixedSize(QWIDGETSIZE_MAX, DESKTOP_SIZE);
m_trayManagerWidget->setFixedWidth(QWIDGETSIZE_MAX);
m_trayManagerWidget->updateLayout();
QSize suitableSize = m_trayManagerWidget->suitableSize();
m_trayManagerWidget->setFixedHeight(suitableSize.height());
} else {
m_desktopWidget->setFixedSize(DESKTOP_SIZE, QWIDGETSIZE_MAX);
// 在调整尺寸过程中,先设置高度,然后更新布局,因为更新布局的时候,里面的
// Layout需要根据高度来调整布局的部件间距和边距此时返回的尺寸会有所变化
// 等布局更新后,再获取返回的尺寸来设置右侧的宽度
// 如果是左右位置,原理一样
m_trayManagerWidget->setFixedHeight(QWIDGETSIZE_MAX);
m_trayManagerWidget->updateLayout();
QSize suitableSize = m_trayManagerWidget->suitableSize();
m_trayManagerWidget->setFixedWidth(suitableSize.width());
}
if (DisplayMode::Fashion == m_displayMode)

View File

@ -39,8 +39,6 @@ class DockItem;
class PlaceholderItem;
class AppDragWidget;
class DesktopWidget;
class TrayManagerWindow;
class DockScreen;
class RecentAppHelper;
class ToolAppHelper;
class MultiWindowHelper;
@ -50,16 +48,14 @@ class MainPanelControl : public QWidget
Q_OBJECT
public:
explicit MainPanelControl(QWidget *parent = nullptr);
explicit MainPanelControl(DockInter *dockInter, QWidget *parent = nullptr);
void setPositonValue(Position position);
void setDisplayMode(DisplayMode dislayMode);
void resizeDockIcon();
void updatePluginsLayout();
void setDockScreen(DockScreen *dockScreen);
QPainterPath areaPath();
QSize suitableSize(int screenSize, double deviceRatio) const;
QSize suitableSize(const Position &position, int screenSize, double deviceRatio) const;
public slots:
void insertItem(const int index, DockItem *item);
@ -96,7 +92,6 @@ private:
void resizeDesktopWidget();
bool checkNeedShowDesktop();
bool appIsOnDock(const QString &appDesktop);
void resetRadius();
void dockRecentApp(DockItem *dockItem);
private Q_SLOTS:
@ -140,7 +135,6 @@ private:
QWidget *m_toolSonAreaWidget; // 工具区域,用来存放回收站等工具
QBoxLayout *m_toolSonLayout; // 工具区域布局
TrayManagerWindow *m_trayManagerWidget;
QBoxLayout *m_pluginLayout; // 插件区域布局
DesktopWidget *m_desktopWidget; // 桌面预览区域
@ -153,7 +147,6 @@ private:
TrayPluginItem *m_tray;
int m_dragIndex = -1; // 记录应用区域被拖拽图标的位置
DockScreen *m_dockScreen;
DockInter *m_dockInter;
RecentAppHelper *m_recentHelper;
ToolAppHelper *m_toolHelper;

View File

@ -25,6 +25,12 @@
#include "dockitemmanager.h"
#include "menuworker.h"
#include "proxyplugincontroller.h"
#include "windowmanager.h"
#include "dockscreen.h"
#include "dragwidget.h"
#include "multiscreenworker.h"
#include "constants.h"
#include "displaymanager.h"
#include <DStyle>
#include <DPlatformWindowHandle>
@ -40,321 +46,47 @@
#include <QX11Info>
#include <QtConcurrent>
#include <qpa/qplatformwindow.h>
#include <qpa/qplatformscreen.h>
#include <qpa/qplatformnativeinterface.h>
#include <QMenu>
#include <X11/X.h>
#include <X11/Xutil.h>
#define SNI_WATCHER_SERVICE "org.kde.StatusNotifierWatcher"
#define SNI_WATCHER_PATH "/StatusNotifierWatcher"
#define DOCK_SCREEN DockScreen::instance()
#define DIS_INS DisplayManager::instance()
#define MAINWINDOW_MAX_SIZE DOCK_MAX_SIZE
#define MAINWINDOW_MIN_SIZE (40)
#define DRAG_AREA_SIZE (5)
#define DRAG_STATE_PROP "DRAG_STATE"
using org::kde::StatusNotifierWatcher;
// let startdde know that we've already started.
void MainWindow::RegisterDdeSession()
MainWindow::MainWindow(MultiScreenWorker *multiScreenWorker, QWidget *parent)
: MainWindowBase(multiScreenWorker, parent)
, m_mainPanel(new MainPanelControl(multiScreenWorker->dockInter(), this))
, m_multiScreenWorker(multiScreenWorker)
{
QString envName("DDE_SESSION_PROCESS_COOKIE_ID");
QByteArray cookie = qgetenv(envName.toUtf8().data());
qunsetenv(envName.toUtf8().data());
if (!cookie.isEmpty()) {
QDBusPendingReply<bool> r = DDBusSender()
.interface("com.deepin.SessionManager")
.path("/com/deepin/SessionManager")
.service("com.deepin.SessionManager")
.method("Register")
.arg(QString(cookie))
.call();
qDebug() << Q_FUNC_INFO << r.value();
}
}
MainWindow::MainWindow(QWidget *parent)
: DBlurEffectWidget(parent)
, m_mainPanel(new MainPanelControl(this))
, m_platformWindowHandle(this)
, m_wmHelper(DWindowManagerHelper::instance())
, m_multiScreenWorker(new MultiScreenWorker(this, m_wmHelper))
, m_menuWorker(new MenuWorker(m_multiScreenWorker->dockInter(), this))
, m_shadowMaskOptimizeTimer(new QTimer(this))
, m_dbusDaemonInterface(QDBusConnection::sessionBus().interface())
, m_sniWatcher(new StatusNotifierWatcher(SNI_WATCHER_SERVICE, SNI_WATCHER_PATH, QDBusConnection::sessionBus(), this))
, m_dragWidget(new DragWidget(this))
, m_launched(false)
, m_updateDragAreaTimer(new QTimer(this))
{
setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_X11DoNotAcceptFocus);
Qt::WindowFlags flags = Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::Window;
//1 确保这两行代码的先后顺序,否则会导致任务栏界面不再置顶
setWindowFlags(windowFlags() | flags | Qt::WindowDoesNotAcceptFocus);
if (Utils::IS_WAYLAND_DISPLAY)
setWindowFlag(Qt::FramelessWindowHint, false); // 会导致设置圆角为0时无效
if (DGuiApplicationHelper::isXWindowPlatform()) {
const auto display = QX11Info::display();
if (!display) {
qWarning() << "QX11Info::display() is " << display;
} else {
//2 确保这两行代码的先后顺序,否则会导致任务栏界面不再置顶
XcbMisc::instance()->set_window_type(xcb_window_t(this->winId()), XcbMisc::Dock);
}
}
setMouseTracking(true);
setAcceptDrops(true);
DPlatformWindowHandle::enableDXcbForWindow(this, true);
m_platformWindowHandle.setEnableBlurWindow(true);
m_platformWindowHandle.setTranslucentBackground(true);
m_platformWindowHandle.setShadowOffset(QPoint(0, 0));
m_platformWindowHandle.setShadowColor(Qt::transparent);
m_mainPanel->setDisplayMode(m_multiScreenWorker->displayMode());
initMember();
initSNIHost();
initComponents();
initConnections();
resetDragWindow();
for (auto item : DockItemManager::instance()->itemList())
m_mainPanel->insertItem(-1, item);
m_dragWidget->setMouseTracking(true);
m_dragWidget->setFocusPolicy(Qt::NoFocus);
if (!Utils::IS_WAYLAND_DISPLAY) {
if ((Top == m_multiScreenWorker->position()) || (Bottom == m_multiScreenWorker->position())) {
m_dragWidget->setCursor(Qt::SizeVerCursor);
} else {
m_dragWidget->setCursor(Qt::SizeHorCursor);
}
}
}
/**
* @brief MainWindow::launch
*
*/
void MainWindow::launch()
{
if (!qApp->property("CANSHOW").toBool())
return;
m_launched = true;
m_multiScreenWorker->initShow();
m_shadowMaskOptimizeTimer->start();
QTimer::singleShot(0, this, [ this ] { this->setVisible(true); });
}
/**
* @brief MainWindow::callShow
* DBus调用的
* @note -r参数启动时DBus调用此接口之后才会显示界面
*
* startdde延后调用
*/
void MainWindow::callShow()
{
static bool flag = false;
if (flag) {
return;
}
flag = true;
qApp->setProperty("CANSHOW", true);
launch();
// 预留200ms提供给窗口初始化再通知startdde不影响启动速度
QTimer::singleShot(200, this, &MainWindow::RegisterDdeSession);
}
/**
* @brief MainWindow::relaodPlugins
* 退
*/
void MainWindow::reloadPlugins()
{
if (qApp->property("PLUGINSLOADED").toBool()) {
return;
}
// 发送事件,通知代理来加载插件
PluginLoadEvent event;
QCoreApplication::sendEvent(qApp, &event);
qApp->setProperty("PLUGINSLOADED", true);
// 退出安全模式
qApp->setProperty("safeMode", false);
}
/**
* @brief MainWindow::mousePressEvent
* @param e
* @note
*/
void MainWindow::mousePressEvent(QMouseEvent *e)
{
e->ignore();
if (e->button() == Qt::RightButton && this->geometry().contains(QCursor::pos())) {
QTimer::singleShot(10, this, [this]{
QMenu *menu = new QMenu(this);
m_menuWorker->showDockSettingsMenu(menu);
});
return;
}
}
void MainWindow::keyPressEvent(QKeyEvent *e)
{
switch (e->key()) {
#ifdef QT_DEBUG
case Qt::Key_Escape: qApp->quit(); break;
#endif
default:;
}
}
void MainWindow::enterEvent(QEvent *e)
{
QWidget::enterEvent(e);
if (QApplication::overrideCursor() && QApplication::overrideCursor()->shape() != Qt::ArrowCursor)
QApplication::restoreOverrideCursor();
}
void MainWindow::mouseMoveEvent(QMouseEvent *e)
{
Q_UNUSED(e);
//重写mouseMoveEvent 解决bug12866 leaveEvent事件失效
}
void MainWindow::moveEvent(QMoveEvent *event)
{
Q_UNUSED(event);
if (!qApp->property(DRAG_STATE_PROP).toBool())
m_updateDragAreaTimer->start();
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
if (!qApp->property(DRAG_STATE_PROP).toBool())
m_updateDragAreaTimer->start();
MainWindowBase::resizeEvent(event);
// 任务栏大小、位置、模式改变都会触发resize发射大小改变信号供依赖项目更新位置
Q_EMIT panelGeometryChanged();
updateMaskArea();
m_mainPanel->updatePluginsLayout();
m_shadowMaskOptimizeTimer->start();
return DBlurEffectWidget::resizeEvent(event);
}
void MainWindow::initMember()
{
//INFO 这里要大于动画的300ms否则可能动画过程中这个定时器就被触发了
m_updateDragAreaTimer->setInterval(500);
m_updateDragAreaTimer->setSingleShot(true);
}
/**
* @brief MainWindow::initSNIHost
* @note Dock注册到StatusNotifierWatcher服务上
*/
void MainWindow::initSNIHost()
{
// registor dock as SNI Host on dbus
QDBusConnection dbusConn = QDBusConnection::sessionBus();
m_sniHostService = QString("org.kde.StatusNotifierHost-") + QString::number(qApp->applicationPid());
dbusConn.registerService(m_sniHostService);
dbusConn.registerObject("/StatusNotifierHost", this);
if (m_sniWatcher->isValid()) {
m_sniWatcher->RegisterStatusNotifierHost(m_sniHostService);
} else {
qDebug() << SNI_WATCHER_SERVICE << "SNI watcher daemon is not exist for now!";
}
}
void MainWindow::initComponents()
{
m_shadowMaskOptimizeTimer->setSingleShot(true);
m_shadowMaskOptimizeTimer->setInterval(100);
QTimer::singleShot(1, this, &MainWindow::compositeChanged);
themeTypeChanged(DGuiApplicationHelper::instance()->themeType());
}
void MainWindow::compositeChanged()
{
const bool composite = m_wmHelper->hasComposite();
setComposite(composite);
m_shadowMaskOptimizeTimer->start();
// 任务栏大小、位置、模式改变都会触发resize发射大小改变信号供依赖项目更新位置
Q_EMIT requestUpdate();
}
void MainWindow::initConnections()
{
connect(m_shadowMaskOptimizeTimer, &QTimer::timeout, this, &MainWindow::adjustShadowMask, Qt::QueuedConnection);
connect(m_wmHelper, &DWindowManagerHelper::hasCompositeChanged, m_shadowMaskOptimizeTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
connect(&m_platformWindowHandle, &DPlatformWindowHandle::frameMarginsChanged, m_shadowMaskOptimizeTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
connect(&m_platformWindowHandle, &DPlatformWindowHandle::windowRadiusChanged, m_shadowMaskOptimizeTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
connect(m_mainPanel, &MainPanelControl::requestUpdate, m_shadowMaskOptimizeTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
connect(m_dbusDaemonInterface, &QDBusConnectionInterface::serviceOwnerChanged, this, &MainWindow::onDbusNameOwnerChanged);
connect(DockItemManager::instance(), &DockItemManager::itemInserted, m_mainPanel, &MainPanelControl::insertItem, Qt::DirectConnection);
connect(DockItemManager::instance(), &DockItemManager::itemRemoved, m_mainPanel, &MainPanelControl::removeItem, Qt::DirectConnection);
connect(DockItemManager::instance(), &DockItemManager::itemUpdated, m_mainPanel, &MainPanelControl::itemUpdated, Qt::DirectConnection);
connect(DockItemManager::instance(), &DockItemManager::trayVisableCountChanged, this, &MainWindow::resizeDockIcon, Qt::QueuedConnection);
connect(DockItemManager::instance(), &DockItemManager::requestWindowAutoHide, m_menuWorker, &MenuWorker::setAutoHide);
connect(m_mainPanel, &MainPanelControl::itemMoved, DockItemManager::instance(), &DockItemManager::itemMoved, Qt::DirectConnection);
connect(m_mainPanel, &MainPanelControl::itemAdded, DockItemManager::instance(), &DockItemManager::itemAdded, Qt::DirectConnection);
// -拖拽任务栏改变高度或宽度-------------------------------------------------------------------------------
connect(m_updateDragAreaTimer, &QTimer::timeout, this, &MainWindow::resetDragWindow);
//TODO 后端考虑删除这块,目前还不能删除,调整任务栏高度的时候,任务栏外部区域有变化
connect(m_updateDragAreaTimer, &QTimer::timeout, m_multiScreenWorker, &MultiScreenWorker::onRequestUpdateRegionMonitor);
connect(m_dragWidget, &DragWidget::dragPointOffset, this, [ = ] { qApp->setProperty(DRAG_STATE_PROP, true); });
connect(m_dragWidget, &DragWidget::dragFinished, this, [ = ] {
m_multiScreenWorker->setStates(MultiScreenWorker::DockIsDraging, false);
qApp->setProperty(DRAG_STATE_PROP, false);
});
connect(m_dragWidget, &DragWidget::dragPointOffset, this, &MainWindow::onMainWindowSizeChanged);
connect(m_dragWidget, &DragWidget::dragFinished, this, &MainWindow::resetDragWindow); // 更新拖拽区域
// ----------------------------------------------------------------------------------------------------
connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, this, &MainWindow::themeTypeChanged);
connect(m_menuWorker, &MenuWorker::autoHideChanged, m_multiScreenWorker, &MultiScreenWorker::onAutoHideChanged);
connect(m_multiScreenWorker, &MultiScreenWorker::opacityChanged, this, &MainWindow::setMaskAlpha, Qt::QueuedConnection);
connect(m_multiScreenWorker, &MultiScreenWorker::displayModeChanegd, this, &MainWindow::adjustShadowMask, Qt::QueuedConnection);
connect(m_multiScreenWorker, &MultiScreenWorker::requestUpdateDockEntry, DockItemManager::instance(), &DockItemManager::requestUpdateDockItem);
// 响应后端触控屏拖拽任务栏高度长按信号
connect(TouchSignalManager::instance(), &TouchSignalManager::middleTouchPress, this, &MainWindow::touchRequestResizeDock);
connect(TouchSignalManager::instance(), &TouchSignalManager::touchMove, m_dragWidget, &DragWidget::onTouchMove);
connect(m_mainPanel, &MainPanelControl::requestUpdate, this, &MainWindow::requestUpdate);
}
/**
@ -366,320 +98,77 @@ void MainWindow::resizeDockIcon()
m_mainPanel->resizeDockIcon();
}
void MainWindow::updateMaskArea()
{
QPainterPath path = m_mainPanel->areaPath();
QPolygon polgon = path.toFillPolygon().toPolygon();
setMask(polgon);
}
/**
* @brief MainWindow::adjustShadowMask
*/
void MainWindow::adjustShadowMask()
{
if (!m_launched || m_shadowMaskOptimizeTimer->isActive())
return;
DStyleHelper dstyle(style());
int radius = 0;
if (m_wmHelper->hasComposite() && m_multiScreenWorker->displayMode() == DisplayMode::Fashion) {
if (Dtk::Core::DSysInfo::isCommunityEdition()) { // 社区版圆角与专业版不同
DPlatformTheme *theme = DGuiApplicationHelper::instance()->systemTheme();
radius = theme->windowRadius(radius);
} else {
QVariant vRadius = qApp->property("EffectBorderRadius");
if (vRadius.isNull())
radius = dstyle.pixelMetric(DStyle::PM_TopLevelWindowRadius);
else
radius = vRadius.toInt();
}
}
m_platformWindowHandle.setWindowRadius(radius);
m_mainPanel->updatePluginsLayout();
updateMaskArea();
}
void MainWindow::onDbusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
{
Q_UNUSED(oldOwner);
if (name == SNI_WATCHER_SERVICE && !newOwner.isEmpty()) {
qDebug() << SNI_WATCHER_SERVICE << "SNI watcher daemon started, register dock to watcher as SNI Host";
m_sniWatcher->RegisterStatusNotifierHost(m_sniHostService);
}
}
/**
* @brief MainWindow::setEffectEnabled
* @param enabled enabled特效来更新任务栏的外观样式
*/
void MainWindow::setEffectEnabled(const bool enabled)
{
Q_UNUSED(enabled);
setMaskColor(AutoColor);
setMaskAlpha(m_multiScreenWorker->opacity());
m_platformWindowHandle.setBorderWidth(0);
}
/**
* @brief MainWindow::setComposite
* @param hasComposite
*/
void MainWindow::setComposite(const bool hasComposite)
{
setEffectEnabled(hasComposite);
}
/**
* @brief MainWindow::resetDragWindow
* @note widget提拽支持geometry发生变化的时候geometry
*/
void MainWindow::resetDragWindow()
{
switch (m_multiScreenWorker->position()) {
case Dock::Top:
m_dragWidget->setGeometry(0, height() - DRAG_AREA_SIZE, width(), DRAG_AREA_SIZE);
break;
case Dock::Bottom:
m_dragWidget->setGeometry(0, 0, width(), DRAG_AREA_SIZE);
break;
case Dock::Left:
m_dragWidget->setGeometry(width() - DRAG_AREA_SIZE, 0, DRAG_AREA_SIZE, height());
break;
case Dock::Right:
m_dragWidget->setGeometry(0, 0, DRAG_AREA_SIZE, height());
break;
}
QRect rect = m_multiScreenWorker->dockRect(m_multiScreenWorker->deskScreen()
, m_multiScreenWorker->position()
, HideMode::KeepShowing
, m_multiScreenWorker->displayMode());
// 这个时候屏幕有可能是隐藏的不能直接使用this->width()这种去设置任务栏的高度,而应该保证原值
int dockSize = 0;
if (m_multiScreenWorker->position() == Position::Left
|| m_multiScreenWorker->position() == Position::Right) {
dockSize = this->width() == 0 ? rect.width() : this->width();
} else {
dockSize = this->height() == 0 ? rect.height() : this->height();
}
/** FIX ME
* dockSize的值在40100
* 1dockSize为39dock的mainwindow高度变成9939
* 2dockSize的值在这里不应该为39
*
*/
dockSize = qBound(MAINWINDOW_MIN_SIZE, dockSize, MAINWINDOW_MAX_SIZE);
// 通知窗管和后端更新数据
m_multiScreenWorker->updateDaemonDockSize(dockSize); // 1.先更新任务栏高度
m_multiScreenWorker->requestUpdateFrontendGeometry(); // 2.再更新任务栏位置,保证先1再2
m_multiScreenWorker->requestNotifyWindowManager();
m_multiScreenWorker->requestUpdateRegionMonitor(); // 界面发生变化,应更新监控区域
if ((Top == m_multiScreenWorker->position()) || (Bottom == m_multiScreenWorker->position())) {
m_dragWidget->setCursor(Qt::SizeVerCursor);
} else {
m_dragWidget->setCursor(Qt::SizeHorCursor);
}
}
void MainWindow::resizeDock(int offset, bool dragging)
{
qApp->setProperty(DRAG_STATE_PROP, dragging);
const QRect &rect = m_multiScreenWorker->getDockShowMinGeometry(m_multiScreenWorker->deskScreen());
QRect newRect;
switch (m_multiScreenWorker->position()) {
case Top: {
newRect.setX(rect.x());
newRect.setY(rect.y());
newRect.setWidth(rect.width());
newRect.setHeight(qBound(MAINWINDOW_MIN_SIZE, offset, MAINWINDOW_MAX_SIZE));
}
break;
case Bottom: {
newRect.setX(rect.x());
newRect.setY(rect.y() + rect.height() - qBound(MAINWINDOW_MIN_SIZE, offset, MAINWINDOW_MAX_SIZE));
newRect.setWidth(rect.width());
newRect.setHeight(qBound(MAINWINDOW_MIN_SIZE, offset, MAINWINDOW_MAX_SIZE));
}
break;
case Left: {
newRect.setX(rect.x());
newRect.setY(rect.y());
newRect.setWidth(qBound(MAINWINDOW_MIN_SIZE, offset, MAINWINDOW_MAX_SIZE));
newRect.setHeight(rect.height());
}
break;
case Right: {
newRect.setX(rect.x() + rect.width() - qBound(MAINWINDOW_MIN_SIZE, offset, MAINWINDOW_MAX_SIZE));
newRect.setY(rect.y());
newRect.setWidth(qBound(MAINWINDOW_MIN_SIZE, offset, MAINWINDOW_MAX_SIZE));
newRect.setHeight(rect.height());
}
break;
}
// 更新界面大小
m_mainPanel->setFixedSize(newRect.size());
setFixedSize(newRect.size());
move(newRect.topLeft());
if (!dragging)
resetDragWindow();
}
/**
* @brief MainWindow::onMainWindowSizeChanged
* @param offset
*/
void MainWindow::onMainWindowSizeChanged(QPoint offset)
{
const QRect &rect = m_multiScreenWorker->dockRect(m_multiScreenWorker->deskScreen()
, m_multiScreenWorker->position()
, HideMode::KeepShowing,
m_multiScreenWorker->displayMode());
QRect newRect;
switch (m_multiScreenWorker->position()) {
case Top: {
newRect.setX(rect.x());
newRect.setY(rect.y());
newRect.setWidth(rect.width());
newRect.setHeight(qBound(MAINWINDOW_MIN_SIZE, rect.height() + offset.y(), MAINWINDOW_MAX_SIZE));
}
break;
case Bottom: {
newRect.setX(rect.x());
newRect.setY(rect.y() + rect.height() - qBound(MAINWINDOW_MIN_SIZE, rect.height() - offset.y(), MAINWINDOW_MAX_SIZE));
newRect.setWidth(rect.width());
newRect.setHeight(qBound(MAINWINDOW_MIN_SIZE, rect.height() - offset.y(), MAINWINDOW_MAX_SIZE));
}
break;
case Left: {
newRect.setX(rect.x());
newRect.setY(rect.y());
newRect.setWidth(qBound(MAINWINDOW_MIN_SIZE, rect.width() + offset.x(), MAINWINDOW_MAX_SIZE));
newRect.setHeight(rect.height());
}
break;
case Right: {
newRect.setX(rect.x() + rect.width() - qBound(MAINWINDOW_MIN_SIZE, rect.width() - offset.x(), MAINWINDOW_MAX_SIZE));
newRect.setY(rect.y());
newRect.setWidth(qBound(MAINWINDOW_MIN_SIZE, rect.width() - offset.x(), MAINWINDOW_MAX_SIZE));
newRect.setHeight(rect.height());
}
break;
}
m_multiScreenWorker->setStates(MultiScreenWorker::DockIsDraging, true);
// 更新界面大小
m_mainPanel->setFixedSize(newRect.size());
setFixedSize(newRect.size());
move(newRect.topLeft());
}
/**
* @brief MainWindow::themeTypeChanged
* @param themeType
*/
void MainWindow::themeTypeChanged(DGuiApplicationHelper::ColorType themeType)
{
if (m_wmHelper->hasComposite()) {
if (themeType == DGuiApplicationHelper::DarkType)
m_platformWindowHandle.setBorderColor(QColor(0, 0, 0, 255 * 0.3));
else
m_platformWindowHandle.setBorderColor(QColor(QColor::Invalid));
}
}
/**
* @brief MainWindow::touchRequestResizeDock
*/
void MainWindow::touchRequestResizeDock()
{
const QPoint touchPos(QCursor::pos());
QRect dockRect = m_multiScreenWorker->dockRect(m_multiScreenWorker->deskScreen()
, m_multiScreenWorker->position()
, HideMode::KeepShowing
, m_multiScreenWorker->displayMode());
// 隐藏状态返回
if (width() == 0 || height() == 0) {
return;
}
int resizeHeight = Utils::SettingValue("com.deepin.dde.dock.touch", QByteArray(), "resizeHeight", 7).toInt();
QRect touchRect;
// 任务栏屏幕 内侧边线 内外resizeHeight距离矩形区域内长按可拖动任务栏高度
switch (m_multiScreenWorker->position()) {
case Position::Top:
touchRect = QRect(dockRect.x(), dockRect.y() + dockRect.height() - resizeHeight, dockRect.width(), resizeHeight * 2);
break;
case Position::Bottom:
touchRect = QRect(dockRect.x(), dockRect.y() - resizeHeight, dockRect.width(), resizeHeight * 2);
break;
case Position::Left:
touchRect = QRect(dockRect.x() + dockRect.width() - resizeHeight, dockRect.y(), resizeHeight * 2, dockRect.height());
break;
case Position::Right:
touchRect = QRect(dockRect.x() - resizeHeight, dockRect.y(), resizeHeight * 2, dockRect.height());
break;
}
if (!touchRect.contains(touchPos)) {
return;
}
qApp->postEvent(m_dragWidget, new QMouseEvent(QEvent::MouseButtonPress, m_dragWidget->mapFromGlobal(touchPos)
, QPoint(), touchPos, Qt::LeftButton, Qt::NoButton
, Qt::NoModifier, Qt::MouseEventSynthesizedByApplication));
}
/**
* @brief MainWindow::setGeometry
* @param rect panelGeometryChanged信号DBus调用方使用
*/
void MainWindow::setGeometry(const QRect &rect)
{
if (rect == this->geometry()) {
if (rect == this->geometry())
return;
}
DBlurEffectWidget::setGeometry(rect);
emit panelGeometryChanged();
emit requestUpdate();
}
/**
* @brief
*/
void MainWindow::sendNotifications()
MainWindowBase::DockWindowType MainWindow::windowType() const
{
QStringList actionButton;
actionButton << "reload" << tr("Exit Safe Mode");
QVariantMap hints;
hints["x-deepin-action-reload"] = QString("dbus-send,--session,--dest=com.deepin.dde.Dock,--print-reply,/com/deepin/dde/Dock,com.deepin.dde.Dock.ReloadPlugins");
// 在进入安全模式时执行此DBUS耗时25S左右导致任务栏显示阻塞所以使用线程调用
QtConcurrent::run(QThreadPool::globalInstance(), [=] {
DDBusSender()
.service("com.deepin.dde.Notification")
.path("/com/deepin/dde/Notification")
.interface("com.deepin.dde.Notification")
.method(QString("Notify"))
.arg(QString("dde-control-center")) // appname
.arg(static_cast<uint>(0)) // id
.arg(QString("preferences-system")) // icon
.arg(QString(tr("Dock - Safe Mode"))) // summary
.arg(QString(tr("The Dock is in safe mode, please exit to show it properly"))) // content
.arg(actionButton) // actions
.arg(hints) // hints
.arg(15000) // timeout
.call();
});
return DockWindowType::MainWindow;
}
void MainWindow::setPosition(const Position &position)
{
MainWindowBase::setPosition(position);
m_mainPanel->setPositonValue(position);
// 更新鼠标拖拽样式在类内部设置到qApp单例上去
if ((Top == position) || (Bottom == position))
m_mainPanel->setCursor(Qt::SizeVerCursor);
else
m_mainPanel->setCursor(Qt::SizeHorCursor);
}
void MainWindow::setDisplayMode(const Dock::DisplayMode &displayMode)
{
m_mainPanel->setDisplayMode(displayMode);
MainWindowBase::setDisplayMode(displayMode);
}
void MainWindow::updateParentGeometry(const Position &pos, const QRect &rect)
{
setFixedSize(rect.size());
setGeometry(rect);
int panelSize = windowSize();
QRect panelRect = rect;
switch (pos) {
case Position::Top:
m_mainPanel->move(0, rect.height() - panelSize);
panelRect.setHeight(panelSize);
break;
case Position::Left:
m_mainPanel->move(width() - panelSize, 0);
panelRect.setWidth(panelSize);
break;
case Position::Bottom:
m_mainPanel->move(0, 0);
panelRect.setHeight(panelSize);
break;
case Position::Right:
m_mainPanel->move(0, 0);
panelRect.setWidth(panelSize);
break;
}
m_mainPanel->setFixedSize(panelRect.size());
}
QSize MainWindow::suitableSize(const Position &pos, const int &screenSize, const double &deviceRatio) const
{
return m_mainPanel->suitableSize(pos, screenSize, deviceRatio);
}
void MainWindow::resetPanelGeometry()
{
m_mainPanel->setFixedSize(size());
m_mainPanel->move(0, 0);
}

View File

@ -24,17 +24,13 @@
#define MAINWINDOW_H
#include "xcb_misc.h"
#include "statusnotifierwatcher_interface.h"
#include "mainpanelcontrol.h"
#include "multiscreenworker.h"
#include "touchsignalmanager.h"
#include "imageutil.h"
#include "utils.h"
#include "mainwindowbase.h"
#include <DPlatformWindowHandle>
#include <DWindowManagerHelper>
#include <DBlurEffectWidget>
#include <DGuiApplicationHelper>
#include <QWidget>
@ -43,189 +39,41 @@ DWIDGET_USE_NAMESPACE
class MainPanelControl;
class QTimer;
class MenuWorker;
class DragWidget : public QWidget
{
Q_OBJECT
class QScreen;
private:
bool m_dragStatus;
QPoint m_resizePoint;
public:
explicit DragWidget(QWidget *parent = nullptr)
: QWidget(parent)
{
setObjectName("DragWidget");
m_dragStatus = false;
}
public slots:
void onTouchMove(double scaleX, double scaleY)
{
Q_UNUSED(scaleX);
Q_UNUSED(scaleY);
static QPoint lastPos;
QPoint curPos = QCursor::pos();
if (lastPos == curPos) {
return;
}
lastPos = curPos;
qApp->postEvent(this, new QMouseEvent(QEvent::MouseMove, mapFromGlobal(curPos)
, QPoint(), curPos, Qt::LeftButton, Qt::LeftButton
, Qt::NoModifier, Qt::MouseEventSynthesizedByApplication));
}
signals:
void dragPointOffset(QPoint);
void dragFinished();
private:
void mousePressEvent(QMouseEvent *event) override
{
// qt转发的触屏按下信号不进行响应
if (event->source() == Qt::MouseEventSynthesizedByQt) {
return;
}
if (event->button() == Qt::LeftButton) {
m_resizePoint = event->globalPos();
m_dragStatus = true;
this->grabMouse();
}
}
void mouseMoveEvent(QMouseEvent *) override
{
if (m_dragStatus) {
QPoint offset = QPoint(QCursor::pos() - m_resizePoint);
emit dragPointOffset(offset);
}
}
void mouseReleaseEvent(QMouseEvent *) override
{
if (!m_dragStatus)
return;
m_dragStatus = false;
releaseMouse();
emit dragFinished();
}
void enterEvent(QEvent *) override
{
if (Utils::IS_WAYLAND_DISPLAY)
updateCursor();
QApplication::setOverrideCursor(cursor());
}
void leaveEvent(QEvent *) override
{
QApplication::setOverrideCursor(Qt::ArrowCursor);
}
void updateCursor()
{
QString theme = Utils::SettingValue("com.deepin.xsettings", "/com/deepin/xsettings/", "gtk-cursor-theme-name", "bloom").toString();
int cursorSize = Utils::SettingValue("com.deepin.xsettings", "/com/deepin/xsettings/", "gtk-cursor-theme-size", 24).toInt();
Position position = static_cast<Dock::Position>(qApp->property("position").toInt());
static QString lastTheme;
static int lastPosition = -1;
static int lastCursorSize = -1;
if (theme != lastTheme || position != lastPosition || cursorSize != lastCursorSize) {
lastTheme = theme;
lastPosition = position;
lastCursorSize = cursorSize;
const char* cursorName = (position == Bottom || position == Top) ? "v_double_arrow" : "h_double_arrow";
QCursor *newCursor = ImageUtil::loadQCursorFromX11Cursor(theme.toStdString().c_str(), cursorName, cursorSize);
if (!newCursor)
return;
setCursor(*newCursor);
static QCursor *lastCursor = nullptr;
if (lastCursor)
delete lastCursor;
lastCursor = newCursor;
}
}
};
class MainWindow : public DBlurEffectWidget
class MainWindow : public MainWindowBase
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
void setEffectEnabled(const bool enabled);
void setComposite(const bool hasComposite);
explicit MainWindow(MultiScreenWorker *multiScreenWorker, QWidget *parent = nullptr);
void setGeometry(const QRect &rect);
void sendNotifications();
friend class MainPanelControl;
MainPanelControl *panel() {return m_mainPanel;}
public slots:
void launch();
void callShow();
void reloadPlugins();
// 以下接口是实现基类的接口
// 用来更新子区域的位置一般用于在执行动画的过程中根据当前的位置来更新里面panel的大小
DockWindowType windowType() const override;
void setPosition(const Dock::Position &position) override;
void setDisplayMode(const Dock::DisplayMode &displayMode) override;
void updateParentGeometry(const Dock::Position &pos, const QRect &rect) override;
QSize suitableSize(const Dock::Position &pos, const int &screenSize, const double &deviceRatio) const override;
void resetPanelGeometry() override;
private:
using QWidget::show;
void mousePressEvent(QMouseEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
void enterEvent(QEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void moveEvent(QMoveEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void initMember();
void initSNIHost();
void initComponents();
void initConnections();
void resizeDockIcon();
void updateMaskArea();
signals:
void panelGeometryChanged();
public slots:
void RegisterDdeSession();
void resizeDock(int offset, bool dragging);
void resetDragWindow(); // 任务栏调整高度或宽度后需调用此函数
private slots:
void compositeChanged();
void adjustShadowMask();
void onDbusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
void onMainWindowSizeChanged(QPoint offset);
void themeTypeChanged(DGuiApplicationHelper::ColorType themeType);
void touchRequestResizeDock();
private:
MainPanelControl *m_mainPanel; // 任务栏
DPlatformWindowHandle m_platformWindowHandle;
DWindowManagerHelper *m_wmHelper;
MultiScreenWorker *m_multiScreenWorker; // 多屏幕管理
MenuWorker *m_menuWorker;
QTimer *m_shadowMaskOptimizeTimer;
QDBusConnectionInterface *m_dbusDaemonInterface;
org::kde::StatusNotifierWatcher *m_sniWatcher; // DBUS状态通知
DragWidget *m_dragWidget;
QString m_sniHostService;
bool m_launched;
QString m_registerKey;
QStringList m_registerKeys;
QTimer *m_updateDragAreaTimer;
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,606 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "mainwindowbase.h"
#include "dragwidget.h"
#include "multiscreenworker.h"
#include "dockscreen.h"
#include "touchsignalmanager.h"
#include "displaymanager.h"
#include "menuworker.h"
#include <DStyle>
#include <DWindowManagerHelper>
#include <DSysInfo>
#include <DPlatformTheme>
#include <QScreen>
#include <QX11Info>
#include <qpa/qplatformscreen.h>
#include <qpa/qplatformnativeinterface.h>
#define DRAG_AREA_SIZE (5)
// 任务栏圆角最小的时候,任务栏的高度值
#define MIN_RADIUS_WINDOWSIZE 46
// 任务栏圆角最小值和最大值的差值
#define MAX_MIN_RADIUS_DIFFVALUE 6
// 最小圆角值
#define MIN_RADIUS 12
#define DOCK_SCREEN DockScreen::instance()
#define DIS_INS DisplayManager::instance()
DGUI_USE_NAMESPACE
MainWindowBase::MainWindowBase(MultiScreenWorker *multiScreenWorker, QWidget *parent)
: DBlurEffectWidget(parent)
, m_displayMode(Dock::DisplayMode::Efficient)
, m_position(Dock::Position::Bottom)
, m_dockInter(multiScreenWorker->dockInter())
, m_dragWidget(new DragWidget(this))
, m_multiScreenWorker(multiScreenWorker)
, m_updateDragAreaTimer(new QTimer(this))
, m_platformWindowHandle(this)
, m_shadowMaskOptimizeTimer(new QTimer(this))
, m_isShow(false)
, m_borderRadius(0)
, m_order(0)
{
initUi();
initAttribute();
initConnection();
initMember();
}
MainWindowBase::~MainWindowBase()
{
}
void MainWindowBase::setOrder(int order)
{
m_order = order;
}
int MainWindowBase::order() const
{
return m_order;
}
void MainWindowBase::initAttribute()
{
setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_X11DoNotAcceptFocus);
Qt::WindowFlags flags = Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::Window;
//1 确保这两行代码的先后顺序,否则会导致任务栏界面不再置顶
setWindowFlags(windowFlags() | flags | Qt::WindowDoesNotAcceptFocus);
if (Utils::IS_WAYLAND_DISPLAY) {
setWindowFlag(Qt::FramelessWindowHint, false); // 会导致设置圆角为0时无效
setAttribute(Qt::WA_NativeWindow);
windowHandle()->setProperty("_d_dwayland_window-type", "dock");
}
if (DGuiApplicationHelper::isXWindowPlatform()) {
const auto display = QX11Info::display();
if (!display) {
qWarning() << "QX11Info::display() is " << display;
} else {
//2 确保这两行代码的先后顺序,否则会导致任务栏界面不再置顶
XcbMisc::instance()->set_window_type(xcb_window_t(this->winId()), XcbMisc::Dock);
}
}
setMouseTracking(true);
setAcceptDrops(true);
m_dragWidget->setMouseTracking(true);
m_dragWidget->setFocusPolicy(Qt::NoFocus);
if ((Dock::Top == m_position) || (Dock::Bottom == m_position))
m_dragWidget->setCursor(Qt::SizeVerCursor);
else
m_dragWidget->setCursor(Qt::SizeHorCursor);
}
void MainWindowBase::initConnection()
{
connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::hasCompositeChanged, m_shadowMaskOptimizeTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
connect(m_shadowMaskOptimizeTimer, &QTimer::timeout, this, &MainWindowBase::adjustShadowMask, Qt::QueuedConnection);
connect(&m_platformWindowHandle, &DPlatformWindowHandle::frameMarginsChanged, m_shadowMaskOptimizeTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
connect(&m_platformWindowHandle, &DPlatformWindowHandle::windowRadiusChanged, m_shadowMaskOptimizeTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
connect(m_dragWidget, &DragWidget::dragFinished, this, [ = ] {
m_multiScreenWorker->setStates(MultiScreenWorker::DockIsDraging, false);
});
// -拖拽任务栏改变高度或宽度-------------------------------------------------------------------------------
connect(m_updateDragAreaTimer, &QTimer::timeout, this, &MainWindowBase::resetDragWindow);
//TODO 后端考虑删除这块,目前还不能删除,调整任务栏高度的时候,任务栏外部区域有变化
connect(m_updateDragAreaTimer, &QTimer::timeout, m_multiScreenWorker, &MultiScreenWorker::onRequestUpdateRegionMonitor);
connect(m_dragWidget, &DragWidget::dragPointOffset, this, &MainWindowBase::onMainWindowSizeChanged);
connect(m_dragWidget, &DragWidget::dragFinished, this, &MainWindowBase::resetDragWindow); // 更新拖拽区域
connect(TouchSignalManager::instance(), &TouchSignalManager::touchMove, m_dragWidget, &DragWidget::onTouchMove);
connect(TouchSignalManager::instance(), &TouchSignalManager::middleTouchPress, this, &MainWindowBase::touchRequestResizeDock);
connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, this, &MainWindowBase::onThemeTypeChanged);
connect(m_multiScreenWorker, &MultiScreenWorker::opacityChanged, this, &MainWindowBase::setMaskAlpha, Qt::QueuedConnection);
onThemeTypeChanged(DGuiApplicationHelper::instance()->themeType());
QMetaObject::invokeMethod(this, &MainWindowBase::onCompositeChanged);
}
void MainWindowBase::initMember()
{
//INFO 这里要大于动画的300ms否则可能动画过程中这个定时器就被触发了
m_updateDragAreaTimer->setInterval(500);
m_updateDragAreaTimer->setSingleShot(true);
m_shadowMaskOptimizeTimer->setSingleShot(true);
m_shadowMaskOptimizeTimer->setInterval(100);
}
int MainWindowBase::getBorderRadius() const
{
if (!DWindowManagerHelper::instance()->hasComposite() || m_multiScreenWorker->displayMode() != DisplayMode::Fashion)
return 0;
if (Dtk::Core::DSysInfo::isCommunityEdition()) { // 社区版圆角与专业版不同
DPlatformTheme *theme = DGuiApplicationHelper::instance()->systemTheme();
return theme->windowRadius(0);
}
int size = ((m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) ? height() : width());
return qMin(MAX_MIN_RADIUS_DIFFVALUE, qMax(size - MIN_RADIUS_WINDOWSIZE, 0)) + MIN_RADIUS;
}
/**
* @brief MainWindow::onMainWindowSizeChanged
* @param offset
*/
void MainWindowBase::onMainWindowSizeChanged(QPoint offset)
{
QScreen *screen = DIS_INS->screen(DOCK_SCREEN->current());
if (!screen)
return;
const QRect rect = getDockGeometry(screen, position(), displayMode(), Dock::HideState::Show);
QRect newRect;
switch (m_multiScreenWorker->position()) {
case Top: {
newRect.setX(rect.x());
newRect.setY(rect.y());
newRect.setWidth(rect.width());
newRect.setHeight(qBound(DOCK_MIN_SIZE, rect.height() + offset.y(), DOCK_MAX_SIZE));
}
break;
case Bottom: {
newRect.setX(rect.x());
newRect.setY(rect.y() + rect.height() - qBound(DOCK_MIN_SIZE, rect.height() - offset.y(), DOCK_MAX_SIZE));
newRect.setWidth(rect.width());
newRect.setHeight(qBound(DOCK_MIN_SIZE, rect.height() - offset.y(), DOCK_MAX_SIZE));
}
break;
case Left: {
newRect.setX(rect.x());
newRect.setY(rect.y());
newRect.setWidth(qBound(DOCK_MIN_SIZE, rect.width() + offset.x(), DOCK_MAX_SIZE));
newRect.setHeight(rect.height());
}
break;
case Right: {
newRect.setX(rect.x() + rect.width() - qBound(DOCK_MIN_SIZE, rect.width() - offset.x(), DOCK_MAX_SIZE));
newRect.setY(rect.y());
newRect.setWidth(qBound(DOCK_MIN_SIZE, rect.width() - offset.x(), DOCK_MAX_SIZE));
newRect.setHeight(rect.height());
}
break;
}
m_multiScreenWorker->setStates(MultiScreenWorker::DockIsDraging, true);
setFixedSize(newRect.size());
move(newRect.topLeft());
resetPanelGeometry();
Q_EMIT requestUpdate();
}
void MainWindowBase::updateDragGeometry()
{
switch (position()) {
case Dock::Top:
m_dragWidget->setGeometry(0, height() - DRAG_AREA_SIZE, width(), DRAG_AREA_SIZE);
break;
case Dock::Bottom:
m_dragWidget->setGeometry(0, 0, width(), 20);
break;
case Dock::Left:
m_dragWidget->setGeometry(width() - DRAG_AREA_SIZE, 0, DRAG_AREA_SIZE, height());
break;
case Dock::Right:
m_dragWidget->setGeometry(0, 0, DRAG_AREA_SIZE, height());
break;
}
m_dragWidget->raise();
if ((Top == position()) || (Bottom == position())) {
m_dragWidget->setCursor(Qt::SizeVerCursor);
} else {
m_dragWidget->setCursor(Qt::SizeHorCursor);
}
}
void MainWindowBase::resetDragWindow()
{
updateDragGeometry();
QScreen *screen = DIS_INS->screen(DOCK_SCREEN->current());
if (!screen)
return;
QRect currentRect = getDockGeometry(screen, position(), displayMode(), Dock::HideState::Show);
// 这个时候屏幕有可能是隐藏的不能直接使用this->width()这种去设置任务栏的高度,而应该保证原值
int dockSize = 0;
if (m_multiScreenWorker->position() == Position::Left
|| m_multiScreenWorker->position() == Position::Right) {
dockSize = this->width() == 0 ? currentRect.width() : this->width();
} else {
dockSize = this->height() == 0 ? currentRect.height() : this->height();
}
/** FIX ME
* dockSize的值在40100
* 1dockSize为39dock的mainwindow高度变成9939
* 2dockSize的值在这里不应该为39
*
*/
dockSize = qBound(DOCK_MIN_SIZE, dockSize, DOCK_MAX_SIZE);
// 通知窗管和后端更新数据
m_multiScreenWorker->updateDaemonDockSize(dockSize); // 1.先更新任务栏高度
m_multiScreenWorker->requestUpdateFrontendGeometry(); // 2.再更新任务栏位置,保证先1再2
m_multiScreenWorker->requestNotifyWindowManager();
m_multiScreenWorker->requestUpdateRegionMonitor(); // 界面发生变化,应更新监控区域
}
void MainWindowBase::touchRequestResizeDock()
{
const QPoint touchPos(QCursor::pos());
QRect dockRect = geometry();
// 隐藏状态返回
if (width() == 0 || height() == 0)
return;
int resizeHeight = Utils::SettingValue("com.deepin.dde.dock.touch", QByteArray(), "resizeHeight", 7).toInt();
QRect touchRect;
// 任务栏屏幕 内侧边线 内外resizeHeight距离矩形区域内长按可拖动任务栏高度
switch (position()) {
case Position::Top:
touchRect = QRect(dockRect.x(), dockRect.y() + dockRect.height() - resizeHeight, dockRect.width(), resizeHeight * 2);
break;
case Position::Bottom:
touchRect = QRect(dockRect.x(), dockRect.y() - resizeHeight, dockRect.width(), resizeHeight * 2);
break;
case Position::Left:
touchRect = QRect(dockRect.x() + dockRect.width() - resizeHeight, dockRect.y(), resizeHeight * 2, dockRect.height());
break;
case Position::Right:
touchRect = QRect(dockRect.x() - resizeHeight, dockRect.y(), resizeHeight * 2, dockRect.height());
break;
}
if (!touchRect.contains(touchPos))
return;
qApp->postEvent(m_dragWidget, new QMouseEvent(QEvent::MouseButtonPress, m_dragWidget->mapFromGlobal(touchPos)
, QPoint(), touchPos, Qt::LeftButton, Qt::NoButton
, Qt::NoModifier, Qt::MouseEventSynthesizedByApplication));
}
void MainWindowBase::adjustShadowMask()
{
if (!m_isShow || m_shadowMaskOptimizeTimer->isActive())
return;
m_platformWindowHandle.setWindowRadius(m_borderRadius);
}
void MainWindowBase::onCompositeChanged()
{
setMaskColor(AutoColor);
setMaskAlpha(m_multiScreenWorker->opacity());
m_platformWindowHandle.setBorderWidth(0);
m_shadowMaskOptimizeTimer->start();
}
void MainWindowBase::onThemeTypeChanged(DGuiApplicationHelper::ColorType themeType)
{
if (DWindowManagerHelper::instance()->hasComposite()) {
if (themeType == DGuiApplicationHelper::DarkType) {
QColor color = Qt::black;
color.setAlpha(255 * 0.3);
m_platformWindowHandle.setBorderColor(color);
} else {
m_platformWindowHandle.setBorderColor(QColor(QColor::Invalid));
}
}
}
void MainWindowBase::setDisplayMode(const Dock::DisplayMode &displayMode)
{
m_displayMode = displayMode;
adjustShadowMask();
}
void MainWindowBase::setPosition(const Dock::Position &position)
{
m_position = position;
}
QRect MainWindowBase::getDockGeometry(QScreen *screen, const Dock::Position &pos, const Dock::DisplayMode &displaymode, const Dock::HideState &hideState, bool withoutScale) const
{
QList<MainWindowBase const *> topMainWindows; // 所有的顶层主窗口列表
QList<MainWindowBase const *> lessOrderMainWindows; // 所有在当前窗口之前的主窗口
QWidgetList topWidgets = qApp->topLevelWidgets();
for (QWidget *widget : topWidgets) {
MainWindowBase *currentWindow = qobject_cast<MainWindowBase *>(widget);
if (!currentWindow || !currentWindow->isVisible())
continue;
topMainWindows << currentWindow;
if (currentWindow->order() < order())
lessOrderMainWindows << currentWindow;
}
if (!topMainWindows.contains(this))
return QRect();
// 对当前窗口前面的所有窗口按照order进行排序
sort(lessOrderMainWindows.begin(), lessOrderMainWindows.end(), [](MainWindowBase const *window1, MainWindowBase const *window2) {
return window1->order() < window2->order();
});
QRect rect;
const double ratio = withoutScale ? 1 : qApp->devicePixelRatio();
const int margin = static_cast<int>((displaymode == DisplayMode::Fashion ? 10 : 0) * (withoutScale ? qApp->devicePixelRatio() : 1));
int dockSize = 0;
if (hideState == Dock::HideState::Show)
dockSize = windowSize();
// 拿到当前显示器缩放之前的分辨率
QRect screenRect = screen->handle()->geometry();
// 计算所有的窗口的总尺寸
int totalSize = 0;
switch (pos) {
case Dock::Position::Top:
case Dock::Position::Bottom: {
// 计算任务栏的总的尺寸
int width = 0;
for (MainWindowBase const *mainWindow : topMainWindows) {
QSize windowSize = mainWindow->suitableSize(pos, screenRect.width(), ratio);
totalSize += windowSize.width() + mainWindow->dockSpace();
if (mainWindow == this)
width = windowSize.width();
}
// 计算第一个窗口的X坐标
int x = screenRect.x() + (static_cast<int>((screenRect.width() / ratio) - totalSize) / 2);
// 计算当前的X坐标
for (MainWindowBase const *mainWindow : lessOrderMainWindows) {
x += mainWindow->suitableSize(pos, screenRect.width(), ratio).width() + mainWindow->dockSpace();
}
int y = 0;
if (pos == Dock::Position::Top)
y = (screenRect.y() + static_cast<int>(margin / ratio));
else
y = (screenRect.y() + static_cast<int>(screenRect.height() / ratio - margin / ratio)) - dockSize;
rect.setX(x);
rect.setY(y);
rect.setWidth(width);
rect.setHeight(dockSize);
break;
}
case Dock::Position::Left:
case Dock::Position::Right: {
int height = 0;
for (MainWindowBase const *mainWindow : topMainWindows) {
QSize windowSize = mainWindow->suitableSize(pos, screenRect.height(), ratio);
totalSize += windowSize.height() + mainWindow->dockSpace();
if (mainWindow == this)
height = windowSize.height();
}
int x = 0;
if (pos == Dock::Position::Left)
x = screenRect.x() + static_cast<int>(margin / ratio);
else
x = screenRect.x() + static_cast<int>(screenRect.width() /ratio - margin / ratio) - dockSize;
int y = screenRect.y() + static_cast<int>(((screenRect.height() / ratio) - totalSize) / 2);
// 计算y坐标
for (MainWindowBase const *mainWindow : lessOrderMainWindows)
y += mainWindow->suitableSize(pos, screenRect.height(), ratio).height() + mainWindow->dockSpace();
rect.setX(x);
rect.setY(y);
rect.setWidth(dockSize);
rect.setHeight(height);
break;
}
}
return rect;
}
QVariantAnimation *MainWindowBase::createAnimation(QScreen *screen, const Dock::Position &pos, const Dock::AniAction &act)
{
/** FIXME
* 2.75mainWindowGeometry返回的任务栏高度有问题40,39
* 3842
* 1
*
*/
QRect mainwindowRect = geometry();
const QRect dockShowRect = getDockGeometry(screen, pos, m_multiScreenWorker->displayMode(), Dock::HideState::Show);
const QRect &dockHideRect = getDockGeometry(screen, pos, m_multiScreenWorker->displayMode(), Dock::HideState::Hide);
if (act == Dock::AniAction::Show) {
if (pos == Position::Top || pos == Position::Bottom) {
if (qAbs(dockShowRect.height() - mainwindowRect.height()) <= 1
&& mainwindowRect.contains(dockShowRect.center()))
return nullptr;
} else if (pos == Position::Left || pos == Position::Right) {
if (qAbs(dockShowRect.width() - mainwindowRect.width()) <= 1
&& mainwindowRect.contains(dockShowRect.center()))
return nullptr;
}
}
if (act == Dock::AniAction::Hide && dockHideRect.size() == mainwindowRect.size())
return nullptr;
// 开始播放动画
QVariantAnimation *ani = new QVariantAnimation(nullptr);
ani->setEasingCurve(QEasingCurve::InOutCubic);
#ifndef DISABLE_SHOW_ANIMATION
const bool composite = DWindowManagerHelper::instance()->hasComposite(); // 判断是否开启特效模式
const int duration = composite ? ANIMATIONTIME : 0;
#else
const int duration = 0;
#endif
ani->setDuration(duration);
connect(ani, &QVariantAnimation::valueChanged, this, [ = ](const QVariant &value) {
if ((!m_multiScreenWorker->testState(MultiScreenWorker::ShowAnimationStart)
&& !m_multiScreenWorker->testState(MultiScreenWorker::HideAnimationStart)
&& !m_multiScreenWorker->testState(MultiScreenWorker::ChangePositionAnimationStart))
|| ani->state() != QVariantAnimation::State::Running)
return;
updateParentGeometry(pos, value.value<QRect>());
});
switch (act) {
case Dock::AniAction::Show: {
ani->setStartValue(dockHideRect);
ani->setEndValue(dockShowRect);
connect(ani, &QVariantAnimation::finished, this, [ = ]{
updateParentGeometry(pos, dockShowRect);
});
break;
}
case Dock::AniAction::Hide: {
ani->setStartValue(dockShowRect);
ani->setEndValue(dockHideRect);
connect(ani, &QVariantAnimation::finished, this, [ = ]{
updateParentGeometry(pos, dockHideRect);
});
break;
}
}
return ani;
}
Dock::DisplayMode MainWindowBase::displayMode() const
{
return m_displayMode;
}
Dock::Position MainWindowBase::position() const
{
return m_position;
}
int MainWindowBase::windowSize() const
{
if (m_displayMode == Dock::DisplayMode::Efficient)
return m_dockInter->windowSizeEfficient();
return m_dockInter->windowSizeFashion();
}
bool MainWindowBase::isDraging() const
{
return m_dragWidget->isDraging();
}
int MainWindowBase::dockSpace() const
{
return DOCKSPACE;
}
void MainWindowBase::initUi()
{
DPlatformWindowHandle::enableDXcbForWindow(this, true);
m_platformWindowHandle.setEnableBlurWindow(true);
m_platformWindowHandle.setTranslucentBackground(true);
m_platformWindowHandle.setShadowOffset(QPoint(0, 0));
m_platformWindowHandle.setShadowColor(Qt::transparent);
}
void MainWindowBase::resizeEvent(QResizeEvent *event)
{
updateDragGeometry();
int borderRadius = getBorderRadius();
if (borderRadius != m_borderRadius) {
m_borderRadius = borderRadius;
updateRadius(m_borderRadius);
}
m_shadowMaskOptimizeTimer->start();
}
void MainWindowBase::moveEvent(QMoveEvent *)
{
updateDragGeometry();
}
void MainWindowBase::enterEvent(QEvent *e)
{
QWidget::enterEvent(e);
if (QApplication::overrideCursor() && QApplication::overrideCursor()->shape() != Qt::ArrowCursor)
QApplication::restoreOverrideCursor();
}
void MainWindowBase::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::RightButton && geometry().contains(QCursor::pos())) {
m_multiScreenWorker->onAutoHideChanged(false);
MenuWorker menuWorker;
menuWorker.exec();
m_multiScreenWorker->onAutoHideChanged(true);
}
DBlurEffectWidget::mousePressEvent(event);
}
void MainWindowBase::showEvent(QShowEvent *event)
{
if (!m_isShow) {
m_isShow = true;
m_shadowMaskOptimizeTimer->start();
}
DBlurEffectWidget::showEvent(event);
}

View File

@ -0,0 +1,118 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef MAINWINDOWBASE_H
#define MAINWINDOWBASE_H
#include "constants.h"
#include "dbusutil.h"
#include <DBlurEffectWidget>
#include <DPlatformWindowHandle>
#include <DGuiApplicationHelper>
#include <QEvent>
#include <QMouseEvent>
#include <utils.h>
class DragWidget;
class MultiScreenWorker;
DWIDGET_USE_NAMESPACE
class MainWindowBase : public DBlurEffectWidget
{
Q_OBJECT
public:
enum class DockWindowType {
MainWindow, // 主窗口
TrayWindow // 主窗口之外的其他窗口
};
public:
explicit MainWindowBase(MultiScreenWorker *multiScreenWorker, QWidget *parent = Q_NULLPTR);
virtual ~MainWindowBase();
void setOrder(int order); // 窗体展示的顺序,按照左到右和上到下
int order() const;
virtual DockWindowType windowType() const = 0;
virtual void setDisplayMode(const Dock::DisplayMode &displayMode);
virtual void setPosition(const Dock::Position &position);
// 用来更新子区域的位置一般用于在执行动画的过程中根据当前的位置来更新里面panel的大小
virtual void updateParentGeometry(const Dock::Position &pos, const QRect &rect) = 0;
virtual QRect getDockGeometry(QScreen *screen, const Dock::Position &pos, const Dock::DisplayMode &displaymode, const Dock::HideState &hideState, bool withoutScale = false) const;
QVariantAnimation *createAnimation(QScreen *screen, const Dock::Position &pos, const Dock::AniAction &act);
virtual void resetPanelGeometry() {} // 重置内部区域,为了让内部区域和当前区域始终保持一致
virtual int dockSpace() const; // 与后面窗体之间的间隔
Q_SIGNALS:
void requestUpdate();
protected:
void resizeEvent(QResizeEvent *event) override;
void moveEvent(QMoveEvent *) override;
void enterEvent(QEvent *e) override;
void mousePressEvent(QMouseEvent *event) override;
void showEvent(QShowEvent *event) override;
Dock::DisplayMode displayMode() const;
Dock::Position position() const;
int windowSize() const;
bool isDraging() const;
virtual void updateRadius(int borderRadius) {}
virtual QSize suitableSize(const Dock::Position &pos, const int &screenSize, const double &deviceRatio) const = 0;
private:
void initUi();
void initAttribute();
void initConnection();
void initMember();
void updateDragGeometry();
int getBorderRadius() const;
private Q_SLOTS:
void onMainWindowSizeChanged(QPoint offset);
void resetDragWindow();
void touchRequestResizeDock();
void adjustShadowMask();
void onCompositeChanged();
void onThemeTypeChanged(DGuiApplicationHelper::ColorType themeType);
private:
Dock::DisplayMode m_displayMode;
Dock::Position m_position;
DockInter *m_dockInter;
DragWidget *m_dragWidget;
MultiScreenWorker *m_multiScreenWorker;
QTimer *m_updateDragAreaTimer;
DPlatformWindowHandle m_platformWindowHandle;
QTimer *m_shadowMaskOptimizeTimer;
bool m_isShow;
int m_borderRadius;
int m_order;
};
#endif // MAINWINDOWBASE_H

View File

@ -131,6 +131,11 @@ void QuickPluginWindow::dragPlugin(PluginsItemInterface *item)
Q_EMIT itemCountChanged();
}
QSize QuickPluginWindow::suitableSize() const
{
return suitableSize(m_position);
}
void QuickPluginWindow::addPlugin(QuickSettingItem *item)
{
for (int i = 0; i < m_mainLayout->count(); i++) {
@ -163,9 +168,9 @@ void QuickPluginWindow::addPlugin(QuickSettingItem *item)
Q_EMIT itemCountChanged();
}
QSize QuickPluginWindow::suitableSize()
QSize QuickPluginWindow::suitableSize(const Dock::Position &position) const
{
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom)
if (position == Dock::Position::Top || position == Dock::Position::Bottom)
return QSize((ITEMSPACE + ICONWIDTH) * m_mainLayout->count() + ITEMSPACE, ITEMSIZE);
int height = 0;

View File

@ -52,7 +52,8 @@ public:
void setPositon(Dock::Position position);
void dragPlugin(PluginsItemInterface *item);
QSize suitableSize();
QSize suitableSize() const;
QSize suitableSize(const Dock::Position &position) const;
Q_SIGNALS:
void itemCountChanged();

View File

@ -72,17 +72,22 @@ void SystemPluginWindow::setPositon(Position position)
}
}
QSize SystemPluginWindow::suitableSize()
QSize SystemPluginWindow::suitableSize() const
{
return suitableSize(m_position);
}
QSize SystemPluginWindow::suitableSize(const Position &position) const
{
QObjectList childs = children();
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) {
if (position == Dock::Position::Top || position == Dock::Position::Bottom) {
int itemWidth = 0;
for (QObject *childObject : childs) {
StretchPluginsItem *childItem = qobject_cast<StretchPluginsItem *>(childObject);
if (!childItem)
continue;
itemWidth += childItem->suitableSize().width();
itemWidth += childItem->suitableSize(position).width();
}
return QSize(itemWidth, QWIDGETSIZE_MAX);
@ -94,7 +99,7 @@ QSize SystemPluginWindow::suitableSize()
if (!item)
continue;
itemHeight += item->suitableSize().height();
itemHeight += item->suitableSize(position).height();
}
return QSize(QWIDGETSIZE_MAX, itemHeight);
@ -175,6 +180,11 @@ QString StretchPluginsItem::itemKey() const
return m_itemKey;
}
QSize StretchPluginsItem::suitableSize() const
{
return suitableSize(m_position);
}
PluginsItemInterface *StretchPluginsItem::pluginInter() const
{
return m_pluginInter;
@ -210,31 +220,38 @@ void StretchPluginsItem::paintEvent(QPaintEvent *event)
painter.drawPixmap(rctPixmap, icon.pixmap(iconSize, iconSize));
}
QSize StretchPluginsItem::suitableSize() const
QSize StretchPluginsItem::suitableSize(const Position &position) const
{
int iconSize = static_cast<int>(ICONSIZE * (qApp->devicePixelRatio()));
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) {
int textWidth = QFontMetrics(textFont()).boundingRect(m_pluginInter->pluginDisplayName()).width();
if (position == Dock::Position::Top || position == Dock::Position::Bottom) {
int textWidth = QFontMetrics(textFont(position)).boundingRect(m_pluginInter->pluginDisplayName()).width();
return QSize(qMax(textWidth, iconSize) + 10 * 2, -1);
}
int height = 6; // 图标上边距6
height += iconSize; // 图标尺寸20
height += ICONTEXTSPACE; // 图标与文字间距6
height += QFontMetrics(textFont()).height(); // 文本高度
height += 4; // 下间距4
int height = 6; // 图标上边距6
height += iconSize; // 图标尺寸20
height += ICONTEXTSPACE; // 图标与文字间距6
height += QFontMetrics(textFont(position)).height(); // 文本高度
height += 4; // 下间距4
return QSize(-1, height);
}
QFont StretchPluginsItem::textFont() const
{
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) {
return textFont(m_position);
}
QFont StretchPluginsItem::textFont(const Position &position) const
{
if (position == Dock::Position::Top || position == Dock::Position::Bottom) {
static QList<QFont> fonts{ DFontSizeManager::instance()->t9(),
DFontSizeManager::instance()->t8(),
DFontSizeManager::instance()->t7(),
DFontSizeManager::instance()->t6() };
#define MINHEIGHT 50
int index = qMin(qMax((height() - MINHEIGHT) / 2, 0), fonts.size() - 1);
// 如果当前的实际位置和请求的位置不一致,说明当前正在切换位置,此时将它的宽度作为它的高度(左到下切换的时候,左侧的宽度和下面的高度一致)
int size = (m_position == position ? height() : width());
int index = qMin(qMax((size - MINHEIGHT) / 2, 0), fonts.size() - 1);
return fonts[index];
}

View File

@ -43,7 +43,8 @@ public:
explicit SystemPluginWindow(QWidget *parent = nullptr);
~SystemPluginWindow() override;
void setPositon(Dock::Position position);
QSize suitableSize();
QSize suitableSize() const;
QSize suitableSize(const Dock::Position &position) const;
Q_SIGNALS:
void itemChanged();
@ -75,6 +76,7 @@ public:
PluginsItemInterface *pluginInter() const;
QString itemKey() const;
QSize suitableSize() const;
QSize suitableSize(const Dock::Position &position) const;
inline ItemType itemType() const override { return DockItem::StretchPlugin; }
@ -89,6 +91,7 @@ protected:
private:
void mouseClick();
QFont textFont() const;
QFont textFont(const Dock::Position &position) const;
bool needShowText() const;
private:

View File

@ -59,6 +59,11 @@ Dock::Position TrayGridView::position() const
}
QSize TrayGridView::suitableSize() const
{
return suitableSize(m_positon);
}
QSize TrayGridView::suitableSize(const Dock::Position &position) const
{
TrayModel *dataModel = qobject_cast<TrayModel *>(model());
if (!dataModel)
@ -88,21 +93,38 @@ QSize TrayGridView::suitableSize() const
}
return QSize(width, height);
}
if (m_positon == Dock::Position::Top || m_positon == Dock::Position::Bottom) {
if (position == Dock::Position::Top || position == Dock::Position::Bottom) {
int length = spacing() + 2;
for (int i = 0; i < dataModel->rowCount(); i++) {
QModelIndex index = dataModel->index(i, 0);
QRect indexRect = visualRect(index);
length += indexRect.width() + spacing();
if (m_positon == Dock::Position::Top || m_positon == Dock::Position::Bottom) {
for (int i = 0; i < dataModel->rowCount(); i++) {
QModelIndex index = dataModel->index(i, 0);
QRect indexRect = visualRect(index);
length += indexRect.width() + spacing();
}
} else {
// 如果是从左右切换过来的,此时还未进入上下位置,则将当前位置的高度作为计算左右位置的宽度
for (int i = 0; i < dataModel->rowCount(); i++) {
QModelIndex index = dataModel->index(i, 0);
QRect indexRect = visualRect(index);
length += indexRect.height() + spacing();
}
}
return QSize(length, -1);
}
int height = spacing() + 2;
for (int i = 0; i < dataModel->rowCount(); i++) {
QModelIndex index = dataModel->index(i, 0);
QRect indexRect = visualRect(index);
height += indexRect.height() + spacing();
if (m_positon == Dock::Position::Left || m_positon == Dock::Position::Right) {
for (int i = 0; i < dataModel->rowCount(); i++) {
QModelIndex index = dataModel->index(i, 0);
QRect indexRect = visualRect(index);
height += indexRect.height() + spacing();
}
} else {
for (int i = 0; i < dataModel->rowCount(); i++) {
QModelIndex index = dataModel->index(i, 0);
QRect indexRect = visualRect(index);
height += indexRect.width() + spacing();
}
}
return QSize(-1, height);

View File

@ -39,6 +39,7 @@ public:
void setPosition(Dock::Position position);
Dock::Position position() const;
QSize suitableSize() const;
QSize suitableSize(const Dock::Position &position) const;
void setDragDistance(int pixel);
void setAnimationProperty(const QEasingCurve::Type easing, const int duringTime = 250);
void moveAnimation();

View File

@ -0,0 +1,163 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "traymainwindow.h"
#include "traymanagerwindow.h"
#include "dragwidget.h"
#include "dockscreen.h"
#include "displaymanager.h"
#include <DSysInfo>
#include <DPlatformTheme>
#include <DStyleHelper>
#include <QBitmap>
#include <QBoxLayout>
#include <QX11Info>
#include <qpa/qplatformwindow.h>
#include <qpa/qplatformscreen.h>
#include <qpa/qplatformnativeinterface.h>
#define DOCK_SCREEN DockScreen::instance()
#define DIS_INS DisplayManager::instance()
TrayMainWindow::TrayMainWindow(MultiScreenWorker *multiScreenWorker, QWidget *parent)
: MainWindowBase(multiScreenWorker, parent)
, m_trayManager(new TrayManagerWindow(this))
, m_multiScreenWorker(multiScreenWorker)
{
initUI();
initConnection();
}
void TrayMainWindow::setPosition(const Dock::Position &position)
{
MainWindowBase::setPosition(position);
m_trayManager->setPositon(position);
}
TrayManagerWindow *TrayMainWindow::trayManagerWindow() const
{
return m_trayManager;
}
void TrayMainWindow::setDisplayMode(const Dock::DisplayMode &displayMode)
{
// 只有在时尚模式下才显示
setVisible(displayMode == Dock::DisplayMode::Fashion);
MainWindowBase::setDisplayMode(displayMode);
}
MainWindowBase::DockWindowType TrayMainWindow::windowType() const
{
return DockWindowType::TrayWindow;
}
void TrayMainWindow::updateParentGeometry(const Dock::Position &position, const QRect &rect)
{
QSize trayPanelSize = m_trayManager->suitableSize(position);
// 设置trayManagerWindow的大小和位置
if (position == Dock::Position::Top || position == Dock::Position::Bottom) {
setFixedSize(trayPanelSize.width(), rect.height());
move(rect.topLeft());
} else {
setFixedSize(rect.width(), trayPanelSize.height());
move(rect.topLeft());
}
int panelSize = windowSize();
QRect panelRect = rect;
switch(position) {
case Dock::Position::Left:
m_trayManager->move(width() - panelSize, 0);
panelRect.setWidth(panelSize);
panelRect.setHeight(trayPanelSize.height());
break;
case Dock::Position::Top:
m_trayManager->move(0, height() - panelSize);
panelRect.setWidth(trayPanelSize.width());
panelRect.setHeight(panelSize);
break;
case Dock::Position::Right: {
m_trayManager->move(0, 0);
panelRect.setWidth(panelSize);
panelRect.setHeight(trayPanelSize.height());
break;
}
case Dock::Position::Bottom: {
m_trayManager->move(0, 0);
panelRect.setWidth(trayPanelSize.width());
panelRect.setHeight(panelSize);
break;
}
}
// 在从高效模式切换到时尚模式的时候,需要调用该函数来设置托盘区域的尺寸,在设置尺寸的时候会触发
// 托盘区域的requestUpdate信号WindowManager接收到requestUpdate会依次对每个顶层界面设置尺寸此时又会触发该函数
// 引起无限循环,因此,在设置尺寸的时候阻塞信号,防止进入死循环
m_trayManager->blockSignals(true);
m_trayManager->setFixedSize(panelRect.size());
m_trayManager->blockSignals(false);
}
QSize TrayMainWindow::suitableSize() const
{
return m_trayManager->suitableSize();
}
void TrayMainWindow::resetPanelGeometry()
{
m_trayManager->setFixedSize(size());
m_trayManager->move(0, 0);
}
int TrayMainWindow::dockSpace() const
{
return 0;
}
void TrayMainWindow::updateRadius(int borderRadius)
{
m_trayManager->updateBorderRadius(borderRadius);
}
QSize TrayMainWindow::suitableSize(const Dock::Position &pos, const int &, const double &) const
{
return m_trayManager->suitableSize(pos);
}
void TrayMainWindow::initUI()
{
m_trayManager->move(0, 0);
}
void TrayMainWindow::initConnection()
{
connect(m_trayManager, &TrayManagerWindow::requestUpdate, this, &TrayMainWindow::onRequestUpdate);
}
void TrayMainWindow::onRequestUpdate()
{
// 如果当前是高效模式,则无需发送信号
if (displayMode() == Dock::DisplayMode::Efficient)
return;
Q_EMIT requestUpdate();
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TRAYMAINWINDOW_H
#define TRAYMAINWINDOW_H
#include "constants.h"
#include "mainwindowbase.h"
#include <DBlurEffectWidget>
class TrayManagerWindow;
class MultiScreenWorker;
DWIDGET_USE_NAMESPACE
class TrayMainWindow : public MainWindowBase
{
Q_OBJECT
public:
TrayMainWindow(MultiScreenWorker *multiScreenWorker, QWidget *parent = Q_NULLPTR);
void setPosition(const Dock::Position &position) override;
TrayManagerWindow *trayManagerWindow() const;
void setDisplayMode(const Dock::DisplayMode &displayMode) override;
DockWindowType windowType() const override;
void updateParentGeometry(const Dock::Position &position, const QRect &rect) override;
QSize suitableSize(const Dock::Position &pos, const int &, const double &) const override;
QSize suitableSize() const;
void resetPanelGeometry() override;
protected:
int dockSpace() const override;
void updateRadius(int borderRadius) override;
private:
void initUI();
void initConnection();
private Q_SLOTS:
void onRequestUpdate();
private:
TrayManagerWindow *m_trayManager;
MultiScreenWorker *m_multiScreenWorker;
};
#endif // TRAYMAINWINDOW_H

View File

@ -57,34 +57,44 @@ TrayManagerWindow::TrayManagerWindow(QWidget *parent)
, m_quickIconWidget(new QuickPluginWindow(m_appPluginWidget))
, m_dateTimeWidget(new DateTimeDisplayer(m_appPluginDatetimeWidget))
, m_appPluginLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight, this))
, m_appDatetimeLayout(new QBoxLayout(QBoxLayout::Direction::TopToBottom, this))
, m_mainLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight, this))
, m_trayView(new TrayGridView(this))
, m_model(new TrayModel(m_trayView, false, true))
, m_delegate(new TrayDelegate(m_trayView, m_trayView))
, m_postion(Dock::Position::Bottom)
, m_position(Dock::Position::Bottom)
, m_splitLine(new QLabel(m_appPluginDatetimeWidget))
, m_dockInter(new DockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus(), this))
, m_singleShow(false)
, m_borderRadius(0)
{
initUi();
initConnection();
setAcceptDrops(true);
setMouseTracking(true);
QMetaObject::invokeMethod(this, &TrayManagerWindow::updateLayout, Qt::QueuedConnection);
}
TrayManagerWindow::~TrayManagerWindow()
{
}
void TrayManagerWindow::updateBorderRadius(int borderRadius)
{
m_borderRadius = borderRadius;
update();
}
void TrayManagerWindow::updateLayout()
{
bool showSingle = true;
if (m_postion == Dock::Position::Top || m_postion == Dock::Position::Bottom)
showSingle = (topLevelWidget()->height() <= CRITLCALHEIGHT);
bool lastIsSingle = m_singleShow;
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom)
m_singleShow = (height() <= CRITLCALHEIGHT);
else
m_singleShow = true;
QBoxLayout::Direction lastDirection = m_appDatetimeLayout->direction();
if (showSingle)
if (m_singleShow)
resetSingleDirection();
else
resetMultiDirection();
@ -94,16 +104,16 @@ void TrayManagerWindow::updateLayout()
Q_EMIT m_delegate->sizeHintChanged(m_model->index(0, 0));
// 当插件区域从单行变成两行或者两行变成单行的时候,发送该信号,通知外部重新调整区域大小
if (lastDirection != m_appDatetimeLayout->direction())
if (lastIsSingle != m_singleShow)
Q_EMIT requestUpdate();
}
void TrayManagerWindow::setPositon(Dock::Position position)
{
if (m_postion == position)
if (m_position == position)
return;
m_postion = position;
m_position = position;
if (position == Dock::Position::Top || position == Dock::Position::Bottom)
m_trayView->setOrientation(QListView::Flow::LeftToRight, false);
@ -120,51 +130,62 @@ void TrayManagerWindow::setPositon(Dock::Position position)
m_quickIconWidget->setPositon(position);
m_dateTimeWidget->setPositon(position);
m_systemPluginWidget->setPositon(position);
updateLayout();
}
int TrayManagerWindow::appDatetimeSize()
int TrayManagerWindow::appDatetimeSize(const Dock::Position &position) const
{
if (m_postion == Dock::Position::Top || m_postion == Dock::Position::Bottom) {
// 如果是一行
if (m_appDatetimeLayout->direction() == QBoxLayout::Direction::LeftToRight) {
return m_trayView->suitableSize().width() + m_quickIconWidget->suitableSize().width()
+ m_dateTimeWidget->suitableSize().width() + m_appDatetimeLayout->spacing();
if (position == Dock::Position::Top || position == Dock::Position::Bottom) {
bool showSingle = m_singleShow;
// 正在从左右切换到上下(m_position当前显示的位置还未切换),此时根据托盘区域的尺寸来决定显示一行还是两行
if (m_position == Dock::Position::Left || m_position == Dock::Position::Right) {
showSingle = m_dockInter->windowSizeFashion() < CRITLCALHEIGHT;
}
// 如果是一行或者是在切换位置(从左右切换到上下)
if (showSingle) {
return m_trayView->suitableSize(position).width() + m_quickIconWidget->suitableSize(position).width()
+ m_dateTimeWidget->suitableSize(position).width() + 4;
}
//如果是两行
int topWidth = m_trayView->suitableSize().width() + m_appDatetimeLayout->spacing() + m_quickIconWidget->width();
int bottomWidth = m_dateTimeWidget->suitableSize().width();
int topWidth = m_trayView->suitableSize(position).width() + m_quickIconWidget->suitableSize(position).width();
int bottomWidth = m_dateTimeWidget->suitableSize(position).width();
return qMax(topWidth, bottomWidth);
}
int trayHeight = m_trayView->suitableSize().height();
QMargins m = m_appDatetimeLayout->contentsMargins();
int traypluginHeight = trayHeight + m_quickIconWidget->suitableSize().height() + m.top() + m.bottom() + m_appPluginLayout->spacing();
return traypluginHeight + m_appDatetimeLayout->spacing() + m_dateTimeWidget->suitableSize().height() + 10;
int trayHeight = m_trayView->suitableSize(position).height();
int traypluginHeight = trayHeight + m_quickIconWidget->suitableSize(position).height() + m_appPluginLayout->spacing();
return traypluginHeight + m_dateTimeWidget->suitableSize(position).height() + 10;
}
QSize TrayManagerWindow::suitableSize()
QSize TrayManagerWindow::suitableSize() const
{
return suitableSize(m_position);
}
QSize TrayManagerWindow::suitableSize(const Dock::Position &position) const
{
QMargins m = m_mainLayout->contentsMargins();
if (m_postion == Dock::Position::Top || m_postion == Dock::Position::Bottom) {
return QSize(appDatetimeSize() + m_appDatetimeLayout->spacing() +
m_systemPluginWidget->suitableSize().width() + m_mainLayout->spacing() +
if (position == Dock::Position::Top || position == Dock::Position::Bottom) {
return QSize(appDatetimeSize(position) +
m_systemPluginWidget->suitableSize(position).width() + m_mainLayout->spacing() +
m.left() + m.right(), QWIDGETSIZE_MAX);
}
return QSize(QWIDGETSIZE_MAX, appDatetimeSize() + m_appDatetimeLayout->spacing() +
m_systemPluginWidget->suitableSize().height() + m_mainLayout->spacing() +
return QSize(QWIDGETSIZE_MAX, appDatetimeSize(position) +
m_systemPluginWidget->suitableSize(position).height() + m_mainLayout->spacing() +
m.top() + m.bottom());
}
// 用于返回需要绘制的圆形区域
QPainterPath TrayManagerWindow::roundedPaths()
{
int topLevelRadius = qApp->property("EffectBorderRadius").toInt();
QMargins mainMargin = m_mainLayout->contentsMargins();
int radius = topLevelRadius - mainMargin.top();
int radius = m_borderRadius - mainMargin.top();
QPainterPath path;
if ((m_postion == Dock::Position::Top || m_postion == Dock::Position::Bottom)
&& (m_appDatetimeLayout->direction() == QBoxLayout::Direction::LeftToRight)) {
if ((m_position == Dock::Position::Top || m_position == Dock::Position::Bottom)
&& m_singleShow) {
// 如果是上下方向,且只有一行
// 计算托盘和快捷插件区域
QPoint pointPlugin(mainMargin.left(), mainMargin.top());
@ -220,13 +241,6 @@ void TrayManagerWindow::initUi()
m_appPluginLayout->addWidget(m_trayView);
m_appPluginLayout->addWidget(m_quickIconWidget);
m_appPluginDatetimeWidget->setLayout(m_appDatetimeLayout);
m_appDatetimeLayout->setContentsMargins(0, 0, 0, 0);
m_appDatetimeLayout->setSpacing(0);
m_appDatetimeLayout->addWidget(m_appPluginWidget);
m_appDatetimeLayout->addWidget(m_splitLine);
m_appDatetimeLayout->addWidget(m_dateTimeWidget);
setLayout(m_mainLayout);
// 通用情况下设置边距和间距都为7
m_mainLayout->setContentsMargins(CONTENTSPACE, CONTENTSPACE, CONTENTSPACE, CONTENTSPACE);
@ -253,7 +267,7 @@ void TrayManagerWindow::initConnection()
connect(m_quickIconWidget, &QuickPluginWindow::itemCountChanged, this, [ this ] {
// 当插件数量发生变化的时候,需要调整尺寸
m_quickIconWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
if (m_postion == Dock::Position::Top || m_postion == Dock::Position::Bottom)
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom)
m_quickIconWidget->setFixedWidth(m_quickIconWidget->suitableSize().width());
else
m_quickIconWidget->setFixedHeight(m_quickIconWidget->suitableSize().height());
@ -264,7 +278,7 @@ void TrayManagerWindow::initConnection()
connect(m_systemPluginWidget, &SystemPluginWindow::itemChanged, this, [ this ] {
// 当系统插件发生变化的时候,同样需要调整尺寸
m_systemPluginWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
if (m_postion == Dock::Position::Top || m_postion == Dock::Position::Bottom)
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom)
m_systemPluginWidget->setFixedWidth(m_systemPluginWidget->suitableSize().width());
else
m_systemPluginWidget->setFixedHeight(m_systemPluginWidget->suitableSize().height());
@ -310,12 +324,13 @@ void TrayManagerWindow::resetChildWidgetSize()
count++;
}
switch (m_postion) {
switch (m_position) {
case Dock::Position::Top:
case Dock::Position::Bottom: {
int trayWidth = m_trayView->suitableSize().width();
int appDateTimeWidth = appDatetimeSize(m_position);
QMargins m = m_appPluginLayout->contentsMargins();
if (m_appDatetimeLayout->direction() == QBoxLayout::Direction::LeftToRight) {
if (m_singleShow) {
// 单行显示
int trayHeight = m_appPluginDatetimeWidget->height() - m.top() - m.bottom();
m_trayView->setFixedSize(trayWidth, trayHeight);
@ -324,27 +339,46 @@ void TrayManagerWindow::resetChildWidgetSize()
m_dateTimeWidget->setFixedSize(m_dateTimeWidget->suitableSize().width(), trayHeight);
// 设置右侧的电源按钮的尺寸
m_systemPluginWidget->setFixedSize(m_systemPluginWidget->suitableSize());
m_mainLayout->setContentsMargins(4, 4, 4 ,4);
m_mainLayout->setSpacing(4);
m_appDatetimeLayout->setSpacing(4);
// 如果顶层窗体的高度为0则直接让其间距为0否则就会出现隐藏模式下有8个像素的高度依然显示
int space = topLevelWidget()->height() == 0 ? 0 : 4;
m_mainLayout->setContentsMargins(space, space, space ,space);
m_mainLayout->setSpacing(space);
// 单行显示需要重新设置插件和时间日期的位置,不显示分割线
m_splitLine->setVisible(false);
m_appPluginWidget->move(0, 0);
m_dateTimeWidget->move(m_appPluginWidget->x() + m_appPluginWidget->width() + 4, m_appPluginWidget->y());
} else {
// 多行显示
m_quickIconWidget->setFixedSize(m_quickIconWidget->suitableSize());
int trayHeight = m_appPluginDatetimeWidget->height() / 2 + 4 - m.top() - m.bottom();
m_trayView->setFixedSize(trayWidth, trayHeight);
m_quickIconWidget->setFixedSize(m_quickIconWidget->suitableSize().width(), trayHeight);
m_appPluginWidget->setFixedSize(trayWidth + m_quickIconWidget->suitableSize().width(), m_appPluginDatetimeWidget->height() / 2 + 4);
m_appPluginWidget->setFixedSize(trayWidth + m_quickIconWidget->suitableSize().width(), trayHeight);
// 因为是两行,所以对于时间控件的尺寸,只能设置最小值
int dateTimeWidth = qMax(m_appPluginWidget->width(), m_dateTimeWidget->suitableSize().width());
m_dateTimeWidget->setMinimumSize(dateTimeWidth, QWIDGETSIZE_MAX);
int dateTimeHeight = m_appPluginDatetimeWidget->height() - - m.top() - m.bottom() - trayHeight;
m_dateTimeWidget->setFixedSize(dateTimeWidth, dateTimeHeight);
m_systemPluginWidget->setFixedSize(m_systemPluginWidget->suitableSize());
int contentSpace = qMin(MAXDIFF, qMax(height() - MINHIGHT, 0)) + MINSPACE;
m_mainLayout->setContentsMargins(contentSpace, contentSpace, contentSpace, contentSpace);
m_appDatetimeLayout->setSpacing(0);
m_mainLayout->setSpacing(contentSpace);
// 调整插件和日期窗体的位置显示,这里没有用到布局,是因为在调整任务栏位置的时候,
// 随着布局方向的改变,显示有很大的问题
m_splitLine->setFixedWidth(appDateTimeWidth);
m_splitLine->setVisible(true);
if (m_position == Dock::Position::Bottom) {
m_appPluginWidget->move(0, 0);
m_splitLine->move(0, m_appPluginWidget->y() + m_appPluginWidget->height());
m_dateTimeWidget->move(0, m_appPluginWidget->y() + m_appPluginWidget->height() + m_splitLine->height());
} else {
m_dateTimeWidget->move(0, 0);
m_splitLine->move(0, m_dateTimeWidget->y() + m_dateTimeWidget->height());
m_appPluginWidget->move(0, m_dateTimeWidget->y() + m_dateTimeWidget->height() + m_splitLine->height());
}
}
QMargins margin = m_mainLayout->contentsMargins();
int appDateHeight = height() - margin.top() - margin.bottom();
m_appPluginDatetimeWidget->setFixedSize(appDatetimeSize(), appDateHeight);
m_appPluginDatetimeWidget->setFixedSize(appDateTimeWidth, appDateHeight);
break;
}
case Dock::Position::Left:
@ -361,13 +395,19 @@ void TrayManagerWindow::resetChildWidgetSize()
m_appPluginWidget->setFixedSize(sizeWidth, trayHeight + quickAreaHeight);
m_systemPluginWidget->setFixedSize(m_systemPluginWidget->suitableSize());
int contentSpace = qMin(MAXDIFF, qMax(width() - MINHIGHT, 0)) + MINSPACE;
int contentSpace = (qMin(MAXDIFF, qMax(width() - MINHIGHT, 0)) + MINSPACE);
m_mainLayout->setContentsMargins(contentSpace, contentSpace, contentSpace, contentSpace);
m_appDatetimeLayout->setSpacing(0);
m_mainLayout->setSpacing(contentSpace);
int appDateWidth = width() - (contentSpace * 2);
m_appPluginDatetimeWidget->setFixedSize(appDateWidth, appDatetimeSize());
m_appPluginDatetimeWidget->setFixedSize(appDateWidth, appDatetimeSize(m_position));
// 调整各个部件的位置
m_appPluginWidget->move(0, 0);
m_splitLine->setFixedWidth(width());
m_splitLine->setVisible(true);
m_splitLine->move(0, m_appPluginWidget->y() + m_appPluginWidget->height());
m_dateTimeWidget->move(0, m_appPluginWidget->y() + m_appPluginWidget->height() + m_splitLine->height());
break;
}
}
@ -375,22 +415,18 @@ void TrayManagerWindow::resetChildWidgetSize()
void TrayManagerWindow::resetSingleDirection()
{
switch (m_postion) {
switch (m_position) {
case Dock::Position::Top:
case Dock::Position::Bottom: {
m_appPluginLayout->setDirection(QBoxLayout::Direction::LeftToRight);
// 应用和时间在一行显示
m_appDatetimeLayout->setSpacing(10);
m_appDatetimeLayout->setDirection(QBoxLayout::Direction::LeftToRight);
m_mainLayout->setDirection(QBoxLayout::Direction::LeftToRight);
m_splitLine->hide();
break;
}
case Dock::Position::Left:
case Dock::Position::Right:{
m_appDatetimeLayout->setSpacing(0);
m_appPluginLayout->setDirection(QBoxLayout::Direction::TopToBottom);
m_appDatetimeLayout->setDirection(QBoxLayout::Direction::TopToBottom);
m_mainLayout->setDirection(QBoxLayout::Direction::TopToBottom);
m_splitLine->show();
break;
@ -401,19 +437,10 @@ void TrayManagerWindow::resetSingleDirection()
void TrayManagerWindow::resetMultiDirection()
{
m_appDatetimeLayout->setSpacing(0);
switch (m_postion) {
case Dock::Position::Top: {
m_appPluginLayout->setDirection(QBoxLayout::Direction::LeftToRight);
m_appDatetimeLayout->setDirection(QBoxLayout::Direction::BottomToTop);
m_mainLayout->setDirection(QBoxLayout::Direction::LeftToRight);
m_splitLine->show();
m_dateTimeWidget->setOneRow(false);
break;
}
switch (m_position) {
case Dock::Position::Top:
case Dock::Position::Bottom: {
m_appPluginLayout->setDirection(QBoxLayout::Direction::LeftToRight);
m_appDatetimeLayout->setDirection(QBoxLayout::Direction::TopToBottom);
m_mainLayout->setDirection(QBoxLayout::Direction::LeftToRight);
m_splitLine->show();
m_dateTimeWidget->setOneRow(false);
@ -422,7 +449,6 @@ void TrayManagerWindow::resetMultiDirection()
case Dock::Position::Left:
case Dock::Position::Right: {
m_appPluginLayout->setDirection(QBoxLayout::Direction::TopToBottom);
m_appDatetimeLayout->setDirection(QBoxLayout::Direction::TopToBottom);
m_mainLayout->setDirection(QBoxLayout::Direction::TopToBottom);
m_splitLine->hide();
m_dateTimeWidget->setOneRow(true);

View File

@ -22,6 +22,7 @@
#define TRAYMANAGERWINDOW_H
#include "constants.h"
#include "dbusutil.h"
#include <QWidget>
@ -43,6 +44,7 @@ class SystemPluginWindow;
class QLabel;
class QDropEvent;
class DateTimeDisplayer;
class QPainterPath;
class TrayManagerWindow : public QWidget
{
@ -52,9 +54,11 @@ public:
explicit TrayManagerWindow(QWidget *parent = nullptr);
~TrayManagerWindow() override;
void updateBorderRadius(int borderRadius);
void updateLayout();
void setPositon(Dock::Position position);
QSize suitableSize();
QSize suitableSize() const;
QSize suitableSize(const Dock::Position &position) const;
Q_SIGNALS:
void requestUpdate();
@ -76,7 +80,7 @@ private:
void resetSingleDirection();
QColor maskColor(uint8_t alpha) const;
int appDatetimeSize();
int appDatetimeSize(const Dock::Position &position) const;
QPainterPath roundedPaths();
private:
@ -86,13 +90,15 @@ private:
QuickPluginWindow *m_quickIconWidget;
DateTimeDisplayer *m_dateTimeWidget;
QBoxLayout *m_appPluginLayout;
QBoxLayout *m_appDatetimeLayout;
QBoxLayout *m_mainLayout;
TrayGridView *m_trayView;
TrayModel *m_model;
TrayDelegate *m_delegate;
Dock::Position m_postion;
Dock::Position m_position;
QLabel *m_splitLine;
DockInter *m_dockInter;
bool m_singleShow; // 用于记录当前日期时间和插件区域是显示一行还是显示多行
int m_borderRadius; // 圆角的值
};
#endif // PLUGINWINDOW_H

View File

@ -0,0 +1,810 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "mainwindow.h"
#include "windowmanager.h"
#include "traymainwindow.h"
#include "multiscreenworker.h"
#include "menuworker.h"
#include "dockitemmanager.h"
#include "dockscreen.h"
#include "displaymanager.h"
#include "proxyplugincontroller.h"
#include <DWindowManagerHelper>
#include <DDBusSender>
#include <QScreen>
#include <QX11Info>
#include <QtConcurrent>
#include <qpa/qplatformscreen.h>
#include <qpa/qplatformnativeinterface.h>
DGUI_USE_NAMESPACE
#define SNI_WATCHER_SERVICE "org.kde.StatusNotifierWatcher"
#define SNI_WATCHER_PATH "/StatusNotifierWatcher"
#define DOCKSCREEN_INS DockScreen::instance()
#define DIS_INS DisplayManager::instance()
using org::kde::StatusNotifierWatcher;
WindowManager::WindowManager(MultiScreenWorker *multiScreenWorker, QObject *parent)
: QObject(parent)
, m_multiScreenWorker(multiScreenWorker)
, m_displayMode(Dock::DisplayMode::Efficient)
, m_position(Dock::Position::Bottom)
, m_dbusDaemonInterface(QDBusConnection::sessionBus().interface())
, m_sniWatcher(new StatusNotifierWatcher(SNI_WATCHER_SERVICE, SNI_WATCHER_PATH, QDBusConnection::sessionBus(), this))
{
initSNIHost();
initConnection();
initMember();
}
WindowManager::~WindowManager()
{
}
void WindowManager::addWindow(MainWindowBase *window)
{
connect(window, &MainWindowBase::requestUpdate, this, &WindowManager::onRequestUpdate);
window->setPosition(m_multiScreenWorker->position());
window->setDisplayMode(m_multiScreenWorker->displayMode());
window->setOrder(m_topWindows.size());
m_topWindows << window;
}
void WindowManager::launch()
{
if (!qApp->property("CANSHOW").toBool())
return;
const QString &currentScreen = DOCKSCREEN_INS->current();
if (m_multiScreenWorker->hideMode() == HideMode::KeepShowing) {
onPlayAnimation(currentScreen, m_multiScreenWorker->position(), Dock::AniAction::Show);
} else if (m_multiScreenWorker->hideMode() == HideMode::KeepHidden) {
qApp->setProperty(PROP_HIDE_STATE, HideState::Hide);
onUpdateDockGeometry(HideMode::KeepHidden);
} else if (m_multiScreenWorker->hideMode() == HideMode::SmartHide) {
switch(m_multiScreenWorker->hideState()) {
case HideState::Show:
onPlayAnimation(currentScreen, m_multiScreenWorker->position(), Dock::AniAction::Show);
break;
case HideState::Hide:
onPlayAnimation(currentScreen, m_multiScreenWorker->position(), Dock::AniAction::Hide);
break;
default:
break;
}
qApp->setProperty(PROP_HIDE_STATE, m_multiScreenWorker->hideState());
}
QMetaObject::invokeMethod(this, [ this ] {
for (MainWindowBase *mainWindow : m_topWindows)
mainWindow->setDisplayMode(m_multiScreenWorker->displayMode());
}, Qt::QueuedConnection);
}
void WindowManager::sendNotifications()
{
QStringList actionButton;
actionButton << "reload" << tr("Exit Safe Mode");
QVariantMap hints;
hints["x-deepin-action-reload"] = QString("dbus-send,--session,--dest=com.deepin.dde.Dock,--print-reply,/com/deepin/dde/Dock,com.deepin.dde.Dock.ReloadPlugins");
// 在进入安全模式时执行此DBUS耗时25S左右导致任务栏显示阻塞所以使用线程调用
QtConcurrent::run(QThreadPool::globalInstance(), [ = ] {
DDBusSender()
.service("com.deepin.dde.Notification")
.path("/com/deepin/dde/Notification")
.interface("com.deepin.dde.Notification")
.method(QString("Notify"))
.arg(QString("dde-control-center")) // appname
.arg(static_cast<uint>(0)) // id
.arg(QString("preferences-system")) // icon
.arg(QString(tr("Dock - Safe Mode"))) // summary
.arg(QString(tr("The Dock is in safe mode, please exit to show it properly"))) // content
.arg(actionButton) // actions
.arg(hints) // hints
.arg(15000) // timeout
.call();
});
}
/**
* @brief MainWindow::callShow
* DBus调用的
* @note -r参数启动时DBus调用此接口之后才会显示界面
*
* startdde延后调用
*/
void WindowManager::callShow()
{
static bool flag = false;
if (flag) {
return;
}
flag = true;
qApp->setProperty("CANSHOW", true);
launch();
// 预留200ms提供给窗口初始化再通知startdde不影响启动速度
QTimer::singleShot(200, this, &WindowManager::RegisterDdeSession);
}
/** 调整任务栏的大小这个接口提供给dbus使用一般是控制中心来调用
* @brief WindowManager::resizeDock
* @param offset
* @param dragging
*/
void WindowManager::resizeDock(int offset, bool dragging)
{
QScreen *screen = DIS_INS->screen(DOCKSCREEN_INS->current());
if (!screen)
return;
m_multiScreenWorker->setStates(MultiScreenWorker::DockIsDraging, dragging);
int dockSize = qBound(DOCK_MIN_SIZE, offset, DOCK_MAX_SIZE);
for (MainWindowBase *mainWindow : m_topWindows) {
QRect windowRect = mainWindow->getDockGeometry(screen, m_multiScreenWorker->position(), m_multiScreenWorker->displayMode(), Dock::HideState::Hide);
QRect newWindowRect;
switch (m_multiScreenWorker->position()) {
case Top: {
newWindowRect.setX(windowRect.x());
newWindowRect.setY(windowRect.y());
newWindowRect.setWidth(windowRect.width());
newWindowRect.setHeight(dockSize);
break;
}
case Bottom: {
newWindowRect.setX(windowRect.x());
newWindowRect.setY(windowRect.y() + windowRect.height() - dockSize);
newWindowRect.setWidth(windowRect.width());
newWindowRect.setHeight(dockSize);
break;
}
case Left: {
newWindowRect.setX(windowRect.x());
newWindowRect.setY(windowRect.y());
newWindowRect.setWidth(dockSize);
newWindowRect.setHeight(windowRect.height());
break;
}
case Right: {
newWindowRect.setX(windowRect.x() + windowRect.width() - dockSize);
newWindowRect.setY(windowRect.y());
newWindowRect.setWidth(dockSize);
newWindowRect.setHeight(windowRect.height());
break;
}
}
// 更新界面大小
mainWindow->blockSignals(true);
mainWindow->setFixedSize(newWindowRect.size());
mainWindow->resetPanelGeometry();
mainWindow->move(newWindowRect.topLeft());
mainWindow->blockSignals(false);
}
m_multiScreenWorker->updateDaemonDockSize(dockSize);
}
/** 获取任务栏的实际大小这个接口用于获取任务栏的尺寸返回给dbus接口
* @brief WindowManager::geometry
* @return
*/
QRect WindowManager::geometry() const
{
int x = 0;
int y = 0;
int width = 0;
int height = 0;
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) {
for (int i = 0; i < m_topWindows.size(); i++) {
MainWindowBase *mainWindow = m_topWindows[i];
if (!mainWindow->isVisible())
continue;
QRect windowRect = mainWindow->rect();
if (i == 0 || x > windowRect.x())
x = windowRect.x();
if (i == 0) {
y = windowRect.y();
height = windowRect.height();
}
width += windowRect.width() + mainWindow->dockSpace();
}
return QRect(x, y, width, height);
}
for (int i = 0; i < m_topWindows.size(); i++) {
MainWindowBase *mainWindow = m_topWindows[i];
if (!mainWindow->isVisible())
continue;
QRect windowRect = mainWindow->rect();
if (i == 0 || y > windowRect.y())
y = windowRect.y();
if (i == 0) {
x = windowRect.x();
width = windowRect.width();
}
height += windowRect.height() + mainWindow->dockSpace();
}
return QRect(x, y, width, height);
}
void WindowManager::onUpdateDockGeometry(const Dock::HideMode &hideMode)
{
Dock::HideState hideState;
if (hideMode == HideMode::KeepShowing || (hideMode == HideMode::SmartHide && m_multiScreenWorker->hideState() == HideState::Show))
hideState = Dock::HideState::Show;
else
hideState = Dock::HideState::Hide;
updateMainGeometry(hideState);
}
void WindowManager::onPositionChanged(const Dock::Position &position)
{
Position lastPos = m_position;
if (lastPos == position)
return;
m_position = position;
// 调用设置位置,一会根据需要放到实际的位置
for (MainWindowBase *mainWindow : m_topWindows)
mainWindow->setPosition(position);
// 在改变位置后,需要根据当前任务栏是隐藏还是显示,来调整左右两侧区域的大小
onUpdateDockGeometry(HideMode::KeepHidden);
}
void WindowManager::onDisplayModeChanged(const Dock::DisplayMode &displayMode)
{
m_displayMode = displayMode;
DockItem::setDockDisplayMode(m_displayMode);
qApp->setProperty(PROP_DISPLAY_MODE, QVariant::fromValue(displayMode));
for (MainWindowBase *mainWindow : m_topWindows)
mainWindow->setDisplayMode(m_displayMode);
onUpdateDockGeometry(m_multiScreenWorker->hideMode());
}
void WindowManager::onDbusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
{
Q_UNUSED(oldOwner);
if (name == SNI_WATCHER_SERVICE && !newOwner.isEmpty()) {
qDebug() << SNI_WATCHER_SERVICE << "SNI watcher daemon started, register dock to watcher as SNI Host";
m_sniWatcher->RegisterStatusNotifierHost(m_sniHostService);
}
}
void WindowManager::showAniFinish()
{
qApp->setProperty(PROP_HIDE_STATE, HideState::Show);
// 通知后端更新区域
onRequestUpdateFrontendGeometry();
onRequestNotifyWindowManager();
}
void WindowManager::hideAniFinish()
{
DockItem::setDockPosition(m_position);
qApp->setProperty(PROP_POSITION, QVariant::fromValue(m_position));
qApp->setProperty(PROP_HIDE_STATE, HideState::Hide);
// 通知后端更新区域
onRequestUpdateFrontendGeometry();
onRequestNotifyWindowManager();
}
/**获取整个任务栏区域的位置和尺寸的信息,用于提供给后端设置位置等信息
* @brief WindowManager::getDockGeometry
* @param withoutScale
* @return
*/
QRect WindowManager::getDockGeometry(bool withoutScale) const
{
QScreen *screen = DIS_INS->screen(DOCKSCREEN_INS->current());
if (!screen)
return QRect();
int x = 0;
int y = 0;
int width = 0;
int height = 0;
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom) {
for (int i = 0; i < m_topWindows.size(); i++) {
MainWindowBase *mainWindow = m_topWindows[i];
if (!mainWindow->isVisible())
continue;
QRect windowRect = mainWindow->getDockGeometry(screen, m_position, m_displayMode, Dock::HideState::Show, withoutScale);
if (i == 0 || x > windowRect.x())
x = windowRect.x();
if (i == 0) {
y = windowRect.y();
height = windowRect.height();
}
width += windowRect.width() + mainWindow->dockSpace();
}
} else {
for (int i = 0; i < m_topWindows.size(); i++) {
MainWindowBase *mainWindow = m_topWindows[i];
if (!mainWindow->isVisible())
continue;
QRect windowRect = mainWindow->getDockGeometry(screen, m_position, m_displayMode, Dock::HideState::Show, withoutScale);
if (i == 0 || y > windowRect.y())
y = windowRect.y();
if (i == 0) {
y = windowRect.y();
width = windowRect.width();
}
height += windowRect.height() + mainWindow->dockSpace();
}
}
return QRect(x, y, width, height);
}
void WindowManager::RegisterDdeSession()
{
QString envName("DDE_SESSION_PROCESS_COOKIE_ID");
QByteArray cookie = qgetenv(envName.toUtf8().data());
qunsetenv(envName.toUtf8().data());
if (!cookie.isEmpty()) {
QDBusPendingReply<bool> r = DDBusSender()
.interface("com.deepin.SessionManager")
.path("/com/deepin/SessionManager")
.service("com.deepin.SessionManager")
.method("Register")
.arg(QString(cookie))
.call();
qDebug() << Q_FUNC_INFO << r.value();
}
}
void WindowManager::initConnection()
{
connect(m_dbusDaemonInterface, &QDBusConnectionInterface::serviceOwnerChanged, this, &WindowManager::onDbusNameOwnerChanged);
connect(m_multiScreenWorker, &MultiScreenWorker::requestUpdateDockGeometry, this, &WindowManager::onUpdateDockGeometry);
connect(m_multiScreenWorker, &MultiScreenWorker::positionChanged, this, &WindowManager::onPositionChanged);
connect(m_multiScreenWorker, &MultiScreenWorker::displayModeChanged, this, &WindowManager::onDisplayModeChanged);
connect(m_multiScreenWorker, &MultiScreenWorker::requestPlayAnimation, this, &WindowManager::onPlayAnimation);
connect(m_multiScreenWorker, &MultiScreenWorker::requestChangeDockPosition, this, &WindowManager::onChangeDockPosition);
connect(m_multiScreenWorker, &MultiScreenWorker::requestUpdateFrontendGeometry, this, &WindowManager::onRequestUpdateFrontendGeometry);
connect(m_multiScreenWorker, &MultiScreenWorker::requestNotifyWindowManager, this, &WindowManager::onRequestNotifyWindowManager);
connect(m_multiScreenWorker, &MultiScreenWorker::requestUpdateFrontendGeometry, DockItemManager::instance(), &DockItemManager::requestUpdateDockItem);
connect(DockItemManager::instance(), &DockItemManager::requestWindowAutoHide, m_multiScreenWorker, &MultiScreenWorker::onAutoHideChanged);
}
void WindowManager::initSNIHost()
{
QDBusConnection dbusConn = QDBusConnection::sessionBus();
m_sniHostService = QString("org.kde.StatusNotifierHost-") + QString::number(qApp->applicationPid());
dbusConn.registerService(m_sniHostService);
dbusConn.registerObject("/StatusNotifierHost", this);
if (m_sniWatcher->isValid()) {
m_sniWatcher->RegisterStatusNotifierHost(m_sniHostService);
} else {
qDebug() << SNI_WATCHER_SERVICE << "SNI watcher daemon is not exist for now!";
}
}
void WindowManager::initMember()
{
m_displayMode = m_multiScreenWorker->displayMode();
m_position = m_multiScreenWorker->position();
}
// 更新任务栏的位置和尺寸的信息
void WindowManager::updateMainGeometry(const Dock::HideState &hideState)
{
QScreen *screen = DIS_INS->screen(DOCKSCREEN_INS->current());
if (!screen)
return;
for (MainWindowBase *mainWindow : m_topWindows) {
QRect windowRect = mainWindow->getDockGeometry(screen, m_multiScreenWorker->position(), m_multiScreenWorker->displayMode(), hideState);
mainWindow->updateParentGeometry(m_position, windowRect);
}
// 在切换模式的时候需要根据实际当前是隐藏还是显示来记录当前任务栏是隐藏还是显示MainPanelWindow会根据这个状态来决定怎么获取图标的尺寸
// 如果不加上这一行,那么鼠标在唤醒任务栏的时候,左侧区域会有显示问题
qApp->setProperty(PROP_HIDE_STATE, hideState);
}
void WindowManager::onPlayAnimation(const QString &screenName, const Dock::Position &pos, Dock::AniAction act, bool containMouse, bool updatePos)
{
// 如果containMouse= true,则需要计算鼠标是否包含在任务栏的位置, 如果鼠标在任务栏内部,则无需执行动画,这种情况一般用于执行隐藏模式发生变化的时候
if (containMouse) {
QRect dockGeometry = getDockGeometry(false);
if (dockGeometry.contains(QCursor::pos()))
return;
}
if (act == Dock::AniAction::Show) {
for (MainWindowBase *mainWindow : m_topWindows) {
if (mainWindow->windowType() != MainWindowBase::DockWindowType::MainWindow)
continue;
// 如果请求显示的动画,且当前任务栏已经显示,则不继续执行动画
if (mainWindow->width() > 0 && mainWindow->height() > 0)
return;
}
}
QScreen *screen = DIS_INS->screen(screenName);
if (!m_multiScreenWorker->testState(MultiScreenWorker::RunState::AutoHide) || qApp->property("DRAG_STATE").toBool()
|| m_multiScreenWorker->testState(MultiScreenWorker::RunState::ChangePositionAnimationStart)
|| m_multiScreenWorker->testState(MultiScreenWorker::RunState::HideAnimationStart)
|| m_multiScreenWorker->testState(MultiScreenWorker::RunState::ShowAnimationStart)
|| !screen)
return;
QParallelAnimationGroup *group = createAnimationGroup(act, screenName, pos);
if (!group)
return;
switch (act) {
case Dock::AniAction::Show:
m_multiScreenWorker->setStates(MultiScreenWorker::ShowAnimationStart);
break;
case Dock::AniAction::Hide:
m_multiScreenWorker->setStates(MultiScreenWorker::HideAnimationStart);
}
connect(group, &QParallelAnimationGroup::finished, this, [ = ] {
switch (act) {
case Dock::AniAction::Show:
showAniFinish();
if (updatePos)
onPositionChanged(m_multiScreenWorker->position());
m_multiScreenWorker->setStates(MultiScreenWorker::ShowAnimationStart, false);
break;
case Dock::AniAction::Hide:
hideAniFinish();
if (updatePos)
onPositionChanged(m_multiScreenWorker->position());
m_multiScreenWorker->setStates(MultiScreenWorker::HideAnimationStart, false);
break;
}
});
group->stop();
group->start(QVariantAnimation::DeleteWhenStopped);
}
/**创建动画,在时尚模式先同时创建左区域和右区域的动画
* @brief WindowManager::createAnimationGroup
* @param aniAction
* @param screenName
* @param position
* @return
*/
QParallelAnimationGroup *WindowManager::createAnimationGroup(const Dock::AniAction &aniAction, const QString &screenName, const Dock::Position &position) const
{
QScreen *screen = DIS_INS->screen(screenName);
if (!screen)
return nullptr;
bool stopAnimation = false;
QList<QVariantAnimation *> animations;
for (MainWindowBase *mainWindow : m_topWindows) {
if (!mainWindow->isVisible())
continue;
QVariantAnimation *ani = mainWindow->createAnimation(screen, position, aniAction);
if (!ani) {
stopAnimation = true;
continue;
}
animations << ani;
}
if (stopAnimation) {
qDeleteAll(animations.begin(), animations.end());
return nullptr;
}
QParallelAnimationGroup *aniGroup = new QParallelAnimationGroup;
for (QVariantAnimation *ani : animations) {
ani->setParent(aniGroup);
aniGroup->addAnimation(ani);
}
return aniGroup;
}
void WindowManager::onChangeDockPosition(QString fromScreen, QString toScreen, const Dock::Position &fromPos, const Dock::Position &toPos)
{
QList<QParallelAnimationGroup *> animations;
// 获取隐藏的动作
QParallelAnimationGroup *hideGroup = createAnimationGroup(Dock::AniAction::Hide, fromScreen, fromPos);
if (hideGroup) {
connect(hideGroup, &QParallelAnimationGroup::finished, this, [ = ] {
// 在隐藏动画结束的时候,开始设置位置信息
onPositionChanged(m_multiScreenWorker->position());
DockItem::setDockPosition(m_multiScreenWorker->position());
qApp->setProperty(PROP_POSITION, QVariant::fromValue(m_multiScreenWorker->position()));
});
animations << hideGroup;
}
// 获取显示的动作
QParallelAnimationGroup *showGroup = createAnimationGroup(Dock::AniAction::Show, toScreen, toPos);
if (showGroup)
animations << showGroup;
if (animations.size() == 0)
return;
m_multiScreenWorker->setStates(MultiScreenWorker::ChangePositionAnimationStart);
QSequentialAnimationGroup *group = new QSequentialAnimationGroup;
connect(group, &QVariantAnimation::finished, this, [ = ] {
// 结束之后需要根据确定需要再隐藏
showAniFinish();
m_multiScreenWorker->setStates(MultiScreenWorker::ChangePositionAnimationStart, false);
});
for (QParallelAnimationGroup *ani : animations) {
ani->setParent(group);
group->addAnimation(ani);
}
group->start(QVariantAnimation::DeleteWhenStopped);
}
void WindowManager::onRequestUpdateFrontendGeometry()
{
QRect rect = getDockGeometry(false);
// 向com.deepin.dde.daemon.Dock的SetFrontendWindowRect接口设置区域时,此区域的高度或宽度不能为0,否则会导致其HideState属性循环切换,造成任务栏循环显示或隐藏
if (rect.width() == 0 || rect.height() == 0)
return;
DockInter dockInter(dockServiceName(), dockServicePath(), QDBusConnection::sessionBus());
dockInter.SetFrontendWindowRect(int(rect.x()), int(rect.y()), uint(rect.width()), uint(rect.height()));
}
void WindowManager::onRequestNotifyWindowManager()
{
static QRect lastRect = QRect();
static int lastScreenWidth = 0;
static int lastScreenHeight = 0;
// 从列表中查找主窗口
MainWindowBase *mainWindow = nullptr;
for (MainWindowBase *window : m_topWindows) {
if (window->windowType() != MainWindowBase::DockWindowType::MainWindow)
continue;
mainWindow = window;
break;
}
if (!mainWindow)
return;
/* 在非主屏或非一直显示状态时,清除任务栏区域,不挤占应用 */
if ((!DIS_INS->isCopyMode() && DOCKSCREEN_INS->current() != DOCKSCREEN_INS->primary()) || m_multiScreenWorker->hideMode() != HideMode::KeepShowing) {
lastRect = QRect();
if (Utils::IS_WAYLAND_DISPLAY) {
QList<QVariant> varList;
varList.append(0);//dock位置
varList.append(0);//dock高度/宽度
varList.append(0);//start值
varList.append(0);//end值
// 此处只需获取左侧主窗口部分即可
QPlatformWindow *windowHandle = mainWindow->windowHandle()->handle();
if (windowHandle)
QGuiApplication::platformNativeInterface()->setWindowProperty(windowHandle, "_d_dwayland_dockstrut", varList);
} else {
const auto display = QX11Info::display();
if (!display) {
qWarning() << "QX11Info::display() is " << display;
return;
}
XcbMisc::instance()->clear_strut_partial(xcb_window_t(mainWindow->winId()));
}
return;
}
QRect dockGeometry = getDockGeometry(true);
if (lastRect == dockGeometry
&& lastScreenWidth == DIS_INS->screenRawWidth()
&& lastScreenHeight == DIS_INS->screenRawHeight()) {
return;
}
lastRect = dockGeometry;
lastScreenWidth = DIS_INS->screenRawWidth();
lastScreenHeight = DIS_INS->screenRawHeight();
qDebug() << "dock real geometry:" << dockGeometry;
qDebug() << "screen width:" << DIS_INS->screenRawWidth() << ", height:" << DIS_INS->screenRawHeight();
const qreal &ratio = qApp->devicePixelRatio();
if (Utils::IS_WAYLAND_DISPLAY) {
QList<QVariant> varList = {0, 0, 0, 0};
switch (m_position) {
case Position::Top:
varList[0] = 1;
varList[1] = dockGeometry.y() + dockGeometry.height() + WINDOWMARGIN * ratio;
varList[2] = dockGeometry.x();
varList[3] = dockGeometry.x() + dockGeometry.width();
break;
case Position::Bottom:
varList[0] = 3;
varList[1] = DIS_INS->screenRawHeight() - dockGeometry.y() + WINDOWMARGIN * ratio;
varList[2] = dockGeometry.x();
varList[3] = dockGeometry.x() + dockGeometry.width();
break;
case Position::Left:
varList[0] = 0;
varList[1] = dockGeometry.x() + dockGeometry.width() + WINDOWMARGIN * ratio;
varList[2] = dockGeometry.y();
varList[3] = dockGeometry.y() + dockGeometry.height();
break;
case Position::Right:
varList[0] = 2;
varList[1] = DIS_INS->screenRawWidth() - dockGeometry.x() + WINDOWMARGIN * ratio;
varList[2] = dockGeometry.y();
varList[3] = dockGeometry.y() + dockGeometry.height();
break;
}
QPlatformWindow *windowHandle = mainWindow->windowHandle()->handle();
if (windowHandle) {
QGuiApplication::platformNativeInterface()->setWindowProperty(windowHandle,"_d_dwayland_dockstrut", varList);
}
} else {
XcbMisc::Orientation orientation = XcbMisc::OrientationTop;
double strut = 0;
double strutStart = 0;
double strutEnd = 0;
switch (m_position) {
case Position::Top:
orientation = XcbMisc::OrientationTop;
strut = dockGeometry.y() + dockGeometry.height();
strutStart = dockGeometry.x();
strutEnd = qMin(dockGeometry.x() + dockGeometry.width(), dockGeometry.right());
break;
case Position::Bottom:
orientation = XcbMisc::OrientationBottom;
strut = DIS_INS->screenRawHeight() - dockGeometry.y();
strutStart = dockGeometry.x();
strutEnd = qMin(dockGeometry.x() + dockGeometry.width(), dockGeometry.right());
break;
case Position::Left:
orientation = XcbMisc::OrientationLeft;
strut = dockGeometry.x() + dockGeometry.width();
strutStart = dockGeometry.y();
strutEnd = qMin(dockGeometry.y() + dockGeometry.height(), dockGeometry.bottom());
break;
case Position::Right:
orientation = XcbMisc::OrientationRight;
strut = DIS_INS->screenRawWidth() - dockGeometry.x();
strutStart = dockGeometry.y();
strutEnd = qMin(dockGeometry.y() + dockGeometry.height(), dockGeometry.bottom());
break;
}
qDebug() << "set reserved area to xcb:" << strut << strutStart << strutEnd;
const auto display = QX11Info::display();
if (!display) {
qWarning() << "QX11Info::display() is " << display;
return;
}
XcbMisc::instance()->set_strut_partial(static_cast<xcb_window_t>(mainWindow->winId()), orientation,
static_cast<uint>(strut + WINDOWMARGIN * ratio), // 设置窗口与屏幕边缘距离,需要乘缩放
static_cast<uint>(strutStart), // 设置任务栏起点坐标上下为x左右为y
static_cast<uint>(strutEnd)); // 设置任务栏终点坐标上下为x左右为y
}
}
void WindowManager::onRequestUpdate()
{
// 如果当前正在执行动画,则无需设置
if (m_multiScreenWorker->testState(MultiScreenWorker::ChangePositionAnimationStart)
|| m_multiScreenWorker->testState(MultiScreenWorker::ShowAnimationStart)
|| m_multiScreenWorker->testState(MultiScreenWorker::HideAnimationStart))
return;
QScreen *screen = DIS_INS->screen(DOCKSCREEN_INS->current());
// 查找发送信号的窗口
MainWindowBase *dragWindow = qobject_cast<MainWindowBase *>(sender());
if (!dragWindow || !screen)
return;
QRect dragGeometry = dragWindow->geometry();
for (MainWindowBase *mainWindow : m_topWindows) {
if (!mainWindow->isVisible())
continue;
QRect windowShowSize = mainWindow->getDockGeometry(screen, m_multiScreenWorker->position(),
m_multiScreenWorker->displayMode(), Dock::HideState::Show);
switch(m_position) {
case Dock::Position::Top: {
windowShowSize.setHeight(dragGeometry.height());
break;
}
case Dock::Position::Bottom: {
int bottomY = windowShowSize.y() + windowShowSize.height();
windowShowSize.setY(bottomY - dragGeometry.height());
windowShowSize.setHeight(dragGeometry.height());
break;
}
case Dock::Position::Left: {
windowShowSize.setWidth(dragGeometry.width());
break;
}
case Dock::Position::Right: {
int righyX = windowShowSize.x() + windowShowSize.width();
windowShowSize.setX(righyX - dragGeometry.width());
windowShowSize.setWidth(dragGeometry.width());
break;
}
}
mainWindow->blockSignals(true);
mainWindow->raise();
mainWindow->setFixedSize(windowShowSize.size());
mainWindow->move(windowShowSize.topLeft());
mainWindow->resetPanelGeometry();
mainWindow->blockSignals(false);
}
// 抛出geometry变化的信号通知控制中心调整尺寸
Q_EMIT panelGeometryChanged();
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd.
*
* Author: donghualin <donghualin@uniontech.com>
*
* Maintainer: donghualin <donghualin@uniontech.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef WINDOWMANAGER_H
#define WINDOWMANAGER_H
#include "constants.h"
#include "statusnotifierwatcher_interface.h"
#include <QObject>
namespace Dtk {namespace Gui { class DWindowManagerHelper; }}
class MainWindowBase;
class MainWindow;
class TrayMainWindow;
class MultiScreenWorker;
class MenuWorker;
class QDBusConnectionInterface;
using namespace Dtk::Gui;
class WindowManager : public QObject
{
Q_OBJECT
public:
explicit WindowManager(MultiScreenWorker *multiScreenWorker, QObject *parent = nullptr);
~WindowManager() override;
void addWindow(MainWindowBase *window);
void launch();
void sendNotifications();
void callShow();
void resizeDock(int offset, bool dragging);
QRect geometry() const;
Q_SIGNALS:
void panelGeometryChanged();
private:
void initConnection();
void initSNIHost();
void initMember();
void updateMainGeometry(const Dock::HideState &hideState);
QParallelAnimationGroup *createAnimationGroup(const Dock::AniAction &aniAction, const QString &screenName, const Dock::Position &position) const;
void showAniFinish();
void hideAniFinish();
QRect getDockGeometry(bool withoutScale = false) const; // 计算左右侧加起来的区域大小
void RegisterDdeSession();
private Q_SLOTS:
void onRequestUpdate(); // 调整尺寸的时候
void onUpdateDockGeometry(const Dock::HideMode &hideMode);
void onPositionChanged(const Dock::Position &position);
void onDisplayModeChanged(const Dock::DisplayMode &displayMode);
void onDbusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
void onPlayAnimation(const QString &screenName, const Dock::Position &pos, Dock::AniAction act, bool containMouse = false, bool updatePos = false);
void onChangeDockPosition(QString fromScreen, QString toScreen, const Dock::Position &fromPos, const Dock::Position &toPos);
void onRequestUpdateFrontendGeometry();
void onRequestNotifyWindowManager();
private:
MultiScreenWorker *m_multiScreenWorker;
QString m_sniHostService;
Dock::DisplayMode m_displayMode;
Dock::Position m_position;
QDBusConnectionInterface *m_dbusDaemonInterface;
org::kde::StatusNotifierWatcher *m_sniWatcher; // DBUS状态通知
QList<MainWindowBase *> m_topWindows;
};
#endif // WINDOWMANAGER_H

View File

@ -43,6 +43,8 @@ namespace Dock {
// 插件最小尺寸,图标采用深色
#define PLUGIN_MIN_ICON_NAME "-dark"
// dock最小尺寸
#define DOCK_MIN_SIZE 40
// dock最大尺寸
#define DOCK_MAX_SIZE 100
///
@ -96,6 +98,11 @@ enum HideState {
Hide = 2,
};
enum class AniAction {
Show = 0,
Hide
};
#define IS_TOUCH_STATE "isTouchState"
}