7

I rely on wmctrl a lot to switch between windows, basically to avoid typing alt-tab many times. I've always used one workspace but now I want to begin using more than one.

I was wondering if it is possible to modify the context of wmctrl so that when I type wmctrl -l, only windows from the current workspace are shown, instead of all windows from all workspaces.

For example, assuming I have a Firefox window opened in workspace 1. I have a keyboard shortcut on ctrl+alt+f that executes wmctrl -a firefox, which switches to Firefox. If I open a new Firefox window on workspace 2 and type ctrl+alt+f, it will switch to the window at workspace 1, which is not what I want.

Any suggestions/ideas on how to solve this?

EDIT: I'm using compiz (Unity)

ivotron
  • 303

2 Answers2

5

If you're using Compiz (run wmctrl -m if not sure), wmctrl only sees 1 desktop (2nd field of wmctrl -l, ie 0) but you can use the geometry (-G) option to know what window is on what virtual desktop. All windows in your current desktop will have an x-position between 0 and your screen's width. Same for the y-position between 0 and your screen's height. So you can use something like that

#!/bin/bash

SCREEN_W=$(xwininfo -root | sed -n 's/^  Width: \(.*\)$/\1/p')
SCREEN_H=$(xwininfo -root | sed -n 's/^  Height: \(.*\)$/\1/p')

NAME='Navigator.Firefox'

wmctrl -xlG | awk -v W="$SCREEN_W" -v H="$SCREEN_H" -v NAME="$NAME" '$7==NAME && $3>=0 && $3<W && $4>=0 && $4<H {print $1}' | while read WINS; do wmctrl -ia "$WINS"; done

exit 0

You can hardcode your screen's width and height if you will, and NAME if you want a one-liner. Im not sure how you want to handle multiple windows matching NAME. That will focus them all.

For metacity, desktop number of windows can be found using wmctrl -l and grepping the 2nd field.

user55822
  • 3,245
0

I have the answer for 2022, it's quite powerful one based on The newest wmctrl logic, welp it mimics autohotkey on windows

So first we need to get the active desktop / workspace

wmctrl -d | grep "*" | awk --field-separator="  "  '{print $1}'

After that, you can piece it to get the list ONLY Window on That desktop

D=$(wmctrl -d | grep "*" | awk --field-separator="  "  '{print $1}')
WINNAME="GVIM"
# Or you can get the full name as hex, more accurate for same window name
WIN=$(wmctrl -l | grep "  $DESKTOP " | grep -i $WIN | awk '{print $1}')
# WIN will be filled with 0xYYYY ID in hex or use simple winname
IN=$(wmctrl -l | grep "  $DESKTOP " | grep -i gvim | awk --field-separator="$(hostname) " '{print $2}')
# Get the number of window contain it's name
STATUS=$(wmctrl -l | grep "  $DESKTOP " | grep -i $WINNAME | wc -l)

Then you can check it using if like this (For winname)

if [ $STATUS -gt 0 ]
then
   activeWindow=$(xprop -id $(xprop -root _NET_ACTIVE_WINDOW | cut -d ' ' -f 5) WM_NAME | cut -d '"' -f 2)      
   # zenity --notification --text="$activeWindow"
   if [[ $activeWindow =~ "$WINNAME" ]]
   then
       wmctrl -r "$WIN" -b toggle,hidden
   else
       wmctrl -a "$WIN"
   fi
else
   /usr/bin/gvim # if the app hasn't started yet, start it
fi

OR

For Hex ID

# ... output omitted
   if [[ $activeWindow =~ "$WINNAME" ]]
   then
       wmctrl -i -r "$WIN" -b toggle,hidden
   else
       wmctrl -i -a "$WIN"
   fi
# ... output omitted, see source before

So if you piece it all together (for using window name, this is not bullet prof as if has same name between workspace, well, it will follow the other workspace)

#!/bin/bash

DESKTOP=$(wmctrl -d | grep "*" | awk --field-separator=" " '{print $1}') STATUS=$(wmctrl -l | grep " $DESKTOP " | grep -i gvim | wc -l) WIN=$(wmctrl -l | grep " $DESKTOP " | grep -i gvim | awk --field-separator="$(hostname) " '{print $4}')

zenity --notification --text="$STATUS $DESKTOP $WIN"

if [ $STATUS -gt 0 ] then activeWindow=$(xprop -id $(xprop -root _NET_ACTIVE_WINDOW | cut -d ' ' -f 5) WM_NAME | cut -d '"' -f 2)

zenity --notification --text="$activeWindow"

if [[ $activeWindow =~ "GVIM" ]] then wmctrl -r $WIN -b toggle,hidden else wmctrl -a $WIN fi else /usr/bin/gvim fi

OR BULLET PROF using HEX ID

#!/bin/bash

DESKTOP=$(wmctrl -d | grep "*" | awk --field-separator=" " '{print $1}') STATUS=$(wmctrl -l | grep " $DESKTOP " | grep -i gvim | wc -l) WIN=$(wmctrl -l | grep " $DESKTOP " | grep -i gvim | awk '{print $1}') #zenity --notification --text="$WIN" if [ $STATUS -gt 0 ] then activeWindow=$(xprop -id $(xprop -root _NET_ACTIVE_WINDOW | cut -d ' ' -f 5) WM_NAME | cut -d '"' -f 2)
#zenity --notification --text="$STATUS $DESKTOP &quot;$WIN&quot; $activeWindow" if [[ $activeWindow =~ "GVIM" ]] then wmctrl -i -r "$WIN" -b toggle,hidden else wmctrl -i -a "$WIN" fi else /usr/bin/gvim fi

-i in man wmctrl means :

-i Interpret window arguments () as a numeric value rather than a string name for the window. If the numeric value starts with the prefix '0x' it is assumed to be a hexadecimal number

You can get window toggle like AHK Script on Windows, but more powerful than it should.

This script tested on XFCE, and works, either Xubuntu 22.04 or Fedora 36.