diff --git a/panels/dock/dconfig/org.deepin.ds.dock.json b/panels/dock/dconfig/org.deepin.ds.dock.json index 8da9bc01d..730cf6d6f 100755 --- a/panels/dock/dconfig/org.deepin.ds.dock.json +++ b/panels/dock/dconfig/org.deepin.ds.dock.json @@ -72,6 +72,16 @@ "permissions": "readwrite", "visibility": "private" }, + "Show_On_All_Screens": { + "value": false, + "serial": 0, + "flags": [], + "name": "show_on_all_screens", + "name[zh_CN]": "任务栏显示在所有屏幕", + "description": "show a mirrored dock on every connected screen", + "permissions": "readwrite", + "visibility": "private" + }, "Locked": { "value": false, "serial": 0, diff --git a/panels/dock/dockhelper.cpp b/panels/dock/dockhelper.cpp index e3767bcb1..972f5d323 100644 --- a/panels/dock/dockhelper.cpp +++ b/panels/dock/dockhelper.cpp @@ -26,6 +26,7 @@ DockHelper::DockHelper(DockPanel *parent) QMetaObject::invokeMethod(this, &DockHelper::checkNeedShowOrNot, Qt::QueuedConnection); connect(parent, &DockPanel::rootObjectChanged, this, &DockHelper::initAreas); + connect(parent, &DockPanel::dockScreenChanged, this, &DockHelper::initAreas); connect(parent, &DockPanel::showInPrimaryChanged, this, &DockHelper::updateAllDockWakeArea); connect(parent, &DockPanel::hideStateChanged, this, &DockHelper::updateAllDockWakeArea); connect(parent, &DockPanel::hideModeChanged, m_hideTimer, static_cast(&QTimer::start)); @@ -141,6 +142,8 @@ bool DockHelper::eventFilter(QObject *watched, QEvent *event) bool DockHelper::wakeUpAreaNeedShowOnThisScreen(QScreen *screen) { auto isDockAllowedShownOnThisScreen = [this, screen]() -> bool { + if (parent()->mirroredInstance()) + return screen == parent()->dockScreen(); return (parent()->showInPrimary() && screen == qApp->primaryScreen()) || !parent()->showInPrimary(); }; @@ -301,11 +304,18 @@ void DockHelper::initAreas() return; // init areas - for (auto screen : qApp->screens()) { - m_areas.insert(screen, createArea(screen)); + if (parent()->mirroredInstance()) { + if (auto *screen = parent()->dockScreen()) + m_areas.insert(screen, createArea(screen)); + } else { + for (auto screen : qApp->screens()) { + m_areas.insert(screen, createArea(screen)); + } } connect(qApp, &QGuiApplication::screenAdded, this, [this](QScreen *screen) { + if (parent()->mirroredInstance() && screen != parent()->dockScreen()) + return; if (m_areas.contains(screen)) return; m_areas.insert(screen, createArea(screen)); diff --git a/panels/dock/dockpanel.cpp b/panels/dock/dockpanel.cpp index 7e3d54dbf..e120615ab 100644 --- a/panels/dock/dockpanel.cpp +++ b/panels/dock/dockpanel.cpp @@ -19,6 +19,7 @@ #include "dockdaemonadaptor.h" #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include @@ -196,6 +198,47 @@ bool DockPanel::init() Q_EMIT dockDaemonAdaptor->LockedChanged(locked()); }); + auto appearanceConfig = DConfig::create(QStringLiteral("org.deepin.dde.appearance"), + QStringLiteral("org.deepin.dde.appearance"), + QString(), this); + if (appearanceConfig && appearanceConfig->isValid()) { + auto dtkThemeConfig = DConfig::create(QStringLiteral("org.deepin.dtk.preference"), + QStringLiteral("org.deepin.dtk.preference"), + QString(), this); + auto controlCenterThemeConfig = DConfig::create(QStringLiteral("org.deepin.dde.control-center"), + QStringLiteral("org.deepin.dtk.preference"), + QString(), this); + auto fileManagerThemeConfig = DConfig::create(QStringLiteral("dde-file-manager"), + QStringLiteral("org.deepin.dtk.preference"), + QString(), this); + auto shellThemeConfig = DConfig::create(QStringLiteral("org.deepin.dde.shell"), + QStringLiteral("org.deepin.dtk.preference"), + QString(), this); + const auto applyGlobalTheme = [this, appearanceConfig, dtkThemeConfig, + controlCenterThemeConfig, fileManagerThemeConfig, + shellThemeConfig]() { + const auto globalTheme = appearanceConfig->value(QStringLiteral("Global_Theme"), QString()).toString(); + const auto theme = globalTheme.contains(QStringLiteral("dark"), Qt::CaseInsensitive) ? Dark : Light; + const auto themeType = theme == Dark ? 2 : 1; + const auto applyThemeType = [themeType](DConfig *config) { + if (config && config->isValid()) + config->setValue(QStringLiteral("themeType"), themeType); + }; + applyThemeType(dtkThemeConfig); + applyThemeType(controlCenterThemeConfig); + applyThemeType(fileManagerThemeConfig); + applyThemeType(shellThemeConfig); + Dtk::Gui::DGuiApplicationHelper::instance()->setPaletteType(static_cast(theme)); + setColorTheme(theme); + }; + applyGlobalTheme(); + connect(appearanceConfig, &DConfig::valueChanged, this, + [applyGlobalTheme](const QString &key) { + if (key == QStringLiteral("Global_Theme")) + applyGlobalTheme(); + }); + } + DPanel::init(); QObject::connect(this, &DApplet::rootObjectChanged, this, [this]() { @@ -206,14 +249,24 @@ bool DockPanel::init() // connect(window(), &QQuickWindow::yChanged, this, &DockPanel::onWindowGeometryChanged); connect(window(), &QQuickWindow::widthChanged, this, &DockPanel::onWindowGeometryChanged); connect(window(), &QQuickWindow::heightChanged, this, &DockPanel::onWindowGeometryChanged); - QMetaObject::invokeMethod(this, &DockPanel::onWindowGeometryChanged); - if (showInPrimary()) + if (mirroredInstance()) { + const auto targetName = appletData().value(QStringLiteral("DockScreen")).toString(); + for (auto *screen : qApp->screens()) { + if (screen->name() == targetName) { + setDockScreen(screen); + break; + } + } + if (!m_dockScreen) + m_dockScreen = window()->screen(); + } else if (showInPrimary()) updateDockScreen(); else { m_dockScreen = window()->screen(); } + QMetaObject::invokeMethod(this, &DockPanel::onWindowGeometryChanged); // 监听屏幕几何信息变化,当主屏位置变化时重新计算 frontendWindowRect - if (auto screen = window()->screen()) { + if (auto screen = m_dockScreen) { connect(screen, &QScreen::geometryChanged, this, &DockPanel::onWindowGeometryChanged); } rootObject()->installEventFilter(this); @@ -221,7 +274,7 @@ bool DockPanel::init() } }); - m_theme = static_cast(Dtk::Gui::DGuiApplicationHelper::instance()->themeType()); + setColorTheme(static_cast(Dtk::Gui::DGuiApplicationHelper::instance()->themeType())); auto platformName = QGuiApplication::platformName(); if (QStringLiteral("wayland") == platformName) { m_helper = new WaylandDockHelper(this); @@ -480,6 +533,8 @@ void DockPanel::updateDockScreen() auto *win = window(); if (!win) return; + if (mirroredInstance()) + return; auto *primary = qApp->primaryScreen(); setDockScreen(primary); @@ -498,6 +553,21 @@ bool DockPanel::showInPrimary() const return SETTINGS->showInPrimary(); } +bool DockPanel::showOnAllScreens() const +{ + return SETTINGS->showOnAllScreens(); +} + +void DockPanel::setShowOnAllScreens(bool newShowOnAllScreens) +{ + SETTINGS->setShowOnAllScreens(newShowOnAllScreens); +} + +bool DockPanel::mirroredInstance() const +{ + return appletData().value(QStringLiteral("DockMirror")).toBool(); +} + void DockPanel::setShowInPrimary(bool newShowInPrimary) { if (SETTINGS->showInPrimary() == newShowInPrimary) @@ -550,6 +620,37 @@ void DockPanel::setDockScreen(QScreen *screen) return; m_dockScreen = screen; window()->setScreen(m_dockScreen); + if (mirroredInstance()) { + QMetaObject::invokeMethod(this, [this, screen] { + if (!screen || !window() || m_dockScreen != screen || !qApp->screens().contains(screen)) + return; + + window()->setScreen(screen); + const auto screenGeometry = screen->geometry(); + const auto windowWidth = window()->width(); + const auto windowHeight = window()->height(); + int x = screenGeometry.x() + (screenGeometry.width() - windowWidth) / 2; + int y = screenGeometry.y() + (screenGeometry.height() - windowHeight) / 2; + + switch (position()) { + case Top: + y = screenGeometry.y(); + break; + case Right: + x = screenGeometry.right() + 1 - windowWidth; + break; + case Bottom: + y = screenGeometry.bottom() + 1 - windowHeight; + break; + case Left: + x = screenGeometry.x(); + break; + } + + window()->setPosition(x, y); + onWindowGeometryChanged(); + }, Qt::QueuedConnection); + } Q_EMIT dockScreenChanged(m_dockScreen); Q_EMIT screenNameChanged(); } diff --git a/panels/dock/dockpanel.h b/panels/dock/dockpanel.h index c69789b3a..105d8ba1e 100644 --- a/panels/dock/dockpanel.h +++ b/panels/dock/dockpanel.h @@ -35,6 +35,8 @@ class DockPanel : public DS_NAMESPACE::DPanel, public QDBusContext Q_PROPERTY(bool fashionMode READ fashionMode NOTIFY fashionModeChanged FINAL) Q_PROPERTY(IndicatorStyle indicatorStyle READ indicatorStyle WRITE setIndicatorStyle NOTIFY indicatorStyleChanged FINAL) Q_PROPERTY(bool showInPrimary READ showInPrimary WRITE setShowInPrimary NOTIFY showInPrimaryChanged FINAL) + Q_PROPERTY(bool showOnAllScreens READ showOnAllScreens WRITE setShowOnAllScreens NOTIFY showOnAllScreensChanged FINAL) + Q_PROPERTY(bool mirroredInstance READ mirroredInstance CONSTANT FINAL) Q_PROPERTY(QString screenName READ screenName NOTIFY screenNameChanged FINAL) Q_PROPERTY(bool locked READ locked WRITE setLocked NOTIFY lockedChanged FINAL) Q_PROPERTY(bool isResizing READ isResizing WRITE setIsResizing NOTIFY isResizingChanged FINAL) @@ -108,6 +110,9 @@ class DockPanel : public DS_NAMESPACE::DPanel, public QDBusContext bool showInPrimary() const; void setShowInPrimary(bool newShowInPrimary); + bool showOnAllScreens() const; + void setShowOnAllScreens(bool newShowOnAllScreens); + bool mirroredInstance() const; bool locked() const; void setLocked(bool newLocked); @@ -157,6 +162,7 @@ private Q_SLOTS: void cardCurrentChanged(const QString &cardCurrent); void indicatorStyleChanged(IndicatorStyle style); void showInPrimaryChanged(bool showInPrimary); + void showOnAllScreensChanged(bool showOnAllScreens); void dockScreenChanged(QScreen *screen); void screenNameChanged(); void requestClosePopup(); diff --git a/panels/dock/docksettings.cpp b/panels/dock/docksettings.cpp index adfbe5678..ca7d435d7 100644 --- a/panels/dock/docksettings.cpp +++ b/panels/dock/docksettings.cpp @@ -27,6 +27,7 @@ const static QString keyIndicatorStyle = "Indicator_Style"; const static QString keyPluginsVisible = "Plugins_Visible"; const static QString keyCardCurrent = "cardCurrent"; const static QString keyShowInPrimary = "Show_In_Primary"; +const static QString keyShowOnAllScreens = "Show_On_All_Screens"; const static QString keyLocked = "Locked"; const static QString keyEnableContextMenu = "enableContextMenu"; const static QString keyEnableFashionMode = "enableFashionMode"; @@ -163,6 +164,7 @@ DockSettings::DockSettings(QObject* parent) , m_dockPosition(dock::Bottom) , m_alignment(dock::CenterAlignment) , m_style(dock::Fashion) + , m_showOnAllScreens(false) , m_locked(false) , m_contextMenuEnabled(true) { @@ -190,6 +192,7 @@ void DockSettings::init() m_pluginsVisible = m_dockConfig->value(keyPluginsVisible).toMap(); m_cardCurrent = m_dockConfig->value(keyCardCurrent).toString(); m_showInPrimary = m_dockConfig->value(keyShowInPrimary).toBool(); + m_showOnAllScreens = m_dockConfig->value(keyShowOnAllScreens, false).toBool(); m_locked = m_dockConfig->value(keyLocked).toBool(); m_contextMenuEnabled = m_dockConfig->value(keyEnableContextMenu, true).toBool(); m_fashionModeEnabled = m_dockConfig->value(keyEnableFashionMode, false).toBool(); @@ -238,6 +241,11 @@ void DockSettings::init() if (showInPrimary == m_showInPrimary) return; m_showInPrimary = showInPrimary; Q_EMIT showInPrimaryChanged(m_showInPrimary); + } else if (keyShowOnAllScreens == key) { + const auto showOnAllScreens = m_dockConfig->value(keyShowOnAllScreens).toBool(); + if (showOnAllScreens == m_showOnAllScreens) return; + m_showOnAllScreens = showOnAllScreens; + Q_EMIT showOnAllScreensChanged(m_showOnAllScreens); } else if (keyLocked == key) { auto locked = m_dockConfig->value(keyLocked).toBool(); if (locked == m_locked) return; @@ -379,6 +387,20 @@ bool DockSettings::showInPrimary() const return m_showInPrimary; } +bool DockSettings::showOnAllScreens() const +{ + return m_showOnAllScreens; +} + +void DockSettings::setShowOnAllScreens(bool newShowOnAllScreens) +{ + if (m_showOnAllScreens == newShowOnAllScreens) + return; + m_showOnAllScreens = newShowOnAllScreens; + m_dockConfig->setValue(keyShowOnAllScreens, m_showOnAllScreens); + Q_EMIT showOnAllScreensChanged(m_showOnAllScreens); +} + bool DockSettings::locked() const { return m_locked; diff --git a/panels/dock/docksettings.h b/panels/dock/docksettings.h index 5d1bee1d1..3e1d515ee 100644 --- a/panels/dock/docksettings.h +++ b/panels/dock/docksettings.h @@ -28,6 +28,7 @@ class DockSettings : public QObject Q_PROPERTY(QVariantMap pluginsVisible READ pluginsVisible WRITE setPluginsVisible NOTIFY pluginsVisibleChanged FINAL) Q_PROPERTY(QString cardCurrent READ cardCurrent WRITE setCardCurrent NOTIFY cardCurrentChanged FINAL) Q_PROPERTY(bool showInPrimary READ showInPrimary WRITE setShowInPrimary NOTIFY showInPrimaryChanged FINAL) + Q_PROPERTY(bool showOnAllScreens READ showOnAllScreens WRITE setShowOnAllScreens NOTIFY showOnAllScreensChanged FINAL) Q_PROPERTY(bool locked READ locked WRITE setLocked NOTIFY lockedChanged FINAL) Q_PROPERTY(bool contextMenuEnabled READ contextMenuEnabled NOTIFY contextMenuEnabledChanged FINAL) Q_PROPERTY(bool fashionModeEnabled READ fashionModeEnabled NOTIFY fashionModeEnabledChanged FINAL) @@ -43,6 +44,7 @@ class DockSettings : public QObject QVariantMap pluginsVisible(); QString cardCurrent() const; bool showInPrimary() const; + bool showOnAllScreens() const; bool locked() const; bool contextMenuEnabled() const; // 时尚模式是否允许开启,由 DConfig 的 enableFashionMode 控制,默认关闭 @@ -56,6 +58,7 @@ class DockSettings : public QObject void setPluginsVisible(const QVariantMap & pluginsVisible); void setCardCurrent(const QString &cardCurrent); void setShowInPrimary(bool newShowInPrimary); + void setShowOnAllScreens(bool newShowOnAllScreens); void setLocked(bool newLocked); private: @@ -84,6 +87,7 @@ class DockSettings : public QObject void cardCurrentChanged(const QString &cardCurrent); void showInPrimaryChanged(bool showInPrimary); + void showOnAllScreensChanged(bool showOnAllScreens); void lockedChanged(bool locked); void contextMenuEnabledChanged(bool enabled); void fashionModeEnabledChanged(bool enabled); @@ -104,6 +108,7 @@ class DockSettings : public QObject QVariantMap m_pluginsVisible; QString m_cardCurrent; bool m_showInPrimary; + bool m_showOnAllScreens; bool m_locked; bool m_contextMenuEnabled; bool m_fashionModeEnabled = false; diff --git a/shell/main.cpp b/shell/main.cpp index 51fc6a9ed..1657af090 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -5,9 +5,15 @@ #include #include #include +#include +#include +#include #include #include +#include +#include +#include #include #include #include @@ -18,6 +24,7 @@ #include #include "applet.h" +#include "appletdata.h" #include "containment.h" #include "pluginloader.h" #include "appletconfigmanager.h" @@ -26,6 +33,7 @@ #include "shell.h" DS_USE_NAMESPACE +DCORE_USE_NAMESPACE DGUI_USE_NAMESPACE DWIDGET_USE_NAMESPACE @@ -56,25 +64,34 @@ class AppletManager qCDebug(dsLog) << "Preloading plugins:" << pluginIds; Q_ASSERT(configManager); - auto rootApplet = qobject_cast(DPluginLoader::instance()->rootApplet()); - Q_ASSERT(rootApplet); + m_configManager = configManager; + Q_ASSERT(qobject_cast(DPluginLoader::instance()->rootApplet())); + + m_dockConfig.reset(DConfig::create("org.deepin.dde.shell", "org.deepin.ds.dock", QString(), qApp)); + if (m_dockConfig && m_dockConfig->isValid()) + m_showOnAllScreens = m_dockConfig->value(QStringLiteral("Show_On_All_Screens"), false).toBool(); for (const auto &pluginId : pluginIds) { - auto applet = rootApplet->createApplet(DAppletData{pluginId}); - if (!applet) { - qCWarning(dsLog) << "Loading plugin failed:" << pluginId; - continue; + if (pluginId == dockPluginId() && m_showOnAllScreens) { + for (auto *screen : qApp->screens()) + addDockForScreen(screen); + } else { + createLoader(DAppletData{pluginId}, pluginIds); } + } - auto loader = new DAppletLoader(applet, configManager); - m_loaders << loader; - QObject::connect(loader, &DAppletLoader::failed, qApp, [this, loader, pluginIds](const QString &pluginId) { - if (pluginIds.contains(pluginId)) { - m_loaders.removeOne(loader); - loader->deleteLater(); - } + if (m_dockConfig && m_dockConfig->isValid()) { + QObject::connect(m_dockConfig.data(), &DConfig::valueChanged, qApp, [this](const QString &key) { + if (key == QStringLiteral("Show_On_All_Screens")) + setShowOnAllScreens(m_dockConfig->value(key, false).toBool()); }); } + QObject::connect(qApp, &QGuiApplication::screenAdded, qApp, [this](QScreen *screen) { + scheduleDockForScreen(screen); + }); + QObject::connect(qApp, &QGuiApplication::screenRemoved, qApp, [this](QScreen *screen) { + removeDockForScreen(screen); + }); QObject::connect(configManager, &AppletConfigManager::appletEnabledChanged, @@ -104,6 +121,7 @@ class AppletManager for (auto loader : std::as_const(m_loaders)) { loader->exec(); } + m_started = true; } void quit() { @@ -132,6 +150,103 @@ class AppletManager } QList m_loaders; + +private: + static QString dockPluginId() { return QStringLiteral("org.deepin.ds.dock"); } + + void scheduleDockForScreen(QScreen *screen, int attempt = 0) + { + if (!screen || !m_showOnAllScreens) + return; + + QPointer pendingScreen(screen); + QTimer::singleShot(250, qApp, [this, pendingScreen, attempt] { + if (!pendingScreen || !m_showOnAllScreens || !qApp->screens().contains(pendingScreen)) + return; + + const auto geometry = pendingScreen->geometry(); + const bool geometryReady = geometry.width() > 1 && geometry.height() > 1; + if (!geometryReady && attempt < 20) { + scheduleDockForScreen(pendingScreen, attempt + 1); + return; + } + + if (geometryReady) + addDockForScreen(pendingScreen); + }); + } + + DAppletLoader *createLoader(const DAppletData &data, const QStringList &rootPluginIds) + { + auto rootApplet = qobject_cast(DPluginLoader::instance()->rootApplet()); + auto applet = rootApplet->createApplet(data); + if (!applet) { + qCWarning(dsLog) << "Loading plugin failed:" << data.pluginId(); + return nullptr; + } + auto loader = new DAppletLoader(applet, m_configManager); + m_loaders << loader; + QObject::connect(loader, &DAppletLoader::failed, qApp, [this, loader, rootPluginIds](const QString &pluginId) { + if (rootPluginIds.contains(pluginId)) { + m_loaders.removeOne(loader); + loader->deleteLater(); + } + }); + return loader; + } + + void addDockForScreen(QScreen *screen) + { + if (!screen || m_dockLoaders.contains(screen)) + return; + QVariantMap data; + data.insert(QStringLiteral("PluginId"), dockPluginId()); + data.insert(QStringLiteral("Id"), QUuid::createUuid().toString(QUuid::WithoutBraces)); + data.insert(QStringLiteral("DockMirror"), true); + data.insert(QStringLiteral("DockScreen"), screen->name()); + data.insert(QStringLiteral("DockMirrorPrimary"), screen == qApp->primaryScreen()); + if (auto *loader = createLoader(DAppletData(data), QStringList{dockPluginId()})) { + m_dockLoaders.insert(screen, loader); + if (m_started) + loader->exec(); + } + } + + void removeDockForScreen(QScreen *screen) + { + auto *loader = m_dockLoaders.take(screen); + if (!loader) + return; + if (auto *applet = loader->applet()) { + if (auto *rootApplet = qobject_cast(applet->parentApplet())) + rootApplet->removeApplet(applet); + } + m_loaders.removeOne(loader); + loader->deleteLater(); + } + + void setShowOnAllScreens(bool enabled) + { + if (m_showOnAllScreens == enabled) + return; + m_showOnAllScreens = enabled; + const auto screens = m_dockLoaders.keys(); + for (auto *screen : screens) + removeDockForScreen(screen); + if (m_showOnAllScreens) { + for (auto *screen : qApp->screens()) + addDockForScreen(screen); + } else { + if (auto *loader = createLoader(DAppletData{dockPluginId()}, QStringList{dockPluginId()})) + loader->exec(); + } + } + + QHash m_dockLoaders; + QScopedPointer m_dockConfig; + AppletConfigManager *m_configManager = nullptr; + bool m_showOnAllScreens = false; + bool m_started = false; }; int main(int argc, char *argv[])