mirror of https://github.com/mpv-player/mpv
x11: support XEmbed
Seems to work with GtkSocket and passing the gtk_socket_get_id() value via "wid" option to mpv. One caveat is that using <tab> to move input focus from mpv to GTK does not work. It seems we would have to interpret <tab> ourselves in this case. I'm not sure if we really should do this - it would probably require emulating some other typical conventions too. I'm not sure if an embedder could do something about this on the toolkit level, but in theory it would be possible, so leave it as is for now.
This commit is contained in:
parent
2e531aaf14
commit
fc95678d8d
|
@ -2304,7 +2304,7 @@ Input
|
|||
|
||||
``--input-vo-keyboard=<yes|no>``
|
||||
Disable all keyboard input on for VOs which can't participate in proper
|
||||
keyboard input dispatching. This currently affects X11. Generally useful for
|
||||
keyboard input dispatching. May not affect all VOs. Generally useful for
|
||||
embedding only.
|
||||
|
||||
On X11, a sub-window with input enabled grabs all keyboard input as long
|
||||
|
@ -2316,11 +2316,14 @@ Input
|
|||
behavior, but naively embedding foreign windows breaks it.
|
||||
|
||||
The only way to handle this reasonably is using the XEmbed protocol, which
|
||||
was designed to solve these problems. But Qt has questionable support, and
|
||||
mpv doesn't implement it yet.
|
||||
was designed to solve these problems. GTK provides ``GtkSocket``, which
|
||||
supports XEmbed. Qt doesn't seem to provide anything working in newer
|
||||
versions.
|
||||
|
||||
As a workaround, this option is disabled by default in libmpv. (Note that
|
||||
``input-default-bindings`` is disabled by default in libmpv as well.)
|
||||
If the embedder supports XEmbed, input should work with default settings
|
||||
and with this option disabled. Note that ``input-default-bindings`` is
|
||||
disabled by default in libmpv as well - it should be enabled if you want
|
||||
the mpv default key bindings.
|
||||
|
||||
(This option was renamed from ``--input-x11-keyboard``.)
|
||||
|
||||
|
|
|
@ -90,6 +90,11 @@
|
|||
|
||||
#define DND_VERSION 5
|
||||
|
||||
#define XEMBED_VERSION 0
|
||||
#define XEMBED_MAPPED (1 << 0)
|
||||
#define XEMBED_EMBEDDED_NOTIFY 0
|
||||
#define XEMBED_REQUEST_FOCUS 3
|
||||
|
||||
// ----- Motif header: -------
|
||||
|
||||
#define MWM_HINTS_FUNCTIONS (1L << 0)
|
||||
|
@ -125,6 +130,8 @@ static void set_screensaver(struct vo_x11_state *x11, bool enabled);
|
|||
static void vo_x11_selectinput_witherr(struct vo *vo, Display *display,
|
||||
Window w, long event_mask);
|
||||
static void vo_x11_setlayer(struct vo *vo, bool ontop);
|
||||
static void vo_x11_xembed_handle_message(struct vo *vo, XClientMessageEvent *ce);
|
||||
static void vo_x11_xembed_send_message(struct vo_x11_state *x11, long m[4]);
|
||||
|
||||
#define XA(x11, s) (XInternAtom((x11)->display, # s, False))
|
||||
#define XAs(x11, s) XInternAtom((x11)->display, s, False)
|
||||
|
@ -926,6 +933,8 @@ int vo_x11_check_events(struct vo *vo)
|
|||
mp_input_put_key(vo->input_ctx,
|
||||
(MP_MOUSE_BTN0 + Event.xbutton.button - 1) |
|
||||
get_mods(Event.xbutton.state) | MP_KEY_STATE_DOWN);
|
||||
long msg[4] = {XEMBED_REQUEST_FOCUS};
|
||||
vo_x11_xembed_send_message(x11, msg);
|
||||
break;
|
||||
case ButtonRelease:
|
||||
if (Event.xbutton.button == 1)
|
||||
|
@ -951,6 +960,7 @@ int vo_x11_check_events(struct vo *vo)
|
|||
Event.xclient.data.l[0] == XA(x11, WM_DELETE_WINDOW))
|
||||
mp_input_put_key(vo->input_ctx, MP_KEY_CLOSE_WIN);
|
||||
vo_x11_dnd_handle_message(vo, &Event.xclient);
|
||||
vo_x11_xembed_handle_message(vo, &Event.xclient);
|
||||
break;
|
||||
case SelectionNotify:
|
||||
vo_x11_dnd_handle_selection(vo, &Event.xselection);
|
||||
|
@ -1088,6 +1098,42 @@ static void vo_x11_update_window_title(struct vo *vo)
|
|||
vo_x11_set_property_utf8(vo, XA(x11, _NET_WM_ICON_NAME), title);
|
||||
}
|
||||
|
||||
static void vo_x11_xembed_update(struct vo_x11_state *x11, int flags)
|
||||
{
|
||||
if (!x11->window || !x11->parent)
|
||||
return;
|
||||
|
||||
long xembed_info[] = {XEMBED_VERSION, flags};
|
||||
Atom name = XA(x11, _XEMBED_INFO);
|
||||
XChangeProperty(x11->display, x11->window, name, name, 32,
|
||||
PropModeReplace, (char *)xembed_info, 2);
|
||||
}
|
||||
|
||||
static void vo_x11_xembed_handle_message(struct vo *vo, XClientMessageEvent *ce)
|
||||
{
|
||||
struct vo_x11_state *x11 = vo->x11;
|
||||
if (!x11->window || !x11->parent || ce->message_type != XA(x11, _XEMBED))
|
||||
return;
|
||||
|
||||
long msg = ce->data.l[1];
|
||||
if (msg == XEMBED_EMBEDDED_NOTIFY)
|
||||
MP_VERBOSE(x11, "Parent windows supports XEmbed.\n");
|
||||
}
|
||||
|
||||
static void vo_x11_xembed_send_message(struct vo_x11_state *x11, long m[4])
|
||||
{
|
||||
if (!x11->window || !x11->parent)
|
||||
return;
|
||||
XEvent ev = {.xclient = {
|
||||
.type = ClientMessage,
|
||||
.window = x11->parent,
|
||||
.message_type = XA(x11, _XEMBED),
|
||||
.format = 32,
|
||||
.data = {.l = { CurrentTime, m[0], m[1], m[2], m[3] }},
|
||||
} };
|
||||
XSendEvent(x11->display, x11->parent, False, NoEventMask, &ev);
|
||||
}
|
||||
|
||||
#if HAVE_ZLIB
|
||||
static bstr decompress_gz(bstr in)
|
||||
{
|
||||
|
@ -1237,6 +1283,7 @@ static void vo_x11_create_window(struct vo *vo, XVisualInfo *vis,
|
|||
vo_x11_update_window_title(vo);
|
||||
vo_x11_dnd_init_window(vo);
|
||||
}
|
||||
vo_x11_xembed_update(x11, 0);
|
||||
}
|
||||
|
||||
static void vo_x11_map_window(struct vo *vo, struct mp_rect rc)
|
||||
|
@ -1277,6 +1324,8 @@ static void vo_x11_map_window(struct vo *vo, struct mp_rect rc)
|
|||
events |= KeyPressMask | KeyReleaseMask;
|
||||
vo_x11_selectinput_witherr(vo, x11->display, x11->window, events);
|
||||
XMapWindow(x11->display, x11->window);
|
||||
|
||||
vo_x11_xembed_update(x11, XEMBED_MAPPED);
|
||||
}
|
||||
|
||||
static void vo_x11_highlevel_resize(struct vo *vo, struct mp_rect rc)
|
||||
|
|
Loading…
Reference in New Issue