lua: add API for observing property changes

A low level API was added already earlier, but that was merely a binding
for the raw C API. Add a "proper" one, and document it.
This commit is contained in:
wm4 2014-04-08 21:10:00 +02:00
parent 708f32b746
commit a94020e25b
3 changed files with 60 additions and 4 deletions

View File

@ -240,6 +240,28 @@ The ``mp`` module is preloaded, although it can be loaded manually with
are equal to the ``fn`` parameter. This uses normal Lua ``==`` comparison, are equal to the ``fn`` parameter. This uses normal Lua ``==`` comparison,
so be careful when dealing with closures. so be careful when dealing with closures.
``mp.observe_property(name, type, fn)``
Watch a property for changes. If the property ``name`` is changed, then
the function ``fn(name)`` will be called. ``type`` can be ``nil``, or be
set to one of ``none``, ``native``, ``bool``, ``string``, or ``number``.
``none`` is the same as ``nil``. For all other values, the new value of
the property will be passed as second argument to ``fn``, using
``mp.get_property_<type>`` to retrieve it. This means if ``type`` is for
example ``string``, ``fn`` is roughly called as in
``fn(name, mp.get_property_string(name))``.
Sporadic property change events are possible. This means the change function
``fn`` can be called even if the property doesn't actually change. Likewise,
in some cases the function is not called even if the property changes. If
possible, change events are coalesced. If a property is changed a bunch of
times in a row, only the last change triggers the change function. (The
exact behavior depends on timing and other things.)
``mp.unobserve_property(fn)``
Undo ``mp.observe_property(..., fn)``. This removes all property handlers
that are equal to the ``fn`` parameter. This uses normal Lua ``==``
comparison, so be careful when dealing with closures.
``mp.add_timeout(seconds, fn)`` ``mp.add_timeout(seconds, fn)``
Call the given function fn when the given number of seconds has elapsed. Call the given function fn when the given number of seconds has elapsed.
Note that the number of seconds can be fractional. As of now, the timer Note that the number of seconds can be fractional. As of now, the timer

View File

@ -432,6 +432,11 @@ static int script_wait_event(lua_State *L)
lua_pushstring(L, mpv_event_name(event->event_id)); // event name lua_pushstring(L, mpv_event_name(event->event_id)); // event name
lua_setfield(L, -2, "event"); // event lua_setfield(L, -2, "event"); // event
if (event->reply_userdata) {
lua_pushnumber(L, event->reply_userdata);
lua_setfield(L, -2, "id");
}
if (event->error < 0) { if (event->error < 0) {
lua_pushstring(L, mpv_error_string(event->error)); // event err lua_pushstring(L, mpv_error_string(event->error)); // event err
lua_setfield(L, -2, "error"); // event lua_setfield(L, -2, "error"); // event
@ -880,6 +885,8 @@ static int script_get_property_native(lua_State *L)
static mpv_format check_property_format(lua_State *L, int arg) static mpv_format check_property_format(lua_State *L, int arg)
{ {
if (lua_isnil(L, arg))
return MPV_FORMAT_NONE;
const char *fmts[] = {"none", "native", "bool", "string", "number", NULL}; const char *fmts[] = {"none", "native", "bool", "string", "number", NULL};
switch (luaL_checkoption(L, arg, "none", fmts)) { switch (luaL_checkoption(L, arg, "none", fmts)) {
case 0: return MPV_FORMAT_NONE; case 0: return MPV_FORMAT_NONE;
@ -891,7 +898,8 @@ static mpv_format check_property_format(lua_State *L, int arg)
abort(); abort();
} }
static int script_observe_property(lua_State *L) // It has a raw_ prefix, because there is a more high level API in defaults.lua.
static int script_raw_observe_property(lua_State *L)
{ {
struct script_ctx *ctx = get_ctx(L); struct script_ctx *ctx = get_ctx(L);
uint64_t id = luaL_checknumber(L, 1); uint64_t id = luaL_checknumber(L, 1);
@ -900,7 +908,7 @@ static int script_observe_property(lua_State *L)
return check_error(L, mpv_observe_property(ctx->client, id, name, format)); return check_error(L, mpv_observe_property(ctx->client, id, name, format));
} }
static int script_unobserve_property(lua_State *L) static int script_raw_unobserve_property(lua_State *L)
{ {
struct script_ctx *ctx = get_ctx(L); struct script_ctx *ctx = get_ctx(L);
uint64_t id = luaL_checknumber(L, 1); uint64_t id = luaL_checknumber(L, 1);
@ -1063,8 +1071,8 @@ static struct fn_entry fn_list[] = {
FN_ENTRY(set_property_bool), FN_ENTRY(set_property_bool),
FN_ENTRY(set_property_number), FN_ENTRY(set_property_number),
FN_ENTRY(set_property_native), FN_ENTRY(set_property_native),
FN_ENTRY(observe_property), FN_ENTRY(raw_observe_property),
FN_ENTRY(unobserve_property), FN_ENTRY(raw_unobserve_property),
FN_ENTRY(property_list), FN_ENTRY(property_list),
FN_ENTRY(set_osd_ass), FN_ENTRY(set_osd_ass),
FN_ENTRY(get_osd_resolution), FN_ENTRY(get_osd_resolution),

View File

@ -241,6 +241,31 @@ local function message_dispatch(ev)
end end
end end
local property_id = 0
local properties = {}
function mp.observe_property(name, t, cb)
local id = property_id + 1
property_id = id
properties[id] = cb
mp.raw_observe_property(id, name, t)
end
function mp.unobserve_property(cb)
for prop_id, prop_cb in pairs(properties) do
if cb == prop_cb then
properties[prop_id] = nil
end
end
end
local function property_change(ev)
local prop = properties[ev.id]
if prop then
prop(ev.name, ev.data)
end
end
-- used by default event loop (mp_event_loop()) to decide when to quit -- used by default event loop (mp_event_loop()) to decide when to quit
mp.keep_running = true mp.keep_running = true
@ -286,6 +311,7 @@ end
mp.register_event("shutdown", function() mp.keep_running = false end) mp.register_event("shutdown", function() mp.keep_running = false end)
mp.register_event("script-input-dispatch", script_dispatch) mp.register_event("script-input-dispatch", script_dispatch)
mp.register_event("client-message", message_dispatch) mp.register_event("client-message", message_dispatch)
mp.register_event("property-change", property_change)
mp.msg = { mp.msg = {
log = mp.log, log = mp.log,