Skip to content

fix: prevent crash when treeland restarts in taskbar#1620

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
18202781743:master
Jun 5, 2026
Merged

fix: prevent crash when treeland restarts in taskbar#1620
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
18202781743:master

Conversation

@18202781743

@18202781743 18202781743 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

The crash occurs because when treeland restarts, the clear() method in
TreeLandWindowMonitor clears internal window lists but fails to reset
the tracked windows model. When treeland restart triggers a cleanup
followed by re-initialization, the model still holds stale references
to windows that have been destroyed, leading to a use-after-free crash
when the model attempts to access the window data during view updates.
Added clearTrackedWindows() method to properly clear all tracked windows
from the model using beginResetModel/endResetModel, and called it at
the start of clear() in both TreeLandWindowMonitor and X11WindowMonitor
to ensure the model is reset before internal lists are cleared. This
ensures the model and view are properly synchronized, preventing access
to destroyed window objects.

Log: fix treeland restart crash

Influence:

  1. Test taskbar behavior when treeland restarts unexpectedly
  2. Verify taskbar shows correct windows after treeland restart
  3. Test taskbar with no windows open during treeland restart
  4. Verify no crash when multiple rapid treeland restarts occur
  5. Test X11 window monitor clear function for regressions
  6. Verify taskbar preview windows still work correctly after restart

fix: 修复任务栏在treeland重启时崩溃的问题

当treeland重启时,TreeLandWindowMonitor中的clear()方法清除了内部窗口列
表,但未能重置跟踪窗口的模型。treeland重启触发清理后重新初始化时,模型
仍然持有已被销毁窗口的陈旧引用,导致视图更新时访问已释放的窗口对象引发崩
溃。新增clearTrackedWindows()方法,通过beginResetModel/endResetModel正确
清除模型中的所有跟踪窗口,并在TreeLandWindowMonitor和X11WindowMonitor的
clear()方法开始时调用该方法,确保在清除内部列表之前重置模型。这保证了模
型和视图同步一致,防止访问已销毁的窗口对象。

Log: 修复treeland重启崩溃问题

Influence:

  1. 测试treeland异常重启时任务栏的行为
  2. 验证treeland重启后任务栏显示正确的窗口
  3. 测试treeland重启时没有打开任何窗口的情况
  4. 验证多次快速重启treeland不会导致崩溃
  5. 测试X11窗口监视器的清除功能是否有回归问题
  6. 验证重启后任务栏预览窗口仍然正常工作

Summary by Sourcery

Prevent taskbar crashes when window monitors are cleared by resetting the tracked window model before internal window lists are cleared.

Bug Fixes:

  • Fix use-after-free crash when TreeLand restarts by resetting tracked windows in the taskbar window monitor model before clearing internal state.
  • Ensure X11 window monitor also resets its tracked windows model on clear to avoid stale references in the taskbar.

Enhancements:

  • Introduce a reusable clearTrackedWindows() helper in AbstractWindowMonitor to atomically reset the tracked windows model.

@sourcery-ai

sourcery-ai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Introduces a model-safe way to clear tracked windows in the taskbar window monitors and wires it into both TreeLand and X11 clear() flows to prevent use-after-free crashes during compositor restarts.

Sequence diagram for clear() with model-safe window reset

sequenceDiagram
    participant Monitor as TreeLandWindowMonitor
    participant Model as AbstractWindowMonitor
    participant View as TaskbarView

    View->>Monitor: clear()
    activate Monitor
    Monitor->>Model: clearTrackedWindows()
    activate Model
    Model->>Model: beginResetModel()
    Model->>Model: m_trackedWindows.clear()
    Model->>Model: endResetModel()
    deactivate Model
    Monitor->>Monitor: m_windows.clear()
    deactivate Monitor
    View->>Model: dataChanged / rowCount
    Model-->>View: updated window list (empty)
Loading

File-Level Changes

Change Details Files
Add a model-reset-aware API for clearing tracked windows in the abstract window monitor and use it from concrete monitors' clear() paths.
  • Add clearTrackedWindows() to AbstractWindowMonitor that wraps clearing m_trackedWindows with beginResetModel/endResetModel and early-exits if there are no tracked windows.
  • Expose clearTrackedWindows() in AbstractWindowMonitor's public interface.
  • Invoke clearTrackedWindows() at the start of TreeLandWindowMonitor::clear() before clearing internal window lists and resetting preview state.
  • Invoke clearTrackedWindows() at the start of X11WindowMonitor::clear() before clearing internal window lists and resetting preview state.
panels/dock/taskmanager/abstractwindowmonitor.cpp
panels/dock/taskmanager/abstractwindowmonitor.h
panels/dock/taskmanager/treelandwindowmonitor.cpp
panels/dock/taskmanager/x11windowmonitor.cpp

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
  #0  0x00007f8dba452759 in dock::AbstractWindowMonitor::data (this=0x55aa9d3b9eb0, index=..., role=257) at /home/deepin/dde-shell/panels/dock/taskmanager/abstractwindowmonitor.cpp:91                            
  #1  0x00007f8dd005244e in QSortFilterProxyModel::data (this=<optimized out>, index=<optimized out>, role=257) at ./src/corelib/itemmodels/qsortfilterproxymodel.cpp:2216                                         
  #2  0x00007f8dba465405 in RoleCombineModel::data (this=0x55aa9d4662a0, index=..., role=257) at /home/deepin/dde-shell/panels/dock/taskmanager/rolecombinemodel.cpp:367                                           
  #3  0x00007f8dba4883f4 in dock::DockCombineModel::data (this=0x55aa9d4662a0, index=..., role=257) at /home/deepin/dde-shell/panels/dock/taskmanager/dockcombinemodel.cpp:80                                      
  #4  0x00007f8dd0027f61 in QAbstractItemModel::match (this=<optimized out>, start=..., role=257, value=..., hits=1, flags=...) at ./src/corelib/itemmodels/qabstractitemmodel.cpp:2540                            
  #5  0x00007f8dba4a2e59 in dock::TaskManager::handleWindowAdded (this=0x55aa9d3bfb80, window=...) at /home/deepin/dde-shell/panels/dock/taskmanager/taskmanager.cpp:333                                           
  #6  0x00007f8dba4ace23 in QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QPointer<dock::AbstractWindow> >, void, void (dock::TaskManager::*)(QPointer<dock::AbstractWindow>)>::call(void      
  (dock::TaskManager::*)(QPointer<dock::AbstractWindow>), dock::TaskManager*, void**)::{lambda()#1}::operator()() const (__closure=0x7ffc3c8d6970) at                                                              
  /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:152                                                                                                                                                  
  #7  0x00007f8dba4add05 in QtPrivate::FunctorCallBase::call_internal<void, QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QPointer<dock::AbstractWindow> >, void, void                         
  (dock::TaskManager::*)(QPointer<dock::AbstractWindow>)>::call(void (dock::TaskManager::*)(QPointer<dock::AbstractWindow>), dock::TaskManager*, void**)::{lambda()#1}>(void**,                                    
  QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QPointer<dock::AbstractWindow> >, void, void (dock::TaskManager::*)(QPointer<dock::AbstractWindow>)>::call(void                                
  (dock::TaskManager::*)(QPointer<dock::AbstractWindow>), dock::TaskManager*, void**)::{lambda()#1}&&) (args=0x7ffc3c8d6b20, fn=...) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:65             
                                                                                                                                                                                                                   
  #8  0x00007f8dba4aceb2 in QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QPointer<dock::AbstractWindow> >, void, void (dock::TaskManager::*)(QPointer<dock::AbstractWindow>)>::call           
      (f=(void (dock::TaskManager::*)(dock::TaskManager * const, QPointer<dock::AbstractWindow>)) 0x7f8dba4a2bfe <dock::TaskManager::handleWindowAdded(QPointer<dock::AbstractWindow>)>, o=0x55aa9d3bfb80,         
  arg=0x7ffc3c8d6b20) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:151                                                                                                                           
  #9  0x00007f8dba4ab84c in QtPrivate::FunctionPointer<void (dock::TaskManager::*)(QPointer<dock::AbstractWindow>)>::call<QtPrivate::List<QPointer<dock::AbstractWindow> >, void>                                  
      (f=(void (dock::TaskManager::*)(dock::TaskManager * const, QPointer<dock::AbstractWindow>)) 0x7f8dba4a2bfe <dock::TaskManager::handleWindowAdded(QPointer<dock::AbstractWindow>)>, o=0x55aa9d3bfb80,         
  arg=0x7ffc3c8d6b20) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:199                                                                                                                           
  #10 0x00007f8dba4aa7ad in QtPrivate::QCallableObject<void (dock::TaskManager::*)(QPointer<dock::AbstractWindow>), QtPrivate::List<QPointer<dock::AbstractWindow> >, void>::impl                                  
      (which=1, this_=0x55aa9d35aa20, r=0x55aa9d3bfb80, a=0x7ffc3c8d6b20, ret=0x0) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:570                                                              
  --Type <RET> for more, q to quit, c to continue without paging--                                                                                                                                                 
  #11 0x00007f8dcfec446c in QtPrivate::QSlotObjectBase::call (a=0x7ffc3c8d6b20, r=0x55aa9d3bfb80, this=0x55aa9d35aa20, this=<optimized out>, r=<optimized out>, a=<optimized out>)                                 
      at ./src/corelib/kernel/qobjectdefs_impl.h:486                                                                                                                                                               
  #12 doActivate<false> (sender=0x55aa9d3b9eb0, signal_index=26, argv=0x7ffc3c8d6b20) at ./src/corelib/kernel/qobject.cpp:4120                                                                                     
  #13 0x00007f8dba3fc743 in dock::AbstractWindowMonitor::windowAdded (this=0x55aa9d3b9eb0, _t1=...)                                                                                                                
      at /home/deepin/dde-shell/build/panels/dock/taskmanager/dock-taskmanager_autogen/EWIEGA46WW/moc_abstractwindowmonitor.cpp:196                                                                                
  #14 0x00007f8dba4b53f5 in dock::TreeLandWindowMonitor::handleForeignToplevelHandleAdded (this=0x55aa9d3b9eb0) at /home/deepin/dde-shell/panels/dock/taskmanager/treelandwindowmonitor.cpp:211                    
  #15 0x00007f8dba4b9513 in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (dock::TreeLandWindowMonitor::*)()>::call(void (dock::TreeLandWindowMonitor::*)(),                      
  dock::TreeLandWindowMonitor*, void**)::{lambda()#1}::operator()() const (__closure=0x7ffc3c8d6ca0) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:152                                            
                                                                                                                                                                                                                   
  #16 0x00007f8dba4b9bf6 in QtPrivate::FunctorCallBase::call_internal<void, QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (dock::TreeLandWindowMonitor::*)()>::call(void          
  (dock::TreeLandWindowMonitor::*)(), dock::TreeLandWindowMonitor*, void**)::{lambda()#1}>(void**, QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void                                  
  (dock::TreeLandWindowMonitor::*)()>::call(void (dock::TreeLandWindowMonitor::*)(), dock::TreeLandWindowMonitor*, void**)::{lambda()#1}&&) (args=0x7ffc3c8d6de8, fn=...) at                                       
  /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:65                                                                                                                                                   
  #17 0x00007f8dba4b9574 in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (dock::TreeLandWindowMonitor::*)()>::call(void (dock::TreeLandWindowMonitor::*)(),                      
  dock::TreeLandWindowMonitor*, void**)                                                                                                                                                                            
                                                                                                                                                                                                                   
      (f=(void (dock::TreeLandWindowMonitor::*)(dock::TreeLandWindowMonitor * const)) 0x7f8dba4b5118 <dock::TreeLandWindowMonitor::handleForeignToplevelHandleAdded()>, o=0x55aa9d3b9eb0, arg=0x7ffc3c8d6de8)      
      at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:151                                                                                                                                           
  #18 0x00007f8dba4b8a10 in QtPrivate::FunctionPointer<void (dock::TreeLandWindowMonitor::*)()>::call<QtPrivate::List<>, void>(void (dock::TreeLandWindowMonitor::*)(), dock::TreeLandWindowMonitor*, void**)      
      (f=(void (dock::TreeLandWindowMonitor::*)(dock::TreeLandWindowMonitor * const)) 0x7f8dba4b5118 <dock::TreeLandWindowMonitor::handleForeignToplevelHandleAdded()>, o=0x55aa9d3b9eb0, arg=0x7ffc3c8d6de8)      
      at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:199                                                                                                                                           
  #19 0x00007f8dba4b7f73 in QtPrivate::QCallableObject<void (dock::TreeLandWindowMonitor::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*)                          
      (which=1, this_=0x55aa9e4fd270, r=0x55aa9d3b9eb0, a=0x7ffc3c8d6de8, ret=0x0) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:570                                                              
  #20 0x00007f8dcfec446c in QtPrivate::QSlotObjectBase::call (a=0x7ffc3c8d6de8, r=0x55aa9d3b9eb0, this=0x55aa9e4fd270, this=<optimized out>, r=<optimized out>, a=<optimized out>)                                 
      at ./src/corelib/kernel/qobjectdefs_impl.h:486                                                                                                                                                               
  #21 doActivate<false> (sender=0x7f8dc4053800, signal_index=5, argv=0x7ffc3c8d6de8) at ./src/corelib/kernel/qobject.cpp:4120                                                                                      
  #22 0x00007f8dba401737 in dock::ForeignToplevelHandle::handlerIsReady (this=0x7f8dc4053800) at                                                                                                                   
  /home/deepin/dde-shell/build/panels/dock/taskmanager/dock-taskmanager_autogen/EWIEGA46WW/moc_treelandwindow.cpp:206                                                                                              
                                                                                                                                                                                                                   
  #23 0x00007f8dba4b101d in dock::ForeignToplevelHandle::treeland_foreign_toplevel_handle_v1_done (this=0x7f8dc4053800) at /home/deepin/dde-shell/panels/dock/taskmanager/treelandwindow.cpp:105                   
  #24 0x00007f8dba4c86e1 in QtWayland::treeland_foreign_toplevel_handle_v1::handle_done (data=0x7f8dc4053810, object=0x7f8d5035e300)                                                                               
      at /home/deepin/dde-shell/build/panels/dock/taskmanager/qwayland-treeland-foreign-toplevel-manager-v1.cpp:352                                                                                                
  --Type <RET> for more, q to quit, c to continue without paging--                                                                                                                                                 
  #25 0x00007f8dcef4c36e in ??? () at /lib/x86_64-linux-gnu/libffi.so.8                                                                                                                                            
  #26 0x00007f8dcef4b65d in ??? () at /lib/x86_64-linux-gnu/libffi.so.8                                                                                                                                            
  #27 0x00007f8dcef4be53 in ffi_call () at /lib/x86_64-linux-gnu/libffi.so.8                                                                                                                                       
  #28 0x00007f8dd1542cf6 in wl_closure_invoke (closure=closure@entry=0x7f8d5079d000, flags=flags@entry=1, target=<optimized out>, target@entry=0x7f8d5035e300, opcode=opcode@entry=7, data=<optimized out>)        
      at ../src/connection.c:1228                                                                                                                                                                                  
  #29 0x00007f8dd153ec2f in dispatch_event (display=display@entry=0x55aa9f3fb910, queue=queue@entry=0x55aa9f3fba08) at ../src/wayland-client.c:1674                                                                
  #30 0x00007f8dd153ff53 in dispatch_queue (queue=0x55aa9f3fba08, display=0x55aa9f3fb910) at ../src/wayland-client.c:1820                                                                                          
  #31 wl_display_dispatch_queue_pending (display=0x55aa9f3fb910, queue=0x55aa9f3fba08) at ../src/wayland-client.c:2062                                                                                             
  #32 0x00007f8dd266a505 in QtWaylandClient::QWaylandDisplay::flushRequests() () at /lib/x86_64-linux-gnu/libQt6WaylandClient.so.6                                                                                 
  #33 0x00007f8dcfec4763 in doActivate<false> (sender=0x55aa9d2c2de0, signal_index=4, argv=0x7ffc3c8d7398) at ./src/corelib/kernel/qobject.cpp:4132                                                                
  #34 0x00007f8dd006cd8b in QEventDispatcherGlib::processEvents (this=0x55aa9d2c2de0, flags=...) at ./src/corelib/kernel/qeventdispatcher_glib.cpp:403                                                             
  #35 0x00007f8dcfe80c2a in QEventLoop::exec (this=0x7ffc3c8d7530, flags=...) at ./src/corelib/global/qflags.h:34                                                                                                  
  #36 0x00007f8dcfe7ace8 in QCoreApplication::exec () at ./src/corelib/global/qflags.h:74                                                                                                                          
  #37 0x000055aa8bf3b37c in main (argc=6, argv=0x7ffc3c8d81b8) at /home/deepin/dde-shell/shell/main.cpp:221 

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

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:

  • Consider whether clearTrackedWindows() should be responsible for any additional cleanup beyond clearing m_trackedWindows (e.g., emitting the same signals or performing the same side effects as destroyWindow()), to keep model state changes consistent regardless of whether windows are removed individually or in bulk.
  • If clearTrackedWindows() is only intended to be used by concrete monitor implementations (like TreeLandWindowMonitor and X11WindowMonitor), you might want to restrict its visibility (e.g., protected) to avoid exposing it as part of the public API surface unnecessarily.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider whether `clearTrackedWindows()` should be responsible for any additional cleanup beyond clearing `m_trackedWindows` (e.g., emitting the same signals or performing the same side effects as `destroyWindow()`), to keep model state changes consistent regardless of whether windows are removed individually or in bulk.
- If `clearTrackedWindows()` is only intended to be used by concrete monitor implementations (like `TreeLandWindowMonitor` and `X11WindowMonitor`), you might want to restrict its visibility (e.g., `protected`) to avoid exposing it as part of the public API surface unnecessarily.

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.

BLumia
BLumia previously approved these changes Jun 5, 2026
The crash occurs because when treeland restarts, the clear() method in
TreeLandWindowMonitor clears internal window lists but fails to reset
the tracked windows model. When treeland restart triggers a cleanup
followed by re-initialization, the model still holds stale references
to windows that have been destroyed, leading to a use-after-free crash
when the model attempts to access the window data during view updates.
Added clearTrackedWindows() method to properly clear all tracked windows
from the model using beginResetModel/endResetModel, and called it at
the start of clear() in both TreeLandWindowMonitor and X11WindowMonitor
to ensure the model is reset before internal lists are cleared. This
ensures the model and view are properly synchronized, preventing access
to destroyed window objects.

Log: fix treeland restart crash

Influence:
1. Test taskbar behavior when treeland restarts unexpectedly
2. Verify taskbar shows correct windows after treeland restart
3. Test taskbar with no windows open during treeland restart
4. Verify no crash when multiple rapid treeland restarts occur
5. Test X11 window monitor clear function for regressions
6. Verify taskbar preview windows still work correctly after restart

fix: 修复任务栏在treeland重启时崩溃的问题

当treeland重启时,TreeLandWindowMonitor中的clear()方法清除了内部窗口列
表,但未能重置跟踪窗口的模型。treeland重启触发清理后重新初始化时,模型
仍然持有已被销毁窗口的陈旧引用,导致视图更新时访问已释放的窗口对象引发崩
溃。新增clearTrackedWindows()方法,通过beginResetModel/endResetModel正确
清除模型中的所有跟踪窗口,并在TreeLandWindowMonitor和X11WindowMonitor的
clear()方法开始时调用该方法,确保在清除内部列表之前重置模型。这保证了模
型和视图同步一致,防止访问已销毁的窗口对象。

Log: 修复treeland重启崩溃问题

Influence:
1. 测试treeland异常重启时任务栏的行为
2. 验证treeland重启后任务栏显示正确的窗口
3. 测试treeland重启时没有打开任何窗口的情况
4. 验证多次快速重启treeland不会导致崩溃
5. 测试X11窗口监视器的清除功能是否有回归问题
6. 验证重启后任务栏预览窗口仍然正常工作
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX。我已仔细审查了你提供的Git Diff。本次修改的主要目的是在清理窗口监控器时,正确地通知Qt的Model/View系统模型正在重置,以避免视图与底层数据不同步。

总体来说,这次修改的方向是正确的,使用了 beginResetModel()endResetModel() 来批量清空数据。但是,在代码逻辑、内存管理和代码安全方面存在一些潜在风险,需要进一步改进。

以下是详细的审查意见:

1. 代码逻辑与内存安全 (严重问题)

问题:TreeLandWindowMonitor::clear()X11WindowMonitor::clear() 中,先调用了 clearTrackedWindows(),紧接着又调用了 m_windows.clear()。这引发了两个严重问题:

  1. 内存泄漏/悬空指针风险:如果 m_trackedWindowsm_windows 存储的是相同的 AbstractWindow* 指针(从类名和业务逻辑推测极大概率是),仅仅调用 QList::clear()QVector::clear() 只会移除指针,并不会释放指针所指向的堆内存。原本代码中可能依赖 destroyWindow 方法来释放内存,或者由底层的 Window 系统管理生命周期,但现在的清空逻辑跳过了正常的窗口销毁流程,可能导致严重的内存泄漏。如果后续还有地方访问这些窗口对象,则会产生悬空指针导致崩溃。
  2. 逻辑冗余与状态不一致:如果 m_trackedWindows 是供 Model 展示的数据源,而 m_windows 是底层实际持有的窗口集合,那么分别清空它们可能导致中间状态不一致。正确的做法应该是统一清理逻辑。

改进建议:

  • 如果 AbstractWindow 的生命周期由父类或底层窗口系统管理(即本类不需要手动 delete):确保 m_windowsm_trackedWindows 的清理顺序不会导致信号回调引发重入问题。
  • 如果本类需要负责释放 AbstractWindow 内存:必须在清空前遍历并安全地释放它们,或者复用已有的 destroyWindow 方法。

2. 代码性能 (建议优化)

问题:clearTrackedWindows() 中,使用了 if (m_trackedWindows.isEmpty()) return; 作为提前返回的条件。

  • 在 Qt 的 Model/View 机制中,如果模型为空,调用 beginResetModel()endResetModel() 依然是安全的,只会通知视图刷新(实际上无事可做)。
  • 加上这个判断虽然省去了两次函数调用的开销,但在清空模型这种极低频的操作中,性能收益微乎其微。
  • 更重要的是,如果保留这个判断,视图将不会收到模型已清空的信号。如果视图内部有额外的状态缓存,可能会因为没收到 endResetModel() 而未能清理,导致状态残留。

改进建议: 移除 isEmpty() 判断,无条件触发 ResetModel,保证视图状态与模型绝对同步。

3. 代码安全与规范 (版权声明)

问题: 头文件中的版权声明从 2023 修改为了 2023 - 2026

  • 通常情况下,开源项目(如 GPL 协议)的版权年份应当是已经过去的年份(即代码实际创建和修改的年份)。将结束年份写为未来的 2026 年是不规范的,可能存在法律合规风险。

改进建议: 如果是修改文件,通常规范的做法是追加当前年份,例如 2023 - 2024,而不是未来的年份。


改进后的代码建议

基于以上分析,我为你提供改进后的代码实现:

1. abstractwindowmonitor.cpp 改进

void AbstractWindowMonitor::clearTrackedWindows()
{
    // 移除 isEmpty 判断,确保视图总能收到模型重置的信号,保证状态同步
    beginResetModel();
    
    // 【关键逻辑确认】:如果 m_trackedWindows 中的指针需要本类释放,
    // 必须在这里释放内存,或者调用 destroyWindow。
    // 假设指针由底层窗口系统管理,无需手动 delete:
    m_trackedWindows.clear();
    
    endResetModel();
}

2. treelandwindowmonitor.cppx11windowmonitor.cpp 改进

需要明确 m_windowsm_trackedWindows 的关系。如果它们包含相同的指针,建议统一管理:

// 以 X11WindowMonitor::clear() 为例
void X11WindowMonitor::clear()
{
    // 1. 先通知 Model 视图即将重置,并清空 Model 侧的数据
    clearTrackedWindows(); 
    
    // 2. 清空底层窗口容器
    // 【注意】:如果 m_windows 中的指针对象需要手动释放,必须先释放再 clear!
    // 例如:qDeleteAll(m_windows); 
    m_windows.clear();
    
    m_windowPreview.reset(nullptr);
}

3. abstractwindowmonitor.h 版权声明修正

-// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
+// SPDX-FileCopyrightText: 2023 - 2024 UnionTech Software Technology Co., Ltd.

总结

本次 PR 的核心逻辑(引入 clearTrackedWindows 并使用 beginResetModel)是正确的,解决了 Model 数据清空但视图未更新的隐患。但需要重点关注指针对象的生命周期管理,避免 clear() 导致的内存泄漏或悬空指针问题。建议在测试时重点验证反复执行 clear() 后,系统内存占用是否持续增长,以及相关的 View 组件是否正确清空了显示。

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

Copy link
Copy Markdown
Contributor Author

/forcemerge

@deepin-bot

deepin-bot Bot commented Jun 5, 2026

Copy link
Copy Markdown

This pr force merged! (status: blocked)

@deepin-bot deepin-bot Bot merged commit c37a0d8 into linuxdeepin:master Jun 5, 2026
9 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