gears.object: Add :weak_connect_signal()
Connecting to a signal weakly has the same effect as connecting to it strongly, but it allows the garbage collector to disconnect the signal in case nothing else references this function. Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
parent
38840c911b
commit
089ed0e8dd
|
@ -38,7 +38,10 @@ function object:add_signal(name)
|
||||||
check(self)
|
check(self)
|
||||||
assert(type(name) == "string", "name must be a string, got: " .. type(name))
|
assert(type(name) == "string", "name must be a string, got: " .. type(name))
|
||||||
if not self._signals[name] then
|
if not self._signals[name] then
|
||||||
self._signals[name] = {}
|
self._signals[name] = {
|
||||||
|
strong = {},
|
||||||
|
weak = setmetatable({}, { __mode = "k" })
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -48,7 +51,19 @@ end
|
||||||
function object:connect_signal(name, func)
|
function object:connect_signal(name, func)
|
||||||
assert(type(func) == "function", "callback must be a function, got: " .. type(func))
|
assert(type(func) == "function", "callback must be a function, got: " .. type(func))
|
||||||
local sig = find_signal(self, name, "connect to")
|
local sig = find_signal(self, name, "connect to")
|
||||||
sig[func] = func
|
assert(sig.weak[func] == nil, "Trying to connect a strong callback which is already connected weakly")
|
||||||
|
sig.strong[func] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Connect to a signal weakly. This allows the callback function to be garbage
|
||||||
|
-- collected and automatically disconnects the signal when that happens.
|
||||||
|
-- @param name The name of the signal
|
||||||
|
-- @param func The callback to call when the signal is emitted
|
||||||
|
function object:weak_connect_signal(name, func)
|
||||||
|
assert(type(func) == "function", "callback must be a function, got: " .. type(func))
|
||||||
|
local sig = find_signal(self, name, "connect to")
|
||||||
|
assert(sig.strong[func] == nil, "Trying to connect a weak callback which is already connected strongly")
|
||||||
|
sig.weak[func] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Disonnect to a signal
|
--- Disonnect to a signal
|
||||||
|
@ -56,7 +71,8 @@ end
|
||||||
-- @param func The callback that should be disconnected
|
-- @param func The callback that should be disconnected
|
||||||
function object:disconnect_signal(name, func)
|
function object:disconnect_signal(name, func)
|
||||||
local sig = find_signal(self, name, "disconnect from")
|
local sig = find_signal(self, name, "disconnect from")
|
||||||
sig[func] = nil
|
sig.weak[func] = nil
|
||||||
|
sig.strong[func] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Emit a signal
|
--- Emit a signal
|
||||||
|
@ -67,7 +83,10 @@ end
|
||||||
-- that are given to emit_signal()
|
-- that are given to emit_signal()
|
||||||
function object:emit_signal(name, ...)
|
function object:emit_signal(name, ...)
|
||||||
local sig = find_signal(self, name, "emit")
|
local sig = find_signal(self, name, "emit")
|
||||||
for func in pairs(sig) do
|
for func in pairs(sig.strong) do
|
||||||
|
func(self, ...)
|
||||||
|
end
|
||||||
|
for func in pairs(sig.weak) do
|
||||||
func(self, ...)
|
func(self, ...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,13 +12,19 @@ describe("gears.object", function()
|
||||||
obj:add_signal("signal")
|
obj:add_signal("signal")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("connect non-existent signal", function()
|
it("strong connect non-existent signal", function()
|
||||||
assert.has.errors(function()
|
assert.has.errors(function()
|
||||||
obj:connect_signal("foo", function() end)
|
obj:connect_signal("foo", function() end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("disconnect non-existent signal", function()
|
it("weak connect non-existent signal", function()
|
||||||
|
assert.has.errors(function()
|
||||||
|
obj:weak_connect_signal("foo", function() end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("strong disconnect non-existent signal", function()
|
||||||
assert.has.errors(function()
|
assert.has.errors(function()
|
||||||
obj:disconnect_signal("foo", function() end)
|
obj:disconnect_signal("foo", function() end)
|
||||||
end)
|
end)
|
||||||
|
@ -30,16 +36,27 @@ describe("gears.object", function()
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("connecting and emitting signal", function()
|
it("strong connecting and emitting signal", function()
|
||||||
local called = false
|
local called = false
|
||||||
obj:connect_signal("signal", function()
|
local function cb()
|
||||||
called = true
|
called = true
|
||||||
end)
|
end
|
||||||
|
obj:connect_signal("signal", cb)
|
||||||
obj:emit_signal("signal")
|
obj:emit_signal("signal")
|
||||||
assert.is_true(called)
|
assert.is_true(called)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("connecting, disconnecting and emitting signal", function()
|
it("weak connecting and emitting signal", function()
|
||||||
|
local called = false
|
||||||
|
local function cb()
|
||||||
|
called = true
|
||||||
|
end
|
||||||
|
obj:weak_connect_signal("signal", cb)
|
||||||
|
obj:emit_signal("signal")
|
||||||
|
assert.is_true(called)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("strong connecting, disconnecting and emitting signal", function()
|
||||||
local called = false
|
local called = false
|
||||||
local function cb()
|
local function cb()
|
||||||
called = true
|
called = true
|
||||||
|
@ -50,13 +67,64 @@ describe("gears.object", function()
|
||||||
assert.is_false(called)
|
assert.is_false(called)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it("weak connecting, disconnecting and emitting signal", function()
|
||||||
|
local called = false
|
||||||
|
local function cb()
|
||||||
|
called = true
|
||||||
|
end
|
||||||
|
obj:weak_connect_signal("signal", cb)
|
||||||
|
obj:disconnect_signal("signal", cb)
|
||||||
|
obj:emit_signal("signal")
|
||||||
|
assert.is_false(called)
|
||||||
|
end)
|
||||||
|
|
||||||
it("arguments to signal", function()
|
it("arguments to signal", function()
|
||||||
obj:connect_signal("signal", function(arg1, arg2)
|
obj:connect_signal("signal", function(arg1, arg2)
|
||||||
assert.is.equal(obj, arg1)
|
assert.is.equal(obj, arg1)
|
||||||
assert.is.same(42, arg2)
|
assert.is.same(42, arg2)
|
||||||
end)
|
end)
|
||||||
|
obj:weak_connect_signal("signal", function(arg1, arg2)
|
||||||
|
assert.is.equal(obj, arg1)
|
||||||
|
assert.is.same(42, arg2)
|
||||||
|
end)
|
||||||
obj:emit_signal("signal", 42)
|
obj:emit_signal("signal", 42)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it("strong non-auto disconnect", function()
|
||||||
|
local called = false
|
||||||
|
obj:connect_signal("signal", function()
|
||||||
|
called = true
|
||||||
|
end)
|
||||||
|
collectgarbage("collect")
|
||||||
|
obj:emit_signal("signal")
|
||||||
|
assert.is_true(called)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("weak auto disconnect", function()
|
||||||
|
local called = false
|
||||||
|
obj:weak_connect_signal("signal", function()
|
||||||
|
called = true
|
||||||
|
end)
|
||||||
|
collectgarbage("collect")
|
||||||
|
obj:emit_signal("signal")
|
||||||
|
assert.is_false(called)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("strong connect after weak connect", function()
|
||||||
|
local function cb() end
|
||||||
|
obj:weak_connect_signal("signal", cb)
|
||||||
|
assert.has.errors(function()
|
||||||
|
obj:connect_signal("signal", cb)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("weak connect after strong connect", function()
|
||||||
|
local function cb() end
|
||||||
|
obj:connect_signal("signal", cb)
|
||||||
|
assert.has.errors(function()
|
||||||
|
obj:weak_connect_signal("signal", cb)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|
||||||
|
|
Loading…
Reference in New Issue