1 -- -*- coding: utf-8 -*-
2 --------------------------------------------------------------------------------
3 -- @author Nicolas Berthier <nberthier@gmail.com>
4 -- @copyright 2010 Nicolas Berthier
5 --------------------------------------------------------------------------------
7 -- Bowls are kind of helpers that can be drawn (at the bottom --- for now) of an
8 -- area, and displaying the current key prefix. It is inspired by emacs'
9 -- behavior, that prints prefix keys in the minibuffer after a certain time.
11 -- I call it `bowl' as a reference to the bowl that one might have at home,
12 -- where one puts its actual keys... A more serious name would be `hint' or
13 -- `tooltip' (but they do not fit well for this usage).
15 -- Example usage: see `rc.lua' file.
17 --------------------------------------------------------------------------------
19 --{{{ Grab environment (mostly aliases)
20 local setmetatable = setmetatable
30 local awesome = awesome
34 local infoline = require ("infoline")
39 -- Privata data: we use weak keys in order to allow collection of private data
40 -- if keys (clients) are collected (i.e., no longer used, after having been
41 -- killed for instance)
42 local data = setmetatable ({}, { __mode = 'k' })
46 --- Default modifier filter
51 ["Shift"] = string.upper,
54 -- Timers configuration
55 local use_timers = true
60 --{{{ Keychain pretty-printing
62 function mod_to_string (mods, k)
64 for _, mod in ipairs (mods) do
65 if modfilter[mod] then
66 local t = type (modfilter[mod])
67 if t == "function" then
69 elseif t == "string" then
70 ret = ret .. modfilter[mod] .. "-"
72 error ("Invalid modifier key filter: got a " .. t)
75 ret = ret .. mod .. "-"
81 function ks_to_string (m, k)
82 local m, k = mod_to_string (m, k)
88 --{{{ Timer management
90 local function delete_timer_maybe (d)
91 if d.timer then -- stop and remove the timer
92 d.timer:remove_signal ("timeout", d.timer_function)
95 d.timer_expired = true
99 local function delayed_call_maybe (d, f)
101 if not d.timer_expired and not d.timer then
102 -- create and start the timer
103 d.timer = timer ({ timeout = timeout })
104 d.timer_function = function () f (); delete_timer_maybe (d) end
105 d.timer:add_signal ("timeout", d.timer_function)
107 d.timer_expired = false
108 elseif not d.timer_expired then
109 -- restart the timer...
111 -- XXX: What is the actual semantics of the call to `start' (ie,
112 -- does it restart the timer with the initial timeout)?
114 d.timer.timeout = timeout -- reset timeout
117 else -- timers disabled
118 f () -- call the given function directly
124 --{{{ Infoline management
128 if d.bowl then -- if bowl was enabled... (should always be true...)
129 infoline.dispose (d.bowl)
132 delete_timer_maybe (d)
136 function append (w, m, k)
138 local pretty_ks = ks_to_string (m, k) .. " "
139 infoline.set_text (d.bowl, infoline.get_text (d.bowl) .. pretty_ks)
141 local function enable_bowl ()
142 -- XXX: is there a possible bad interleaving that could make
143 -- this function execute while the bowl has already been
144 -- disposed of? in which case the condition should be checked
148 infoline.attach (d.bowl, w)
152 delayed_call_maybe (d, enable_bowl)
156 -- XXX: Note the prefix text could be customizable...
157 data[w] = { bowl = infoline.new (" ") }
163 --- Initializes the bowl module, with given properties; should be called before
164 --- ANY other function of this module.
165 -- Configurations fields include:
167 -- `use_timers', `timeout': A boolean defining whether bowls drawing should be
168 -- delayed, along with a number being this time shift, in seconds (Default
169 -- values are `true' and `2').
171 -- `modfilter': A table associating modifiers (Mod1, Mod4, Control, Shift, etc.)
172 -- with either a string (in this case it will replace the modifier when printed
173 -- in heplers) or functions (in this case the key string will be repaced by a
174 -- call to this function with the key string as parameter). Default value is:
175 -- { ["Mod1"] = "M", ["Mod4"] = "S", ["Control"] = "C", ["Shift"] =
178 -- @param c The table of properties.
181 modfilter = c.modfilter and c.modfilter or modfilter
182 if c.use_timers ~= nil then use_timers = c.use_timers end
184 timeout = c.timeout ~= nil and c.timeout or timeout
188 --- Setup signal listeners, that trigger appropriate functions for a default
190 function default_setup ()
191 local function to_root (f) return function (...) f (root, ...) end end
192 client.add_signal ("keychain::enter", create)
193 client.add_signal ("keychain::append", append)
194 client.add_signal ("keychain::leave", dispose)
195 awesome.add_signal ("keychain::enter", to_root (create))
196 awesome.add_signal ("keychain::append", to_root (append))
197 awesome.add_signal ("keychain::leave", to_root (dispose))
201 -- indent-tabs-mode: nil
203 -- lua-indent-level: 4
205 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80