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
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.
In order to pin a window, right-click on the icon in your tray again and enter Pin Mode. Your cursor will change to a pin – click on the title bar of the window you want to always keep on top, and a pin will appear on that bar. It'll be the color you set in the options menu earlier. By default, it will be red.
His name is Always on top, does not require installation, just run and in the window you want to keep visible, always press Ctrl + Space. To remove the window, also press Ctrl + Space, or close the program on the taskbar.
Select the window you want to keep on top and press “Ctrl + Space” simultaneously.
Now you can press Ctrl + Space keyboard shortcut to set any active window always on top. Then when you use Chrome browser, you can press Ctrl + Space to make Chrome always on top, and press Ctrl + Space again to disable Chrome always on top.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With