-
Notifications
You must be signed in to change notification settings - Fork 0
/
watcher.lua
75 lines (61 loc) · 2.02 KB
/
watcher.lua
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
local gtable_crush = require("gears.table").crush
local gtimer = require("gears.timer")
local object = require("gears.object")
local module = {}
local class = {}
function class:get_parsed_menu()
local ret = rawget(self, "parsed_menu")
if ret ~= nil then
-- Return the cached value, when available.
return ret
end
ret = self.menu_parser(self.raw_menu)
rawset(self, "parsed_menu", ret)
return ret
end
function class:set_raw_menu()
error("Cannot set 'raw_menu' property, because it is read-only")
end
function class:signal_menu_change()
rawset(self, "parsed_menu", nil)
self:emit_signal("gnome_menu::changed")
end
-- Runs a given function immediately once, and then after every menu change.
function class:run_on_menu_change(handler)
self:connect_signal("gnome_menu::changed", handler)
handler(self)
end
function module.new(args)
args = args or {}
assert(args.raw_menu)
assert(args.menu_parser)
local ret = object({
-- class = class,
enable_properties = true,
enable_auto_signals = true,
})
-- Copy over class methods.
gtable_crush(ret, class, true)
-- Init properties.
rawset(ret, "raw_menu", args.raw_menu)
rawset(ret, "menu_parser", args.menu_parser)
rawset(ret, "parsed_menu", nil)
-- Invalidate parsed menu cache too, if the user happens to change the menu parser.
ret:connect_signal("property::menu_parser", function(o) o:signal_menu_change() end)
local signal_scheduled = false
args.raw_menu.on_changed = function()
-- Throttle/coalesce the signals to avoid getting DoS-ed with inotify events,
-- otherwise a malicious program that quickly adds/removes a .menu file
-- in the watched dirs can hang awesome for good.
if signal_scheduled then
return
end
signal_scheduled = true
gtimer.delayed_call(function()
signal_scheduled = false
ret:signal_menu_change()
end)
end
return ret
end
return module