Lots of random documentation fixes
[awesome.git] / lib / awful / rules.lua.in
blob8891d44001481a7fbd4b898d9696b0aaa82ba664
1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2009 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 -- Grab environment we need
8 local client = client
9 local table = table
10 local type = type
11 local ipairs = ipairs
12 local pairs = pairs
13 local aclient = require("awful.client")
14 local atag = require("awful.tag")
16 --- Apply rules to clients at startup.
17 -- awful.rules
18 local rules = {}
20 --- This is the global rules table.
21 -- <p>You should fill this table with your rule and properties to apply.
22 -- For example, if you want to set xterm maximized at startup, you can add:
23 -- <br/>
24 -- <code>
25 -- { rule = { class = "xterm" },
26 -- properties = { maximized_vertical = true, maximized_horizontal = true } }
27 -- </code>
28 -- </p>
29 -- <p>If you want to set mplayer floating at startup, you can add:
30 -- <br/>
31 -- <code>
32 -- { rule = { name = "MPlayer" },
33 -- properties = { floating = true } }
34 -- </code>
35 -- </p>
36 -- <p>If you want to put Firefox on a specific tag at startup, you
37 -- can add:
38 -- <br/>
39 -- <code>
40 -- { rule = { instance = "firefox" },
41 -- properties = { tag = mytagobject } }
42 -- </code>
43 -- </p>
44 -- <p>If you want to put Emacs on a specific tag at startup, and
45 -- immediately switch to that tag you can add:
46 -- <br/>
47 -- <code>
48 -- { rule = { class = "Emacs" },
49 -- properties = { tag = mytagobject, switchtotag = true } }
50 -- </code>
51 -- </p>
52 -- <p>If you want to apply a custom callback to execute when a rule matched,
53 -- for example to pause playing music from mpd when you start dosbox, you
54 -- can add:
55 -- <br/>
56 -- <code>
57 -- { rule = { class = "dosbox" },
58 -- callback = function(c)
59 -- awful.util.spawn('mpc pause')
60 -- end }
61 -- </code>
62 -- </p>
63 -- <p>Note that all "rule" entries need to match. If any of the entry does not
64 -- match, the rule won't be applied.</p>
65 -- <p>If a client matches multiple rules, their applied in the order they are
66 -- put in this global rules table. If the value of a rule is a string, then the
67 -- match function is used to determine if the client matches the rule.</p>
68 -- <p>If the value of a property is a function, that function gets called and
69 -- function's return value is used for the property.</p>
71 -- <p> To match multiple clients to a rule one need to use slightly different
72 -- syntax:
73 -- <br/>
74 -- <code>
75 -- { rule_any = { class = { "MPlayer", "Nitrogen" }, instance = { "xterm" } },
76 -- properties = { floating = true } }
77 -- </code>
78 -- </p>
80 -- <p> To match multiple clients with an exception one can couple 'except' or
81 -- 'except_any' with the rules:
82 -- <br/>
83 -- <code>
84 -- { rule = { class = "Firefox" },
85 -- except = { instance = "Navigator" },
86 -- properties = {floating = true},
87 -- },
88 -- </code>
89 -- <br/>
90 -- <code>
91 -- { rule_any = { class = { "Pidgin", "Xchat" } },
92 -- except_any = { role = { "conversation" } },
93 -- properties = { tag = tags[1][1] }
94 -- }
95 -- <br/>
96 -- <code>
97 -- { rule = {},
98 -- except_any = { class = { "Firefox", "Vim" } },
99 -- properties = { floating = true }
100 -- }
101 -- </code>
102 -- </p>
104 -- @class table
105 -- @name rules
106 rules.rules = {}
108 --- Check if a client match a rule.
109 -- @param c The client.
110 -- @param rule The rule to check.
111 -- @return True if it matches, false otherwise.
112 function rules.match(c, rule)
113 if not rule then return false end
114 for field, value in pairs(rule) do
115 if c[field] then
116 if type(c[field]) == "string" then
117 if not c[field]:match(value) and c[field] ~= value then
118 return false
120 elseif c[field] ~= value then
121 return false
123 else
124 return false
127 return true
130 --- Check if a client match a rule. Multiple clients can be matched
131 -- @param c The client.
132 -- @param rule The rule to check.
133 -- @return True if at least one rule is matched, false otherwise.
134 function rules.match_any(c, rule)
135 if not rule then return false end
136 for field, values in pairs(rule) do
137 if c[field] then
138 for _, value in ipairs(values) do
139 if c[field] == value then
140 return true
141 elseif type(c[field]) == "string" and c[field]:match(value) then
142 return true
147 return false
150 --- Apply rules to a client.
151 -- @param c The client.
152 function rules.apply(c)
153 local props = {}
154 local callbacks = {}
155 for _, entry in ipairs(rules.rules) do
156 if (rules.match(c, entry.rule) or rules.match_any(c, entry.rule_any)) and
157 (not rules.match(c, entry.except) and not rules.match_any(c, entry.except_any)) then
158 if entry.properties then
159 for property, value in pairs(entry.properties) do
160 props[property] = value
163 if entry.callback then
164 table.insert(callbacks, entry.callback)
169 for property, value in pairs(props) do
170 if property ~= "focus" and type(value) == "function" then
171 value = value(c)
173 if property == "floating" then
174 aclient.floating.set(c, value)
175 elseif property == "tag" then
176 c:tags({ value })
177 c.screen = atag.getscreen(value)
178 elseif property == "switchtotag" and value and props.tag then
179 atag.viewonly(props.tag)
180 elseif property == "height" or property == "width" or
181 property == "x" or property == "y" then
182 local geo = c:geometry();
183 geo[property] = value
184 c:geometry(geo);
185 elseif property == "focus" then
186 -- This will be handled below
187 elseif type(c[property]) == "function" then
188 c[property](c, value)
189 else
190 c[property] = value
194 -- If untagged, stick the client on the current one.
195 if #c:tags() == 0 then
196 atag.withcurrent(c)
199 -- Apply all callbacks from matched rules.
200 for i, callback in pairs(callbacks) do
201 callback(c)
204 -- Do this at last so we do not erase things done by the focus
205 -- signal.
206 if props.focus and (type(props.focus) ~= "function" or props.focus(c)) then
207 client.focus = c
211 client.connect_signal("manage", rules.apply)
212 client.disconnect_signal("manage", atag.withcurrent)
214 return rules
216 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80