使用Xlib在Python中获取窗口位置和大小

8

我需要找到窗口的位置和大小,但是我不知道如何做。例如,如果我尝试:

id.get_geometry()    # "id" is Xlib.display.Window

我得到了类似于这样的东西:
data = {'height': 2540,
'width': 1440,
'depth': 24,
'y': 0, 'x': 0,
'border_width': 0
'root': <Xlib.display.Window 0x0000026a>
'sequence_number': 63}

我需要找到窗口的位置和大小,我的问题是:“y”,“x”和“border_width”始终为0;更糟糕的是,返回的“height”和“width”没有包括窗口边框。

在这种情况下,在我的X屏幕上(其尺寸为4400x2560),我期望x = 1280,y = 0,width = 1440,height = 2560。

换句话说,我正在寻找Python等效代码:

#!/bin/bash
id=$1
wmiface framePosition $id
wmiface frameSize $id

如果您认为Xlib不是我想要的,可以自由地提供非Xlib解决方案,只要它可以将窗口ID作为参数(就像上面的bash脚本)。在Python代码中使用bash脚本的输出明显是一种变通方法,但并不合适。

感谢Andrey Sidorov的回答,我解决了我的问题。这里有一个非常简单的脚本,演示了解决方案:print_frame_geometry_of_all_windows.py - Lissanro Rayen
4个回答

3

你可能正在使用重新父窗口管理器,因此该id窗口的x和y坐标为零。请检查父窗口(即窗口管理器框架)的坐标。


我正在使用KWin作为我的窗口管理器。但是如何获取父窗口? - Lissanro Rayen
在我问如何找到父窗口之前,我搜索了一下谷歌,并看到了这个页面。不幸的是,它是关于C xlib(而不是Python xlib)的,所以没有帮助。有任何想法如何用python找到父窗口? - Lissanro Rayen
3
parent = id.query_tree().parent - Andrey Sidorov
2
非常感谢您的帮助!以下这行代码让我得到了框架的几何信息:"id.query_tree().parent.query_tree().parent.get_geometry()"。在KWin中,WM框架是客户端窗口的祖父节点。 - Lissanro Rayen
2
我建议独立于窗口管理器,向上走到根目录,并在每一步计算相对的x、y坐标。 - Andrey Sidorov
好的,再次感谢。我实现了你的建议。为了使这个答案对其他人更有用,我写了一个非常简短的脚本作为示例:print_frame_geometry_of_all_windows.py - Lissanro Rayen

2

Liss在评论中提供了以下解决方案:

from ewmh import EWMH
ewmh = EWMH()

def frame(client):
    frame = client
    while frame.query_tree().parent != ewmh.root:
        frame = frame.query_tree().parent
    return frame

for client in ewmh.getClientList():
    print frame(client).get_geometry()

我将其复制在此处,因为答案应包含实际答案,并且防止链接失效


那么frame()只是返回传入客户端的第二个祖先节点吗?我认为这并不能实现沿树向上步行到根并在每一步计算x、y的建议... - mgalgs

0

这是我想出来的,似乎很有效:

from collections import namedtuple

import Xlib.display


disp = Xlib.display.Display()
root = disp.screen().root

MyGeom = namedtuple('MyGeom', 'x y height width')


def get_absolute_geometry(win):
    """
    Returns the (x, y, height, width) of a window relative to the top-left
    of the screen.
    """
    geom = win.get_geometry()
    (x, y) = (geom.x, geom.y)
    while True:
        parent = win.query_tree().parent
        pgeom = parent.get_geometry()
        x += pgeom.x
        y += pgeom.y
        if parent.id == root.id:
            break
        win = parent
    return MyGeom(x, y, geom.height, geom.width)

完整示例在这里


0
在与@mgalgs相同的思路下,但更加直接,我请求根窗口翻译目标窗口的(0,0)坐标:
# assuming targetWindow is the window you want to know the position of

geometry = targetWindow.get_geometry()
position = geometry.root.translate_coords(targetWindow.id, 0, 0)
# coordinates are in position.x and position.y

# if you are not interested in the geometry, you can do directly
import Xlib.display
position = Xlib.display.Display().screen().root.translate_coords(targetWindow.id, 0, 0)

这将返回目标窗口客户区的位置(即不包括窗口管理器创建的边框、标题栏和阴影装饰)。如果您想要包括它们,请将targetWindow替换为targetWindow.query_tree().parent(或第二个父级)。

在KUbuntu 20.04(即KDE、Plasma和KWin装饰)上测试通过。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接