8

I've created some shortcuts mimicking the Unity's Mod4 + num behavior.

wmctrl -xa Sublime || subl

What I don't like, is that once sublime is running, it always focuses the first opened window. I'd like to focus the last "focused" window. Same as in Unity. Is there a flag for that?

mreq
  • 4,932

5 Answers5

15

This script does what you want:

#!/bin/bash

app=$1
workspace=$(wmctrl -d | grep '\*' | cut -d ' ' -f1)
win_list=$(wmctrl -lx | grep $app | grep " $workspace " | awk '{print $1}')

IDs=$(xprop -root|grep "^_NET_CLIENT_LIST_STACKING" | tr "," " ")
IDs=(${IDs##*#})

for (( idx=${#IDs[@]}-1 ; idx>=0 ; idx-- )) ; do
    for i in $win_list; do
        if [ $((i)) = $((IDs[idx])) ]; then
            wmctrl -ia $i
            exit 0
        fi
    done
done

exit 1

EDIT: This script always focuses on the last focused window, as opposed to cycling through the windows in the order they were opened.

EDIT 2: I modified the script (turns out wmctrl and xprop use slightly different formats for displaying hexadecimal numbers).

EDIT 3: app name should be taken from the 3rd column of wmctrl -lx to avoid certain conflicts.

5

I've made a very robust app switcher using wmctrl. Check my Ubuntu Forums post and my askubuntu answer.

This is the script to launch:

#!/bin/bash
app_name=$1
workspace_number=`wmctrl -d | grep '\*' | cut -d' ' -f 1`
win_list=`wmctrl -lx | grep $app_name | grep " $workspace_number " | awk '{print $1}'`


active_win_id=`xprop -root | grep '^_NET_ACTIVE_W' | awk -F'# 0x' '{print $2}' | awk -F', ' '{print $1}'`
if [ "$active_win_id" == "0" ]; then
    active_win_id=""
fi


# get next window to focus on, removing id active
switch_to=`echo $win_list | sed s/.*$active_win_id// | awk '{print $1}'`
# if the current window is the last in the list ... take the first one
if [ "$switch_to" == "" ];then
    switch_to=`echo $win_list | awk '{print $1}'`
fi


if [[ -n "${switch_to}" ]]
    then
        (wmctrl -ia "$switch_to") &
    else
        if [[ -n "$2" ]]
            then
                ($2) &
        fi
fi


exit 0
mreq
  • 4,932
4

I made a combination of both previous answers which I find quite convenient. It enables to:

  • set the focus to the most recently focused window of the app (answer of Raul Laasner) if that window does not already have the focus;
  • otherwise, cycle to the next window of the app (answer of mreq);
  • if there is no window of the app, open one (there is now an optional second argument which specifies the command to run in that case).

Here is the script:

#!/bin/bash
if [ $# -lt 1 ] ; then
  echo "Usage : $0 <window name> [<command to run if there is no window with that name>]"
  exit 1
fi

app_name=$1

workspace_number=wmctrl -d | grep '\*' | cut -d' ' -f 1 win_list=wmctrl -lx | grep $app_name | grep &quot; $workspace_number &quot; | awk '{print $1}'

Get the id of the active window (i.e., window which has the focus)

active_win_id=xprop -root | grep '^_NET_ACTIVE_W' | awk -F'# 0x' '{print $2}' | awk -F', ' '{print $1}' if [ "$active_win_id" == "0" ]; then active_win_id="" fi

If the window currently focused matches the first argument, seek the id of the next window in win_list which matches it

if [[ "$win_list" == "$active_win_id" ]]; then

# Get next window to focus on 
# (sed removes the focused window and the previous windows from the list)
switch_to=`echo $win_list | sed s/.*$active_win_id// | awk '{print $1}'`

# If the focused window is the last in the list, take the first one
if [ &quot;$switch_to&quot; == &quot;&quot; ];then
    switch_to=`echo $win_list | awk '{print $1}'`
fi

If the currently focused window does not match the first argument

else

# Get the list of all the windows which do
win_list=$(wmctrl -lx | grep $app_name | awk '{print $1}')

IDs=$(xprop -root|grep &quot;^_NET_CLIENT_LIST_STACKING&quot; | tr &quot;,&quot; &quot; &quot;)
IDs=(${IDs##*#})

For each window in focus order

for (( idx=${#IDs[@]}-1 ; idx&gt;=0 ; idx-- )) ; do
    for i in $win_list; do

       # If the window matches the first argument, focus on it
        if [ $((i)) = $((IDs[idx])) ]; then
            wmctrl -ia $i
            exit 0
        fi
    done
done

fi

If a window to focus on has been found, focus on it

if [[ -n "${switch_to}" ]] then (wmctrl -ia "$switch_to") &

If there is no window which matches the first argument

else

# If there is a second argument which specifies a command to run, run it
if [[ -n &quot;$2&quot; ]]
then
    ($2) &amp;
fi

fi

exit 0

Example of usages:

focus_window.sh vlc vlc
focus_window.sh gnome-control-center gnome-control-center
focus_window.sh gnome-terminal gnome-terminal
Zach
  • 195
0

Late for the answer, but managed to do it work gracefully, in my case, using Firefox:

/usr/lib/firefox/firefox && sleep 0.5 && wmctrl -ia $(wmctrl -l Firefox | grep "Mozilla Firefox" | sort -r | head -n 1 | cut -d " " -f 1)

Explanation:

/usr/lib/firefox/firefox - Opens firefox

sleep 0.5 - Gives some time for the window to open

wmctrl -ia - Focus on a specific window ID

$(wmctrl -l Firefox | grep "Mozilla Firefox" | sort -r | head -n 1 | cut -d " " -f 1) - Gets the last window ID, which in my case, is open on the homepage, so its name is "Mozilla Firefox".

0

Keep in mind that if you are working within a virtual environment such as noVNC, you might need to open the Show Extra Keys feature within the Control Bar or similar to activate the Alt key within the environment (see screenshot below). Otherwise when you press the space bar on your keyboard, the menu bar of the web browser or whatever application is running your virtual environment will load, and not the menu of the application you are trying to move within the virtual environment. Also keep in mind that when you press the space bar, you need to have the application you are trying to move within the environment in focus to activate the menu bar and access the Move action (the easiest way to ensure this is to drag the bottom or side edge of the application with your cursor and then press the space bar on your keyboard).

screenshot of