Skip to content

fix: fix occasional crash in treeland under layer shell surface#1577

Merged
deepin-bot[bot] merged 1 commit intolinuxdeepin:masterfrom
18202781743:treeland-adapter
Apr 30, 2026
Merged

fix: fix occasional crash in treeland under layer shell surface#1577
deepin-bot[bot] merged 1 commit intolinuxdeepin:masterfrom
18202781743:treeland-adapter

Conversation

@18202781743
Copy link
Copy Markdown
Contributor

@18202781743 18202781743 commented Apr 29, 2026

  1. Replace direct screenChanged lambda that captured window pointer with
    member function scheduleRecreate
  2. Add m_output tracking to prevent redundant recreate calls
  3. Add scheduleCommit to coalesce multiple commit calls and delay them
    via QueuedConnection
  4. Add m_commitScheduled and m_recreateScheduled flags to debounce
    operations
  5. Fix marginsChanged signal handler missing explicit commit
  6. This prevents race conditions when window gets destroyed during
    asynchronous reset/reinit cycle

Influence:

  1. Test layer shell surface creation with screen changes
  2. Verify no crashes when rapidly changing screen configuration
  3. Test margins, anchors, keyboard interactivity changes
  4. Verify commit debouncing works correctly
  5. Test edge cases with null waylandSurface or window
  6. Test on treeland to confirm crash is fixed

修复: 修复在 treeland 下图层壳表面的偶发崩溃

  1. 将直接捕获窗口指针的 screenChanged lambda 替换为成员函数
    scheduleRecreate
  2. 添加 m_output 跟踪以防止重复的 recreate 调用
  3. 添加 scheduleCommit 合并多个 commit 调用并通过 QueuedConnection 延迟
    执行
  4. 添加 m_commitScheduled 和 m_recreateScheduled 标志以去抖操作
  5. 修复 marginsChanged 信号处理程序缺少显式 commit 的问题
  6. 这防止了在异步 reset/reinit 周期中窗口被销毁时的竞态条件

Influence:

  1. 测试屏幕变化时的图层壳表面创建
  2. 验证快速改变屏幕配置时无崩溃
  3. 测试边距、锚点、键盘交互性变化
  4. 验证 commit 去抖工作正常
  5. 测试 waylandSurface 或窗口为 null 的边界情况
  6. 在 treeland 上测试确认崩溃已修复

Summary by Sourcery

Debounce layer shell surface state updates and screen-change handling to avoid crashes when recreating windows on Treeland.

Bug Fixes:

  • Prevent crashes caused by window destruction during asynchronous reset/reinit triggered by screen changes.

Enhancements:

  • Coalesce and defer Wayland surface commit operations to reduce redundant commits and improve stability of state changes.
  • Track the current wl_output and avoid unnecessary layer shell surface recreation when the screen output has not changed.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 29, 2026

Reviewer's Guide

Refactors QWaylandLayerShellSurface to debounce Wayland surface commits and layer-shell surface recreation on screen changes, avoiding use-after-free crashes by scheduling operations on the object itself, tracking wl_output, and guarding against null window/surface.

Sequence diagram for debounced Wayland surface commits via scheduleCommit

sequenceDiagram
    participant DLayerShellWindow
    participant QWaylandLayerShellSurface
    participant QtWaylandClient_QWaylandWindow as QWaylandWindow
    participant QtWaylandClient_QWaylandSurface as QWaylandSurface

    rect rgb(230,230,250)
        DLayerShellWindow->>QWaylandLayerShellSurface: layerChanged
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: set_layer
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: scheduleCommit
    end

    rect rgb(230,230,250)
        DLayerShellWindow->>QWaylandLayerShellSurface: exclusionZoneChanged
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: set_exclusive_zone
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: scheduleCommit
    end

    rect rgb(230,230,250)
        DLayerShellWindow->>QWaylandLayerShellSurface: marginsChanged
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: set_margin
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: scheduleCommit
    end

    rect rgb(230,230,250)
        DLayerShellWindow->>QWaylandLayerShellSurface: keyboardInteractivityChanged
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: set_keyboard_interactivity
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: scheduleCommit
    end

    rect rgb(230,230,250)
        DLayerShellWindow->>QWaylandWindow: inputRegionChanged
        QWaylandWindow->>QWaylandLayerShellSurface: applyInputRegion lambda
        QWaylandLayerShellSurface->>QWaylandWindow: window.setMask
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: scheduleCommit
    end

    rect rgb(220,255,220)
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: scheduleCommit
        alt first call
            QWaylandLayerShellSurface->>QWaylandLayerShellSurface: m_commitScheduled = true
            QWaylandLayerShellSurface-->>QWaylandLayerShellSurface: invokeMethod Qt QueuedConnection
        else subsequent calls while m_commitScheduled is true
            QWaylandLayerShellSurface-->>QWaylandLayerShellSurface: return without scheduling
        end
    end

    rect rgb(220,240,255)
        QWaylandLayerShellSurface-->>QWaylandLayerShellSurface: queued lambda executes
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: m_commitScheduled = false
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: commitWindowState
        QWaylandLayerShellSurface->>QWaylandWindow: window()
        alt window or waylandSurface is null
            QWaylandLayerShellSurface-->>QWaylandLayerShellSurface: return, skip commit
        else valid window and surface
            QWaylandLayerShellSurface->>QWaylandSurface: commit
        end
    end
Loading

Sequence diagram for debounced layer shell surface recreation on screenChanged

sequenceDiagram
    participant QWindow as QWindow
    participant QWaylandLayerShellSurface
    participant QtWaylandClient_QWaylandWindow as QWaylandWindow
    participant QtWaylandClient_QWaylandScreen as QWaylandScreen
    participant wl_output as wl_output

    rect rgb(230,230,250)
        QWindow->>QWaylandLayerShellSurface: screenChanged
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: scheduleRecreate
    end

    rect rgb(220,255,220)
        QWaylandLayerShellSurface->>QWaylandWindow: window()
        alt window missing or destroyed
            QWaylandLayerShellSurface-->>QWaylandLayerShellSurface: return, no recreate
        else window exists
            QWaylandLayerShellSurface->>QWaylandWindow: window()
            QWaylandWindow->>QWindow: screen()
            QWindow->>QWaylandScreen: handle cast
            alt waylandScreen is null
                QWaylandLayerShellSurface-->>QWaylandLayerShellSurface: warning, return
            else waylandScreen valid
                QWaylandScreen->>wl_output: output
                QWaylandLayerShellSurface->>QWaylandLayerShellSurface: compare output with m_output
                alt output unchanged or m_recreateScheduled true
                    QWaylandLayerShellSurface-->>QWaylandLayerShellSurface: return
                else new output and no recreate scheduled
                    QWaylandLayerShellSurface->>QWaylandLayerShellSurface: m_output = output
                    QWaylandLayerShellSurface->>QWaylandLayerShellSurface: m_recreateScheduled = true
                    QWaylandLayerShellSurface-->>QWaylandLayerShellSurface: invokeMethod Qt QueuedConnection
                end
            end
        end
    end

    rect rgb(220,240,255)
        QWaylandLayerShellSurface-->>QWaylandLayerShellSurface: queued recreate lambda executes
        QWaylandLayerShellSurface->>QWaylandLayerShellSurface: m_recreateScheduled = false
        QWaylandLayerShellSurface->>QWaylandWindow: window()
        alt window destroyed before recreate
            QWaylandLayerShellSurface-->>QWaylandLayerShellSurface: return, skip reset and reinit
        else window still alive
            QWaylandLayerShellSurface->>QWaylandWindow: reset
            QWaylandLayerShellSurface-->>QWaylandWindow: invokeMethod reinit Qt QueuedConnection
            QWaylandWindow-->>QWaylandWindow: reinit executes asynchronously
        end
    end
Loading

Class diagram for updated QWaylandLayerShellSurface debouncing and output tracking

classDiagram
    class QWaylandLayerShellSurface {
        +QWaylandLayerShellSurface(zwlr_layer_surface_v1* surface, DLayerShellWindow* dlayerShellWindow)
        +void setWindowGeometry(QRect geometry)
        +void calcAndSetRequestSize(QSize requestSize)
        +bool anchorsSizeConflict()
        +void trySetAnchorsAndSize()
        +void commitWindowState()
        +void scheduleCommit()
        +void scheduleRecreate()
        -DLayerShellWindow* m_dlayerShellWindow
        -QSize m_pendingSize
        -QSize m_requestSize
        -wl_output* m_output
        -bool m_configured
        -bool m_commitScheduled
        -bool m_recreateScheduled
    }

    class DLayerShellWindow {
        +QtWaylandClient_QWaylandWindow* window()
        +QtWaylandClient_QWaylandSurface* waylandSurface()
        +int layer()
        +QString scope()
        +Qt::ScreenOrientation screenConfiguration()
        +Qt::Edges anchors()
        +int exclusionZone()
        +int topMargin()
        +int rightMargin()
        +int bottomMargin()
        +int leftMargin()
        +QRegion inputRegion()
        +int keyboardInteractivity()
        +void reset()
        +void reinit()
        <<signals>> layerChanged
        <<signals>> exclusionZoneChanged
        <<signals>> marginsChanged
        <<signals>> keyboardInteractivityChanged
        <<signals>> inputRegionChanged
    }

    class QtWaylandClient_QWaylandShellSurface {
        +void init(wl_surface* surface)
        +void set_layer(int layer)
        +void set_anchor(int anchors)
        +void set_size(int width, int height)
        +void set_margin(int top, int right, int bottom, int left)
        +void set_exclusive_zone(int zone)
        +void set_keyboard_interactivity(int mode)
    }

    class QtWaylandClient_QWaylandWindow {
        +QWindow* window()
        +QtWaylandClient_QWaylandSurface* waylandSurface()
        +void reset()
        +void reinit()
    }

    class QtWaylandClient_QWaylandSurface {
        +void commit()
    }

    QWaylandLayerShellSurface --|> QtWaylandClient_QWaylandShellSurface
    QWaylandLayerShellSurface ..> DLayerShellWindow : observes
    QWaylandLayerShellSurface ..> QtWaylandClient_QWaylandWindow : uses window
    QtWaylandClient_QWaylandWindow ..> QtWaylandClient_QWaylandSurface : owns
    QtWaylandClient_QWaylandSurface <.. QWaylandLayerShellSurface : commitWindowState
Loading

File-Level Changes

Change Details Files
Debounce and centralize Wayland surface commits through a scheduled commit helper instead of committing directly in multiple signal handlers.
  • Introduce commitWindowState() to commit the associated Wayland surface after null checks.
  • Add scheduleCommit() which coalesces multiple commit requests via a queued invoke and a m_commitScheduled flag.
  • Replace direct waylandSurface()->commit() calls in layer, exclusionZone, margins, keyboardInteractivity, inputRegion, and anchors/size paths with scheduleCommit().
frame/layershell/qwaylandlayershellsurface.cpp
frame/layershell/qwaylandlayershellsurface_p.h
Make screen-change-driven recreation safe and idempotent by scheduling recreate on the surface object and tracking wl_output to avoid redundant work.
  • Replace the QWindow::screenChanged lambda that captured the window pointer with a connect to scheduleRecreate() on QWaylandLayerShellSurface.
  • Implement scheduleRecreate() to validate the Wayland window, resolve the QWaylandScreen and its wl_output, skip if unchanged or already pending, and then asynchronously reset/reinit the window via queued invokes.
  • Track the last used wl_output in m_output and add m_recreateScheduled to prevent redundant recreate cycles.
frame/layershell/qwaylandlayershellsurface.cpp
frame/layershell/qwaylandlayershellsurface_p.h
Minor structural and metadata updates to support the new behavior.
  • Add private members m_output, m_commitScheduled, and m_recreateScheduled to QWaylandLayerShellSurface and initialize them with safe defaults.
  • Update the SPDX copyright header to cover years 2023–2026.
frame/layershell/qwaylandlayershellsurface_p.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

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 found 2 issues, and left some high level feedback:

  • In scheduleRecreate(), consider adding null checks for waylandWindow->window(), window()->screen(), and screen()->handle() before the dynamic_cast, as screen changes or teardown could temporarily leave these as nullptr and reintroduce a crash path.
  • scheduleRecreate() updates m_output and sets m_recreateScheduled before the queued reset/reinit runs; if multiple screen changes occur quickly, later changes are ignored—if that’s not intentional, you may want to track the latest pending output and always recreate to the most recent one when the queued call executes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In scheduleRecreate(), consider adding null checks for waylandWindow->window(), window()->screen(), and screen()->handle() before the dynamic_cast, as screen changes or teardown could temporarily leave these as nullptr and reintroduce a crash path.
- scheduleRecreate() updates m_output and sets m_recreateScheduled before the queued reset/reinit runs; if multiple screen changes occur quickly, later changes are ignored—if that’s not intentional, you may want to track the latest pending output and always recreate to the most recent one when the queued call executes.

## Individual Comments

### Comment 1
<location path="frame/layershell/qwaylandlayershellsurface.cpp" line_range="192" />
<code_context>
+        return;
+    }
+
+    auto waylandScreen = dynamic_cast<QtWaylandClient::QWaylandScreen *>(waylandWindow->window()->screen()->handle());
+    if (!waylandScreen) {
+        qCWarning(layershellsurface) << "failed to get screen for wayland";
</code_context>
<issue_to_address>
**issue (bug_risk):** Consider guarding against a null QWindow::screen() before accessing its handle in scheduleRecreate().

`window()->screen()` can briefly be null (for example during screen transitions), but we dereference it unconditionally here. Please add a null check before using `screen()->handle()` to avoid a crash in those cases.
</issue_to_address>

### Comment 2
<location path="frame/layershell/qwaylandlayershellsurface.cpp" line_range="162" />
<code_context>
     trySetAnchorsAndSize();
 }

+void QWaylandLayerShellSurface::commitWindowState()
+{
+    auto waylandWindow = window();
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting reusable helpers and small slots for screen/output lookup, window recreation, and commit flushing to reduce lambda nesting, duplication, and custom state handling while preserving the new batching/debouncing behaviour.

You can keep the new behaviour (batched commits, debounced recreation) while reducing nesting, duplication, and custom state by extracting a couple of small helpers and using member-function invokes instead of lambdas.

### 1. Reduce lambda nesting & duplication for recreation

The reset/reinit sequence and `QWaylandScreen` lookup are duplicated and spread across lambdas. Pull them into helpers so `scheduleRecreate()` reads like a small state machine:

```cpp
QtWaylandClient::QWaylandScreen *QWaylandLayerShellSurface::currentWaylandScreen() const
{
    auto waylandWindow = window();
    if (!waylandWindow || !waylandWindow->window())
        return nullptr;

    return dynamic_cast<QtWaylandClient::QWaylandScreen *>(
        waylandWindow->window()->screen()->handle());
}

wl_output *QWaylandLayerShellSurface::currentOutput() const
{
    if (auto screen = currentWaylandScreen())
        return screen->output();
    qCWarning(layershellsurface) << "failed to get screen for wayland";
    return nullptr;
}

void QWaylandLayerShellSurface::recreateWindow()
{
    auto waylandWindow = window();
    if (!waylandWindow)
        return;

    waylandWindow->reset();
    QMetaObject::invokeMethod(
        waylandWindow,
        &QtWaylandClient::QWaylandWindow::reinit,
        Qt::QueuedConnection);
}

void QWaylandLayerShellSurface::scheduleRecreate()
{
    auto output = currentOutput();
    if (!output || output == m_output || m_recreateScheduled)
        return;

    m_output = output;
    m_recreateScheduled = true;

    QMetaObject::invokeMethod(
        this,
        [this]() {
            m_recreateScheduled = false;
            recreateWindow();
        },
        Qt::QueuedConnection);
}
```

This keeps:

- debouncing via `m_recreateScheduled`,
- avoiding redundant recreation on the same `wl_output`,
- async `reset()` → queued `reinit()`,

but removes the deeply nested lambdas and repeated null/type checks.

### 2. Simplify commit scheduling plumbing

You can keep the coalescing behaviour while avoiding an extra lambda and making the intent clearer by turning `commitWindowState()` into an invokable helper:

```cpp
void QWaylandLayerShellSurface::commitWindowState()
{
    auto waylandWindow = window();
    if (!waylandWindow || !waylandWindow->waylandSurface())
        return;

    waylandWindow->waylandSurface()->commit();
}

void QWaylandLayerShellSurface::scheduleCommit()
{
    if (m_commitScheduled)
        return;

    m_commitScheduled = true;
    QMetaObject::invokeMethod(
        this,
        [this]() {
            m_commitScheduled = false;
            commitWindowState();
        },
        Qt::QueuedConnection);
}
```

If you want to go one step further, you can remove the inner lambda too and use a small private slot:

```cpp
private slots:
    void flushScheduledCommit();

void QWaylandLayerShellSurface::flushScheduledCommit()
{
    m_commitScheduled = false;
    commitWindowState();
}

void QWaylandLayerShellSurface::scheduleCommit()
{
    if (m_commitScheduled)
        return;

    m_commitScheduled = true;
    QMetaObject::invokeMethod(this,
                              &QWaylandLayerShellSurface::flushScheduledCommit,
                              Qt::QueuedConnection);
}
```

This preserves batching (only one commit per event-loop turn) but makes the control flow around commits and recreation easier to follow and test.
</issue_to_address>

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.

Comment thread frame/layershell/qwaylandlayershellsurface.cpp Outdated
Comment thread frame/layershell/qwaylandlayershellsurface.cpp
@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented Apr 29, 2026

TAG Bot

New tag: 2.0.39
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1580

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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 force-pushed the treeland-adapter branch 2 times, most recently from 8d39da2 to 3d891f7 Compare April 29, 2026 13:04
1. Replace direct screenChanged lambda that captured window pointer with
member function scheduleRecreate
2. Add m_output tracking to prevent redundant recreate calls
3. Add scheduleCommit to coalesce multiple commit calls and delay them
via QueuedConnection
4. Add m_commitScheduled and m_recreateScheduled flags to debounce
operations
5. Fix marginsChanged signal handler missing explicit commit
6. This prevents race conditions when window gets destroyed during
asynchronous reset/reinit cycle

Influence:
1. Test layer shell surface creation with screen changes
2. Verify no crashes when rapidly changing screen configuration
3. Test margins, anchors, keyboard interactivity changes
4. Verify commit debouncing works correctly
5. Test edge cases with null waylandSurface or window
6. Test on treeland to confirm crash is fixed

修复: 修复在 treeland 下图层壳表面的偶发崩溃

1. 将直接捕获窗口指针的 screenChanged lambda 替换为成员函数
scheduleRecreate
2. 添加 m_output 跟踪以防止重复的 recreate 调用
3. 添加 scheduleCommit 合并多个 commit 调用并通过 QueuedConnection 延迟
执行
4. 添加 m_commitScheduled 和 m_recreateScheduled 标志以去抖操作
5. 修复 marginsChanged 信号处理程序缺少显式 commit 的问题
6. 这防止了在异步 reset/reinit 周期中窗口被销毁时的竞态条件

Influence:
1. 测试屏幕变化时的图层壳表面创建
2. 验证快速改变屏幕配置时无崩溃
3. 测试边距、锚点、键盘交互性变化
4. 验证 commit 去抖工作正常
5. 测试 waylandSurface 或窗口为 null 的边界情况
6. 在 treeland 上测试确认崩溃已修复
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

Git Diff 代码审查报告

总体评价

本次代码重构对 QWaylandLayerShellSurface 类进行了很好的优化,主要改进包括:

  1. 将重复的代码逻辑提取为独立方法,提高代码复用性
  2. 引入了延迟提交机制,减少不必要的 Wayland 协议调用
  3. 改进了窗口重建逻辑,避免不必要的重建操作
  4. 增加了更多辅助方法,使代码结构更清晰

详细审查

1. 语法与逻辑

优点

  • 代码语法正确,符合 C++ 规范
  • 逻辑结构清晰,方法命名准确反映其功能
  • 使用了 dynamic_cast 进行类型检查,提高了类型安全性
  • 使用了 QMetaObject::invokeMethod 进行异步调用,避免潜在的同步问题

改进建议

  1. waylandScreen() 方法中,dynamic_cast 结果未检查:

    QtWaylandClient::QWaylandScreen *QWaylandLayerShellSurface::waylandScreen()
    {
        auto currentWindowHandle = windowHandle();
        if (!currentWindowHandle || !currentWindowHandle->screen()) {
            return nullptr;
        }
    
        auto screen = dynamic_cast<QtWaylandClient::QWaylandScreen *>(currentWindowHandle->screen()->handle());
        if (!screen) {
            qCWarning(layershellsurface) << "Failed to cast to QWaylandScreen";
        }
        return screen;
    }
  2. scheduleRecreate() 方法中,建议添加对 m_output 初始状态的检查:

    void QWaylandLayerShellSurface::scheduleRecreate()
    {
        auto currentWindowHandle = windowHandle();
        if (!currentWindowHandle) {
            return;
        }
    
        const auto output = currentOutput();
        if (!output) {
            qCWarning(layershellsurface) << "failed to get screen for wayland";
            return;
        }
    
        // 如果 m_output 尚未初始化,则不需要比较
        if (m_output && (output == m_output || m_recreateScheduled)) {
            return;
        }
    
        m_output = output;
        m_recreateScheduled = true;
        QMetaObject::invokeMethod(this, &QWaylandLayerShellSurface::flushRecreate, Qt::QueuedConnection);
    }

2. 代码质量

优点

  • 代码组织良好,功能划分清晰
  • 使用了有意义的变量和方法命名
  • 减少了代码重复,提高了可维护性
  • 添加了适当的错误检查和日志记录

改进建议

  1. 考虑为新增方法添加文档注释,说明其用途和参数:

    /**
     * @brief 获取当前 Wayland 窗口对象
     * @return 指向 QWaylandWindow 的指针,如果不可用则返回 nullptr
     */
    QtWaylandClient::QWaylandWindow *waylandWindow();
  2. 考虑将一些频繁使用的方法内联,如 waylandWindow()windowHandle(),以减少函数调用开销:

    inline QtWaylandClient::QWaylandWindow *waylandWindow() { return window(); }
    inline QWindow *windowHandle() { auto currentWindow = waylandWindow(); return currentWindow ? currentWindow->window() : nullptr; }

3. 性能优化

优点

  • 引入了延迟提交机制,减少了不必要的 Wayland 协议调用
  • 通过 m_commitScheduledm_recreateScheduled 标志避免重复操作
  • 使用了 QMetaObject::invokeMethod 进行异步调用,避免阻塞主线程

改进建议

  1. 考虑使用 QPointer 来跟踪窗口对象,避免潜在的悬空指针问题:

    QPointer<QWindow> m_windowHandle;
  2. 对于频繁调用的方法,如 applyMargins(),可以考虑缓存上次的边距值,避免不必要的设置:

    void QWaylandLayerShellSurface::applyMargins()
    {
        const auto top = m_dlayerShellWindow->topMargin();
        const auto right = m_dlayerShellWindow->rightMargin();
        const auto bottom = m_dlayerShellWindow->bottomMargin();
        const auto left = m_dlayerShellWindow->leftMargin();
        
        // 检查边距是否改变
        if (m_cachedMargins.top() == top && 
            m_cachedMargins.right() == right && 
            m_cachedMargins.bottom() == bottom && 
            m_cachedMargins.left() == left) {
            return;
        }
        
        m_cachedMargins = QMargins(left, top, right, bottom);
        set_margin(top, right, bottom, left);
        scheduleCommit();
    }

4. 安全性

优点

  • 添加了空指针检查,提高了代码的健壮性
  • 使用了 dynamic_cast 进行类型安全检查
  • 使用了标志变量防止重复操作

改进建议

  1. recreateWindow() 方法中,建议添加对窗口状态的检查:

    void QWaylandLayerShellSurface::recreateWindow()
    {
        auto currentWaylandWindow = waylandWindow();
        if (!currentWaylandWindow) {
            return;
        }
        
        // 检查窗口是否已经处于重置状态
        if (currentWaylandWindow->isResetting()) {
            qCWarning(layershellsurface) << "Window is already being reset";
            return;
        }
    
        currentWaylandWindow->reset();
        QMetaObject::invokeMethod(currentWaylandWindow, &QtWaylandClient::QWaylandWindow::reinit, Qt::QueuedConnection);
    }
  2. 考虑添加对 Wayland 协议错误的处理:

    void QWaylandLayerShellSurface::commitWindowState()
    {
        auto currentWaylandWindow = waylandWindow();
        if (!currentWaylandWindow || !currentWaylandWindow->waylandSurface()) {
            return;
        }
    
        try {
            currentWaylandWindow->waylandSurface()->commit();
        } catch (const std::exception &e) {
            qCWarning(layershellsurface) << "Failed to commit window state:" << e.what();
        }
    }

总结

这次代码重构整体上是一个很好的改进,提高了代码的可读性、可维护性和性能。主要的改进点是将重复的代码逻辑提取为独立方法,并引入了延迟提交机制来优化性能。

建议的改进主要集中在:

  1. 添加更多的错误检查和日志记录
  2. 为新方法添加文档注释
  3. 考虑使用缓存机制减少不必要的 Wayland 协议调用
  4. 增强对异常情况的处理

这些改进将进一步提高代码的健壮性和可靠性。

@18202781743
Copy link
Copy Markdown
Contributor Author

/forcemerge

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented Apr 30, 2026

This pr force merged! (status: blocked)

@deepin-bot deepin-bot Bot merged commit 54056af into linuxdeepin:master Apr 30, 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