File: signal.lua

package info (click to toggle)
luakit 2012.09.13-r1-8
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 1,160 kB
  • ctags: 1,276
  • sloc: ansic: 6,086; makefile: 153; ruby: 79; sh: 38
file content (120 lines) | stat: -rw-r--r-- 3,274 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
--------------------------------------------------------------
-- Mimic the luakit signal api functions for tables         --
-- @author Fabian Streitel <karottenreibe@gmail.com>  --
-- @author Mason Larobina  <mason.larobina@gmail.com> --
-- @copyright 2010 Fabian Streitel, Mason Larobina          --
--------------------------------------------------------------

-- Grab environment we need
local assert = assert
local io = io
local ipairs = ipairs
local setmetatable = setmetatable
local string = string
local table = table
local tostring = tostring
local type = type
local unpack = unpack
local verbose = luakit.verbose

--- Provides a signal API similar to GTK's signals.
module("lousy.signal")

-- Private signal data for objects
local data = setmetatable({}, { __mode = "k" })

local methods = {
    "add_signal",
    "emit_signal",
    "remove_signal",
    "remove_signals",
}

local function get_data(object)
    local d = data[object]
    assert(d, "object isn't setup for signals")
    return d
end

function add_signal(object, signame, func)
    local signals = get_data(object).signals

    -- Check signal name
    assert(type(signame) == "string", "invalid signame type: " .. type(signame))
    assert(string.match(signame, "^[%w_%-:]+$"), "invalid chars in signame: " .. signame)

    -- Check handler function
    assert(type(func) == "function", "invalid handler function")

    -- Add to signals table
    if not signals[signame] then
        signals[signame] = { func, }
    else
        table.insert(signals[signame], func)
    end
end

function emit_signal(object, signame, ...)
    local d = get_data(object)
    local sigfuncs = d.signals[signame] or {}

    if verbose then
        io.stderr:write(string.format("D: lousy.signal: emit_signal: "
            .. "%q on %s\n", signame, tostring(object)))
    end

    for _, sigfunc in ipairs(sigfuncs) do
        local ret
        if d.module then
            ret = { sigfunc(...) }
        else
            ret = { sigfunc(object, ...) }
        end
        if ret[1] ~= nil then
            return unpack(ret)
        end
    end
end

-- Remove a signame & function pair.
function remove_signal(object, signame, func)
    local signals = get_data(object).signals
    local sigfuncs = signals[signame] or {}

    for i, sigfunc in ipairs(sigfuncs) do
        if sigfunc == func then
            table.remove(sigfuncs, i)
            -- Remove empty sigfuncs table
            if #sigfuncs == 0 then
                signals[signame] = nil
            end
            return func
        end
    end
end

-- Remove all signal handlers with the given signame.
function remove_signals(object, signame)
    local signals = get_data(object).signals
    signals[signame] = nil
end

function setup(object, module)
    assert(not data[object], "given object already setup for signals")

    data[object] = { signals = {}, module = module }

    for _, fn in ipairs(methods) do
        assert(not object[fn], "signal object method conflict: " .. fn)
        if module then
            local func = _M[fn]
            object[fn] = function (...) return func(object, ...) end
        else
            object[fn] = _M[fn]
        end
    end

    return object
end

-- vim: et:sw=4:ts=8:sts=4:tw=80