让 wmctrl 忽略当前工作区以外的窗口

让 wmctrl 忽略当前工作区以外的窗口

我经常使用 wmctrl 在窗口之间切换,主要是为了避免多次输入 alt-tab。我一直使用一个工作区,但现在我想开始使用多个工作区。

我想知道是否可以修改 wmctrl 的上下文,以便当我键入时wmctrl -l,只显示当前工作区的窗口,而不是所有工作区的所有窗口。

例如,假设我在工作区 1 中打开了一个 Firefox 窗口。我有一个键盘快捷键,ctrl+alt+f执行wmctrl -a firefox,它会切换到 Firefox。如果我在工作区 2 上打开一个新的 Firefox 窗口并输入ctrl+alt+f,它会切换到工作区 1 的窗口,这不是我想要的。

关于如何解决这个问题有什么建议/想法吗?

编辑:我正在使用 compiz (Unity)

答案1

如果您使用的是 Compiz(wmctrl -m如果不确定,请运行),wmctrl 只能看到 1 个桌面(wmctrl -l 的第二个字段,即 0),但您可以使用 geometry (-G) 选项来了解哪个窗口在哪个虚拟桌面上。当前桌面上的所有窗口的 x 位置都在 0 和屏幕宽度之间。y 位置在 0 和屏幕高度之间也是如此。因此,您可以使用类似的东西

#!/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

您可以对屏幕的宽度和高度进行硬编码(如果您愿意的话),如果您想要一行代码,也可以对 NAME 进行硬编码。我不确定您想如何处理与 NAME 匹配的多个窗口。这将使它们全部聚焦。

对于 metacity,可以使用wmctrl -l并 grep 第二个字段来找到桌面窗口的数量。

答案2

我有 2022 年的答案,它基于最新的 wmctrl 逻辑,非常强大,它模仿了 Windows 上的自动热键

因此,首先我们需要获取活动桌面/工作区

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

之后,你可以将其拼凑起来以获取该桌面上的唯一窗口列表

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)

然后你可以像这样使用 if 检查它(对于 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

或者

对于十六进制 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

所以如果你把它们拼凑在一起(对于使用窗口名称,这不是项目符号,因为如果工作区之间有相同的名字,那么它将遵循其他工作区)

#!/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

或使用十六进制 ID 进行 BULLET PROF

#!/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 \"$WIN\" $activeWindow"
   if [[ $activeWindow =~ "GVIM" ]]
   then
       wmctrl -i -r "$WIN" -b toggle,hidden
   else
       wmctrl -i -a "$WIN"
   fi
else
   /usr/bin/gvim
fi

-iman wmctrl表示:

-i 将窗口参数 () 解释为数值而不是窗口的字符串名称。如果数值以前缀“0x”开头,则假定为十六进制数

您可以获得类似 Windows 上的 AHK 脚本的窗口切换,但功能比它应有的更强大。

该脚本已在 XFCE 上测试,并且可在 Xubuntu 22.04 或 Fedora 36 上运行。

相关内容