3

I am using Ubuntu 23.10 and I would like to set an application, in my case CuteCom Serial Monitor, to be always on top. At the moment if my IDE is fullscreen I have to launch CuteCom from the dash and then after I return to the IDE and make some changes I have to relaunch Cutecom from the dash again.

If this is possible I can imagine it being useful for other applications too.

andrew.46
  • 39,479

2 Answers2

4

Just right-click on the titlebar of the window you want to keep on top and select Always on Top from the menu.

screenshot displaying the Always on Top option

Alternatively, if you prefer to not use the mouse, you can press Alt+Super and use the up and down arrows to select Always on Top.

  • And how do we modify the application startup icon to run in "Always on Top" mode, each time it is re-launched? – FedKad Jan 10 '24 at 19:06
  • @FedKad I guess that you could change the Exec= line of the application's .desktop file in ~/.local/share/applications to add && sleep 1 && wmctrl -r :ACTIVE: -b toggle,above" wrapped in sh -c "". For example, to make Nautilus always on top when launched, you would change its Exec= line to Exec=sh -c "nautilus --new-window %U && sleep 1 && wmctrl -r :ACTIVE: -b toggle,above". You may have to adjust the sleep duration. Use cp /usr/share/applications/application.desktop ~/.local/share/applications/ to copy an application's .desktop file to ~/.local/share/applications/. – BeastOfCaerbannog Jan 10 '24 at 21:05
  • @FedKad I think that this would also be nice as a new question and maybe someone could have a better approach than mine. – BeastOfCaerbannog Jan 10 '24 at 21:07
1

From command line? If so, you need wmctrl.
In it's most simple form:

xwin=$(xwininfo | grep -oP 'Window id: \K0x[0-9a-f]+'); wmctrl -i -r "$xwin" -b add,above

This could serve as a GUI version.
These are the dependencies you will need to install.

sudo apt-get install xdotool xprop wmctrl yad xbindkeys
#!/bin/bash

about_dialog() { yad --window-icon="help-faq" --title="About" --on-top --borders=10 --center --skip-taskbar --image="preferences-system-windows" --buttons-layout="center" --text-align=center --text="Always On Top!\n\nChange selected window's 'state' from\n'Below' to 'Above' & Vice-versa.\n" --button=Close!application-exit!:0 } export -f about_dialog

set_keybinding() { if [ ! -f ~/.ontop_tray_xkbrc ]; then current_binding='[none]' else current_binding=$(sed '2q;d' ~/.ontop_tray_xkbrc) fi

remove_button='rm ~/.ontop_tray_xkbrc; echo "\"bash -c 'toggle_gnome'\"" > ~/.ontop_tray_xkbrc && xdotool windowkill window="cat /tmp/xwin_id_xkb" && bash -c set_keybinding'
show_current=$(echo "$current_binding")

yad --window-icon="input-keyboard" --borders="15" --on-top --skip-taskbar --title="Key Binding" \
    --text-align="center" --buttons-layout="center" --text="Current Binding\n$show_current\n" \
    --separator=" " --item-separator=" " --print-xid="/tmp/xwin_id_xkb" --form  \
    --field="Hold 1:":CB "Ctrl Alt Shift" \
    --field="Hold 2:":CB "Shift Ctrl Alt" \
    --field="Action:":entry "T" \
    --field=Remove-Binding:BTN "bash -c '$remove_button'" \
    --button=Confirm:0 \
    --button=Cancel:1 > /tmp/entries

if [ $? -ne 0 ]; then
    exit 1
fi

entries=$(cut -d'|' -f1 < /tmp/entries)

f1=$(echo "$entries" | awk '{print $1}')
f2=$(echo "$entries" | awk '{print $2}')
f3=$(echo "$entries" | awk '{print $3}')

key_combo=$(echo "$f1+$f2+$f3" | tr ' ' '+')

if [ ! -f ~/.ontop_tray_xkbrc ]; then
    echo "\"bash -c 'toggle_gnome'\"" > ~/.ontop_tray_xkbrc
fi

echo "$key_combo" > ~/.ontop_tray_xkbrc

# Restart xbindkeys
killall xbindkeys 2> /dev/null
xbindkeys --file ~/.ontop_tray_xkbrc

} export -f set_keybinding

tmp_error() { yad --skip-taskbar --on-top --window-icon="gtk-error" --title="Write Error" --image="gtk-error"
--button="Quit":1
--text="Unable to write to /tmp\nCheck permissions for $USER." exit 1 } export -f tmp_error

error_control() {

Workaround: Clicking OSK's enter-key will cause crosshair failure.

wmctrl, xdotool & xprop—all fail with 'onboard' OSK.

yad --skip-taskbar --on-top --window-icon="dialog-question" --title="Retry?" --image="dialog-question" \
    --button="Try Again":0 \
    --button="Quit":1 \
    --text="Failed to focus on the window.\nDo you want to retry?" \

response=$?

if [ $response -eq 0 ]; then
            select_window
else
    exit 1
fi

} export -f error_control

select_window() { xdotool selectwindow > /tmp/xwin_id

    if [ $? -ne 0 ]; then
        error_control
    fi

    if [ ! -f /tmp/xwin_id ]; then
    tmp_error
    fi

    wmctrl -i -r "$(sed '1q;d' /tmp/xwin_id)" -b add,above

} export -f select_window

select_new() { wmctrl -i -r $(sed '1q;d' /tmp/xwin_id) -b remove,above rm /tmp/xwin_id select_window } export -f select_new

toggle_gnome() { toggle_xwin_id=$(</tmp/xwin_id) xprop -id "$toggle_xwin_id" > /tmp/xwin_state check_state=$(cat /tmp/xwin_state | grep -q "_NET_WM_STATE(ATOM) = _NET_WM_STATE_ABOVE")

if [ $? -eq 0 ]; then
    wmctrl -i -r &quot;$toggle_xwin_id&quot; -b remove,above
else
    wmctrl -i -r &quot;$toggle_xwin_id&quot; -b add,above
fi

} export -f toggle_gnome

select_window

Tray Icon & Menu

yad --notification --skip-taskbar --image="go-top"
--command="bash -c 'about_dialog'"
--menu=" Toggle !bash -c 'toggle_gnome'
| Select !bash -c 'echo "1" >> /tmp/xwin_id; select_new'
| Keybind !bash -c 'set_keybinding'
| Exit !bash -c 'wmctrl -i -r $(sed '1q;d' /tmp/xwin_id) -b remove,above && killall yad'"
--text="Always On Top!"

exit 0

It will prompt to choose a window. Right click the tray icon to: Toggle (on/off), Select different "Always On Top" window & Keybind to set hotkey for toggling.

Save to: ontop_tray_icon.sh
Change mode to executable: chmod +x ontop_tray_icon.sh
Usage: ./ontop_tray_icon.sh

  • 1
    This seems a bit overkill since the always on top functionality is already builtin on GNOME, but may be useful for other DEs. However, the script in its current form doesn't work. You don't seem to call the focus_window() function somewhere. Also, your script uses yad and wmctrl, which are not installed by default, so you should add instructions for how to install them. You should also add instructions for how to run the script. – BeastOfCaerbannog Jan 05 '24 at 21:14
  • Okay. I will do those things. It's not a big deal to delete, but if it will help someone? I'll even make it install the dependency's. – JayCravens Jan 05 '24 at 21:23
  • No, I didn't comment to make you delete the answer! Feel free to keep it as long as you make it work! Even if it is for your own learning, it is still useful and perfectly acceptable if it works at the end! Choice is always welcome! :) – BeastOfCaerbannog Jan 05 '24 at 21:29
  • It works after your last edit and even the option I mentioned in my answer shows as selected! However, I don't get any yad window. Also how can it be turned off so that the selected window becomes normal again? – BeastOfCaerbannog Jan 05 '24 at 21:33
  • Excellent! Right click the tray icon to adjust it. – JayCravens Jan 05 '24 at 21:36
  • You know what, I thought of a usecase where this could be really handy: have it as a keyboard shortcut that toggles the state of the currently active window. Assigning it to, say, Super+T it will be much faster to make a window stay on top than having to use the mouse. Excellent for people that would use this functionality a lot. Could you adjust your script to make it work that way? – BeastOfCaerbannog Jan 05 '24 at 21:38
  • I don't get a tray icon. Do you use GNOME? – BeastOfCaerbannog Jan 05 '24 at 21:39
  • Is it just the green liquid beaker? I chose the big gold star for no particular reason. Across versions, icon names vary some. Use yad-icon-browser to find one you like and change "starred" in --image="starred" to the name in the icon browser. And, yes sir, I'll add a toggle to the menu + key binding. – JayCravens Jan 05 '24 at 21:44
  • @BeastOfCaerbannog Got it! Let me know if you have any problems. – JayCravens Jan 06 '24 at 22:36
  • Is there a reason this code is constantly being edited? Ask Ubuntu is not a code repository, you might want to consider putting your script on Github or a Gist or something instead of using Ask Ubuntu as a code repository. – Thomas Ward Jan 10 '24 at 20:21
  • @ThomasWard There is. It's finished now. https://chat.stackexchange.com/rooms/150683/discussion-between-beastofcaerbannog-and-j-cravens – JayCravens Jan 10 '24 at 22:09