X11:无边框窗口逐帧 glfwSetWindowPos 拖动被 WM 钳制在屏幕内;Wayland 构建无法拖动
メンテナーはふだん 2 日以内に返信
まだ誰も着手していません。
評価
調査の方向性
Start with the public surface in include/eui/window.h and the core::window implementation, then trace how the title-bar drag currently calls glfwSetWindowPos each frame. The proposed beginWindowMove and beginWindowResize would need a per-backend implementation: X11 via _NET_WM_MOVERESIZE, with Wayland and Windows/macOS returning false. Done means beginWindowMove returns true on X11 so the app drops its own drag loop, while other backends return false and the existing per-frame fallback still works.
索引モデルが issue の本文から書いたものです。
説明
X11:无边框窗口用逐帧 glfwSetWindowPos 拖动会被窗口管理器钳制在屏幕内;Wayland 构建则完全无法拖动
EUI-NEO v0.6.0-dev(ff1e757),bundled GLFW(GLFW_BUILD_X11=ON / GLFW_BUILD_WAYLAND=OFF),无边框窗口(.decorated(false))+ 自绘标题栏。Ubuntu 24.04,GNOME 46 Wayland 会话(XWayland),Mutter 46.2。
复现方式
使用 .decorated(false) 的应用按常规方式实现自绘标题栏拖动:
- 在标题栏按下时记录窗口原点与指针原点。
- 拖动过程中每帧调用
glfwSetWindowPos(window, startX + dx, startY + dy)。
预期:窗口跟随指针,并且和原生标题栏拖动一样可以拖出屏幕边缘(也能享受原生贴边分屏)。
实际:窗口只在完全位于工作区内时跟随指针;到达任意屏幕边缘就卡住,永远无法超出。同样的代码在原生 Wayland GLFW 构建下拖动完全无效。
根因
- X11:
glfwSetWindowPos每帧发起XMoveWindow,每次移动都以客户端ConfigureRequest形式到达窗口管理器。Mutter 将其视为非用户动作的配置请求,由constrain_fully_onscreen(src/core/constraints.c,优先级PRIORITY_ENTIRELY_VISIBLE_ON_WORKAREA)把位置推回可用显示器区域。该约束的豁免条件恰好解释了为什么 WM 原生拖动不受影响:info->is_user_action(交互式移动)、dock/desktop 窗口、全屏窗口。逐帧XMoveWindow循环在 WM 眼里不是用户动作,于是被钳制。 - Wayland:客户端根本没有定位权限,
_glfwSetWindowPosWayland是文档化的 no-op(GLFW_FEATURE_UNAVAILABLE),这种拖动循环在原理上就不可能工作。唯一正确的机制是xdg_toplevel.move。
所以这不是 GLFW 或 WM 的 bug,而是缺失的窗口能力:拥有自绘 chrome 的 EUI 应用没有任何途径把拖动交给合成器,而每个无边框应用要么接受边缘钳制,要么自己在应用层重写一遍 WM 协议代码。
建议方案
在 core::window 增加一个小能力,经 include/eui/window.h 暴露:
namespace eui::window {
// 请窗口管理器/合成器接管交互式移动/缩放。
// 当前平台/后端无法委托时返回 false,调用方保留自己的程序化回退。
bool beginWindowMove(Handle window);
bool beginWindowResize(Handle window, WindowResizeEdge edge);
}
- GLFW/X11:向根窗口发送 EWMH
_NET_WM_MOVERESIZEClientMessage(direction 8 = MOVE,或对应SIZE_*方向;source indication 1 = application;指针根坐标用XQueryPointer获取),发送前按规范先释放按钮的隐式 grab。之后由 WM 执行交互式移动/缩放:无逐帧往返、允许部分拖出屏幕、原生吸附/分屏白拿。 - GLFW/Wayland:
xdg_toplevel.move/resize需要按下时的 seat serial,只有后端内部持有。如果暂时拿不到,就返回false并在文档说明;X11 构建已经能拿到正确行为。 - SDL2/X11:经
SDL_SysWMinfo发送同一条消息。 - Windows/macOS:返回
false(程序化循环在这些平台本来就可用)。
应用侧只需改一行:标题栏按下时调用 beginWindowMove,返回 true 就停用自己的拖动循环。
验收标准
- GNOME / XWayland:无边框窗口按自绘标题栏拖动可以拖出屏幕边缘,并像原生拖动一样触发贴边分屏。
- 自绘边缘拖手缩放同样委托给 WM。
- 无法满足的平台/后端返回
false,既有逐帧回退保持可用。 - 有边框窗口与非 Linux 平台行为不变。
- 主要言語
- C++
- スター
- 2k
- フォーク
- 177
- 平均マージ
- 2日 1時間
- マージ済み PR(30日)
- 13
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
sudoevolve/EUI-NEO のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
sudoevolve/EUI-NEO#110 ·
メンテナーはふだん 2 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 20/100
sudoevolve/EUI-NEO#113 ·
メンテナーはふだん 2 日以内に返信
-
Windows transparent margins composite as black: bundled GLFW redirection alpha is uninitialized対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 22/100
sudoevolve/EUI-NEO#109 · コメント 1 件 ·
メンテナーはふだん 2 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 32/100
sudoevolve/EUI-NEO#106 ·
メンテナーはふだん 2 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
sudoevolve/EUI-NEO#45 · コメント 5 件 ·
メンテナーはふだん 2 日以内に返信
sudoevolve/EUI-NEO の issue をすべて見る
似ている issue
-
自定义颜色添加为常用颜色オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
mg-chao/snow-apps#2227 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
crash lld:COFF
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
llvm/llvm-project#235970 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
[Bug]: iOS textarea wraps text mid-word because LynxUIBaseInput hardcodes NSLineBreakByCharWrappingオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
lynx-family/lynx#10455 ·
メンテナーはふだん 1 日以内に返信
-
[DocDB] C++ tests that run the YSQL Connection Manager do not build odyssey or its config templateオープンarea/docdb kind/bug priority/medium status/awaiting-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
yugabyte/yugabyte-db#35861 ·
メンテナーはふだん 1 日以内に返信
-
A-tools P-low S-blocked task
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信