Linux¶
Linux 是 swinx 最早适配的非 Windows 平台。它的平台 API 全部在 swinx 内部实现(swinx/src/platform/linux),不依赖任何外部桥接库,也不使用 g_platformAPI。
构建选择¶
swinx/CMakeLists.txt 中,Linux 走的是兜底分支:
if(CMAKE_SYSTEM_NAME MATCHES "OHOS|OpenHarmony|HarmonyOS|Android")
include(mobile.cmake)
elseif(CMAKE_SYSTEM_NAME MATCHES "iOS")
include(ios.cmake)
elseif(CMAKE_SYSTEM_NAME MATCHES Darwin)
include(macos.cmake)
else()
include(linux.cmake) # ← Linux
endif()
swinx/linux.cmake 编译的源码集合为:
file(GLOB SRCS
thirdparty/xcb-util-image/*.c
thirdparty/xcb-util-renderutil/*.c
thirdparty/xcb-util-keysyms/*.c
thirdparty/xcb-util-wm/*.c
thirdparty/xcb-util/*.c
thirdparty/libxcb/*.c
src/*.cpp
src/cmnctl32/*.cpp
src/cmnctl32/*.c
src/platform/linux/*.cpp
src/gdi/cairo/*.cpp
)
即:swinx 公共层 + 通用控件 + Linux 平台层 + Cairo 2D 后端。
第三方依赖:全部内置编译¶
swinx 刻意不依赖发行版的开发包,而是把关键库放在 swinx/thirdparty/ 内一起编译,以保证不同发行版上行为一致:
add_subdirectory(thirdparty/xkbcommon)
add_subdirectory(thirdparty/libxcb)
add_subdirectory(thirdparty/xcb-imdkit)
add_subdirectory(thirdparty/dbus-1.14.10)
| 内置库 | 作用 |
|---|---|
libxcb + xcb-util-* |
X11 协议客户端;窗口创建、属性、事件、键盘符号 |
xkbcommon |
键盘布局与按键映射(keyboard.cpp) |
xcb-imdkit |
输入法支持,走 XIM 协议(imm.cpp 中的 xcb_xim_*) |
dbus-1.14.10 |
通用对话框走 D-Bus portal(dlghelper.cpp) |
cairo / pixman-1 / freetype / fontconfig |
2D 绘制与字体(来自 swinx/thirdparty) |
最终链接:
target_link_libraries(swinx
cairo xkbcommon xcb-imdkit dbus-1
${SWINX_LIBS} # dl xcb uuid atomic m stdc++ ${ALSA_LIBRARIES}
)
系统侧只需要提供 libxcb、libuuid、C++ 运行库等基础库。
窗口系统与事件泵¶
swinx/src/platform/linux/SConnection.cpp 中,swinx 自己建立 X11 连接并驱动消息循环:
connection = xcb_connect(nullptr, &screenNum);
if (int errCode = xcb_connection_has_error(connection) > 0) {
SLOG_STME() << "xcb_connect failed, error=" << errCode;
}
消息泵基于 poll() 阻塞等待,被唤醒后用 xcb_poll_for_event() 排空事件队列,再转换为 Win32 消息投递给 SOUI:
int ret = poll(fds, nfds, -1); // 阻塞等待 X 连接 / 唤醒管道 / 定时器
xcb_generic_event_t *event = xcb_poll_for_event(connection);
这也是 GetMessage / PeekMessage 在 Linux 上的底层实现——SOUI 业务侧的消息循环写法与 Windows 完全一致。
关于 Wayland
linux.cmake 只编译 xcb 相关代码,swinx 目前没有原生 Wayland 后端。在 Wayland 桌面环境下通过 XWayland 兼容层运行。
2D 绘制:Cairo¶
GDI 调用由 swinx/src/gdi/cairo/ 翻译到 Cairo:
| 文件 | 作用 |
|---|---|
gdi.cpp |
DC、位图、画刷、画笔、BitBlt 等核心 GDI 实现 |
drawtext.cpp |
DrawText / TextOut 的布局与换行处理 |
cairo_show_text2.cpp |
文本绘制的底层封装 |
builtin_image.cpp |
内置图片解码 |
注意区分层次:Cairo 是 swinx 的 2D 后端;SOUI 上层通常仍使用 Render_Skia 渲染工厂绘制 UI,最终结果通过 Cairo 上屏。
桌面集成特性¶
Linux 平台层实现了以下桌面集成能力:
| 特性 | 实现文件 | 机制 |
|---|---|---|
| 托盘图标 | STrayIconMgr.cpp |
遵循 freedesktop 系统托盘协议:查找 _NET_SYSTEM_TRAY_S0 托盘窗口,通过 _NET_SYSTEM_TRAY_OPCODE 发送嵌入请求;按 _NET_SYSTEM_TRAY_VISUAL 创建 32 位视觉的图标窗口以支持透明 |
| 拖放 | SDragdrop.cpp |
XDND 协议,对接 swinx 的 OLE 拖放接口 |
| 剪贴板 | SClipboard.cpp |
X11 Selection 机制 |
| 输入法 | imm.cpp |
通过 xcb-imdkit 走 XIM 协议对接 fcitx / ibus |
| 文件对话框 | dlghelper.cpp |
优先走 D-Bus org.freedesktop.portal(含 deepin/UOS 专用 portal 适配);D-Bus 不可用或调用失败时回退到 zenity |
音频¶
ALSA 是可选依赖:
pkg_check_modules(ALSA QUIET alsa)
if(ALSA_FOUND)
message(STATUS "ALSA found, enabling native audio support")
add_definitions(-DHAS_ALSA)
else()
message(STATUS "ALSA not found, will use avplay fallback for audio, please install libasound2-dev")
endif()
- 有 ALSA(
libasound2-dev):PlaySound走原生 ALSA 播放。 - 无 ALSA:回退到调用外部
avplay进程。
编译与运行注意事项¶
WCHAR_SIZE=4:Linux 的wchar_t是 4 字节。业务代码不要假设宽字符是 2 字节,统一使用SStringT/_T()。- 字体需显式加载:Linux 发行版字体差异大,建议随包分发字体并在
SAppCfg::DoConfig之后调用AddFontResource("simsun.ttc")。 - 文件名大小写敏感:XML 布局、皮肤中引用的资源名必须与实际文件名完全一致。
- RPATH 设置:根
CMakeLists.txt为非 Apple 平台设置了CMAKE_INSTALL_RPATH=$ORIGIN,同时linux.cmake为 swinx 动态库设置INSTALL_RPATH "$ORIGIN"与-Wl,--export-dynamic,因此依赖库与可执行文件同目录即可运行。 - Release 会 strip:Linux 的 Release 配置追加了
-s(CMAKE_CXX_FLAGS_RELEASE),需要符号时请用 Debug 或 RelWithDebInfo。
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)