9

After trying the answers in this question: How to start an app with "Always On Top" set?, specially the one in the comments by @MichaelTunnell:

This is the best option for me because I can create a bash script or a keyboard shortcut (which I did) using this command and that way I can use it when I need it but not when I don't. I did make a change though...I wanted a shortcut to turn always on top for the active window and only when I needed so here is my command. wmctrl -r :ACTIVE: -b toggle,above

I was able to toggle always on top in Ubuntu 16.10 or below, but not on Ubuntu 17.10 which is the one I have installed right now and would like to have this same shortcut

I have also tried this post which is basically a more detailed post of the comment of Michael Tunnell: Keyboard shortcut for always on top Ubuntu

The shortcut can be seen in the image below and it works for setting the window Always-on-top to True, but even if I use the same command again to "turn it off", I can't get the active application to remove that property.

enter image description here

Is this a bug in GNOME Ubuntu 17.10? Or am I missing any extra configuration in this particular version?

Frakcool
  • 245
  • 2
    You can use the Unity 7.5 + XORG engines with 17.10 and 18.04 LTS if you want to maintain original functionality. Ubuntu 16.04 uses Unity 7.4 but I'm not sure what 16.10 and 17.04 uses for Unity version number. Or as the answer below points out you can use Gnome DE + XORG too. – WinEunuuchs2Unix Feb 21 '18 at 00:19

3 Answers3

4

After a lot of research and working out how to write proper code in bash, I have created a single command that uses the wmctrl commands within a layer of logic to toggle the 'always on top' state effectively on the current GNOME desktop! Behold:

bash -c 'wmctrl -r :ACTIVE: -b $([[ $(xprop -id $(xprop -root -f _NET_ACTIVE_WINDOW 0x " \$0\\n" _NET_ACTIVE_WINDOW | awk "{print \$2}") _NET_WM_STATE) =~ "ABOVE" ]] && echo "remove" || echo "add"),above'

It checks the active window state property "_NET_WM_STATE" using xprops, and if it contains the text "ABOVE" that means the 'always on top' option is active. Then it just runs the wmctrl command with the parameter add or remove as appropriate.


Command breakdown (each command is inserted into the next, replacing the placeholder):

  • Get active window id:

xprop -root -f _NET_ACTIVE_WINDOW 0x " \$0\\n" _NET_ACTIVE_WINDOW | awk "{print \$2}"

  • Get the window state from xprop using the id:

xprop -id $(■) _NET_WM_STATE

  • Check if the state contains 'ABOVE', indicating that the window is set to 'always on top':

[[ $(■) =~ "ABOVE" ]]

  • Return "remove" if true, otherwise return "add":

■ && echo "remove" || echo "add"

  • run wmctrl command using the returned value as a parameter

wmctrl -r :ACTIVE: -b $(■),above

  • Send the whole thing to bash so that you can use command substitution $( ... ), bash boolean evaluation [[ ... ]] and the regex match operator =~

bash -c '■'

This last step in particular took me a very long time to figure out. Until I realised that the keyboard shortcuts weren't running in bash by default, I had no idea why the commands were working in the console as I was testing them but silently failing when run directly as a keyboard shortcut. It drove me up the wall for ages!

Note: because you need quotes around the command you're sending to bash, I had to be careful when writing the command that I never went more than one more level deep (using double quotes). Any further nesting of strings in quotes would have required lots of confusing backslashes to escape the quotes.

Geoff Davids
  • 243
  • 2
  • 6
3

wmctrl is not fully compatible with Wayland, which is the default session on Ubuntu 17.10.

As a workaround you switch back to an Xorg session following this Q&A: How do you switch from Wayland back to Xorg in Ubuntu 17.10?

pomsky
  • 68,507
  • 1
    I am in Xorg by the way, but wmctrl -r :ACTIVE: -b toggle,above still doesn't work. so I tried @geoff-davids answer, then it just works. – fsevenm Sep 01 '20 at 07:38
3

I think Geoff's solution is great but I wanted something a little more readable/adaptable so I wrote this quick bash script that functions very similarly but employs xdotool to get the id for xprop

#!/bin/bash

check if window is currently "ABOVE"

xprop -id $(xdotool getactivewindow) | grep NET_WM_STATE | grep -q ABOVE

if [ $? -eq 0 ]; then wmctrl -r :ACTIVE: -b remove,above else wmctrl -r :ACTIVE: -b add,above fi

Now I just make my shortcut point to this script and it works for me.

Pretty self-explanatory, I think. The one part that might need explaining is the $? which just returns the exit code of the previous command (in this case grep: 0 if it matched, 1 if it failed). Note that it's probably not good practice to use the exit code this way since grep could fail for some other reason, but this script failing is pretty low risk ;)