mirror of
https://github.com/mpv-player/mpv.git
synced 2026-10-16 22:40:53 +08:00
command: add update-clipboard command
This uses the update_data request for clipboard backends that require it. When clipboard monitoring is disabled, the backends will no longer fetch data when it detects data change, and will now only do that when receiving the update_data request. The client now needs to run this command to update the clipboard content, otherwise the property value is outdated. This makes sure that applications that depend on "paste once" behavior work correctly. This command runs in a separate worker thread so that it can be used as a "blocking" way to update clipboard until the update notification arrives without blocking the playback core. It accepts a maximum timeout parameter. This uses the existing mp_cancel mechanism to make sure this command can be aborted and the worker threads will not stall the player too much when quitting mpv. For backends that do not support update_data, this command does nothing.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
add `update-clipboard` command
|
||||
change `clipboard` property to require `update-clipboard` command when clipboard monitoring is disabled
|
||||
@@ -1758,6 +1758,22 @@ Miscellaneous Commands
|
||||
``context-menu``
|
||||
Show context menu on the video window. See `Context Menu`_ section for details.
|
||||
|
||||
``update-clipboard <type> [timeout]``
|
||||
Update the clipboard content so that the ``clipboard`` property reflects
|
||||
up-to-date value. This command is required to update the ``clipboard``
|
||||
property value if ``--clipboard-monitor=no``. ``<type>`` must be ``text``
|
||||
or ``text-primary`` to indicate whether to update clipboard or primary
|
||||
selection. ``[timeout]`` specifies the maximum timeout in ms to wait for
|
||||
the clipboard content to be updated. A negative timeout means infinite.
|
||||
The default timeout is 10 ms.
|
||||
|
||||
This command returns as soon as the clipboard content is updated or the
|
||||
timeout has reached. On some platforms, this command does nothing and
|
||||
returns immediately.
|
||||
|
||||
This command can be asynchronously aborted via API. See `Asynchronous
|
||||
command details`_.
|
||||
|
||||
Undocumented commands: ``ao-reload`` (experimental/internal).
|
||||
|
||||
List of events
|
||||
@@ -4285,6 +4301,13 @@ Property list
|
||||
does not have this limitation.
|
||||
See ``current-clipboard-backend`` property for more details.
|
||||
|
||||
.. warning::
|
||||
|
||||
Since mpv 0.42.0, this property does not return the current clipboard
|
||||
content on certain platforms if ``--clipboard-monitor=no``.
|
||||
When reading clipboard content, you must run ``update-clipboard``
|
||||
command to update the clipboard content manually in this case.
|
||||
|
||||
::
|
||||
|
||||
MPV_FORMAT_NODE_MAP
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/global.h"
|
||||
#include "misc/thread_tools.h"
|
||||
#include "options/m_config.h"
|
||||
#include "player/core.h"
|
||||
|
||||
@@ -107,7 +108,9 @@ static void mp_clipboard_create(struct clipboard_ctx *cl,
|
||||
continue;
|
||||
if (backend->init(cl, params) != CLIPBOARD_SUCCESS)
|
||||
break;
|
||||
mp_mutex_lock(&cl->lock);
|
||||
cl->backend = backend;
|
||||
mp_mutex_unlock(&cl->lock);
|
||||
MP_VERBOSE(cl, "Initialized %s clipboard backend.\n", cl->backend->name);
|
||||
return;
|
||||
}
|
||||
@@ -116,16 +119,26 @@ static void mp_clipboard_create(struct clipboard_ctx *cl,
|
||||
MP_WARN(cl, "Failed to initialize any clipboard backend.\n");
|
||||
}
|
||||
|
||||
void mp_clipboard_notify_update_data(struct clipboard_ctx *cl)
|
||||
{
|
||||
mp_mutex_lock(&cl->lock);
|
||||
for (int i = 0; i < cl->num_cancels; ++i)
|
||||
mp_cancel_trigger(cl->cancels[i]);
|
||||
mp_mutex_unlock(&cl->lock);
|
||||
}
|
||||
|
||||
void mp_clipboard_destroy(struct clipboard_ctx *cl)
|
||||
{
|
||||
mp_mutex_lock(&cl->lock);
|
||||
if (cl->backend && cl->backend->uninit)
|
||||
cl->backend->uninit(cl);
|
||||
*cl = (struct clipboard_ctx){.log = cl->log};
|
||||
cl->backend = cl->priv = NULL;
|
||||
mp_mutex_unlock(&cl->lock);
|
||||
}
|
||||
|
||||
bool mp_clipboard_data_changed(struct clipboard_ctx *cl)
|
||||
{
|
||||
if (cl && cl->backend->data_changed && cl->monitor)
|
||||
if (cl->backend && cl->backend->data_changed && cl->monitor)
|
||||
return cl->backend->data_changed(cl);
|
||||
return false;
|
||||
}
|
||||
@@ -146,6 +159,32 @@ int mp_clipboard_set_data(struct clipboard_ctx *cl, struct clipboard_access_para
|
||||
return CLIPBOARD_UNAVAILABLE;
|
||||
}
|
||||
|
||||
bool mp_clipboard_update_data(struct clipboard_ctx *cl, struct clipboard_access_params *params,
|
||||
struct mp_cancel *cancel, double timeout)
|
||||
{
|
||||
mp_mutex_lock(&cl->lock);
|
||||
if (cl->backend && cl->backend->update_data) {
|
||||
cl->backend->update_data(cl, params);
|
||||
} else {
|
||||
mp_mutex_unlock(&cl->lock);
|
||||
return true;
|
||||
}
|
||||
MP_TARRAY_APPEND(cl, cl->cancels, cl->num_cancels, cancel);
|
||||
mp_mutex_unlock(&cl->lock);
|
||||
|
||||
bool success = mp_cancel_wait(cancel, timeout);
|
||||
|
||||
mp_mutex_lock(&cl->lock);
|
||||
for (int i = 0; i < cl->num_cancels; ++i) {
|
||||
if (cl->cancels[i] == cancel) {
|
||||
MP_TARRAY_REMOVE_AT(cl->cancels, cl->num_cancels, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mp_mutex_unlock(&cl->lock);
|
||||
return success;
|
||||
}
|
||||
|
||||
const char *mp_clipboard_get_backend_name(struct clipboard_ctx *cl)
|
||||
{
|
||||
return cl->backend ? cl->backend->name : NULL;
|
||||
@@ -168,8 +207,17 @@ void reinit_clipboard(struct MPContext *mpctx)
|
||||
talloc_free(opts);
|
||||
}
|
||||
|
||||
static void clipboard_destructor(void *ctx)
|
||||
{
|
||||
struct clipboard_ctx *cl = ctx;
|
||||
mp_mutex_destroy(&cl->lock);
|
||||
}
|
||||
|
||||
void clipboard_init(struct MPContext *mpctx)
|
||||
{
|
||||
mpctx->clipboard = talloc_zero_ptrtype(mpctx, mpctx->clipboard);
|
||||
mpctx->clipboard->log = mp_log_new(mpctx->clipboard, mpctx->global->log, "clipboard");
|
||||
struct clipboard_ctx *cl = talloc_zero_ptrtype(mpctx, cl);
|
||||
talloc_set_destructor(cl, clipboard_destructor);
|
||||
cl->log = mp_log_new(cl, mpctx->global->log, "clipboard");
|
||||
mp_mutex_init(&cl->lock);
|
||||
mpctx->clipboard = cl;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/common.h"
|
||||
#include "osdep/threads.h"
|
||||
|
||||
struct clipboard_ctx;
|
||||
struct mp_image;
|
||||
@@ -75,6 +76,7 @@ struct clipboard_backend {
|
||||
struct clipboard_data *out, void *talloc_ctx);
|
||||
int (*set_data)(struct clipboard_ctx *cl, struct clipboard_access_params *params,
|
||||
struct clipboard_data *data);
|
||||
void (*update_data)(struct clipboard_ctx *cl, struct clipboard_access_params *params);
|
||||
};
|
||||
|
||||
struct clipboard_ctx {
|
||||
@@ -82,6 +84,12 @@ struct clipboard_ctx {
|
||||
struct mp_log *log;
|
||||
void *priv; // backend-specific internal data
|
||||
bool monitor;
|
||||
// For notifying mp_clipboard_update_data waiters.
|
||||
// Lock protects backend and cancel access.
|
||||
// Must outlive the pending commands that use worker threads.
|
||||
mp_mutex lock;
|
||||
struct mp_cancel **cancels;
|
||||
int num_cancels;
|
||||
};
|
||||
|
||||
void mp_clipboard_destroy(struct clipboard_ctx *cl);
|
||||
@@ -90,7 +98,10 @@ int mp_clipboard_get_data(struct clipboard_ctx *cl, struct clipboard_access_para
|
||||
struct clipboard_data *out, void *talloc_ctx);
|
||||
int mp_clipboard_set_data(struct clipboard_ctx *cl, struct clipboard_access_params *params,
|
||||
struct clipboard_data *data);
|
||||
bool mp_clipboard_update_data(struct clipboard_ctx *cl, struct clipboard_access_params *params,
|
||||
struct mp_cancel *cancel, double timeout);
|
||||
const char *mp_clipboard_get_backend_name(struct clipboard_ctx *cl);
|
||||
void mp_clipboard_notify_update_data(struct clipboard_ctx *cl);
|
||||
|
||||
void reinit_clipboard(struct MPContext *mpctx);
|
||||
void clipboard_init(struct MPContext *mpctx);
|
||||
|
||||
@@ -7151,6 +7151,20 @@ static void cmd_begin_vo_dragging(void *p)
|
||||
vo_control(vo, VOCTRL_BEGIN_DRAGGING, NULL);
|
||||
}
|
||||
|
||||
static void cmd_update_clipboard(void *p)
|
||||
{
|
||||
struct mp_cmd_ctx *cmd = p;
|
||||
struct MPContext *mpctx = cmd->mpctx;
|
||||
struct clipboard_access_params params = {.type = cmd->args[0].v.i};
|
||||
double timeout = cmd->args[1].v.i / 1000.0;
|
||||
bool success = false;
|
||||
|
||||
mp_core_unlock(mpctx);
|
||||
success = mp_clipboard_update_data(mpctx->clipboard, ¶ms, cmd->abort->cancel, timeout);
|
||||
mp_core_lock(mpctx);
|
||||
cmd->success = success;
|
||||
}
|
||||
|
||||
static void cmd_context_menu(void *p)
|
||||
{
|
||||
struct mp_cmd_ctx *cmd = p;
|
||||
@@ -7705,6 +7719,16 @@ const struct mp_cmd_def mp_cmds[] = {
|
||||
|
||||
{ "begin-vo-dragging", cmd_begin_vo_dragging },
|
||||
|
||||
{ "update-clipboard", cmd_update_clipboard,
|
||||
{ {"type", OPT_CHOICE(v.i,
|
||||
{"text", CLIPBOARD_TARGET_CLIPBOARD},
|
||||
{"text-primary", CLIPBOARD_TARGET_PRIMARY_SELECTION})},
|
||||
{"timeout", OPT_INT(v.i), OPTDEF_INT(10)},
|
||||
},
|
||||
.spawn_thread = true,
|
||||
.can_abort = true,
|
||||
},
|
||||
|
||||
{ "context-menu", cmd_context_menu },
|
||||
|
||||
{ "flush-status-line", cmd_flush_status_line, { {"clear", OPT_BOOL(v.b)} } },
|
||||
|
||||
Reference in New Issue
Block a user