How to make a window always on top?
compiz, qt5, ubuntu, window-managers, x11
Solution
the EWMH specification explicitly states that:
_NET_WM_STATE_ABOVE and _NET_WM_STATE_BELOW are mainly meant for user preferences and should not be used by applications e.g. for drawing attention to their dialogs (the Urgency hint should be used in that case, see the section called “Urgency”).
so window managers have no responsibility to respect applications which set this property directly (i.e by XChangeProperty) by themselves. this property can be changed only by sending a client message to the root window which window managers listens on.
i don't know how to do it in high-level gui toolkits like Qt, but here is how to do it in plain X11.(see EWMH spec, or _wnck_change_state for a sample implementation).
//file: test.c
//to build it, run
//shell> gcc test.c -lX11
#include <X11/Xlib.h>
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
#define _NET_WM_STATE_ADD 1 /* add/set property */
#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
// change a window's _NET_WM_STATE property so that it can be kept on top.
// @display: x11 display singleton.
// @xid : the window to set on top.
Status x11_window_set_on_top (Display* display, Window xid)
{
XEvent event;
event.xclient.type = ClientMessage;
event.xclient.serial = 0;
event.xclient.send_event = True;
event.xclient.display = display;
event.xclient.window = xid;
event.xclient.message_type = XInternAtom (display, "_NET_WM_STATE", False);
event.xclient.format = 32;
event.xclient.data.l[0] = _NET_WM_STATE_ADD;
event.xclient.data.l[1] = XInternAtom (display, "_NET_WM_STATE_ABOVE", False);
event.xclient.data.l[2] = 0; //unused.
event.xclient.data.l[3] = 0;
event.xclient.data.l[4] = 0;
return XSendEvent (display, DefaultRootWindow(display), False,
SubstructureRedirectMask|SubstructureNotifyMask, &event);
}
// a sample main function for testing.
// shell> ./a.out window_xid
int main (int argc, char** argv)
{
Window xid = strtol (argv[1], NULL, 0);
Display* display = XOpenDisplay (NULL);
x11_window_set_on_top (display, xid);
XFlush (display); //for simplicity, no event loops here.
XCloseDisplay (display);
}
also note that in some x11 environment(e.g. compiz), system menus are provided by a separate decorator program instead of the compositing window manager.
Problem
I have created a frameless Qt/QML window, and I really would like to know any programmatic means of setting its "Always On Top" system menu flag. Clicking ALT+SPACE I can bring up the system menu for the frameless window, and by clicking the "Always On Top" option the window does keep always on top, but I've not found a programmatic way of doing the same. The `Qt.WindowStaysOnTopHint` doesn't work, and trying `wmctrl -r "window name" -b add,above` doesn't work either, even though `wmctrl` does work for other windows. `wmctrl` not working for my window of interest apparently has something to do with the `N/A` for the machine name column on `wmctrl -l`: ``` francisco@Ubuntu:~$ wmctrl -l 0x02600006 0 Ubuntu Área de trabalho 0x03c00002 0 Ubuntu XdndCollectionWindowImp 0x03c00005 0 Ubuntu unity-launcher 0x03c00008 0 Ubuntu unity-panel 0x03c0000b 0 Ubuntu unity-dash 0x03c0000c 0 Ubuntu Hud 0x046000b3 0 Ubuntu How to make a window aways on top? - Stack Overflow - Mozilla Firefox 0x0520000b 0 N/A Qt Creator 0x05002396 0 Ubuntu francisco@Ubuntu: ~ 0x0540000b 0 N/A backlight ``` I've also gone through this procedure but as for the user asking, it's not working for me either, same behavior. The `_NET_WM_STATE_ABOVE` is set, but focusing the window and then checking the flag again it's not there anymore, it's sticky only when clicking through system menu. This is the QML: https://gist.github.com/oblitum/8050586 Related askubuntu question: https://askubuntu.com/questions/394998 EDIT Notice In the related askubuntu question, it was found that there should be a bug on wmctrl for targeting certain windows through their names. Using `wmctrl -i -r <window id> -b add,above` also solves the issue.