Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 51 additions & 7 deletions panels/dock/multitaskview/package/multitaskview.qml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,58 @@ AppletDockItem {
sourceSize: Qt.size(Dock.MAX_DOCK_TASKMANAGER_ICON_SIZE, Dock.MAX_DOCK_TASKMANAGER_ICON_SIZE)
}

readonly property bool useCompositorTooltip: Qt.platform.pluginName === "wayland"

@18202781743 18202781743 Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

能否给dock定制一个PanelToolTip,覆盖掉dde-shell提供的默认的实现,
在这个控件里区分是x11还是treeland,在treeland情况下调用预览的show_tooltip接口,在x11下保持原来的,沿用PanelToolTipWindow去实现,
ToolTip相对位置,文本等,PanelToolTip已经存在已有的接口现,只有显示时不一样,
dde-shell不仅仅只有这几个tooltip,还有启动器等插件,

property bool compositorTooltipActive: false
function compositorTooltipApplet() {
if (!useCompositorTooltip)
return null

const applets = DS.appletList("org.deepin.ds.dock.taskmanager")
for (let i = 0; i < applets.length; ++i) {
if (applets[i].parent === Applet.parent)
return applets[i]
}
return null
}

function hideTooltip() {
if (toolTipShowTimer.running)
toolTipShowTimer.stop()

if (compositorTooltipActive) {
compositorTooltipActive = false
var applet = compositorTooltipApplet()
if (applet)
applet.hideItemPreview()
} else {
toolTip.close()
}
}

Timer {
id: toolTipShowTimer
interval: 50
onTriggered: {
var applet = compositorTooltipApplet()
if (applet) {
var itemPos = toggleworkspace.mapToItem(null, 0, 0)
var xOffset, yOffset, interval = 10
if (!useColumnLayout) {
xOffset = itemPos.x + toggleworkspace.width / 2
yOffset = (Panel.position == Dock.Bottom ? -interval : interval + Panel.dockSize)
} else {
xOffset = (Panel.position == Dock.Right ? -interval : interval + Panel.dockSize)
yOffset = itemPos.y + toggleworkspace.height / 2
}

compositorTooltipActive = false
if (applet.requestTooltip(toolTip.text, Panel.rootObject, xOffset, yOffset, Panel.position)) {
compositorTooltipActive = true
return
}
// 合成器协议不可用时回退到原生 tooltip,避免 tooltip 直接消失
}

var point = toggleworkspace.mapToItem(null, toggleworkspace.width / 2, toggleworkspace.height / 2)
toolTip.DockPanelPositioner.bounding = Qt.rect(point.x, point.y, toolTip.width, toolTip.height)
toolTip.open()
Expand All @@ -51,7 +99,7 @@ AppletDockItem {
onTapped: function (eventPoint, buttons) {
if (buttons === Qt.LeftButton) {
Applet.openWorkspace()
toolTip.close()
hideTooltip()
}
}
}
Expand All @@ -62,19 +110,15 @@ AppletDockItem {
gesturePolicy: TapHandler.WithinBounds
onTapped: function (eventPoint, buttons) {
Applet.openWorkspace()
toolTip.close()
hideTooltip()
}
}
HoverHandler {
onHoveredChanged: {
if (hovered) {
toolTipShowTimer.start()
} else {
if (toolTipShowTimer.running) {
toolTipShowTimer.stop()
}

toolTip.close()
hideTooltip()
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions panels/dock/taskmanager/abstractwindowmonitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ void AbstractWindowMonitor::requestUpdateWindowIconGeometry(const QModelIndex &i
{
}

bool AbstractWindowMonitor::requestTooltip(const QString &text, QWindow *relativePositionItem, int32_t previewXoffset, int32_t previewYoffset, uint32_t direction)
{
Q_UNUSED(text)
Q_UNUSED(relativePositionItem)
Q_UNUSED(previewXoffset)
Q_UNUSED(previewYoffset)
Q_UNUSED(direction)
return false;
}

void AbstractWindowMonitor::requestWindowsView(const QModelIndexList &indexes) const
{
qDebug() << indexes;
Expand Down
4 changes: 4 additions & 0 deletions panels/dock/taskmanager/abstractwindowmonitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class AbstractWindowMonitor : public QAbstractListModel, public AbstractTaskMana
virtual void
requestPreview(QAbstractItemModel *sourceModel, QWindow *relativePositionItem, int32_t previewXoffset, int32_t previewYoffset, uint32_t direction) = 0;

// 返回是否已交由合成器绘制,false 时调用方应回退到自身的 tooltip。
virtual bool
requestTooltip(const QString &text, QWindow *relativePositionItem, int32_t previewXoffset, int32_t previewYoffset, uint32_t direction);

void requestWindowsView(const QModelIndexList &indexes) const override;

virtual void presentWindows(QList<uint32_t> windowsId) = 0;
Expand Down
61 changes: 58 additions & 3 deletions panels/dock/taskmanager/package/AppItem.qml
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,9 @@ Item {
}
}

readonly property bool useCompositorTooltip: Qt.platform.pluginName === "wayland"
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
property bool compositorTooltipActive: false

Timer {
id: previewTimer
interval: 500
Expand All @@ -444,16 +447,34 @@ Item {
property int xOffset: 0
property int yOffset: 0
onTriggered: {
if (root.windows.length != 0 || Qt.platform.pluginName === "wayland") {
if (root.windows.length != 0) {
// 使用基于 modelIndex 的预览API,确保精确匹配
taskmanager.Applet.requestPreview(root.modelIndex, Panel.rootObject, xOffset, yOffset, Panel.position);
}
}
}

Timer {
id: tooltipTimer
interval: 50
running: false
repeat: false
property int xOffset: 0
property int yOffset: 0
onTriggered: {
var text = root.itemId === "dde-trash" ? root.name + "-" + taskmanager.Applet.getTrashTipText() : root.name
// 合成器协议不可用时回退到原生 tooltip,避免 tooltip 直接消失
if (taskmanager.Applet.requestTooltip(text, Panel.rootObject, xOffset, yOffset, Panel.position)) {
root.compositorTooltipActive = true
} else {
root.compositorTooltipActive = false
toolTipShowTimer.start()
}
}
}

function onEntered() {
if (windows.length === 0) {
if (windows.length === 0 && !useCompositorTooltip) {
toolTipShowTimer.start()
return
}
Expand All @@ -467,6 +488,16 @@ Item {
xOffset = (Panel.position == 1 ? -interval : interval + Panel.dockSize)
yOffset = itemPos.y + (root.height / 2)
}

if (windows.length === 0) {
// 无窗口应用:交给合成器绘制 tooltip,以便与窗口预览保持连续的过渡动画
tooltipTimer.xOffset = xOffset
tooltipTimer.yOffset = yOffset
tooltipTimer.start()
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
return
}

compositorTooltipActive = false
previewTimer.xOffset = xOffset
previewTimer.yOffset = yOffset
previewTimer.start()
Expand All @@ -481,8 +512,17 @@ Item {
previewTimer.stop()
}

if (tooltipTimer.running) {
tooltipTimer.stop()
}

if (windows.length === 0) {
toolTip.close()
if (useCompositorTooltip) {
compositorTooltipActive = false
taskmanager.Applet.hideItemPreview()
} else {
toolTip.close()
}
return
}
closeItemPreview()
Expand Down Expand Up @@ -537,6 +577,14 @@ Item {
root.Drag.imageSource = result.url;
})
}
// 按下时立即取消待显示的 tooltip,避免启动应用后 tooltip 才弹出
if (tooltipTimer.running) {
tooltipTimer.stop()
}
if (compositorTooltipActive) {
compositorTooltipActive = false
taskmanager.Applet.hideItemPreview()
}
toolTip.close()
closeItemPreview()
}
Expand Down Expand Up @@ -632,6 +680,13 @@ Item {
if (windows.length > 0 && toolTip.toolTipVisible) {
toolTip.close()
}
// 无窗口应用在悬停期间新开窗口时,从合成器 tooltip 切换到窗口预览
if (windows.length > 0 && compositorTooltipActive) {
compositorTooltipActive = false
previewTimer.xOffset = tooltipTimer.xOffset
previewTimer.yOffset = tooltipTimer.yOffset
previewTimer.start()
}
}

onIconGlobalPointChanged: {
Expand Down
10 changes: 10 additions & 0 deletions panels/dock/taskmanager/taskmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,16 @@ void TaskManager::requestPreview(const QModelIndex &index, QObject *relativePosi
m_windowMonitor->requestPreview(m_hoverPreviewModel, qobject_cast<QWindow *>(relativePositionItem), previewXoffset, previewYoffset, direction);
}

bool TaskManager::requestTooltip(const QString &text, QObject *relativePositionItem, int32_t previewXoffset, int32_t previewYoffset, uint32_t direction)
{
if (!m_windowMonitor) {
qCWarning(taskManagerLog) << "TaskManager::requestTooltip: m_windowMonitor is null";
return false;
}

return m_windowMonitor->requestTooltip(text, qobject_cast<QWindow *>(relativePositionItem), previewXoffset, previewYoffset, direction);
}

void TaskManager::requestWindowsView(const QModelIndexList &indexes) const
{
dataModel()->requestWindowsView(indexes);
Expand Down
2 changes: 2 additions & 0 deletions panels/dock/taskmanager/taskmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ class TaskManager : public DS_NAMESPACE::DContainment, public AbstractTaskManage
Q_INVOKABLE void requestUpdateWindowIconGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate = nullptr) const override;
Q_INVOKABLE void
requestPreview(const QModelIndex &index, QObject *relativePositionItem, int32_t previewXoffset, int32_t previewYoffset, uint32_t direction);
Q_INVOKABLE bool
requestTooltip(const QString &text, QObject *relativePositionItem, int32_t previewXoffset, int32_t previewYoffset, uint32_t direction);
Q_INVOKABLE void requestWindowsView(const QModelIndexList &indexes) const override;

Q_INVOKABLE QString desktopIdToAppId(const QString& desktopId);
Expand Down
104 changes: 68 additions & 36 deletions panels/dock/taskmanager/treelandwindowmonitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
#include "taskmanager.h"
#include "treelandwindow.h"

#include <QDebug>

Check warning on line 12 in panels/dock/taskmanager/treelandwindowmonitor.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDebug> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QPointer>

Check warning on line 13 in panels/dock/taskmanager/treelandwindowmonitor.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QPointer> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QIODevice>

Check warning on line 14 in panels/dock/taskmanager/treelandwindowmonitor.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QIODevice> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QVarLengthArray>

Check warning on line 15 in panels/dock/taskmanager/treelandwindowmonitor.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QVarLengthArray> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <QtWaylandClient/private/qwaylandwindow_p.h>

Expand Down Expand Up @@ -61,6 +62,12 @@
show(windowsId, previewXoffset, previewYoffset, direction);
}

void TreeLandDockPreviewContext::showTooltip(const QString &text, int32_t previewXoffset, int32_t previewYoffset, uint32_t direction)
{
m_isDockMouseAreaEnter = true;
show_tooltip(text, previewXoffset, previewYoffset, direction);
}

void TreeLandDockPreviewContext::hideWindowsPreview()
{
m_isDockMouseAreaEnter = false;
Expand Down Expand Up @@ -126,57 +133,82 @@
m_dockPreview->hideWindowsPreview();
}

void TreeLandWindowMonitor::ensureDockPreviewContext(QWindow *relativePositionItem)
{
if (!m_dockPreview.isNull())
return;

auto window = relativePositionItem;
if (!window) return;
auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(window->handle());
if (!waylandWindow) return;

auto context = m_foreignToplevelManager->get_dock_preview_context(waylandWindow->wlSurface());
m_dockPreview.reset(new TreeLandDockPreviewContext(context));
connect(window, &QWindow::visibleChanged, m_dockPreview.get(), [this]() {
m_dockPreview.reset();
});
connect(m_dockPreview.get(), &TreeLandDockPreviewContext::closed, this, [this]() {
// 当预览关闭时,发出信号清空过滤状态
emit previewShouldClear();
});
}

void TreeLandWindowMonitor::requestPreview(QAbstractItemModel *sourceModel,
QWindow *relativePositionItem,
int32_t previewXoffset,
int32_t previewYoffset,
uint32_t direction)
{
if (!m_foreignToplevelManager->isActive()) {
if (!m_foreignToplevelManager || !m_foreignToplevelManager->isActive()) {
return;
}

if (m_dockPreview.isNull()) {
auto window = relativePositionItem;
if (!window) return;
auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(window->handle());
if (!waylandWindow) return;

auto context = m_foreignToplevelManager->get_dock_preview_context(waylandWindow->wlSurface());
m_dockPreview.reset(new TreeLandDockPreviewContext(context));
connect(window, &QWindow::visibleChanged, m_dockPreview.get(), [this]() {
m_dockPreview.reset();
});
connect(m_dockPreview.get(), &TreeLandDockPreviewContext::closed, this, [this]() {
// 当预览关闭时,发出信号清空过滤状态
emit previewShouldClear();
});
if (!sourceModel || sourceModel->rowCount() == 0) {
qWarning() << "requestPreview called without any window";
return;
}

m_dockPreview->m_isDockMouseAreaEnter = true;
ensureDockPreviewContext(relativePositionItem);
if (m_dockPreview.isNull())
return;

if (sourceModel && sourceModel->rowCount() > 0) {
QVarLengthArray<uint32_t> array;
for (int i = 0; i < sourceModel->rowCount(); ++i) {
QModelIndex index = sourceModel->index(i, 0);
uint32_t winId = index.data(TaskManager::WinIdRole).toUInt();
if (winId != 0) {
array.append(winId);
}
QVarLengthArray<uint32_t> array;
for (int i = 0; i < sourceModel->rowCount(); ++i) {
QModelIndex index = sourceModel->index(i, 0);
uint32_t winId = index.data(TaskManager::WinIdRole).toUInt();
if (winId != 0) {
array.append(winId);
}
}

if (!array.isEmpty()) {
QByteArray byteArray;
int size = array.size() * sizeof(uint32_t);
byteArray.resize(size);
memcpy(byteArray.data(), array.constData(), size);
m_dockPreview->showWindowsPreview(byteArray, previewXoffset, previewYoffset, direction);
} else {
m_dockPreview->show_tooltip("???", previewXoffset, previewYoffset, direction);
}
} else {
m_dockPreview->show_tooltip("???", previewXoffset, previewYoffset, direction);
if (array.isEmpty()) {
qWarning() << "requestPreview called without any valid window id";
return;
}

QByteArray byteArray;
int size = array.size() * sizeof(uint32_t);
byteArray.resize(size);
memcpy(byteArray.data(), array.constData(), size);
m_dockPreview->showWindowsPreview(byteArray, previewXoffset, previewYoffset, direction);
}

bool TreeLandWindowMonitor::requestTooltip(const QString &text,
QWindow *relativePositionItem,
int32_t previewXoffset,
int32_t previewYoffset,
uint32_t direction)
{
if (!m_foreignToplevelManager || !m_foreignToplevelManager->isActive())
return false;

ensureDockPreviewContext(relativePositionItem);
if (m_dockPreview.isNull())
return false;

m_dockPreview->showTooltip(text, previewXoffset, previewYoffset, direction);
return true;
}

void TreeLandWindowMonitor::requestUpdateWindowIconGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate) const
Expand Down
Loading
Loading