2 -- ion/mod_statusbar/mod_statusbar.lua
4 -- Copyright (c) Tuomo Valkonen 2004-2009.
6 -- See the included file LICENSE for details.
9 -- This is a slight abuse of the package.loaded variable perhaps, but
10 -- library-like packages should handle checking if they're loaded instead of
11 -- confusing the user with require/include differences.
12 if package.loaded["mod_statusbar"] then return end
14 if not ioncore.load_module("mod_statusbar") then
18 local mod_statusbar=_G["mod_statusbar"]
28 function mod_statusbar.inform(name, value)
35 -- Template processing {{{
37 local function process_template(template, meter_f, text_f, stretch_f)
38 local st, en, b, c, r, p, tmp
42 st, en, b, r=string.find(template, '^(.-)%%(.*)')
50 -- Add preciding text as normal text element
55 -- Check for '% ' and '%%'
56 st, en, c, r=string.find(template, '^([ %%])(.*)')
66 -- Extract [alignment][zero padding]<meter name>
67 local pat='([<|>]?)(0*[0-9]*)([a-zA-Z0-9_]+)'
69 st, en, c, p, b, r=string.find(template, '^{'..pat..'}(.*)')
72 st, en, c, p, b, r=string.find(template, '^'..pat..'(.*)')
75 meter_f(b, c, tonumber(p))
85 function mod_statusbar.template_to_table(template)
87 local m=meters --set_date(stng, meters)
88 local aligns={["<"]=0, ["|"]=1, [">"]=2}
90 process_template(template,
94 table.insert(res, {type=4})
95 elseif (string.find(s, "^systray$") or
96 string.find(s, "^systray_")) then
107 tmpl=meters[s.."_template"],
130 mod_statusbar._set_template_parser(mod_statusbar.template_to_table)
138 -- Update statusbar contents. To be called after series
139 -- of \fnref{mod_statusbar.inform} calls.
140 function mod_statusbar.update(update_templates)
141 for _, sb in pairs(mod_statusbar.statusbars()) do
142 if update_templates then
143 local t=sb:get_template_table()
144 for _, v in pairs(t) do
146 v.tmpl=meters[v.meter.."_template"]
149 sb:set_template_table(t)
158 -- ion-statusd support {{{
162 function mod_statusbar.rcv_statusd(str)
167 local function doline(i)
169 mod_statusbar.update(updatenw)
172 local _, _, m, v=string.find(i, "^([^:]+):%s*(.*)")
174 mod_statusbar.inform(m, v)
175 updatenw=updatenw or string.find(m, "_template")
183 data=string.gsub(data..str, "([^\n]*)\n", doline)
184 str=coroutine.yield(updated)
187 ioncore.warn(TR("ion-statusd quit."))
190 mod_statusbar.update(updatenw)
194 function mod_statusbar.get_modules()
196 local specials={["filler"]=true, ["systray"]=true}
198 for _, sb in pairs(mod_statusbar.statusbars()) do
199 for _, item in pairs(sb:get_template_table()) do
200 if item.type==2 and not specials[item.meter] then
201 local _, _, m=string.find(item.meter, "^([^_]*)");
213 function mod_statusbar.cfg_statusd(cfg)
214 if date_format_backcompat_kludge then
216 cfg=table.copy(cfg, false)
217 cfg.date={date_format=date_format_backcompat_kludge}
218 elseif not cfg.date.date_format then
219 cfg=table.copy(cfg, true)
220 cfg.date.date_format=date_format_backcompat_kludge
224 --TODO: don't construct file name twice.
225 ioncore.write_savefile("cfg_statusd", cfg)
226 return ioncore.get_savefile("cfg_statusd")
230 function mod_statusbar.rcv_statusd_err(str)
237 -- Load modules and launch \file{ion-statusd} with configuration
238 -- table \var{cfg}. The options for each \file{ion-statusd} monitor
239 -- script should be contained in the corresponding sub-table of \var{cfg}.
240 function mod_statusbar.launch_statusd(cfg)
241 if statusd_pid>0 then
245 -- Launch tried, don't do it automatically after reading
247 mod_statusbar.no_autolaunch=true
249 local mods=mod_statusbar.get_modules()
252 for m in pairs(mods) do
253 if dopath("statusbar_"..m, true) then
258 -- Lookup ion-statusd
259 local statusd_script="ion-statusd"
260 local statusd=ioncore.lookup_script(statusd_script)
262 ioncore.warn(TR("Could not find %s", statusd_script))
267 local function initrcverr(str)
268 statusd_errors=(statusd_errors or "")..str
271 local cfg=mod_statusbar.cfg_statusd(cfg or {})
273 table.foreach(mods, function(k) params=params.." -m "..k end)
274 local cmd=statusd.." -c "..cfg..params
276 local rcv=coroutine.wrap(mod_statusbar.rcv_statusd)
277 local rcverr=mod_statusbar.rcv_statusd_err
279 statusd_pid=mod_statusbar._launch_statusd(cmd,
283 if statusd_errors then
284 warn(TR("Errors starting ion-statusd:\n")..statusd_errors)
287 if statusd_pid<=0 then
288 warn(TR("Failed to start ion-statusd."))
295 -- Initialisation and default settings {{{
298 -- Create a statusbar. The possible parameters in the
299 -- table \var{param} are:
301 -- \begin{tabularx}{\linewidth}{llX}
302 -- Variable & Type & Description \\
303 -- \var{template} & string & The template; see
304 -- Section \ref{sec:statusbar}. \\
305 -- \var{pos} & string & Position: \codestr{tl}, \codestr{tr},
306 -- \codestr{bl} or \codestr{br}
307 -- (for the obvious combinations of
308 -- top/left/bottom/right). \\
309 -- \var{screen} & integer & Screen number to create the statusbar on. \\
310 -- \var{fullsize} & boolean & If set, the statusbar will waste
311 -- space instead of adapting to layout. \\
312 -- \var{systray} & boolaen & Swallow (KDE protocol) systray icons. \\
315 function mod_statusbar.create(param)
316 local scr=ioncore.find_screen_id(param.screen or 0)
318 error(TR("Screen not found."))
321 if not param.force then
322 local stdisp=scr:get_stdisp()
323 if stdisp and stdisp.reg then
324 error(TR("Screen already has an stdisp. Refusing to create a "..
329 local sb=scr:set_stdisp({
331 pos=(param.pos or "bl"),
332 fullsize=param.fullsize,
334 template=param.template,
335 template_table=param.template_table,
336 systray=param.systray,
340 error(TR("Failed to create statusbar."))
349 -- Mark ourselves loaded.
350 package.loaded["mod_statusbar"]=true
353 -- Load user configuration file
354 dopath('cfg_statusbar', true)
356 -- Launch statusd if the user didn't launch it.
357 if not mod_statusbar.no_autolaunch then
358 mod_statusbar.launch_statusd()