diff --git a/panels/dock/AppletItemButton.qml b/panels/dock/AppletItemButton.qml index 0b94c3777..1c52fd334 100644 --- a/panels/dock/AppletItemButton.qml +++ b/panels/dock/AppletItemButton.qml @@ -42,4 +42,27 @@ IconButton { Component.onCompleted: { contentItem.smooth = false } + + property var contentGlobalPoint: { + var a = contentItem + if (!a) return Qt.point(0, 0) + var x = 0, y = 0 + while (a && a.parent) { + x += a.x + y += a.y + a = a.parent + } + + return Qt.point(x, y) + } + + PositionFixer { + id: positionFixer + item: control + container: control + } + + onContentGlobalPointChanged: { + positionFixer.fix() + } } diff --git a/panels/dock/CMakeLists.txt b/panels/dock/CMakeLists.txt index 98d20dce7..a2bc3037f 100644 --- a/panels/dock/CMakeLists.txt +++ b/panels/dock/CMakeLists.txt @@ -110,6 +110,8 @@ file( pluginmanagerintegration.cpp dockpositioner.h dockpositioner.cpp + positionfixer.h + positionfixer.cpp ) set_source_files_properties(DockCompositor.qml PROPERTIES diff --git a/panels/dock/positionfixer.cpp b/panels/dock/positionfixer.cpp new file mode 100644 index 000000000..0aff77061 --- /dev/null +++ b/panels/dock/positionfixer.cpp @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "positionfixer.h" +#include +#include + +namespace dock { + +PositionFixer::PositionFixer(QQuickItem *parent) + : QQuickItem(parent) +{ + m_timer = new QTimer(this); + m_timer->setInterval(100); + m_timer->setSingleShot(true); + connect(m_timer, &QTimer::timeout, this, &PositionFixer::forceFix); +} + +QQuickItem *PositionFixer::item() const +{ + return m_item; +} + +void PositionFixer::setItem(QQuickItem *newItem) +{ + if (m_item == newItem) + return; + m_item = newItem; + if (m_item && !m_container) { + setContainer(m_item->parentItem()); + } + emit itemChanged(); +} + +QQuickItem *PositionFixer::container() const +{ + return m_container; +} + +void PositionFixer::setContainer(QQuickItem *newContainer) +{ + if (m_container == newContainer) + return; + m_container = newContainer; + emit containerChanged(); +} + +void PositionFixer::fix() +{ + m_timer->start(); +} + +void PositionFixer::forceFix() +{ + if (!m_item || !m_container || !m_container->window()) { + return; + } + + QQuickItem *contentItem = m_container->window()->contentItem(); + if (!contentItem) { + return; + } + + QPointF scenePos = m_container->mapToItem(contentItem, QPointF(0, 0)); + + qreal dpr = m_container->window()->devicePixelRatio(); + qreal physicalX = std::round(scenePos.x() * dpr); + qreal physicalY = std::round(scenePos.y() * dpr); + + QQuickItem *itemParent = m_item->parentItem() ? m_item->parentItem() : m_container; + + QPointF localPosX = itemParent->mapFromItem(contentItem, QPointF(physicalX / dpr, scenePos.y())); + QPointF localPosY = itemParent->mapFromItem(contentItem, QPointF(scenePos.x(), physicalY / dpr)); + m_item->setX(localPosX.x()); + m_item->setY(localPosY.y()); +} + +} diff --git a/panels/dock/positionfixer.h b/panels/dock/positionfixer.h new file mode 100644 index 000000000..380628e39 --- /dev/null +++ b/panels/dock/positionfixer.h @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include + +namespace dock { + +class PositionFixer : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(QQuickItem *item READ item WRITE setItem NOTIFY itemChanged) + Q_PROPERTY(QQuickItem *container READ container WRITE setContainer NOTIFY containerChanged) + + QML_NAMED_ELEMENT(PositionFixer) + +public: + explicit PositionFixer(QQuickItem *parent = nullptr); + + QQuickItem *item() const; + void setItem(QQuickItem *newItem); + + QQuickItem *container() const; + void setContainer(QQuickItem *newContainer); + + Q_INVOKABLE void fix(); + Q_INVOKABLE void forceFix(); + +signals: + void itemChanged(); + void containerChanged(); + void useZeroTargetChanged(); + +private: + QQuickItem *m_item = nullptr; + QQuickItem *m_container = nullptr; + QTimer *m_timer = nullptr; +}; + +} diff --git a/panels/dock/taskmanager/package/AppItem.qml b/panels/dock/taskmanager/package/AppItem.qml index 94e332aae..58ec082cb 100644 --- a/panels/dock/taskmanager/package/AppItem.qml +++ b/panels/dock/taskmanager/package/AppItem.qml @@ -140,88 +140,63 @@ Item { } target: Panel } - - D.DciIcon { - id: icon - name: root.iconName - height: iconSize - width: iconSize - sourceSize: Qt.size(iconSize, iconSize) + //加一层Item为了实现图标centerIn,不受到icon中fixposition的影响 + Item { + width: root.iconSize + height: root.iconSize anchors.centerIn: parent - retainWhileLoading: true - smooth: false - - function mapToScene(px, py) { - return parent.mapToItem(Window.window.contentItem, Qt.point(px, py)) - } - function mapFromScene(px, py) { - return parent.mapFromItem(Window.window.contentItem, Qt.point(px, py)) - } - - function fixPosition() { - if (root.Drag.active || !parent || launchAnimation.running) { - return + D.DciIcon { + id: icon + name: root.iconName + anchors.fill: parent + sourceSize: Qt.size(iconSize, iconSize) + retainWhileLoading: true + smooth: false + + PositionFixer { + id: positionFixer + item: icon } - anchors.centerIn = undefined - var targetX = (parent.width - width) / 2 - var targetY = (parent.height - height) / 2 - - var scenePos = mapToScene(targetX, targetY) - - var physicalX = Math.round(scenePos.x * Panel.devicePixelRatio) - var physicalY = Math.round(scenePos.y * Panel.devicePixelRatio) - - var localPos = mapFromScene(physicalX / Panel.devicePixelRatio, physicalY / Panel.devicePixelRatio) - - x = localPos.x - y = localPos.y - } - Timer { - id: fixPositionTimer - interval: 100 - repeat: false - running: false - onTriggered: { - icon.fixPosition() - } - } - - Connections { - target: root - function onIconGlobalPointChanged() { - fixPositionTimer.start() - } - } - LaunchAnimation { - id: launchAnimation - launchSpace: { - switch (Panel.position) { - case Dock.Top: - case Dock.Bottom: - return (root.height - icon.height) / 2 - case Dock.Left: - case Dock.Right: - return (root.width - icon.width) / 2 + Connections { + target: root + function onIconGlobalPointChanged() { + if (root.Drag.active || !parent || launchAnimation.running) { + return + } + positionFixer.fix() } } + LaunchAnimation { + id: launchAnimation + launchSpace: { + switch (Panel.position) { + case Dock.Top: + case Dock.Bottom: + return (root.height - icon.height) / 2 + case Dock.Left: + case Dock.Right: + return (root.width - icon.width) / 2 + } + } - direction: { - switch (Panel.position) { - case Dock.Top: - return LaunchAnimation.Direction.Down - case Dock.Bottom: - return LaunchAnimation.Direction.Up - case Dock.Left: - return LaunchAnimation.Direction.Right - case Dock.Right: - return LaunchAnimation.Direction.Left + direction: { + switch (Panel.position) { + case Dock.Top: + return LaunchAnimation.Direction.Down + case Dock.Bottom: + return LaunchAnimation.Direction.Up + case Dock.Left: + return LaunchAnimation.Direction.Right + case Dock.Right: + return LaunchAnimation.Direction.Left + } } + target: icon + loops: 1 + running: false } - target: icon - loops: 1 - running: false } } } diff --git a/panels/dock/tray/ShellSurfaceItemProxy.qml b/panels/dock/tray/ShellSurfaceItemProxy.qml index 5fe978aae..47a278a36 100644 --- a/panels/dock/tray/ShellSurfaceItemProxy.qml +++ b/panels/dock/tray/ShellSurfaceItemProxy.qml @@ -27,7 +27,12 @@ Item { } function fixPosition() { - fixPositionTimer.start() + positionFixer.fix() + } + + PositionFixer { + id: positionFixer + item: impl } ShellSurfaceItem { @@ -56,11 +61,10 @@ Item { onVisibleChanged: function () { if (visible) { - fixPositionTimer.start() + positionFixer.fix() } if (autoClose && !visible) { - // surface is valid but client's shellSurface maybe invalid. Qt.callLater(closeShellSurface) } } @@ -71,37 +75,8 @@ Item { } } - function mapToScene(x, y) { - const point = Qt.point(x, y) - // Must use parent.mapFoo, because the impl's position is relative to the parent Item - const mappedPoint = parent.mapToItem(Window.window.contentItem, point) - return mappedPoint - } - - function mapFromScene(x, y) { - const point = Qt.point(x, y) - // Must use parent.mapFoo, because the impl's position is relative to the parent Item - const mappedPoint = parent.mapFromItem(Window.window.contentItem, point) - return mappedPoint - } - - function fixPosition() { - // See QTBUG: https://bugreports.qt.io/browse/QTBUG-135833 - // TODO: should get the devicePixelRatio from the Window - x = mapFromScene(Math.ceil(mapToScene(0, 0).x * Panel.devicePixelRatio) / Panel.devicePixelRatio, 0).x - y = mapFromScene(0, Math.ceil(mapToScene(0, 0).y * Panel.devicePixelRatio) / Panel.devicePixelRatio).y - } - - Timer { - id: fixPositionTimer - interval: 100 - repeat: false - running: false - onTriggered: { - impl.fixPosition() - } - } } + Component.onCompleted: function () { impl.surfaceDestroyed.connect(root.surfaceDestroyed) }