有多种方法可以解决此问题,具体取决于您这样做的原因。前两个被大多数窗口管理器“官方支持”并在规范中进行了描述,然后它变成了脆弱的黑客。
语义
规范鼓励您使用 _NET_WM_WINDOW_TYPE 而不是设置位置,如果这样做有意义的话。见http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html#id2507144
例如,DIALOG 类型(或带有 WM_TRANSIENT_FOR 提示集的窗口)通常会在其父窗口或屏幕上居中,而 _NET_WM_WINDOW_TYPE_SPLASH(启动画面)类型通常会在屏幕上居中。 “通常”这里的意思是“明智的窗口管理器可能会居中,使用奇怪的窗口管理器的人不是你的问题,让他们受苦。”
(沿同一行的另一个提示是_NET_WM_STATE_FULLSCREEN,虽然不是您想要的,但它避免了手动调整大小/定位以全屏显示。)
如果语义提示有效,则处理定位的窗口管理器代码有望比任何可以轻松手动编写的代码更智能,例如它可能处理多头设置。设置正确的语义类型还可以让 WM 在其他方面变得智能,而不是定位。
重力
如果规范中没有对您有帮助的语义提示,那么您可以手动居中。重要的是要注意窗口管理器可以忽略手动位置请求,其中一些会。如果您在 WM_NORMAL_HINTS 中设置了 USPosition 标志,有些可能只接受请求(该标志应该仅在用户明确请求位置时设置,例如使用 -geometry 命令行选项)。其他人可能总是忽略该请求。但是,您可能会忽略执行此操作的 WM;用户选择使用该 WM。
补偿窗口装饰(标题栏等)的方式是使用 WM_NORMAL_HINTS 的 win_gravity 字段,该字段最初在 ICCCM 中(参见 http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.2.3),但在 EWMH 的实现说明中更好地指定:http://standards.freedesktop.org/wm-spec/latest/ar01s09.html#id2570420
WM_NORMAL_HINTS 见http://tronche.com/gui/x/xlib/ICC/client-to-window-manager/wm-normal-hints.html#XSizeHints(注意:属性类型是WM_SIZE_HINTS,属性名称是WM_NORMAL_HINTS,所以涉及到两个不同的原子名称)。
要居中,您可以将 win_gravity 设置为 Center,这允许您定位窗口的中心(包括其装饰)而不是左上角。
win_gravity 不经常使用,并且可能在某些窗口管理器中存在错误,因为没有人费心对其进行编码/测试,但它应该可以在更主流的窗口管理器中使用。
更新,可能的混淆点:X 协议中还有其他“重力”,特别是 CreateWindow 请求让您设置“bit_gravity”和“win_gravity”;这些与 XSizeHints.win_gravity 不同。 CreateWindow 重力描述了在调整窗口大小时如何处理窗口的内容(像素/子窗口)。
基于猜测装饰尺寸的技巧
这是一个脆弱的技巧,但是......您可以尝试找出装饰尺寸,然后将其纳入您的定位中。
要获取窗口装饰的大小,一种方法是 _NET_FRAME_EXTENTS 提示,请参阅http://standards.freedesktop.org/wm-spec/latest/ar01s05.html#id2569862
对于老式的窗口管理器(但不是那些花哨的新合成器,尽管那些希望支持 _NET_FRAME_EXTENTS),窗口装饰是一个 X 窗口,因此您可以获取父窗口并查看它的大小。
这两种方法的问题是你必须在添加装饰之前映射窗口,所以你必须映射;等待获取 MapNotify 事件;然后得到装饰尺寸;然后移动窗口。不幸的是,这将导致用户可见的闪烁(窗口最初会出现然后移动)。我认为没有先映射就可以获取窗口装饰大小的方法。
进一步深入到可怕的黑客领域,您可以假设对于您映射的第一个窗口之后的窗口,装饰将匹配先前映射的窗口。 (并不是说这是一个合理的假设:不同种类的窗户可能有不同的装饰。)
实现说明:请记住,装饰窗口可以随时被销毁,这将在您提到该窗口的任何未完成的 Xlib 请求中导致 X 错误,并默认退出您的程序。为避免这种情况,请在触摸不属于您的客户端的窗口时设置 X 错误处理程序。
覆盖重定向
使用覆盖重定向是一种具有不良副作用的火箭筒,如果您的目标只是使窗口居中,则根本不是一个好主意。
如果您在创建窗口时设置了覆盖重定向标志,则窗口管理器将不会管理其大小、位置、堆叠顺序、装饰或地图状态(窗口管理器对 ConfigureRequest 和 MapRequest 的重定向被覆盖)。
对于用户认为是窗口的任何东西来说,这都是一个非常糟糕的主意。它通常用于工具提示和弹出菜单。如果你在一个窗口上设置了覆盖重定向,那么所有正常的窗口管理 UI 都会被破坏,堆叠顺序将基本上是随机的(窗口往往会卡在顶部或底部,或者更糟的是陷入无限循环与另一个客户重新战斗)。
但是,覆盖重定向的窗口不会有装饰,也不会被 WM 触摸,因此您可以确保将其居中而不会受到干扰。
(如果你不想要任何装饰,请使用 SPLASH 之类的语义类型或使用“MWM”提示,不要使用覆盖重定向。)
总结
简短的回答是设置语义提示(如果有),否则使用 XSizeHints.win_gravity=Center。
您可以看到为什么人们使用工具包和 SDL ;-) 在客户端到窗口管理器的交互中通常有很多奇怪的历史包袱和极端案例,设置窗口位置只是兴奋的开始!