mirror of
https://github.com/mpv-player/mpv.git
synced 2026-05-07 20:02:49 +00:00
input/dnd: move built-in drag and drop handling to mpv client
This moves the drag and drop handling to an internal mpv client, removing the hardcoded handling from core.
This commit is contained in:
+1
-2
@@ -3232,8 +3232,7 @@ Property list
|
||||
(key and string value for each pad-btn entry)
|
||||
|
||||
``dropped-files``
|
||||
Information of the most recent drag-and-drop event mpv received. This
|
||||
property is only updated when ``--input-builtin-drag-and-drop=no``.
|
||||
Information of the most recent drag-and-drop event mpv received.
|
||||
A client can observe this property to detect when a drag-and-drop event
|
||||
happens. This property is unavailable if no drag-and-drop event has
|
||||
happened.
|
||||
|
||||
@@ -4454,8 +4454,7 @@ Input
|
||||
|
||||
``--input-builtin-drag-and-drop=<yes|no>``
|
||||
Enable the built-in drag-and-drop behavior (default: yes). Setting it to no
|
||||
disables the built-in drag-and-drop handling and enables the ``dropped-files``
|
||||
property, which can be used to retrieve information about dropped files.
|
||||
disables the built-in drag-and-drop handling.
|
||||
|
||||
``--input-cmdlist``
|
||||
Prints all commands that can be bound to keys.
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnd.h"
|
||||
#include "common/msg.h"
|
||||
#include "misc/bstr.h"
|
||||
#include "misc/node.h"
|
||||
#include "misc/path_utils.h"
|
||||
#include "osdep/threads.h"
|
||||
#include "player/client.h"
|
||||
|
||||
static bool might_be_subtitle_file(mpv_node *sub_exts, char *file)
|
||||
{
|
||||
for (int i = 0; i < sub_exts->u.list->num; i++) {
|
||||
mpv_node sub_ext = sub_exts->u.list->values[i];
|
||||
if (sub_ext.format != MPV_FORMAT_STRING)
|
||||
continue;
|
||||
if (!bstrcasecmp0(bstr_get_ext(bstr0(file)), sub_ext.u.string))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void handle_dnd(mpv_handle *mpv, mpv_node *files, char *action)
|
||||
{
|
||||
mpv_node sub_exts = {0};
|
||||
if (mpv_get_property(mpv, "sub-auto-exts", MPV_FORMAT_NODE, &sub_exts) != MPV_ERROR_SUCCESS ||
|
||||
sub_exts.format != MPV_FORMAT_NODE_ARRAY)
|
||||
goto end;
|
||||
|
||||
struct mpv_node_list *list = files->u.list;
|
||||
for (int i = 0; i < list->num; i++) {
|
||||
mpv_node file = list->values[i];
|
||||
if (file.format != MPV_FORMAT_STRING)
|
||||
goto end;
|
||||
}
|
||||
|
||||
bool all_sub = true;
|
||||
for (int i = 0; i < list->num; i++)
|
||||
all_sub &= might_be_subtitle_file(&sub_exts, list->values[i].u.string);
|
||||
|
||||
if (all_sub) {
|
||||
for (int i = 0; i < list->num; i++) {
|
||||
const char *cmd[] = {
|
||||
"osd-auto",
|
||||
"sub-add",
|
||||
list->values[i].u.string,
|
||||
NULL
|
||||
};
|
||||
mpv_command(mpv, cmd);
|
||||
}
|
||||
} else if (!strcmp(action, "insert-next")) {
|
||||
/* To insert the entries in the correct order, we iterate over them
|
||||
backwards */
|
||||
for (int i = list->num - 1; i >= 0; i--) {
|
||||
const char *cmd[] = {
|
||||
"osd-auto",
|
||||
"loadfile",
|
||||
list->values[i].u.string,
|
||||
/* Since we're inserting in reverse, wait til the final item
|
||||
is added to start playing */
|
||||
(i > 0) ? "insert-next" : "insert-next-play",
|
||||
NULL
|
||||
};
|
||||
mpv_command(mpv, cmd);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < list->num; i++) {
|
||||
const char *cmd[] = {
|
||||
"osd-auto",
|
||||
"loadfile",
|
||||
list->values[i].u.string,
|
||||
/* Either start playing the dropped files right away
|
||||
or add them to the end of the current playlist */
|
||||
(i == 0 && !strcmp(action, "replace")) ? "replace" : "append-play",
|
||||
NULL
|
||||
};
|
||||
mpv_command(mpv, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
mpv_free_node_contents(&sub_exts);
|
||||
}
|
||||
|
||||
static MP_THREAD_VOID mpv_event_loop_fn(void *arg)
|
||||
{
|
||||
mp_thread_set_name("dnd");
|
||||
mpv_handle *mpv = arg;
|
||||
bool enabled = false;
|
||||
mpv_observe_property(mpv, 0, "dropped-files", MPV_FORMAT_NODE);
|
||||
mpv_observe_property(mpv, 0, "input-builtin-drag-and-drop", MPV_FORMAT_FLAG);
|
||||
|
||||
while (1) {
|
||||
mpv_event *event = mpv_wait_event(mpv, -1);
|
||||
if (event->event_id == MPV_EVENT_SHUTDOWN)
|
||||
break;
|
||||
if (event->event_id == MPV_EVENT_PROPERTY_CHANGE) {
|
||||
mpv_event_property *prop = event->data;
|
||||
if (enabled && !strcmp(prop->name, "dropped-files") && prop->format == MPV_FORMAT_NODE) {
|
||||
mpv_node *node = prop->data;
|
||||
mpv_node *action = node_map_get(node, "action");
|
||||
if (!action || action->format != MPV_FORMAT_STRING)
|
||||
continue;
|
||||
|
||||
mpv_node *files = node_map_get(node, "files");
|
||||
if (!files || files->format != MPV_FORMAT_NODE_ARRAY)
|
||||
continue;
|
||||
handle_dnd(mpv, files, action->u.string);
|
||||
}
|
||||
if (!strcmp(prop->name, "input-builtin-drag-and-drop") && prop->format == MPV_FORMAT_FLAG)
|
||||
enabled = *(int *)prop->data;
|
||||
}
|
||||
}
|
||||
|
||||
mpv_destroy(mpv);
|
||||
MP_THREAD_RETURN();
|
||||
}
|
||||
|
||||
void mp_dnd_init(mpv_handle *mpv)
|
||||
{
|
||||
mp_thread mpv_event_loop;
|
||||
if (!mp_thread_create(&mpv_event_loop, mpv_event_loop_fn, mpv))
|
||||
mp_thread_detach(mpv_event_loop);
|
||||
else
|
||||
mpv_destroy(mpv);
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "player/client.h"
|
||||
|
||||
void mp_dnd_init(mpv_handle *mpv);
|
||||
+7
-58
@@ -210,7 +210,6 @@ struct input_opts {
|
||||
bool default_bindings;
|
||||
bool builtin_bindings;
|
||||
bool builtin_dragging;
|
||||
bool builtin_dnd;
|
||||
bool enable_mouse_movements;
|
||||
bool vo_key_input;
|
||||
bool test;
|
||||
@@ -230,7 +229,6 @@ const struct m_sub_options input_config = {
|
||||
{"input-default-bindings", OPT_BOOL(default_bindings)},
|
||||
{"input-builtin-bindings", OPT_BOOL(builtin_bindings)},
|
||||
{"input-builtin-dragging", OPT_BOOL(builtin_dragging)},
|
||||
{"input-builtin-drag-and-drop", OPT_BOOL(builtin_dnd)},
|
||||
{"input-test", OPT_BOOL(test)},
|
||||
{"input-doubleclick-time", OPT_INT(doubleclick_time),
|
||||
M_RANGE(0, 1000)},
|
||||
@@ -262,7 +260,6 @@ const struct m_sub_options input_config = {
|
||||
.default_bindings = true,
|
||||
.builtin_bindings = true,
|
||||
.builtin_dragging = true,
|
||||
.builtin_dnd = true,
|
||||
.vo_key_input = true,
|
||||
.allow_win_drag = true,
|
||||
.preprocess_wheel = true,
|
||||
@@ -1291,63 +1288,15 @@ void mp_input_drop_files(struct input_ctx *ictx, int num_files, char **files,
|
||||
enum mp_dnd_action action)
|
||||
{
|
||||
input_lock(ictx);
|
||||
if (!ictx->opts->builtin_dnd) {
|
||||
TA_FREEP(&ictx->dropped_files);
|
||||
ictx->dropped_files = talloc_zero_array(ictx, bstr, num_files);
|
||||
ictx->num_dropped_files = num_files;
|
||||
ictx->dnd_ts = mp_time_ns();
|
||||
ictx->dnd_action = action;
|
||||
for (int i = 0; i < num_files; i++)
|
||||
ictx->dropped_files[i] = bstrdup(ictx->dropped_files, bstr0(files[i]));
|
||||
|
||||
notify_event_update(ictx);
|
||||
input_unlock(ictx);
|
||||
return;
|
||||
}
|
||||
|
||||
bool all_sub = true;
|
||||
TA_FREEP(&ictx->dropped_files);
|
||||
ictx->dropped_files = talloc_zero_array(ictx, bstr, num_files);
|
||||
ictx->num_dropped_files = num_files;
|
||||
ictx->dnd_ts = mp_time_ns();
|
||||
ictx->dnd_action = action;
|
||||
for (int i = 0; i < num_files; i++)
|
||||
all_sub &= mp_might_be_subtitle_file(files[i]);
|
||||
ictx->dropped_files[i] = bstrdup(ictx->dropped_files, bstr0(files[i]));
|
||||
|
||||
if (all_sub) {
|
||||
for (int i = 0; i < num_files; i++) {
|
||||
const char *cmd[] = {
|
||||
"osd-auto",
|
||||
"sub-add",
|
||||
files[i],
|
||||
NULL
|
||||
};
|
||||
queue_cmd(ictx, mp_input_parse_cmd_strv(ictx->log, 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
|
||||
};
|
||||
queue_cmd(ictx, mp_input_parse_cmd_strv(ictx->log, cmd));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < num_files; i++) {
|
||||
const char *cmd[] = {
|
||||
"osd-auto",
|
||||
"loadfile",
|
||||
files[i],
|
||||
/* Either start playing the dropped files right away
|
||||
or add them to the end of the current playlist */
|
||||
(i == 0 && action == DND_REPLACE) ? "replace" : "append-play",
|
||||
NULL
|
||||
};
|
||||
queue_cmd(ictx, mp_input_parse_cmd_strv(ictx->log, cmd));
|
||||
}
|
||||
}
|
||||
notify_event_update(ictx);
|
||||
input_unlock(ictx);
|
||||
}
|
||||
|
||||
|
||||
@@ -129,6 +129,7 @@ sources = files(
|
||||
|
||||
## Input
|
||||
'input/cmd.c',
|
||||
'input/dnd.c',
|
||||
'input/event.c',
|
||||
'input/input.c',
|
||||
'input/ipc.c',
|
||||
|
||||
@@ -920,6 +920,7 @@ static const m_option_t mp_opts[] = {
|
||||
{"", OPT_SUBSTRUCT(resample_opts, resample_conf)},
|
||||
|
||||
{"", OPT_SUBSTRUCT(input_opts, input_config)},
|
||||
{"input-builtin-drag-and-drop", OPT_BOOL(builtin_dnd)},
|
||||
|
||||
{"clipboard", OPT_SUBSTRUCT(clipboard_opts, clipboard_conf)},
|
||||
|
||||
@@ -1076,6 +1077,7 @@ static const struct MPOpts mp_default_opts = {
|
||||
.screenshot_template = "mpv-shot%n",
|
||||
.play_dir = 1,
|
||||
.media_controls = true,
|
||||
.builtin_dnd = true,
|
||||
.video_exts = (char *[]){
|
||||
"3g2", "3gp", "avi", "flv", "ivf", "m2ts", "m4v", "mj2", "mkv", "mov",
|
||||
"mp4", "mpeg", "mpg", "mxf", "ogv", "rmvb", "ts", "webm", "wmv", "y4m",
|
||||
|
||||
@@ -390,6 +390,7 @@ typedef struct MPOpts {
|
||||
struct hwdec_opts *hwdec_opts;
|
||||
|
||||
struct input_opts *input_opts;
|
||||
bool builtin_dnd;
|
||||
|
||||
struct clipboard_opts *clipboard_opts;
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "common/playlist.h"
|
||||
#include "options/options.h"
|
||||
#include "options/path.h"
|
||||
#include "input/dnd.h"
|
||||
#include "input/input.h"
|
||||
#include "demux/packet_pool.h"
|
||||
|
||||
@@ -420,6 +421,8 @@ int mp_initialize(struct MPContext *mpctx, char **options)
|
||||
mp_smtc_init(mp_new_client(mpctx->clients, "SystemMediaTransportControls"));
|
||||
#endif
|
||||
|
||||
mp_dnd_init(mp_new_client(mpctx->clients, "dnd"));
|
||||
|
||||
mpctx->ipc_ctx = mp_init_ipc(mpctx->clients, mpctx->global);
|
||||
|
||||
if (opts->encode_opts->file && opts->encode_opts->file[0]) {
|
||||
|
||||
Reference in New Issue
Block a user