Skip to content
Newer
Older
100644 356 lines (301 sloc) 10.2 KB
1165d58 @dodo titlebars
authored Oct 9, 2011
1 --------------------------------------------------------------------------------
2 -- @author dodo
3 -- @copyright 2011 https://github.com/dodo
4 -- @release v3.4-503-g4972a28
5 --------------------------------------------------------------------------------
6
7 local awful = require("awful")
8 local wibox = require("wibox")
9 local beautiful = require("beautiful")
10 local uzful = { util = require("uzful.util") }
11 local string = { format = string.format }
12 local esc = awful.util.escape
13 local ipairs = ipairs
14 local pairs = pairs
15 local pcall = pcall
16 local type = type
17 local print = print
18 local setmetatable = setmetatable
19 local capi =
20 {
21 client = client,
22 screen = screen,
23 oocairo = oocairo
24 }
25
26 local function any(list, iter)
27 for key, value in pairs(list) do
28 if iter(value, key) == true then
29 return true
30 end
31 end
32 return false
33 end
34
35 module("uzful.widget.titlebar")
36
37
38 local function coord(key, dir, geometry, size)
39 if dir == "north" then
40 if key == "x" then
41 return geometry["x"]
42 else
43 return geometry["y"] - size
44 end
45 elseif dir == "south" then
46 if key == "x" then
47 return geometry["x"]
48 else
49 return geometry["y"] + geometry["height"]
50 end
51 elseif dir == "east" then
52 if key == "x" then
53 return geometry["x"] + geometry["width"]
54 else
55 return geometry["y"]
56 end
57 elseif dir == "west" then
58 if key == "x" then
59 return geometry["x"] - size
60 else
61 return geometry["y"]
62 end
63 end
64 end
65
66
67 local function extent(key, dir, geometry, size)
68 if dir == "north" or dir == "south" then
69 if key == "width" then
70 return geometry["width"]
71 else
72 return size
73 end
74 elseif dir == "east" or dir == "west" then
75 if key == "width" then
76 return size
77 else
78 return geometry["height"]
79 end
80 end
81 end
82
83 local function text(tb, c)
84 local txt
85
86 if c.minimized then
87 txt = (esc(c.icon_name) or esc(c.name) or esc("<untitled>"))
88 else
89 txt = (esc(c.name) or esc("<untitled>"))
90 end
91
92 -- The text might be invalid, so use pcall
93 if not pcall(tb.set_markup, tb, txt) then
94 tb:set_markup("<i>&lt;Invalid text&gt;</i>")
95 end
96
97 end
98
99
100
101 function direction(bar, geometry)
102 local dir = bar._dir
103 geometry = geometry or bar.client:geometry()
104 if dir == "auto" then
105 if geometry["width"] > geometry["height"] then
106 return "west"
107 else
108 return "north"
109 end
110 else
111 if dir == "south" then
112 return "north"
113 else
114 return dir
115 end
116 end
117 end
118
119
120 function visiblity(bar)
121 local c = bar.client
122 local w = bar.widget
123 local geometry = c:geometry()
124 local d = bar:direction(geometry)
125 local area = capi.screen[c.screen].workarea
c5fe174 @dodo check if on the a visible tag first
authored Oct 9, 2011
126 w.visible = (c.sticky or any(c:tags(), function (t) return t.selected end))
127 and ( not (c.hidden or
1165d58 @dodo titlebars
authored Oct 9, 2011
128 c.minimized or
129 c.fullscreen or
91e4968 @dodo show titlebars only when floating
authored Oct 9, 2011
130 c.maximized_vertical or
131 c.maximized_horizontal)
132 and awful.layout.get(c.screen) == awful.layout.suit.floating
c5fe174 @dodo check if on the a visible tag first
authored Oct 9, 2011
133 or awful.client.floating.get(c) )
1165d58 @dodo titlebars
authored Oct 9, 2011
134 c.skip_taskbar = w.visible
135 end
136
137
138 function color(bar, args)
139 args = args or {}
140 local w = bar.widget
141 local theme = beautiful.get()
142 if capi.client.focus == bar.client then
143 w:set_fg(args.fg_focus or theme.titlebar_fg_focus or theme.fg_focus)
144 w:set_bg(args.bg_focus or theme.titlebar_bg_focus or theme.bg_focus)
145 else
146 w:set_fg(args.fg_normal or theme.titlebar_fg_normal or theme.fg_normal)
147 w:set_bg(args.bg_normal or theme.titlebar_bg_normal or theme.bg_normal)
148 end
149 end
150
151 function update(bar)
152 local w = bar.widget
153 local geometry = bar.client:geometry()
154 local d = bar:direction(geometry)
155 w.height = extent("height", d, geometry, bar.size)
156 w.width = extent("width", d, geometry, bar.size)
157 w.y = coord("y", d, geometry, bar.size)
158 w.x = coord("x", d, geometry, bar.size)
159 bar.rotation:set_direction(d)
160 bar:visiblity()
161 end
162
163
164
165
166 function new(c, args)
167 args = args or {}
168
169 local ret = {}
170
171 local theme = beautiful.get()
172 local box = wibox(uzful.util.table.update({ type = "utility" }, args))
173 ret.widget = box
174 ret.client = c
175
176 local dir = args.dir or "auto"
177 local size = args.size or theme.menu_height
178 ret.size = size
179 ret._dir = dir
180
181 local rot, ib, tb, m, l, r, f, buttons
182
183 rot = wibox.layout.rotate()
184 ib = wibox.widget.imagebox()
185 tb = wibox.widget.textbox()
186 m = wibox.layout.margin(tb, 4, 4)
187 l = wibox.layout.fixed.horizontal()
188 r = wibox.layout.fixed.horizontal()
189 f = wibox.layout.align.horizontal()
190
191 l:add(ib)
192 l:add(m)
193
194 ret.rotation = rot
195 ret.text = tb
196 ret.icon = ib
197
198 box.screen = c.screen
199 box.ontop = true--c.ontop
200
201 buttons = {
202 { "sticky", state = true, function () c.sticky = not c.sticky end },
203 { "ontop", state = true, function () c.ontop = not c.ontop end },
204 { "maximized", state = true, function ()
205 c.maximized_horizontal = not c.maximized_horizontal
206 c.maximized_vertical = not c.maximized_vertical
207 end },
208 { "floating", state = true, function () awful.client.floating.toggle(c) end },
209 { "close", function () c:kill() end },
210 }
211
212 local controls = {}
213 local image, img, key
214 for _, con in ipairs(buttons) do
215 local name = con[1]
216 local control = {}
217 controls[name] = control
218
219 for _, focustype in ipairs({"focus", "normal"}) do
220 local focusstate = {}
221 control[focustype] = focusstate
222 for state, val in pairs({active = true, inactive = false}) do
223
224 if con.state then
225 key = string.format(
226 "titlebar_%s_button_%s_%s", name, focustype, state)
227 else
228 key = string.format(
229 "titlebar_%s_button_%s", name, focustype)
230 end
231 image = args[key] or theme[key]
232
233 if type(image) == "string" then
234 img = capi.oocairo.image_surface_create_from_png(image)
235 elseif type(image) == "userdata" and image.type and image:type() == "cairo_surface_t" then
236 img = image
237 elseif type(image) == "userdata" and image._NAME and image._NAME == "cairo surface object" then
238 img = image
239 end
240 focusstate[val] = img
241 end
242 end
243
244 control.image = wibox.widget.imagebox()
245 control.state = "normal"
246
247 control.update_image = function ()
248 control.image:set_image(control[control.state][not (not c[name])])
249 end
250 control.image:connect_signal("mouse::enter", function ()
251 control.state = "focus"
252 control.update_image()
253 end)
254 control.image:connect_signal("mouse::leave", function ()
255 control.state = "normal"
256 control.update_image()
257 end)
258
259 if #con > 1 and type(con[2]) == "function" then
260 control.image:buttons(awful.button({ }, 1, con[2]))
261 end
262
263 control.update_image()
264 r:add(control.image)
265 end
266
267 ret.controls = controls
268
269 text(tb, c)
270 ib:set_image(c.icon)
271 f:set_left(l)
272 f:set_right(r)
273 rot:set_widget(f)
274 box:set_widget(rot)
275
276 box:connect_signal("mouse::enter", function ()
277 capi.client.focus = c
278 end)
279
280 local signals = {}
281 signals["property::icon"] = function () ib:set_image(c.icon) end
282 signals["property::ontop"] = function () controls.ontop.update_image() end
283 signals["property::floating"] = function () controls.floating.update_image() end
284 local set_geometry = function () ret:update() end
285 signals["property::width"] = set_geometry
286 signals["property::height"] = set_geometry
287 local toggle_focus = function () ret:color(args) end
288 signals["unfocus"] = toggle_focus
289 signals["focus"] = toggle_focus
290 local set_name = function () text(tb, c) end
291 signals["property::name"] = set_name
292 signals["property::icon_name"] = set_name
293 local set_visibility = function () ret:visiblity() end
294 signals["tagged"] = set_visibility
295 signals["untagged"] = set_visibility
296 signals["property::hidden"] = set_visibility
297 signals["property::minimized"] = set_visibility
298 signals["property::fullscreen"] = set_visibility
299 signals["property::maximized_vertical"] = set_visibility
300 signals["property::sticky"] = function ()
301 controls.sticky.update_image()
302 ret:visiblity()
303 end
304 signals["property::x"] = function ()
305 local geometry = c:geometry()
306 local d = ret:direction(geometry)
307 box.x = coord("x", d, geometry, size)
308 ret:visiblity()
309 end
310 signals["property::y"] = function ()
311 local geometry = c:geometry()
312 local d = ret:direction(geometry)
313 box.y = coord("y", d, geometry, size)
314 ret:visiblity()
315 end
316 signals["unmanage"] = function ()
317 for signal, callback in pairs(signals) do
318 c:disconnect_signal(signal, callback)
319 end
320 box.visible = false
321 box:set_widget(nil)
322 end
323
324
325 for signal, callback in pairs(signals) do
326 c:connect_signal(signal, callback)
327 end
328
329 for _, k in ipairs({"visiblity", "update", "color", "direction"}) do
330 ret[k] = _M[k]
331 end
332
333 ret:color()
334 ret:update()
335 awful.client.property.set(c, "titlebar", ret)
336
337 return ret
338 end
339
340
341 capi.client.add_signal("property::titlebar")
342
343 local update_titlebars = function(tag)
344 for _, c in ipairs(tag:clients()) do
345 local bar = awful.client.property.get(c, "titlebar")
346 if bar ~= nil then
347 bar:visiblity()
348 end
349 end
350 end
351
6cb96e3 @dodo nice api
authored Oct 9, 2011
352 awful.tag.attached_connect_signal(nil, "property::selected", update_titlebars)
353 awful.tag.attached_connect_signal(nil, "property::hide", update_titlebars)
1165d58 @dodo titlebars
authored Oct 9, 2011
354
355 setmetatable(_M, { __call = function (_, ...) return new(...) end })
Something went wrong with that request. Please try again.