1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2009 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 -- Grab environment we need
13 local aclient
= require("awful.client")
14 local atag
= require("awful.tag")
16 --- Apply rules to clients at startup.
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:
25 -- { rule = { class = "xterm" },
26 -- properties = { maximized_vertical = true, maximized_horizontal = true } }
29 -- <p>If you want to set mplayer floating at startup, you can add:
32 -- { rule = { name = "MPlayer" },
33 -- properties = { floating = true } }
36 -- <p>If you want to put Firefox on a specific tag at startup, you
40 -- { rule = { instance = "firefox" },
41 -- properties = { tag = mytagobject } }
44 -- <p>If you want to put Emacs on a specific tag at startup, and
45 -- immediately switch to that tag you can add:
48 -- { rule = { class = "Emacs" },
49 -- properties = { tag = mytagobject, switchtotag = true } }
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
57 -- { rule = { class = "dosbox" },
58 -- callback = function(c)
59 -- awful.util.spawn('mpc pause')
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
75 -- { rule_any = { class = { "MPlayer", "Nitrogen" }, instance = { "xterm" } },
76 -- properties = { floating = true } }
80 -- <p> To match multiple clients with an exception one can couple 'except' or
81 -- 'except_any' with the rules:
84 -- { rule = { class = "Firefox" },
85 -- except = { instance = "Navigator" },
86 -- properties = {floating = true},
91 -- { rule_any = { class = { "Pidgin", "Xchat" } },
92 -- except_any = { role = { "conversation" } },
93 -- properties = { tag = tags[1][1] }
98 -- except_any = { class = { "Firefox", "Vim" } },
99 -- properties = { floating = true }
108 --- Check if a client matches 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
116 if type(c
[field
]) == "string" then
117 if not c
[field
]:match(value
) and c
[field
] ~= value
then
120 elseif c
[field
] ~= value
then
130 --- Check if a client matches any part of a rule.
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
138 for _
, value
in ipairs(values
) do
139 if c
[field
] == value
then
141 elseif type(c
[field
]) == "string" and c
[field
]:match(value
) then
150 --- Get list of matching rules for a client.
151 -- @param c The client.
152 -- @param _rules The rules to check. List with "rule", "rule_any", "except" and
153 -- "except_any" keys.
154 -- @return The list of matched rules.
155 function rules
.matching_rules(c
, _rules
)
157 for _
, entry
in ipairs(_rules
) do
158 if (rules
.match(c
, entry
.rule
) or rules
.match_any(c
, entry
.rule_any
)) and
159 (not rules
.match(c
, entry
.except
) and not rules
.match_any(c
, entry
.except_any
)) then
160 table.insert(result
, entry
)
166 --- Check if a client matches a given set of rules.
167 -- @param c The client.
168 -- @param rules The rules to check. List with "rule", "rule_any", "except" and
169 -- "except_any" keys.
170 -- @return True if at least one rule is matched, false otherwise.
171 function rules
.does_match(c
, rules
)
172 local result
= rules
.matching_rules(c
, rules
)
173 return #result
== 0 and false or result
176 --- Apply awful.rules.rules to a client.
177 -- @param c The client.
178 function rules
.apply(c
)
182 for _
, entry
in ipairs(rules
.matching_rules(c
, rules
.rules
)) do
183 if entry
.properties
then
184 for property
, value
in pairs(entry
.properties
) do
185 props
[property
] = value
188 if entry
.callback
then
189 table.insert(callbacks
, entry
.callback
)
193 rules
.execute(c
, props
, callbacks
)
197 --- Apply properties and callbacks to a client.
198 -- @param c The client.
199 -- @param props Properties to apply.
200 -- @param callbacks Callbacks to apply (optional).
201 function rules
.execute(c
, props
, callbacks
)
202 for property
, value
in pairs(props
) do
203 if property
~= "focus" and type(value
) == "function" then
206 if property
== "floating" then
207 aclient
.floating
.set(c
, value
)
208 elseif property
== "tag" then
209 c
.screen
= atag
.getscreen(value
)
211 elseif property
== "switchtotag" and value
and props
.tag then
212 atag
.viewonly(props
.tag)
213 elseif property
== "height" or property
== "width" or
214 property
== "x" or property
== "y" then
215 local geo
= c
:geometry();
216 geo
[property
] = value
218 elseif property
== "focus" then
219 -- This will be handled below
220 elseif type(c
[property
]) == "function" then
221 c
[property
](c
, value
)
227 -- If untagged, stick the client on the current one.
228 if #c
:tags() == 0 then
232 -- Apply all callbacks.
234 for i
, callback
in pairs(callbacks
) do
239 -- Do this at last so we do not erase things done by the focus
241 if props
.focus
and (type(props
.focus
) ~= "function" or props
.focus(c
)) then
242 c
:emit_signal('request::activate',"rules")
246 client
.connect_signal("manage", rules
.apply
)
247 client
.disconnect_signal("manage", atag
.withcurrent
)
251 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80