我们知道,在KDE中可以通过窗口管理器方便地将窗口设置为总在最前、设置出现在所有工作区等, 但是Ubuntu 6.06的Gnome中无法做到这一点。Gnome所用的窗口管理器MetaCity认为这些不是窗口管理器的任务, 因此没有实现这些功能。好在Gnome的一名开发者为我们开发了 Devil’s Pie 这个程序,它能够根据预先设定的动作自动控制Gnome中的窗口。


# 原理

Devil’s Pie启动之后会监视新窗口的建立,如果新建的窗口满足指定的条件则按照预定的动作设置该窗口的属性。 例如,如果设置“标题为GVIM的窗口最大化”这样的条件,那么gvim启动时就会被 Devil’s Pie 检测到并被最大话。

Devil’s Pie的配置文件为 /etc/devilspie 和 ~/.devilspie/*.ds。每当有窗口启动时,Devil’s Pie会针对此窗口 执行所有的配置文件,遇到匹配的条件则对此窗口执行相应的动作。

安装

Ubuntu 6.06 下安装很简单:

$ sudo apt-get install devilspie

若需要从源代码编译,可以从官方主页下载最新版。

关于版本

Ubuntu 6.06 自带的版本是 0.16,以下教程都以该版本为准。0.12之前的版本使用 XML 配置文件, 而0.13之后的版本使用一种类似于 LISP 的语言―――― S-expression作为配置文件, 其扩展名为 .ds。

最新版本是 0.17(2006/09/22时的情况),如果你想使用最新版,可以自己编译。

入门

假设我们要让 Firefox 在 2 号桌面启动。 我们在自己的主目录下建立 .devilspie 目录,并创建一个名为 firefox.ds 的文件。

$ cd ~
$ mkdir .devilspie
$ gedit .devilspie/firefox.ds

然后输入以下的内容并保存,注意大小写。

(if 
  (contains (window_name) "Mozilla Firefox")
  (set_workspace 2)
)

然后从终端中输入以下命令:

$ devilspie

之后启动 Firefox,你会发现 Firefox 被移动到了2号工作区。

(如果不能正常工作,请参考 FAQ篇。)

我们当然不能每次都手动启动 Devil’s Pie,因此要将其加入到自动启动中。选择 主菜单中的系统->首选项->会话,然后选择启动程序拦,单击添加, 输入启动命令为devilspie,确定。下次登录时系统会自动启动 Devil’s Pie 了。

命令参考

流程控制

if [#if]

条件判断命令,相当于 C语言的 if 语句。

格式

(if a b)        - 如果满足条件 a,则执行b。
(if a b c)      - 如果满足条件 a,则执行b,否则执行c。

使用例

(if (contains (window_name) "Firefox") (set_workspace 2))
如果窗口名匹配字符串"Firefox",则将该窗口移动到2号工作区。

begin [#begin]

连续执行一连串的动作,相当于C语言的程序块。

格式

(begin a b c ...)    - 连续执行 a、b、c……

使用例

(if (contains (window_name) "Firefox") (begin (set_workspace 2) (maximize)))
如果窗口名匹配字符串"Firefox",则将该窗口移动到2号工作区,然后将其最大化。

逻辑运算

and [#and]

当两个条件均为真时返回真;只要有一个条件为假,则返回假。相当于 C 语言的 && 运算符。

格式

(and a b)      - 如果条件 a 和 b 均为真,则全体的值为真

or [#or]

当两个条件有一个为真,则返回真,两个均为假时返回假。相当于 C 语言的   运算符。

格式

(or a b)      - 只要条件 a 和 b 有一个为真,则全体的值为真 

not [#not]

返回与给定条件相反的真假值,相当于 C 语言的 ! 运算符。

格式

(not a)      - 若 a 为真,则返回假;若 a 为假,则返回真

字符串测试

is [#is]

当给定两个字符串完全相等时返回真,否则返回假。相当于 C 语言的 strcmp 函数。

格式

(is "foo" "foo")      - 返回真
(is "foo" "bar")      - 返回假

contains [#contains]

给定两个字符串,若前者包含后者(即后者是前者的子字符串),则返回真,否则返回假。

格式

(contains haystack needle)   - 若 haystack 包含 needle 则返回真

使用例

(if (contains (window_name) "Firefox") (set_workspace 2))
如果窗口名称包含字符串 "Firefox" 则将窗口移动到2号工作区。

matches [#matches]

给定一个字符串和一个正规表达式,如果字符串匹配正规表达式则返回真,否则返回假。

格式

(matches str pattern)      - 若 str 匹配 pattern 则返回真

使用例

(if (matches (window_name) "Firefox$") (set_workspace 2))
当窗口名称的末尾是 "Firefox" 时将其移动到2号工作区。
(matches “foobar” “[o]{2}b”) - 真
(matches “foobar” “[0-9]+”) - 假

窗口变量

窗口变量返回对象窗口的某种属性。

window_name [#window_name]

返回窗口名称,即窗口标题栏上显示的文字。

格式

(window_name)

window_role [#window_role]

返回窗口角色名,该属性由窗口内部的 WM_WINDOW_ROLE 变量定义。

格式

(window_role)

application_name [#application_name]

返回应用程序名。

格式

(application_name)

动作

指定针对对象窗口进行的操作,大部分为修改窗口属性。

debug [#debug]

输出调试信息,包括配置文件的读取、执行的窗口动作等。相当于命令行选项 -d。

格式

(debug)

输出指定的字符串,一般用作调试。

格式

(print text)

使用例

(print (application_name))
输出对象窗口的应用程序名称。

geometry [#geometry]

设置窗口位置。给定的字符串必须是一个合法的位置指定字符串。该字符串的格式如下:

[=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]

详细说明可参考 man XParseGeometry 文档。

格式

(geometry geo)     - 用字符串 geo 设置窗口位置。

应用例

(geometry "400×300+0-22")
(geometry "640×480")
(geometry "+10+10")

fullscreen [#fullscreen]

设置窗口为全屏显示。

格式

(fullscreen)

focus [#focus]

设置对象窗口为活动窗口。

格式

(focus)

center [#center]

将对象窗口移动到屏幕正中央。

格式

(center)

maximize [#maximize]

将对象窗口最大化。

格式

(maximize)

maximize_vertically [#maximize_vertically]

将对象窗口在垂直方向上最大化。

格式

(maximize_vertically)

maximize_horizontally [#maximize_horizontally]

将对象窗口在水平方向上最大化。

格式

(maximize_horizontally)

minimize [#minimize]

将对象窗口最小化。

格式

(minimize)

shade [#shade]

格式

(shade)

unshade [#unshade]

格式

(unshade)

close [#close]

关闭对象窗口。

格式

(close)

pin [#pin]

将对象窗口固定在所有的工作区上。

格式

(pin)

unpin [#unpin]

解除对象窗口的 pin 状态。

set_workspace [#set_workspace]

将窗口移动到指定的工作区上。

格式

(set_workspace num)

使用例

(set_workspace 1)

skip_pager [#skip_pager]

格式

(skip_pager)

skip_tasklist [#skip_tasklist]

格式

(skip_tasklist)

above [#above]

使对象窗口总在最前。

格式

(above)

below [#below]

使对象窗口总在最底层。

格式

(below)

undecorate [#undecorate]

删除对象窗口上的所有窗口修饰。

格式

(undecorate)

wintype [#wintype]

设置窗口类型。窗口类型可以是以下字符串:”normal”, “dialog”, “menu”, “toolbar”, “splashscreen”, “utility”, “dock”, “desktop”。

格式

(wintype type)

使用例

(wintype "normal")

FAQ [#faq]

为什么我的脚本不起作用?

很有可能你的 window_name、application_name 等匹配字符串设置不正确。 首先确定对象窗口的正确的 window_name、application_name 之后再修改配置文件。

如何确定一个窗口的 window_name、application_name、window_role?

最简单的方法就是使用 print 动作输出 window_name 等变量。在 .devilspie 目录下建立 window_name.ds、application_name.ds、window_role.ds 三个文件,内容分别如下:

window_name.ds

(print (window_name))

application_name.ds

(print (application_name)))

window_role.ds

(print (window_role))

然后从命令行运行 Devil’s Pie,再打开对象窗口,查看终端的输出结果。

为什么我的配置文件中,第二条以后的命令都不能执行?

这是 Devil’s Pie 的一个bug,每一个 .ds 文件只有第一个命令(第一对括号内的内容)才能被执行。 因此,你无法把所有配置都写到一个文件中,而只能为每一条配置建立一个单独的配置文件。

如何在 vim 中使用语法高亮显示?

Devil’s Pie 的配置文件语法与 LISP 相同,因此你可以在 vim 中使用下面的命令来设置语法高亮。

:set syntax=lisp

如何终止正在执行中的 Devil’s Pie?

$ killall devilspie

参考

本文参考了以下网站,在此表示感谢。