mirror of
https://github.com/mpv-player/mpv.git
synced 2026-10-16 22:40:53 +08:00
caf9cb2df2
drag and drop is enabled by default in the options, but disabled in the dnd handling in code before the initial property change event was dispatched. leading to ignored dropped-files events when dispatched too early. Fixes #17921
155 lines
5.2 KiB
C
155 lines
5.2 KiB
C
/*
|
|
* 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(mp_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};
|
|
mpv_node drop_type = {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;
|
|
if (mpv_get_property(mpv, "drag-and-drop", MPV_FORMAT_NODE, &drop_type) != MPV_ERROR_SUCCESS ||
|
|
drop_type.format != MPV_FORMAT_STRING)
|
|
goto end;
|
|
if (!strcmp(drop_type.u.string, "no"))
|
|
goto end;
|
|
if (strcmp(drop_type.u.string, "auto"))
|
|
action = drop_type.u.string;
|
|
|
|
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);
|
|
mpv_free_node_contents(&drop_type);
|
|
}
|
|
|
|
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);
|
|
|
|
int enabled_flag;
|
|
if (mpv_get_property(mpv, "input-builtin-drag-and-drop", MPV_FORMAT_FLAG, &enabled_flag) == MPV_ERROR_SUCCESS)
|
|
enabled = enabled_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);
|
|
}
|