Contents
实时控制 Sawfish
使用 sawfish-client
sawfish-client 可以对 Sawfish 进行实时控制,可以直接在终端里面运行
sawfish-client ,不过更好用的方法是使用 sawfish.el 在 Emacs 里的
sawfish-mode 里面进行编辑,并用 C-x C-e
来执行相应的 lisp 语句。
值得注意的是,sawfish-client 里面有一个 (quit)
函数,它并不是退出
sawfish-client ,而是直接退出 Sawfish ,随便执行这个操作有可能造成你其
他 X 程序的数据丢失。
使用 sawfish-ui
sawfish-ui 是一个图形化的配置对话框,里面可以配置包括主题、快捷键等很
多东西,配置会被写入到 ~/.sawfish/custom
里面去。
使用扩展
使用 Sawfish 的扩展和 Emacs 差不多,也是通过一个 load-path
来加载扩展。
我把下载到的扩展全部放在 ~/.sawfish/extensions
里面,并在 ~/.sawfishrc
里面加入一句
然后就可以通过 require
来加载对应的扩展了。在在线资源这里可以找到许多下
载扩展的地方。这里介绍几个常用的扩展。
jump-or-exec
自从我第一次接触这个功能我就再也离不开它了,它让我保持某个程序只有一个 实例,并且能方便地切换。正如它的名字所言,jump 对应于跳转,如果程序正 在运行,则跳转到程序那里,即把程序的窗口切换到前台,这个功能让我不再需 要使用任务栏来切换窗口;exec 表示运行,如果程序没有运行,着运行它,通 常,新运行的程序会自动被带到前台,这样,不管程序有没有在运行,我只需要 一个快捷键就可以把它唤出,于是我根本不需要查看任务栏得出当前哪个程序有 没有在运行,因为我不再需要关心这个问题。这样,由于任务栏的两大存在理由 都已经没有意义,jump-or-exec 的出现让我最终抛弃了任务栏。
在这里可以下载到 jump-or-exec.jl ,在 Sawfish Wiki 上有一个例子讲解如 何配置。我建立了一个列表,把我常用的只需要启动一个实例的程序都配置为 jump-or-exec :
其中 kid-display-message
是我自己定义的一个工具函数,可以在这里找到。
更加智能的 emacsclient
Emacs 启动比较慢,一直以来有各种解决办法,Emacs 自己提供的一个解决办法 是使用 emacsclient 来打开文件,这个方法的缺点是把要打开的文件发送给 Emacs 之后,Emacs 的主窗口并不能自动切换到前台,这个缺点可以通过窗口管 理器来解决,这里介绍使用 sawfish-client 的方法:
首先,在 ~/.emacs
里面加入 (server-start)
好让 Emacs 在启动的时候启动
server ,这样就可以使用emacsclient 来连接到 Emacs 了。然后在 Sawfish 里
面写一个切换到 Emacs 的函数,我这里使用了jump-or-exec ,虽然这不是必须
的,但是我平时也使用这个功能来切换到 Emacs 。
然后我可以写一个脚本来调用 emacsclient:
不过这样并不能满足要求,因为 Emacs 的启动需要几秒钟的时间,如果事先没
有启动 Emacs ,就调用 e
,则 sawfis-client -c jump-or-exec-emacs
立即
返回,这个时候 Emacs 还没有完全启动起来并执行 (server-start)
,所以
emacsclient 这个时候会抱怨找不到 server 。没关系,我们修改一下代码,如
果 Emacs 没有启动起来,就 sleep 几秒,在 Sawfish 里面 sleep 当然不好,
所以将作为一个返回值传回脚本 ,并由脚本来 sleep 。下面是修改后的
jump-or-exec-emacs
函数:
并修改脚本 e
为:
其中, jump-or-exec-emacs
里面的秒数可以根据自己 Emacs 的启动速度来设
定,这样是不是非常方便了?
iswitch-window
毕竟不是所有的程序都是只启动一个实例就够了,有些程序需要启动多个实例, 用 jump-or-exec 切换起来就比较痛苦,这里介绍了在 Sawfish 里面模拟 fluxbox 的把几个窗口放到一个窗口的多个 tab 里面的方法。
这里要介绍的 iswitch-window 是一个方便切换窗口的扩展,就像 Emacs 的
iswitch-buffer 一类的扩展那样,列出窗口列表,并根据你的输入动态更新,过
滤掉不匹配输入的项,切换起来还是非常方便的。配置也非常方便,只需要在
这里下载 iswitch-window.jl ,放到 load-path 里面,然后在 ~/.sawfishrc
里加上这两行即可:
快捷键
选择合适的快捷键
通常,常用的 Control
、 Shift
、 Alt
相关的快捷键都被 Emacs 占据,不过
现在普通键盘上通常还有左右两个 Win
键,正好可以让我们用于窗口管理器的
操作。这里我把左边的 Win
键映射到 Super
,同时我也设定 wm-modifier 为
Super
,然后把右边的 Win
键映射到 Hyper
。通常我用 Hyper
来进行切换窗
口相关的操作(如 jump-or-exec 和 iswitch-window 等),而用 Super
来进行
窗口控制(如移动、改变大小、最大化、关闭等)。
映射 Win
键可以用 xmodmap 程序来完成,这里介绍了映射的方法。还可以用这
个方法来交换 Control 和 Caps Lock 键。这里是我的 ~/.Xmodmap
文件:
keycode 115 = Super_L keycode 116 = Hyper_R clear mod3 add mod3 = Super_L clear mod4 add mod4 = Hyper_R
配置好之后要保证启动 X 的时候 xmodmap 程序去加载这个文件,重新启动一下
X ,并在一个终端模拟器里面输入 xmodmap
,看是否有我们写进去的这些内容,如
果没有的话,则要在 ~/.xinitrc
或 ~/.xsession
之类的文件里面手工加上一
句:
xmodmap ~/.Xmodmap
如何表示快捷键
Sawfish 里面表示快捷键的方法和 Emacs 里面差不多,但是又不是完全一样,最
郁闷的就是想要把某个快捷键绑定到某个命令上,但是有不知道该如何写。这里
有一个函数可以查看输入的快捷键的名字,有点类似于 Emacs 里面的 C-h k
,
不过这个并不显示键的绑定信息,也不会连续抓取 key sequence ,但是还是很
有用的:
显示出来的快捷键的名字就可以直接作为 bind-keys
的参数。
使用 key sequence
Sawfish 也可以像 Emacs 那样使用 key sequence ,方法和 Emacs 差不多,都
是使用 keymap ,不过新版本的 Emacs 在 define-key
等函数中会自动判断并
定义需要的 keymap ,而在 Sawfish 中则需要手动定义 keymap 。这里我写了
一个 kid-bind-keys
,能够自动定义 keymap :
这样,就可以像 Emacs 那样直接设定复杂的 key sequence 了,例如:
但是要保持定义快捷键的方式一致,如果你一会自己手动定义 keymap ,一会儿
使用 kid-bind-keys
来定义,有可能会出问题,因为 kid-bind-keys
并不知道
你定义的 keymap 。另外,如果一个快捷键有多种表示方式(例如,在我这里
Super-h
和 W-h
是同样的,因为我把 wm-modifier 设定成了 Super
键),也不
要多种表示混用,否则会导致某一种表示方式定义的快捷键丢失。
抓图
为了方便抓图,我自己试着写了一个模块来完成这个工作:
要能够正常工作,还需要一个脚本 sawfish-capture
:
可以看见其实是使用 ImageMagick 包的 import
命令抓图,并用 xloadimage
显示出来,而那么多的代码其实主要是处理文件名方面,如果能够计算出几乎每
次都很让人满意的默认文件名的话,抓图就很惬意了!在输入文件名的那个窗口
里面,虽然编辑功能比不上 Emacs 的 minibuffer ,但是也能够进行文件名补
全了。
要使用这个功能,把他放到合适的路径下(这里介绍了应该把模块放到什么路径
下面),并让那个 ZShell 脚本可以运行(如果没有 ZShell ,你也可以用自己喜
欢的 shell 写一个类似的,或者,如果不需要抓图之后预览一下的话,可以直
接在 Sawfish 的 lisp 代码里面运行 import
抓图就行了。) ,然后可以绑定
到相应的快捷键:
Sawfish 小技巧
nil 的引用问题
注意在 Sawfish 配置里面, (null (car '(nil)))
返回为假,不过可以这样来
得到返回为真的值: (null (car `(,nil)))
。这是一个容易犯错误的地方,不
过在 Elisp 或者是 CommonLisp 中, nil
和 'nil
是相等的,所以不会出现这
种情况。还有一个办法就是使用 ()
来代替 nil
: (null (car '(())))
求值就
会得到想要的 t
。
我想出现这样事情的原因是在 librep1 里面仅仅以 ()
来表示假,而 nil
只
是一个普通的值为 ()
的 symbol
而已,这个 symbol
本身并没有得到特殊对待
而理解为假。
显示消息
Sawfish 提供了 display-message
函数可以在屏幕上显示一段文字,不过这段
文字并不会自动消失,于是我自己弄了一个函数,可以使用 display-message
来显示一段文字,并让消息在指定的一段时间之后自动消失:
wm-modifier
在设定 Sawfish 的快捷键的时候经常看到 W-h
这类的快捷键, W
其实就是
wm-modifier
,这是可以定制的,不过通常我们设定他为 Super
键,这样可以
避免和 Emacs 的快捷键冲突。可以在 sawfish-ui 里面设定这个值。
启动程序
我使用 startx
来启动 X ,所以我的必要的程序都在 ~/.xinitrc
里面启动,
但是在 Sawfish 退出的时候并不知道其他程序的存在,所以他们经常是异常退
出。一个办法就是在 Sawfish 里面使用 start-process 来启动程序,并在退出
之前结束掉它们。
模块
Sawfish 的扩展可以写成一个一个的模块,通过 require
来加载,例如
sawfish.wm.util.prompt
。Sawfish 到 load-path
里面去找对应的模块,例
如,它会去 load-path
中的目录下面的 sawfish/wm/util
子目录下面寻找
prompt.jl
或 prompt.jlc
文件来加载 sawfish.wm.util.prompt
模块。
Sawfish 在线资源
- 王垠的关于 Sawfish 的介绍
- Sawfish 的主页
- Sawfish Wiki
- 一个 Sawfish 的教程
- Sawfish 在 GMANE 的邮件列表在线浏览
- 一些使用 sawfish 的人的站点上的资料