Get window position and size in python with Xlib
Asked Answered
T

4

8

I need to find window position and size, but I cannot figure out how. For example if I try:

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

I get something like this:

data = {'height': 2540,
'width': 1440,
'depth': 24,
'y': 0, 'x': 0,
'border_width': 0
'root': <Xlib.display.Window 0x0000026a>
'sequence_number': 63}

I need to find window position and size, so my problem is: "y", "x" and "border_width" are always 0; even worse, "height" and "width" are returned without window frame.

In this case on my X screen (its dimensions are 4400x2560) I expected x=1280, y=0, width=1440, height=2560.

In other words I'm looking for python equivalent for:

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

If you think Xlib is not what I want, feel free to offer non-Xlib solution in python if it can take window id as argument (like the bash script above). Obvious workaround to use output of the bash script in python code does not feel right.

Tensimeter answered 8/10, 2012 at 4:0 Comment(1)
Thanks to answer by Andrey Sidorov I solved my problem. Here is very simple script which demonstrates the solution: print_frame_geometry_of_all_windows.py.Tensimeter
G
3

You are probably using reparenting window manager, and because of this id window has zero x and y. Check coordinates of parent window (which is window manager frame)

Glance answered 12/10, 2012 at 7:11 Comment(6)
I'm using KWin as my window manager. But how do I get parent window?Tensimeter
Before I asked how to find parent window, I googled, and saw this page. Unfortunately, it is about C xlib (not python xlib), so it does not help. Any idea how to find parent window with python?Tensimeter
parent = id.query_tree().parentGlance
Thank you very much for your help! The following line allowed me to get frame geometry: "id.query_tree().parent.query_tree().parent.get_geometry()". WM frame is grandparent of client window (at least in KWin).Tensimeter
I suggest to be wm-independent walk up to root and calculate relative x,y on each stepGlance
OK, thanks again. I implemented your suggestion. To make this answer more useful to others I wrote very short script as an example: print_frame_geometry_of_all_windows.pyTensimeter
I
2

Liss posted the following solution as a comment:

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()

I'm copying it here because answers should contain the actual answer, and to prevent link rot.

Inlaid answered 3/9, 2015 at 21:24 Comment(1)
So frame() is just returning the second-to-root ancestor of the passed in client? I don't think that accomplishes the suggestion to walk up the tree to the root and calculate the x,y on each step...Holbrook
H
0

Here's what I came up with that seems to work well:

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)

Full example here.

Holbrook answered 7/12, 2019 at 0:16 Comment(0)
P
0

In the same idea as @mgalgs, but more direct, I ask the root window to translate the (0,0) coordinate of the target window :

# 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)

This gives the position of the client region of the targeted window (ie. without borders, title bar and shadow decoration created by the window manage). If you want to include them, replace targetWindow with targetWindow.query_tree().parent (or second parent).

Tested with KUbuntu 20.04 (ie KDE, Plasma and KWin decoration).

Pudding answered 31/5, 2022 at 12:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.