Skip to content

feat(window): 无边框窗口 + 自定义标题栏组件 - #60

Open
FarnaHerry wants to merge 3 commits into
sudoevolve:devfrom
FarnaHerry:feat/frameless-titlebar
Open

feat(window): 无边框窗口 + 自定义标题栏组件#60
FarnaHerry wants to merge 3 commits into
sudoevolve:devfrom
FarnaHerry:feat/frameless-titlebar

Conversation

@FarnaHerry

Copy link
Copy Markdown
Contributor

概述

新增无边框窗口模式 + 自定义标题栏组件,让应用可以自绘窗口装饰(标题栏、窗口控制按钮、拖动移动、四边缩放),不再局限于操作系统自带的标题栏。

背景与动机

当前 EUI-NEO 只能使用系统原生标题栏,无法实现自定义窗口外观。很多应用场景(编辑器、播放器、客户端工具)需要无边框窗口 + 自绘标题栏来做统一、定制化的 UI。

实现内容

1. 窗口层(core/window)

  • WindowCreateRequest.decorated:控制是否使用系统边框(GLFW GLFW_DECORATED=OFF / SDL SDL_WINDOW_BORDERLESS
  • 新增跨平台窗口控制:minimizeWindow / maximizeWindow / restoreWindow / isWindowMaximized / requestWindowClose
  • dragWindow() / startWindowResize(edge):通过平台桥接合成原生移动/缩放(Win32 WM_NCLBUTTONDOWN / X11 _NET_WM_MOVERESIZE,正确上报鼠标 root 坐标避免窗口跳到左上角)
  • Linux 下两个后端补链接 libX11

2. 应用层(eui)

  • DslAppConfig::frameless(bool):启用无边框
  • eui/window.h 导出 ResizeEdge 枚举
  • 新增 app::minimizeWindow / maximizeWindow / toggleMaximizeWindow / isWindowMaximized / requestWindowClose / dragWindow / startWindowResize,作用于当前运行的 DSL 应用窗口

3. 组件层(components/titlebar.h)

  • TitleBarBuilder 覆盖整个窗口:顶部标题栏(标题 + 默认最小化/全屏/关闭三按钮,全屏后图标自动切换为还原图标)+ 四边四角 resize 手柄
  • content() 回调:完全自定义标题栏内容,背景拖动 / resize 手柄仍自动提供

4. 示例

  • examples/titlebar_demo.cpp:默认布局(左上角标题 + 右上角三按钮)
  • examples/titlebar_custom_demo.cpp:content() 回调自定义(图标 + 标题 + 自定义按钮)

平台一致性

能力 Windows macOS Linux X11 Linux Wayland
无边框 / 最小化 / 最大化 / 关闭
拖动移动(dragWindow)
四边缩放(startWindowResize)
  • macOS 的拖动/缩放桥接当前为 TODO(返回 false、不崩溃),其余平台已验证
  • Wayland 的移动/缩放是协议限制(_NET_WM_MOVERESIZE 是 X11 协议)

命名说明

组件命名为 titlebar(对齐现有 navbar 导航栏的命名风格),类名 TitleBarBuilder。如对命名有偏好请告知,改动很小。

已知问题

  • resize 拖动时画面有轻微抖动,是已有的 GLFW resize 渲染同步问题(issue [ERROR] Native title bar #43),与无边框功能无关,建议作为独立优化项处理。

测试验证

KDE Plasma 6 实机验证通过:无边框窗口、拖动移动、四边四角缩放、三按钮(最小化/全屏/关闭、全屏↔还原图标切换)均正常。GLFW + SDL2 两后端均编译通过。

Add a frameless window mode and an idiomatic titlebar component so apps
can draw their own window chrome instead of the OS decoration.

Window layer (core/window):
- WindowCreateRequest.decorated toggles the OS frame (GLFW_DECORATED /
  SDL_WINDOW_BORDERLESS).
- minimizeWindow / maximizeWindow / restoreWindow / isWindowMaximized /
  requestWindowClose, cross-platform in both backends.
- dragWindow() and startWindowResize(edge) synthesize a native move/resize
  via a per-platform bridge (Win32 WM_NCLBUTTONDOWN / X11 _NET_WM_MOVERESIZE,
  reporting the cursor's root coordinates so the window doesn't jump).

App layer (eui):
- DslAppConfig::frameless() toggles the mode; eui/window.h re-exports
  ResizeEdge.
- app::minimizeWindow / maximizeWindow / toggleMaximizeWindow /
  isWindowMaximized / requestWindowClose / dragWindow / startWindowResize,
  operating on the running DSL app's window.

Component layer (components/titlebar.h):
- TitleBarBuilder covers the whole window: a title strip (title + default
  minimize/maximize/close buttons with a live maximize<->restore icon) plus
  optional resize handles on the four edges/corners.
- content() callback overrides the default layout so callers can fill the
  strip freely while background drag + resize stay automatic.

Also wires libX11 on Linux (both backends) and adds two examples:
titlebar_demo (default layout) and titlebar_custom_demo (content callback).
@FarnaHerry

Copy link
Copy Markdown
Contributor Author

补充一个 SDL 后端在 Wayland 会话下的已知局限,以及改进方向,供参考:

当前实现的拖动/缩放机制

dragWindow() / startWindowResize(edge) 两个后端共用一套手写桥接(X11 _NET_WM_MOVERESIZE + Win32 WM_NCLBUTTONDOWN)。

  • X11 会话(含 XWayland):GLFW 和 SDL 都工作 ✅
  • SDL 在 Wayland 原生后端:SDL 默认走 Wayland 后端,窗口不在 X11 上,这条 X11 消息发出去无人接收,所以拖动/缩放失效 ❌(测试时加 SDL_VIDEODRIVER=x11 强制 X11 后端可绕过)

为什么没用 SDL 的正式 API

SDL 有跨平台的 SDL_SetWindowHitTest(本机 SDL 2.32.70 的 Wayland 后端已支持,内部走 xdg_toplevel.move/resize)。但它和当前 DSL 的 mousearea(主动触发)机制冲突:

  • SDL hit-test 是「声明式」(告诉 SDL 哪些区域可拖,SDL 自己处理)
  • 现有 titlebar 组件是「主动式」(mousearea 按下时调 app::dragWindow())
  • GLFW 没有 hit-test API,只能靠 mousearea 主动触发手写桥接

所以若 SDL 后端改用 SDL_SetWindowHitTest,titlebar 组件就得「后端感知」(SDL 走 hit-test、GLFW 走 mousearea),破坏组件后端无关的设计。

建议

这个改进(获得 Wayland 支持)可作为独立的后续 PR,把「titlebar 组件后端感知」的设计权衡单独讨论。当前 PR 先支持 X11 会话(X11/Wayland 桌面用户绝大多数是 X11 会话或可用 SDL_VIDEODRIVER=x11),平台一致性表里已如实标注。

eui_neo is static, so its PRIVATE X11 link leaks into the exported link
interface as \$<LINK_ONLY:X11::X11>. Consumers of the installed SDK then
failed at find_package(eui-neo) because X11::X11 was never declared. Add
find_dependency(X11) to the generated config on Linux so the imported
target resolves.
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.

1 participant