From f921a248a075508c3c3626a7964eea7a558c7c02 Mon Sep 17 00:00:00 2001 From: Ivy233 Date: Thu, 29 Jan 2026 16:36:06 +0800 Subject: [PATCH] fix: refactor dock position management and decouple from animation flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Lift positionForAnimation from dockAnimation to dock Window level - Move property from SequentialAnimation to Window scope - Update all references from dockAnimation.positionForAnimation to dock.positionForAnimation - Improve code organization and semantic clarity 2. Remove m_beforePosition member variable and beforePosition() getter - Directly emit beforePositionChanged(SETTINGS->position()) in setPosition() - Eliminate unnecessary intermediate storage - Simplify code and reduce memory footprint 3. Position change flow improvements - C++ directly commits position changes via SETTINGS->setPosition() - Animation logic triggered by beforePositionChanged signal - No dependency on QML animation callbacks 修复:重构任务栏位置管理并与动画流程解耦 1. 将 positionForAnimation 从 dockAnimation 提升到 dock Window 级别 - 将属性从 SequentialAnimation 移至 Window 作用域 - 更新所有引用从 dockAnimation.positionForAnimation 改为 dock.positionForAnimation - 改善代码组织和语义清晰度 2. 移除 m_beforePosition 成员变量和 beforePosition() getter 函数 - 在 setPosition() 中直接发送 beforePositionChanged(SETTINGS->position()) - 消除不必要的中间存储 - 简化代码并减少内存占用 3. 位置变更流程改进 - C++ 直接通过 SETTINGS->setPosition() 提交位置变更 - 动画逻辑由 beforePositionChanged 信号触发 - 不依赖 QML 动画回调 PMS: BUG-346777 --- panels/dock/dockpanel.cpp | 6 + panels/dock/dockpanel.h | 1 + panels/dock/package/main.qml | 120 +++++++++++++----- panels/dock/taskmanager/package/AppItem.qml | 2 +- .../dock/taskmanager/package/TaskManager.qml | 2 +- 5 files changed, 96 insertions(+), 35 deletions(-) diff --git a/panels/dock/dockpanel.cpp b/panels/dock/dockpanel.cpp index 6b41822de..087d8f019 100644 --- a/panels/dock/dockpanel.cpp +++ b/panels/dock/dockpanel.cpp @@ -262,6 +262,12 @@ Position DockPanel::position() void DockPanel::setPosition(const Position& position) { + if (position == SETTINGS->position()) return; + + // Emit signal with old position before updating + Q_EMIT beforePositionChanged(SETTINGS->position()); + + // Directly commit the position change SETTINGS->setPosition(position); } diff --git a/panels/dock/dockpanel.h b/panels/dock/dockpanel.h index 0b3318ca9..a06c4c670 100644 --- a/panels/dock/dockpanel.h +++ b/panels/dock/dockpanel.h @@ -119,6 +119,7 @@ private Q_SLOTS: void dockSizeChanged(uint size); void hideModeChanged(HideMode mode); + void beforePositionChanged(Position beforePosition); void positionChanged(Position position); void itemAlignmentChanged(ItemAlignment alignment); void indicatorStyleChanged(IndicatorStyle style); diff --git a/panels/dock/package/main.qml b/panels/dock/package/main.qml index 32932da40..22a618c42 100644 --- a/panels/dock/package/main.qml +++ b/panels/dock/package/main.qml @@ -17,7 +17,8 @@ import org.deepin.dtk.style 1.0 as DStyle Window { id: dock - property bool useColumnLayout: Applet.position % 2 + property int positionForAnimation: Panel.position + property bool useColumnLayout: positionForAnimation % 2 // TODO: 临时溢出逻辑,待后面修改 property int dockLeftSpaceForCenter: useColumnLayout ? (Screen.height - dockLeftPart.implicitHeight - dockRightPart.implicitHeight) : @@ -43,8 +44,8 @@ Window { property real dockItemIconSize: dockItemMaxSize * 9 / 14 // NOTE: -1 means not set its size, follow the platform size - width: Panel.position === Dock.Top || Panel.position === Dock.Bottom ? -1 : dockSize - height: Panel.position === Dock.Left || Panel.position === Dock.Right ? -1 : dockSize + width: positionForAnimation === Dock.Top || positionForAnimation === Dock.Bottom ? -1 : dockSize + height: positionForAnimation === Dock.Left || positionForAnimation === Dock.Right ? -1 : dockSize color: "transparent" flags: Qt.WindowDoesNotAcceptFocus @@ -55,7 +56,7 @@ Window { return appearance.opacity } - DLayerShellWindow.anchors: position2Anchors(Applet.position) + DLayerShellWindow.anchors: position2Anchors(positionForAnimation) DLayerShellWindow.layer: DLayerShellWindow.LayerTop DLayerShellWindow.exclusionZone: Panel.hideMode === Dock.KeepShowing ? Applet.dockSize : 0 DLayerShellWindow.scope: "dde-shell/dock" @@ -102,7 +103,7 @@ Window { return dock.useColumnLayout ? "width" : "height"; } to: { - if (useTransformBasedAnimation) return Panel.hideState !== Dock.Hide ? 0 : ((Panel.position === Dock.Left || Panel.position === Dock.Top) ? -Panel.dockSize : Panel.dockSize); + if (useTransformBasedAnimation) return Panel.hideState !== Dock.Hide ? 0 : ((dock.positionForAnimation === Dock.Left || dock.positionForAnimation === Dock.Top) ? -Panel.dockSize : Panel.dockSize); return Panel.hideState !== Dock.Hide ? Panel.dockSize : 1; } duration: 500 @@ -168,6 +169,7 @@ Window { id: dockAnimation property bool useTransformBasedAnimation: Qt.platform.pluginName === "xcb" property bool isShowing: false + property bool isPositionChanging: false property var target: useTransformBasedAnimation ? dockTransform : dock property string animProperty: { if (useTransformBasedAnimation) return dock.useColumnLayout ? "x" : "y"; @@ -179,13 +181,29 @@ Window { start(); } + function setTransformToHiddenPosition() { + if (useTransformBasedAnimation) { + var hideOffset = (Panel.position === Dock.Left || Panel.position === Dock.Top) ? -Panel.dockSize : Panel.dockSize; + if (dock.useColumnLayout) { + dockTransform.x = hideOffset; + dockTransform.y = 0; + } else { + dockTransform.x = 0; + dockTransform.y = hideOffset; + } + } else { + dockTransform.x = 0; + dockTransform.y = 0; + } + } + PropertyAnimation { target: dockAnimation.target property: dockAnimation.animProperty from: { if (dockAnimation.isShowing) { if (dockAnimation.useTransformBasedAnimation) { - return (Panel.position === Dock.Left || Panel.position === Dock.Top) ? -Panel.dockSize : Panel.dockSize; + return (dock.positionForAnimation === Dock.Left || dock.positionForAnimation === Dock.Top) ? -Panel.dockSize : Panel.dockSize; } return 1; } @@ -196,7 +214,7 @@ Window { return 0; } else { if (dockAnimation.useTransformBasedAnimation) { - return (Panel.position === Dock.Left || Panel.position === Dock.Top) ? -Panel.dockSize : Panel.dockSize; + return (dock.positionForAnimation === Dock.Left || dock.positionForAnimation === Dock.Top) ? -Panel.dockSize : Panel.dockSize; } return 1; } @@ -215,6 +233,28 @@ Window { } else { dock.visible = ((dock.useColumnLayout ? dock.width : dock.height) !== 1); } + + // If this was a hide animation during position change, prepare for show animation + if (isPositionChanging && !isShowing) { + isPositionChanging = false; + + // Update position for animation to new position for show animation + dock.positionForAnimation = Panel.position; + + // Set transform to hidden position before showing + setTransformToHiddenPosition(); + + startAnimation(true); + } else if (isShowing) { + // After show animation completes, check if we need to auto-hide + // For KeepHidden and SmartHide modes, trigger hide check immediately + if (Panel.hideMode === Dock.KeepHidden || Panel.hideMode === Dock.SmartHide) { + hideTimer.running = true; + } else if (Panel.hideState === Dock.Hide) { + // For other cases, if hideState is already Hide, trigger hide animation + hideTimer.running = true; + } + } } } @@ -224,31 +264,9 @@ Window { required property int value text: name - property var positionChangeCallback: function() { - // Disconnect any existing callback first - dockAnimation.onStopped.disconnect(positionChangeCallback); - // Stop any running animations first --fix bug with do not show dock - dockAnimation.stop(); - // Reset transform before starting new animation--fix bug with change position,will have a blank area - dockTransform.x = 0; - dockTransform.y = 0; - - Applet[prop] = value; - checked = Qt.binding(function() { - return Applet[prop] === value; - }); - dockAnimation.startAnimation(true); - } onTriggered: { - if (prop === "position") { - // Connect the callback and start the hide animation - dockAnimation.onStopped.connect(positionChangeCallback); - dockAnimation.startAnimation(false); - } else { + if (Applet[prop] !== value) { Applet[prop] = value - checked = Qt.binding(function() { - return Applet[prop] === value - }) } } checked: Applet[prop] === value @@ -648,7 +666,7 @@ Window { } function changeDragAreaAnchor() { - switch(Panel.position) { + switch(dock.positionForAnimation) { case Dock.Top: { dragArea.anchorToTop() return @@ -669,9 +687,42 @@ Window { } Connections { + function onBeforePositionChanged(beforePosition) { + // Stop any running animations first + dockAnimation.stop(); + hideShowAnimation.stop(); + + // Set the position for animation to old position for hide animation + dock.positionForAnimation = beforePosition; + + // Mark that we're changing position + dockAnimation.isPositionChanging = true; + + // Check if dock is currently hidden + if (Panel.hideState === Dock.Hide && !dock.visible) { + // Dock is already hidden, no need for hide animation + // Wait for onPositionChanged to get the new position, then show + dockAnimation.isPositionChanging = false; + } else { + // Start hide animation at old position + // When animation completes, onStopped will handle show animation + dockAnimation.startAnimation(false); + } + } + function onPositionChanged() { changeDragAreaAnchor() Panel.requestClosePopup() + + // If dock was hidden when position change started, show it now at new position + if (!dockAnimation.isPositionChanging && !dock.visible) { + dock.positionForAnimation = Panel.position; + + // Set transform to hidden position before showing + dockAnimation.setTransformToHiddenPosition(); + + dockAnimation.startAnimation(true); + } } function onDockSizeChanged() { dock.dockSize = Panel.dockSize @@ -681,7 +732,10 @@ Window { if (Panel.hideState === Dock.Hide) { hideTimer.running = true } else { - hideShowAnimation.restart() + // Only restart animation if not already running or if visible state doesn't match + if (!hideShowAnimation.running || !dock.visible) { + hideShowAnimation.restart() + } } } function onRequestClosePopup() { @@ -734,7 +788,7 @@ Window { }) DockCompositor.dockPosition = Qt.binding(function(){ - return Panel.position + return dock.positionForAnimation }) DockCompositor.dockSize = Qt.binding(function(){ diff --git a/panels/dock/taskmanager/package/AppItem.qml b/panels/dock/taskmanager/package/AppItem.qml index 49de6e2b3..1b2215f23 100644 --- a/panels/dock/taskmanager/package/AppItem.qml +++ b/panels/dock/taskmanager/package/AppItem.qml @@ -37,7 +37,7 @@ Item { Drag.dragType: Drag.Automatic Drag.mimeData: { "text/x-dde-dock-dnd-appid": itemId, "text/x-dde-dock-dnd-source": "taskbar", "text/x-dde-dock-dnd-winid": windows.length > 0 ? windows[0] : ""} - property bool useColumnLayout: Panel.position % 2 + property bool useColumnLayout: Panel.rootObject.useColumnLayout property int statusIndicatorSize: useColumnLayout ? root.width * 0.72 : root.height * 0.72 property int iconSize: Panel.rootObject.dockItemMaxSize * 9 / 14 property bool enableTitle: false diff --git a/panels/dock/taskmanager/package/TaskManager.qml b/panels/dock/taskmanager/package/TaskManager.qml index 3fff93655..a691a969e 100644 --- a/panels/dock/taskmanager/package/TaskManager.qml +++ b/panels/dock/taskmanager/package/TaskManager.qml @@ -12,7 +12,7 @@ import org.deepin.dtk 1.0 as D ContainmentItem { id: taskmanager - property bool useColumnLayout: Panel.position % 2 + property bool useColumnLayout: Panel.rootObject.useColumnLayout property int dockOrder: 16 property real remainingSpacesForTaskManager: Panel.itemAlignment === Dock.LeftAlignment ? Panel.rootObject.dockLeftSpaceForCenter : Panel.rootObject.dockRemainingSpaceForCenter