mirror of https://github.com/mpv-player/mpv
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:
parent
708f32b746
commit
a94020e25b
|
@ -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
|
||||||
|
|
16
player/lua.c
16
player/lua.c
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue