Skip to content

fix: resolve occasional crash in TreeLandWindow destructor under treeland#1583

Merged
18202781743 merged 1 commit intolinuxdeepin:masterfrom
18202781743:treeland-adapter
Apr 30, 2026
Merged

fix: resolve occasional crash in TreeLandWindow destructor under treeland#1583
18202781743 merged 1 commit intolinuxdeepin:masterfrom
18202781743:treeland-adapter

Conversation

@18202781743
Copy link
Copy Markdown
Contributor

@18202781743 18202781743 commented Apr 30, 2026

Remove the emission of stateChanged signal in TreeLandWindow destructor
to prevent accessing partially destroyed objects. Refactor fullscreen
state update logic into a dedicated method called from multiple
locations (clear, handle remove) instead of using lambda connections.
Added updateFullscreenState call in clear() to maintain correct state
when all windows are removed.

Log: Fixed crash when TreeLandWindow is destroyed under treeland

Influence:

  1. Test window management operations under treeland (open/close/
    maximize/minimize)
  2. Verify fullscreen state detection works correctly
  3. Test rapid window creation and destruction
  4. Test dock visibility changes during fullscreen transitions

fix: 修复treeland下TreeLandWindow析构时偶发崩溃

移除TreeLandWindow析构函数中的stateChanged信号发射,避免访问已部分析构的
对象。将全屏状态更新逻辑重构为专用方法,在clear()和handle remove等多个位
置调用,替代lambda连接。在clear()中添加updateFullscreenState调用,确保移
除所有窗口时保持正确状态。

Log: 修复treeland下TreeLandWindow析构时的崩溃问题

Influence:

  1. 在treeland环境下测试窗口管理操作(打开/关闭/最大化/最小化)
  2. 验证全屏状态检测功能正常工作
  3. 测试窗口的快速创建和销毁场景
  4. 测试全屏切换过程中dock可见性变化

Summary by Sourcery

Resolve treeland window destruction crash by decoupling fullscreen state tracking from window lifetime and centralizing fullscreen updates in the monitor.

Bug Fixes:

  • Prevent occasional crashes when TreeLandWindow objects are destroyed under treeland by avoiding stateChanged emissions during destruction.

Enhancements:

  • Centralize fullscreen state detection into TreeLandWindowMonitor::updateFullscreenState and reuse it from window add/remove and clear paths to keep dock fullscreen state in sync.

treeland

Remove the emission of stateChanged signal in TreeLandWindow destructor
to prevent accessing partially destroyed objects. Refactor fullscreen
state update logic into a dedicated method called from multiple
locations (clear, handle remove) instead of using lambda connections.
Added updateFullscreenState call in clear() to maintain correct state
when all windows are removed.

Log: Fixed crash when TreeLandWindow is destroyed under treeland

Influence:
1. Test window management operations under treeland (open/close/
maximize/minimize)
2. Verify fullscreen state detection works correctly
3. Test rapid window creation and destruction
4. Test dock visibility changes during fullscreen transitions

fix: 修复treeland下TreeLandWindow析构时偶发崩溃

移除TreeLandWindow析构函数中的stateChanged信号发射,避免访问已部分析构的
对象。将全屏状态更新逻辑重构为专用方法,在clear()和handle remove等多个位
置调用,替代lambda连接。在clear()中添加updateFullscreenState调用,确保移
除所有窗口时保持正确状态。

Log: 修复treeland下TreeLandWindow析构时的崩溃问题

Influence:
1. 在treeland环境下测试窗口管理操作(打开/关闭/最大化/最小化)
2. 验证全屏状态检测功能正常工作
3. 测试窗口的快速创建和销毁场景
4. 测试全屏切换过程中dock可见性变化
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 30, 2026

Reviewer's Guide

Refactors fullscreen state tracking in TreeLandWindowMonitor to use a shared helper method and avoid emitting stateChanged from the TreeLandWindow destructor, preventing crashes caused by accessing partially destroyed objects, while also ensuring fullscreen state is recalculated when windows are cleared or removed.

Updated class diagram for TreeLandWindow and TreeLandWindowMonitor fullscreen logic

classDiagram
    class AbstractWindow {
        <<interface>>
        +bool isFullscreen()
        +signal stateChanged()
    }

    class TreeLandWindow {
        +TreeLandWindow(uint32_t id, QObject *parent)
        +~TreeLandWindow()
        +uint32_t id()
        +signal stateChanged()
    }

    class TreeLandWindowMonitor {
        -QHash<ulong, QSharedPointer<TreeLandWindow>> m_windows
        -QSharedPointer<AbstractWindow> m_dockPreview
        -bool m_fullscreenState
        +void clear()
        +QPointer<AbstractWindow> getWindowByWindowId(ulong windowId)
        +slot handleForeignToplevelHandleAdded()
        +slot handleForeignToplevelHandleRemoved()
        +slot updateFullscreenState()
        +signal windowFullscreenChanged(bool fullscreen)
    }

    AbstractWindow <|-- TreeLandWindow
    TreeLandWindowMonitor "1" o--> "*" TreeLandWindow
    TreeLandWindowMonitor ..> AbstractWindow : uses
    TreeLandWindowMonitor ..> TreeLandWindow : manages
    TreeLandWindowMonitor ..> TreeLandWindow : connects stateChanged to updateFullscreenState
    TreeLandWindowMonitor ..> DockPanel

    class DockPanel {
        +slot onWindowFullscreenChanged(bool fullscreen)
    }

    DockPanel ..> TreeLandWindowMonitor : listens windowFullscreenChanged
Loading

File-Level Changes

Change Details Files
Centralized fullscreen state tracking in TreeLandWindowMonitor and invoked it on relevant window lifecycle events.
  • Added updateFullscreenState() method to recompute m_fullscreenState by scanning existing windows and emitting windowFullscreenChanged only on state transitions.
  • Replaced the inline lambda connected to AbstractWindow::stateChanged with a direct connection to updateFullscreenState using Qt::UniqueConnection.
  • Called updateFullscreenState() in clear() after clearing m_windows and resetting m_dockPreview to keep fullscreen state consistent when all windows are removed.
  • Invoked updateFullscreenState() in handleForeignToplevelHandleRemoved() after removing a window to recalculate fullscreen state when a toplevel is destroyed or goes away.
panels/dock/taskmanager/treelandwindowmonitor.cpp
panels/dock/taskmanager/treelandwindowmonitor.h
Removed unsafe stateChanged emission from TreeLandWindow destructor to avoid crashes during object teardown.
  • Deleted emit stateChanged() call from TreeLandWindow::~TreeLandWindow(), relying instead on monitor-side state recomputation when windows are removed.
panels/dock/taskmanager/treelandwindow.cpp
Updated SPDX copyright headers to include 2026.
  • Extended SPDX-FileCopyrightText year range from 2023 to 2023 - 2026 in affected source and header files.
panels/dock/taskmanager/treelandwindowmonitor.cpp
panels/dock/taskmanager/treelandwindow.cpp
panels/dock/taskmanager/treelandwindowmonitor.h

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@18202781743
Copy link
Copy Markdown
Contributor Author

Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007f99c6dbe368 in (anonymous namespace)::QLoggingCategoryMacroHolder<(QtMsgType)0>::init (this=0x7ffd1be54050, cat=...) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qloggingcategory.h:77
77 control = cat.isDebugEnabled();
[Current thread is 1 (Thread 0x7f99d6ef9cc0 (LWP 451540))]
(gdb) bt
#0 0x00007f99c6dbe368 in (anonymous namespace)::QLoggingCategoryMacroHolder<(QtMsgType)0>::init (this=0x7ffd1be54050, cat=...) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qloggingcategory.h:77
#1 0x00007f99c6dbe308 in (anonymous namespace)::QLoggingCategoryMacroHolder<(QtMsgType)0>::QLoggingCategoryMacroHolder (this=0x7ffd1be54050, cat=...)
at /usr/include/x86_64-linux-gnu/qt6/QtCore/qloggingcategory.h:68
#2 0x00007f99c6dbd94d in dock::TreeLandWindow::~TreeLandWindow (this=0x5650fe82fae0, __in_chrg=) at /home/deepin/repo/dde-shell/panels/dock/taskmanager/treelandwindow.cpp:122
#3 0x00007f99c6dbda10 in dock::TreeLandWindow::~TreeLandWindow (this=0x5650fe82fae0, __in_chrg=) at /home/deepin/repo/dde-shell/panels/dock/taskmanager/treelandwindow.cpp:124
#4 0x00007f99c6dc4b43 in QtSharedPointer::CustomDeleter<dock::TreeLandWindow, QtSharedPointer::NormalDeleter>::execute (this=0x5650ff2cfa20)
at /usr/include/x86_64-linux-gnu/qt6/QtCore/qsharedpointer_impl.h:161
#5 0x00007f99c6dc3fcf in QtSharedPointer::ExternalRefCountWithCustomDeleter<dock::TreeLandWindow, QtSharedPointer::NormalDeleter>::deleter (self=0x5650ff2cfa10)
at /usr/include/x86_64-linux-gnu/qt6/QtCore/qsharedpointer_impl.h:179
#6 0x00007f99c6d1080b in QtSharedPointer::ExternalRefCountData::destroy (this=0x5650ff2cfa10) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qsharedpointer_impl.h:115
#7 0x00007f99c6d2f365 in QSharedPointerdock::TreeLandWindow::deref (dd=0x5650ff2cfa10) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qsharedpointer_impl.h:476
#8 0x00007f99c6d2f13e in QSharedPointerdock::TreeLandWindow::deref (this=0x7ffd1be541d0) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qsharedpointer_impl.h:471
#9 0x00007f99c6d2eff0 in QSharedPointerdock::TreeLandWindow::~QSharedPointer (this=0x7ffd1be541d0, __in_chrg=) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qsharedpointer_impl.h:284
#10 0x00007f99c6dc192e in operator() (__closure=0x5650ff2b7a10) at /home/deepin/repo/dde-shell/panels/dock/taskmanager/treelandwindowmonitor.cpp:211
#11 0x00007f99c6dc2ad9 in operator() (_closure=0x7ffd1be54260) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:141
#12 0x00007f99c6dc2bd2 in QtPrivate::FunctorCallBase::call_internal<void, QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, dock::TreeLandWindowMonitor::handleForeignToplevelHandleAdded()::<lambda()> >::call(dock::TreeLandWindowMonitor::handleForeignToplevelHandleAdded()::<lambda()>&, void**)::<lambda()> >(void **, struct {...} &&) (args=0x7ffd1be54388, fn=...)
at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:65
#13 0x00007f99c6dc2b0f in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, dock::TreeLandWindowMonitor::handleForeignToplevelHandleAdded()::<lambda()> >::call(struct {...} &, void **)
(f=..., arg=0x7ffd1be54388) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:140
#14 0x00007f99c6dc296b in QtPrivate::FunctorCallable<dock::TreeLandWindowMonitor::handleForeignToplevelHandleAdded()::<lambda()> >::call<QtPrivate::List<>, void>(struct {...} &, void *, void **)
(f=..., arg=0x7ffd1be54388) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:362
--Type for more, q to quit, c to continue without paging--
#15 0x00007f99c6dc2842 in QtPrivate::QCallableObject<dock::TreeLandWindowMonitor::handleForeignToplevelHandleAdded()::<lambda()>, QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase *, QObject *, void **, bool *) (which=1, this
=0x5650ff2b7a00, r=0x5650fd6a68a0, a=0x7ffd1be54388, ret=0x0) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:572
#16 0x00007f99dc44d46c in QtPrivate::QSlotObjectBase::call (a=0x7ffd1be54388, r=0x5650fd6a68a0, this=0x5650ff2b7a00, this=, r=, a=)
at ./src/corelib/kernel/qobjectdefs_impl.h:486
#17 doActivate (sender=0x5650fe82fae0, signal_index=9, argv=0x7ffd1be54388) at ./src/corelib/kernel/qobject.cpp:4120
#18 0x00007f99c6d08eaf in dock::AbstractWindow::stateChanged (this=0x5650fe82fae0) at /home/deepin/repo/dde-shell/build/panels/dock/taskmanager/dock-taskmanager_autogen/EWIEGA46WW/moc_abstractwindow.cpp:307
#19 0x00007f99c6dbd9d8 in dock::TreeLandWindow::~TreeLandWindow (this=0x5650fe82fae0, __in_chrg=) at /home/deepin/repo/dde-shell/panels/dock/taskmanager/treelandwindow.cpp:123
#20 0x00007f99c6dbda10 in dock::TreeLandWindow::~TreeLandWindow (this=0x5650fe82fae0, __in_chrg=) at /home/deepin/repo/dde-shell/panels/dock/taskmanager/treelandwindow.cpp:124

@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

这段代码主要涉及 Wayland 窗口管理相关的逻辑,特别是在处理全屏状态变化时的重构。以下是对这段 diff 的详细审查意见:

1. 语法逻辑

优点:

  • 逻辑重构:将全屏状态检查的逻辑提取为独立的 updateFullscreenState 成员函数,这是一个很好的改进。它遵循了 DRY(Don't Repeat Yourself)原则,使得代码更易于维护和阅读。
  • 连接优化:使用 connect(window.data(), ..., this, &TreeLandWindowMonitor::updateFullscreenState, Qt::UniqueConnection) 替代了原来的 Lambda 表达式。这不仅减少了代码量,还利用 Qt::UniqueConnection 防止了重复连接,逻辑更加严谨。
  • 资源清理:在 TreeLandWindowMonitor::clear()handleForeignToplevelHandleRemoved() 中显式调用 updateFullscreenState(),确保在窗口列表发生变化时,全屏状态能够被正确重置和更新,填补了之前可能存在的逻辑漏洞。

问题与建议:

  • 析构函数中的信号移除:在 treelandwindow.cppTreeLandWindow::~TreeLandWindow() 中移除了 emit stateChanged()。这是一个非常关键的改动。
    • 分析:通常,在对象析构时发出状态变化信号是危险的,因为接收信号的槽函数可能会尝试访问即将销毁的对象(尽管这里使用了 QPointer 等智能指针,但依然存在风险)。移除它是为了防止在对象销毁过程中触发不必要的副作用。
    • 建议:确认移除此信号后,TreeLandWindowMonitor 中的逻辑依然正确。目前的 diff 显示在 handleForeignToplevelHandleRemoved 中会调用 updateFullscreenState,这能弥补移除析构函数信号后可能遗漏的状态更新。这个改动是合理的。

2. 代码质量

优点:

  • 可读性提升:通过提取 updateFullscreenState 函数,handleForeignToplevelHandleAdded 变得更加简洁,主流程更加清晰。
  • 版权年份更新:将版权年份从 2023 更新为 2023 - 2026,符合开源项目维护规范。

建议:

  • 空指针检查:在 updateFullscreenState 中,使用了 std::as_const(m_windows) 遍历容器,并检查了 if (window && ...)。这是很好的防御性编程习惯。不过,由于 m_windows 存储的是 QSharedPointer,通常情况下容器内的指针不应为空(除非手动插入了 nullptr)。如果逻辑上保证容器内非空,这个检查可以略微简化,但保留它也无妨,增加了健壮性。

3. 代码性能

分析:

  • 遍历开销updateFullscreenState 函数在每次窗口状态改变、窗口添加、窗口移除或清空时都会被调用。它遍历 m_windows 哈希表。
    • 影响:如果系统中的窗口数量非常多(例如几十个),频繁的遍历可能会带来微小的 CPU 开销。但对于任务栏/坞站这种场景,窗口数量通常在个位数或两位数,这种 O(N) 的遍历开销完全可以忽略不计。
    • 优化建议:目前的实现已经足够高效。如果未来需要极致优化,可以考虑维护一个单独的 m_fullscreenWindowCount 计数器,在窗口状态变化时增减计数,从而将检查复杂度降为 O(1)。但这会增加代码复杂度(需要处理各种边界情况),目前的 O(N) 遍历方案在可读性和性能之间取得了很好的平衡。

4. 代码安全

优点:

  • 防止悬空指针:使用 QSharedPointer 管理 TreeLandWindow 生命周期,配合 QPointer(如果 AbstractWindow 继承自 QObject 且使用 QPointer 传递),能有效防止内存泄漏和悬空指针访问。
  • 使用 std::as_const:在 updateFullscreenState 中使用 std::as_const(m_windows) 进行遍历,防止了隐式共享(COW)带来的不必要的 detach(深拷贝),这是一个很好的 C++ Qt 编程实践。
  • 移除析构信号:如前所述,移除析构函数中的 emit stateChanged() 避免了在对象销毁阶段触发信号处理,防止了潜在的"在已销毁对象上操作"或"重入"导致的安全隐患。

潜在风险点:

  • Qt::UniqueConnection 的使用
    • handleForeignToplevelHandleAdded 中使用了 Qt::UniqueConnection。这确保了如果同一个信号被多次连接到同一个槽,只会调用一次。
    • 注意Qt::UniqueConnection 在使用函数指针(如 &TreeLandWindowMonitor::updateFullscreenState)时工作正常。如果将来改回 Lambda 表达式,Qt::UniqueConnection 可能无法按预期工作(因为 Lambda 每次都是不同的对象)。目前的用法是安全的。

总结

这是一次高质量的重构。主要改进点在于:

  1. 消除了代码重复:提取了 updateFullscreenState
  2. 增强了健壮性:在窗口移除和清空时显式更新状态,并移除了析构函数中不安全的信号发射。
  3. 提升了连接安全性:使用了 Qt::UniqueConnection

最终建议:
代码逻辑正确,风格良好,无明显安全漏洞。可以合并。

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • In updateFullscreenState(), iterate with const auto &window (or similar) instead of copying each QSharedPointer to avoid unnecessary reference count churn.
  • Given updateFullscreenState() is now called from multiple places, consider documenting in the header (e.g., brief comment) that it recalculates and emits fullscreen changes based on m_windows, so future callers know its side effects.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `updateFullscreenState()`, iterate with `const auto &window` (or similar) instead of copying each `QSharedPointer` to avoid unnecessary reference count churn.
- Given `updateFullscreenState()` is now called from multiple places, consider documenting in the header (e.g., brief comment) that it recalculates and emits fullscreen changes based on `m_windows`, so future callers know its side effects.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, wjyrich

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@18202781743 18202781743 merged commit 9d8b608 into linuxdeepin:master Apr 30, 2026
10 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants