1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2008 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 -- Grab environment we need
12 local setmetatable
= setmetatable
21 local abutton
= require("awful.button")
22 local beautiful
= require("beautiful")
23 local util
= require("awful.util")
24 local widget
= require("awful.widget")
25 local mouse
= require("awful.mouse")
26 local client
= require("awful.client")
27 local layout
= require("awful.widget.layout")
29 --- Titlebar module for awful
30 module("awful.titlebar")
33 local data
= setmetatable({}, { __mode
= 'k' })
35 -- Predeclaration for buttons
38 local function button_callback_focus_raise_move(w
, t
)
39 capi
.client
.focus
= t
.client
41 mouse
.client
.move(t
.client
)
44 local function button_callback_move(w
, t
)
45 return mouse
.client
.move(t
.client
)
48 local function button_callback_resize(w
, t
)
49 return mouse
.client
.resize(t
.client
)
52 --- Create a standard titlebar.
53 -- @param c The client.
54 -- @param args Arguments.
55 -- modkey: the modkey used for the bindings.
56 -- fg: the foreground color.
57 -- bg: the background color.
58 -- fg_focus: the foreground color for focused window.
59 -- fg_focus: the background color for focused window.
60 -- width: the titlebar width
62 if not c
or (c
.type ~= "normal" and c
.type ~= "dialog") then return end
63 if not args
then args
= {} end
64 if not args
.height
then args
.height
= capi
.awesome
.font_height
* 1.5 end
65 local theme
= beautiful
.get()
68 data
[c
].fg
= args
.fg
or theme
.titlebar_fg_normal
or theme
.fg_normal
69 data
[c
].bg
= args
.bg
or theme
.titlebar_bg_normal
or theme
.bg_normal
70 data
[c
].fg_focus
= args
.fg_focus
or theme
.titlebar_fg_focus
or theme
.fg_focus
71 data
[c
].bg_focus
= args
.bg_focus
or theme
.titlebar_bg_focus
or theme
.bg_focus
72 data
[c
].width
= args
.width
73 data
[c
].font
= args
.font
or theme
.titlebar_font
or theme
.font
75 local tb
= capi
.wibox(args
)
77 local title
= capi
.widget({ type = "textbox" })
79 title
.text
= "<span font_desc='" .. data
[c
].font
.. "'> " ..
80 util
.escape(c
.name
) .. " </span>"
83 -- Redirect relevant events to the client the titlebar belongs to
84 local bts
= util
.table.join(
85 abutton({ }, 1, button_callback_focus_raise_move
),
86 abutton({ args
.modkey
}, 1, button_callback_move
),
87 abutton({ args
.modkey
}, 3, button_callback_resize
))
90 local appicon
= capi
.widget({ type = "imagebox" })
91 appicon
.image
= c
.icon
93 -- for each button group, call create for the client.
94 -- if a button set is created add the set to the
95 -- data[c].button_sets for late updates and add the
96 -- individual buttons to the array part of the widget
99 layout
= layout
.horizontal
.rightleft
103 data
[c
].button_sets
= {}
104 for i
= 1, #button_groups
do
105 local set
= button_groups
[i
].create(c
, args
.modkey
, theme
)
107 data
[c
].button_sets
[is
] = set
109 for n
,b
in pairs(set
) do
121 layout
= layout
.horizontal
.flex
123 layout
= layout
.horizontal
.rightleft
128 c
:add_signal("property::icon", update
)
129 c
:add_signal("property::name", update
)
130 c
:add_signal("property::sticky", update
)
131 c
:add_signal("property::floating", update
)
132 c
:add_signal("property::ontop", update
)
133 c
:add_signal("property::maximized_vertical", update
)
134 c
:add_signal("property::maximized_horizontal", update
)
138 --- Update a titlebar. This should be called in some hooks.
139 -- @param c The client to update.
140 -- @param prop The property name which has changed.
142 if c
.titlebar
and data
[c
] then
143 local widgets
= c
.titlebar
.widgets
144 if widgets
[2].title
then
145 widgets
[2].title
.text
= "<span font_desc='" .. data
[c
].font
..
146 "'> ".. util
.escape(c
.name
) .. " </span>"
148 if widgets
[2].appicon
then
149 widgets
[2].appicon
.image
= c
.icon
151 if capi
.client
.focus
== c
then
152 c
.titlebar
.fg
= data
[c
].fg_focus
153 c
.titlebar
.bg
= data
[c
].bg_focus
155 c
.titlebar
.fg
= data
[c
].fg
156 c
.titlebar
.bg
= data
[c
].bg
159 -- iterated of all registered button_sets and update
160 local sets
= data
[c
].button_sets
162 sets
[i
].update(c
,prop
)
167 --- Remove a titlebar from a client.
168 -- @param c The client.
174 -- Create a new button for the toolbar
175 -- @param c The client of the titlebar
176 -- @param name The base name of the button (i.e. close)
177 -- @param modkey ... you know that one, don't you?
178 -- @param theme The theme from beautifull. Used to get the image paths
179 -- @param state The state the button is associated to. Containse path the action and info about the image
180 local function button_new(c
, name
, modkey
, theme
, state
)
181 local bts
= abutton({ }, 1, nil, state
.action
)
183 -- get the image path from the theme. Only return a button if we find an image
185 img
= "titlebar_" .. name
.. "_button_" .. state
.img
187 if not img
then return end
189 if not img
then return end
191 -- now create the button
192 local bname
= name
.. "_" .. state
.idx
193 local button
= widget
.button({ image
= img
})
194 if not button
then return end
195 local rbts
= button
:buttons()
197 for k
, v
in pairs(rbts
) do
202 button
.visible
= false
206 -- Update the buttons in a button group
207 -- @param s The button group to update
208 -- @param c The client of the titlebar
209 -- @param p The property that has changed
210 local function button_group_update(s
,c
,p
)
211 -- hide the currently active button, get the new state and show the new button
212 local n
= s
.select_state(c
,p
)
213 if n
== nil then return end
214 if (s
.active
~= nil) then s
.active
.visible
= false end
215 s
.active
= s
.buttons
[n
]
216 s
.active
.visible
= true
219 -- Create all buttons in a group
220 -- @param c The client of the titlebar
221 -- @param group The button group to create the buttons for
223 -- @param theme Theme for the image paths
224 local function button_group_create(c
, group
, modkey
, theme
)
227 s
.select_state
= group
.select_state
229 layout
= layout
.horizontal
.rightleft
231 for n
,state
in pairs(group
.states
) do
232 s
.buttons
[n
] = button_new(c
, s
.name
, modkey
, theme
, state
)
233 if (s
.buttons
[n
] == nil) then return end
234 for a
,v
in pairs(group
.attributes
) do
238 function s
.update(c
,p
) button_group_update(s
,c
,p
) end
242 -- Builds a new button group
243 -- @param name The base name for the buttons in the group (i.e. "close")
244 -- @param attrs Common attributes for the buttons (i.e. {align = "right")
245 -- @param sfn State select function.
246 -- @param args The states of the button
247 local function button_group(name
, attrs
, sfn
, ...)
256 s
.states
[state
.idx
] = state
259 function s
.create(c
,modkey
, theme
) return button_group_create(c
,s
,modkey
, theme
) end
263 -- Select a state for a client based on an attribute of the client and whether it has focus
264 -- @param c The client of the titlebar
265 -- @param p The property that has changed
266 -- @param a The property to check
267 local function select_state(c
,p
,a
)
268 if (c
== nil) then return "n/i" end
269 if capi
.client
.focus
== c
then
284 -- Select a state for a client based on whether it's floating or not
285 -- @param c The client of the titlebar
286 -- @param p The property that has changed
287 local function select_state_floating(c
,p
)
288 if not c
then return end
289 if capi
.client
.focus
== c
then
290 if client
.floating
.get(c
) then
295 if client
.floating
.get(c
) then
301 -- Select a state for a client based on whether it's maximized or not
302 -- @param c The client of the titlebar
303 -- @param p The property that has changed
304 local function select_state_maximized(c
,p
)
305 if (c
== nil) then return "n/i" end
306 if capi
.client
.focus
== c
then
307 if c
.maximized_horizontal
or c
.maximized_vertical
then
313 if c
.maximized_horizontal
or c
.maximized_vertical
then
321 -- Select a state for a client based on whether it has focus or not
322 -- @param c The client of the titlebar
323 -- @param p The property that has changed
324 local function select_state_focus(c
,p
)
325 if c
and capi
.client
.focus
== c
then
331 -- These are the predefined button groups
332 -- A short explanation using 'close_buttons' as an example:
333 -- "close" : name of the button, the images for this button are taken from the
334 -- theme variables titlebar_close_button_...
335 -- { align ... : attributes of all the buttons
336 -- select_state_focus : This function returns a short string used to describe
337 -- the state. In this case either "n" or "f" depending on
338 -- the focus state of the client. These strings can be
339 -- choosen freely but the< must match one of the idx fuekds
340 -- of the states below
341 -- { idx = "n" ... : This is the state of the button for the 'unfocussed'
342 -- (normal) state. The idx = "n" parameter connects this
343 -- button to the return value of the 'select_state_focus'
344 -- function. The img = "normal" parameter is used to
345 -- determine its image. In this case the iamge is taken from
346 -- the theme variable "titlebar_close_button_normal".
347 -- Finally the last parameter is the action for mouse
350 local ontop_buttons
= button_group("ontop",
352 function(c
,p
) return select_state(c
, p
, "ontop") end,
353 { idx
= "n/i", img
= "normal_inactive",
354 action
= function(w
, t
) t
.client
.ontop
= true end },
355 { idx
= "f/i", img
= "focus_inactive",
356 action
= function(w
, t
) t
.client
.ontop
= true end },
357 { idx
= "n/a", img
= "normal_active",
358 action
= function(w
, t
) t
.client
.ontop
= false end },
359 { idx
= "f/a", img
= "focus_active",
360 action
= function(w
, t
) t
.client
.ontop
= false end })
362 local sticky_buttons
= button_group("sticky",
364 function(c
,p
) return select_state(c
,p
,"sticky") end,
365 { idx
= "n/i", img
= "normal_inactive",
366 action
= function(w
, t
) t
.client
.sticky
= true end },
367 { idx
= "f/i", img
= "focus_inactive",
368 action
= function(w
, t
) t
.client
.sticky
= true end },
369 { idx
= "n/a", img
= "normal_active",
370 action
= function(w
, t
) t
.client
.sticky
= false end },
371 { idx
= "f/a", img
= "focus_active",
372 action
= function(w
, t
) t
.client
.sticky
= false end })
374 local maximized_buttons
= button_group("maximized",
376 select_state_maximized
,
377 { idx
= "n/i", img
= "normal_inactive",
378 action
= function(w
, t
) t
.client
.maximized_horizontal
= true
379 t
.client
.maximized_vertical
= true end },
380 { idx
= "f/i", img
= "focus_inactive",
381 action
= function(w
, t
) t
.client
.maximized_horizontal
= true
382 t
.client
.maximized_vertical
= true end },
383 { idx
= "n/a", img
= "normal_active",
384 action
= function(w
, t
) t
.client
.maximized_horizontal
= false
385 t
.client
.maximized_vertical
= false end },
386 { idx
= "f/a", img
= "focus_active",
387 action
= function(w
, t
) t
.client
.maximized_horizontal
= false
388 t
.client
.maximized_vertical
= false end })
390 local close_buttons
= button_group("close",
393 { idx
= "n", img
= "normal",
394 action
= function (w
, t
) t
.client
:kill() end },
395 { idx
= "f", img
= "focus",
396 action
= function (w
, t
) t
.client
:kill() end })
398 local function floating_update(w
, t
)
399 client
.floating
.toggle(t
.client
)
402 local floating_buttons
= button_group("floating",
404 select_state_floating
,
405 { idx
= "n/i", img
= "normal_inactive", action
= floating_update
},
406 { idx
= "f/i", img
= "focus_inactive", action
= floating_update
},
407 { idx
= "n/a", img
= "normal_active", action
= floating_update
},
408 { idx
= "f/a", img
= "focus_active", action
= floating_update
})
410 button_groups
= { close_buttons
,
416 -- Register standards hooks
417 capi
.client
.add_signal("focus", update
)
418 capi
.client
.add_signal("unfocus", update
)
420 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80