From a8a314b829498c55aed393d4bc7f4f7bf9e92362 Mon Sep 17 00:00:00 2001 From: David Vaughan Date: Sat, 3 Feb 2024 19:41:43 -0800 Subject: [PATCH] input: add insert-next support for drag-and-drop This commit adds a DND_INSERT_NEXT action option for drag-and-drop, allows for selecting it through the --drag-and-drop=insert-next option, and adds the necessary plumbing to make that happen when something is dragged onto the player. --- DOCS/man/options.rst | 15 ++++++++------- input/event.c | 15 +++++++++++++++ input/event.h | 5 +++-- options/options.c | 4 +++- video/out/wayland_common.c | 10 ++++++++-- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 39a075e74c..3dcdc4eba4 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -3197,13 +3197,14 @@ Window ``--snap-window`` (Windows only) Snap the player window to screen edges. -``--drag-and-drop=`` - Controls the default behavior of drag and drop on platforms that support this. - ``auto`` will obey what the underlying os/platform gives mpv. Typically, holding - shift during the drag and drop will append the item to the playlist. Otherwise, - it will completely replace it. ``replace`` and ``append`` always force replacing - and appending to the playlist respectively. ``no`` disables all drag and drop - behavior. +``--drag-and-drop=`` + Controls the default behavior of drag and drop on platforms that support + this. ``auto`` will obey what the underlying os/platform gives mpv. + Typically, holding shift during the drag and drop will append the item to + the playlist. Otherwise, it will completely replace it. ``replace``, + ``append``, and ``insert-next`` always force replacing, appending to, and + inserting next into the playlist respectively. ``no`` disables all drag and + drop behavior. ``--ontop`` Makes the player window stay on top of other windows. diff --git a/input/event.c b/input/event.c index 266e0294e2..6c1e00409a 100644 --- a/input/event.c +++ b/input/event.c @@ -37,6 +37,21 @@ void mp_event_drop_files(struct input_ctx *ictx, int num_files, char **files, }; mp_input_run_cmd(ictx, cmd); } + } else if (action == DND_INSERT_NEXT) { + /* To insert the entries in the correct order, we iterate over them + backwards */ + for (int i = num_files - 1; i >= 0; i--) { + const char *cmd[] = { + "osd-auto", + "loadfile", + files[i], + /* Since we're inserting in reverse, wait til the final item + is added to start playing */ + (i > 0) ? "insert-next" : "insert-next-play", + NULL + }; + mp_input_run_cmd(ictx, cmd); + } } else { for (int i = 0; i < num_files; i++) { const char *cmd[] = { diff --git a/input/event.h b/input/event.h index 1e2149bb89..5f48bee00e 100644 --- a/input/event.h +++ b/input/event.h @@ -24,16 +24,17 @@ struct input_ctx; enum mp_dnd_action { DND_REPLACE, DND_APPEND, + DND_INSERT_NEXT, }; // Enqueue files for playback after drag and drop void mp_event_drop_files(struct input_ctx *ictx, int num_files, char **files, - enum mp_dnd_action append); + enum mp_dnd_action action); // Drop data in a specific format (identified by the mimetype). // Returns <0 on error, ==0 if data was ok but empty, >0 on success. int mp_event_drop_mime_data(struct input_ctx *ictx, const char *mime_type, - bstr data, enum mp_dnd_action append); + bstr data, enum mp_dnd_action action); // Many drag & drop APIs support multiple mime types, and this function returns // whether a type is preferred (higher integer score), or supported (scores diff --git a/options/options.c b/options/options.c index c380bce808..0370294dbd 100644 --- a/options/options.c +++ b/options/options.c @@ -112,7 +112,9 @@ static const m_option_t mp_vo_opt_list[] = { {"vo", OPT_SETTINGSLIST(video_driver_list, &vo_obj_list)}, {"taskbar-progress", OPT_BOOL(taskbar_progress)}, {"drag-and-drop", OPT_CHOICE(drag_and_drop, {"no", -2}, {"auto", -1}, - {"replace", DND_REPLACE}, {"append", DND_APPEND})}, + {"replace", DND_REPLACE}, + {"append", DND_APPEND}, + {"insert-next", DND_INSERT_NEXT})}, {"snap-window", OPT_BOOL(snap_window)}, {"ontop", OPT_BOOL(ontop)}, {"ontop-level", OPT_CHOICE(ontop_level, {"window", -1}, {"system", -2}, diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index 91148f3af1..a36076b708 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -695,8 +695,14 @@ static void data_offer_action(void *data, struct wl_data_offer *wl_data_offer, u wl->dnd_action = dnd_action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY ? DND_REPLACE : DND_APPEND; } - MP_VERBOSE(wl, "DND action is %s\n", - wl->dnd_action == DND_REPLACE ? "DND_REPLACE" : "DND_APPEND"); + + static const char * const dnd_action_names[] = { + [DND_REPLACE] = "DND_REPLACE", + [DND_APPEND] = "DND_APPEND", + [DND_INSERT_NEXT] = "DND_INSERT_NEXT", + }; + + MP_VERBOSE(wl, "DND action is %s\n", dnd_action_names[wl->dnd_action]); } }