Xlib中心窗口

时间:2012-01-15 05:21:23

标签: linux x11 xlib

我正在编写一个Xlib应用,我希望窗口居中。我已将XMoveWindow(desktopWidth - width) / 2, (desktopHeight - height) / 2一起使用,它大致位于正确的位置。

但问题是宽度和高度是客户区域,而不是总面积。我有什么方法可以获得窗口的总面积吗?

我需要使用Xlib,因为我使用的是GlxOpenGL。我不想使用SDL,也不想拥有庞大的图形库。

2 个答案:

答案 0 :(得分:10)

有很多方法可以解决这个问题,具体取决于你这样做的原因。前两个是#34;正式支持"大多数窗口管理员在规范中描述,然后它变成了脆弱的黑客。

语义

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

答案 1 :(得分:-1)

  

win_gravity经常不被使用,并且可能在某些窗口管理器中有问题,因为没有人费心去编码/测试它,但它应该适用于更主流的窗口管理器。

显然Unity没有实现这一点。测试显示XCB_GRAVITY_STATIC不受尊重,通过快速查看Unity源代码,我找不到实现此部分规范的代码。