image of the blog
ShadowThink Logo

Awesome-like Window Switching

Motivation

Differing from Windows and MacOS, Linux is highly customizable for its desktop environment. In the desktop environment, window manager plays a crucial role in controlling the placement and appearance of windows and the interaction when you switch, preview, or hide windows. Unconsciously, these interactions through window manager steal your time especially when you use multiple windows on multiple screens using mouse extensively. Developers prefer to work in this mode. Fortunately, some excellent window managers are developed to alleviate this issue. Awesome is a representative one. However, naively using Awesome on laptop disables my favorite touchpad gestures tool, libinput-gestures. Thus, I decided to write a small tool to mimic window switching shortcuts in Awesome window manager.

As a dynamic window manager, Awesome inherently has some features from both tiling and floating window managers. For me, I prefer its two major features, tilling layout switching and window switching. In this post, I mainly discuss window switching because tilling layout switching is a special feature on tiling mode and it is hard to mimic using floating window manager (i.e., Mutter for GNOME).

Window Switching in Script

Inspired by libinput-gestures, I use wmctrl to interact with the window manager. In following sections, I first introduce how to get windows list and parse previous and next windows to their proper window titles. Then finish the script to support quickly switch to previous, next or target window.

Getting Windows

For wmctrl, windows are represented by window title, id, etc. To get the windows list, the main idea is to use wmctrl -l. However, there are many facets to consider when you parse windows list. 1) The active desktop and its windows 2) Retrieving with proper window title to avoid conflicts. (After a test, we found that wmctrl CANNOT retrieve window with id while switching to it, but it works with title).

Finally, the bash code snippet to get three key windows including currently active, previous and next window title is shown as follow:

#!/bin/bash
WID=`xprop -root | grep _NET_ACTIVE_WINDOW | head -1 | awk '{print $5}'`
WID="${WID:2}"
ACTIVE_WIN=`wmctrl -lx | grep $WID`
ACTIVE_WIN_ID=`echo $ACTIVE_WIN | awk '{print $1}'`
DESK=`echo $ACTIVE_WIN | awk '{print $2}'`

function get_proper_title() {
  echo $1 | awk '{print $5" "$6" "$7}' | \
    sed -e 's/N\/A//' | \
    sed -e 's/[[:space:]]*$//' | sed -e 's/^[[:space:]]//'
}

if [[ $(wmctrl -lx | awk '$2 == '$DESK | grep -B 1 $ACTIVE_WIN_ID | wc -l) == 2 ]]; then
  PREV_WIN=`wmctrl -lx | awk '$2 == '$DESK | grep -B 1 $ACTIVE_WIN_ID | head -1`
else
  # loop to last window
  PREV_WIN=`wmctrl -lx | awk '$2 == '$DESK | tail -1`
fi
PREV_WIN_TITLE=`get_proper_title "$PREV_WIN"`

if [[ $(wmctrl -lx | awk '$2 == '$DESK | grep -A 1 $ACTIVE_WIN_ID | wc -l) == 2 ]]; then
  NEXT_WIN=`wmctrl -lx | awk '$2 == '$DESK | grep -A 1 $ACTIVE_WIN_ID | tail -1`
else
  # loop to first window
  NEXT_WIN=`wmctrl -lx | awk '$2 == '$DESK | head -1`
fi
NEXT_WIN_TITLE=`get_proper_title "$NEXT_WIN"`

Binding and Switching

After getting the target window to switch, we need to open APIs for real actions. As shown in following code snippet, actions for -p and -n are easy to interpret. For option -t, it accepts an integer number n to represent the n-th window in current active desktop. The script is saved as switch-window.sh in a directory which is included in $PATH.

if [[ $1 == '-p' ]]; then
  wmctrl -a "$PREV_WIN_TITLE"
elif [[ $1 == '-n' ]]; then
  wmctrl -a "$NEXT_WIN_TITLE"
elif [[ $1 == '-t' ]]; then
  TARGET_WIN=`wmctrl -lx | awk '$2 == '$DESK | sed -n $2p`
  TARGET_WIN_TITLE=`get_proper_title "$TARGET_WIN"`
  wmctrl -a "$TARGET_WIN_TITLE"
fi

For the shortcut binding, I use Awesome-like binding, friendly for Vim users:

  • Win + j: wmctrl -n, switch to next window.
  • Win + k: wmctrl -p, switch to previous window.
  • Win + Alt + h: wmctrl -t 1, switch to window 1 on current desktop
  • Win + Alt + j: wmctrl -t 2, switch to window 2 on current desktop
  • Win + Alt + k: wmctrl -t 3, switch to window 3 on current desktop
  • Win + Alt + l: wmctrl -t 4, switch to window 4 on current desktop

Now, you can jump to any window with one action. No repetitive Alt + Tab anymore!