Xlib中心窗口

Pro*_*ude 9 linux x11 xlib

我正在编写一个Xlib应用程序,我希望窗口居中.我已经习惯XMoveWindow了(desktopWidth - width) / 2, (desktopHeight - height) / 2它,它大致在正确的位置.

然而问题是宽度和高度是客户区域,而不是总面积.有什么方法让我得到窗口的总面积?

我需要使用,Xlib因为我正在使用Glx和OpenGL.我不想使用SDL,也没有庞大的图形库.

Hav*_*c P 10

有多种方法可以解决这个问题,具体取决于你为什么这样做.前两个是大多数窗口管理器"正式支持"并在规范中描述,然后它变成了脆弱的黑客.

语义

规范鼓励您使用_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 ;-)一般来说,在客户到窗口管理器交互中有很多奇怪的历史包袱和角落案例,设置窗口位置只是兴奋的开始!