Ubuntu – How to make Alt+Tab return to same application window as last used (Unity)

14.04application-switcherunity

Using Alt +Tab normally does what I want; it groups windows from the same application. If I want to switch between windows of one and the same application, I use Alt +`

However, if I have multiple terminal windows open (for example), and I use Alt +Tab to switch to another application, and then switch back to the terminal, another terminal window is in front than the last one.

How do I force it to always return to the same application window, like gnome 3 does?

Ubuntu 14.04 unity.

Best Answer

Below a script that switches through application windows. It remembers the last used (= frontmost) window of all running applications, bypassing other windows of the same application.

The script is based on the same principle as the scripts here, but since the script only runs when a key combination is pressed, the last used window (per application) needs to be stored and read outside the script(-'s memory).

How to use

  • The script uses wmctrl

      sudo apt-get install wmctrl
    
  • Copy the script below into an empty file, same it as alternative_switcher.py

  • Add it to a shortcut key combination: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command:

      python3 /path/to/alternative_switcher.py
    
  • Use it as an alternative switcher with your key combination.

Note

The script switches among "normal" application windows, as defined as: "_NET_WM_WINDOW_TYPE_NORMAL" in the output of the xprop -id <window_id> command. That means that dialogue windows will be excluded from the window list, as well as Idle windows for example, which have pid 0.

The script

#!/usr/bin/env python3
import subprocess
import os
import getpass

home = os.environ["HOME"]
lastdir = home+"/.config/alternative_switcher"; wlist = lastdir+"/"+"wlist.txt"

def get(command):
    return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")

def get_frontmost():
    cmd = "xprop -root"
    frontmost = [l for l in get(cmd).splitlines() if\
                 "ACTIVE_WINDOW(WINDOW)" in l][0].split()[-1]
    return frontmost[:2]+"0"+frontmost[2:]
# read last used windowlist
if not os.path.exists(lastdir):
    os.makedirs(lastdir)
try:
    with open(wlist) as src:
        windowlist = eval(src.read())
except (FileNotFoundError, SyntaxError):
    windowlist = []
# creating window list: id, application name
w_data = [l.split()[0:7] for l in get("wmctrl -lpG").splitlines()]
[windowlist.remove(w) for w in windowlist if not w[1] in [data[0] for data in w_data]]
windows = [[get("ps -u "+getpass.getuser()+" | grep "+w[2]).split()[-1], w[0]]
           for w in w_data if "_NET_WM_WINDOW_TYPE_NORMAL" in get("xprop -id "+w[0])]
# get frontmost window + application
frontmost = [data for data in windows if data[1] == get_frontmost()][0]
[windowlist.remove(item) for item in windowlist if item[0] == frontmost[0]]
# add frontmost to  windowlist of last-used application windows
windowlist.insert(0, frontmost)
current_app = frontmost[0]
# determine next application
apps = sorted(set([w[0] for w in windows]))
next_app_i = apps.index(current_app)+1
if next_app_i == len(apps):
    next_app_i = 0
next_app = apps[next_app_i]
# find matching window to raise
try:
    next_w = [w[1] for w in windowlist if w[0] == next_app][0]
except IndexError:
    next_w = [w[1] for w in windows  if w[0] == next_app][0]
# write last- window list
with open(wlist, "wt") as out:
    out.write(str(windowlist))
# raise next window
cmd = "wmctrl -ia "+next_w
subprocess.Popen(["/bin/bash", "-c", cmd])