From 0367af2be9f773582df1e7fb53cf59498d1ceadd Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Tue, 11 Aug 2015 13:21:32 +0200 Subject: [PATCH 1/2] gears.timer: Add simpler ways to start timers This adds gears.timer.start(timeout, callback) that creates a timer object and connects a callback to it, all in one go. Additionally, this adds gears.timer.weak_start(timeout, callback). The weak version still allows the callback function to be garbage collected and will then stop the timer. This was tested with the following code: require("gears.timer").start(0.3, function() print("ping") if collectgarbage("step", 500) then print("collection done") error("err") end return true end) require("gears.timer").weak_start(0.1, function() io.stdout:write(".") return true end) After a full collection cycle, both timers are stopped. The first one is stopped because of the error() that it generated. The second one is stopped because the callback function was garbage collected. Ref: https://github.com/awesomeWM/awesome/issues/216 Signed-off-by: Uli Schlachter --- lib/gears/timer.lua | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/lib/gears/timer.lua b/lib/gears/timer.lua index cda03b3b6..f95bfe2ad 100644 --- a/lib/gears/timer.lua +++ b/lib/gears/timer.lua @@ -103,6 +103,46 @@ timer.new = function(args) return ret end +--- Create a timeout for calling some callback function. +-- When the callback function returns true, it will be called again after the +-- same timeout. If false is returned, no more calls will be done. If the +-- callback function causes an error, no more calls are done. +-- @tparam number timeout Timeout in seconds (e.g. 1.5). +-- @tparam function callback Function to run. +-- @see timer.weak_start_new +function timer.start_new(timeout, callback) + local t = timer.new({ timeout = timeout }) + t:connect_signal("timeout", function() + local success, cont = xpcall(callback, function(err) + print(debug.traceback("Error during executing timeout handler: "..tostring(err), 2)) + end) + if not success or not cont then + t:stop() + end + end) + t:start() + return t +end + +--- Create a timeout for calling some callback function. +-- This function is almost identical to `timer.start_new`. The only difference +-- is that this does not prevent the callback function from being garbage +-- collected. After the callback function was collected, the timer returned +-- will automatically be stopped. +-- @tparam number timeout Timeout in seconds (e.g. 1.5). +-- @tparam function callback Function to start. +-- @see timer.start_new +function timer.weak_start_new(timeout, callback) + local indirection = setmetatable({}, { __mode = "v" }) + indirection.callback = callback + return timer.start_new(timeout, function() + local cb = indirection.callback + if cb then + return cb() + end + end) +end + local delayed_calls = {} capi.awesome.connect_signal("refresh", function() for _, callback in ipairs(delayed_calls) do From 74276b3a1171bbb819552e9394e4e5b9baff66cf Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Tue, 11 Aug 2015 13:29:49 +0200 Subject: [PATCH 2/2] gears.timer: Add a note about GC'ing timers Ref: https://github.com/awesomeWM/awesome/issues/216 Signed-off-by: Uli Schlachter --- lib/gears/timer.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/gears/timer.lua b/lib/gears/timer.lua index f95bfe2ad..3a14dfbb5 100644 --- a/lib/gears/timer.lua +++ b/lib/gears/timer.lua @@ -20,7 +20,8 @@ local object = require("gears.object") --- Timer objects. This type of object is useful when triggering events repeatedly. -- The timer will emit the "timeout" signal every N seconds, N being the timeout --- value. +-- value. Note that a started timer will not be garbage collected. Call `:stop` +-- to enable garbage collection. -- @tfield number timeout Interval in seconds to emit the timeout signal. -- Can be any value, including floating point ones -- (e.g. 1.5 seconds).