gxde-wlcom:基于 wlroots 的 Wayland 合成器项目

派生自Kylin Wayland Window Compositor的又一个wlroots系wayland合成器

分支2Tags2
文件最后提交记录最后更新时间
27 天前
2 个月前
24 天前
24 天前
24 天前
2 个月前
24 天前
1 个月前
1 年前
26 天前
24 天前
2 个月前
1 年前
1 个月前
1 个月前
2 个月前
1 年前
1 个月前
24 天前
2 个月前
1 个月前
26 天前
26 天前
3 年前

GitHub contributors GitHub Release Static Badge Static Badge

GXDE Wayland合成器

派生自Kylin Wayland Window Compositor的又一个wlroots系wayland合成器
查看文档 »

查看往期版本 · 报告Bug · 请求新功能

关于本项目

GXDE Wayland 合成器(亦称 gxde-wlcom)是基于 wlroots 开发的 Wayland 合成器,其原始代码派生自 kylin-wayland-compositor。(以下简称 kywc

本仓库由 GXDE OS 团队fork,并在原项目基础上针对 GXDE OS 进行适配与优化,当前作为 GXDE OS Wayland 会话的默认合成器进行开发与维护。

该项目以开源协议 GPL-3.0-or-later 发布,项目中引用或包含的来自其他开源项目的文件及代码片段,均遵照其原始许可证要求进行使用。

优点

  1. 依赖少,未引入Qt或者GTK等图形框架(内部的QML文件vendor自deepin-kwin,仅用作移植参考,实际构建.deb包时通过 -Dexamples=false参数跳过)
  2. 按需设计应用与合成器之间的协议,目前协议支持情况请参阅「PROTOCOLS」。
  3. 特效支持,支持常用的窗口动效。
  4. 完整的中文输入支持,支持input-method v2text-input v1/v2/v3
  5. 快捷键和触摸手势支持,支持键盘快捷键,触摸板和触摸屏手势设置。
  6. 输入设备支持,支持鼠标、键盘、触摸板、触摸屏、数位板。
  7. 多语言国际化支持。
  8. 多后端支持,支持x11/wayland嵌套运行,支持drmfbdev显示后端。

GXDE做出的修改

  1. 修改构建,解决依赖问题。
  2. 移植DDE Shell/deepin-chameleon主题「云璃」的默认窗体外观。
  3. 移植dde-shell协议,并扩展wlr-layer-shell排布逻辑,为deepin-menu等沿用X11思路的菜单守护进程在Wayland下提供菜单定位支持。
  4. Cherry pick了上游Wlroots的一些更新。
  5. 自动安装gxde-wlcom会话与startgxde_wlcom启动脚本至系统。
  6. 修复了原版Wlcom(截至我们Fork时的版本)在GXDE OS上layer-shell表面无法吸附至屏幕顶端的问题。
  7. 提供了新接口允许设置GXDE主题。
  8. 提供了新接口允许控制GTK标题栏上最小化/最大化/关闭按钮的可见性。(默认为全部可见)
  9. 提供了一个接口,允许用户强制裁剪所有CSD(客户端自行装饰的)窗口,使其拥有圆角。用户亦可允许合成器跳过对layer-shell表面(这些表面通常包含GXDE顶栏、Dock、GXDE控制中心等)圆角的裁剪。强制裁剪圆角为不稳定功能。
  10. 为原来Wlcom的一些功能做了一些alias, 供GXDE控制中心使用(详见这里)。
  11. 参考deepin-kwin移植了Deepin风格的多任务视图。
  12. 修正了wl_seat晚于剪贴板相关全局对象广播的问题。dde-clipboard-daemon一类基于KWayland的客户端会在data-control管理器一被广播就拿seat创建data device,此前会因此启动即崩溃。
  13. 新增剪贴板持久化:源程序退出后,合成器会接管其剪贴板内容,使截图工具一类「复制完就退出」的程序仍能被正常粘贴(构建参数-Dclipboard_persist=false可关闭)。
  14. 新增全屏截图到剪贴板:按下PrintScreen截取全屏;也可通过top.gxde.Wlcom.Screenshot接口调用(详见这里)。

依赖项

运行时需要使用的库或程序:

  • wayland, libinput, xkbcommon
  • libseat, libdrm, libsystemd, librsvg-2.0
  • cairo, pango, pangocairo, pixman-1, glib-2.0, gio-2.0
  • gbm, json-c, libudev
  • xwayland, xcb (可选)

编译时需要的库或程序:

  • ninja-build, libdrm-dev, libxkbcommon-dev, libpixman-1-dev, libgbm-dev, libudev-dev, libseat-dev, libinput-dev, libdisplay-info-dev, hwdata, libegl-dev, libgles2-mesa-dev, libxcb1-dev, libxcb-composite0-dev, libxcb-icccm4-dev, libxcb-render0-dev, libxcb-res0-dev, libxcb-ewmh-dev, libxcb-errors-dev, xwayland

Wlroots问题

无须担心Wlroots,meson会自动从https://github.com/GXDE-OS/open-kylin-wlroots.git (我们对Open Kylin版Wlroots的fork) 拉取Open Kylin打过自己补丁的Wlroots,锁定合适的版本并作为子项目构建并静态链接。

为何作为子项目编译?Open Kylin对Wlroots做了大量扩展与修改,并且二进制/devel包名仍然是wlroots:

项目 GXDE自带的Wlroots (25.4) Open Kylin版本 (0.7.14-ok17) 是否冲突
.so二进制 libwlroots-0.19.so libwlroots-0.17.so 侥幸不冲突,但凡有一天这俩版本一旦跟上就会冲突
头文件 /usr/include/wlr /usr/include/wlr 是,若安装dev包将会覆盖

为避免与系统上现有包冲突起见,我们这么做了。

treeland-protocols 0.5.9 与 personalization 协议

理论上现在不用担心这个了,GXWM已经做到了对两个版本的自适应支持

这一节关系到整个桌面能否启动,改动protocols/treeland-personalization-manager-v1.xml前请务必读完。

上游在treeland-protocols 0.5.9(提交8576b9c,2026-06-16)中删除了get_wallpaper_context请求和treeland_personalization_wallpaper_context_v1接口,理由是该功能已迁移至xdg-desktop-portal。问题在于这次删除没有bump版本号——manager接口前后都是version="2",接口名也没变,提交信息自己写的就是Influence: Broken change

Wayland的opcode是按XML中的出现顺序排的,少一个请求,后面全部错位一格:

客户端发出 opcode 布局不一致的服务端会执行
0.5.9客户端的get_cursor_context 1 0.5.8服务端的get_wallpaper_context
0.5.8客户端的get_appearance_context 4 0.5.9服务端的destroy

由于两种布局同名、同版本,服务端在bind时拿不到任何信号去区分对面是哪一种,无法同时兼容。一旦对不上,所有DTK程序(libdtkgui/libdtk6gui,也就是几乎全部GXDE程序)会在启动时被合成器以wl_display error杀掉,桌面直接起不来。

因此本仓库vendor的XML必须与系统上DTK编译时所用的那一份保持wire一致,而不是跟着上游master走。当前仓库内的版本对应 0.5.8(含wallpaper context)

何时需要切换

真正的引爆点不是apt upgrade treeland-protocols——XML只是编译期输入,升级协议包本身不改变任何已编译好的客户端。引爆点是libdtkgui/libdtk6gui等被按0.5.9重新编译的那一刻

不过下面的自动探测已经把这件事接管了,正常情况下不需要改代码、不需要重新编译、也不需要人工切换,只要重新登录一次即可:布局是在wl_global_create时定死的,运行中的合成器不会中途重新探测,所以DTK升级后当前会话里新启动的DTK程序仍会挂,注销重登后自动探测就会看到新的DTK并切到0.5.9。

只有两种情况仍需人工介入:

  • DTK5与DTK6不同步(只重编了其中一个)——见下文,需要补完编译或手动指定优先保谁。
  • 有人把protocols/同步到了上游——这是唯一会让开关失效的操作。好在它编译期就会失败(wallpaper实现引用的生成符号消失,直接报incomplete type等一串错误),产不出二进制,所以不构成隐患。

判断依据(任选其一):

# 1. 看系统协议包版本
dpkg -l treeland-protocols

# 2. 直接看DTK是否还引用wallpaper context,这一条才是决定性的(也是合成器自动探测所用的判据)
strings -a /usr/lib/x86_64-linux-gnu/libdtk6gui.so.* | grep -c treeland_personalization_wallpaper_context
#   >0 : DTK仍按0.5.8编译,需要0.5.8布局
#    0 : DTK已按0.5.9编译,需要0.5.9布局

运行时开关(无需重新编译)

合成器把两种布局都编译在了同一个二进制里,启动时选一个:0.5.8布局用的是wayland-scanner生成的方法表,0.5.9布局则在运行时从同一张表里挑出{0,2,3,4,5}(跳过get_wallpaper_context)拼出来,因此两条路径同源、不会各自漂移。前提是vendor的XML保持0.5.8超集——真正切到0.5.9后这个开关连同wallpaper实现一起删掉即可。

这个前提有代码守卫:启动时会核对vendor的XML里第1号请求是不是get_wallpaper_context,不是就打ERROR说明开关已失效、并原样服务vendor的表。它针对的是「请求还在但位置变了」这种能编译通过、却会静默错开全部opcode的改动;至于整个请求被删掉的情况编译期就过不去,轮不到它管。

默认行为是自动探测:启动时扫描已安装的libdtk*gui(Qt5与Qt6两套都查,含multiarch路径),看它们是否还引用treeland_personalization_wallpaper_context_v1。这比看协议包版本准,因为XML只是编译期输入。探测不到DTK时(构建chroot、精简安装)退回去看/usr/share/treeland-protocols,再不行默认0.5.8。

理论上不需要强制设定,但如果非得要,设环境变量即可,改startgxde_wlcom里一行然后重新登录:

export GXDE_WLCOM_PERSONALIZATION=058   # 或 059;亦接受 0.5.8 / 0.5.9

确认当前选了哪个(该行是INFO级,默认WARN不显示,需-VKYWC_LOG_LEVEL=INFO):

grep Personalization ~/.log/gxde-wlcom.log | tail -1
# (Treeland Shim) Personalization: probed 4 DTK libraries, wallpaper context referenced -> using the 0.5.8 layout
# (Treeland Shim) Personalization: layout forced to 0.5.9 by GXDE_WLCOM_PERSONALIZATION

若探测发现DTK5与DTK6不一致(一个已按0.5.9重编、另一个还没有),会打一条ERROR并选择0.5.8。这种混合状态下没有任何一种选择能让两边都活,只能把落后的那个包补编译完,或用环境变量指定优先保谁。

总开关:完全不广播该协议

上面的开关是在两种布局之间二选一,而这个是直接不广播treeland_personalization_manager_v1这个global:

export GXWM_DONOT_BROADCAST_TLPM=TRUE   # 亦接受 ON / YES / 1,大小写不敏感

默认关闭(即默认正常广播)。取值不在上述列表内的一律视为关闭,包括导出了但为空的情况,所以=FALSE=0export GXWM_DONOT_BROADCAST_TLPM=都是照常广播,不会误伤。

万一哪天上游又来一次不bump版本号的破坏性改动,而上面的布局开关也救不了场,用它可以让桌面先能登录进去。客户端拿不到这个global就会回退到自己的默认外观——窗口模糊、自定义圆角、客户端指定的标题栏这些会失效,但比登进桌面panel不显示强。

该开关的日志是WARN级(默认可见,无需-V

grep Personalization ~/.log/gxde-wlcom.log | tail -1
# [WARN]: (Treeland Shim) Personalization: global not advertised, disabled by GXWM_DONOT_BROADCAST_TLPM

彻底移除兼容代码

日常切换用上面的开关就够了,本节是等GXDE彻底转向0.5.9之后清理死代码的做法(此后合成器不再能服务0.5.8客户端)。

个人觉得没必要移除,全程用开关就够了。

按顺序撤销这两个提交即可,无需其他改动:

git revert 773f0364   # feat: Treeland personal manager version autoswitch
git revert 17585154   # fix: DTK program crashes due to lacking wallpaper support ...
ninja -C build

顺序不能反。 773f0364的运行时开关引用了get_wallpaper_context/manager_get_wallpaper_context等符号,先撤17585154会留下一堆悬空引用。

这个流程已实测过:两步revert无冲突,编译通过,撤销后protocols/treeland-personalization-manager-v1.xml回到1010e86f(与上游master逐字节相同),与0.5.9包wire完全一致(54项)。注意773f0364同时包含本章节的README内容,撤销它也会一并删掉这些说明——如果之后还需要留档,记得把仍然适用的部分捡回来。

若日后rebase/squash导致hash失效,等价的手工步骤是:

  1. 用系统上的新版覆盖vendor的XML:
    cp /usr/share/treeland-protocols/treeland-personalization-manager-v1.xml protocols/
    
  2. 删除src/view/treeland_personalization.c中的运行时开关:enum personalization_layout、manager里的layout/interface_059/requests_059manager_implementation_059manager_impl_059layout_derive_059file_containsdtk_lib_patternslayout_from_envlayout_detectlayout_is_059,以及treeland_personalization_manager_create里的探测段落;personalization_manager_bindwl_global_create改回直接使用生成的treeland_personalization_manager_v1_interfacemanager_impl
  3. 删除同一文件中的wallpaper context实现:wallpaper_*系列函数、wallpaper_implmanager_get_wallpaper_contextmanager_impl中的.get_wallpaper_contextpersonalization_context里的wallpaper子结构、manager里的wallpaper_contextswallpaper_metadata及其初始化/释放。文件里另有BLEND_MODE_WALLPAPER相关的两处,属于window context的blend mode,与本节无关,不要删
  4. ninja -C build,编译期若有遗漏会直接报错。

不要git revert b9dafa79 那个提交引入的是整套personalization支持(window/cursor/font/appearance四类context),撤销它会连窗口圆角、模糊、标题栏控制一起丢掉。撤销后合成器不再广播该global,客户端会自行回退、不会崩溃,但功能全部消失,属于因噎废食。

顺带一提,b9dafa79当初vendor的XML本身就是0.5.9布局(与上游master逐字节相同),只是当时系统上的DTK还是按0.5.8编译的,才导致了错位。所以撤销17585154实际上就是把该文件还原回b9dafa79时的状态。

改动XML后必须做的校验

描述文字随便改,但wire布局(接口、请求/事件顺序、参数类型、type="destructor"since、version)必须与目标版本完全一致。改完请比对:

python3 - <<'EOF' protocols/treeland-personalization-manager-v1.xml /usr/share/treeland-protocols/treeland-personalization-manager-v1.xml
import sys, xml.etree.ElementTree as ET
def wire(p):
    out = []
    for i in ET.parse(p).getroot().findall('interface'):
        out.append(('IFACE', i.get('name'), i.get('version')))
        for kind in ('request', 'event'):
            for op, m in enumerate(i.findall(kind)):
                args = [(a.get('type'), a.get('interface')) for a in m.findall('arg')]
                out.append((kind, i.get('name'), op, m.get('name'), m.get('type'), m.get('since'), args))
    return out
a, b = wire(sys.argv[1]), wire(sys.argv[2])
print("WIRE IDENTICAL" if a == b else "WIRE MISMATCH:\n" + "\n".join(
    f"  ours={x}\n  upst={y}" for x, y in zip(a, b) if x != y))
EOF

再嵌套跑一遍确认真机行为,这一步能在污染真实会话之前抓到问题:

WAYLAND_DISPLAY=wayland-0 ./build/gxde-wlcom   # 对外暴露 wayland-1
WAYLAND_DISPLAY=wayland-1 gxde-terminal        # 任一DTK程序,能起来即为正常

同样的比对建议对protocols/下其余treeland协议一并执行——它们目前与系统包一致。

开始上手

编译

(EMACS Flymake/clang用户请看) 初始化Flymake/clang

$ meson setup build
$ ln -sf build/compile_commands.json compile_commands.json

然后重新打开emacs

手动编译 (命令行)

编译选项见meson_options.txt,简单的编译指令如下:

$ meson setup build -Dbuildtype=debugoptimized
$ ninja -C build
$ meson install -C build --skip-subprojects

手动编辑 (构建脚本)

构建脚本位于./build-deb, 这是个shell脚本,用于在调试时生成安装包,便于在调试机器上轻松部署与卸载。

首先先修改脚本权限:

$ chmod a+x ./build-deb

然后以下上参数帮助:

用法: ./build-deb <选项>

选项:
  -b, --binary          仅构建二进制包(默认行为)
    -d, --install-deps    先安装构建依赖(读 debian/control),再构建
    -c, --clean           仅清理构建产物后退出
    -h, --help            打印帮助信息

初次编译建议执行:

$ ./build-deb -d    # 安装依赖并构建

以后就可以不用安装依赖了:

$ ./build-deb    # 直接构建

构建完成后清理中间产物:

$ ./build-deb -c

使用

注意: 默认情况下,日志打印到文件$HOME/.log/kylin-wlcom.log

基础使用

程序参数如下:

Usage: kylin-wlcom [options] [command]
  -h, --help               Show help message and quit.\n
  -d, --debug              Enables full logging, including debug information.\n
  -D, --debug <options>    noxwayland or logtostdout.\n
  -s, --session <process>  Run session on startup\n
  -v, --version            Show the version number and quit.\n
  -V, --verbose            Enables more verbose logging.\n

通过-D参数可以方便运行时调试, 支持参数如下:

-Dnoxwayland    关闭xwayland支持
-Dlogtostdout   将日志打印到stdout
-Dloginmtime    使用monotonic time输出日志

在GXDE上建立kywc会话

请参阅「./docs/gxde/gxde-wlcom-session.md」,了解如何在GXDE上建立kywc会话。

现在GXDE Wlcom会在安装.deb包时自动安装会话文件,不再需要手动安装,相关的.desktop文件与启动脚本可以在本repo的data/下找到。

GXDE版本的特殊功能

多任务视图

Meta+S打开或关闭多任务视图。当前实现提供:

  • 根据com.deepin.wrap.gnome.desktop.backgroundpicture-uri设置显示桌面及工作区壁纸预览;
  • 带抗锯齿圆角和3px活动高亮线的工作区预览;
  • 显示普通及最小化窗口的实时缩略图;
  • 关闭窗口、切换窗口置顶状态;
  • 添加、删除、切换工作区;
  • 将窗口拖入其他工作区,释放后保持多任务视图开启;
  • 拖拽工作区预览以重新排序工作区。

Deepin KWin的原始实现和资源保存在 src/vendor/dkwin/multitask/upstream/,Wlcom适配层位于 src/vendor/dkwin/multitask/wlcom_multitask.c

GXDE菜单中的「多任务视图」启动器也可直接使用,无需修改桌面文件。 gxde-wlcom会在用户会话总线上提供com.deepin.wm,并将 /com/deepin/wm上的PerformAction(1)直接连接到同一个原生多任务视图 开关。接口契约与验证方法见 multitasking-launcher-interface.md

显示桌面

Wayland会话中,gxde-wlcom直接持有com.deepin.wm,并兼容 GetIsShowDesktop()SetShowDesktop(bool)。接口与Meta+D共用 view_manager_show_desktop()状态机,因此只恢复由本次“显示桌面”操作 最小化的窗口。X11会话仍由原来的deepin-wm处理;本包不安装或替换 deepin-daemondesktop-toggle

切换窗口

可以通过Alt + Tab或者Alt + Shift + Tab唤起窗口切换器,其外观模仿Deepin KWin

设置GTK主题

在用户会话总线,我们提供了top.gxde.Wlcom.Theme接口,可以通过其SetGTK方法,设置已安装的主题。

GNOME与UKUI的主题设置会同步更改,更改应该立即可见。

以下是使用示例,您需要把主题名称换为本机真实存在的主题。

busctl --user call \
  top.gxde.Wlcom.Theme \
  /top/gxde/Wlcom/Theme \
  top.gxde.Wlcom.Theme \
  SetGTK s "主题名称"

该方法接收一个字符串参数并返回boolean。返回true代表所有可用设置项均已成功写入。

设置GTK窗口按钮的可见性

top.gxde.Wlcom.WindowBtn接口用于设置GTK窗口的最小化、最大化和关闭按钮是否显示。使用三个boolean参数对应这三个按钮是否显示。

以下是例子 --

设置最小化/最大化/关闭按钮都需要显示:

busctl --user call \
  top.gxde.Wlcom.WindowBtn \
  /top/gxde/Wlcom/WindowBtn \
  top.gxde.Wlcom.WindowBtn \
  SetGtkDecorationButtons bbb true true true

查询当前设置:

busctl --user call \
  top.gxde.Wlcom.WindowBtn \
  /top/gxde/Wlcom/WindowBtn \
  top.gxde.Wlcom.WindowBtn \
  GetGtkDecorationButtons
强制裁剪圆角 (不稳定)

强制裁剪圆角与Wlcom所支持的窗口圆角不同,在强制裁剪圆角下,所有CSD(客户端自行装饰的)窗口都会被强制裁剪圆角,圆角大小取决于Wlcom设置的窗口圆角大小(即数值与普通「启用窗口圆角」功能共享)

在用户会话总线,我们提供了top.gxde.Wlcom.WindowCorner接口,用于管理两个持久化的DBus配置:

  • ForceRoundCorner:强制裁剪窗口圆角。
  • ForceRoundCornerExcludeLayerShell:启用强制裁剪时,不裁剪 wlr-layer-shell表面(例如顶栏、Dock、GXDE控制中心等的窗体)。仅在ForceRoundCorner启用时生效。
启用强制圆角裁切
busctl --user call \
  top.gxde.Wlcom.WindowCorner \
  /top/gxde/Wlcom/WindowCorner \
  top.gxde.Wlcom.WindowCorner \
  SetForceRoundCorner b true

将上述命令中的true改为false即可关闭相应配置。可通过以下方法查询 当前值:

busctl --user call \
  top.gxde.Wlcom.WindowCorner \
  /top/gxde/Wlcom/WindowCorner \
  top.gxde.Wlcom.WindowCorner \
启用强制裁剪,但排除wlr-layer-shell表面:
busctl --user call \
  top.gxde.Wlcom.WindowCorner \
  /top/gxde/Wlcom/WindowCorner \
  top.gxde.Wlcom.WindowCorner \
  SetForceRoundCornerExcludeLayerShell b true
注意事项

配置修改后立即生效,并写入~/.config/gxde-wlcom/config.jsontheme对象,对应的key分别为force_round_cornerforce_round_corner_exclude_layer_shell

多语言支持

po目录中,LINGUAS文件中加入支持的语言,POTFILES.in加入需要翻译的源文件。

然后运行以下命令,更新pot文件:

$ meson compile gxde-wlcom-pot

里程碑

参与开发

请参阅「CONTRIBUTING」文件,了解贡献所需的信息。

对于MR,请将代码PR至gxde/testing分支,测试稳定后将由管理员合并至gxde/zhuangzhuang分支并bump。

GXDE Wlcom的贡献者们

(注:不知道为何很多原版KYWC的贡献者没有显示,您可以在此处找到原版KYWC贡献者的信息)

contrib.rocks image

许可证

该项目使用开源协议GPL-3.0-or-later,详见「COPYING」。

项目中来源于其他开源项目的文件或代码片段遵守原开源协议要求。

请参阅./LICENSES/文件夹下的许可。

对于每一个源码,也请查看其顶部标明的SPDX-License-Identifier

致谢

感谢以下代码与模板提供参考:

项目介绍

派生自Kylin Wayland Window Compositor的又一个wlroots系wayland合成器

定制我的领域