废话少说,这是一篇在 Linux 下的各个窗口之间快速切换的文章。
假设开发过程中,涉及到以下界面:Terminal, Editor, Browser, 外加一个随便什么鬼玩意儿。例如:某个 PDF 阅读软件,在阅读 PDF.
地球人都知道 ALT TAB, 但是最大的问题是:如果开的多了,你常常需要 ALT + TAB TAB ... 很多次。在 Win 7 下,对于系统托盘,有类似于 Win + 0, Win + 1 的快捷键,我相信很多 Linux 发布版也有类似功能。如果你用的很爽,而且也不打算换发布版,下面不用看了。
我要求所有 UNIX Like 系统都通用 (只要有 X), 即:使用 Linux 下一些最基本的功能来实现。
我要求在任何桌面,按下一个快捷键,会立即弹出我想要的以上任一窗口,再按一次,一定会返回到原来的窗口。例如:我的快捷键是:C-M 立即激活 Terminal (当然,你可以开任意多个 TAB), C-I 会激活到 Emacs 的某个 Frame (或创建一个), C-; 会激活 Firefox.
当然你也可以任意组合,例如:你打开一个 pdf 再看一本书,然后 C-m 切换到 Terminal 下写点东西,然后直接 C-i 打开 Emacs 做点笔记,然后再次 C-i 回到之前的 pdf, C-; 浏览下网页,再次 C-; , 又返回 pdf...
全局
快捷键到一个脚本或命令,他是基于纯 X 的。你甚至不需要 Gnome 或 KDE , 仅仅启动一个 Xterm, 就可以用它。这些公共函数你可以单独放在一个文件中,然后稍后通过 find, 全部 source, 你可以直接放到你的 .bashrc 里面。
第一个函数主要用来获取某个窗口的 id , 名称之类的信息,我的函数是这样的
function GET_CURRENT_FRAME_VARIABLE () {
if [ $(uname -o) != Cygwin ]; then
CURRENT_WND_ID=$(xprop -root _NET_ACTIVE_WINDOW 2>/dev/null |cut -d ' ' -f 5|cut -d"," -f1) &&
CURRENT_WND_NAME=$(xprop -id $CURRENT_WND_ID _NET_WM_NAME 2>/dev/null |cut -d '"' -f2) &&
echo "[0m[32m($CURRENT_WND_ID)[0m"
[ $(xprop -id $CURRENT_WND_ID WM_WINDOW_ROLE |cut -d'"' -f2) == "xfce4-terminal-dropdown" ] &&
DROPDOWN_TERMINAL=true
return 0
fi
return 1
}
export -f GET_CURRENT_FRAME_VARIABLE
CURRENT_WND_ID 获取任意窗口的 ID CURRENT_WND_NAME 获取对应名称。
最后一段,是判断当前 Terminal 窗口是不是 xfce4-terminal-dropdown. 之所以这样做,是我可能会开两个 Terminal, 一个非 dropdown, 一个 dropdown, 标题一模一样。只能通过这种方式判断了。如果当前 Terminal 是 dropdown, 那么返回一个值为 true 的变量 DROPDOWN_TERMINAL, 否则变量值为空。
记得写完后,source .bashrc
第二个函数是一个通用模板,其中保存了一大坨用来切换窗口的公共代码
function switch_to () {
GET_CURRENT_FRAME_VARIABLE &>/dev/null
eval local $2_wnd_id=$(cat $SHM_TMP/.$2_wnd_id) &>/dev/null
eval local before_$2_wnd_id=$(cat $SHM_TMP/.before_$2_wnd_id) &>/dev/null
if [ $CURRENT_WND_ID == "$(eval echo \${$2_wnd_id})" ]; then
wmctrl -i -a "$(eval echo \${before_$2_wnd_id})"
elif [ "$(egrep -e "$1" <<< "$CURRENT_WND_NAME")" -a $CURRENT_WND_ID != "$(eval echo \${$2_wnd_id})" ]; then
echo $CURRENT_WND_ID > $SHM_TMP/.$2_wnd_id &&
wmctrl -i -a "$(eval echo \${before_$2_wnd_id})"
else
[ "$DROPDOWN_TERMINAL" ] || echo $CURRENT_WND_ID > $SHM_TMP/.before_$2_wnd_id
[ $CURRENT_WND_ID != "$(eval echo \${$2_wnd_id})" ] && wmctrl -i -a "$(eval echo \${$2_wnd_id})" ||
wmctrl -a "$1" &>/dev/null || exec ${@:3} &
fi
}
export -f switch_to
这逻辑稍稍有点杂乱,但是基本原理可以说下,不过提前声明,你完全可以无视这一坨代码,你只要稍后按照我的方式调用即可。
1) 如果不是 Emacs 窗口,那么首先保存当前窗口的 id 到 $SHM_TMP 目录下的某个文件中. 2) 切换到之前保存的 id 对应的窗口,如果不成功,尝试选择一个,还不行,新启动一个。 3) 切换成功之后,将激活的这个 Emacs 窗口 id 保存起来。 4) 如果是原先的 Emacs 窗口,切换回到来之前的窗口。 5) 如果是一个新的 Emacs 窗口 (我常常会存在多个), 那么将新的窗口 id 存起来。稍后快捷键就在新的窗口和原窗口之间切换了。
大概懂点编程的人应该都可以看个大概懂了...
几个地方稍稍提下:
1) GET_CURRENT_FRAME_VARIABLE 调用的之前定义的那个函数. 2) $SHM_TMP 是我的一个全局变量,我设的是 /dev/shm, 你也可以设 /tmp, 随你. 3) wmctrl -i -a 是切换到 id, 格式大概为:0x03e00075, 你可以 wmctrl -l 看看. wmctrl -a 是按照名字切换,可以模糊匹配。
home 下面新建一个 .xbindkeysrc, 加入以下内容:
☠ # cat emacs_frame
"switch_to_firefox"
Control + semicolon
"emacs_frame"
Control + i
然后启动 xbindkeys &
启动 daemon. 你应该将这个加到 .bashrc 当中,让它自动启动。
因为有了上面那一坨公共逻辑代码,脚本写起来就很简单了,只需要一行。
☠ # cat emacs_frame
#!/bin/sh
emacs_frame_pattern=$($MY_EDITOR -e '(concat " " "-" " " invocation-name "@" system-name)'|sed 's#"##g')
switch_to "$emacs_frame_pattern" "emacs" "$MY_EDITOR -nc --eval (nav)"
☠ # cat switch_to_firefox
#!/bin/sh
# 使用方式: switch_to '标题模板' ' 关键字' '调用的命令'
switch_to 'Mozilla Firefox' "firefox" "firefox $@"
最后,重要的一点:记得给这个文件加 x 执行属性。chmod +x emacs_frame switch_to_emacs.
完了,写了一堆,其实一点都不复杂... 写到这里,其实你也看出来了,dropdown 的 Terminal, 并非必须的。你完全可以将 Terminal 放到一个新的 Workspace, 来达到同样的 (当未激活时,完全隐藏窗口) 效果,只不过,少了 dropdown 特效而已。
好吧,我有理由相信在 Apple 占大多数的咱社区,对这文章有兴趣的不多,如果你觉得没什么用,嘴下留情呀。也许有人觉得有用呢?