mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 17:40:40 -05:00
tests: Add "accept_take_focus" command
When used it setups an X11 event monitor that replies to WM_TAKE_FOCUS ClientMessage's with a XSetInputFocus request. It can only be used by x11 clients on windows that have WM_TAKE_FOCUS atom set and that does not accept input. https://gitlab.gnome.org/GNOME/mutter/merge_requests/669
This commit is contained in:
parent
bd0f1bd338
commit
b80250e483
@ -33,6 +33,7 @@ static gboolean wayland;
|
|||||||
GHashTable *windows;
|
GHashTable *windows;
|
||||||
GQuark event_source_quark;
|
GQuark event_source_quark;
|
||||||
GQuark event_handlers_quark;
|
GQuark event_handlers_quark;
|
||||||
|
GQuark can_take_focus_quark;
|
||||||
|
|
||||||
typedef void (*XEventHandler) (GtkWidget *window, XEvent *event);
|
typedef void (*XEventHandler) (GtkWidget *window, XEvent *event);
|
||||||
|
|
||||||
@ -63,6 +64,7 @@ lookup_window (const char *window_id)
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GSource base;
|
GSource base;
|
||||||
|
GSource **self_ref;
|
||||||
GPollFD event_poll_fd;
|
GPollFD event_poll_fd;
|
||||||
Display *xdisplay;
|
Display *xdisplay;
|
||||||
} XClientEventSource;
|
} XClientEventSource;
|
||||||
@ -120,10 +122,19 @@ x_event_source_dispatch (GSource *source,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
x_event_source_finalize (GSource *source)
|
||||||
|
{
|
||||||
|
XClientEventSource *x_source = (XClientEventSource *) source;
|
||||||
|
|
||||||
|
*x_source->self_ref = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static GSourceFuncs x_event_funcs = {
|
static GSourceFuncs x_event_funcs = {
|
||||||
x_event_source_prepare,
|
x_event_source_prepare,
|
||||||
x_event_source_check,
|
x_event_source_check,
|
||||||
x_event_source_dispatch,
|
x_event_source_dispatch,
|
||||||
|
x_event_source_finalize,
|
||||||
};
|
};
|
||||||
|
|
||||||
static GSource*
|
static GSource*
|
||||||
@ -138,6 +149,7 @@ ensure_xsource_handler (GdkDisplay *gdkdisplay)
|
|||||||
|
|
||||||
source = g_source_new (&x_event_funcs, sizeof (XClientEventSource));
|
source = g_source_new (&x_event_funcs, sizeof (XClientEventSource));
|
||||||
x_source = (XClientEventSource *) source;
|
x_source = (XClientEventSource *) source;
|
||||||
|
x_source->self_ref = &source;
|
||||||
x_source->xdisplay = xdisplay;
|
x_source->xdisplay = xdisplay;
|
||||||
x_source->event_poll_fd.fd = ConnectionNumber (xdisplay);
|
x_source->event_poll_fd.fd = ConnectionNumber (xdisplay);
|
||||||
x_source->event_poll_fd.events = G_IO_IN;
|
x_source->event_poll_fd.events = G_IO_IN;
|
||||||
@ -163,6 +175,15 @@ window_has_x11_event_handler (GtkWidget *window,
|
|||||||
return g_list_find (handlers, handler) != NULL;
|
return g_list_find (handlers, handler) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unref_and_maybe_destroy_gsource (GSource *source)
|
||||||
|
{
|
||||||
|
g_source_unref (source);
|
||||||
|
|
||||||
|
if (source->ref_count == 1)
|
||||||
|
g_source_destroy (source);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
window_add_x11_event_handler (GtkWidget *window,
|
window_add_x11_event_handler (GtkWidget *window,
|
||||||
XEventHandler handler)
|
XEventHandler handler)
|
||||||
@ -175,7 +196,7 @@ window_add_x11_event_handler (GtkWidget *window,
|
|||||||
|
|
||||||
source = ensure_xsource_handler (gtk_widget_get_display (window));
|
source = ensure_xsource_handler (gtk_widget_get_display (window));
|
||||||
g_object_set_qdata_full (G_OBJECT (window), event_source_quark, source,
|
g_object_set_qdata_full (G_OBJECT (window), event_source_quark, source,
|
||||||
(GDestroyNotify) g_source_unref);
|
(GDestroyNotify) unref_and_maybe_destroy_gsource);
|
||||||
|
|
||||||
handlers = g_list_append (handlers, handler);
|
handlers = g_list_append (handlers, handler);
|
||||||
g_object_set_qdata (G_OBJECT (window), event_handlers_quark, handlers);
|
g_object_set_qdata (G_OBJECT (window), event_handlers_quark, handlers);
|
||||||
@ -196,6 +217,31 @@ window_remove_x11_event_handler (GtkWidget *window,
|
|||||||
g_object_set_qdata (G_OBJECT (window), event_handlers_quark, handlers);
|
g_object_set_qdata (G_OBJECT (window), event_handlers_quark, handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_take_focus (GtkWidget *window,
|
||||||
|
XEvent *xevent)
|
||||||
|
{
|
||||||
|
GdkWindow *gdkwindow = gtk_widget_get_window (window);
|
||||||
|
GdkDisplay *display = gtk_widget_get_display (window);
|
||||||
|
Atom wm_protocols =
|
||||||
|
gdk_x11_get_xatom_by_name_for_display (display, "WM_PROTOCOLS");
|
||||||
|
Atom wm_take_focus =
|
||||||
|
gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS");
|
||||||
|
|
||||||
|
if (xevent->xany.type != ClientMessage ||
|
||||||
|
xevent->xany.window != GDK_WINDOW_XID (gdkwindow))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (xevent->xclient.message_type == wm_protocols &&
|
||||||
|
xevent->xclient.data.l[0] == wm_take_focus)
|
||||||
|
{
|
||||||
|
XSetInputFocus (xevent->xany.display,
|
||||||
|
GDK_WINDOW_XID (gdkwindow),
|
||||||
|
RevertToParent,
|
||||||
|
xevent->xclient.data.l[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
process_line (const char *line)
|
process_line (const char *line)
|
||||||
{
|
{
|
||||||
@ -264,6 +310,9 @@ process_line (const char *line)
|
|||||||
gtk_window_set_title (GTK_WINDOW (window), title);
|
gtk_window_set_title (GTK_WINDOW (window), title);
|
||||||
g_free (title);
|
g_free (title);
|
||||||
|
|
||||||
|
g_object_set_qdata (G_OBJECT (window), can_take_focus_quark,
|
||||||
|
GUINT_TO_POINTER (TRUE));
|
||||||
|
|
||||||
gtk_widget_realize (window);
|
gtk_widget_realize (window);
|
||||||
|
|
||||||
if (!wayland)
|
if (!wayland)
|
||||||
@ -350,6 +399,14 @@ process_line (const char *line)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wayland &&
|
||||||
|
window_has_x11_event_handler (window, handle_take_focus))
|
||||||
|
{
|
||||||
|
g_print ("Impossible to use %s for windows accepting take focus",
|
||||||
|
argv[1]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean enabled = g_ascii_strcasecmp (argv[2], "true") == 0;
|
gboolean enabled = g_ascii_strcasecmp (argv[2], "true") == 0;
|
||||||
gtk_window_set_accept_focus (GTK_WINDOW (window), enabled);
|
gtk_window_set_accept_focus (GTK_WINDOW (window), enabled);
|
||||||
}
|
}
|
||||||
@ -374,6 +431,13 @@ process_line (const char *line)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window_has_x11_event_handler (window, handle_take_focus))
|
||||||
|
{
|
||||||
|
g_print ("Impossible to change %s for windows accepting take focus",
|
||||||
|
argv[1]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
GdkDisplay *display = gdk_display_get_default ();
|
GdkDisplay *display = gdk_display_get_default ();
|
||||||
GdkWindow *gdkwindow = gtk_widget_get_window (window);
|
GdkWindow *gdkwindow = gtk_widget_get_window (window);
|
||||||
Display *xdisplay = gdk_x11_display_get_xdisplay (display);
|
Display *xdisplay = gdk_x11_display_get_xdisplay (display);
|
||||||
@ -399,10 +463,51 @@ process_line (const char *line)
|
|||||||
new_protocols[n++] = wm_take_focus;
|
new_protocols[n++] = wm_take_focus;
|
||||||
|
|
||||||
XSetWMProtocols (xdisplay, xwindow, new_protocols, n);
|
XSetWMProtocols (xdisplay, xwindow, new_protocols, n);
|
||||||
|
g_object_set_qdata (G_OBJECT (window), can_take_focus_quark,
|
||||||
|
GUINT_TO_POINTER (add));
|
||||||
|
|
||||||
XFree (new_protocols);
|
XFree (new_protocols);
|
||||||
XFree (protocols);
|
XFree (protocols);
|
||||||
}
|
}
|
||||||
|
else if (strcmp (argv[0], "accept_take_focus") == 0)
|
||||||
|
{
|
||||||
|
if (argc != 3)
|
||||||
|
{
|
||||||
|
g_print ("usage: %s <window-id> [true|false]", argv[0]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWidget *window = lookup_window (argv[1]);
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
g_print ("unknown window %s", argv[1]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wayland)
|
||||||
|
{
|
||||||
|
g_print ("%s not supported under wayland", argv[0]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gtk_window_get_accept_focus (GTK_WINDOW (window)))
|
||||||
|
{
|
||||||
|
g_print ("%s not supported for input windows", argv[0]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_object_get_qdata (G_OBJECT (window), can_take_focus_quark))
|
||||||
|
{
|
||||||
|
g_print ("%s not supported for windows with no WM_TAKE_FOCUS set",
|
||||||
|
argv[0]);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_ascii_strcasecmp (argv[2], "true") == 0)
|
||||||
|
window_add_x11_event_handler (window, handle_take_focus);
|
||||||
|
else
|
||||||
|
window_remove_x11_event_handler (window, handle_take_focus);
|
||||||
|
}
|
||||||
else if (strcmp (argv[0], "show") == 0)
|
else if (strcmp (argv[0], "show") == 0)
|
||||||
{
|
{
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
@ -669,6 +774,7 @@ main(int argc, char **argv)
|
|||||||
g_free, NULL);
|
g_free, NULL);
|
||||||
event_source_quark = g_quark_from_static_string ("event-source");
|
event_source_quark = g_quark_from_static_string ("event-source");
|
||||||
event_handlers_quark = g_quark_from_static_string ("event-handlers");
|
event_handlers_quark = g_quark_from_static_string ("event-handlers");
|
||||||
|
can_take_focus_quark = g_quark_from_static_string ("can-take-focus");
|
||||||
|
|
||||||
GInputStream *raw_in = g_unix_input_stream_new (0, FALSE);
|
GInputStream *raw_in = g_unix_input_stream_new (0, FALSE);
|
||||||
GDataInputStream *in = g_data_input_stream_new (raw_in);
|
GDataInputStream *in = g_data_input_stream_new (raw_in);
|
||||||
|
@ -497,6 +497,25 @@ test_case_do (TestCase *test,
|
|||||||
NULL))
|
NULL))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
else if (strcmp (argv[0], "accept_take_focus") == 0)
|
||||||
|
{
|
||||||
|
if (argc != 3 ||
|
||||||
|
(g_ascii_strcasecmp (argv[2], "true") != 0 &&
|
||||||
|
g_ascii_strcasecmp (argv[2], "false") != 0))
|
||||||
|
BAD_COMMAND("usage: %s <client-id>/<window-id> [true|false]",
|
||||||
|
argv[0]);
|
||||||
|
|
||||||
|
TestClient *client;
|
||||||
|
const char *window_id;
|
||||||
|
if (!test_case_parse_window_id (test, argv[1], &client, &window_id, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!test_client_do (client, error,
|
||||||
|
argv[0], window_id,
|
||||||
|
argv[2],
|
||||||
|
NULL))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
else if (strcmp (argv[0], "show") == 0)
|
else if (strcmp (argv[0], "show") == 0)
|
||||||
{
|
{
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
|
Loading…
Reference in New Issue
Block a user