Initial commit before publication.
[berthome:berthome.git] / infoline.lua
1 -- -*- coding: utf-8 -*-
2 --------------------------------------------------------------------------------
3 -- @author Nicolas Berthier <nberthier@gmail.com>
4 -- @copyright 2010 Nicolas Berthier
5 --------------------------------------------------------------------------------
6 --
7 -- This is a module for defining infolines in awesome. An infoline is a wibox
8 -- attached to a region (typically, a client or the root window).
9 --
10 -- Remarks:
11 --
12 -- - It has not been tested with multiple screens yet.
13 --
14 -- Example usage: (TODO --- read the comments for now, there are not many
15 -- functions)
16 --
17 --------------------------------------------------------------------------------
18
19 --{{{ Grab environment (mostly aliases)
20 local setmetatable = setmetatable
21 local ipairs = ipairs
22 local type = type
23 local pairs = pairs
24 local string = string
25 local print = print
26 local error = error
27 local io = io
28
29 local client = client
30 local awesome = awesome
31 local wibox = wibox
32 local widget = widget
33 local root  = root
34 local screen  = screen
35 local mouse  = mouse
36 --}}}
37
38 module ("infoline")
39
40 -- Privata data: we use weak keys in order to allow collection of private data
41 -- if keys (clients) are collected (i.e., no longer used, after having been
42 -- killed for instance).
43 -- 
44 -- XXX: For now, we have at most one infoline per client, but it could be
45 -- interesting to create several types of infolines (identified by indexes to be
46 -- allocated by this module), and associated to, e.g., different configuration
47 -- flags and positioning routine...
48 local data = setmetatable ({}, { __mode = 'k' })
49
50 --{{{ Infoline positioning
51
52 -- XXX: this is a hack that positions an infoline at the bottom of a given area.
53 local function setup_position (wb, geom)
54     local b = wb:geometry ()
55     b.x = geom.x
56     b.width = geom.width
57     b.y = geom.y + geom.height - awesome.font_height
58     b.height = awesome.font_height
59     wb:geometry (b)
60 end
61
62 --}}}
63
64 --{{{ Configurations:
65
66 -- When true, this flag indicates that an infoline is hidden if its attached
67 -- client loses its focus. Otherwise, it remains always visible.
68 follow_focus = true
69
70 --}}}
71
72 --{{{ Infoline updates
73
74 function get_text (il) return il.wb.widgets[1].text end
75 function set_text (il, text) il.wb.widgets[1].text = text end
76
77 -- Forces a refresh of the given infoline.
78 function update (il)
79     local wb = il.wb
80     local c = il.cli
81
82     if il.enabled then
83         -- XXX: Note this could be much better if we had some sort of root and
84         -- client interface unification: the following involves a priori useless
85         -- code duplication...
86         if c == root then
87             wb.screen = mouse.screen -- XXX: is this the behavior we need?
88             wb.visible = true
89             setup_position (wb, screen[mouse.screen].workarea)
90         else
91             if c:isvisible () and (not follow_focus or client.focus == c) then
92                 wb.screen = c.screen
93                 wb.visible = true
94                 setup_position (wb, c:geometry ())
95             else                    -- do we have to hide it?
96                 wb.visible = false
97             end
98         end
99     elseif wb.visible then      --otherwise we need to hide it.
100         wb.visible = false
101     end
102 end
103
104 local function update_from_client (c)
105     -- Note we may not have any infoline for this client, hence the
106     -- conditional...
107     if data[c] then update (data[c]) end
108 end
109
110 -- Force execution of the above function on client state modification.
111 client.add_signal ("focus", update_from_client)
112 client.add_signal ("unfocus", update_from_client)
113 client.add_signal ("unmanage", update_from_client)
114
115 --}}}
116
117 --{{{ Infoline management
118
119 --- Creates a new infoline, with the given initial text. Note it is not visible
120 --- by default, and not attached to any client.
121 function new (text)
122     local il = {
123         wb = wibox ({
124                         ontop = true, -- XXX: setting a depth when attaching to
125                                       --a client would be much better
126                         widgets = {
127                             widget ({ type = "textbox", align="left" })
128                         },
129                     })
130     }
131     -- these will remain false until the infoline is attached to a client.
132     il.wb.visible = false
133     il.enabled = false
134     set_text (il, text or "")
135     return il
136 end
137
138 -- Attached infolines will react to the following client-related signals, and
139 -- automatically setup their position according to the client's geometry.
140 local csignals = { "property::geometry", "property::minimized",
141     "property::visible", "property::focus", "property::screen", }
142
143 -- Attaches an infoline to a client. Note the infoline becomes visible at that
144 -- time, if the client is currently visible (and if it has focus, when
145 -- `follow_focus' holds).
146 function attach (il, c)
147     data[c] = il
148     il.cli = c
149     il.enabled = true
150     update (il)
151     if c ~= root then
152         -- subscribe to client-related signals
153         for _, s in ipairs (csignals) do
154             c:add_signal (s, update_from_client)
155         end
156     end
157 end
158
159 --- Detach the given infoline from its client, if any.
160 function dispose (il)
161     local c = il.cli
162     if c then -- note c can be nil here, if the given infoline has not been
163               --attached to any client...
164         il.enabled = false
165         update (il)         -- a shortcut here would be: `il.wb.visible = false'
166         data[c] = nil
167         if c ~= root then
168             -- unsubscribe from client-related signals
169             for _, s in ipairs (csignals) do
170                 c:remove_signal (s, update_from_client)
171             end
172         end
173     end
174 end
175
176 --}}}
177
178 -- Local variables:
179 -- indent-tabs-mode: nil
180 -- fill-column: 80
181 -- lua-indent-level: 4
182 -- End:
183 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80