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,125
  • 1
  • 17
  • 13
  • 1
    The only issue is that, besides my laptop's screen (14"), I use a monitor at the lab and another at home, the three of them having distinct resolutions, so the x-position varies depending on which display I'm using. I guess I could define ranges, mmm. Will try it. I wonder if there are alternatives to make wmctlr know the desktop number on compiz – ivotron Oct 01 '12 at 20:06
  • That's what the 2 first lines are for. They get your screen resolution (SCREEN_W: width and SCREEN_H: height) and pass them in awk.. You can either use the code abore for all 3 or use 3 different commands for each of them, ae (1440x900): wmctrl -xlG | awk '$7=="Navigator.Firefox" && $3>=0 && $3<1440 && $4>=0 && $4<900 {print $1}' | while read WIN; do wmctrl -ia "$WIN"; done – user55822 Oct 01 '12 at 20:27
  • i see, cool! that solves my issue then. Thanks! Will work on it and comment back on how it went – ivotron Oct 01 '12 at 22:34
  • @ivotron how did it go? – nutty about natty Oct 06 '16 at 20:47
  • @user55822 How could one move an application from one workspace to another with wmctrl (and compiz)? Could you give an example one-liner and/or script, please please please? – nutty about natty Oct 06 '16 at 20:49
  • @nuttyaboutnatty Yes, this it's what works for me. You invoke it by doing something like ~/.scripts/bringtocurrent Firefox. That'll bring Firefox to the current window. – ivotron Oct 10 '16 at 16:35
  • @ivotron Hmm. That's a start. But what I'm looking for is to have a script / one-liner that would put, say, Firefox on Workspace 1, Geany on Workspace 2, Okular on Workspace 3 and Nautilus on Workspace 4, -- independently of the current Workspace and all "at once" (I don't want to run four separate commands, else I'm quicker using keyboard shortcuts). Could you easily "upgrade" your script? Please... :-) ? – nutty about natty Oct 12 '16 at 09:08
  • ps: a bounty expired on that question last week, but I am more than willing to award one again for a good solution! – nutty about natty Oct 12 '16 at 09:12
  • sorry @nuttyaboutnatty, while I'd love to work on it, I don't have time :-( – ivotron Oct 12 '16 at 17:11
  • @ivotron there's no rush. maybe you could put it on the back-burner for now... ;) – nutty about natty Oct 13 '16 at 08:45
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.