我正在编写一个Xlib应用程序,我希望窗口居中。我已经在(desktopWidth - width) / 2, (desktopHeight - height) / 2中使用了XMoveWindow,它的位置大致正确。
然而,问题是宽度和高度是客户区,而不是总面积。有没有办法让我知道窗子的总面积?
我需要使用Xlib,因为我使用的是Glx和OpenGL。我不想使用SDL,也不想有一个庞大的图形库。
发布于 2012-01-22 11:35:49
有多种方法可以做到这一点,这取决于你为什么要这样做。前两个被大多数窗口管理器“官方支持”,并在规范中描述,然后它下降到脆弱的黑客。
语义
规范鼓励您使用_NET_WM_WINDOW_TYPE而不是设置位置,如果这样做有意义的话。请参阅http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html#id2507144
例如,对话框类型(或设置了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 ;-)在客户端到窗口管理器的交互中,许多奇怪的历史包裹物和角落案例通常,设置窗口位置只是令人兴奋的开始!
发布于 2018-04-12 21:43:34
win_gravity并不经常使用,而且在一些窗口管理器中可能会有错误,因为没有人会费心编写/测试它,但它应该可以在更主流的窗口管理器中工作。
显然Unity还没有实现这一点。测试表明,XCB_GRAVITY_STATIC没有得到尊重,通过快速查看Unity源代码,我找不到实现规范的这一部分的代码。
https://stackoverflow.com/questions/8867715
复制相似问题