From 155fc92a0094cc19041b8df61ad94cad036b81bf Mon Sep 17 00:00:00 2001 From: hadrien-f Date: Sat, 26 Sep 2026 14:39:51 +0200 Subject: [PATCH 1/2] wayland: add --wayland-display option Applications that embed mpv on Wayland cannot parent mpv's surface under their own, so one way to embed it is to proxy mpv's Wayland connection through a private socket and turn its toplevel into a subsurface. Today the only way to point mpv at such a socket is to change WAYLAND_DISPLAY for the whole process, which also redirects the host toolkit (e.g. when Qt reconnects after a compositor restart) and every child process. Add --wayland-display to name the display the VO connects to. When it is set, the VO no longer requires WAYLAND_DISPLAY or WAYLAND_SOCKET to be set while probing. WAYLAND_SOCKET still takes precedence, as wl_display_connect() ignores the name when it is set, so warn about it. --- DOCS/interface-changes/wayland-display.txt | 1 + DOCS/man/options.rst | 12 ++++++++++++ options/options.c | 1 + options/options.h | 1 + video/out/wayland_common.c | 20 ++++++++++++++++---- 5 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 DOCS/interface-changes/wayland-display.txt diff --git a/DOCS/interface-changes/wayland-display.txt b/DOCS/interface-changes/wayland-display.txt new file mode 100644 index 0000000000000..6fc0049a88254 --- /dev/null +++ b/DOCS/interface-changes/wayland-display.txt @@ -0,0 +1 @@ +add `--wayland-display` option to connect to a Wayland display other than the one given by `WAYLAND_DISPLAY` diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 3f73771f9158a..db94fceecfe97 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -6521,6 +6521,18 @@ them. (default) will automatically switch between telling the compositor the content is a photo, video or possibly none depending on internal heuristics. +``--wayland-display=`` + Connect to this Wayland display instead of the one given by the + ``WAYLAND_DISPLAY`` environment variable (default: unset). This is either + a socket name relative to ``XDG_RUNTIME_DIR`` or an absolute path. Not + setting this or setting it to the empty string uses the environment as + usual. If ``WAYLAND_SOCKET`` is set, it takes precedence over this option. + + This is useful for applications embedding mpv that proxy its Wayland + connection, since it redirects mpv without changing ``WAYLAND_DISPLAY`` + for the whole process. Changes take effect the next time the VO is + created. + ``--wayland-edge-pixels-pointer=`` Defines the size of an edge border (default: 16) to initiate client side resize events in the wayland contexts with the mouse or tablet. This is only diff --git a/options/options.c b/options/options.c index e8b590af8c04f..c535b84384751 100644 --- a/options/options.c +++ b/options/options.c @@ -216,6 +216,7 @@ static const m_option_t mp_vo_opt_list[] = { {"photo", 1}, {"video", 2}, {"game", 3})}, {"wayland-disable-vsync", OPT_BOOL(wl_disable_vsync), .deprecation_message = "replaced by --wayland-internal-vsync=no"}, + {"wayland-display", OPT_STRING(wayland_display)}, {"wayland-internal-vsync", OPT_CHOICE(wl_internal_vsync, {"no", 0}, {"auto", 1}, {"yes", 2})}, {"wayland-edge-pixels-pointer", OPT_INT(wl_edge_pixels_pointer), diff --git a/options/options.h b/options/options.h index 26a791343ffff..7aaf5d3f10c10 100644 --- a/options/options.h +++ b/options/options.h @@ -29,6 +29,7 @@ typedef struct mp_vo_opts { char *winname; char *appid; char *wayland_session; + char *wayland_display; int x11_netwm; int x11_bypass_compositor; int x11_present; diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index d1bf43e1f48ff..e1b06cd84eab0 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -4528,9 +4528,15 @@ bool vo_wayland_valid_format(struct vo_wayland_state *wl, uint32_t drm_format, u bool vo_wayland_init(struct vo *vo) { - if (vo->probing && !getenv("WAYLAND_DISPLAY") && !getenv("WAYLAND_SOCKET")) { - MP_VERBOSE(vo, "Skipping Wayland because neither WAYLAND_DISPLAY or " - "WAYLAND_SOCKET is set\n"); + const char *display_name = vo->opts->wayland_display; + if (display_name && !display_name[0]) + display_name = NULL; + + if (vo->probing && !display_name && !getenv("WAYLAND_DISPLAY") && + !getenv("WAYLAND_SOCKET")) + { + MP_VERBOSE(vo, "Skipping Wayland because neither --wayland-display, " + "WAYLAND_DISPLAY or WAYLAND_SOCKET is set\n"); goto err; } @@ -4558,7 +4564,13 @@ bool vo_wayland_init(struct vo *vo) wl_list_init(&wl->seat_list); wl_list_init(&wl->tranche_list); - wl->display = wl_display_connect(NULL); + if (display_name && getenv("WAYLAND_SOCKET")) { + MP_WARN(wl, "WAYLAND_SOCKET is set and takes precedence over " + "--wayland-display.\n"); + } + MP_VERBOSE(wl, "Connecting to Wayland display: %s\n", + display_name ? display_name : "(default)"); + wl->display = wl_display_connect(display_name); if (!wl->display) { MP_MSG(wl, vo->probing ? MSGL_V : MSGL_FATAL, "Couldn't connect to Wayland display: %s\n", strerror(errno)); From 0771ceb38df097dd85b2b2e2643d03cb3baffda4 Mon Sep 17 00:00:00 2001 From: hadrien-f Date: Sat, 26 Sep 2026 15:06:44 +0200 Subject: [PATCH 2/2] clipboard-wayland: respect --wayland-display The Wayland clipboard backend opens its own connection at player start. Pass --wayland-display to it, so that all of mpv's Wayland connections go to the same display, and skip the environment check when it is set. Also treat the option as a Wayland environment in the X11 backend, so it doesn't fall back to an X11 clipboard when the Wayland one fails. Mark the option UPDATE_CLIPBOARD so changing it at runtime reconnects the clipboard. --- DOCS/man/options.rst | 9 +++++---- options/options.c | 2 +- player/clipboard/clipboard-wayland.c | 15 +++++++++++---- player/clipboard/clipboard-x11.c | 10 +++++++--- player/clipboard/clipboard.c | 1 + player/clipboard/clipboard.h | 1 + 6 files changed, 26 insertions(+), 12 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index db94fceecfe97..c53ed457930fe 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -6528,10 +6528,11 @@ them. setting this or setting it to the empty string uses the environment as usual. If ``WAYLAND_SOCKET`` is set, it takes precedence over this option. - This is useful for applications embedding mpv that proxy its Wayland - connection, since it redirects mpv without changing ``WAYLAND_DISPLAY`` - for the whole process. Changes take effect the next time the VO is - created. + This applies to the VO and to the Wayland clipboard backend. It is useful + for applications embedding mpv that proxy its Wayland connection, since it + redirects mpv without changing ``WAYLAND_DISPLAY`` for the whole process. + Changes reconnect the clipboard immediately and take effect for the VO the + next time it is created. ``--wayland-edge-pixels-pointer=`` Defines the size of an edge border (default: 16) to initiate client side diff --git a/options/options.c b/options/options.c index c535b84384751..fcd72636732ee 100644 --- a/options/options.c +++ b/options/options.c @@ -216,7 +216,7 @@ static const m_option_t mp_vo_opt_list[] = { {"photo", 1}, {"video", 2}, {"game", 3})}, {"wayland-disable-vsync", OPT_BOOL(wl_disable_vsync), .deprecation_message = "replaced by --wayland-internal-vsync=no"}, - {"wayland-display", OPT_STRING(wayland_display)}, + {"wayland-display", OPT_STRING(wayland_display), .flags = UPDATE_CLIPBOARD}, {"wayland-internal-vsync", OPT_CHOICE(wl_internal_vsync, {"no", 0}, {"auto", 1}, {"yes", 2})}, {"wayland-edge-pixels-pointer", OPT_INT(wl_edge_pixels_pointer), diff --git a/player/clipboard/clipboard-wayland.c b/player/clipboard/clipboard-wayland.c index 677a3cd242394..88de18acec5bf 100644 --- a/player/clipboard/clipboard-wayland.c +++ b/player/clipboard/clipboard-wayland.c @@ -336,12 +336,18 @@ static void clipboard_wayland_uninit(struct clipboard_wayland_priv *wl) wl_display_disconnect(wl->display); } -static bool clipboard_wayland_init(struct clipboard_wayland_priv *wl, bool monitor) +static bool clipboard_wayland_init(struct clipboard_wayland_priv *wl, bool monitor, + const char *display_name) { - if (!getenv("WAYLAND_DISPLAY") && !getenv("WAYLAND_SOCKET")) + if (display_name && !display_name[0]) + display_name = NULL; + if (!display_name && !getenv("WAYLAND_DISPLAY") && + !getenv("WAYLAND_SOCKET")) + { goto err; + } - wl->display = wl_display_connect(NULL); + wl->display = wl_display_connect(display_name); if (!wl->display) goto err; @@ -520,7 +526,8 @@ static int init(struct clipboard_ctx *cl, struct clipboard_init_params *params) if (mp_make_wakeup_pipe(priv->message_pipe) < 0) goto pipe_err; - if (!clipboard_wayland_init(priv, params->flags & CLIPBOARD_INIT_ENABLE_MONITORING)) + if (!clipboard_wayland_init(priv, params->flags & CLIPBOARD_INIT_ENABLE_MONITORING, + params->wayland_display)) goto init_err; if (mp_thread_create(&priv->thread, clipboard_thread, cl->priv)) goto thread_err; diff --git a/player/clipboard/clipboard-x11.c b/player/clipboard/clipboard-x11.c index 9b6bc60e9d6ac..313ea2a8aa2d0 100644 --- a/player/clipboard/clipboard-x11.c +++ b/player/clipboard/clipboard-x11.c @@ -67,9 +67,12 @@ static void clipboard_x11_uninit(struct clipboard_x11_priv *x11) XCloseDisplay(x11->display); } -static bool clipboard_x11_init(struct clipboard_x11_priv *x11, bool xwayland, bool monitor) +static bool clipboard_x11_init(struct clipboard_x11_priv *x11, bool xwayland, bool monitor, + const char *wayland_display) { - if (!xwayland && (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET"))) { + bool wayland = (wayland_display && wayland_display[0]) || + getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET"); + if (!xwayland && wayland) { MP_VERBOSE(x11, "Stopping init due to suspected wayland environment\n"); goto err; } @@ -279,7 +282,8 @@ static int init(struct clipboard_ctx *cl, struct clipboard_init_params *params) if (mp_make_wakeup_pipe(priv->message_pipe) < 0) goto pipe_err; if (!clipboard_x11_init(priv, params->flags & CLIPBOARD_INIT_ENABLE_XWAYLAND, - params->flags & CLIPBOARD_INIT_ENABLE_MONITORING)) + params->flags & CLIPBOARD_INIT_ENABLE_MONITORING, + params->wayland_display)) goto init_err; if (mp_thread_create(&priv->thread, clipboard_thread, cl->priv)) goto thread_err; diff --git a/player/clipboard/clipboard.c b/player/clipboard/clipboard.c index 7b2f9058a58f3..4a9cadb70e6a6 100644 --- a/player/clipboard/clipboard.c +++ b/player/clipboard/clipboard.c @@ -199,6 +199,7 @@ void reinit_clipboard(struct MPContext *mpctx) struct clipboard_init_params params = { .mpctx = mpctx, .backends = opts->backends, + .wayland_display = mpctx->opts->vo->wayland_display, }; params.flags |= opts->monitor ? CLIPBOARD_INIT_ENABLE_MONITORING : 0; params.flags |= opts->xwayland ? CLIPBOARD_INIT_ENABLE_XWAYLAND : 0; diff --git a/player/clipboard/clipboard.h b/player/clipboard/clipboard.h index 7a30cb9ac6277..5ae882ba2f664 100644 --- a/player/clipboard/clipboard.h +++ b/player/clipboard/clipboard.h @@ -56,6 +56,7 @@ struct clipboard_init_params { int flags; struct MPContext *mpctx; // For clipboard_vo only struct m_obj_settings *backends; + const char *wayland_display; // For clipboard_wayland and clipboard_x11 }; struct clipboard_access_params {