6

Once upon a time there was the fabulous window manager called "enlightenment".

If you used it, and you hit Alt+Tab then you saw a small list of window titles below each other.

Like this:

  • user@remote-host
  • foo@db-server
  • emacs
  • ...

Or like this:

window-switcher-simple-and-beautiful

I liked it a lot.

I want it back. I mean the feature, not the app.

I am using Ubuntu 18.04

I don't want to see icons of applications like this:

alt-tab-is-useless-at-the-moment

I have up to five terminals open. If I press the windows-key I will see the roughly same image (small version of a big terminal) five times.

window-key-icons

It takes time and mental energy to find the right terminal. And I want to switch with the keyboard only, without using the mouse.

The magic behind the terminal:

xtermset -title foo

I have this the bash script which gets executed if I login via ssh.

This way I can distinguish between several terminals easily.

How to get this feature which worked in the year 1998 back?

(Please don't tell me to install the enlightenment window-manager, this question is about a simple feature, not the app)

User "DK Bose" wanted me to show the output of these commands:

===> wmctrl -m
Name: GNOME Shell
Class: N/A
PID: N/A
Window manager's "showing the desktop" mode: N/A
tguettler@aptguettler:~
===> 


tguettler@aptguettler:~
===> wmctrl -lx
0x0200000a  0 desktop_window.Nautilus  aptguettler Schreibtisch
0x01c00178  0 Pidgin.Pidgin         aptguettler tbz
0x02600010  0 Navigator.Firefox     aptguettler command line - List of window names on ALT-Tab - Ask Ubuntu - Mozilla Firefox
0x02200010  0 Mail.Thunderbird      aptguettler Posteingang - tguettler@tbz-pariv.de (IMAP) - Mozilla Thunderbird
0x04400006  0 gnome-terminal-server.Gnome-terminal  aptguettler foooooo
0x044000ce  0 gnome-terminal-server.Gnome-terminal  aptguettler tguettler@aptguettler

The string "foooooo" was set via xtermset -title foooooo. The title was set in a shell which was running ssh on a remote server.

  • 1
    Something like i.stack.imgur.com/59JH3.png? – Justice for Monica Feb 8 at 14:30
  • From this and your previous question I am getting a feeling that somehow you've misunderstood the application-switching feature or using it wrong. Ideally there should not be five terminal icons for five terminal windows. <Alt><Tab> switches between applications whereas <Alt><key-above-Tab> switches between windows of the same application. If you use <Alt><key-above-Tab> you should see small window previews with window titles, à la i2.wp.com/itsfoss.com/wp-content/uploads/2017/10/… – pomsky Feb 8 at 14:46
  • 1
    @pomsky, I stole it from my answer here: askubuntu.com/a/1085193/248158. It's one of many defaults in Kubuntu 18.04 and is not an add-on. – Justice for Monica Feb 8 at 14:57
  • @DKBose yes, the screenshot looks very nice. More is not needed. Simple and beautiful :-) – guettli Feb 8 at 14:57
  • 1
    @pomsky yes, the screenshot by DK is what I would like ALT-TAB to look like. – guettli Feb 9 at 8:33
6
+25

I'm not sure it's advisable to attempt to change the window manager in Ubuntu 18.04. The window manager is integrated into GNOME Shell.

You may find Rofi suitable for the purpose you describe while leaving the system's default intact.

Rofi in window switcher mode

  • Rofi is available in the universe section.

  • It has an installed size of 524 kB and and very few dependencies which you can see by running apt show rofi as well as by simulating its install using apt install -s rofi.

  • Rofi has several functions but the one of interest here is the window switcher.

Once Rofi is installed:

  • Create a folder called rofi in ~/.config.

  • Run rofi -dump-config > ~/.config/rofi/config.rasi to generate a local config file which you can modify to suit your needs.

  • Preview the theme you'd like to use by running rofi-theme-selector. If you want to tweak the theme further, you could copy the theme over from /usr/share/rofi/themes to ~/.config/rofi and give it a new name to avoid confusion. I like Pop-Dark and named the local version myPop-Dark. In the images posted in this answer, I've used myPop-Dark.

Usage

To demonstrate Rofi's use as an alternative to the system's Alt+Tab:

  • I opened several windows including five xterm windows. (I opened GNOME terminal and ran nohup xterm -xrm 'XTerm.vt100.allowTitleOps: false' -T whatever & as based on the accepted answer in Simply set xterm title.)

  • I assigned Ctrl+Win+R as a shortcut keyboard combination to run rofi -show window -theme myPop-Dark

In the image posted above, there are three columns. If you always want only the name of the application and the title of the window, edit ~/.config/rofi/config.rasi to change the commented out window-format line to

window-format: "{n}    {t}";

You can also modify the width, the height, and the location of the rofi window.

To bring the window you want into focus, use the arrow keys or your mouse pointer to highlight the entry and then press Enter.

If you have a really long list of windows, press a key that's unique to the window you want to filter out all other windows. If that's not possible, filter the entries by typing, as in the animation below, f, followed by o to limit the list to windows containing the string "foo".

The animation below illustrates that.

filtering windows

To close a highlighted window, press Shift+Delete.

  • The link was initial broken. I updated the answer. To make AskU happy I added more characters. Unfortunately I can't remove them again. useless constraint. Sometimes patches containing on changed character are important - useless feature of AskU – guettli Feb 13 at 14:20
5

Ubuntu, including 18.04, is now based on GNOME and some additional features could be made available via GNOME Shell Extensions. Go to the website and search: use "window switcher" as keywords and the relevant extension may be listed in the first page of search result.

This one seems relevant and maintained:

Switcher by dlandau

switcher by dlandau in action

Switch windows or launch applications quickly by typing

Use the configured global hotkey (Super+w by default) to open a list of current windows. Type a part of the name or title of the application window you want to activate and hit enter or click on the item you wish to activate. You can use the arrow keys to navigate among the filtered selection and type several space separated search terms to filter further. Use Esc or click anywhere outside the switcher to cancel.

Use the configured global hotkey (Super+x by default) to open the application launcher. Type a part of the name of the application you want to launch and hit enter. You can use Ctrl+Space or Ctrl+Tab to switch between the switcher and the launcher, or when there are no open windows matching a name but there are apps the mode is switched automatically.

You can customize the look and feel and functionality in the preferences.

Extension Homepage: https://github.com/daniellandau/switcher

Shell version: 3.30 3.28 3.26 3.24 3.22 3.20 3.18 3.16.3 3.16 3.14

To bind the common keyboard shortcut Alt+Tab or Super+Tab with this extension, user may be required to use a workaround. A GitHub user, PHLAK, has submitted this issue #63 on GitHub and also explained the workaround in several comments:

I would like to bind the Switcher to Super + Tab but am unable to. I've also noticed I cannot bind it to Alt + Tab either.


I was able to work around this by setting the value directly with dconf:

dconf write /org/gnome/shell/extensions/switcher/show-switcher "['<Super>tab']"

You can also do the same by using the dconf-config GUI.


You might also have to unbind any pre-configured shortcuts using that key combination. Specifically, "Switch applications" is bound to Super+Tab in Gnome.

You can change this by opening the Settings and navigating to Devices > Keyboard. Then Search for Super+Tab and change or remove this binding.

Disclaimer: I do not use Ubuntu 18.04 or GNOME Shell, so I did not test this extension. I merely quoted the most seemingly reliable resources found on the web. The screenshot was redone and optimized (122kB) in GIMP instead, because the original screenshot and the animated image were too large (500kB, 7MB).

TL;DR Go to the GNOME Shell Extensions website and install the extension of choice: Switcher by dlandau. Subject to compatibility with the Shell version.

  • Ubuntu 18.04 uses GNOME Shell 3.28, so the extension is supposedly compatible. – clearkimura Feb 14 at 19:32
  • This is a great answer. But does it fit to the above question? The app you talk about does this: "Switch windows or launch applications quickly by typing". The question is about a simple list of the window titles to switch between windows with alt-tab. – guettli Feb 25 at 12:03
  • Initially, I found "Openboxy Alt-Tab by sharat87" that fits perfectly to the question; however, this extension is unmaintained and compatible with only Shell version 3.10. Hence this answer suggested "Switcher by dlandau" as the closest alternative. – clearkimura Feb 26 at 12:55
  • The described feature is something similar to the traditional smart launcher i.e. Kupfer, GNOME Do, or Launchy: press Alt-<key> or any assigned shortcut, then display a launcher window pop-up (requires to type to find opened windows). In contrast, the Shell extension will display a launcher window pop-up that readily show list of opened windows. The typing or using cursor keys is only required for switching to the target window (the only missing criteria). – clearkimura Feb 26 at 13:10
  • In short: the extension "Switcher by dlandau" will display a simple list of the window titles, but does not switch between windows with the same Alt-Tab. That is the closest you can get on GNOME with Shell extension to this date. – clearkimura Feb 26 at 13:24
4

Textual Alt Tab

A late home-cooked one:

In action

enter image description here

How to set up

The setup exists of two tiny scripts, to be saved into one and the same directory:

script 1

#!/usr/bin/env python3
import gi
gi.require_version("Gtk", "3.0")
gi.require_version('Wnck', '3.0')
from gi.repository import Gtk, Wnck, Gdk
import subprocess

css_data = """
.activestyle {
  background-color: grey;
  color: white;
  border-width: 1px;
  border-radius: 0px;
  border-color: white;
}
.defaultstyle {
  border-width: 0px;
  color: black;
  background-color: white;
}
"""

class AltTabStuff(Gtk.Window):
    def __init__(self):
        # css
        self.provider = Gtk.CssProvider.new()
        self.provider.load_from_data(css_data.encode())       
        Gtk.Window.__init__(
            self, title="AltTab replacement"
        )
        self.curr_index = 0
        self.connect('key-press-event', self.get_key)
        self.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
        self.set_decorated(False)
        buttongrid = Gtk.Grid()
        self.add(buttongrid)
        self.connect("delete_event", Gtk.main_quit)

        wins = get_winlist()
        self.buttonindex = 0
        self.buttonsets = []
        index = 0
        for w in wins:
            button = Gtk.Button("\t" + w.get_name())
            button.set_relief(Gtk.ReliefStyle.NONE)
            buttongrid.attach(button, 0, index, 1, 1)
            index = index + 1
            button.connect("clicked", raise_window, w)
            self.buttonsets.append([button, w])
        self.set_focus()
        self.show_all()
        Gtk.main()

    def set_focus(self):
        for b in self.buttonsets:
            button = b[0]
            self.set_style(button, active=False)
        newactive = self.buttonsets[self.buttonindex][0]
        self.set_style(newactive, active=True)
        n_buttons = len(self.buttonsets)
        self.buttonindex = self.buttonindex + 1
        if self.buttonindex >= n_buttons:
            self.buttonindex = 0

    def set_style(self, button, active):
        st_cont = button.get_style_context()
        if active:
            st_cont.add_class("activestyle")
            st_cont.remove_class("defaultstyle")
        else:
            st_cont.remove_class("activestyle")
            st_cont.add_class("defaultstyle")
        Gtk.StyleContext.add_provider(
            st_cont,
            self.provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
        )

    def get_key(self, val1, val2):
        keyname = Gdk.keyval_name(val2.keyval)
        if keyname == "Tab":
            self.set_focus()
        elif keyname == "Alt_L":
            window = self.buttonsets[self.buttonindex-1][1]
            button = self.buttonsets[self.buttonindex-1][0]
            raise_window(button, window)
        elif keyname == "Escape":
            Gtk.main_quit()


def raise_window(button, window):
    subprocess.Popen(["wmctrl", "-ia", str(window.get_xid())])
    Gtk.main_quit()

def check_windowtype(window):
    try:
        return "WNCK_WINDOW_NORMAL" in str(
            window.get_window_type()
        )
    except AttributeError:
        pass

def get_winlist(scr=None):
    """

    """
    if not scr:
        scr = Wnck.Screen.get_default()
        scr.force_update()
    windows = [w for w in scr.get_windows() if check_windowtype(w)]
    return windows


AltTabStuff()

script 2

#!/bin/bash

dr=`dirname $0`
f=$dr'/alttab_runner'

if ! pgrep -f $f
then
$f
else
echo "runs"
fi

Do the following steps:

  1. Make sure both Wnck and wmctrl are installed:

    sudo apt install python3-gi gir1.2-wnck-3.0 wmctrl
    
  2. Save script 1 into an empty file as (exactly) alttab_runner, script 2 as (exactly) alttab_alternative. make both scripts executable

  3. Disable the existing Alt-Tab:

    gsettings set org.gnome.desktop.wm.keybindings switch-applications '[]'
    
  4. Set the shortcut (exactly) Alt-Tab to run script 2:

    /path/to/alttab_alternative
    

Usage

Press Alt + Tab to call the switcher (as in the picture), release Alt and press Tab to cycle through the windows, press Alt again to pick the selected window from the list.

Escape will dismiss (close) the switcher.

Options

If you'd like different colors, you can play with the css in script 1 to set your own styling.

enter image description here enter image description here

To do so, edit this section, where activestyle is obviously the currently selected item:

css_data = """
.activestyle {
  background-color: blue;
  color: white;
  border-width: 1px;
  border-radius: 0px;
  border-color: white;
}
.defaultstyle {
  border-width: 0px;
  color: black;
  background-color: white;
}
"""

See for Gtk css options here on font and buttons.


EDIT

If you'd like to stick to exactly Alt + Tab, in the exact key behaviour as the usual one, use instead of script one:

#!/bin/bash

dr=`dirname $0`
user=$USER
f=$dr'/alttab_runner'
trg='/tmp/'$user'_alttab_trigger'

if ! pgrep -f $f
then
$f
else
echo "runs"
touch $trg
fi

And instead of script 2:

#!/usr/bin/env python3
import gi
gi.require_version("Gtk", "3.0")
gi.require_version('Wnck', '3.0')
from gi.repository import Gtk, Wnck, Gdk
import subprocess
from threading import Thread
import time
import os

trigger = os.path.join("/tmp", os.environ["USER"] + "_alttab_trigger")

css_data = """
.activestyle {
  background-color: grey;
  color: white;
  border-width: 1px;
  border-radius: 0px;
  border-color: white;
}
.defaultstyle {
  border-width: 1px;
  color: black;
  background-color: white;
}
"""

class AltTabStuff(Gtk.Window):
    def __init__(self):
        # apply css
        self.provider = Gtk.CssProvider.new()
        self.provider.load_from_data(css_data.encode())       
        Gtk.Window.__init__(
            self, title="AltTab replacement"
        )
        self.curr_index = 0
        self.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
        self.set_decorated(False)
        buttongrid = Gtk.Grid()
        self.add(buttongrid)
        self.connect("delete_event", Gtk.main_quit)

        wins = get_winlist()
        self.buttonindex = 0
        self.buttonsets = []
        index = 0
        for w in wins:
            button = Gtk.Button("\t" + w.get_name())
            button.set_relief(Gtk.ReliefStyle.NONE)
            buttongrid.attach(button, 0, index, 1, 1)
            index = index + 1
            button.connect("clicked", raise_window, w)
            self.buttonsets.append([button, w])
        self.set_focus()

        # thread to watch the trigger file
        self.timer = Thread(target=self.wait)
        self.timer.setDaemon(True)
        self.timer.start()

        self.show_all()
        Gtk.main()

    def set_focus(self):
        # rotate the focus + styling
        for b in self.buttonsets:
            button = b[0]
            self.set_style(button, active=False)

        newactive = self.buttonsets[self.buttonindex][0]
        newselected = self.buttonsets[self.buttonindex][1]
        time.sleep(0.03)
        self.set_style(newactive, active=True)
        n_buttons = len(self.buttonsets)
        self.buttonindex = self.buttonindex + 1
        if self.buttonindex >= n_buttons:
            self.buttonindex = 0
        return newselected

    def wait(self):
        """
        wait loop; see if trigger file pops up, or we need to quit on immediate
        key release
        """
        newfocus = self.buttonsets[0][1]
        while True:
            time.sleep(0.05)
            if not self.key_checker():
                # try/except, in case no windows on workspace
                try:
                    self.activate(str(newfocus.get_xid()))
                except TypeError:
                    pass
                Gtk.main_quit()
            if os.path.exists(trigger):
                os.remove(trigger)
                newfocus = self.set_focus()

    def activate(self, arg1, arg2=None):
        # activate the selected window, close preview window
        w = arg2 or arg1
        subprocess.Popen(["wmctrl", "-ia", w])
        Gtk.main_quit()

    def set_style(self, button, active):
        st_cont = button.get_style_context()
        if active:
            # st_cont.add_class(Gtk.STYLE_CLASS_SUGGESTED_ACTION)
            st_cont.add_class("activestyle")
            st_cont.remove_class("defaultstyle")
        else:
            st_cont.remove_class("activestyle")
            # st_cont.remove_class("suggested-action")
            st_cont.add_class("defaultstyle")
        Gtk.StyleContext.add_provider(
            st_cont,
            self.provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
        )


    def key_checker(self):
        # check if keys are in a pressed state
        exclude = ["Button", "Virtual", "pointer"]
        keyboards = [
            k for k in get(["xinput", "--list"]).splitlines()
            if not any([s in k for s in exclude])
        ]
        dev_ids = [[
            s.split("=")[1] for s in k.split() if "id=" in s
        ][0] for k in keyboards]
        pressed = False
        for d in dev_ids:
            if "down" in get(["xinput", "--query-state", d]):
                pressed = True
                break
        return pressed


def get(cmd):
    # just a helper
    try:
        return subprocess.check_output(cmd).decode("utf-8").strip()
    except (subprocess.CalledProcessError, TypeError, UnicodeDecodeError):
        pass


def raise_window(button, window):
    subprocess.Popen(["wmctrl", "-ia", str(window.get_xid())])
    Gtk.main_quit()


def check_windowtype(window):
    try:
        return "WNCK_WINDOW_NORMAL" in str(
            window.get_window_type()
        )
    except AttributeError:
        pass


def get_winlist(scr=None):
    if not scr:
        scr = Wnck.Screen.get_default()
        scr.force_update()
    windows = [w for w in scr.get_windows() if check_windowtype(w)]
    return windows


AltTabStuff()

Setup is exactly as the first version:

  1. Make sure both Wnck and wmctrl are installed:

    sudo apt install python3-gi gir1.2-wnck-3.0 wmctrl
    
  2. Save script 1 into an empty file as (exactly) alttab_runner, script 2 as (exactly) alttab_alternative. make both scripts executable

  3. Disable the existing Alt-Tab:

    gsettings set org.gnome.desktop.wm.keybindings switch-applications '[]'
    
  4. Set the shortcut (exactly) Alt-Tab to run script 2:

    /path/to/alttab_alternative
    
  • 1
    @DKBose Ah, sorry, I was editing exactly at the same time! accidentally overwrote your edit. – Jacob Vlijm Feb 18 at 15:13
  • Hi @DKBose not at my box atm, but did you by any chance forget to make the python script executable or forgot to include the shebang? Both scripts need to be. Looks like bash is trying to interprete python code. No imagemagick involved of course. – Jacob Vlijm Feb 20 at 6:40
  • @DKBose could you run the python scrip with python3 script? Again: the error message even isn't python error code. Bash is trying to run the python code. – Jacob Vlijm Feb 20 at 6:54
  • @DKBose Yep, What I thought, please check your python shebang. You might have missed one character.. Exactly getting your message when I remove !#/usr/bin/env python3 – Jacob Vlijm Feb 20 at 6:59
  • 1
    @DKBose Haha, no problem, glad it works :) – Jacob Vlijm Feb 20 at 8:26
3

I think you are specifically looking for "Cycling through windows in a list" feature that is available in Window Manager Tweaks->Cycling in XFCE.

ALT-TAB Cycling in a List

enter image description here

  • Up to now I am using the default gnome desktop of Ubuntu 18.04. AFAIK xfce is not running on my desktop. Could you please elaborate your answer. Do I need to install linux mint first? – guettli Feb 25 at 12:00
  • No, you would not need to install linux Mint, as XFCE is only a desktop environment as are Gnome,KDE,LXDE etc. You can even do one better, and simply add XFCE to your current Ubuntu distro while keeping your current Gnome, and if give XFCE a try to see if you like it more than Gnome and if not you will be able to switch back fairly seamlessly. – BarBar1234 Feb 27 at 3:02
  • Oh I forgot to include the most important thing, namely the command to run to install XFCE packages. $sudo apt-get update && sudo apt-get install xfce4 . Once packages are installed, reboot, and when you see the login screen you will have another option (likely there will be a drop down combo box near the button to login) to select as far as your desktop environment for the session. – BarBar1234 Feb 27 at 3:07
  • could you please elaborate the consequences this has? If I use xfce, what other things change? I guess I am not running gnome any more. – guettli Feb 27 at 8:36
  • 1
    1, the most noticeable consequence will be visual. Your desktop environment will look different than the current look of Gnome/Unity but you should be able to get used to it fairly quickly. 2. XFCE has the enormous advantages of being very fast, light, and very stable. I actually still have it running on a very old laptop that only has a single core (the other core overheated and went dead) 1.2 GHz Athlon laptop with only 1GB RAM and 5400 HDD without a single issue, and there is no interfacing delay whatsoever. 3. XFCE is highly customizable. If you want a functionality, you can add it. – BarBar1234 Feb 27 at 17:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.