5

I am looking for the keyboard equivalent to pressing mouse middle roller-button while cursor is at window top title bar. This lowers that window so its behind all other windows.

4
  • Lower the frontmost (active) window or, like the "real" button, any window under the cursor? The first one is easy, the last one much more complex... Oct 20, 2015 at 17:07
  • I will take (active) however the mouse technique works for any window, not necessarily the active one Oct 20, 2015 at 17:10
  • I know, but it will probably be hard coded and not available as a separate command :) Oct 20, 2015 at 17:11
  • In Openbox (not the default wm in Ubuntu), you can set a keybind for "focustobottom": openbox.org/wiki/Help:Actions#FocusToBottom
    – DK Bose
    Oct 20, 2015 at 17:20

2 Answers 2

5

A shamlessly dirty solution

To achieve a command that does what you want turns out to be more complicated than it seems at first sight. The issue is to lower the window and maintain the window order (z-wise) at the same time, which seems nearly impossible. Both xdotool and wmctrl provide commands to raise a window, but not to lower a window.

The solution below is a dirty hack/workaround, but it works nicely and reliably nevertheless. It uses both wmctrl and xdotool, which are not on your system by default.

Although the script is run by a keyboard shortcut, it actually does exactly the same as when you middle-click on the top of your window. What it does:

  • It looks up the active window (using xprop -root)
  • Looks up if the window is a "normal" window (unlike e.g. your desktop, which is also listed in wmctrl -lG as a window)
  • If so, it calculates the position of the top of the window, moves the mouse to the calculated position, simulates middle- click and moves the mouse back to where you left it.

This all happens in a split second, so you won't even notice the mouse moving and moving back. The only thing you notice is the window sent to back, which is exactly what you want.

The script

#!/usr/bin/env python3
import subprocess
import time

# find the frontmost window
active = [l for l in subprocess.check_output(["xprop", "-root"]).decode("utf-8").splitlines() \
          if "_NET_ACTIVE_WINDOW(WINDOW)" in l][0].split("#")[-1].strip()
# convert the window-id from xprop- format to wmctrl- format
w_id = active[:2] + str((10-len(active))*"0")+active[2:]
# if the window is a "normal" window, find the window geometry in wmctrl -lG,
# move the mouse to the top of the window and click the middle button
if "_NET_WM_WINDOW_TYPE_NORMAL" in subprocess.check_output(["xprop", "-id", w_id]).decode("utf-8"):
    match = [l for l in subprocess.check_output(["wmctrl", "-lG"]).decode("utf-8").splitlines() if w_id in l][0].split()[2:6]
    current_mousepos = subprocess.check_output(["xdotool", "getmouselocation"]).decode("utf-8").split()
    coords = ([s.replace("x:", "") for s in current_mousepos if s.startswith("x:")][0],
              [s.replace("y:", "") for s in current_mousepos if s.startswith("y:")][0])
    top_x = str(int(int(match[0])+(int(match[2])/2))); top_y = str(int(match[1]) -10)
    # The time.sleep(0.3) possibly needs to be optimized (longer sleep = safer); the 0.3 works fine on my system when used from a keyboard shortcut (which turns out to make a difference...)
    subprocess.Popen(["xdotool", "mousemove", "--sync", top_x, top_y]); time.sleep(0.3)
    # move the mouse back to its original position
    subprocess.Popen(["xdotool", "click", "2"]); time.sleep(0.05)
    subprocess.Popen(["xdotool", "mousemove", coords[0], coords[1]])

How to use

  1. Install both wmctrl and xdotool

    sudo apt-get install xdotool wmctrl
    
  2. Copy the script above into an empty file, save it as sendtoback.py

  3. Test- run the script by opening a terminal, run the command in it:

    python3 /path/to/sendtoback.py
    

    The window should be sent to the background, exactly like you were used to when middle-clicked.

  4. If all works fine, Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command:

    python3 /path/to/sendtoback.py
    

    to a key shortcut of your choice.

Note

In some cases (especially on slower systems), the sleep time in the line:

subprocess.Popen(["xdotool", "mousemove", "--sync", top_x, top_y]); time.sleep(0.3)

needs to be increased. On faster systems, it could be reduced.

1

Gnome provides keybindings via gnome-keybinding-properties in Gnome 2, and via gnome-control-center keyboard in Gnome 3.

In Gnome 2, the default active keybinding that comes close to what you want is

Raise window if it's covered by another window, otherwise lower it

using a shortcut of Win+space


Edit: I'm using mate now, which is a fork of Gnome 2, and using the command line gives me either "Command not found" for gnome-keybinding-properties, or a core dump for gnome-control-center.

But using the UI, the key binding are accessible under System->Control Center->Hardware->Keyboard Shortcuts. It's easiest to collapse the Sound, Desktop, and Accessibility sections, which leaves Window Management. "Raise window if it's covered by another window, otherwise lower it" is in about the middle of the section, and, in Mate, is disabled.

2
  • i dont seem to see that keyboard section there though
    – FantomX1
    Nov 12, 2020 at 19:38
  • @FantomX1 - I'm not exactly sure where your "there" is, but I've updated my answer, and may have clarified things a bit for you.
    – Randall
    Nov 23, 2020 at 16:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .