使用wmcrtl在同一应用程序的窗口中循环

时间:2013-03-02 09:09:49

标签: linux focus keyboard-shortcuts console-application window-managers

我正在配置xbindkeys以使用快捷方式更改窗口焦点。 例如,我设法创建了一个快捷方式,专注于一个应用程序窗口,让我们说一个终结器窗口:

wmctrl -xa terminator

不幸的是,它始终集中在同一个终结器窗口,阻止我循环终止器窗口。

你能否建议我专注于终结者窗口的命令,如果再次按下,会循环遍历所有终结器窗口吗?

2013年3月30日更新

我修改了这个脚本 http://lars.st0ne.at/blog/switch%20between%20windows%20within%20the%20same%20application 制作一个

的脚本
script.sh NAME

专注于应用程序NAME或循环浏览NAME的所有窗口,如果它的窗口已经聚焦,但它无法正常工作。

这是脚本

win_class=$1 # 'terminator' # $1

# get list of all windows matching with the class above
win_list=$(wmctrl -x -l | grep -i $win_class | awk '{print $1}' )

# get id of the focused window
active_win_id=$(xprop -root | grep '^_NET_ACTIVE_W' | awk -F'# 0x' '{print $2}')

# 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

# switch to window
wmctrl -i -a $switch_to

脚本确实专注于应用程序的窗口,并循环遍历它们直到它到达窗口,我猜最后创建的窗口。那时,骑自行车已不再适用了。

4 个答案:

答案 0 :(得分:5)

如果没有窗口有焦点,我在脚本中发现了一个问题。

您可以尝试以下修改后的脚本:

#!/bin/bash
win_class=$1 # 'terminator' # $1

# get list of all windows matching with the class above
win_list=$(wmctrl -x -l | grep -i $win_class | awk '{print $1}' )

# get id of the focused window
active_win_id=$(xprop -root | grep '^_NET_ACTIVE_W' | awk -F'# 0x' '{print $2}')
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

# switch to window
wmctrl -i -a $switch_to

答案 1 :(得分:1)

在通过st0ne调整脚本之后,我有一个通用的版本(不需要指定app_name)。希望对某人有用。 :)

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

app_name=`wmctrl -lx | grep $active_win_id | awk '{print $3}'`
workspace_number=`wmctrl -d | grep '\*' | cut -d' ' -f 1`
win_list=`wmctrl -lx | grep -ri $app_name | grep " $workspace_number " | awk '{print $1}'`

# 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

答案 2 :(得分:0)

该脚本适合我。

无论如何,似乎脚本在你的情况下找不到活动窗口。因此,它设法切换到您的应用程序,但无法循环。它切换到$ win_list中的第一个窗口,因为sed命令无法从$ win_list中删除活动窗口(以及之前的所有列表条目)。

尝试以下命令:

xprop -root _NET_ACTIVE_WINDOW

输出应该是这样的:

_NET_ACTIVE_WINDOW(WINDOW): window id # 0x2400005

属性“_NET_ACTIVE_WINDOW”是 EWMH 标准的一部分。见:http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html

也许您正在使用非 EWMH (扩展窗口管理器提示)兼容窗口管理器! 您使用的是哪种WM?

...某些窗口管理器允许通过配置或插件启用EWMH兼容性。

答案 3 :(得分:0)

我在tkt028's answer上遇到了一个小问题 1 ,但是我喜欢他们在处理任何通用应用程序方面的工作。但是我也很喜欢st0ne's answer如何处理特定命名的应用程序的窗口中的循环。所以我结合了这些方法。

我的脚本采用一个可选的第一个参数来指定一个应循环运行其窗口的应用程序。如果没有找到这样的窗口,并且提供了可选的第二个参数,它将退回到启动由第二个参数指定的命令。

如果根本不提供任何参数,那么它将仅循环浏览当前活动应用程序的窗口。

#!/bin/bash

if [[ "$1" == "-h" || "$1" == "--help" ]]; then
    echo "Cycle through windows of the active, or specified, application."
    echo ""
    echo "Usage: $(basename $0) [window_class_name [application_launcher]]"
    echo ""
    echo "  window_class_name:    regex string specifying an application's window name,"
    echo "                        as specified by the third column of"
    echo "                        'wmctrl -l -x'"
    echo "  application_launcher: application to optionally launch if no windows"
    echo "                        matching window_class_name are found"
    echo ""
    echo "If no arguments are specified, cycles through the windows of the active application."
    exit
fi

# get ID of active window
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 [[ -n "$1" ]]; then
    # get app name from input argument
    app_name="$1"
else
    # get corresponding app name
    app_name="${app_name:-$(wmctrl -lx | grep $active_win_id | awk '{print $3}')}"
fi

# get active workspace number
workspace_number=`wmctrl -d | grep '\*' | cut -d' ' -f 1`

# get list of windows corresponding to the desired app
win_list=`wmctrl -lx | grep -i $app_name | grep " $workspace_number " | awk '{print $1}'`

# get next window of app to focus on
#
# (Parses $win_list as a single string, removing everything except the token
# after the active ID. If active ID is sole token or last token, string will be
# left unmodified, producing an array from which we'll extract the first element.)
# Note: If active window was not of class app_name, then this will end up
#       selecting the first window of app_name, if running. Otherwise, we'll fall
#       through to launching a new instance of the app in the else of the next block.
switch_to=($(echo $win_list | sed "s/.*\<\(0x0\+\)\?$active_win_id\>\s*\(\<0x[0-9a-f]\+\>\).*/\2/"))

# if we have a valid window to switch to, do so
if [[ -n "${switch_to}" ]]; then
    wmctrl -ia "${switch_to[0]}"
    exit $?
else
    # if the user specified a fallback application to run if target window
    # was not found, try to launch it
    if [[ -n "$2" ]]; then
        $2 &
        # check whether process corresponding to PID of background
        # process we just launched is still running
        ps -p $! > /dev/null
        exit $?
    else
        exit $?
    fi
fi

1 tkt028的答案中此行的递归grep在我的环境中不起作用。也许取决于您的grep版本。

win_list=`wmctrl -lx | grep -ri $app_name | grep " $workspace_number " | awk '{print $1}'`

我只是从r中删除了grep自变量,然后他们的脚本像宣传的那样工作。

win_list=`wmctrl -lx | grep -i $app_name | grep " $workspace_number " | awk '{print $1}'`