diff --git a/DOCS/interface-changes/dnd.txt b/DOCS/interface-changes/dnd.txt index b47c561e29..dcb8752632 100644 --- a/DOCS/interface-changes/dnd.txt +++ b/DOCS/interface-changes/dnd.txt @@ -1 +1,2 @@ add `--input-builtin-drag-and-drop` option +add `dropped-file` property diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 03d58443e3..97f9781d28 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -3231,6 +3231,39 @@ Property list "pad-btns" MPV_FORMAT_NODE_MAP (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``. + 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. + + Has the following sub-properties: + + ``dropped-files/time`` + The timestamp of the last drag-and-drop event mpv received, in + nanoseconds. This uses the same clock as ``mpv_get_time_ns()``. + + ``dropped-files/action`` + The action of the drag-and-drop event, can be one of ``replace``, + ``append``, or ``insert-next``. This is affected by the + ``--drag-and-drop`` option. + + ``dropped-files/files`` + The dropped file names of the drag-and-drop event. + + When querying the property with the client API using ``MPV_FORMAT_NODE``, + or with Lua ``mp.get_property_native``, this will return a mpv_node with + the following contents: + + :: + + MPV_FORMAT_NODE_MAP + "time" MPV_FORMAT_INT64 + "action" MPV_FORMAT_STRING + "files" MPV_FORMAT_NODE_ARRAY + MPV_FORMAT_STRING + ``sub-ass-extradata`` The current ASS subtitle track's extradata. There is no formatting done. The extradata is returned as a string as-is. This property is not diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index f530b1f402..e0fbb025c4 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -4454,7 +4454,8 @@ Input ``--input-builtin-drag-and-drop=`` Enable the built-in drag-and-drop behavior (default: yes). Setting it to no - disables the built-in drag-and-drop handling. + disables the built-in drag-and-drop handling and enables the ``dropped-files`` + property, which can be used to retrieve information about dropped files. ``--input-cmdlist`` Prints all commands that can be bound to keys. diff --git a/input/event.h b/input/event.h index 7a5c426ece..683c2d9ff7 100644 --- a/input/event.h +++ b/input/event.h @@ -25,6 +25,7 @@ enum mp_dnd_action { DND_REPLACE, DND_APPEND, DND_INSERT_NEXT, + DND_NONE, }; // Drop data in a specific format (identified by the mimetype). diff --git a/input/input.c b/input/input.c index 60d9545e8c..93f3a5dcb9 100644 --- a/input/input.c +++ b/input/input.c @@ -160,6 +160,12 @@ struct input_ctx { struct touch_point *touch_points; int num_touch_points; + // List of last dropped files + int64_t dnd_ts; + enum mp_dnd_action dnd_action; + bstr *dropped_files; + int num_dropped_files; + int tablet_x, tablet_y; // Indicates tablet tools in proximity / close to tablet surface bool tablet_tool_in_proximity; @@ -1286,6 +1292,15 @@ void mp_input_drop_files(struct input_ctx *ictx, int num_files, char **files, { 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; } @@ -1336,6 +1351,23 @@ void mp_input_drop_files(struct input_ctx *ictx, int num_files, char **files, input_unlock(ictx); } +void mp_input_get_dropped_files(struct input_ctx *ictx, void *talloc_ctx, + int64_t *dnd_ts, + enum mp_dnd_action *dnd_action, + char ***dropped_files) +{ + input_lock(ictx); + *dnd_ts = ictx->dnd_ts; + *dnd_action = ictx->dnd_action; + *dropped_files = NULL; + int num = 0; + for (int i = 0; i < ictx->num_dropped_files; i++) + MP_TARRAY_APPEND(talloc_ctx, *dropped_files, num, + bstrto0(talloc_ctx, ictx->dropped_files[i])); + MP_TARRAY_APPEND(talloc_ctx, *dropped_files, num, NULL); + input_unlock(ictx); +} + unsigned int mp_input_get_mouse_event_counter(struct input_ctx *ictx) { // Make the frontend always display the mouse cursor (as long as it's not @@ -1746,6 +1778,7 @@ struct input_ctx *mp_input_init(struct mpv_global *global, .wakeup_ctx = wakeup_ctx, .active_sections = talloc_array(ictx, struct active_section, 0), .touch_points = talloc_array(ictx, struct touch_point, 0), + .dnd_action = DND_NONE, }; ictx->opts = ictx->opts_cache->opts; diff --git a/input/input.h b/input/input.h index cb012854aa..6223c2d576 100644 --- a/input/input.h +++ b/input/input.h @@ -209,6 +209,11 @@ bool mp_input_test_dragging(struct input_ctx *ictx, int x, int y); // Enqueue files for playback after drag and drop void mp_input_drop_files(struct input_ctx *ictx, int num_files, char **files, enum mp_dnd_action action); +// Last dropped files +void mp_input_get_dropped_files(struct input_ctx *ictx, void *talloc_ctx, + int64_t *dnd_ts, + enum mp_dnd_action *dnd_action, + char ***dropped_files); // Initialize the input system struct mpv_global; diff --git a/player/command.c b/player/command.c index e972073fad..4e63962905 100644 --- a/player/command.c +++ b/player/command.c @@ -3267,6 +3267,44 @@ static int mp_property_tablet_pos(void *ctx, struct m_property *prop, return M_PROPERTY_NOT_IMPLEMENTED; } +static int mp_property_dropped_files(void *ctx, struct m_property *prop, + int action, void *arg) +{ + MPContext *mpctx = ctx; + + int valid = m_property_read_sub_validate(ctx, prop, action, arg); + if (valid != M_PROPERTY_VALID) + return valid; + + int64_t dnd_ts; + enum mp_dnd_action dnd_action; + char **dropped_files; + void *talloc_ctx = talloc_new(NULL); + mp_input_get_dropped_files(mpctx->input, talloc_ctx, &dnd_ts, + &dnd_action, &dropped_files); + int r = M_PROPERTY_UNAVAILABLE; + if (dnd_action == DND_NONE) + goto done; + + char *actionstr = dnd_action == DND_REPLACE ? "replace" : + dnd_action == DND_APPEND ? "append" : + dnd_action == DND_INSERT_NEXT ? "insert-next" : + "none"; + + struct m_sub_property props[] = { + {"time", SUB_PROP_INT64(dnd_ts)}, + {"action", SUB_PROP_STR(actionstr)}, + {"files", SUB_PROP_STRING_LIST(dropped_files)}, + {0} + }; + + r = m_property_read_sub(props, action, arg); + +done: + talloc_free(talloc_ctx); + return r; +} + /// Video fps (RO) static int mp_property_fps(void *ctx, struct m_property *prop, int action, void *arg) @@ -4666,6 +4704,7 @@ static const struct m_property mp_properties_base[] = { {"mouse-pos", mp_property_mouse_pos}, {"touch-pos", mp_property_touch_pos}, {"tablet-pos", mp_property_tablet_pos}, + {"dropped-files", mp_property_dropped_files}, // Subs {"sid", mp_property_switch_track, .priv = (void *)(const int[]){0, STREAM_SUB}}, @@ -4810,7 +4849,7 @@ static const char *const *const mp_event_property_change[] = { E(MP_EVENT_CHANGE_PLAYLIST, "playlist", "playlist-pos", "playlist-pos-1", "playlist-count", "playlist/count", "playlist-current-pos", "playlist-playing-pos"), - E(MP_EVENT_INPUT_PROCESSED, "mouse-pos", "touch-pos", "tablet-pos"), + E(MP_EVENT_INPUT_PROCESSED, "mouse-pos", "touch-pos", "tablet-pos", "dropped-files"), E(MP_EVENT_CORE_IDLE, "core-idle", "eof-reached"), }; #undef E