I'd like to be able to raise another application's Window using Python.
I did see this, which I suppose I could try:
X11: raise an existing window via command line?
However, I'd prefer to do it in Python if at all possible.
I'd like to be able to raise another application's Window using Python.
I did see this, which I suppose I could try:
X11: raise an existing window via command line?
However, I'd prefer to do it in Python if at all possible.
To activate another window, the right thing to do on the Xlib protocol layer is to send a _NET_ACTIVE_WINDOW message as described in the EWMH spec http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html
This could be done with python-xlib (presumably) or with gdk_window_focus() on a foreign GdkWindow using GDK through pygtk
_NET_ACTIVE_WINDOW is superior to XRaiseWindow() and has been in all the important WMs for many many years.
You should avoid XSetInputFocus() which will cause problems (especially if you get the timestamp wrong). The issue is that the WM can't intercept the SetInputFocus() so it causes weird race conditions and UI inconsistencies.
Really only _NET_ACTIVE_WINDOW works properly, which is why it was invented, because the previous hacks were bad.
There is a library called libwnck that will let you activate windows (among other things) but unfortunately it adds quite a lot of overhead because it always tracks all open windows from any app, even if you don't need to do that. However if you want to track windows from other apps anyway, then libwnck has a function to activate those windows that does the right thing and would be a good choice.
The strictly correct approach is to check for EWMH _NET_ACTIVE_WINDOW support (EWMH documents how to do this) and fall back to XRaiseWindow if the WM doesn't have _NET_ACTIVE_WINDOW. However, since any WM that's been actively worked on in the last many years has EWMH, lots of people are lazy about the fallback for legacy WMs.
You can have a look at the python ewmh package. Documentation contains examples, but here is how you can achieve what you want:
from ewmh import EWMH
import random
ewmh = EWMH()
# get every displayed windows
wins = ewmh.getClientList()
# let's active one window randomly
ewmh.setActiveWindow(random.choice(wins))
# flush requests - that's actually do the real job
ewmh.display.flush()
You need to use python-xlib and call .circulate(Xlib.X.RaiseLowest)
on the window object (which can be identified in many, many different ways -- can't guess which one is appropriate for you from the zero amount of info about it in your Q;-). For a great example of using python-xlib
, check out the tinywm window manager -- after the C version, the author gives a Python version that takes about 30 non-blank, non-comment lines (for a usable, if tiny, window manager...!-).
Using python-xlib:
# https://specifications.freedesktop.org/wm-spec/1.3/ar01s03.html#id-1.4.10
from Xlib.xobject.drawable import Window
from Xlib.display import Display
from Xlib.protocol.event import ClientMessage
from Xlib.X import AnyPropertyType
from Xlib import X
display: Display = Display()
root: Window | None = display.screen().root
if root is None:
raise NotImplementedError()
# your window hex id from wmctrl -l
hex_id = "0x07c0000c"
xwin: Window = display.create_resource_object('window', int(hex_id, 16))
# `source` is set to 1 with lib pyewmh but not working on KDE 5.103.0.
# When set to 0 it works on my system
source: int = 0
timestamp: int = X.CurrentTime
currently_active_window: int = 0
ev = ClientMessage(
window=xwin,
client_type=display.get_atom("_NET_ACTIVE_WINDOW"),
data=(32, [source, timestamp, currently_active_window, 0, 0]))
root.send_event(
ev,
event_mask=(X.SubstructureRedirectMask | X.SubstructureNotifyMask))
display.flush()
© 2022 - 2024 — McMap. All rights reserved.
_NET_ACTIVE_WINDOW
in python... – Vincents