summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-02-10 21:03:59 +0100
committerwm4 <wm4@nowhere>2014-02-10 21:03:59 +0100
commit206616b697672d973b24330af9b094ac851f7ca4 (patch)
tree5baea012aa584c11f573373c1c7cbeddced209f5 /player
parent88ae914b1ef2b76362c527985bd459b0d8226d45 (diff)
downloadmpv-206616b697672d973b24330af9b094ac851f7ca4.tar.bz2
mpv-206616b697672d973b24330af9b094ac851f7ca4.tar.xz
lua: port to client API
This is partial only, and it still accesses some MPContext internals. Specifically, chapter and track lists are still read directly, and OSD access is special-cased too. The OSC seems to work fine, except using the fast-forward/backward buttons. These buttons behave differently, because the OSC code had certain assumptions how often its update code is called. The Lua interface changes slightly. Note that this has the odd property that Lua script and video start at the same time, asynchronously. If this becomes an issue, explicit synchronization could be added.
Diffstat (limited to 'player')
-rw-r--r--player/command.c57
-rw-r--r--player/command.h1
-rw-r--r--player/core.h1
-rw-r--r--player/loadfile.c2
-rw-r--r--player/lua.c337
-rw-r--r--player/lua.h4
-rw-r--r--player/lua/defaults.lua47
-rw-r--r--player/lua/osc.lua11
-rw-r--r--player/main.c3
-rw-r--r--player/playloop.c3
10 files changed, 242 insertions, 224 deletions
diff --git a/player/command.c b/player/command.c
index 2d0f7c0d9a..ada0aef16e 100644
--- a/player/command.c
+++ b/player/command.c
@@ -78,8 +78,6 @@
#include "lua.h"
struct command_ctx {
- int events;
-
double last_seek_time;
double last_seek_pts;
@@ -3119,14 +3117,20 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
cmd->args[1].v.s, msg_osd);
break;
- case MP_CMD_SCRIPT_DISPATCH:
- if (mpctx->lua_ctx) {
-#if HAVE_LUA
- mp_lua_script_dispatch(mpctx, cmd->args[0].v.s, cmd->args[1].v.i,
- cmd->key_up_follows ? "keyup_follows" : "press");
-#endif
+ case MP_CMD_SCRIPT_DISPATCH: {
+ mpv_event_script_input_dispatch *event = talloc_ptrtype(NULL, event);
+ *event = (mpv_event_script_input_dispatch){
+ .arg0 = cmd->args[1].v.i,
+ .type = cmd->key_up_follows ? "keyup_follows" : "press",
+ };
+ if (mp_client_send_event(mpctx, cmd->args[0].v.s,
+ MPV_EVENT_SCRIPT_INPUT_DISPATCH, event) < 0)
+ {
+ MP_VERBOSE(mpctx, "Can't find script '%s' when handling input.\n",
+ cmd->args[0].v.s);
}
break;
+ }
#if HAVE_SYS_MMAN_H
case MP_CMD_OVERLAY_ADD:
@@ -3182,45 +3186,8 @@ void command_init(struct MPContext *mpctx)
void mp_notify(struct MPContext *mpctx, int event, void *arg)
{
struct command_ctx *ctx = mpctx->command_ctx;
- ctx->events |= 1u << event;
if (event == MPV_EVENT_START_FILE)
ctx->last_seek_pts = MP_NOPTS_VALUE;
mp_client_broadcast_event(mpctx, event, arg);
}
-
-static void handle_script_event(struct MPContext *mpctx, const char *name,
- const char *arg)
-{
-#if HAVE_LUA
- mp_lua_event(mpctx, name, arg);
-#endif
-}
-
-void mp_flush_events(struct MPContext *mpctx)
-{
- struct command_ctx *ctx = mpctx->command_ctx;
-
- ctx->events |= (1u << MPV_EVENT_TICK);
-
- for (int n = 0; n < 16; n++) {
- int event = n;
- unsigned mask = 1 << event;
- if (ctx->events & mask) {
- // The event handler could set event flags again; in this case let
- // the next mp_flush_events() call handle it to avoid infinite loops.
- ctx->events &= ~mask;
- const char *name = NULL;
- switch (event) {
- case MPV_EVENT_TICK: name = "tick"; break;
- case MPV_EVENT_TRACKS_CHANGED: name = "track-layout"; break;
- case MPV_EVENT_PLAYBACK_START: name = "playback-start"; break;
- case MPV_EVENT_START_FILE: name = "start"; break;
- case MPV_EVENT_END_FILE: name = "end"; break;
- default: ;
- }
- if (name)
- handle_script_event(mpctx, name, "");
- }
- }
-}
diff --git a/player/command.h b/player/command.h
index 8047fd747a..61fe1ffad0 100644
--- a/player/command.h
+++ b/player/command.h
@@ -35,6 +35,5 @@ int mp_property_do(const char* name, int action, void* val,
const struct m_option *mp_get_property_list(void);
void mp_notify(struct MPContext *mpctx, int event, void *arg);
-void mp_flush_events(struct MPContext *mpctx);
#endif /* MPLAYER_COMMAND_H */
diff --git a/player/core.h b/player/core.h
index d39ac64dab..10c2f1886d 100644
--- a/player/core.h
+++ b/player/core.h
@@ -339,7 +339,6 @@ typedef struct MPContext {
struct screenshot_ctx *screenshot_ctx;
struct command_ctx *command_ctx;
struct encode_lavc_context *encode_lavc_ctx;
- struct lua_ctx *lua_ctx;
struct mp_nav_state *nav_state;
} MPContext;
diff --git a/player/loadfile.c b/player/loadfile.c
index b289ef4922..94a0274297 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -1052,7 +1052,6 @@ static void play_current_file(struct MPContext *mpctx)
mpctx->initialized_flags |= INITIALIZED_PLAYBACK;
mp_notify(mpctx, MPV_EVENT_START_FILE, NULL);
- mp_flush_events(mpctx);
mpctx->stop_play = 0;
mpctx->filename = NULL;
@@ -1411,7 +1410,6 @@ terminate_playback: // don't jump here after ao/vo/getch initialization!
mp_notify(mpctx, MPV_EVENT_TRACKS_CHANGED, NULL);
mp_notify(mpctx, MPV_EVENT_END_FILE, NULL);
- mp_flush_events(mpctx);
}
// Determine the next file to play. Note that if this function returns non-NULL,
diff --git a/player/lua.c b/player/lua.c
index 79bf61b713..68b8c40ab0 100644
--- a/player/lua.c
+++ b/player/lua.c
@@ -16,9 +16,12 @@
#include "options/path.h"
#include "bstr/bstr.h"
#include "osdep/timer.h"
+#include "osdep/threads.h"
#include "sub/osd.h"
#include "core.h"
#include "command.h"
+#include "client.h"
+#include "libmpv/client.h"
#include "lua.h"
// List of builtin modules and their contents as strings.
@@ -40,25 +43,12 @@ static const char *builtin_lua_scripts[][2] = {
struct script_ctx {
const char *name;
lua_State *state;
- struct mp_log_buffer *messages;
struct mp_log *log;
+ struct mpv_handle *client;
struct MPContext *mpctx;
+ int suspended;
};
-struct lua_ctx {
- struct script_ctx **scripts;
- int num_scripts;
-};
-
-static struct script_ctx *find_script(struct lua_ctx *lctx, const char *name)
-{
- for (int n = 0; n < lctx->num_scripts; n++) {
- if (strcmp(lctx->scripts[n]->name, name) == 0)
- return lctx->scripts[n];
- }
- return NULL;
-}
-
static struct script_ctx *get_ctx(lua_State *L)
{
lua_getfield(L, LUA_REGISTRYINDEX, "ctx");
@@ -103,10 +93,29 @@ static void report_error(lua_State *L)
lua_pop(L, 1);
}
+// Check client API error code:
+// if err >= 0, return 0.
+// if err < 0, raise the error as Lua error.
+static int check_error(lua_State *L, int err)
+{
+ if (err >= 0)
+ return 0;
+ luaL_error(L, "mpv API error: %s", mpv_error_string(err));
+ abort();
+}
+
+static int run_event_loop(lua_State *L)
+{
+ lua_getglobal(L, "mp_event_loop");
+ if (lua_isnil(L, -1))
+ luaL_error(L, "no event loop function\n");
+ lua_call(L, 0, 0);
+ return 0;
+}
+
static void add_functions(struct script_ctx *ctx);
-static char *script_name_from_filename(void *talloc_ctx, struct lua_ctx *lctx,
- const char *fname)
+static char *script_name_from_filename(void *talloc_ctx, const char *fname)
{
fname = mp_basename(fname);
if (fname[0] == '@')
@@ -124,10 +133,7 @@ static char *script_name_from_filename(void *talloc_ctx, struct lua_ctx *lctx,
!(c >= '0' && c <= '9'))
name[n] = '_';
}
- // Make unique (stupid but simple)
- while (find_script(lctx, name))
- name = talloc_strdup_append(name, "_");
- return name;
+ return talloc_asprintf(talloc_ctx, "lua/%s", name);
}
static int load_file(struct script_ctx *ctx, const char *fname)
@@ -171,16 +177,28 @@ static bool require(lua_State *L, const char *name)
return true;
}
-static void mp_lua_load_script(struct MPContext *mpctx, const char *fname)
+struct thread_arg {
+ struct MPContext *mpctx;
+ mpv_handle *client;
+ const char *fname;
+};
+
+static void *lua_thread(void *p)
{
- struct lua_ctx *lctx = mpctx->lua_ctx;
+ pthread_detach(pthread_self());
+
+ struct thread_arg *arg = p;
+ struct MPContext *mpctx = arg->mpctx;
+ const char *fname = arg->fname;
+ mpv_handle *client = arg->client;
+
struct script_ctx *ctx = talloc_ptrtype(NULL, ctx);
*ctx = (struct script_ctx) {
.mpctx = mpctx,
- .name = script_name_from_filename(ctx, lctx, fname),
+ .client = client,
+ .name = mpv_client_name(client),
+ .log = mp_client_get_log(client),
};
- char *log_name = talloc_asprintf(ctx, "lua/%s", ctx->name);
- ctx->log = mp_log_new(ctx, mpctx->log, log_name);
lua_State *L = ctx->state = luaL_newstate();
if (!L)
@@ -234,30 +252,43 @@ static void mp_lua_load_script(struct MPContext *mpctx, const char *fname)
goto error_out;
}
- MP_TARRAY_APPEND(lctx, lctx->scripts, lctx->num_scripts, ctx);
- return;
+ // Call the script's event loop runs until the script terminates and unloads.
+ if (mp_cpcall(L, run_event_loop, 0) != 0)
+ report_error(L);
error_out:
+ if (ctx->suspended)
+ mpv_resume(ctx->client);
if (ctx->state)
lua_close(ctx->state);
+ mpv_destroy(ctx->client);
talloc_free(ctx);
+ talloc_free(arg);
+ return NULL;
}
-static void kill_script(struct script_ctx *ctx)
+static void mp_lua_load_script(struct MPContext *mpctx, const char *fname)
{
- if (!ctx)
+ struct thread_arg *arg = talloc_ptrtype(NULL, arg);
+ char *name = script_name_from_filename(arg, fname);
+ *arg = (struct thread_arg){
+ .mpctx = mpctx,
+ .fname = talloc_strdup(arg, fname),
+ // Create the client before creating the thread; otherwise a race
+ // condition could happen, where MPContext is destroyed while the
+ // thread tries to create the client.
+ .client = mp_new_client(mpctx->clients, name),
+ };
+ if (!arg->client) {
+ talloc_free(arg);
return;
- struct lua_ctx *lctx = ctx->mpctx->lua_ctx;
- if (ctx->messages)
- mp_msg_log_buffer_destroy(ctx->messages);
- lua_close(ctx->state);
- for (int n = 0; n < lctx->num_scripts; n++) {
- if (lctx->scripts[n] == ctx) {
- MP_TARRAY_REMOVE_AT(lctx->scripts, lctx->num_scripts, n);
- break;
- }
}
- talloc_free(ctx);
+
+ pthread_t thread;
+ if (pthread_create(&thread, NULL, lua_thread, arg))
+ talloc_free(arg);
+
+ return;
}
static int check_loglevel(lua_State *L, int arg)
@@ -308,139 +339,130 @@ static int script_find_config_file(lua_State *L)
return 1;
}
-static int run_event(lua_State *L)
+static int script_suspend(lua_State *L)
{
- lua_getglobal(L, "mp_event"); // name arg mp_event
- if (lua_isnil(L, -1))
- return 0;
- lua_insert(L, -3); // mp_event name arg
- lua_call(L, 2, 0);
+ struct script_ctx *ctx = get_ctx(L);
+ if (!ctx->suspended)
+ mpv_suspend(ctx->client);
+ ctx->suspended++;
return 0;
}
-static void poll_messages(struct script_ctx *ctx)
+static int script_resume(lua_State *L)
{
- lua_State *L = ctx->state;
+ struct script_ctx *ctx = get_ctx(L);
+ static const char *modes[] = {"normal", "all", NULL};
+ if (luaL_checkoption(L, 1, "normal", modes) == 1) {
+ if (ctx->suspended)
+ mpv_resume(ctx->client);
+ ctx->suspended = 0;
+ } else {
+ if (ctx->suspended < 1)
+ luaL_error(L, "trying to resume, but core is not suspended");
+ ctx->suspended--;
+ if (!ctx->suspended)
+ mpv_resume(ctx->client);
+ }
+ return 0;
+}
- if (!ctx->messages)
- return;
+static int script_wait_event(lua_State *L)
+{
+ struct script_ctx *ctx = get_ctx(L);
- while (1) {
- struct mp_log_buffer_entry *msg = mp_msg_log_buffer_read(ctx->messages);
- if (!msg)
- break;
+ double timeout = luaL_optnumber(L, 1, 1e20);
+
+ // This will almost surely lead to a deadlock. (Polling is still ok.)
+ if (ctx->suspended && timeout > 0)
+ luaL_error(L, "attempting to wait while core is suspended");
+
+ mpv_event *event = mpv_wait_event(ctx->client, timeout);
- lua_pushstring(L, "message"); // msg
- lua_newtable(L); // msg t
- lua_pushstring(L, msg->prefix); // msg t s
- lua_setfield(L, -2, "prefix"); // msg t
- lua_pushstring(L, mp_log_levels[msg->level]); // msg t s
- lua_setfield(L, -2, "level"); // msg t
- lua_pushstring(L, msg->text); // msg t s
- lua_setfield(L, -2, "text"); // msg t
+ lua_newtable(L); // event
+ lua_pushstring(L, mpv_event_name(event->event_id)); // event name
+ lua_setfield(L, -2, "event"); // event
- if (mp_cpcall(L, run_event, 2) != 0)
- report_error(L);
+ if (event->error < 0) {
+ lua_pushstring(L, mpv_error_string(event->error)); // event err
+ lua_setfield(L, -2, "error"); // event
+ }
- talloc_free(msg);
+ switch (event->event_id) {
+ case MPV_EVENT_LOG_MESSAGE: {
+ mpv_event_log_message *msg = event->data;
+
+ lua_pushstring(L, msg->prefix); // event s
+ lua_setfield(L, -2, "prefix"); // event
+ lua_pushstring(L, msg->level); // event s
+ lua_setfield(L, -2, "level"); // event
+ lua_pushstring(L, msg->text); // event s
+ lua_setfield(L, -2, "text"); // event
+ break;
+ }
+ case MPV_EVENT_SCRIPT_INPUT_DISPATCH: {
+ mpv_event_script_input_dispatch *msg = event->data;
+
+ lua_pushinteger(L, msg->arg0); // event i
+ lua_setfield(L, -2, "arg0"); // event
+ lua_pushstring(L, msg->type); // event s
+ lua_setfield(L, -2, "type"); // event
+ break;
+ }
+ default: ;
}
+
+ return 1;
}
-void mp_lua_event(struct MPContext *mpctx, const char *name, const char *arg)
+static int script_request_event(lua_State *L)
{
- // There is no proper subscription mechanism yet, so all scripts get it.
- struct lua_ctx *lctx = mpctx->lua_ctx;
- for (int n = 0; n < lctx->num_scripts; n++) {
- struct script_ctx *ctx = lctx->scripts[n];
- lua_State *L = ctx->state;
- lua_pushstring(L, name);
- if (arg) {
- lua_pushstring(L, arg);
- } else {
- lua_pushnil(L);
+ struct script_ctx *ctx = get_ctx(L);
+ const char *event = luaL_checkstring(L, 1);
+ bool enable = lua_toboolean(L, 2);
+ // brute force event name -> id; stops working for events > assumed max
+ int event_id = -1;
+ for (int n = 0; n < 256; n++) {
+ const char *name = mpv_event_name(n);
+ if (name && strcmp(name, event) == 0) {
+ event_id = n;
+ break;
}
- if (mp_cpcall(L, run_event, 2) != 0)
- report_error(L);
- poll_messages(ctx);
}
+ lua_pushboolean(L, mpv_request_event(ctx->client, event_id, enable) >= 0);
+ return 1;
}
static int script_enable_messages(lua_State *L)
{
struct script_ctx *ctx = get_ctx(L);
- if (ctx->messages)
- luaL_error(L, "messages already enabled");
-
- int size = luaL_checkinteger(L, 1);
- int level = check_loglevel(L, 2);
- if (size < 2 || size > 100000)
- luaL_error(L, "size argument out of range");
- ctx->messages = mp_msg_log_buffer_new(ctx->mpctx->global, size, level);
- return 0;
-}
-
-static int run_script_dispatch(lua_State *L)
-{
- int id = lua_tointeger(L, 1);
- const char *event = lua_tostring(L, 2);
- lua_getglobal(L, "mp_script_dispatch");
- if (lua_isnil(L, -1))
- return 0;
- lua_pushinteger(L, id);
- lua_pushstring(L, event);
- lua_call(L, 2, 0);
- return 0;
-}
-
-void mp_lua_script_dispatch(struct MPContext *mpctx, char *script_name,
- int id, char *event)
-{
- struct script_ctx *ctx = find_script(mpctx->lua_ctx, script_name);
- if (!ctx) {
- MP_VERBOSE(mpctx, "Can't find script '%s' when handling input.\n",
- script_name);
- return;
- }
- lua_State *L = ctx->state;
- lua_pushinteger(L, id);
- lua_pushstring(L, event);
- if (mp_cpcall(L, run_script_dispatch, 2) != 0)
- report_error(L);
+ check_loglevel(L, 1);
+ const char *level = luaL_checkstring(L, 1);
+ return check_error(L, mpv_request_log_messages(ctx->client, level));
}
static int script_send_command(lua_State *L)
{
- struct MPContext *mpctx = get_mpctx(L);
+ struct script_ctx *ctx = get_ctx(L);
const char *s = luaL_checkstring(L, 1);
- mp_cmd_t *cmd = mp_input_parse_cmd(mpctx->input, bstr0((char*)s), "<lua>");
- if (!cmd)
- luaL_error(L, "error parsing command");
- mp_input_queue_cmd(mpctx->input, cmd);
-
- return 0;
+ return check_error(L, mpv_command_string(ctx->client, s));
}
static int script_send_commandv(lua_State *L)
{
struct script_ctx *ctx = get_ctx(L);
int num = lua_gettop(L);
- bstr args[50];
- if (num > MP_ARRAY_SIZE(args))
+ const char *args[50];
+ if (num + 1 > MP_ARRAY_SIZE(args))
luaL_error(L, "too many arguments");
for (int n = 1; n <= num; n++) {
- size_t len;
- const char *s = lua_tolstring(L, n, &len);
+ const char *s = lua_tostring(L, n);
if (!s)
luaL_error(L, "argument %d is not a string", n);
- args[n - 1] = (bstr){(char *)s, len};
+ args[n - 1] = s;
}
- mp_cmd_t *cmd = mp_input_parse_cmd_bstrv(ctx->log, 0, num, args, "<lua>");
- if (!cmd)
- luaL_error(L, "error parsing command");
- mp_input_queue_cmd(ctx->mpctx->input, cmd);
-
- return 0;
+ args[num] = NULL;
+ return check_error(L, mpv_command(ctx->client, args));
}
static int script_property_list(lua_State *L)
@@ -457,18 +479,24 @@ static int script_property_list(lua_State *L)
static int script_property_string(lua_State *L)
{
- struct MPContext *mpctx = get_mpctx(L);
+ struct script_ctx *ctx = get_ctx(L);
const char *name = luaL_checkstring(L, 1);
int type = lua_tointeger(L, lua_upvalueindex(1))
- ? M_PROPERTY_PRINT : M_PROPERTY_GET_STRING;
+ ? MPV_FORMAT_OSD_STRING : MPV_FORMAT_STRING;
char *result = NULL;
- if (mp_property_do(name, type, &result, mpctx) >= 0 && result) {
+ int err = mpv_get_property(ctx->client, name, type, &result);
+ if (err >= 0) {
lua_pushstring(L, result);
talloc_free(result);
return 1;
}
- if (type == M_PROPERTY_PRINT) {
+ // out of convenience, property access errors are not hard errors
+ if (err != MPV_ERROR_PROPERTY_NOT_FOUND &&
+ err != MPV_ERROR_PROPERTY_ERROR &&
+ err != MPV_ERROR_PROPERTY_UNAVAILABLE)
+ check_error(L, err);
+ if (type == MPV_FORMAT_OSD_STRING) {
lua_pushstring(L, "");
return 1;
}
@@ -528,6 +556,7 @@ static int script_get_timer(lua_State *L)
static int script_get_chapter_list(lua_State *L)
{
struct MPContext *mpctx = get_mpctx(L);
+ mp_dispatch_lock(mpctx->dispatch);
lua_newtable(L); // list
int num = get_chapter_count(mpctx);
for (int n = 0; n < num; n++) {
@@ -543,6 +572,7 @@ static int script_get_chapter_list(lua_State *L)
lua_settable(L, -3); // list
talloc_free(name);
}
+ mp_dispatch_unlock(mpctx->dispatch);
return 1;
}
@@ -559,6 +589,7 @@ static const char *stream_type(enum stream_type t)
static int script_get_track_list(lua_State *L)
{
struct MPContext *mpctx = get_mpctx(L);
+ mp_dispatch_lock(mpctx->dispatch);
lua_newtable(L); // list
for (int n = 0; n < mpctx->num_tracks; n++) {
struct track *track = mpctx->tracks[n];
@@ -593,6 +624,7 @@ static int script_get_track_list(lua_State *L)
lua_insert(L, -2); // list n1 track
lua_settable(L, -3); // list
}
+ mp_dispatch_unlock(mpctx->dispatch);
return 1;
}
@@ -668,16 +700,24 @@ static int script_format_time(lua_State *L)
static int script_getopt(lua_State *L)
{
struct MPContext *mpctx = get_mpctx(L);
+
+ mp_dispatch_lock(mpctx->dispatch);
+
char **opts = mpctx->opts->lua_opts;
const char *name = luaL_checkstring(L, 1);
+ int r = 0;
for (int n = 0; opts && opts[n] && opts[n + 1]; n++) {
if (strcmp(opts[n], name) == 0) {
lua_pushstring(L, opts[n + 1]);
- return 1;
+ r = 1;
+ break;
}
}
- return 0;
+
+ mp_dispatch_unlock(mpctx->dispatch);
+
+ return r;
}
struct fn_entry {
@@ -689,6 +729,10 @@ struct fn_entry {
static struct fn_entry fn_list[] = {
FN_ENTRY(log),
+ FN_ENTRY(suspend),
+ FN_ENTRY(resume),
+ FN_ENTRY(wait_event),
+ FN_ENTRY(request_event),
FN_ENTRY(find_config_file),
FN_ENTRY(send_command),
FN_ENTRY(send_commandv),
@@ -730,7 +774,6 @@ static void add_functions(struct script_ctx *ctx)
void mp_lua_init(struct MPContext *mpctx)
{
- mpctx->lua_ctx = talloc_zero(NULL, struct lua_ctx);
// Load scripts from options
if (mpctx->opts->lua_load_osc)
mp_lua_load_script(mpctx, "@osc");
@@ -740,13 +783,3 @@ void mp_lua_init(struct MPContext *mpctx)
mp_lua_load_script(mpctx, files[n]);
}
}
-
-void mp_lua_uninit(struct MPContext *mpctx)
-{
- if (mpctx->lua_ctx) {
- while (mpctx->lua_ctx->num_scripts)
- kill_script(mpctx->lua_ctx->scripts[0]);
- talloc_free(mpctx->lua_ctx);
- mpctx->lua_ctx = NULL;
- }
-}
diff --git a/player/lua.h b/player/lua.h
index 050548e2d2..cb4a7f95ec 100644
--- a/player/lua.h
+++ b/player/lua.h
@@ -6,9 +6,5 @@
struct MPContext;
void mp_lua_init(struct MPContext *mpctx);
-void mp_lua_uninit(struct MPContext *mpctx);
-void mp_lua_event(struct MPContext *mpctx, const char *name, const char *arg);
-void mp_lua_script_dispatch(struct MPContext *mpctx, char *script_name,
- int id, char *event);
#endif
diff --git a/player/lua/defaults.lua b/player/lua/defaults.lua
index 4b5e5e6126..7dca478252 100644
--- a/player/lua/defaults.lua
+++ b/player/lua/defaults.lua
@@ -52,18 +52,31 @@ function mp.set_mouse_area(x0, y0, x1, y1, section)
mp.input_set_section_mouse_area(section or default_section, x0, y0, x1, y1)
end
--- called by C on script_dispatch input command
-function mp_script_dispatch(id, event)
- local cb = callbacks[id]
+local function script_dispatch(event)
+ local cb = callbacks[event.arg0]
if cb then
- if event == "press" and cb.press then
+ if event.type == "press" and cb.press then
cb.press()
- elseif event == "keyup_follows" and cb.before_press then
+ elseif event.type == "keyup_follows" and cb.before_press then
cb.before_press()
end
end
end
+-- used by default event loop (mp_event_loop()) to decide when to quit
+mp.keep_running = true
+
+local event_handlers = {}
+
+function mp.register_event(name, cb)
+ event_handlers[name] = cb
+ mp.request_event(name, true)
+end
+
+-- default handlers
+mp.register_event("shutdown", function() mp.keep_running = false end)
+mp.register_event("script-input-dispatch", script_dispatch)
+
mp.msg = {
log = mp.log,
fatal = function(...) return mp.log("fatal", ...) end,
@@ -79,4 +92,28 @@ _G.print = mp.msg.info
package.loaded["mp"] = mp
package.loaded["mp.msg"] = mp.msg
+_G.mp_event_loop = function()
+ wait = 0
+ while mp.keep_running do
+ -- Drop all locks - important especially if an error happened while
+ -- locked, and the error was handled, but the lock not dropped.
+ if wait > 0 then
+ mp.resume("all")
+ end
+ local e = mp.wait_event(wait)
+ if e.event == "none" then
+ wait = 1e20
+ else
+ -- Empty the event queue while suspended; otherwise, each
+ -- event will keep us waiting until the core suspends again.
+ mp.suspend()
+ wait = 0
+ local handler = event_handlers[e.event]
+ if handler then
+ handler(e)
+ end
+ end
+ end
+end
+
return {}
diff --git a/player/lua/osc.lua b/player/lua/osc.lua
index cf6ce3449e..d19bfd7d78 100644
--- a/player/lua/osc.lua
+++ b/player/lua/osc.lua
@@ -1257,14 +1257,9 @@ function tick()
end
end
-function mp_event(name, arg)
- if name == "tick" then
- tick()
- elseif name == "start" or name == "track-layout" then
- request_init()
- elseif name == "end" then
- end
-end
+mp.register_event("tick", tick)
+mp.register_event("start-file", request_init)
+mp.register_event("tracks-changed", request_init)
-- mouse show/hide bindings
mp.set_key_bindings({
diff --git a/player/main.c b/player/main.c
index c455a0641c..4493d8aeb5 100644
--- a/player/main.c
+++ b/player/main.c
@@ -139,9 +139,6 @@ void mp_destroy(struct MPContext *mpctx)
mpctx->encode_lavc_ctx = NULL;
-#if HAVE_LUA
- mp_lua_uninit(mpctx);
-#endif
shutdown_clients(mpctx);
command_uninit(mpctx);
diff --git a/player/playloop.c b/player/playloop.c
index d97fedccbc..57d5281240 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -747,8 +747,6 @@ static void handle_cursor_autohide(struct MPContext *mpctx)
static void handle_input_and_seek_coalesce(struct MPContext *mpctx)
{
- mp_flush_events(mpctx);
-
mp_cmd_t *cmd;
while ((cmd = mp_input_get_cmd(mpctx->input, 0, 1)) != NULL) {
mp_dispatch_queue_process(mpctx->dispatch, 0);
@@ -1340,7 +1338,6 @@ void idle_loop(struct MPContext *mpctx)
if (cmd)
run_command(mpctx, cmd);
mp_cmd_free(cmd);
- mp_flush_events(mpctx);
mp_dispatch_queue_process(mpctx->dispatch, 0);
if (mpctx->opts->use_terminal)
getch2_poll();