You are not logged in.
Hello,
how do i get the window id of a specific window, eg. a movie played with mplayer in python? I can do s.th. like
xwininfo -name MPlayer
, but can't find a more pythonic way. Any ideas?
Thanks,
rich_o
Last edited by rich_o (2011-02-11 00:15:20)
Offline
Afaik there are direct python to Xlib bindings. In Xlib, the XQueryTree() function can be used to traverse the window hierarchy. It starts from the root window or a specific window and gives you a list of window ids of the windows child windows. XGetClassHint allows you to receive the class name and class for a specific window id. That's the c way to do it. If you have a direct binding for python, you'll likely have to do it the same way. There may be other libs that provide Xlib bindings in a more pythonic fashion.
Last edited by hbekel (2011-02-12 16:48:21)
Offline
This is python-xlib in community. I have been using it in fpdb and found it to be a pain in the butt. It has been causing some crashes on various systems. It also doesn't handle things like non-ascii chars in window titles. I have gone back to using xwininfo to get the same information.
Offline
This is actually sufficiently more complex that it would seem at first. Iterating over the QueryList of the root window isn't quite enough---since you're going to get a lot more results than you otherwise would. (There are many windows that usually make up each client.)
There are two approaches here. You can go with the QueryList idea, but you'll need to check that WM_STATE is defined for each particular window (this is how you tell whether it's a top-level window or not). Alternatively, if you're using any sort of standardized window manager, you could rely on the _NET_CLIENT_LIST property that is defined on the root window. (This is an EWMH standard.) In fact, in the former method, whether WM_STATE is set or not is also a standard, but an older one (the ICCCM standard).
I prefer using the _NET_CLIENT_LIST way. The property is maintained by the window manager and contains a list of all window IDs that the window manager is currently "managing."
While you can use python-xlib (and in my experience, it is perfectly suitable), you might also try xpyb, which is the Python version of XCB. The following should do the job you're looking for:
import struct
import xcb, xcb.xproto
winname = 'Geany'
def get_property_value(property_reply):
assert isinstance(property_reply, xcb.xproto.GetPropertyReply)
if property_reply.format == 8:
if 0 in property_reply.value:
ret = []
s = ''
for o in property_reply.value:
if o == 0:
ret.append(s)
s = ''
else:
s += chr(o)
else:
ret = str(property_reply.value.buf())
return ret
elif property_reply.format in (16, 32):
return list(struct.unpack('I' * property_reply.value_len,
property_reply.value.buf()))
return None
def contains(needle, haystack):
return haystack.lower().find(needle.lower()) > -1
c = xcb.connect()
root = c.get_setup().roots[0].root
_NET_CLIENT_LIST = c.core.InternAtom(True, len('_NET_CLIENT_LIST'),
'_NET_CLIENT_LIST').reply().atom
raw_clientlist = c.core.GetProperty(False, root, _NET_CLIENT_LIST,
xcb.xproto.GetPropertyType.Any,
0, 2 ** 32 - 1).reply()
clientlist = get_property_value(raw_clientlist)
cookies = {}
for ident in clientlist:
cookies[ident] = c.core.GetProperty(False, ident, xcb.xproto.Atom.WM_CLASS,
xcb.xproto.GetPropertyType.Any,
0, 2 ** 32 - 1)
for ident in cookies:
winclass = get_property_value(cookies[ident].reply())
if any([contains(winname, wncls) for wncls in winclass]):
print ident, winclass
Note: The above searches on WM_CLASS. You may also want to search on _NET_WM_NAME (or maybe even WM_NAME, if you're dealing with some legacy applications).
Finally, if you're going to do any more heavy lifting, may I suggest you check out my xpyb-util git repository? The above could be condensed into this with xpyb-util:
import struct
import xcb
import xcb.xproto
import util
import icccm
import ewmh
winname = 'Geany'
def contains(needle, haystack):
return haystack.lower().find(needle.lower()) > -1
c = xcb.connect()
root = c.get_setup().roots[0].root
clientlist = ewmh.get_client_list(c, root).reply()
cookies = {}
for ident in clientlist:
cookies[ident] = icccm.get_wm_class(c, ident)
for ident in cookies:
winclass = cookies[ident].reply()
if any([contains(winname, wncls) for wncls in winclass]):
print ident, winclass
My repo can be found here: https://github.com/BurntSushi/xpyb-util
(If you import the image module, you'll need PIL installed.)
Education is favorable to liberty. Freedom can exist only in a society of knowledge. Without learning, men are incapable of knowing their rights, and where learning is confined to a few people, liberty can be neither equal nor universal.
Tu ne cede malis sed contra audentior ito
Offline
@BurntSushi: You're probably right about checking WM_STATE when using XQueryTree. I found that in practice i get the correct (toplevel) window id when I simply traverse the window tree top down and choose the first window that matches the desired WM_CLASS name property, but maybe i've just been lucky so far... So thanks for clarifying this.
Offline
Thank you all,
glad to see it's possible without external programs. A special thank you to BurntSushi for the additional insight, never thought the matter is so complicated. But well, that's what modules and extra utils are for, right?
rich_o
Offline