开发工具 Linux 窗口之间快速切换 - 加速你的开发效率!

zw963 · 2013年10月12日 · 最后由 sanivbyfish 回复于 2013年10月15日 · 15968 次阅读

废话少说,这是一篇在 Linux 下的各个窗口之间快速切换的文章。

先说下 Spec.

  1. 假设开发过程中,涉及到以下界面:Terminal, Editor, Browser, 外加一个随便什么鬼玩意儿。例如:某个 PDF 阅读软件,在阅读 PDF.

  2. 地球人都知道 ALT TAB, 但是最大的问题是:如果开的多了,你常常需要 ALT + TAB TAB ... 很多次。在 Win 7 下,对于系统托盘,有类似于 Win + 0, Win + 1 的快捷键,我相信很多 Linux 发布版也有类似功能。如果你用的很爽,而且也不打算换发布版,下面不用看了。

  3. 我要求所有 UNIX Like 系统都通用 (只要有 X), 即:使用 Linux 下一些最基本的功能来实现。

  4. 我要求在任何桌面,按下一个快捷键,会立即弹出我想要的以上任一窗口,再按一次,一定会返回到原来的窗口。例如:我的快捷键是:C-M 立即激活 Terminal (当然,你可以开任意多个 TAB), C-I 会激活到 Emacs 的某个 Frame (或创建一个), C-; 会激活 Firefox.

当然你也可以任意组合,例如:你打开一个 pdf 再看一本书,然后 C-m 切换到 Terminal 下写点东西,然后直接 C-i 打开 Emacs 做点笔记,然后再次 C-i 回到之前的 pdf, C-; 浏览下网页,再次 C-; , 又返回 pdf...

  1. 好吧我知道很多 XD 都是多显示器,而且显示器很大,常常拆分成好几块儿,鼠标玩的也很转,如果你那样很爽,我没有任何意见,这只是我个人的习惯,分享给同好者吧。

准备工作

  1. 首先,你需要一个叫做 Xbindkeys 的工具。传送门:http://www.nongnu.org/xbindkeys/ 他的用途是:绑定任意全局快捷键到一个脚本或命令,他是基于纯 X 的。你甚至不需要 Gnome 或 KDE , 仅仅启动一个 Xterm, 就可以用它。
  2. 你需要一个 dropdown Terminal, 就是一个下拉式的全屏 Terminal. 当你按下快捷键时,自顶向下,会弹出 Terminal. 当你再次按下快捷键或点击任何其他窗口时,自动隐藏了。如果你没有,我推荐一个足够简单,对我来说也足够好的 XFCE Terminal. 传送门:http://git.xfce.org/apps/xfce4-terminal/.
  3. wmctrl, 很多发布版应该带这个小命令了,可以让你激活指定的窗口,甚至不同 Work Space 之间也可以切换。如果碰巧你没有,传送门:http://tomas.styblo.name/wmctrl/
  4. 你需要 xprop 命令... 我想哪怕是最老的 UNIX , 只要有 X 都应该有这个命令吧 ?

步骤


首先我们要编写两个公共函数,这些函数可以方便的在所有脚本中被使用。

这些公共函数你可以单独放在一个文件中,然后稍后通过 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 当中,让它自动启动。

最后一步,编写在 xbindkeys 中调用的那两个脚本

因为有了上面那一坨公共逻辑代码,脚本写起来就很简单了,只需要一行。

# 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 占大多数的咱社区,对这文章有兴趣的不多,如果你觉得没什么用,嘴下留情呀。也许有人觉得有用呢?

你就不能用 Emacs 看 PDF 么

#2 楼 @bhuztez

回 B 大,Emacs 的 PDF 功能那就是个玩具呀!首先它是整个加载的,速度超级慢,会加载全部页面,CPU 负荷超高,即使加载完成,效果也很悲剧。貌似都不知道怎么放大。

可以试试平铺窗口管理器,比如 xmonad, awesome wm

感谢分享

深度定制,真的可以方便自己。

试试 @tualatrix 的 Manico

类似的工具: mac 下我用 apptivate

linux 下 绑定快捷键:

#!/bin/sh

# jump-or-exec by wmctrl

REXP="$1"
CMD="$2"

wmctrl -x -a $REXP && exit
exec $CMD &

楼主这种定制纯粹是折腾。

  1. 关掉一些开发过程中不需要的应用,保证当前窗口只有你用到的工具(Ubuntu 的工作区非常好用)。
  2. 养成一个较有规律的切换习惯(比如我一般 Terminital 开三个 tab,第一个就在项目根目录可以运行 git 或者临时修改 hosts,第二个是 Rails Console,第三个是 Rails Server)。
  3. 尝试平铺式窗口管理器如 @doitian 所列出的

楼主确实整的很复杂啊,我都是 IDE full screen,terminal 是 multi tabs,外加 browser 跑 javascript tests。窗口如果过多的话,可以使用 mission control 或者 alt tab,切换代码和 terminal 的时候,就四指切换屏幕。

真正追求效率的话只能说别开太多工作之外的窗口。或者双机多屏工作。

#4 楼 @doitian

两种都曾经简单试过,不得要领,也就没有深入。

#7 楼 @as181920

道行尚浅,谈不上深度,目前的精力,也不可能放到这一块。够用即可. 我觉得这文章主要意义在于:让大家认识这几个通用的小工具,在即使对底层不是很了解的前提下,尽量个性化的实现自己所需的功能。例如:我重启 Rails Server 以及 重启测试,都是通过快捷键,并且通过 notify-send 发送消息。而且,既然你能找到所需的窗口,你也可以针对某个窗口定制特殊的行为,例如:让某个窗口的 Alt + F4 失效。

#9 楼 @gihnius 受教了,这脚本的确很酷,exec 是神来之笔。

恭喜你重新发明了 WM……

自己用的舒服就好了,我在 Linux 下面大部分只用 Awesome,有时候有的小屏幕的机器,我用 Awesome + Gnome

现在用得不多了,原因很简单我用 Mac 了。。。。而且我开发 API 为主,不需要 browser 啦。

以前用 applescript + 系统快捷键面板,现在用 alfred, 自己加个 hotkey launch file group 的 workflow 就可以了

一直想找一个这样功能的东西,没找到

修改了下内容,提取了个 switch_to 方法出来,脚本中只需要一行就行了。

我想大家就算不懂 shell, 或者不愿意看那一大坨屎一样的代码,也可以自己写快捷键脚本了吧...

guake 一个下拉 Terminal

#9 楼 @gihnius 你好,请问一下,没在 Google 上搜到 apptivate,是在哪里下载呢?

#10 楼 @hbin 我 也是 不喜欢 折腾的人

任务栏开三行的人飘过

#15 楼 @gene_wu 怒顶 Awesome, Arch 加 Awesome 简直神了。

楼主的头像好风骚

又更新了下,现在即使你完全不懂 bash shell, 照着我说的做,你也可以自己随意定制快捷键喽~~

本人第一篇精华帖,哈哈~

#21 楼 @gihnius 这个蛮不错的,你们一般都设什么快捷键

需要 登录 后方可回复, 如果你还没有账号请 注册新账号