2 -- Copyright (c) 2007, Bart Trojanowski <bart@jukie.net>
4 -- WMII event loop, in lua
6 -- git://www.jukie.net/wmiirc-lua.git/
9 -- ========================================================================
11 -- ========================================================================
17 wmii.lua - WMII event-loop methods in lua
23 -- Write something to the wmii filesystem, in this case a key event.
24 wmii.write ("/event", "Key Mod1-j")
26 -- Set your wmii /ctl parameters
31 -- Configure wmii.lua parameters
33 xterm = 'x-terminal-emulator'
36 -- Now start the event loop
41 wmii.lua provides methods for replacing the stock sh-based wmiirc shipped with
42 wmii 3.6 and newer with a lua-based event loop.
44 It should be used by your wmiirc
53 -- ========================================================================
55 -- ========================================================================
57 local wmiirc
= os
.getenv("HOME") .. "/.wmii-3.5/wmiirc"
59 package
.path
= package
.path
60 .. ";" .. os
.getenv("HOME") .. "/.wmii-3.5/plugins/?.lua"
61 package
.cpath
= package
.cpath
62 .. ";" .. os
.getenv("HOME") .. "/.wmii-3.5/core/?.so"
63 .. ";" .. os
.getenv("HOME") .. "/.wmii-3.5/plugins/?.so"
65 local ixp
=require
"ixp"
66 local eventloop
= require
"eventloop"
69 local io
= require("io")
70 local os
= require("os")
71 local posix
= require("posix")
72 local string = require("string")
73 local table = require("table")
74 local math
= require("math")
79 local tostring = tostring
80 local tonumber = tonumber
81 local setmetatable
= setmetatable
86 local mypid
= posix
.getprocessid("pid")
88 -- ========================================================================
90 -- ========================================================================
92 -- wmiir points to the wmiir executable
93 -- TODO: need to make sure that wmiir is in path, and if not find it
96 -- wmii_adr is the address we use when connecting using ixp
97 local wmii_adr
= os
.getenv("WMII_ADDRESS")
98 or ("unix!/tmp/ns." .. os
.getenv("USER") .. "."
99 .. os
.getenv("DISPLAY"):match("(:%d+)") .. "/wmii")
101 -- wmixp is the ixp context we use to talk to wmii
102 local wmixp
= ixp
.new(wmii_adr
)
104 -- history of previous views, view_hist[#view_hist] is the last one
105 local view_hist
= {} -- sorted with 1 being the oldest
106 local view_hist_max
= 10 -- max number to keep track of
108 -- allow for a client to be forced to a tag
109 local next_client_goes_to_tag
= nil
111 -- ========================================================================
113 -- ========================================================================
120 Log the message provided in C<str>
122 Currently just writes to io.stderr
127 io
.stderr
:write (str
.. "\n")
130 -- ========================================================================
131 -- MAIN ACCESS FUNCTIONS
132 -- ========================================================================
137 =item ls ( dir, fmt )
139 List the wmii filesystem directory provided in C<dir>, in the format specified
142 Returns an iterator of TODO
146 function ls (dir
, fmt
)
147 local verbose
= fmt
and fmt
:match("l")
149 local s
= wmixp
:stat(dir
)
151 return function () return nil end
153 if s
.modestr
:match("^[^d]") then
155 return stat2str(verbose
, s
)
159 local itr
= wmixp
:idir (dir
)
170 return stat2str(verbose
, s
)
176 local function stat2str(verbose
, stat
)
178 return string.format("%s %s %s %5d %s %s", stat
.modestr
, stat
.uid
, stat
.gid
, stat
.length
, stat
.timestr
, stat
.name
)
180 if stat
.modestr
:match("^d") then
181 return stat
.name
.. "/"
188 -- ------------------------------------------------------------------------
189 -- read all contents of a wmii virtual file
191 return wmixp
:read (file
)
194 -- ------------------------------------------------------------------------
195 -- return an iterator which walks all the lines in the file
198 -- for event in wmii.iread("/event")
201 function iread (file
)
202 return wmixp
:iread(file
)
205 -- ------------------------------------------------------------------------
206 -- create a wmii file, optionally write data to it
207 function create (file
, data
)
208 wmixp
:create(file
, data
)
211 -- ------------------------------------------------------------------------
212 -- remove a wmii file
213 function remove (file
)
217 -- ------------------------------------------------------------------------
218 -- write a value to a wmii virtual file system
219 function write (file
, value
)
220 wmixp
:write (file
, value
)
223 -- ------------------------------------------------------------------------
224 -- setup a table describing dmenu command
225 local function dmenu_cmd (prompt
)
226 local cmdt
= { "dmenu", "-b" }
227 local fn
= get_ctl("font")
229 cmdt
[#cmdt
+1] = "-fn"
232 local normcolors
= get_ctl("normcolors")
234 local nf
, nb
= normcolors
:match("(#%x+)%s+(#%x+)%s#%x+")
236 cmdt
[#cmdt
+1] = "-nf"
237 cmdt
[#cmdt
+1] = "'" .. nf
.. "'"
240 cmdt
[#cmdt
+1] = "-nb"
241 cmdt
[#cmdt
+1] = "'" .. nb
.. "'"
244 local focuscolors
= get_ctl("focuscolors")
246 local sf
, sb
= focuscolors
:match("(#%x+)%s+(#%x+)%s#%x+")
248 cmdt
[#cmdt
+1] = "-sf"
249 cmdt
[#cmdt
+1] = "'" .. sf
.. "'"
252 cmdt
[#cmdt
+1] = "-sb"
253 cmdt
[#cmdt
+1] = "'" .. sb
.. "'"
258 cmdt
[#cmdt
+1] = "'" .. prompt
.. "'"
264 -- ------------------------------------------------------------------------
265 -- displays the menu given an table of entires, returns selected text
266 function menu (tbl
, prompt
)
267 local dmenu
= dmenu_cmd(prompt
)
269 local infile
= os
.tmpname()
270 local fh
= io
.open (infile
, "w+")
273 for i
,v
in pairs(tbl
) do
274 if type(i
) == 'number' and type(v
) == 'string' then
283 local outfile
= os
.tmpname()
285 dmenu
[#dmenu
+1] = "<"
286 dmenu
[#dmenu
+1] = infile
287 dmenu
[#dmenu
+1] = ">"
288 dmenu
[#dmenu
+1] = outfile
290 local cmd
= table.concat(dmenu
," ")
293 fh
= io
.open (outfile
, "r")
296 local sel
= fh
:read("*l")
302 -- ------------------------------------------------------------------------
303 -- displays the a tag selection menu, returns selected tag
305 local tags
= get_tags()
307 return menu(tags
, "tag:")
310 -- ------------------------------------------------------------------------
311 -- displays the a program menu, returns selected program
312 function prog_menu ()
313 local dmenu
= dmenu_cmd("cmd:")
315 local outfile
= os
.tmpname()
317 dmenu
[#dmenu
+1] = ">"
318 dmenu
[#dmenu
+1] = outfile
320 local cmd
= "dmenu_path |" .. table.concat(dmenu
," ")
323 local fh
= io
.open (outfile
, "rb")
326 local prog
= fh
:read("*l")
332 -- ------------------------------------------------------------------------
333 -- displays the a program menu, returns selected program
337 for s
in wmixp
:idir ("/tag") do
338 if s
.name
and not (s
.name
== "sel") then
346 -- ------------------------------------------------------------------------
347 -- displays the a program menu, returns selected program
349 local v
= wmixp
:read("/ctl") or ""
350 return v
:match("view%s+(%S+)")
353 -- ------------------------------------------------------------------------
354 -- changes the current view to the name given
355 function set_view(sel
)
356 local cur
= get_view()
357 local all
= get_tags()
359 if #all
< 2 or sel
== cur
then
360 -- nothing to do if we have less then 2 tags
364 if not (type(sel
) == "string") then
365 error ("string argument expected")
369 write ("/ctl", "view " .. sel
)
372 -- ------------------------------------------------------------------------
373 -- changes the current view to the index given
374 function set_view_index(sel
)
375 local cur
= get_view()
376 local all
= get_tags()
379 -- nothing to do if we have less then 2 tags
383 local num
= tonumber (sel
)
385 error ("number argument expected")
388 local name
= all
[sel
]
389 if not name
or name
== cur
then
394 write ("/ctl", "view " .. name
)
397 -- ------------------------------------------------------------------------
398 -- chnages to current view by offset given
399 function set_view_ofs(jump
)
400 local cur
= get_view()
401 local all
= get_tags()
404 -- nothing to do if we have less then 2 tags
409 if (jump
< - #all
) or (jump
> #all
) then
410 error ("view selector is out of range")
413 -- find the one that's selected index
416 for i
,v
in pairs (all
) do
417 if v
== cur
then curi
= i
end
421 local newi
= math
.fmod(#all
+ curi
+ jump
- 1, #all
) + 1
422 if (newi
< - #all
) or (newi
> #all
) then
423 error ("error computng new view")
426 write ("/ctl", "view " .. all
[newi
])
429 -- ------------------------------------------------------------------------
430 -- toggle between last view and current view
431 function toggle_view()
432 local last
= view_hist
[#view_hist
]
438 -- ========================================================================
440 -- ========================================================================
442 local action_handlers
= {
444 write ("/ctl", "quit")
447 exec
= function (act
, args
)
448 local what
= args
or wmiirc
449 write ("/ctl", "exec " .. what
)
453 posix
.exec ("lua", wmiirc
)
457 -- TODO: consider storing list of executables around, and
458 -- this will then reinitialize that list
459 log (" TODO: rehash")
463 -- TODO: this should eventually update something on the /rbar
464 log (" TODO: status")
468 -- ========================================================================
470 -- ========================================================================
472 local key_handlers
= {
473 ["*"] = function (key
)
477 -- execution and actions
478 ["Mod1-Return"] = function (key
)
479 local xterm
= get_conf("xterm") or "xterm"
480 log (" executing: " .. xterm
)
481 os
.execute (xterm
.. " &")
483 ["Mod1-Shift-Return"] = function (key
)
484 local tag = tag_menu()
486 local xterm
= get_conf("xterm") or "xterm"
487 log (" executing: " .. xterm
.. " on: " .. tag)
488 next_client_goes_to_tag
= tag
489 os
.execute (xterm
.. " &")
492 ["Mod1-a"] = function (key
)
493 local text
= menu(action_handlers
, "action:")
497 local si
= text
:find("%s")
499 act
,args
= string.match(text
.. " ", "(%w+)%s(.+)")
502 local fn
= action_handlers
[act
]
509 ["Mod1-p"] = function (key
)
510 local prog
= prog_menu()
512 log (" executing: " .. prog
)
513 os
.execute (prog
.. " &")
516 ["Mod1-Shift-p"] = function (key
)
517 local tag = tag_menu()
519 local prog
= prog_menu()
521 log (" executing: " .. prog
.. " on: " .. tag)
522 next_client_goes_to_tag
= tag
523 os
.execute (prog
.. " &")
527 ["Mod1-Shift-c"] = function (key
)
528 write ("/client/sel/ctl", "kill")
531 -- HJKL active selection
532 ["Mod1-h"] = function (key
)
533 write ("/tag/sel/ctl", "select left")
535 ["Mod1-l"] = function (key
)
536 write ("/tag/sel/ctl", "select right")
538 ["Mod1-j"] = function (key
)
539 write ("/tag/sel/ctl", "select down")
541 ["Mod1-k"] = function (key
)
542 write ("/tag/sel/ctl", "select up")
546 ["Mod1-Shift-h"] = function (key
)
547 write ("/tag/sel/ctl", "send sel left")
549 ["Mod1-Shift-l"] = function (key
)
550 write ("/tag/sel/ctl", "send sel right")
552 ["Mod1-Shift-j"] = function (key
)
553 write ("/tag/sel/ctl", "send sel down")
555 ["Mod1-Shift-k"] = function (key
)
556 write ("/tag/sel/ctl", "send sel up")
560 ["Mod1-space"] = function (key
)
561 write ("/tag/sel/ctl", "select toggle")
563 ["Mod1-Shift-space"] = function (key
)
564 write ("/tag/sel/ctl", "send sel toggle")
568 ["Mod4-#"] = function (key
, num
)
571 ["Mod4-Shift-#"] = function (key
, num
)
572 write ("/client/sel/tags", tostring(num
))
574 ["Mod1-comma"] = function (key
)
577 ["Mod1-period"] = function (key
)
580 ["Mod1-r"] = function (key
)
581 -- got to the last view
585 -- switching views and retagging
586 ["Mod1-t"] = function (key
)
588 local tag = tag_menu()
593 ["Mod1-Shift-t"] = function (key
)
594 -- move selected client to a tag
595 local tag = tag_menu()
597 write ("/client/sel/tags", tag)
600 ["Mod1-Shift-r"] = function (key
)
601 -- move selected client to a tag, and follow
602 local tag = tag_menu()
604 write ("/client/sel/tags", tag)
608 ["Mod1-Control-t"] = function (key
)
609 log (" TODO: Mod1-Control-t: " .. key
)
613 ["Mod1-d"] = function (key
)
614 write("/tag/sel/ctl", "colmode sel default")
616 ["Mod1-s"] = function (key
)
617 write("/tag/sel/ctl", "colmode sel stack")
619 ["Mod1-m"] = function (key
)
620 write("/tag/sel/ctl", "colmode sel max")
624 -- ------------------------------------------------------------------------
625 -- update the /keys wmii file with the list of all handlers
626 function update_active_keys ()
629 for x
,y
in pairs(key_handlers
) do
631 local i
= x
:find("#")
644 local all_keys
= table.concat(t
, "\n")
645 --log ("setting /keys to...\n" .. all_keys .. "\n");
646 write ("/keys", all_keys
)
649 -- ------------------------------------------------------------------------
650 -- update the /lbar wmii file with the current tags
651 function update_displayed_tags ()
653 local fc
= get_ctl("focuscolors") or ""
654 local nc
= get_ctl("normcolors") or ""
656 -- build up a table of existing tags in the /lbar
659 for s
in wmixp
:idir ("/lbar") do
663 -- for all actual tags in use create any entries in /lbar we don't have
664 -- clear the old table entries if we have them
665 local cur
= get_view()
666 local all
= get_tags()
668 for i
,v
in pairs(all
) do
674 create ("/lbar/" .. v
, color
.. " " .. v
)
676 write ("/lbar/" .. v
, color
.. " " .. v
)
680 -- anything left in the old table should be removed now
681 for i
,v
in pairs(old
) do
688 -- ========================================================================
690 -- ========================================================================
692 local ev_handlers
= {
693 ["*"] = function (ev
, arg
)
694 log ("ev: " .. tostring(ev
) .. " - " .. tostring(arg
))
697 -- process timer events
698 ProcessTimerEvents
= function (ev
, arg
)
702 -- exit if another wmiirc started up
703 Start
= function (ev
, arg
)
705 if arg
== "wmiirc" then
706 -- backwards compatibility with bash version
709 -- ignore if it came from us
710 local pid
= string.match(arg
, "wmiirc (%d+)")
712 local pid
= tonumber (pid
)
713 if not (pid
== mypid
) then
722 CreateTag
= function (ev
, arg
)
723 local nc
= get_ctl("normcolors") or ""
724 create ("/lbar/" .. arg
, nc
.. " " .. arg
)
726 DestroyTag
= function (ev
, arg
)
727 remove ("/lbar/" .. arg
)
730 FocusTag
= function (ev
, arg
)
731 local fc
= get_ctl("focuscolors") or ""
732 create ("/lbar/" .. arg
, fc
.. " " .. arg
)
733 write ("/lbar/" .. arg
, fc
.. " " .. arg
)
735 UnfocusTag
= function (ev
, arg
)
736 local nc
= get_ctl("normcolors") or ""
737 create ("/lbar/" .. arg
, nc
.. " " .. arg
)
738 write ("/lbar/" .. arg
, nc
.. " " .. arg
)
740 -- don't duplicate the last entry
741 if not (arg
== view_hist
[#view_hist
]) then
742 view_hist
[#view_hist
+1] = arg
744 -- limit to view_hist_max
745 if #view_hist
> view_hist_max
then
746 table.remove(view_hist
, 1)
751 -- key event handling
752 Key
= function (ev
, arg
)
755 -- can we find an exact match?
756 local fn
= key_handlers
[arg
]
758 local key
= arg
:gsub("-%d+", "-#")
759 -- can we find a match with a # wild card for the number
760 fn
= key_handlers
[key
]
762 -- convert the trailing number to a number
763 num
= tonumber(arg
:match("-(%d+)"))
765 -- everything else failed, try default match
766 fn
= key_handlers
["*"]
774 -- mouse handling on the lbar
775 LeftBarClick
= function (ev
, arg
)
776 local button
,tag = string.match(arg
, "(%w+)%s+(%w+)")
781 ClientFocus
= function (ev
, arg
)
782 log ("ClientFocus: " .. arg
)
784 ColumnFocus
= function (ev
, arg
)
785 log ("ColumnFocus: " .. arg
)
789 CreateClient
= function (ev
, arg
)
790 if next_client_goes_to_tag
then
791 local tag = next_client_goes_to_tag
793 next_client_goes_to_tag
= nil
794 write ("/client/" .. cli
.. "/tags", tag)
800 UrgentTag
= function (ev
, arg
)
801 log ("UrgentTag: " .. arg
)
802 -- wmiir xwrite "/lbar/$@" "*$@"
804 NotUrgentTag
= function (ev
, arg
)
805 log ("NotUrgentTag: " .. arg
)
806 -- wmiir xwrite "/lbar/$@" "$@"
811 -- ========================================================================
812 -- MAIN INTERFACE FUNCTIONS
813 -- ========================================================================
816 xterm
= 'x-terminal-emulator'
819 -- ------------------------------------------------------------------------
820 -- write configuration to /ctl wmii file
821 -- wmii.set_ctl({ "var" = "val", ...})
822 -- wmii.set_ctl("var, "val")
823 function set_ctl (first
,second
)
824 if type(first
) == "table" and second
== nil then
826 for x
, y
in pairs(first
) do
827 write ("/ctl", x
.. " " .. y
)
830 elseif type(first
) == "string" and type(second
) == "string" then
831 write ("/ctl", first
.. " " .. second
)
834 error ("expecting a table or two string arguments")
838 -- ------------------------------------------------------------------------
839 -- read a value from /ctl wmii file
840 function get_ctl (name
)
842 for s
in iread("/ctl") do
843 local var
,val
= s
:match("(%w+)%s+(.+)")
851 -- ------------------------------------------------------------------------
852 -- set an internal wmiirc.lua variable
853 -- wmii.set_conf({ "var" = "val", ...})
854 -- wmii.set_conf("var, "val")
855 function set_conf (first
,second
)
856 if type(first
) == "table" and second
== nil then
858 for x
, y
in pairs(first
) do
862 elseif type(first
) == "string"
863 and (type(second
) == "string"
864 or type(second
) == "number") then
865 config
[first
] = second
868 error ("expecting a table, or string and string/number as arguments")
872 -- ------------------------------------------------------------------------
873 -- read an internal wmiirc.lua variable
874 function get_conf (name
)
878 -- ========================================================================
880 -- ========================================================================
882 -- the event loop instance
883 local el
= eventloop
.new()
885 -- add the core event handler for events
886 el
:add_exec (wmiir
.. " read /event",
888 local line
= line
or "nil"
890 -- try to split off the argument(s)
891 local ev
,arg
= string.match(line
, "(%S+)%s+(.+)")
896 -- now locate the handler function and call it
897 local fn
= ev_handlers
[ev
] or ev_handlers
["*"]
903 -- ------------------------------------------------------------------------
904 -- run the event loop and process events, this function does not exit
905 function run_event_loop ()
906 -- stop any other instance of wmiirc
907 wmixp
:write ("/event", "Start wmiirc " .. tostring(mypid
))
909 log("wmii: updating lbar")
911 update_displayed_tags ()
913 log("wmii: updating rbar")
915 update_displayed_widgets ()
917 log("wmii: updating active keys")
919 update_active_keys ()
921 log("wmii: starting event loop")
923 local sleep_for
= process_timers()
924 el
:run_loop(sleep_for
)
928 -- ========================================================================
930 -- ========================================================================
932 -- ------------------------------------------------------------------------
937 -- ------------------------------------------------------------------------
938 -- create a widget object and add it to the wmii /rbar
941 -- widget = wmii.widget:new ("999_clock")
942 -- widget = wmii.widget:new ("999_clock", clock_event_handler)
943 function widget
:new (name
, fn
)
946 if type(name
) == "string" then
948 if type(fn
) == "function" then
952 error ("expected name followed by an optional function as arguments")
955 setmetatable (o
,self
)
957 self
.__gc
= function (o
) o
:hide() end
965 -- ------------------------------------------------------------------------
966 -- stop and destroy the timer
967 function widget
:delete ()
968 widgets
[self
.name
] = nil
972 -- ------------------------------------------------------------------------
973 -- displays or updates the widget text
974 function widget
:show (txt
)
975 local txt
= txt
or ""
976 local color
= get_ctl("normcolors") or ""
978 create ("/rbar/" .. self
.name
, color
.. " " .. txt
)
980 write ("/rbar/" .. self
.name
, color
.. " " .. txt
)
985 -- ------------------------------------------------------------------------
986 -- hides a widget and removes it from the bar
987 function widget
:hide ()
989 remove ("/lbar/" .. self
.name
)
994 -- ------------------------------------------------------------------------
995 -- remove all /rbar entries that we don't have widget objects for
996 function update_displayed_widgets ()
998 local nc
= get_ctl("normcolors") or ""
1000 -- build up a table of existing tags in the /lbar
1003 for s
in wmixp
:idir ("/rbar") do
1007 -- for all actual widgets in use we want to remove them from the old list
1009 for i
,v
in pairs(widgets
) do
1013 -- anything left in the old table should be removed now
1014 for i
,v
in pairs(old
) do
1021 -- ------------------------------------------------------------------------
1022 -- create a new program and for each line it generates call the callback function
1023 -- returns fd which can be passed to kill_exec()
1024 function add_exec (command
, callback
)
1025 return el
:add_exec (command
, callback
)
1028 -- ------------------------------------------------------------------------
1029 -- terminates a program spawned off by add_exec()
1030 function kill_exec (fd
)
1031 return el
:kill_exec (fd
)
1034 -- ------------------------------------------------------------------------
1039 -- ------------------------------------------------------------------------
1040 -- create a timer object and add it to the event loop
1043 -- timer:new (my_timer_fn)
1044 -- timer:new (my_timer_fn, 15)
1045 function timer
:new (fn
, seconds
)
1048 if type(fn
) == "function" then
1051 error ("expected function followed by an optional number as arguments")
1054 setmetatable (o
,self
)
1056 self
.__gc
= function (o
) o
:stop() end
1059 timers
[#timers
+1] = o
1067 -- ------------------------------------------------------------------------
1068 -- stop and destroy the timer
1069 function timer
:delete ()
1072 for i
,t
in pairs(timers
) do
1074 table.remove (timers
,i
)
1080 -- ------------------------------------------------------------------------
1081 -- run the timer given new interval
1082 function timer
:resched (seconds
)
1083 local seconds
= seconds
or self
.interval
1084 if not (type(seconds
) == "number") then
1085 error ("expected number as argument")
1088 local now
= tonumber(os
.date("%s"))
1090 self
.interval
= seconds
1091 self
.next_time
= now
+ seconds
1093 -- resort the timer list
1094 table.sort (timers
, timer
.is_less_then
)
1097 function timer
:is_less_then(another
)
1098 if not self
.next_time
then
1099 return false -- another is smaller, nil means infinity
1101 elseif not another
.next_time
then
1102 return true -- self is smaller, nil means infinity
1104 elseif self
.next_time
< another
.next_time
then
1105 return true -- self is smaller than another
1108 return false -- another is smaller then self
1111 -- ------------------------------------------------------------------------
1113 function timer
:stop ()
1114 self
.next_time
= nil
1116 -- resort the timer list
1117 table.sort (timers
, timer
.is_less_then
)
1120 -- ------------------------------------------------------------------------
1121 -- figure out how long before the next event
1122 function time_before_next_timer_event()
1123 local timer
= timers
[1]
1124 if timer
and timer
.next_time
then
1125 local now
= tonumber(os
.date("%s"))
1126 local seconds
= timer
.next_time
- now
1131 return 0 -- sleep for ever
1134 -- ------------------------------------------------------------------------
1135 -- handle outstanding events
1136 function process_timers ()
1137 local now
= tonumber(os
.date("%s"))
1141 for i
,timer
in pairs (timers
) do
1142 if (not timer
) or (not timer
.next_time
) then
1143 table.remove(timers
,i
)
1147 if timer
.next_time
> now
then
1148 return timer
.next_time
- now
1151 torun
[#torun
+1] = timer
1154 for i
,timer
in pairs (torun
) do
1156 local new_interval
= timer
:fn()
1157 if not (new_interval
== -1) then
1162 local sleep_for
= time_before_next_timer_event()
1167 -- ========================================================================
1169 -- ========================================================================
1182 Used to determine location of wmii's listen socket.
1188 L<wmii(1)>, L<lua(1)>
1192 Bart Trojanowski B<< <bart@jukie.net> >>
1194 =head1 COPYRIGHT AND LICENSE
1196 Copyright (c) 2007, Bart Trojanowski <bart@jukie.net>
1198 This is free software. You may redistribute copies of it under the terms of
1199 the GNU General Public License L<http://www.gnu.org/licenses/gpl.html>. There
1200 is NO WARRANTY, to the extent permitted by law.