Python: Xlib -- How to Raise(Bring to Top) Windows

X11 - How to raise another application's window using Python

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.

Bring main window to top on PySide

Creating the test window without a parent fixed this question.

QtWidgets.QMainWindow.__init__(self)

python-xlib - how to deterministically tell whether display output is in extending or mirroring mode

With the following you can get x,y coordinates of framebuffer of a crtc of given output (from which you can derive whether given output is cloned or extended):

        crtcInfo = d.xrandr_get_crtc_info(_data['crtc'],
resources['config_timestamp'])
x = crtcInfo.x
y = crtcInfo.y

The following helped me to understand the problem:
https://www.x.org/wiki/Development/Documentation/HowVideoCardsWork/#index3h3

How to move or resize X11 windows (even if they are maximized)?

Thanks to n.m. comment I found a solution. Here are relevant parts from my python script (it saves and restores state and geometry of all windows, so this example unmaximizes, unmaps and maps all windows):

from time import sleep
from ewmh import EWMH
from Xlib import display, protocol, X
from Xlib.protocol.request import *
...
ewmh = EWMH()
disp = display.Display()
poll_interval = 0.025 # s
poll_attempts_limit = 10
...
def unmaximize(window):
ewmh.setWmState(window, 0, "_NET_WM_STATE_MAXIMIZED_VERT")
ewmh.setWmState(window, 0, "_NET_WM_STATE_MAXIMIZED_HORZ")
...
for client in all_win:
unmaximize(client.window)
ewmh.display.flush()
for client in all_win:
client.xwin.unmap()
poll_attempts = 0
for client in all_win:
while client.xwin.get_attributes().map_state == X.IsViewable \
and poll_attempts < poll_attempts_limit:
sleep(poll_interval)
poll_attempts += 1
for client in all_win:
client.xwin.map()
poll_attempts = 0
for client in all_win:
while client.xwin.get_attributes().map_state != X.IsViewable \
and poll_attempts < poll_attempts_limit:
sleep(poll_interval)
poll_attempts += 1

After executing this code it is possible to set window geometry for any window. all_win is a list of all windows represented as list of custom class objects populated with data from ewmh.getClientList(). Each client.xwin = disp.create_resource_object("window", client.id). Waiting for mapping/unmapping to finish is important, otherwise it will be unreliable. Also, it is necessary to limit poll attempts to prevent infinite loop in case some window gets mapped or unmapped unexpectedly.


If you do not want to reconfigure a lot of windows at once, there is no noticeable performance improvement from using python xlib module for unmapping and mapping, it is easier to use xdotool instead:

from os import system
...
system("xdotool windowunmap --sync " + str(client.window.id))
system("xdotool windowmap --sync " + str(client.window.id))

If you want to set window geometry in shell script the following example should work even if the window is maximized:

wmctrl -i -r $WID -b remove,maximized_vert,maximized_horz
xdotool windowunmap --sync $WID
xdotool windowmap --sync $WID
wmctrl -i -r $WID -e 0,$x,$y,$width,$height

How to get an Xlib.display.Window instance by id?

Use dpy.create_resource_object('window', 0x1400003) where dpy is a Display object to get a Window object on that display for an existing window with the given XID.

Example usage:

>>> import Xlib
>>> import Xlib.display
>>> dpy = Xlib.display.Display()
>>> win = dpy.create_resource_object('window', 0x277075e)
>>> win.get_wm_class()
('gnome-terminal', 'Gnome-terminal')

Bring terminal to the front in Python

That "bring the Linux terminal to the front of your screen" is likely talking about terminal emulators running in an X Window environment. Ultimately this is accomplished by making a request to the window manager. There is more than one way to do this.

  • xterm (and some other terminal emulators) implement the Sun control sequences for window manipulation (from the 1980s) which were reimplemented in dtterm during the early 1990s. xterm has done this since 1996 (patch #18).
  • Python: Xlib — How can I raise(bring to top) windows? mentions wmctl, a command-line tool which allows you to make various requests to the window manager.
  • xdotool is another command-line tool which performs similar requests.
  • finally, Can a WM raise or lower windows? points out that you can write your own application (and because python can use shared libraries written in C, you could write a script using the X library).

X11/Xlib: Window always on top

You don't want to use XRaiseWindow() to try to stay on top. Some window managers will ignore it entirely. For those that don't, consider what happens if more than one app tries to do this. Boom! That's why the window manager is in charge of stacking windows, not the app.

The way you do this is to use the protocols defined in the Extended Window Manager Hints (EWMH), see: http://www.freedesktop.org/wiki/Specifications/wm-spec

Specifically here you want _NET_WM_STATE_ABOVE which is how the "Always on Top" menu item works.

If you aren't using a toolkit you'll want to get used to scavenging in toolkit source code to figure out how to do things. In this case you could look at the function gdk_window_set_keep_above() in GTK+'s X11 backend. That will show how to use the _NET_WM_STATE_ABOVE hint.



Related Topics



Leave a reply



Submit