ewmh.activate: focus and especially raise clients during startup
[awesome.git] / lib / awful / titlebar.lua.in
blobaff36308a7226da3178c39c68d5464099fa21522
1 ---------------------------------------------------------------------------
2 -- @author Uli Schlachter
3 -- @copyright 2012 Uli Schlachter
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 local error = error
8 local type = type
9 local abutton = require("awful.button")
10 local aclient = require("awful.client")
11 local beautiful = require("beautiful")
12 local object = require("gears.object")
13 local drawable = require("wibox.drawable")
14 local base = require("wibox.widget.base")
15 local imagebox = require("wibox.widget.imagebox")
16 local textbox = require("wibox.widget.textbox")
17 local capi = {
18 client = client
20 local titlebar = {
21 widget = {}
24 local all_titlebars = setmetatable({}, { __mode = 'k' })
26 -- Get a color for a titlebar, this tests many values from the array and the theme
27 local function get_color(name, c, args)
28 local suffix = "_normal"
29 if capi.client.focus == c then
30 suffix = "_focus"
31 end
32 local function get(array)
33 return array["titlebar_"..name..suffix] or array["titlebar_"..name] or array[name..suffix] or array[name]
34 end
35 return get(args) or get(beautiful)
36 end
38 local function get_titlebar_function(c, position)
39 if position == "left" then
40 return c.titlebar_left
41 elseif position == "right" then
42 return c.titlebar_right
43 elseif position == "top" then
44 return c.titlebar_top
45 elseif position == "bottom" then
46 return c.titlebar_bottom
47 else
48 error("Invalid titlebar position '" .. position .. "'")
49 end
50 end
52 --- Get a client's titlebar
53 -- @class function
54 -- @param c The client for which a titlebar is wanted.
55 -- @param args An optional table with extra arguments for the titlebar. The
56 -- "size" is the height of the titlebar. Available "position" values are top,
57 -- left, right and bottom. Additionally, the foreground and background colors
58 -- can be configured via e.g. "bg_normal" and "bg_focus".
59 -- @name titlebar
60 local function new(c, args)
61 local args = args or {}
62 local position = args.position or "top"
63 local size = args.size or beautiful.get_font_height(args.font) * 1.5
64 local d = get_titlebar_function(c, position)(c, size)
66 -- Make sure that there is never more than one titlebar for any given client
67 local bars = all_titlebars[c]
68 if not bars then
69 bars = {}
70 all_titlebars[c] = bars
71 end
73 local ret
74 if not bars[position] then
75 ret = drawable(d, nil)
76 local function update_colors()
77 local args = bars[position].args
78 ret:set_bg(get_color("bg", c, args))
79 ret:set_fg(get_color("fg", c, args))
80 end
82 bars[position] = {
83 args = args,
84 drawable = ret,
85 update_colors = update_colors
88 -- Update the colors when focus changes
89 c:connect_signal("focus", update_colors)
90 c:connect_signal("unfocus", update_colors)
91 else
92 bars[position].args = args
93 ret = bars[position].drawable
94 end
96 -- Make sure the titlebar has the right colors applied
97 bars[position].update_colors()
99 return ret
102 --- Show a client's titlebar.
103 -- @param c The client whose titlebar is modified
104 -- @param position Optional position of the titlebar. Must be one of "left",
105 -- "right", "top", "bottom". Default is "top".
106 function titlebar.show(c, position)
107 local position = position or "top"
108 local bars = all_titlebars[c]
109 local data = bars and bars[position]
110 local args = data and data.args
111 new(c, args)
114 --- Hide a client's titlebar.
115 -- @param c The client whose titlebar is modified
116 -- @param position Optional position of the titlebar. Must be one of "left",
117 -- "right", "top", "bottom". Default is "top".
118 function titlebar.hide(c, position)
119 local position = position or "top"
120 get_titlebar_function(c, position)(c, 0)
123 --- Toggle a client's titlebar, hiding it if it is visible, otherwise showing it.
124 -- @param c The client whose titlebar is modified
125 -- @param position Optional position of the titlebar. Must be one of "left",
126 -- "right", "top", "bottom". Default is "top".
127 function titlebar.toggle(c, position)
128 local position = position or "top"
129 local drawable, size = get_titlebar_function(c, position)(c)
130 if size == 0 then
131 titlebar.show(c, position)
132 else
133 titlebar.hide(c, position)
137 --- Create a new titlewidget. A title widget displays the name of a client.
138 -- Please note that this returns a textbox and all of textbox' API is available.
139 -- This way, you can e.g. modify the font that is used.
140 -- @param c The client for which a titlewidget should be created.
141 -- @return The title widget.
142 function titlebar.widget.titlewidget(c)
143 local ret = textbox()
144 local function update()
145 ret:set_text(c.name or "<unknown>")
147 c:connect_signal("property::name", update)
148 update()
150 return ret
153 --- Create a new icon widget. An icon widget displays the icon of a client.
154 -- Please note that this returns an imagebox and all of the imagebox' API is
155 -- available. This way, you can e.g. disallow resizes.
156 -- @param c The client for which an icon widget should be created.
157 -- @return The icon widget.
158 function titlebar.widget.iconwidget(c)
159 local ret = imagebox()
160 local function update()
161 ret:set_image(c.icon)
163 c:connect_signal("property::icon", update)
164 update()
166 return ret
169 --- Create a new button widget. A button widget displays an image and reacts to
170 -- mouse clicks. Please note that the caller has to make sure that this widget
171 -- gets redrawn when needed by calling the returned widget's update() function.
172 -- The selector function should return a value describing a state. If the value
173 -- is a boolean, either "active" or "inactive" are used. The actual image is
174 -- then found in the theme as "titlebar_[name]_button_[normal/focus]_[state]".
175 -- If that value does not exist, the focused state is ignored for the next try.
176 -- @param c The client for which a button is created.
177 -- @param name Name of the button, used for accessing the theme.
178 -- @param selector A function that selects the image that should be displayed.
179 -- @param action Function that is called when the button is clicked.
180 -- @return The widget
181 function titlebar.widget.button(c, name, selector, action)
182 local ret = imagebox()
183 local function update()
184 local img = selector(c)
185 if type(img) ~= "nil" then
186 -- Convert booleans automatically
187 if type(img) == "boolean" then
188 if img then
189 img = "active"
190 else
191 img = "inactive"
194 -- First try with a prefix based on the client's focus state
195 local prefix = "normal"
196 if capi.client.focus == c then
197 prefix = "focus"
199 if img ~= "" then
200 prefix = prefix .. "_"
202 local theme = beautiful["titlebar_" .. name .. "_button_" .. prefix .. img]
203 if not theme then
204 -- Then try again without that prefix if nothing was found
205 theme = beautiful["titlebar_" .. name .. "_button_" .. img]
207 if theme then
208 img = theme
211 ret:set_image(img)
213 if action then
214 ret:buttons(abutton({ }, 1, nil, function() action(c, selector(c)) end))
217 ret.update = update
218 update()
220 -- We do magic based on whether a client is focused above, so we need to
221 -- connect to the corresponding signal here.
222 local function focus_func(o)
223 if o == c then update() end
225 capi.client.connect_signal("focus", focus_func)
226 capi.client.connect_signal("unfocus", focus_func)
228 return ret
231 --- Create a new float button for a client.
232 -- @param c The client for which the button is wanted.
233 function titlebar.widget.floatingbutton(c)
234 local widget = titlebar.widget.button(c, "floating", aclient.floating.get, aclient.floating.toggle)
235 c:connect_signal("property::floating", widget.update)
236 return widget
239 --- Create a new maximize button for a client.
240 -- @param c The client for which the button is wanted.
241 function titlebar.widget.maximizedbutton(c)
242 local widget = titlebar.widget.button(c, "maximized", function(c)
243 return c.maximized_horizontal or c.maximized_vertical
244 end, function(c, state)
245 c.maximized_horizontal = not state
246 c.maximized_vertical = not state
247 end)
248 c:connect_signal("property::maximized_vertical", widget.update)
249 c:connect_signal("property::maximized_horizontal", widget.update)
250 return widget
253 --- Create a new minimize button for a client.
254 -- @param c The client for which the button is wanted.
255 function titlebar.widget.minimizebutton(c)
256 local widget = titlebar.widget.button(c, "minimize", function() return c.minimized end, function(c) c.minimized = not c.minimized end)
257 c:connect_signal("property::minimized", widget.update)
258 return widget
261 --- Create a new closing button for a client.
262 -- @param c The client for which the button is wanted.
263 function titlebar.widget.closebutton(c)
264 return titlebar.widget.button(c, "close", function() return "" end, function(c) c:kill() end)
267 --- Create a new ontop button for a client.
268 -- @param c The client for which the button is wanted.
269 function titlebar.widget.ontopbutton(c)
270 local widget = titlebar.widget.button(c, "ontop", function(c) return c.ontop end, function(c, state) c.ontop = not state end)
271 c:connect_signal("property::ontop", widget.update)
272 return widget
275 --- Create a new sticky button for a client.
276 -- @param c The client for which the button is wanted.
277 function titlebar.widget.stickybutton(c)
278 local widget = titlebar.widget.button(c, "sticky", function(c) return c.sticky end, function(c, state) c.sticky = not state end)
279 c:connect_signal("property::sticky", widget.update)
280 return widget
283 return setmetatable(titlebar, { __call = function(_, ...) return new(...) end})
285 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80