diff --git a/applets/dde-key-notify/treelandkeynotify.cpp b/applets/dde-key-notify/treelandkeynotify.cpp index 1fda99bb8..9f74cd06a 100644 --- a/applets/dde-key-notify/treelandkeynotify.cpp +++ b/applets/dde-key-notify/treelandkeynotify.cpp @@ -17,6 +17,16 @@ TreelandKeyNotify::TreelandKeyNotify(QObject *parent) connect(this, &TreelandKeyNotify::activeChanged, this, &TreelandKeyNotify::updateWatcher); } +TreelandKeyNotify::~TreelandKeyNotify() +{ + if (m_watcher) { + delete m_watcher; + m_watcher = nullptr; + } + if (isInitialized()) + destroy(); +} + void TreelandKeyNotify::setCapsLockEnabled(bool enabled) { if (m_capsLockEnabled == enabled) { @@ -83,6 +93,12 @@ TreelandKeyWatcher::TreelandKeyWatcher(struct ::treeland_keyboard_state_watcher_ { } +TreelandKeyWatcher::~TreelandKeyWatcher() +{ + if (isInitialized()) + destroy(); +} + void TreelandKeyWatcher::watchLocks(bool watchCapsLock) { set_modifiers(watchCapsLock ? modifier_caps_lock | modifier_num_lock : modifier_num_lock); diff --git a/applets/dde-key-notify/treelandkeynotify.h b/applets/dde-key-notify/treelandkeynotify.h index 7ddd78fa7..cbac83f3d 100644 --- a/applets/dde-key-notify/treelandkeynotify.h +++ b/applets/dde-key-notify/treelandkeynotify.h @@ -24,6 +24,7 @@ class TreelandKeyNotify : public QWaylandClientExtensionTemplate(treeland_dde_shell_manager_v1_interface.version) + : QWaylandClientExtensionTemplate(treeland_compositor_action_v1_interface.version) { } -void TreeLandLockScreen::lock() +TreeLandLockScreen::~TreeLandLockScreen() { - if (auto impl = workder()) - impl->lock(); -} - -void TreeLandLockScreen::shutdown() -{ - if (auto impl = workder()) - impl->shutdown(); + if (isInitialized()) { + destroy(); + } } -void TreeLandLockScreen::switchUser() +void TreeLandLockScreen::lock() { - if (auto impl = workder()) - impl->switch_user(); + if (isActive()) { + trigger(action_lockscreen); + } } -TreeLandLockScreenWorker *TreeLandLockScreen::workder() +void TreeLandLockScreen::shutdown() { - if (!isActive()) { - return nullptr; + if (isActive()) { + trigger(action_shutdown_menu); } - - if (m_worker.isNull()) { - m_worker.reset(new TreeLandLockScreenWorker(get_treeland_lockscreen())); - } - return m_worker.get(); } -TreeLandLockScreenWorker::TreeLandLockScreenWorker(struct ::treeland_lockscreen_v1 *object) - : QWaylandClientExtensionTemplate(treeland_lockscreen_v1_interface.version) - , QtWayland::treeland_lockscreen_v1(object) +void TreeLandLockScreen::switchUser() { + if (isActive()) { + trigger(action_show_user_switch); + } } } DS_END_NAMESPACE diff --git a/applets/dde-shutdown/treelandlockscreen.h b/applets/dde-shutdown/treelandlockscreen.h index 452913166..1cd74cf35 100644 --- a/applets/dde-shutdown/treelandlockscreen.h +++ b/applets/dde-shutdown/treelandlockscreen.h @@ -1,41 +1,27 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "dsglobal.h" -#include "qwayland-treeland-dde-shell-v1.h" +#include "qwayland-treeland-compositor-action-unstable-v1.h" #include DS_BEGIN_NAMESPACE namespace shutdown { -class TreeLandLockScreenWorker; -class TreeLandLockScreen : public QWaylandClientExtensionTemplate, public QtWayland::treeland_dde_shell_manager_v1 +class TreeLandLockScreen : public QWaylandClientExtensionTemplate, public QtWayland::treeland_compositor_action_v1 { Q_OBJECT public: explicit TreeLandLockScreen(); + ~TreeLandLockScreen(); void lock(); void shutdown(); void switchUser(); - -private: - TreeLandLockScreenWorker *workder(); - -private: - QScopedPointer m_worker; -}; - -class TreeLandLockScreenWorker : public QWaylandClientExtensionTemplate, public QtWayland::treeland_lockscreen_v1 -{ - Q_OBJECT - -public: - explicit TreeLandLockScreenWorker(struct ::treeland_lockscreen_v1 *object); }; } DS_END_NAMESPACE diff --git a/debian/control b/debian/control index 27a16a495..be6dfa2e3 100644 --- a/debian/control +++ b/debian/control @@ -40,7 +40,7 @@ Build-Depends: qt6-wayland-dev-tools, qt6-wayland-private-dev, systemd, - treeland-protocols (>= 0.6.0), + treeland-protocols (>= 0.7.0), wayland-protocols, Standards-Version: 4.6.2 Homepage: https://github.com/linuxdeepin/dde-shell diff --git a/frame/wayland/xdgactivation.cpp b/frame/wayland/xdgactivation.cpp index 118fdf1cc..11ba604a0 100644 --- a/frame/wayland/xdgactivation.cpp +++ b/frame/wayland/xdgactivation.cpp @@ -29,7 +29,8 @@ class XdgActivationTokenV1 : public QObject, public QtWayland::xdg_activation_to public: ~XdgActivationTokenV1() override { - destroy(); + if (isInitialized()) + destroy(); } Q_SIGNALS: diff --git a/panels/dock/CMakeLists.txt b/panels/dock/CMakeLists.txt index 58deda7db..70ba6f2b1 100644 --- a/panels/dock/CMakeLists.txt +++ b/panels/dock/CMakeLists.txt @@ -61,7 +61,6 @@ qt_generate_wayland_protocol_client_sources(dockpanel NO_INCLUDE_CORE_ONLY FILES ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-wallpaper-color-v1.xml - ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-dde-shell-v1.xml ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-xwindow-control-unstable-v1.xml ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-region-watch-unstable-v1.xml ) diff --git a/panels/dock/multitaskview/CMakeLists.txt b/panels/dock/multitaskview/CMakeLists.txt index 158cf4810..d742320e7 100644 --- a/panels/dock/multitaskview/CMakeLists.txt +++ b/panels/dock/multitaskview/CMakeLists.txt @@ -4,14 +4,14 @@ find_package(PkgConfig REQUIRED) find_package(Qt${QT_VERSION_MAJOR} ${REQUIRED_QT_VERSION} COMPONENTS WaylandClient) -find_package(TreelandProtocols REQUIRED) +find_package(TreelandProtocols 0.7.0 REQUIRED) pkg_check_modules(WaylandClient REQUIRED IMPORTED_TARGET wayland-client) add_library(dock-multitaskview SHARED multitaskview.cpp multitaskview.h - treelandmultitaskview.cpp - treelandmultitaskview.h + treelandcompositoraction.cpp + treelandcompositoraction.h ) target_include_directories(dock-multitaskview PRIVATE @@ -20,9 +20,8 @@ target_include_directories(dock-multitaskview PRIVATE ) qt_generate_wayland_protocol_client_sources(dock-multitaskview - NO_INCLUDE_CORE_ONLY FILES - ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-dde-shell-v1.xml + ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-compositor-action-unstable-v1.xml ) target_link_libraries(dock-multitaskview PRIVATE diff --git a/panels/dock/multitaskview/multitaskview.cpp b/panels/dock/multitaskview/multitaskview.cpp index 750f93a5b..66517ce4e 100644 --- a/panels/dock/multitaskview/multitaskview.cpp +++ b/panels/dock/multitaskview/multitaskview.cpp @@ -41,7 +41,7 @@ MultiTaskView::MultiTaskView(QObject *parent) }); auto platformName = QGuiApplication::platformName(); if (QStringLiteral("wayland") == platformName) { - m_multitaskview.reset(new TreeLandMultitaskview); + m_compositorAction.reset(new TreelandCompositorAction); } else { m_kWinCompositingConfig = DConfig::create("org.kde.kwin", "org.kde.kwin.compositing", QString(), this); m_kWinEffect = m_kWinCompositingConfig->value(windowEffectTypeKey).toInt() != KWinOptimalPerformance; @@ -87,8 +87,8 @@ void MultiTaskView::openWorkspace() {QStringLiteral("kwin_version"), m_kwinVersion} })); #endif - if (m_multitaskview) { - m_multitaskview->toggle(); + if (m_compositorAction) { + m_compositorAction->toggle(); return; } diff --git a/panels/dock/multitaskview/multitaskview.h b/panels/dock/multitaskview/multitaskview.h index 14ab24e0d..2403d3023 100644 --- a/panels/dock/multitaskview/multitaskview.h +++ b/panels/dock/multitaskview/multitaskview.h @@ -8,7 +8,7 @@ #include "../frame/dockiteminfo.h" #include "applet.h" #include "dsglobal.h" -#include "treelandmultitaskview.h" +#include "treelandcompositoraction.h" #include @@ -38,7 +38,7 @@ class MultiTaskView : public DS_NAMESPACE::DAppletDock bool m_kWinEffect = true; QString m_kwinVersion; QString m_iconName; - QScopedPointer m_multitaskview; + QScopedPointer m_compositorAction; Dtk::Core::DConfig *m_kWinCompositingConfig = nullptr; }; diff --git a/panels/dock/multitaskview/treelandcompositoraction.cpp b/panels/dock/multitaskview/treelandcompositoraction.cpp new file mode 100644 index 000000000..29b2f1adf --- /dev/null +++ b/panels/dock/multitaskview/treelandcompositoraction.cpp @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "treelandcompositoraction.h" +#include "wayland-treeland-compositor-action-unstable-v1-client-protocol.h" + +namespace dock +{ +TreelandCompositorAction::TreelandCompositorAction(QObject *parent) + : QWaylandClientExtensionTemplate(treeland_compositor_action_v1_interface.version) +{ + setParent(parent); +} + +TreelandCompositorAction::~TreelandCompositorAction() +{ + if (isInitialized()) { + destroy(); + } +} + +void TreelandCompositorAction::toggle() +{ + if (isActive()) { + trigger(action_toggle_multitask_view); + } +} +} diff --git a/panels/dock/multitaskview/treelandcompositoraction.h b/panels/dock/multitaskview/treelandcompositoraction.h new file mode 100644 index 000000000..b2b4ed6ea --- /dev/null +++ b/panels/dock/multitaskview/treelandcompositoraction.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "qwayland-treeland-compositor-action-unstable-v1.h" +#include + +namespace dock +{ + +class TreelandCompositorAction : public QWaylandClientExtensionTemplate, public QtWayland::treeland_compositor_action_v1 +{ +public: + explicit TreelandCompositorAction(QObject *parent = nullptr); + ~TreelandCompositorAction(); + void toggle(); +}; +} diff --git a/panels/dock/multitaskview/treelandmultitaskview.cpp b/panels/dock/multitaskview/treelandmultitaskview.cpp deleted file mode 100644 index 371438ed6..000000000 --- a/panels/dock/multitaskview/treelandmultitaskview.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "treelandmultitaskview.h" - -namespace dock -{ -TreeLandMultitaskview::TreeLandMultitaskview() - : QWaylandClientExtensionTemplate(treeland_dde_shell_manager_v1_interface.version) -{ -} - -void TreeLandMultitaskview::toggle() -{ - if (!isActive()) { - return; - } - - if (m_worker.isNull()) { - m_worker.reset(new TreeLandMultitaskviewWorker(get_treeland_multitaskview())); - } - m_worker->toggle(); -} - -TreeLandMultitaskviewWorker::TreeLandMultitaskviewWorker(struct ::treeland_multitaskview_v1 *object) - : QWaylandClientExtensionTemplate(treeland_multitaskview_v1_interface.version) - , QtWayland::treeland_multitaskview_v1(object) -{ -} -} diff --git a/panels/dock/multitaskview/treelandmultitaskview.h b/panels/dock/multitaskview/treelandmultitaskview.h deleted file mode 100644 index 4a3e2d85a..000000000 --- a/panels/dock/multitaskview/treelandmultitaskview.h +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "qwayland-treeland-dde-shell-v1.h" - -#include - -namespace dock -{ -class TreeLandMultitaskviewWorker; -class TreeLandMultitaskview : public QWaylandClientExtensionTemplate, public QtWayland::treeland_dde_shell_manager_v1 -{ - Q_OBJECT - -public: - explicit TreeLandMultitaskview(); - void toggle(); - -private: - QScopedPointer m_worker; -}; - -class TreeLandMultitaskviewWorker : public QWaylandClientExtensionTemplate, public QtWayland::treeland_multitaskview_v1 -{ - Q_OBJECT - -public: - explicit TreeLandMultitaskviewWorker(struct ::treeland_multitaskview_v1 *object); -}; -} diff --git a/panels/dock/showdesktop/CMakeLists.txt b/panels/dock/showdesktop/CMakeLists.txt index 2b8f400c5..ee89c4556 100644 --- a/panels/dock/showdesktop/CMakeLists.txt +++ b/panels/dock/showdesktop/CMakeLists.txt @@ -4,19 +4,19 @@ find_package(PkgConfig REQUIRED) find_package(Qt${QT_VERSION_MAJOR} ${REQUIRED_QT_VERSION} COMPONENTS WaylandClient) -find_package(TreelandProtocols 0.6.0 REQUIRED) +find_package(TreelandProtocols 0.7.0 REQUIRED) pkg_check_modules(WaylandClient REQUIRED IMPORTED_TARGET wayland-client) add_library(dock-showdesktop SHARED showdesktop.cpp showdesktop.h - treelandshowdesktop.cpp - treelandshowdesktop.h + treelandcompositoraction.cpp + treelandcompositoraction.h ) qt_generate_wayland_protocol_client_sources(dock-showdesktop FILES - ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-show-desktop-unstable-v1.xml + ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-compositor-action-unstable-v1.xml ) target_link_libraries(dock-showdesktop PRIVATE diff --git a/panels/dock/showdesktop/showdesktop.cpp b/panels/dock/showdesktop/showdesktop.cpp index 409a7d5dc..f273e1212 100644 --- a/panels/dock/showdesktop/showdesktop.cpp +++ b/panels/dock/showdesktop/showdesktop.cpp @@ -5,7 +5,7 @@ #include "showdesktop.h" #include "applet.h" #include "pluginfactory.h" -#include "treelandshowdesktop.h" +#include "treelandcompositoraction.h" #include #include @@ -22,7 +22,7 @@ namespace dock { ShowDesktop::ShowDesktop(QObject *parent) : DApplet(parent) - , m_showDesktop(nullptr) + , m_compositorAction(nullptr) , m_dockConfig(nullptr) , m_visible(true) { @@ -47,7 +47,7 @@ bool ShowDesktop::load() bool ShowDesktop::init() { if (QStringLiteral("wayland") == QGuiApplication::platformName()) { - m_showDesktop = new TreelandShowDesktop(this); + m_compositorAction = new TreelandCompositorAction(this); } // 从配置中读取初始的可见性状态 @@ -61,8 +61,8 @@ bool ShowDesktop::init() void ShowDesktop::toggleShowDesktop() { - if (m_showDesktop) { - m_showDesktop->desktopToggle(); + if (m_compositorAction) { + m_compositorAction->desktopToggle(); return; } diff --git a/panels/dock/showdesktop/showdesktop.h b/panels/dock/showdesktop/showdesktop.h index da2d00e46..30c0c0303 100644 --- a/panels/dock/showdesktop/showdesktop.h +++ b/panels/dock/showdesktop/showdesktop.h @@ -6,7 +6,7 @@ #include "applet.h" #include "dsglobal.h" -#include "treelandshowdesktop.h" +#include "treelandcompositoraction.h" #include @@ -35,7 +35,7 @@ private slots: void onEnableShowDesktopChanged(); private: - TreelandShowDesktop *m_showDesktop; + TreelandCompositorAction *m_compositorAction; Dtk::Core::DConfig *m_dockConfig; bool m_visible; }; diff --git a/panels/dock/showdesktop/treelandcompositoraction.cpp b/panels/dock/showdesktop/treelandcompositoraction.cpp new file mode 100644 index 000000000..c0689b0fd --- /dev/null +++ b/panels/dock/showdesktop/treelandcompositoraction.cpp @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "treelandcompositoraction.h" +#include "wayland-treeland-compositor-action-unstable-v1-client-protocol.h" + +namespace dock +{ +TreelandCompositorAction::TreelandCompositorAction(QObject *parent) + : QWaylandClientExtensionTemplate(treeland_compositor_action_v1_interface.version) +{ + setParent(parent); +} + +TreelandCompositorAction::~TreelandCompositorAction() +{ + if (isInitialized()) { + destroy(); + } +} + +void TreelandCompositorAction::desktopToggle() +{ + if (isActive()) { + trigger(action_show_desktop); + } +} +} diff --git a/panels/dock/showdesktop/treelandcompositoraction.h b/panels/dock/showdesktop/treelandcompositoraction.h new file mode 100644 index 000000000..ec6f2c9cb --- /dev/null +++ b/panels/dock/showdesktop/treelandcompositoraction.h @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "qwayland-treeland-compositor-action-unstable-v1.h" +#include + +namespace dock +{ + +class TreelandCompositorAction : public QWaylandClientExtensionTemplate, public QtWayland::treeland_compositor_action_v1 +{ +public: + explicit TreelandCompositorAction(QObject *parent); + ~TreelandCompositorAction(); + + void desktopToggle(); +}; +} diff --git a/panels/dock/showdesktop/treelandshowdesktop.cpp b/panels/dock/showdesktop/treelandshowdesktop.cpp deleted file mode 100644 index ff1beffe9..000000000 --- a/panels/dock/showdesktop/treelandshowdesktop.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "treelandshowdesktop.h" -#include "wayland-treeland-show-desktop-unstable-v1-client-protocol.h" - -namespace dock -{ -TreelandShowDesktop::TreelandShowDesktop(QObject *parent) - : QWaylandClientExtensionTemplate(treeland_show_desktop_v1_interface.version) - , m_desktopState(state_normal) -{ - setParent(parent); -} - -void TreelandShowDesktop::desktopToggle() -{ - if (isActive()) { - set_show_desktop_state(m_desktopState == state_show ? state_normal : state_show); - } -} - -void TreelandShowDesktop::treeland_show_desktop_v1_show_desktop_state(uint32_t state) -{ - if (state != m_desktopState) { - m_desktopState = state; - } -} -} diff --git a/panels/dock/showdesktop/treelandshowdesktop.h b/panels/dock/showdesktop/treelandshowdesktop.h deleted file mode 100644 index 311208ccb..000000000 --- a/panels/dock/showdesktop/treelandshowdesktop.h +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "qwayland-treeland-show-desktop-unstable-v1.h" -#include -#include - -namespace dock -{ - -class TreelandShowDesktop : public QWaylandClientExtensionTemplate, public QtWayland::treeland_show_desktop_v1 -{ -public: - explicit TreelandShowDesktop(QObject *parent); - - void desktopToggle(); - -protected: - void treeland_show_desktop_v1_show_desktop_state(uint32_t state) override; - -private: - uint32_t m_desktopState; -}; -} diff --git a/panels/dock/taskmanager/treelandwindowmonitor.cpp b/panels/dock/taskmanager/treelandwindowmonitor.cpp index 4603c8dcb..d0ccaabc1 100644 --- a/panels/dock/taskmanager/treelandwindowmonitor.cpp +++ b/panels/dock/taskmanager/treelandwindowmonitor.cpp @@ -51,7 +51,8 @@ TreeLandDockPreviewContext::TreeLandDockPreviewContext(struct ::treeland_dock_pr TreeLandDockPreviewContext::~TreeLandDockPreviewContext() { - destroy(); + if (isInitialized()) + destroy(); } void TreeLandDockPreviewContext::showWindowsPreview(QByteArray windowsId, int32_t previewXoffset, int32_t previewYoffset, uint32_t direction) diff --git a/panels/dock/waylanddockhelper.cpp b/panels/dock/waylanddockhelper.cpp index ce7f37c86..6e72cb112 100644 --- a/panels/dock/waylanddockhelper.cpp +++ b/panels/dock/waylanddockhelper.cpp @@ -8,9 +8,7 @@ #include "dockhelper.h" #include "dockpanel.h" #include "layershell/dlayershellwindow.h" -#include "qwayland-treeland-dde-shell-v1.h" #include "qwayland-treeland-xwindow-control-unstable-v1.h" -#include "wayland-treeland-dde-shell-v1-client-protocol.h" #include "wayland-treeland-xwindow-control-unstable-v1-client-protocol.h" #include "qwayland-treeland-region-watch-unstable-v1.h" #include "wayland-treeland-region-watch-unstable-v1-client-protocol.h" @@ -26,7 +24,6 @@ WaylandDockHelper::WaylandDockHelper(DockPanel *panel) , m_isCurrentActiveWindowFullscreened(false) , m_panel(panel) { - m_ddeShellManager.reset(new TreeLandDDEShellManager()); m_xwindowControl.reset(new TreeLandXWindowControl()); m_regionWatchManager.reset(new TreeLandRegionWatchManager()); DS_NAMESPACE::DAppletBridge bridge("org.deepin.ds.dock.taskmanager"); @@ -213,6 +210,12 @@ WallpaperColorManager::WallpaperColorManager(WaylandDockHelper *helper) { } +WallpaperColorManager::~WallpaperColorManager() +{ + if (isInitialized()) + destroy(); +} + void WallpaperColorManager::treeland_wallpaper_color_manager_v1_output_color(const QString &output, uint32_t isDark) { if (output == m_helper->dockScreenName()) { @@ -227,11 +230,6 @@ void WallpaperColorManager::watchScreen(const QString &screeName) } } -TreeLandDDEShellManager::TreeLandDDEShellManager() - : QWaylandClientExtensionTemplate(treeland_dde_shell_manager_v1_interface.version) -{ -} - TreeLandXWindowControl::TreeLandXWindowControl() : QWaylandClientExtensionTemplate(treeland_xwindow_control_v1_interface.version) { @@ -273,7 +271,8 @@ TreeLandRegionWatch::TreeLandRegionWatch(WaylandDockHelper *helper, struct ::tre TreeLandRegionWatch::~TreeLandRegionWatch() { - destroy(); + if (isInitialized()) + destroy(); } void TreeLandRegionWatch::treeland_region_watch_v1_enter() diff --git a/panels/dock/waylanddockhelper.h b/panels/dock/waylanddockhelper.h index 592cec8ad..d135ea389 100644 --- a/panels/dock/waylanddockhelper.h +++ b/panels/dock/waylanddockhelper.h @@ -7,7 +7,6 @@ #include "dockhelper.h" #include "dockpanel.h" -#include "qwayland-treeland-dde-shell-v1.h" #include "qwayland-treeland-wallpaper-color-v1.h" #include "qwayland-treeland-xwindow-control-unstable-v1.h" #include "qwayland-treeland-region-watch-unstable-v1.h" @@ -20,7 +19,6 @@ namespace dock { class WallpaperColorManager; class TreeLandDockTriggerArea; -class TreeLandDDEShellManager; class TreeLandXWindowControl; class TreeLandRegionWatchManager; class TreeLandRegionWatch; @@ -65,7 +63,6 @@ protected Q_SLOTS: QScopedPointer m_wallpaperColorManager; QScopedPointer m_regionWatch; QScopedPointer m_regionWatchManager; - QScopedPointer m_ddeShellManager; QScopedPointer m_xwindowControl; struct ::wl_surface *m_dockWlSurface = nullptr; // Dock's wl_surface for XEmbed positioning }; @@ -75,6 +72,7 @@ class WallpaperColorManager : public QWaylandClientExtensionTemplate, public QtWayland::treeland_dde_shell_manager_v1 -{ - Q_OBJECT - -public: - explicit TreeLandDDEShellManager(); -}; - class TreeLandXWindowControl : public QWaylandClientExtensionTemplate, public QtWayland::treeland_xwindow_control_v1 { Q_OBJECT diff --git a/panels/notification/osd/brightness/CMakeLists.txt b/panels/notification/osd/brightness/CMakeLists.txt index 9a1e2b0b8..53bb4b18d 100644 --- a/panels/notification/osd/brightness/CMakeLists.txt +++ b/panels/notification/osd/brightness/CMakeLists.txt @@ -16,7 +16,7 @@ add_library(osd-brightness SHARED qt_generate_wayland_protocol_client_sources(osd-brightness NO_INCLUDE_CORE_ONLY FILES - ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-output-manager-v1.xml + ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-output-manager-unstable-v2.xml ) target_link_libraries(osd-brightness PRIVATE diff --git a/panels/notification/osd/brightness/treelandbrightness.cpp b/panels/notification/osd/brightness/treelandbrightness.cpp index dd6b99983..83575d120 100644 --- a/panels/notification/osd/brightness/treelandbrightness.cpp +++ b/panels/notification/osd/brightness/treelandbrightness.cpp @@ -4,7 +4,7 @@ #include "treelandbrightness.h" -#include "wayland-treeland-output-manager-v1-client-protocol.h" +#include "wayland-treeland-output-manager-unstable-v2-client-protocol.h" #include #include @@ -13,32 +13,32 @@ namespace osd { -TreelandColorControl::TreelandColorControl(struct ::treeland_output_color_control_v1 *object, QObject *parent) +TreelandPictureControl::TreelandPictureControl(struct ::treeland_output_picture_control_v2 *object, QObject *parent) : QObject(parent) - , QtWayland::treeland_output_color_control_v1(object) + , QtWayland::treeland_output_picture_control_v2(object) { } -TreelandColorControl::~TreelandColorControl() +TreelandPictureControl::~TreelandPictureControl() { if (isInitialized()) { destroy(); } } -double TreelandColorControl::brightness() const +double TreelandPictureControl::brightness() const { return m_brightness; } -void TreelandColorControl::treeland_output_color_control_v1_brightness(wl_fixed_t brightness) +void TreelandPictureControl::treeland_output_picture_control_v2_brightness(wl_fixed_t brightness) { m_brightness = wl_fixed_to_double(brightness); Q_EMIT brightnessChanged(m_brightness); } TreelandBrightness::TreelandBrightness(QObject *parent) - : QWaylandClientExtensionTemplate(treeland_output_manager_v1_interface.version) + : QWaylandClientExtensionTemplate(treeland_output_manager_v2_interface.version) { setParent(parent); connect(this, &TreelandBrightness::activeChanged, this, &TreelandBrightness::refresh); @@ -47,8 +47,6 @@ TreelandBrightness::TreelandBrightness(QObject *parent) TreelandBrightness::~TreelandBrightness() { delete m_control; - m_control = nullptr; - m_output = nullptr; if (isInitialized()) { destroy(); } @@ -76,13 +74,13 @@ void TreelandBrightness::refresh() return; } - auto *raw = get_color_control(output); + auto *raw = get_picture_control(output); if (!raw) { return; } - m_control = new TreelandColorControl(raw, this); - connect(m_control, &TreelandColorControl::brightnessChanged, + m_control = new TreelandPictureControl(raw, this); + connect(m_control, &TreelandPictureControl::brightnessChanged, this, &TreelandBrightness::brightnessChanged); } diff --git a/panels/notification/osd/brightness/treelandbrightness.h b/panels/notification/osd/brightness/treelandbrightness.h index ea87d8a92..f308b727c 100644 --- a/panels/notification/osd/brightness/treelandbrightness.h +++ b/panels/notification/osd/brightness/treelandbrightness.h @@ -4,24 +4,24 @@ #pragma once -#include "qwayland-treeland-output-manager-v1.h" +#include "qwayland-treeland-output-manager-unstable-v2.h" #include #include #include struct wl_output; -struct treeland_output_color_control_v1; +struct treeland_output_picture_control_v2; namespace osd { -class TreelandColorControl : public QObject, public QtWayland::treeland_output_color_control_v1 +class TreelandPictureControl : public QObject, public QtWayland::treeland_output_picture_control_v2 { Q_OBJECT public: - explicit TreelandColorControl(struct ::treeland_output_color_control_v1 *object, QObject *parent = nullptr); - ~TreelandColorControl() override; + explicit TreelandPictureControl(struct ::treeland_output_picture_control_v2 *object, QObject *parent = nullptr); + ~TreelandPictureControl() override; double brightness() const; @@ -29,18 +29,18 @@ class TreelandColorControl : public QObject, public QtWayland::treeland_output_c void brightnessChanged(double brightness); protected: - void treeland_output_color_control_v1_brightness(wl_fixed_t brightness) override; + void treeland_output_picture_control_v2_brightness(wl_fixed_t brightness) override; private: double m_brightness = 0.0; }; // Read-only Treeland brightness provider for the OSD. It binds a single -// treeland_output_color_control_v1 to the primary wl_output and caches the +// treeland_output_picture_control_v2 to the primary wl_output and caches the // brightness reported by the compositor. It never commits brightness changes; // dde-shortcut-tool is responsible for adjusting brightness, and this provider // only reflects the resulting value. -class TreelandBrightness : public QWaylandClientExtensionTemplate, public QtWayland::treeland_output_manager_v1 +class TreelandBrightness : public QWaylandClientExtensionTemplate, public QtWayland::treeland_output_manager_v2 { Q_OBJECT @@ -58,7 +58,7 @@ class TreelandBrightness : public QWaylandClientExtensionTemplate m_control; + QPointer m_control; struct wl_output *m_output = nullptr; }; diff --git a/panels/notification/osd/default/package/icons/osd_bluetooth_off.dci b/panels/notification/osd/default/package/icons/osd_bluetooth_off.dci new file mode 100644 index 000000000..7aacb0b3e Binary files /dev/null and b/panels/notification/osd/default/package/icons/osd_bluetooth_off.dci differ diff --git a/panels/notification/osd/default/package/icons/osd_bluetooth_on.dci b/panels/notification/osd/default/package/icons/osd_bluetooth_on.dci new file mode 100644 index 000000000..0e28bcf65 Binary files /dev/null and b/panels/notification/osd/default/package/icons/osd_bluetooth_on.dci differ diff --git a/panels/notification/osd/default/package/main.qml b/panels/notification/osd/default/package/main.qml index 20d727fe3..3637712ad 100644 --- a/panels/notification/osd/default/package/main.qml +++ b/panels/notification/osd/default/package/main.qml @@ -64,6 +64,8 @@ AppletItem { ListElement { type: "FnToggle"; iconName: "osd_fn"; text: qsTr("Fn toggle")} // Fn切换 ListElement { type: "AirplaneModeOn"; iconName: "osd_airplane_on"; text: qsTr("Airplane mode on")} ListElement { type: "AirplaneModeOff"; iconName: "osd_airplane_off"; text: qsTr("Airplane mode off")} + ListElement { type: "BluetoothOn"; iconName: "osd_bluetooth_on"; text: qsTr("Bluetooth on")} + ListElement { type: "BluetoothOff"; iconName: "osd_bluetooth_off"; text: qsTr("Bluetooth off")} ListElement { type: "AudioMicMuteOn"; iconName: "osd_mic_off"; text: qsTr("Microphone off")} ListElement { type: "AudioMicMuteOff"; iconName: "osd_mic_on"; text: qsTr("Microphone on")} ListElement { type: "balance"; iconName: "osd_power_balance"; text: qsTr("Balanced power")} diff --git a/panels/notification/osd/displaymode/displaymodeapplet.cpp b/panels/notification/osd/displaymode/displaymodeapplet.cpp index 847ec77e8..e9707af0d 100644 --- a/panels/notification/osd/displaymode/displaymodeapplet.cpp +++ b/panels/notification/osd/displaymode/displaymodeapplet.cpp @@ -13,6 +13,9 @@ #include #include +#include + +DGUI_USE_NAMESPACE Q_LOGGING_CATEGORY(osdDPLog, "org.deepin.dde.shell.osd.display") @@ -77,6 +80,12 @@ DisPlayModeApplet::DisPlayModeApplet(QObject *parent) QObject::connect(m_actionTimer, &QTimer::timeout, this, &DisPlayModeApplet::doAction); } +bool DisPlayModeApplet::load() +{ + m_isWayland = DGuiApplicationHelper::testAttribute(DGuiApplicationHelper::IsWaylandPlatform); + return DApplet::load(); +} + int DisPlayModeApplet::state() const { return m_state; @@ -102,6 +111,13 @@ QQmlListProperty DisPlayModeApplet::planItems() void DisPlayModeApplet::sync() { + // On Wayland there is no Treeland display-mode protocol yet; fall back to + // a disabled state so the OSD shows "unavailable" until a protocol is ready. + if (m_isWayland) { + setState(2); + return; + } + if (!m_actionTimer->isActive()) { fetchPlanItems(); auto current = fetchCurrentPlanItem(); @@ -115,6 +131,11 @@ void DisPlayModeApplet::sync() void DisPlayModeApplet::next() { + // Display mode switching is not available on Wayland yet. + if (m_isWayland) { + return; + } + auto it = std::find_if(m_planItems.begin(), m_planItems.end(), [this](const DPItem *item) { return m_currentPlanItem && item->key() == m_currentPlanItem->key(); }); @@ -131,6 +152,11 @@ void DisPlayModeApplet::next() void DisPlayModeApplet::doAction() { + // Display mode switching is not available on Wayland yet. + if (m_isWayland) { + return; + } + const auto item = currentPlanItem(); if (!item) return; diff --git a/panels/notification/osd/displaymode/displaymodeapplet.h b/panels/notification/osd/displaymode/displaymodeapplet.h index 2957fb9b9..0e3cf05b8 100644 --- a/panels/notification/osd/displaymode/displaymodeapplet.h +++ b/panels/notification/osd/displaymode/displaymodeapplet.h @@ -56,6 +56,8 @@ class DisPlayModeApplet : public DS_NAMESPACE::DApplet public: explicit DisPlayModeApplet(QObject *parent = nullptr); + bool load() override; + int state() const; DPItem *currentPlanItem() const; QQmlListProperty planItems(); @@ -79,8 +81,9 @@ class DisPlayModeApplet : public DS_NAMESPACE::DApplet private: QList m_planItems; DPItem *m_currentPlanItem = nullptr; - int m_state; + int m_state = 0; QTimer *m_actionTimer = nullptr; + bool m_isWayland = false; }; } diff --git a/panels/notification/osd/osdpanel.cpp b/panels/notification/osd/osdpanel.cpp index 6d47be03d..4597abc0c 100644 --- a/panels/notification/osd/osdpanel.cpp +++ b/panels/notification/osd/osdpanel.cpp @@ -19,6 +19,10 @@ namespace osd { OsdPanel::OsdPanel(QObject *parent) : DPanel(parent) { + m_osdTimer = new QTimer(this); + m_osdTimer->setInterval(m_interval); + m_osdTimer->setSingleShot(true); + QObject::connect(m_osdTimer, &QTimer::timeout, this, &OsdPanel::doneSetting); } bool OsdPanel::load() @@ -44,10 +48,6 @@ bool OsdPanel::init() } new OsdDBusAdaptor(this); - m_osdTimer = new QTimer(this); - m_osdTimer->setInterval(m_interval); - m_osdTimer->setSingleShot(true); - QObject::connect(m_osdTimer, &QTimer::timeout, this, &OsdPanel::doneSetting); return DPanel::init(); } diff --git a/shell/treelandoutputwatcher.cpp b/shell/treelandoutputwatcher.cpp index 5fb82e913..c71da0e2f 100644 --- a/shell/treelandoutputwatcher.cpp +++ b/shell/treelandoutputwatcher.cpp @@ -20,7 +20,8 @@ TreelandOutputWatcher::TreelandOutputWatcher(QObject *parent) TreelandOutputWatcher::~TreelandOutputWatcher() { - destroy(); + if (isInitialized()) + destroy(); } void TreelandOutputWatcher::onScreenAdded(QScreen *) diff --git a/tests/at/spi/expected_names.yaml b/tests/at/spi/expected_names.yaml index 4565179cc..3f4222929 100644 --- a/tests/at/spi/expected_names.yaml +++ b/tests/at/spi/expected_names.yaml @@ -997,4 +997,116 @@ qml_elements: source_file: shell/SceneWindow.qml parent_type: ApplicationWindow line: 24 +- element_type: Window + id: root + accessible_id: Root + accessible_role: '' + source_file: panels/notification/osd/package/main.qml + parent_type: '' + line: 13 +- element_type: Control + id: '' + accessible_id: Control + accessible_role: '' + source_file: panels/notification/osd/package/main.qml + parent_type: Window + line: 75 +- element_type: Repeater + id: '' + accessible_id: Repeater + accessible_role: '' + source_file: panels/notification/osd/package/main.qml + parent_type: Control + line: 82 +- element_type: AppletItem + id: control + accessible_id: Control + accessible_role: '' + source_file: panels/notification/osd/default/package/main.qml + parent_type: '' + line: 12 +- element_type: DciIcon + id: '' + accessible_id: DciIcon + accessible_role: '' + source_file: panels/notification/osd/default/package/main.qml + parent_type: RowLayout + line: 86 +- element_type: Text + id: '' + accessible_id: Text + accessible_role: '' + source_file: panels/notification/osd/default/package/main.qml + parent_type: RowLayout + line: 99 +- element_type: AppletItem + id: control + accessible_id: Control + accessible_role: '' + source_file: panels/notification/osd/audio/package/main.qml + parent_type: '' + line: 12 +- element_type: DciIcon + id: '' + accessible_id: DciIcon + accessible_role: '' + source_file: panels/notification/osd/audio/package/main.qml + parent_type: RowLayout + line: 48 +- element_type: ProgressBar + id: progressBar + accessible_id: ProgressBar + accessible_role: '' + source_file: panels/notification/osd/audio/package/main.qml + parent_type: ColumnLayout + line: 76 +- element_type: Text + id: '' + accessible_id: Text + accessible_role: '' + source_file: panels/notification/osd/audio/package/main.qml + parent_type: RowLayout + line: 123 +- element_type: Text + id: '' + accessible_id: Text + accessible_role: '' + source_file: panels/notification/osd/audio/package/main.qml + parent_type: RowLayout + line: 129 +- element_type: AppletItem + id: control + accessible_id: Control + accessible_role: '' + source_file: panels/notification/osd/brightness/package/main.qml + parent_type: '' + line: 12 +- element_type: DciIcon + id: '' + accessible_id: DciIcon + accessible_role: '' + source_file: panels/notification/osd/brightness/package/main.qml + parent_type: RowLayout + line: 46 +- element_type: ProgressBar + id: progressBar + accessible_id: ProgressBar + accessible_role: '' + source_file: panels/notification/osd/brightness/package/main.qml + parent_type: RowLayout + line: 58 +- element_type: Text + id: '' + accessible_id: Text + accessible_role: '' + source_file: panels/notification/osd/brightness/package/main.qml + parent_type: RowLayout + line: 98 +- element_type: Text + id: '' + accessible_id: Text + accessible_role: '' + source_file: panels/notification/osd/brightness/package/main.qml + parent_type: RowLayout + line: 104 transient_elements: [] diff --git a/tests/panels/notification/CMakeLists.txt b/tests/panels/notification/CMakeLists.txt index e72550161..095cbc348 100644 --- a/tests/panels/notification/CMakeLists.txt +++ b/tests/panels/notification/CMakeLists.txt @@ -4,3 +4,4 @@ add_subdirectory(common) add_subdirectory(server) +add_subdirectory(osd) diff --git a/tests/panels/notification/osd/CMakeLists.txt b/tests/panels/notification/osd/CMakeLists.txt new file mode 100644 index 000000000..f2203944c --- /dev/null +++ b/tests/panels/notification/osd/CMakeLists.txt @@ -0,0 +1,183 @@ +# SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +find_package(GTest REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS + Core + Test + DBus +) + +# ---- osdpanel_test ---- +add_executable(osdpanel_tests + ${CMAKE_SOURCE_DIR}/panels/notification/osd/osdpanel.h + ${CMAKE_SOURCE_DIR}/panels/notification/osd/osdpanel.cpp + ${CMAKE_SOURCE_DIR}/panels/notification/osd/osddbusadaptor.h + ${CMAKE_SOURCE_DIR}/panels/notification/osd/osddbusadaptor.cpp + osdpanel_test.cpp +) + +set_property(TARGET osdpanel_tests APPEND PROPERTY AUTOMOC_MACRO_NAMES "D_APPLET_CLASS") + +target_compile_options(osdpanel_tests PRIVATE + -fvisibility=hidden + -fvisibility-inlines-hidden +) + +target_include_directories(osdpanel_tests PRIVATE + ${CMAKE_SOURCE_DIR}/panels/notification/osd + ${CMAKE_SOURCE_DIR}/frame +) + +target_link_libraries(osdpanel_tests PRIVATE + GTest::GTest + GTest::gmock + GTest::gmock_main + GTest::Main + + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Test + Qt${QT_VERSION_MAJOR}::DBus + + dde-shell-frame +) + +add_test( + NAME osdpanel_tests + COMMAND ${CMAKE_COMMAND} -E env + LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/frame + $ +) + +# ---- audioapplet_test ---- +add_executable(audioapplet_tests + ${CMAKE_SOURCE_DIR}/panels/notification/osd/audio/audioapplet.h + ${CMAKE_SOURCE_DIR}/panels/notification/osd/audio/audioapplet.cpp + audioapplet_test.cpp +) + +set_property(TARGET audioapplet_tests APPEND PROPERTY AUTOMOC_MACRO_NAMES "D_APPLET_CLASS") + +target_compile_options(audioapplet_tests PRIVATE + -fvisibility=hidden + -fvisibility-inlines-hidden +) + +target_include_directories(audioapplet_tests PRIVATE + ${CMAKE_SOURCE_DIR}/panels/notification/osd/audio + ${CMAKE_SOURCE_DIR}/frame +) + +target_link_libraries(audioapplet_tests PRIVATE + GTest::GTest + GTest::gmock + GTest::gmock_main + GTest::Main + + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Test + Qt${QT_VERSION_MAJOR}::DBus + + dde-shell-frame +) + +add_test( + NAME audioapplet_tests + COMMAND ${CMAKE_COMMAND} -E env + LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/frame + $ +) + +# ---- brightnessapplet_test ---- +find_package(TreelandProtocols REQUIRED) +find_package(PkgConfig REQUIRED) +pkg_check_modules(WaylandClient REQUIRED IMPORTED_TARGET wayland-client) + +add_executable(brightnessapplet_tests + ${CMAKE_SOURCE_DIR}/panels/notification/osd/brightness/brightnessapplet.h + ${CMAKE_SOURCE_DIR}/panels/notification/osd/brightness/brightnessapplet.cpp + ${CMAKE_SOURCE_DIR}/panels/notification/osd/brightness/treelandbrightness.h + ${CMAKE_SOURCE_DIR}/panels/notification/osd/brightness/treelandbrightness.cpp + brightnessapplet_test.cpp +) + +qt_generate_wayland_protocol_client_sources(brightnessapplet_tests + NO_INCLUDE_CORE_ONLY + FILES + ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-output-manager-unstable-v2.xml +) + +set_property(TARGET brightnessapplet_tests APPEND PROPERTY AUTOMOC_MACRO_NAMES "D_APPLET_CLASS") + +target_compile_options(brightnessapplet_tests PRIVATE + -fvisibility=hidden + -fvisibility-inlines-hidden +) + +target_include_directories(brightnessapplet_tests PRIVATE + ${CMAKE_SOURCE_DIR}/panels/notification/osd/brightness + ${CMAKE_SOURCE_DIR}/frame +) + +target_link_libraries(brightnessapplet_tests PRIVATE + GTest::GTest + GTest::gmock + GTest::gmock_main + GTest::Main + + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Test + Qt${QT_VERSION_MAJOR}::DBus + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::WaylandClient + + dde-shell-frame + PkgConfig::WaylandClient +) + +add_test( + NAME brightnessapplet_tests + COMMAND ${CMAKE_COMMAND} -E env + LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/frame + $ +) + +# ---- displaymodeapplet_test ---- +add_executable(displaymodeapplet_tests + ${CMAKE_SOURCE_DIR}/panels/notification/osd/displaymode/displaymodeapplet.h + ${CMAKE_SOURCE_DIR}/panels/notification/osd/displaymode/displaymodeapplet.cpp + displaymodeapplet_test.cpp +) + +set_property(TARGET displaymodeapplet_tests APPEND PROPERTY AUTOMOC_MACRO_NAMES "D_APPLET_CLASS") + +target_compile_options(displaymodeapplet_tests PRIVATE + -fvisibility=hidden + -fvisibility-inlines-hidden +) + +target_include_directories(displaymodeapplet_tests PRIVATE + ${CMAKE_SOURCE_DIR}/panels/notification/osd/displaymode + ${CMAKE_SOURCE_DIR}/frame +) + +target_link_libraries(displaymodeapplet_tests PRIVATE + GTest::GTest + GTest::gmock + GTest::gmock_main + GTest::Main + + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Test + Qt${QT_VERSION_MAJOR}::DBus + + dde-shell-frame +) + +add_test( + NAME displaymodeapplet_tests + COMMAND ${CMAKE_COMMAND} -E env + LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/frame + $ +) diff --git a/tests/panels/notification/osd/audioapplet_test.cpp b/tests/panels/notification/osd/audioapplet_test.cpp new file mode 100644 index 000000000..26d4a1c65 --- /dev/null +++ b/tests/panels/notification/osd/audioapplet_test.cpp @@ -0,0 +1,112 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include +#include +#include + +#include "audioapplet.h" + +using namespace osd; +using ::testing::Return; + +// Mock interface for audio DBus operations. +// The real AudioApplet uses DDBusSender to call org.deepin.dde.Audio1. +// For unit testing we cannot rely on a live DBus session, so we test +// the icon name computation logic directly by setting the internal +// volume value and observing the result of sync/fetchIconName. +class AudioAppletTest : public ::testing::Test { +protected: + void SetUp() override { + if (!QCoreApplication::instance()) { + int argc = 0; + char *argv[] = {nullptr}; + app = new QCoreApplication(argc, argv); + } + applet = new AudioApplet(); + } + + void TearDown() override { + delete applet; + applet = nullptr; + } + + QCoreApplication *app = nullptr; + AudioApplet *applet = nullptr; +}; + +// Test initial state +TEST_F(AudioAppletTest, InitialState) { + EXPECT_EQ(applet->iconName().toStdString(), ""); + EXPECT_DOUBLE_EQ(applet->volumeValue(), 1.0); +} + +// Test setIconName emits signal +TEST_F(AudioAppletTest, SetIconNameEmitsSignal) { + QSignalSpy spy(applet, &AudioApplet::iconNameChanged); + applet->setIconName("osd_volume_33"); + EXPECT_EQ(applet->iconName().toStdString(), "osd_volume_33"); + EXPECT_EQ(spy.count(), 1); +} + +// Test setIconName does not emit when unchanged +TEST_F(AudioAppletTest, SetIconNameNoSignalWhenUnchanged) { + applet->setIconName("osd_volume_33"); + QSignalSpy spy(applet, &AudioApplet::iconNameChanged); + applet->setIconName("osd_volume_33"); + EXPECT_EQ(spy.count(), 0); +} + +// Test setVolumeValue emits signal +TEST_F(AudioAppletTest, SetVolumeValueEmitsSignal) { + QSignalSpy spy(applet, &AudioApplet::volumeValueChanged); + applet->setVolumeValue(0.5); + EXPECT_DOUBLE_EQ(applet->volumeValue(), 0.5); + EXPECT_EQ(spy.count(), 1); +} + +// Test setVolumeValue does not emit when unchanged (fuzzy compare) +TEST_F(AudioAppletTest, SetVolumeValueNoSignalWhenUnchanged) { + applet->setVolumeValue(0.5); + QSignalSpy spy(applet, &AudioApplet::volumeValueChanged); + applet->setVolumeValue(0.5); + EXPECT_EQ(spy.count(), 0); +} + +// Test increaseVolume property +TEST_F(AudioAppletTest, IncreaseVolumeProperty) { + EXPECT_TRUE(applet->increaseVolume()); + + QSignalSpy spy(applet, &AudioApplet::increaseVolumeChanged); + applet->setIncreaseVolume(false); + EXPECT_FALSE(applet->increaseVolume()); + EXPECT_EQ(spy.count(), 1); +} + +// Test increaseVolume no signal when unchanged +TEST_F(AudioAppletTest, IncreaseVolumeNoSignalWhenUnchanged) { + applet->setIncreaseVolume(true); + QSignalSpy spy(applet, &AudioApplet::increaseVolumeChanged); + applet->setIncreaseVolume(true); + EXPECT_EQ(spy.count(), 0); +} + +// Test sync does not crash without DBus (graceful degradation) +TEST_F(AudioAppletTest, SyncWithoutDBus) { + EXPECT_NO_THROW(applet->sync()); +} + +// Main function for tests +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + QCoreApplication app(argc, argv); + + return RUN_ALL_TESTS(); +} + +#include "audioapplet_test.moc" diff --git a/tests/panels/notification/osd/brightnessapplet_test.cpp b/tests/panels/notification/osd/brightnessapplet_test.cpp new file mode 100644 index 000000000..48ae123c2 --- /dev/null +++ b/tests/panels/notification/osd/brightnessapplet_test.cpp @@ -0,0 +1,85 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include +#include +#include + +#include "brightnessapplet.h" + +using namespace osd; + +// Test fixture for BrightnessApplet +class BrightnessAppletTest : public ::testing::Test { +protected: + void SetUp() override { + applet = new BrightnessApplet(); + } + + void TearDown() override { + delete applet; + applet = nullptr; + } + + BrightnessApplet *applet = nullptr; +}; + +// Test initial state +TEST_F(BrightnessAppletTest, InitialState) { + EXPECT_DOUBLE_EQ(applet->brightness(), 0.0); + EXPECT_EQ(applet->iconName().toStdString(), ""); +} + +// Test sync does not crash without DBus (graceful degradation) +TEST_F(BrightnessAppletTest, SyncWithoutDBus) { + EXPECT_NO_THROW(applet->sync()); +} + +// Test sync sets icon name for zero brightness +TEST_F(BrightnessAppletTest, SyncSetsIconForZeroBrightness) { + applet->sync(); + // Without DBus, fetchBrightness returns 0, so brightness stays 0 + // fetchIconName for brightness <= 0 returns "osd_brightness0" + EXPECT_EQ(applet->iconName().toStdString(), "osd_brightness0"); +} + +// Test brightness property signal +TEST_F(BrightnessAppletTest, BrightnessSignalEmission) { + QSignalSpy spy(applet, &BrightnessApplet::brightnessChanged); + // sync() with no DBus will call setBrightness(0) which equals initial 0, + // so no signal is emitted + applet->sync(); + EXPECT_EQ(spy.count(), 0); +} + +// Test iconName signal is emitted on first sync +TEST_F(BrightnessAppletTest, IconNameSignalEmission) { + QSignalSpy spy(applet, &BrightnessApplet::iconNameChanged); + applet->sync(); + // iconName changes from "" to "osd_brightness0" + EXPECT_EQ(spy.count(), 1); +} + +// Test iconName does not change when sync called again with same brightness +TEST_F(BrightnessAppletTest, IconNameNoChangeOnRepeatedSync) { + applet->sync(); + QSignalSpy spy(applet, &BrightnessApplet::iconNameChanged); + applet->sync(); + // iconName is already "osd_brightness0", no new signal + EXPECT_EQ(spy.count(), 0); +} + +// Main function for tests +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + QCoreApplication app(argc, argv); + + return RUN_ALL_TESTS(); +} + +#include "brightnessapplet_test.moc" diff --git a/tests/panels/notification/osd/displaymodeapplet_test.cpp b/tests/panels/notification/osd/displaymodeapplet_test.cpp new file mode 100644 index 000000000..ca039ce86 --- /dev/null +++ b/tests/panels/notification/osd/displaymodeapplet_test.cpp @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include +#include +#include + +#include "displaymodeapplet.h" + +using namespace osd; + +// Test fixture for DisPlayModeApplet +class DisplayModeAppletTest : public ::testing::Test { +protected: + void SetUp() override { + applet = new DisPlayModeApplet(); + } + + void TearDown() override { + delete applet; + applet = nullptr; + } + + DisPlayModeApplet *applet = nullptr; +}; + +// Test DPItem construction with 4-arg constructor +TEST(DisplayModeItemTest, ConstructWithFourArgs) { + DPItem item("Duplicate", "osd_multi_screen_copy", DPItem::Merge); + EXPECT_EQ(item.text().toStdString(), "Duplicate"); + EXPECT_EQ(item.name().toStdString(), ""); + EXPECT_EQ(item.iconName().toStdString(), "osd_multi_screen_copy"); + EXPECT_EQ(item.mode(), DPItem::Merge); +} + +// Test DPItem construction with 5-arg constructor +TEST(DisplayModeItemTest, ConstructWithFiveArgs) { + DPItem item("Only on HDMI-1", "HDMI-1", "osd_multi_screen_only1", DPItem::Single); + EXPECT_EQ(item.text().toStdString(), "Only on HDMI-1"); + EXPECT_EQ(item.name().toStdString(), "HDMI-1"); + EXPECT_EQ(item.iconName().toStdString(), "osd_multi_screen_only1"); + EXPECT_EQ(item.mode(), DPItem::Single); +} + +// Test DPItem key format +TEST(DisplayModeItemTest, KeyFormat) { + DPItem item("Extend", "osd_multi_screen_extension", DPItem::Extend); + QString expectedKey = QString("%1-%2-%3").arg("Extend").arg("").arg(DPItem::Extend); + EXPECT_EQ(item.key().toStdString(), expectedKey.toStdString()); +} + +// Test DPItem key format with name +TEST(DisplayModeItemTest, KeyFormatWithName) { + DPItem item("Only on VGA", "VGA-1", "osd_multi_screen_only2", DPItem::Single); + QString expectedKey = QString("%1-%2-%3").arg("Only on VGA").arg("VGA-1").arg(DPItem::Single); + EXPECT_EQ(item.key().toStdString(), expectedKey.toStdString()); +} + +// Test DPItem mode enum values +TEST(DisplayModeItemTest, ModeEnumValues) { + EXPECT_EQ(DPItem::Merge, 1); + EXPECT_EQ(DPItem::Extend, 2); + EXPECT_EQ(DPItem::Single, 3); +} + +// Test initial state +TEST_F(DisplayModeAppletTest, InitialState) { + EXPECT_EQ(applet->state(), 0); + EXPECT_EQ(applet->currentPlanItem(), nullptr); +} + +// Test sync does not crash without DBus (graceful degradation) +TEST_F(DisplayModeAppletTest, SyncWithoutDBus) { + EXPECT_NO_THROW(applet->sync()); +} + +// Test next() does not crash on empty plan list +TEST_F(DisplayModeAppletTest, NextOnEmptyPlanList) { + EXPECT_NO_THROW(applet->next()); +} + +// Test doAction does not crash without current item +TEST_F(DisplayModeAppletTest, DoActionWithoutCurrentItem) { + EXPECT_NO_THROW(applet->doAction()); +} + +// Test state signal is emitted when changed +TEST_F(DisplayModeAppletTest, StateSignalEmission) { + // sync() without DBus will not change state from initial 0, + // since fetchState() depends on DConfig which may not be available. + // Just verify no crash. + QSignalSpy spy(applet, &DisPlayModeApplet::stateChanged); + applet->sync(); + // State may or may not change depending on DConfig availability. + // The key point is no crash. + SUCCEED(); +} + +// Test planItems is initially empty +TEST_F(DisplayModeAppletTest, PlanItemsInitiallyEmpty) { + // planItems() returns QQmlListProperty; check via the list + auto items = applet->planItems(); + EXPECT_EQ(items.count(&items), 0); +} + +// Main function for tests +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + QCoreApplication app(argc, argv); + + return RUN_ALL_TESTS(); +} + +#include "displaymodeapplet_test.moc" diff --git a/tests/panels/notification/osd/osdpanel_test.cpp b/tests/panels/notification/osd/osdpanel_test.cpp new file mode 100644 index 000000000..8ff9c01ac --- /dev/null +++ b/tests/panels/notification/osd/osdpanel_test.cpp @@ -0,0 +1,171 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "osdpanel.h" + +using namespace osd; + +// Test fixture for OsdPanel +class OsdPanelTest : public ::testing::Test { +protected: + void SetUp() override { + panel = new OsdPanel(); + } + + void TearDown() override { + delete panel; + panel = nullptr; + } + + OsdPanel *panel = nullptr; +}; + +// Test initial state +TEST_F(OsdPanelTest, InitialState) { + EXPECT_FALSE(panel->visible()); + EXPECT_TRUE(panel->osdType().isEmpty()); + EXPECT_TRUE(panel->lastOsdType().isEmpty()); +} + +// Test ShowOSD sets osdType via signal +TEST_F(OsdPanelTest, ShowOSDSetsOsdType) { + QSignalSpy spy(panel, &OsdPanel::osdTypeChanged); + + panel->ShowOSD("AudioUp"); + + // ShowOSD uses a 100ms timer to set osdType; wait for it + QTest::qWait(200); + + EXPECT_EQ(panel->osdType().toStdString(), "AudioUp"); + EXPECT_EQ(spy.count(), 1); + EXPECT_EQ(spy.takeFirst().at(0).toString().toStdString(), "AudioUp"); +} + +// Test ShowOSD makes panel visible +TEST_F(OsdPanelTest, ShowOSDMakesVisible) { + QSignalSpy spy(panel, &OsdPanel::visibleChanged); + + EXPECT_FALSE(panel->visible()); + + panel->ShowOSD("AudioUp"); + QTest::qWait(200); + + EXPECT_TRUE(panel->visible()); + EXPECT_EQ(spy.count(), 1); +} + +// Test ShowOSD with different type updates osdType +TEST_F(OsdPanelTest, ShowOSDDifferentType) { + panel->ShowOSD("AudioUp"); + QTest::qWait(200); + EXPECT_EQ(panel->osdType().toStdString(), "AudioUp"); + + panel->ShowOSD("AudioDown"); + QTest::qWait(200); + EXPECT_EQ(panel->osdType().toStdString(), "AudioDown"); +} + +// Test lastOsdType is updated after show +TEST_F(OsdPanelTest, LastOsdTypeUpdated) { + panel->ShowOSD("BrightnessUp"); + QTest::qWait(200); + EXPECT_EQ(panel->lastOsdType().toStdString(), "BrightnessUp"); +} + +// Test hideOsd sets visible false after timer expires +TEST_F(OsdPanelTest, HideOsdSetsInvisible) { + panel->ShowOSD("AudioUp"); + QTest::qWait(200); + EXPECT_TRUE(panel->visible()); + + // Non-SwitchWM3D interval is 1000ms, plus doneSetting delay. + // Wait long enough for the full hide cycle. + QTest::qWait(3000); + EXPECT_FALSE(panel->visible()); +} + +// Test ShowOSD called multiple times resets timer +TEST_F(OsdPanelTest, ShowOSDMultipleCallsResetTimer) { + panel->ShowOSD("AudioUp"); + QTest::qWait(200); + + panel->ShowOSD("AudioDown"); + QTest::qWait(200); + + EXPECT_EQ(panel->osdType().toStdString(), "AudioDown"); + EXPECT_TRUE(panel->visible()); +} + +// Test empty osd type +TEST_F(OsdPanelTest, ShowOSDEmptyType) { + panel->ShowOSD(""); + QTest::qWait(200); + EXPECT_TRUE(panel->osdType().isEmpty()); +} + +// Test SwitchWM3D uses 2000ms interval +TEST_F(OsdPanelTest, ShowOSDSwitchWM3D) { + panel->ShowOSD("SwitchWM3D"); + QTest::qWait(200); + EXPECT_EQ(panel->osdType().toStdString(), "SwitchWM3D"); + EXPECT_TRUE(panel->visible()); +} + +// D-Bus integration test for org.deepin.dde.Osd1 ShowOSD +class OsdDBusTest : public ::testing::Test { +protected: + void SetUp() override { + panel = new OsdPanel(); + // Try to initialize (registers DBus service). May fail if service + // is already taken; in that case skip the DBus tests. + dbusReady = panel->init(); + } + + void TearDown() override { + delete panel; + panel = nullptr; + } + + OsdPanel *panel = nullptr; + bool dbusReady = false; +}; + +// Test ShowOSD via DBus interface +TEST_F(OsdDBusTest, ShowOSDViaDBus) { + if (!dbusReady) { + GTEST_SKIP() << "DBus service registration failed; skipping DBus integration test"; + } + + QDBusInterface iface("org.deepin.dde.Osd1", "/", "org.deepin.dde.Osd1", + QDBusConnection::sessionBus()); + ASSERT_TRUE(iface.isValid()); + + QDBusReply reply = iface.call("ShowOSD", QString("AudioUp")); + ASSERT_TRUE(reply.isValid()); + + QTest::qWait(200); + EXPECT_EQ(panel->osdType().toStdString(), "AudioUp"); + EXPECT_TRUE(panel->visible()); +} + +// Main function for tests +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + QCoreApplication app(argc, argv); + + return RUN_ALL_TESTS(); +} + +#include "osdpanel_test.moc"