Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix: normal termination for Treeland #731

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
misaka18931 wants to merge 5 commits into linuxdeepin:master
base: master
Choose a base branch
Loading
from misaka18931:owoqwq

Conversation

@misaka18931
Copy link
Collaborator

@misaka18931 misaka18931 commented Feb 3, 2026
edited by sourcery-ai bot
Loading

fix: waylib: release renderers before scene graph invalidation

Changes:

  • RhiManager: destruct on QQuickWindow::sceneGraphInvalidated:
    RhiManager holds a QSGRenderer* which must be released before scene
    graph invalidation. RhiManager itself cannot function without that
    renderer.
  • WBufferRenderer: instance method outputWindow() should use
    window() instead of parent(), as its parents are generally not of
    class WOutputRenderWindow.
  • WBufferRenderer: release texture providers and renderers upon scene
    graph invalidation.
  • WBufferRenderer: explicitly connect slot invalidateSceneGraph to
    QQuickWindow::sceneGraphInvalidated, as Qt auto discovery can fail
    in practice.

fix: qwlroots: expose qw_xwayland::destroy()

wlr_xwayland is a compositor owned object, and thus should be
destroyed compositor-side.

fix: SessionManager: correct destruction routine of WXWayland instances

WXWayland instances are managed by ShellHandler, and should be deleted
by it if possible. Otherwise, let WServer clean up.
The underlying wlr_xwayland object for XWayland instances must be
explicitly destroyed through wlr_xwayland_destroy, to clean up wayland
event listensers of wlr_xwayland_shell_v1.

fix: Treeland destruction timing

Helper::m_instance should be cleared immidiately when Helper begin
destruction.
Destroy UserModel before Helper to clean user sessions and surfaces,
for their destruction often requires assistence of Helper.
Destroy Helper before QmlEngine, as SurfaceWrapper::createNewOrClose
requires a functional engine.
Miscellaneous: cleaned unimplemented instance method
Helper::removeXWayland.

fix: temp: emergency restart key

Bring back the hard-coded Meta+F12 to crash Treeland, for debug purpose.
Currently treeland & ddm cannot handle quitting qwq.
Even a successful normal termination of Treeland leave the outputs with
the last rendered frame.
This should be reverted after a rework of the termination sequence.

Summary by Sourcery

Ensure Treeland and its Wayland/XWayland integrations shut down cleanly by fixing destruction order, resource release, and adding a temporary emergency restart shortcut.

New Features:

  • Add a temporary Meta+F12 emergency restart shortcut that forces Treeland to quit for debugging purposes.

Bug Fixes:

  • Release buffer renderers and texture providers when the Qt scene graph is invalidated to avoid use-after-free and stale graphics resources.
  • Correct WBufferRenderer to resolve its output window from the associated QQuickWindow instead of its parent item.
  • Tie RhiManager lifetime to QQuickWindow::sceneGraphInvalidated so renderers are destroyed before the scene graph is torn down.
  • Expose and invoke the qw_xwayland::destroy() wrapper to properly destroy the underlying wlr_xwayland object and its Wayland listeners.
  • Adjust WXWayland and Session destruction so XWayland instances are removed by ShellHandler when available or left to WServer otherwise, avoiding invalid access during shutdown.
  • Fix Helper singleton teardown by clearing the global instance at the start of destruction and cleaning up root surfaces and shell handler in a safe order.
  • Clean up the QML engine’s UserModel singleton and clear QML singletons during Treeland shutdown to ensure user sessions and surfaces are torn down correctly.
  • Avoid dangling pointers by nulling Session socket and XWayland members after deletion.

Enhancements:

  • Force-process application termination after Treeland::quit() completes to avoid getting stuck in an inconsistent state during shutdown.

Copilot AI review requested due to automatic review settings February 3, 2026 10:09
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: misaka18931

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

Copy link

sourcery-ai bot commented Feb 3, 2026

Reviewer's Guide

Adjusts scene graph and renderer cleanup, XWayland teardown, and Treeland shutdown sequencing to ensure normal termination and safer resource destruction, plus adds a temporary emergency restart keybinding.

Sequence diagram for scene graph invalidation cleanup

sequenceDiagram
 participant QQuickWindow
 participant WBufferRenderer
 participant RhiManager
 participant QSGRenderer
 %% WBufferRenderer connection
 QQuickWindow->>WBufferRenderer: sceneGraphInvalidated
 activate WBufferRenderer
 WBufferRenderer->>WBufferRenderer: invalidateSceneGraph()
 WBufferRenderer->>WBufferRenderer: m_textureProvider.reset()
 loop for each Source in m_sourceList
 WBufferRenderer->>QSGRenderer: delete Source.renderer
 WBufferRenderer->>WBufferRenderer: Source.renderer = nullptr
 end
 deactivate WBufferRenderer
 %% RhiManager connection
 QQuickWindow->>RhiManager: sceneGraphInvalidated
 activate RhiManager
 RhiManager->>RhiManager: delete this
 deactivate RhiManager
 destroy RhiManager
 RhiManager-->>QSGRenderer: ~RhiManager()
 destroy QSGRenderer
Loading

Sequence diagram for WXWayland destruction and XWayland teardown

sequenceDiagram
 participant Session
 participant Helper
 participant ShellHandler
 participant WXWayland
 participant QWXWayland
 participant wlr_xwayland
 Session->>Session: ~Session()
 alt Helper instance exists
 Session->>Helper: Helper::instance()
 Helper-->>Session: pointer
 Session->>Helper: shellHandler()
 Helper-->>Session: ShellHandler*
 Session->>ShellHandler: removeXWayland(m_xwayland)
 ShellHandler->>WXWayland: destroy(WServer*)
 WXWayland->>QWXWayland: handle()
 WXWayland->>QWXWayland: destroy()
 QWXWayland->>wlr_xwayland: wlr_xwayland_destroy()
 WXWayland->>WXWayland: clear surfaceList
 WXWayland-->>ShellHandler: destruction complete
 ShellHandler-->>Session: WXWayland removed
 Session->>Session: m_xwayland = nullptr
 else Helper instance is null
 Session->>Session: m_xwayland kept for WServer cleanup
 Session->>Session: m_xwayland = nullptr
 end
Loading

Updated class diagram for renderer, XWayland, and shutdown management

classDiagram
 class WBufferRenderer {
 +WBufferRenderer(QQuickItem* parent)
 +~WBufferRenderer()
 +invalidateSceneGraph() void
 +releaseResources() void
 -cleanTextureProvider() void
 -resetSources() void
 -renderWindow() WOutputRenderWindow*
 -outputWindow() WOutputRenderWindow*
 -m_textureProvider
 -m_sourceList
 }
 class RhiManager {
 +RhiManager(QQuickWindow* owner)
 +~RhiManager()
 -renderer QSGRenderer*
 -isBatchRenderer bool
 }
 class Helper {
 +Helper(QObject* parent)
 +~Helper()
 +beforeDisposeEvent(WSeat* seat, QWindow* window, QInputEvent* event) bool
 +addSocket(WSocket* socket) void
 +createXWayland() WXWayland*
 +personalization() PersonalizationV1*
 +shellHandler() ShellHandler*
 +static instance() Helper*
 -m_instance static Helper*
 +requestQuit()
 }
 class Session {
 +Session(QObject* parent)
 +~Session()
 +id() int
 -m_xwayland WXWayland*
 -m_socket WSocket*
 -m_settingManager
 }
 class WXWayland {
 +create(WServer* server) void
 +destroy(WServer* server) void
 -surfaceList
 -handle() QWXWayland*
 }
 class QWXWayland {
 +get_xwm_connection() xcb_connection_t*
 +destroy() void
 }
 class Treeland {
 +quit() void
 }
 class TreelandPrivate {
 +~TreelandPrivate()
 -qmlEngine QQmlEngine*
 -pluginTs
 }
 class QQuickWindow
 class QQuickItem
 class WOutputRenderWindow
 class QSGRenderer
 class WSeat
 class QWindow
 class QInputEvent
 class WSocket
 class ShellHandler
 class WServer
 class PersonalizationV1
 WBufferRenderer --> QQuickItem : inherits
 WBufferRenderer --> QQuickWindow : window()
 WBufferRenderer --> WOutputRenderWindow : renderWindow()
 WBufferRenderer --> QSGRenderer : uses in sources
 RhiManager --> QQuickWindow : owner
 RhiManager --> QSGRenderer : renderer
 Helper --> ShellHandler : owns
 Helper --> WSocket : manages
 Helper --> WXWayland : factory
 Session --> WXWayland : m_xwayland
 Session --> Helper : uses instance
 Session --> WSocket : m_socket
 WXWayland --> QWXWayland : handle
 WXWayland --> WServer : create, destroy
 QWXWayland --> wlr_xwayland : wraps
 Treeland --> TreelandPrivate : holds d_ptr
 TreelandPrivate --> QQmlEngine : qmlEngine
 TreelandPrivate --> UserModel : singleton
 Helper ..> Treeland : requestQuit signal
 QQuickWindow ..> WBufferRenderer : sceneGraphInvalidated signal
 QQuickWindow ..> RhiManager : sceneGraphInvalidated signal
Loading

File-Level Changes

Change Details Files
Ensure Qt Quick rendering resources are released safely on scene graph invalidation.
  • Connect WBufferRenderer::invalidateSceneGraph directly to QQuickWindow::sceneGraphInvalidated using a direct connection
  • Release texture providers and per-source renderers during scene graph invalidation
  • Ensure releaseResources fully resets sources and texture providers
  • Have RhiManager self-destruct when the associated QQuickWindow scene graph is invalidated to release its QSGRenderer
waylib/src/server/qtquick/private/wbufferrenderer.cpp
waylib/src/server/qtquick/private/wrenderbuffernode.cpp
Fix relationships and destruction order between WBufferRenderer and its output window.
  • Change WBufferRenderer::renderWindow to use window() instead of parent() for obtaining the WOutputRenderWindow instance
  • Add a TODO comment about WBufferRenderer instances created via WOutputViewport that may not yet have a window
waylib/src/server/qtquick/private/wbufferrenderer_p.h
waylib/src/server/qtquick/private/wbufferrenderer.cpp
Expose and use explicit XWayland destruction so the compositor owns lifecycle correctly.
  • Expose a destroy() wrapper for the underlying wlr_xwayland in the QWXWayland type
  • Call the handle()->destroy() method from WXWayland::destroy to clean Wayland listeners
  • Adjust Session teardown so XWayland instances are removed via ShellHandler when available, otherwise left for WServer cleanup, and clear member pointers after deletion
qwlroots/src/types/qwxwayland.h
waylib/src/server/protocols/wxwayland.cpp
src/session/session.cpp
Correct Helper and Treeland shutdown ordering and clear global/singleton state deterministically.
  • Move clearing of Helper::m_instance to the beginning of Helper::~Helper with an assertion
  • Adjust destruction order inside Helper::~Helper to destroy shell handler and surface container after clearing the singleton pointer
  • In TreelandPrivate shutdown, explicitly delete the UserModel QML singleton and clear all QML singletons
  • In Treeland::quit, fully reset the private impl, request application quit, and then forcefully terminate the process
src/seat/helper.cpp
src/core/treeland.cpp
Remove dead Helper API and add a temporary hardcoded crash shortcut for debugging termination issues.
  • Remove the unused Helper::removeXWayland declaration from the Helper interface
  • Add a Meta+F12 keybinding in Helper::beforeDisposeEvent that emits requestQuit, acting as an emergency restart/crash shortcut
src/seat/helper.h
src/seat/helper.cpp

Possibly linked issues

  • #(unlabeled): PR reworks Treeland’s termination, Helper/UserModel/XWayland teardown, and scene-graph cleanup, addressing the crash-on-quit behavior described.

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

@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:

  • The direct connect(window(), &QQuickWindow::sceneGraphInvalidated, ...) in WBufferRenderer's constructor risks window() being null at construction time (as your own TODO notes); consider wiring this up via windowChanged, componentComplete, or a lazy one-shot connection when a non-null window is first available.
  • Unconditionally calling std::terminate() at the end of Treeland::quit() forces an abnormal shutdown and bypasses normal object destruction; it might be safer to guard this behind a debug flag or dedicated emergency path so that non-debug quits can still follow a regular teardown sequence.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The direct `connect(window(), &QQuickWindow::sceneGraphInvalidated, ...)` in `WBufferRenderer`'s constructor risks `window()` being null at construction time (as your own TODO notes); consider wiring this up via `windowChanged`, `componentComplete`, or a lazy one-shot connection when a non-null window is first available.
- Unconditionally calling `std::terminate()` at the end of `Treeland::quit()` forces an abnormal shutdown and bypasses normal object destruction; it might be safer to guard this behind a debug flag or dedicated emergency path so that non-debug quits can still follow a regular teardown sequence.
## Individual Comments
### Comment 1
<location> `waylib/src/server/qtquick/private/wbufferrenderer.cpp:90-91` </location>
<code_context>
-
+ // ensure graphical resources are deleted when scene graph is invalidated
+ // TODO: WBufferRenderer created through WOutputViewport has window() == nullptr?
+ connect(window(), &QQuickWindow::sceneGraphInvalidated,
+  this, &WBufferRenderer::invalidateSceneGraph,
+  Qt::DirectConnection);
 }
</code_context>
<issue_to_address>
**issue:** Connecting to window() once in the ctor can miss later window changes or operate on nullptr.
This assumes the item already has a permanent window. For items constructed before being added to a window, `connect(window(), ...)` is effectively a no-op, so `sceneGraphInvalidated` will never be received. If the item later moves to a different window, the connection will still target the original one. Instead, listen to `QQuickItem::windowChanged` and (dis)connect `sceneGraphInvalidated` when the window becomes available or changes.
</issue_to_address>
### Comment 2
<location> `src/core/treeland.cpp:106-107` </location>
<code_context>
 it->second->deleteLater();
 pluginTs.erase(it++);
 }
+  delete qmlEngine->singletonInstance<UserModel *>("Treeland", "UserModel");
+  qmlEngine->clearSingletons();
 }
</code_context>
<issue_to_address>
**issue (bug_risk):** Manually deleting a QML singleton instance is likely a double-free; ownership belongs to the engine.
`singletonInstance<T>()` objects are owned and destroyed by the QML engine (e.g. during teardown or `clearSingletons()`). Deleting this pointer here and then calling `clearSingletons()` can cause a double delete or other lifetime issues if the engine still tracks it. Please avoid deleting it directly; rely on `clearSingletons()` or change the singleton registration so the engine does not own the instance if you need manual control.
</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.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Improve shutdown/termination stability by explicitly releasing Qt Quick scene graph resources on invalidation, fixing XWayland destruction ownership, and adjusting Treeland teardown ordering (with a temporary emergency quit key).

中文:通过在 scene graph 失效时显式释放 Qt Quick 图形资源、修正 XWayland 的销毁所有权与调用路径,并调整 Treeland 的销毁顺序,来提升退出/销毁阶段的稳定性(并临时加入紧急退出快捷键)。

Changes:

  • Release Qt Quick renderers/texture providers on QQuickWindow::sceneGraphInvalidated and fix WBufferRenderer window lookup.
  • Expose and call XWayland destroy() from the compositor side; adjust Session/XWayland cleanup path.
  • Adjust Helper/Treeland destruction timing and add a temporary Meta+F12 emergency quit path.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
waylib/src/server/qtquick/private/wrenderbuffernode.cpp Attempt to destroy RhiManager on scene graph invalidation to release QSGRenderer earlier.
waylib/src/server/qtquick/private/wbufferrenderer_p.h Use window() instead of parent() to obtain the WOutputRenderWindow.
waylib/src/server/qtquick/private/wbufferrenderer.cpp Connect invalidation handler and free texture providers/renderers on scene graph invalidation.
waylib/src/server/protocols/wxwayland.cpp Explicitly destroy underlying XWayland handle during teardown.
qwlroots/src/types/qwxwayland.h Expose qw_xwayland::destroy() binding.
src/session/session.cpp Make Session teardown resilient when Helper is already destroyed.
src/seat/helper.h Remove Helper::removeXWayland declaration (cleanup now via ShellHandler).
src/seat/helper.cpp Clear Helper::m_instance earlier during destruction; add Meta+F12 quit signal emission.
src/core/treeland.cpp Adjust singleton teardown and force-terminate on quit.

@misaka18931 misaka18931 force-pushed the owoqwq branch 6 times, most recently from 3847114 to c05e744 Compare February 4, 2026 08:06
Copy link

deepin-bot bot commented Feb 4, 2026

TAG Bot

New tag: 0.8.3
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #733

Changes:
- RhiManager: destruct on `QQuickWindow::sceneGraphInvalidated`:
 RhiManager holds a `QSGRenderer*` which must be released before scene
 graph invalidation. RhiManager itself cannot function without that
 renderer.
- WBufferRenderer: instance method `outputWindow()` should use
 `window()` instead of `parent()`, as its parents are generally not of
 class `WOutputRenderWindow`.
- WBufferRenderer: release texture providers and renderers upon scene
 graph invalidation.
- WBufferRenderer: explicitly connect slot `invalidateSceneGraph` to
 `QQuickWindow::sceneGraphInvalidated`, as Qt auto discovery can fail
 in practice.
`wlr_xwayland` is a compositor owned object, and thus should be
destroyed compositor-side.
WXWayland instances are managed by `ShellHandler`, and should be deleted
by it if possible. Otherwise, let WServer clean up.
The underlying wlr_xwayland object for XWayland instances must be
explicitly destroyed through wlr_xwayland_destroy, to clean up wayland
event listensers of wlr_xwayland_shell_v1.
`Helper::m_instance` should be cleared immidiately when `Helper` begin
destruction.
Destroy UserModel before Helper to clean user sessions and surfaces,
for their destruction often requires assistence of Helper.
Destroy Helper before QmlEngine, as `SurfaceWrapper::createNewOrClose`
requires a functional engine.
Miscellaneous: cleaned unimplemented instance method
`Helper::removeXWayland`.
Bring back the hard-coded Meta+F12 to crash Treeland, only for debug
builds.
Remapped the default normal quitting keybind to Meta+Shift+Q
}
m_rhi.reset();
// Destructor for RhiManager runs in the GUI thread
deleteLater();
Copy link
Member

Choose a reason for hiding this comment

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

算了,为了避免考虑 QQuickWindow::sceneGraphInitialized 信号,这里总归要销毁它,既然如此,这个机制做到 DataManagerBase 里去,在 sceneGraphInvalidated 时先把 this->setParent(nullptr); 然后直接 delete this; 即让这个对象在sceneGraph无效之前销毁。

Copy link
Member

Choose a reason for hiding this comment

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

另外,在 DataManagerBase 的构造函数里断言一下 isSceneGraphInitialized

// Renderer of source is delay initialized in ensureRenderer. It might be null here.
if (s.renderer)
s.renderer->deleteLater();
delete s.renderer;
Copy link
Member

Choose a reason for hiding this comment

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

s.renderer = nullptr

m_sourceList.clear();
}

void WBufferRenderer::removeSource(int index)
Copy link
Member

Choose a reason for hiding this comment

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

改名叫 destroySource,叫remove不合适,因为这个source还在list里,只是销毁了一些数据,没有从list里移除

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@sourcery-ai sourcery-ai[bot] sourcery-ai[bot] left review comments

Copilot code review Copilot Copilot left review comments

@zccrs zccrs zccrs requested changes

Requested changes must be addressed to merge this pull request.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /