Visitar URL original
GitHub - linuxdeepin/treeland · GitHub
Skip to content
linuxdeepinPublic

About

No description, website, or topics provided.

Resources

Stars

79 stars

Watchers

2 watching

Forks

Latest commit

 

History

10,701 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Treeland

treeland is a wayland compositor based on wlroots and QtQuick, designed to provide efficient and flexible graphical interface support.

Dependencies

Check the debian/control file to understand specific build and runtime dependencies, or use cmake to check for missing necessary components.

Core build dependencies:

  • waylib: A Wayland compositor development library based on wlroots and QtQuick
    • Qt >= 6.8.0
    • wlroots = 0.20
  • treeland-protocols: Private Wayland protocols used by treeland

Recommended runtime dependencies:

  • ddm: A display manager optimized for multiple users

Building

Treeland uses cmake for building. The WITH_SUBMODULE_WAYLIB option can force the use of the waylib code from the submodule. If you want to use the system-provided waylib, set this option to OFF.

Using the system-provided waylib:

$ git clone git@github.com:linuxdeepin/treeland.git
$ cd treeland
$ cmake -Bbuild -DWITH_SUBMODULE_WAYLIB=OFF
$ cmake --build build

Using the waylib from the submodule:

$ git clone git@github.com:linuxdeepin/treeland.git --recursive
$ cd treeland
$ cmake -Bbuild -DWITH_SUBMODULE_WAYLIB=ON
$ cmake --build build

Packaging

A debian folder is provided to build the package under the deepin linux desktop distribution. To build the package, use the following command:

$ sudo apt build-dep . # install build dependencies
$ dpkg-buildpackage -uc -us -nc -b # build binary package(s)

treeland-debug

treeland-debug is an adb-style command-line inspector and controller for the running Treeland compositor. It connects to Treeland's debug Remote Object over Qt Remote Objects and exposes subcommands for inspecting the window tree, controlling windows, injecting input events and grabbing screenshots. Like adb, it runs in two modes:

  • Non-shell (one-shot) mode — the default: treeland-debug <command> [args].
  • Shell mode — an interactive REPL: treeland-debug shell.

The client builds as part of the normal Treeland build (it is on by default; pass -DBUILD_TREELAND_DEBUG=OFF to skip it):

cmake -B build
cmake --build build --target treeland-debug
sudo cmake --install build --component treeland-debug

Enabling the debug source

The debug Remote Object is off by default: it hands out window contents and input injection, which a compositor running inside a user session must not offer unasked. remoteDebug is Treeland's master switch for it: while the switch is on, Treeland publishes its debug socket and serves the window tree remote source to whoever connects -- the source is a thin QObject that only does work per call, so it costs nothing when no client is attached. Turn the switch off to forbid debugging entirely; the socket then disappears too. Release builds keep the socket root-only (mode 0000). A debug build instead ignores the switch and opens the channel to every local user for good: its -dev socket is 0666 and the directory Treeland owns is widened to 0711 at startup, so treeland-debug connects without a polkit prompt even when the compositor is the deb-installed global service running as its own user (/run/treeland-debug/...). The separate -dev name keeps such an instance apart from a release one. A session instance's socket sits in $XDG_RUNTIME_DIR, which stays 0700 like Qt requires, so there only its own user (and root) connects -- that user is the one debugging it anyway.

The root restriction of a release build can be lifted for a while over the debug protocol itself: treeland-debug no-auth (the requestNoAuth method of WindowTreeRemote) asks the compositor to open its debug directory (0711) and its socket (0666) to every local user. Only a caller that already got through the sealed socket can ask, and in a release build that is root alone: mode 0000 blocks the compositor's own user as well, and only CAP_DAC_OVERRIDE passes. So that connection is the authentication -- opening the window therefore costs root one pkexec prompt, and everyone who connects during those 30 minutes needs none. The window closes 30 minutes later; every remote call while it is open pushes it out again, so a forgotten request cannot leave the channel open for longer than an idle half hour. Closing it also drops the connections that were opened while it was open, so the window cannot be kept alive by holding a client connected.

Only the global service gets this window, and only for a directory of its own: /run/treeland-debug (RuntimeDirectory=treeland-debug), never its $XDG_RUNTIME_DIR (/run/treeland) -- Qt insists that one stays 0700 and would move new sessions' wayland sockets to $TMPDIR otherwise. A session instance runs inside /run/user/<uid>, which also holds the session bus and other per-session sockets, so Treeland leaves that directory alone there and root stays required.

The window is held in memory only, so nothing outlives the compositor: a crash or a restart comes back root-only, and every socket is sealed on startup even if the previous process died with the window open. The directory itself is widened once (0711, traverse but not list) and stays that way until the process exits, because several instances may share it and one closing its window must not cut off a peer's; a restart under systemd recreates it 0700. Access is gated by the socket modes alone. Any number of clients can attach at once while it is open. If no socket is published, either the switch is off or Treeland is not running -- the client says so on stderr and points at the switch. Toggling remoteDebug takes effect immediately: the remote source is created or destroyed on the fly, no restart needed.

Flip the switch with treeland-debug debug on / treeland-debug debug off (debug without an argument reports the current state). The switch is a per-user DConfig key that Treeland reads for the user it runs as, so the command finds that user through the running compositor and escalates through pkexec when it is not you; --no-escalate reports the requirement instead of prompting. Underneath it runs, as root, the equivalent of:

dde-dconfig -u <compositor uid> set \
  -a org.deepin.dde.treeland \
  -r org.deepin.dde.treeland \
  -k remoteDebug \
  -v true

All commands below are run as the dde user, e.g. sudo -u dde -- treeland-debug windows.

Socket naming and connection

Treeland publishes the debug source on a local socket whose default name is org.deepin.dde.treeland.debug, bound at an absolute path in a directory of its own: /run/treeland-debug/org.deepin.dde.treeland.debug for the global service (RuntimeDirectory=treeland-debug), /run/user/<uid>/... (i.e. $XDG_RUNTIME_DIR) for a session. Nothing is put in /tmp, which is world-writable and where a $TMPDIR-resolved path is invisible to a client with a different TMPDIR. The global service's directory is created 0700 by systemd and is not its $XDG_RUNTIME_DIR, because the no-auth window widens it to 0711 and Qt requires a runtime directory to stay 0700; $TREELAND_DEBUG_DIR overrides it for development. The socket is reachable by root, and by the compositor's own user in a debug build (0666). A treeland-debug client probes, in order, its own runtime directory, the global service's /run/treeland-debug, /run/treeland (where compositors from before the dedicated directory bound), and every /run/user/<uid> it may list (root only), because it cannot know the compositor's directory otherwise. When the name is already taken by another running treeland (global service, session service, local build), a numeric suffix is appended (org.deepin.dde.treeland.debug-1, -2, …), selected with a non-blocking advisory lock (the same approach libwayland uses for Wayland sockets). A stale socket file left by a crashed instance is reclaimed, and a live old-build instance (one without a lock file) is probed and left alone.

Debug builds use a distinct base name (org.deepin.dde.treeland.debug-dev) so a debug-compiled treeland can run alongside a release one. A debug-built treeland-debug client automatically prefers the debug instance and falls back to the release instance when the debug one is unreachable; a release-built client uses the release instance. The socket is chosen in this order: --url, then $TREELAND_DEBUG_SOCKET (a socket path or a bare name, treated like local:<value>; a value with a scheme is used as-is), then the probing above. An explicit URL always overrides this with no implicit processing -- that is also the way to reach a socket published by an older treeland, which still lives at the pre-migration /tmp/<name> path: --url local:/tmp/org.deepin.dde.treeland.debug.

Global options

Option Default Description
--url <url> $TREELAND_DEBUG_SOCKET, else auto: debug socket (debug build) with release fallback, else release socket Remote object host URL.
--name <name> WindowTree Remote object name.
--timeout-ms <n> 30000 Request timeout in ms (non-negative integer).
--json off Emit machine-readable JSON for tree/cursor/windows/clients.
--preview auto Force inline image preview in terminal (auto-detected by default).
--no-preview off Disable inline image preview.
-h, --help — Show help.
-v, --version — Show version.
--tree / --cursor — Backward-compatible aliases for the tree / cursor commands.

Command reference

Window-control commands accept a target given by numeric id (printed by windows / clients / top) or by appId (the first matching window is used).

Inspection

Command Arguments Output
tree (none, default) Layout tree (human-readable; --json for JSON).
cursor (none) Cursor position x=… y=… (--json for {"x","y"}).
windows (none) Window table; --json for a JSON array.
clients (none) Client + window table; --json for a JSON array.
shortcuts (none) Registered shortcuts (keys and gestures); --json for a JSON array.
top [interval-ms] (default 1000) Live, top-like refreshing client view (Ctrl+C to quit).

Window control

Command Arguments Output
activate <id> ok / failed.
close <id> ok / failed.
minimize <id> ok / failed.
maximize <id> ok / failed (toggles maximized).
fullscreen <id> ok / failed (toggles fullscreen).
move <id> <x> <y> ok / failed.
resize <id> <w> <h> ok / failed.
workspace <id> <ws-id> ok / failed (move window to a workspace).

Input / event injection

Command Arguments Output
move-cursor <x> <y> ok / failed.
event motion <x> <y> ok / failed.
event button <left|right|middle|code> [press|release|click] ok / failed (default click).
event key <name|evdev-code> [press|release|tap] ok / failed (default tap).

Pointer buttons use Linux input codes (left=0x110, right=0x111, middle=0x112, or a numeric code). Keyboard keys use Linux evdev keycodes; common names are recognised (esc, enter, space, tab, a–z, 0–9, arrow keys, f1–f12, home/end/pageup/pagedown/insert/del, …) or a raw code may be passed. Keys are delivered to the keyboard-focused surface — activate a window first to target it; pointer buttons go to the surface under the cursor.

Image capture

Screenshots are rendered server-side and returned to the treeland-debug client as PNG bytes; the client writes them to a file and prints the path. The compositor itself never touches the filesystem. If file is omitted a path under /tmp is generated.

Command Arguments Output
screenshot output [name] [file] PNG file path (stdout).
screenshot window <id> [file] PNG file path (stdout).

Interactive

Command Arguments Output
shell (none) REPL (treeland>) accepting all commands plus help/exit.
help (none) Full help text.

Output formats

tree and cursor print a human-readable format by default; pass --json for machine-readable JSON. windows and clients also default to human-readable tables and use --json for JSON. Window JSON object (WindowInfo):

Field Type Notes
id integer Stable window id (the wl_surface wl_resource pointer); globally unique, accepted by control commands.
appId string Application id.
title string Window title.
output string Output name.
container string Container name.
workspace integer Workspace id.
layer integer Layer id.
z integer Z order.
type integer Window type.
state integer 0 Normal, 1 Maximized, 2 Minimized, 3 Fullscreen, 4 Tiling.
visible boolean Visibility.
active boolean Active / focused flag.
geometry object {"x","y","width","height"}.
titlebarGeometry object Same shape.
boundingRect object Same shape.
iconGeometry object Same shape.
position object {"x","y"}.
frames integer Number of committed frames (from wlr_surface).
damage object Last committed buffer-damage rectangle {"x","y","width","height"}.
inputRegion array of object Input region as surface-local boxes ([{"x","y","width","height"}, ...]), already clipped to the surface size. An unset (NULL) input region is infinite per protocol and therefore reads back as one box covering the whole surface; the list is empty only when the client committed an empty region (the surface then accepts no input) or before the surface has committed a buffer.
opaqueRegion array of object Opaque region as surface-local boxes, same shape. Empty means the client declared no opaque area — the protocol default, and also the value before the first commit. It is a repaint optimization hint, not a statement that the window is actually transparent.

Client JSON object (ClientInfo): id (integer), appId (string), pid (integer, 0 when unavailable), executable (string), windows (array of WindowInfo).

The tree JSON is {"currentMode": str, "layers": [{"name", "layer", "windows": [WindowInfo], "workspaces": [{"id", "isActive", "windows": [WindowInfo]}]}]}.

Exit codes

0 on success; 1 on connection failure, RPC failure, an unknown command, or a control command that returns failed.

Usage examples

All commands run as the dde user:

# Inspect the window tree (human-readable, default command)
sudo -u dde -- treeland-debug tree

# Cursor position
sudo -u dde -- treeland-debug cursor
# → x=960 y=540

# List windows
sudo -u dde -- treeland-debug windows

# List clients and their windows
sudo -u dde -- treeland-debug clients

# Live refreshing top view (1 s interval)
sudo -u dde -- treeland-debug top
# (Ctrl+C to quit)

# Activate a window by id
sudo -u dde -- treeland-debug activate 1407374883553280

# Activate a window by appId
sudo -u dde -- treeland-debug activate dde-file-manager

# Move a window
sudo -u dde -- treeland-debug move 1407374883553280 100 200

# Resize a window
sudo -u dde -- treeland-debug resize 1407374883553280 800 600

# Move a window to workspace 2
sudo -u dde -- treeland-debug workspace 1407374883553280 2

# Move cursor
sudo -u dde -- treeland-debug move-cursor 960 540

# Send a pointer click
sudo -u dde -- treeland-debug event button left click

# Send a key tap
sudo -u dde -- treeland-debug event key enter tap

# Screenshot the primary output to a file
sudo -u dde -- treeland-debug screenshot output /tmp/ss.png

# Screenshot a window (with terminal preview if supported)
sudo -u dde -- treeland-debug screenshot window 1407374883553280

# Interactive shell mode
sudo -u dde -- treeland-debug shell
treeland> help
treeland> windows
treeland> exit

# Machine-readable JSON output
sudo -u dde -- treeland-debug --json windows
sudo -u dde -- treeland-debug --json cursor

The top view refreshes every interval-ms (default 1000 ms) using a QTimer. Each cycle calls getClients() via Qt Remote Objects, clears the terminal (\033[2J\033[H), and re-prints a header with the current timestamp and client count, followed by the client + window table. Press Ctrl+C to stop.

GitHub Actions / CI

This project uses GitHub Actions for continuous integration. The following workflows are configured:

  • waylib builds: Triggered when waylib/** files are modified
  • treeland builds: Main project builds

Getting Involved

License

treeland is licensed under Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only.

About

No description, website, or topics provided.

Resources

Stars

79 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages