From 67b5f1ac3588402bc664bcca5ff4f468b32b1fda Mon Sep 17 00:00:00 2001 From: Wu JiangYu Date: Wed, 26 Aug 2026 13:27:30 +0800 Subject: [PATCH] fix: add delay for x11 window preview to prevent accidental shows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Add a 300ms delay timer before showing X11 window previews 2. Store the pending preview window ID and only trigger preview if mouse remains on the item 3. Cancel pending previews on hover leave, mouse click, and container hide events 4. Prevent flickering when users quickly move across taskbar items Log: X11窗口预view display now has a 300ms delay to reduce accidental previews Influence: 1. Hover over a taskbar item and verify preview appears after ~300ms 2. Quickly move across multiple taskbar items and verify no preview flickering 3. Hover and move away before the delay expires, verify preview does not appear 4. Click a taskbar item while preview is pending, verify it is cancelled 5. Hide the preview container while a preview is pending, verify timers are cleaned up 6. Verify preview behavior in both compositing and non-compositing environments fix: 为 X11 窗口预览添加延迟显示功能 1. 添加300ms的延迟定时器,用于X11窗口预览显示 2. 记录待预览的窗口ID,仅当鼠标仍停留在项目上时才触发预览 3. 在鼠标悬停离开、鼠标点击和容器隐藏事件时取消待处理的预览 4. 防止用户快速滑动任务栏项目时出现预览闪烁 Log: X11窗口预览新增300ms延迟,减少误触发现象 Influence: 1. 悬停在任务栏项目上,验证约300ms后显示预览 2. 快速滑动多个任务栏项目,验证无预览闪烁 3. 在延迟时间内移开鼠标,验证预览不显示 4. 在预览等待期间点击任务栏项目,验证取消操作 5. 预览等待期间隐藏容器,验证定时器正确清理 6. 在非合成和合成环境下验证预览行为 PMS: TASK-394749 --- panels/dock/taskmanager/x11preview.cpp | 27 +++++++++++++++++++++++--- panels/dock/taskmanager/x11preview.h | 4 +++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/panels/dock/taskmanager/x11preview.cpp b/panels/dock/taskmanager/x11preview.cpp index 6513ed377..39df9c463 100644 --- a/panels/dock/taskmanager/x11preview.cpp +++ b/panels/dock/taskmanager/x11preview.cpp @@ -50,6 +50,7 @@ Q_LOGGING_CATEGORY(x11WindowPreview, "org.deepin.dde.shell.dock.taskmanager.x11W #define PREVIEW_CONTAINER_MARGIN 10 #define PREVIEW_HOVER_BORDER 4 #define PREVIEW_MINI_WIDTH 140 +#define PREVIEW_WINDOW_DELAY 300 #define PREVIEW_HOVER_BORDER_COLOR QColor(0, 0, 0, 255 * 0.2) #define PREVIEW_HOVER_BORDER_COLOR_DARK_MODE QColor(255, 255, 255, 255 * 0.3) #define PREVIEW_BACKGROUND_COLOR QColor(0, 0, 0, 255 * 0.05) @@ -378,12 +379,24 @@ X11WindowPreviewContainer::X11WindowPreviewContainer(X11WindowMonitor *monitor, , m_monitor(monitor) , m_sourceModel(nullptr) , m_titleWidget(new QWidget()) + , m_previewDelayTimer(nullptr) + , m_pendingPreviewWinId(0) , m_direction(0) { m_hideTimer = new QTimer(this); m_hideTimer->setSingleShot(true); m_hideTimer->setInterval(500); + m_previewDelayTimer = new QTimer(this); + m_previewDelayTimer->setSingleShot(true); + m_previewDelayTimer->setInterval(PREVIEW_WINDOW_DELAY); + connect(m_previewDelayTimer, &QTimer::timeout, this, [this]() { + if (m_pendingPreviewWinId == 0 || m_monitor.isNull()) + return; + if (WM_HELPER->hasComposite()) + m_monitor->previewWindow(m_pendingPreviewWinId); + }); + setWindowFlags(Qt::ToolTip | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus | Qt::FramelessWindowHint); setMouseTracking(true); initUI(); @@ -415,9 +428,9 @@ X11WindowPreviewContainer::X11WindowPreviewContainer(X11WindowMonitor *monitor, connect(m_view, &QListView::entered, this, [this](const QModelIndex &enter) { m_closeAllButton->setVisible(false); - if (WM_HELPER->hasComposite()) { - m_monitor->previewWindow(enter.data(TaskManager::WinIdRole).toInt()); - } + // 延迟预览:记录待预览窗口并重启定时器,300ms 后仍停留才显示窗口 + m_pendingPreviewWinId = enter.data(TaskManager::WinIdRole).toUInt(); + m_previewDelayTimer->start(); // 获取图标,优先使用窗口图标,如果为空则使用应用图标 QVariant iconData = enter.data(TaskManager::WinIconRole); @@ -559,6 +572,9 @@ void X11WindowPreviewContainer::showEvent(QShowEvent *event) void X11WindowPreviewContainer::hideEvent(QHideEvent*) { + m_previewDelayTimer->stop(); + m_pendingPreviewWinId = 0; + // 只通知监视器清空预览状态,让 TaskManager 统一管理模型清理 // 不要在这里断开模型连接,因为 clearPreviewState 信号会触发 TaskManager 的 clearFilter // QPointer 会自动处理对象销毁的情况 @@ -766,6 +782,9 @@ bool X11WindowPreviewContainer::eventFilter(QObject *watched, QEvent *event) switch (event->type()) { case QEvent::HoverLeave: { + // 取消尚未触发的延迟预览 + m_previewDelayTimer->stop(); + m_pendingPreviewWinId = 0; if (WM_HELPER->hasComposite()) { m_monitor->cancelPreviewWindow(); } @@ -781,6 +800,8 @@ bool X11WindowPreviewContainer::eventFilter(QObject *watched, QEvent *event) if (mouseEvent->button() != Qt::LeftButton) return false; // cancel preview b4 active window + m_previewDelayTimer->stop(); + m_pendingPreviewWinId = 0; if (WM_HELPER->hasComposite()) m_monitor->cancelPreviewWindow(); diff --git a/panels/dock/taskmanager/x11preview.h b/panels/dock/taskmanager/x11preview.h index 334078ff5..19162bce7 100644 --- a/panels/dock/taskmanager/x11preview.h +++ b/panels/dock/taskmanager/x11preview.h @@ -1,4 +1,4 @@ -// 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 @@ -106,6 +106,8 @@ private Q_SLOTS: DIconButton* m_closeAllButton; QTimer* m_hideTimer; + QTimer* m_previewDelayTimer; + uint32_t m_pendingPreviewWinId; int32_t m_previewXoffset; int32_t m_previewYoffset;