From 0200f4fcd9bc5921f15a8547cce6c5ba85f4cea9 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 30 Dec 2018 12:58:31 +0100 Subject: [PATCH 01/16] x11: Move focus sentinel to MetaX11Display This focus sentinel is a mechanism to avoid some X11-specific race conditions in focus-follows-pointer, using X11 mechanisms. Move it to MetaX11Display altogether. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/core/display-private.h | 8 -------- src/core/display.c | 32 ------------------------------ src/core/window.c | 10 ++++++---- src/x11/events.c | 4 ++-- src/x11/meta-x11-display-private.h | 9 +++++++++ src/x11/meta-x11-display.c | 31 +++++++++++++++++++++++++++++ 6 files changed, 48 insertions(+), 46 deletions(-) diff --git a/src/core/display-private.h b/src/core/display-private.h index 068c710af44..ea683a39acb 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -203,10 +203,6 @@ struct _MetaDisplay MetaEdgeResistanceData *grab_edge_resistance_data; unsigned int grab_last_user_action_was_snap; - /* we use property updates as sentinels for certain window focus events - * to avoid some race conditions on EnterNotify events - */ - int sentinel_counter; int grab_resize_timeout_id; MetaKeyBindingManager key_binding_manager; @@ -363,10 +359,6 @@ gboolean meta_grab_op_is_resizing (MetaGrabOp op); gboolean meta_grab_op_is_mouse (MetaGrabOp op); gboolean meta_grab_op_is_keyboard (MetaGrabOp op); -void meta_display_increment_focus_sentinel (MetaDisplay *display); -void meta_display_decrement_focus_sentinel (MetaDisplay *display); -gboolean meta_display_focus_sentinel_clear (MetaDisplay *display); - void meta_display_queue_autoraise_callback (MetaDisplay *display, MetaWindow *window); void meta_display_remove_autoraise_callback (MetaDisplay *display); diff --git a/src/core/display.c b/src/core/display.c index adef7de5dc4..a762af7fd5e 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -683,7 +683,6 @@ meta_display_open (void) } display->current_time = META_CURRENT_TIME; - display->sentinel_counter = 0; display->grab_resize_timeout_id = 0; display->grab_have_keyboard = FALSE; @@ -2490,37 +2489,6 @@ prefs_changed_callback (MetaPreference pref, } } -void -meta_display_increment_focus_sentinel (MetaDisplay *display) -{ - unsigned long data[1]; - - data[0] = meta_display_get_current_time (display); - - XChangeProperty (display->x11_display->xdisplay, - display->x11_display->xroot, - display->x11_display->atom__MUTTER_SENTINEL, - XA_CARDINAL, - 32, PropModeReplace, (guchar*) data, 1); - - display->sentinel_counter += 1; -} - -void -meta_display_decrement_focus_sentinel (MetaDisplay *display) -{ - display->sentinel_counter -= 1; - - if (display->sentinel_counter < 0) - display->sentinel_counter = 0; -} - -gboolean -meta_display_focus_sentinel_clear (MetaDisplay *display) -{ - return (display->sentinel_counter == 0); -} - void meta_display_sanity_check_timestamps (MetaDisplay *display, guint32 timestamp) diff --git a/src/core/window.c b/src/core/window.c index 89408081da0..c37afa36b79 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -1939,9 +1939,10 @@ idle_calc_showing (gpointer data) while (tmp != NULL) { MetaWindow *window = tmp->data; + MetaDisplay *display = window->display; - if (!window->display->mouse_mode) - meta_display_increment_focus_sentinel (window->display); + if (display->x11_display && !display->mouse_mode) + meta_x11_display_increment_focus_sentinel (display->x11_display); tmp = tmp->next; } @@ -2411,6 +2412,7 @@ meta_window_show (MetaWindow *window) gboolean needs_stacking_adjustment; MetaWindow *focus_window; gboolean notify_demands_attention = FALSE; + MetaDisplay *display = window->display; meta_topic (META_DEBUG_WINDOW_STATE, "Showing window %s, shaded: %d iconic: %d placed: %d\n", @@ -2577,7 +2579,7 @@ meta_window_show (MetaWindow *window) meta_window_focus (window, timestamp); } - else + else if (display->x11_display) { /* Prevent EnterNotify events in sloppy/mouse focus from * erroneously focusing the window that had been denied @@ -2585,7 +2587,7 @@ meta_window_show (MetaWindow *window) * ideas for a better way to accomplish the same thing, but * they're more involved so do it this way for now. */ - meta_display_increment_focus_sentinel (window->display); + meta_x11_display_increment_focus_sentinel (display->x11_display); } } diff --git a/src/x11/events.c b/src/x11/events.c index 92b5d70156b..5fdff162c13 100644 --- a/src/x11/events.c +++ b/src/x11/events.c @@ -882,7 +882,7 @@ handle_input_xevent (MetaX11Display *x11_display, enter_event->mode != XINotifyGrab && enter_event->mode != XINotifyUngrab && enter_event->detail != XINotifyInferior && - meta_display_focus_sentinel_clear (display)) + meta_x11_display_focus_sentinel_clear (x11_display)) { meta_window_handle_enter (window, enter_event->time, @@ -1525,7 +1525,7 @@ handle_other_xevent (MetaX11Display *x11_display, if (event->xproperty.atom == x11_display->atom__MUTTER_SENTINEL) { - meta_display_decrement_focus_sentinel (display); + meta_x11_display_decrement_focus_sentinel (x11_display); } } } diff --git a/src/x11/meta-x11-display-private.h b/src/x11/meta-x11-display-private.h index 9a8ab83b209..c7af182d9f0 100644 --- a/src/x11/meta-x11-display-private.h +++ b/src/x11/meta-x11-display-private.h @@ -135,6 +135,11 @@ struct _MetaX11Display guint keys_grabbed : 1; + /* we use property updates as sentinels for certain window focus events + * to avoid some race conditions on EnterNotify events + */ + int sentinel_counter; + int composite_event_base; int composite_error_base; int composite_major_version; @@ -222,4 +227,8 @@ MetaLogicalMonitor *meta_x11_display_xinerama_index_to_logical_monitor (MetaX11D void meta_x11_display_update_workspace_layout (MetaX11Display *x11_display); void meta_x11_display_update_workspace_names (MetaX11Display *x11_display); +void meta_x11_display_increment_focus_sentinel (MetaX11Display *x11_display); +void meta_x11_display_decrement_focus_sentinel (MetaX11Display *x11_display); +gboolean meta_x11_display_focus_sentinel_clear (MetaX11Display *x11_display); + #endif /* META_X11_DISPLAY_PRIVATE_H */ diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c index af8ae7a8d6d..2aece19a836 100644 --- a/src/x11/meta-x11-display.c +++ b/src/x11/meta-x11-display.c @@ -2177,3 +2177,34 @@ prefs_changed_callback (MetaPreference pref, set_workspace_names (x11_display); } } + +void +meta_x11_display_increment_focus_sentinel (MetaX11Display *x11_display) +{ + unsigned long data[1]; + + data[0] = meta_display_get_current_time (x11_display->display); + + XChangeProperty (x11_display->xdisplay, + x11_display->xroot, + x11_display->atom__MUTTER_SENTINEL, + XA_CARDINAL, + 32, PropModeReplace, (guchar*) data, 1); + + x11_display->sentinel_counter += 1; +} + +void +meta_x11_display_decrement_focus_sentinel (MetaX11Display *x11_display) +{ + x11_display->sentinel_counter -= 1; + + if (x11_display->sentinel_counter < 0) + x11_display->sentinel_counter = 0; +} + +gboolean +meta_x11_display_focus_sentinel_clear (MetaX11Display *x11_display) +{ + return (x11_display->sentinel_counter == 0); +} -- GitLab From 39bac6eabd5f8658339b823c8bbc62b381d6504c Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 6 May 2019 19:25:21 +0200 Subject: [PATCH 02/16] core: Turn MetaStack into a GObject So we can have it emit signals and whatnot. Those are unused, yet. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/core/display.c | 2 +- src/core/stack.c | 150 +++++++++++++++++++++++++++++++++++++++------ src/core/stack.h | 13 ++-- 3 files changed, 136 insertions(+), 29 deletions(-) diff --git a/src/core/display.c b/src/core/display.c index a762af7fd5e..d36aaad8bf3 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -923,7 +923,7 @@ meta_display_close (MetaDisplay *display, g_clear_object (&display->gesture_tracker); - g_clear_pointer (&display->stack, meta_stack_free); + g_clear_object (&display->stack); g_clear_pointer (&display->stack_tracker, meta_stack_tracker_free); diff --git a/src/core/stack.c b/src/core/stack.c index 7ab590c98d5..55701d5bf61 100644 --- a/src/core/stack.c +++ b/src/core/stack.c @@ -63,40 +63,138 @@ static void stack_do_resort (MetaStack *stack); static void stack_ensure_sorted (MetaStack *stack); -MetaStack * -meta_stack_new (MetaDisplay *display) +enum { - MetaStack *stack; - - stack = g_new (MetaStack, 1); - - stack->display = display; - stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window)); + PROP_DISPLAY = 1, + N_PROPS +}; - stack->sorted = NULL; - stack->added = NULL; - stack->removed = NULL; +enum +{ + CHANGED, + WINDOW_ADDED, + WINDOW_REMOVED, + N_SIGNALS +}; - stack->freeze_count = 0; - stack->n_positions = 0; +static GParamSpec *pspecs[N_PROPS] = { 0 }; +static guint signals[N_SIGNALS] = { 0 }; - stack->need_resort = FALSE; - stack->need_relayer = FALSE; - stack->need_constrain = FALSE; +G_DEFINE_TYPE (MetaStack, meta_stack, G_TYPE_OBJECT) - return stack; +static void +meta_stack_init (MetaStack *stack) +{ + stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window)); } -void -meta_stack_free (MetaStack *stack) +static void +meta_stack_finalize (GObject *object) { + MetaStack *stack = META_STACK (object); + g_array_free (stack->xwindows, TRUE); g_list_free (stack->sorted); g_list_free (stack->added); g_list_free (stack->removed); - g_free (stack); + G_OBJECT_CLASS (meta_stack_parent_class)->finalize (object); +} + +static void +meta_stack_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaStack *stack = META_STACK (object); + + switch (prop_id) + { + case PROP_DISPLAY: + stack->display = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_stack_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaStack *stack = META_STACK (object); + + switch (prop_id) + { + case PROP_DISPLAY: + g_value_set_object (value, stack->display); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_stack_class_init (MetaStackClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = meta_stack_set_property; + object_class->get_property = meta_stack_get_property; + object_class->finalize = meta_stack_finalize; + + signals[CHANGED] = + g_signal_new ("changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + signals[WINDOW_ADDED] = + g_signal_new ("window-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, META_TYPE_WINDOW); + signals[WINDOW_REMOVED] = + g_signal_new ("window-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, META_TYPE_WINDOW); + + pspecs[PROP_DISPLAY] = + g_param_spec_object ("display", + "Display", + "Display", + META_TYPE_DISPLAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, N_PROPS, pspecs); +} + +MetaStack * +meta_stack_new (MetaDisplay *display) +{ + return g_object_new (META_TYPE_STACK, + "display", display, + NULL); +} + +static void +meta_stack_changed (MetaStack *stack) +{ + /* Bail out if frozen */ + if (stack->freeze_count > 0) + return; + + stack_ensure_sorted (stack); + g_signal_emit (stack, signals[CHANGED], 0); } void @@ -113,6 +211,7 @@ meta_stack_add (MetaStack *stack, meta_bug ("Window %s had stack position already\n", window->desc); stack->added = g_list_prepend (stack->added, window); + g_signal_emit (stack, signals[WINDOW_ADDED], 0, window); window->stack_position = stack->n_positions; stack->n_positions += 1; @@ -121,6 +220,7 @@ meta_stack_add (MetaStack *stack, window->desc, window->stack_position); stack_sync_to_xserver (stack); + meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -144,6 +244,8 @@ meta_stack_remove (MetaStack *stack, stack->added = g_list_remove (stack->added, window); stack->sorted = g_list_remove (stack->sorted, window); + g_signal_emit (stack, signals[WINDOW_REMOVED], 0, window); + /* stack->removed is only used to update stack->xwindows */ if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) { @@ -159,6 +261,7 @@ meta_stack_remove (MetaStack *stack, } stack_sync_to_xserver (stack); + meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -170,6 +273,7 @@ meta_stack_update_layer (MetaStack *stack, stack->need_relayer = TRUE; stack_sync_to_xserver (stack); + meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -181,6 +285,7 @@ meta_stack_update_transient (MetaStack *stack, stack->need_constrain = TRUE; stack_sync_to_xserver (stack); + meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -211,6 +316,7 @@ meta_stack_raise (MetaStack *stack, meta_window_set_stack_position_no_sync (window, max_stack_position); stack_sync_to_xserver (stack); + meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -240,6 +346,7 @@ meta_stack_lower (MetaStack *stack, meta_window_set_stack_position_no_sync (window, min_stack_position); stack_sync_to_xserver (stack); + meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -256,6 +363,7 @@ meta_stack_thaw (MetaStack *stack) stack->freeze_count -= 1; stack_sync_to_xserver (stack); + meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, NULL); } @@ -1416,6 +1524,7 @@ meta_stack_set_positions (MetaStack *stack, "Reset the stack positions of (nearly) all windows\n"); stack_sync_to_xserver (stack); + meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, NULL); } @@ -1481,6 +1590,7 @@ meta_window_set_stack_position (MetaWindow *window, meta_window_set_stack_position_no_sync (window, position); stack_sync_to_xserver (window->display->stack); + meta_stack_changed (window->display->stack); meta_stack_update_window_tile_matches (window->display->stack, workspace_manager->active_workspace); } diff --git a/src/core/stack.h b/src/core/stack.h index fa7bcca455b..c407a2ba80a 100644 --- a/src/core/stack.h +++ b/src/core/stack.h @@ -51,6 +51,8 @@ */ struct _MetaStack { + GObject parent; + /** The MetaDisplay containing this stack. */ MetaDisplay *display; @@ -121,6 +123,9 @@ struct _MetaStack unsigned int need_constrain : 1; }; +#define META_TYPE_STACK (meta_stack_get_type ()) +G_DECLARE_FINAL_TYPE (MetaStack, meta_stack, META, STACK, GObject) + /** * meta_stack_new: * @display: The MetaDisplay which will be the parent of this stack. @@ -131,14 +136,6 @@ struct _MetaStack */ MetaStack *meta_stack_new (MetaDisplay *display); -/** - * meta_stack_free: - * @stack: The stack to destroy. - * - * Destroys and frees a MetaStack. - */ -void meta_stack_free (MetaStack *stack); - /** * meta_stack_add: * @stack: The stack to add it to -- GitLab From ef074ea510e7f3d10fa99d56121a2bdcc13f6f39 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Tue, 7 May 2019 12:59:50 +0200 Subject: [PATCH 03/16] x11: Add MetaX11Stack object This object takes care of the X11 representation of the window stack, namely the _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING root window properties. This code has been lifted from src/core/stack.c into src/x11 as it's dependent on the X11 display availability. This also leaves MetaStack squeaky clean of x11 specifics. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/core/stack.c | 257 +----------------- src/core/stack.h | 26 -- src/meson.build | 2 + src/x11/meta-x11-display-private.h | 2 + src/x11/meta-x11-display.c | 3 + src/x11/meta-x11-stack-private.h | 33 +++ src/x11/meta-x11-stack.c | 413 +++++++++++++++++++++++++++++ 7 files changed, 458 insertions(+), 278 deletions(-) create mode 100644 src/x11/meta-x11-stack-private.h create mode 100644 src/x11/meta-x11-stack.c diff --git a/src/core/stack.c b/src/core/stack.c index 55701d5bf61..5a2f8330173 100644 --- a/src/core/stack.c +++ b/src/core/stack.c @@ -29,18 +29,13 @@ #include "core/stack.h" -#include - #include "backends/meta-logical-monitor.h" #include "core/frame.h" #include "core/meta-workspace-manager-private.h" #include "core/window-private.h" #include "meta/group.h" -#include "meta/meta-x11-errors.h" #include "meta/prefs.h" #include "meta/workspace.h" -#include "x11/group-private.h" -#include "x11/meta-x11-display-private.h" #define WINDOW_HAS_TRANSIENT_TYPE(w) \ (w->type == META_WINDOW_DIALOG || \ @@ -52,11 +47,8 @@ #define WINDOW_TRANSIENT_FOR_WHOLE_GROUP(w) \ (WINDOW_HAS_TRANSIENT_TYPE (w) && w->transient_for == NULL) -static void stack_sync_to_xserver (MetaStack *stack); static void meta_window_set_stack_position_no_sync (MetaWindow *window, int position); -static void stack_do_window_deletions (MetaStack *stack); -static void stack_do_window_additions (MetaStack *stack); static void stack_do_relayer (MetaStack *stack); static void stack_do_constrain (MetaStack *stack); static void stack_do_resort (MetaStack *stack); @@ -85,7 +77,6 @@ G_DEFINE_TYPE (MetaStack, meta_stack, G_TYPE_OBJECT) static void meta_stack_init (MetaStack *stack) { - stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window)); } static void @@ -93,11 +84,7 @@ meta_stack_finalize (GObject *object) { MetaStack *stack = META_STACK (object); - g_array_free (stack->xwindows, TRUE); - g_list_free (stack->sorted); - g_list_free (stack->added); - g_list_free (stack->removed); G_OBJECT_CLASS (meta_stack_parent_class)->finalize (object); } @@ -210,7 +197,11 @@ meta_stack_add (MetaStack *stack, if (meta_window_is_in_stack (window)) meta_bug ("Window %s had stack position already\n", window->desc); - stack->added = g_list_prepend (stack->added, window); + stack->sorted = g_list_prepend (stack->sorted, window); + stack->need_resort = TRUE; /* may not be needed as we add to top */ + stack->need_constrain = TRUE; + stack->need_relayer = TRUE; + g_signal_emit (stack, signals[WINDOW_ADDED], 0, window); window->stack_position = stack->n_positions; @@ -219,7 +210,6 @@ meta_stack_add (MetaStack *stack, "Window %s has stack_position initialized to %d\n", window->desc, window->stack_position); - stack_sync_to_xserver (stack); meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -240,27 +230,10 @@ meta_stack_remove (MetaStack *stack, window->stack_position = -1; stack->n_positions -= 1; - /* We don't know if it's been moved from "added" to "stack" yet */ - stack->added = g_list_remove (stack->added, window); stack->sorted = g_list_remove (stack->sorted, window); g_signal_emit (stack, signals[WINDOW_REMOVED], 0, window); - /* stack->removed is only used to update stack->xwindows */ - if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) - { - /* Remember the window ID to remove it from the stack array. - * The macro is safe to use: Window is guaranteed to be 32 bits, and - * GUINT_TO_POINTER says it only works on 32 bits. - */ - stack->removed = g_list_prepend (stack->removed, - GUINT_TO_POINTER (window->xwindow)); - if (window->frame) - stack->removed = g_list_prepend (stack->removed, - GUINT_TO_POINTER (window->frame->xwindow)); - } - - stack_sync_to_xserver (stack); meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -272,7 +245,6 @@ meta_stack_update_layer (MetaStack *stack, MetaWorkspaceManager *workspace_manager = window->display->workspace_manager; stack->need_relayer = TRUE; - stack_sync_to_xserver (stack); meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -284,7 +256,6 @@ meta_stack_update_transient (MetaStack *stack, MetaWorkspaceManager *workspace_manager = window->display->workspace_manager; stack->need_constrain = TRUE; - stack_sync_to_xserver (stack); meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -315,7 +286,6 @@ meta_stack_raise (MetaStack *stack, meta_window_set_stack_position_no_sync (window, max_stack_position); - stack_sync_to_xserver (stack); meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -345,7 +315,6 @@ meta_stack_lower (MetaStack *stack, meta_window_set_stack_position_no_sync (window, min_stack_position); - stack_sync_to_xserver (stack); meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -362,7 +331,6 @@ meta_stack_thaw (MetaStack *stack) g_return_if_fail (stack->freeze_count > 0); stack->freeze_count -= 1; - stack_sync_to_xserver (stack); meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, NULL); } @@ -879,99 +847,6 @@ apply_constraints (Constraint **constraints, g_slist_free (heads); } -/** - * stack_do_window_deletions: - * - * Go through "deleted" and take the matching windows - * out of "windows". - */ -static void -stack_do_window_deletions (MetaStack *stack) -{ - /* Do removals before adds, with paranoid idea that we might re-add - * the same window IDs. - */ - GList *tmp; - int i; - - tmp = stack->removed; - while (tmp != NULL) - { - Window xwindow; - xwindow = GPOINTER_TO_UINT (tmp->data); - - /* We go from the end figuring removals are more - * likely to be recent. - */ - i = stack->xwindows->len; - while (i > 0) - { - --i; - - /* there's no guarantee we'll actually find windows to - * remove, e.g. the same xwindow could have been - * added/removed before we ever synced, and we put - * both the window->xwindow and window->frame->xwindow - * in the removal list. - */ - if (xwindow == g_array_index (stack->xwindows, Window, i)) - { - g_array_remove_index (stack->xwindows, i); - goto next; - } - } - - next: - tmp = tmp->next; - } - - g_list_free (stack->removed); - stack->removed = NULL; -} - -static void -stack_do_window_additions (MetaStack *stack) -{ - GList *tmp; - gint n_added; - - n_added = g_list_length (stack->added); - if (n_added > 0) - { - meta_topic (META_DEBUG_STACK, - "Adding %d windows to sorted list\n", - n_added); - - /* stack->added has the most recent additions at the - * front of the list, so we need to reverse it - */ - stack->added = g_list_reverse (stack->added); - - tmp = stack->added; - while (tmp != NULL) - { - MetaWindow *w; - - w = tmp->data; - - if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) - g_array_append_val (stack->xwindows, w->xwindow); - - /* add to the main list */ - stack->sorted = g_list_prepend (stack->sorted, w); - - tmp = tmp->next; - } - - stack->need_resort = TRUE; /* may not be needed as we add to top */ - stack->need_constrain = TRUE; - stack->need_relayer = TRUE; - } - - g_list_free (stack->added); - stack->added = NULL; -} - /** * stack_do_relayer: * @@ -1089,131 +964,11 @@ stack_do_resort (MetaStack *stack) static void stack_ensure_sorted (MetaStack *stack) { - stack_do_window_deletions (stack); - stack_do_window_additions (stack); stack_do_relayer (stack); stack_do_constrain (stack); stack_do_resort (stack); } -/** - * stack_sync_to_server: - * - * Order the windows on the X server to be the same as in our structure. - * We do this using XRestackWindows if we don't know the previous order, - * or XConfigureWindow on a few particular windows if we do and can figure - * out the minimum set of changes. After that, we set __NET_CLIENT_LIST - * and __NET_CLIENT_LIST_STACKING. - * - * FIXME: Now that we have a good view of the stacking order on the server - * with MetaStackTracker it should be possible to do a simpler and better - * job of computing the minimal set of stacking requests needed. - */ -static void -stack_sync_to_xserver (MetaStack *stack) -{ - GArray *x11_stacked; - GArray *all_root_children_stacked; /* wayland OR x11 */ - GList *tmp; - GArray *hidden_stack_ids; - - /* Bail out if frozen */ - if (stack->freeze_count > 0) - return; - - meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n"); - - stack_ensure_sorted (stack); - - /* Create stacked xwindow arrays, in bottom-to-top order - */ - x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); - - all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64)); - hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64)); - - meta_topic (META_DEBUG_STACK, "Bottom to top: "); - meta_push_no_msg_prefix (); - - for (tmp = g_list_last(stack->sorted); tmp != NULL; tmp = tmp->prev) - { - MetaWindow *w = tmp->data; - guint64 top_level_window; - guint64 stack_id; - - if (w->unmanaging) - continue; - - meta_topic (META_DEBUG_STACK, "%u:%d - %s ", - w->layer, w->stack_position, w->desc); - - if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) - g_array_append_val (x11_stacked, w->xwindow); - - if (w->frame) - top_level_window = w->frame->xwindow; - else - top_level_window = w->xwindow; - - if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) - stack_id = top_level_window; - else - stack_id = w->stamp; - - /* We don't restack hidden windows along with the rest, though they are - * reflected in the _NET hints. Hidden windows all get pushed below - * the screens fullscreen guard_window. */ - if (w->hidden) - { - g_array_append_val (hidden_stack_ids, stack_id); - continue; - } - - g_array_append_val (all_root_children_stacked, stack_id); - } - - meta_topic (META_DEBUG_STACK, "\n"); - meta_pop_no_msg_prefix (); - - /* The screen guard window sits above all hidden windows and acts as - * a barrier to input reaching these windows. */ - guint64 guard_window_id = stack->display->x11_display->guard_window; - g_array_append_val (hidden_stack_ids, guard_window_id); - - /* Sync to server */ - - meta_topic (META_DEBUG_STACK, "Restacking %u windows\n", - all_root_children_stacked->len); - - meta_stack_tracker_restack_managed (stack->display->stack_tracker, - (guint64 *)all_root_children_stacked->data, - all_root_children_stacked->len); - meta_stack_tracker_restack_at_bottom (stack->display->stack_tracker, - (guint64 *)hidden_stack_ids->data, - hidden_stack_ids->len); - - /* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */ - - XChangeProperty (stack->display->x11_display->xdisplay, - stack->display->x11_display->xroot, - stack->display->x11_display->atom__NET_CLIENT_LIST, - XA_WINDOW, - 32, PropModeReplace, - (unsigned char *)stack->xwindows->data, - stack->xwindows->len); - XChangeProperty (stack->display->x11_display->xdisplay, - stack->display->x11_display->xroot, - stack->display->x11_display->atom__NET_CLIENT_LIST_STACKING, - XA_WINDOW, - 32, PropModeReplace, - (unsigned char *)x11_stacked->data, - x11_stacked->len); - - g_array_free (x11_stacked, TRUE); - g_array_free (hidden_stack_ids, TRUE); - g_array_free (all_root_children_stacked, TRUE); -} - MetaWindow* meta_stack_get_top (MetaStack *stack) { @@ -1523,7 +1278,6 @@ meta_stack_set_positions (MetaStack *stack, meta_topic (META_DEBUG_STACK, "Reset the stack positions of (nearly) all windows\n"); - stack_sync_to_xserver (stack); meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, NULL); } @@ -1589,7 +1343,6 @@ meta_window_set_stack_position (MetaWindow *window, MetaWorkspaceManager *workspace_manager = window->display->workspace_manager; meta_window_set_stack_position_no_sync (window, position); - stack_sync_to_xserver (window->display->stack); meta_stack_changed (window->display->stack); meta_stack_update_window_tile_matches (window->display->stack, workspace_manager->active_workspace); diff --git a/src/core/stack.h b/src/core/stack.h index c407a2ba80a..00d1cfe543c 100644 --- a/src/core/stack.h +++ b/src/core/stack.h @@ -56,35 +56,9 @@ struct _MetaStack /** The MetaDisplay containing this stack. */ MetaDisplay *display; - /** - * A sequence of all the Windows (X handles, not MetaWindows) of the windows - * we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST. - */ - GArray *xwindows; - /** The MetaWindows of the windows we manage, sorted in order. */ GList *sorted; - /** - * MetaWindows waiting to be added to the "sorted" and "windows" list, after - * being added by meta_stack_add() and before being assimilated by - * stack_ensure_sorted(). - * - * The order of the elements in this list is not important; what is important - * is the stack_position element of each window. - */ - GList *added; - - /** - * Windows (X handles, not MetaWindows) waiting to be removed from the - * "windows" list, after being removed by meta_stack_remove() and before - * being assimilated by stack_ensure_sorted(). (We already removed them - * from the "sorted" list.) - * - * The order of the elements in this list is not important. - */ - GList *removed; - /** * If this is zero, the local stack oughtn't to be brought up to date with * the X server's stack, because it is in the middle of being updated. diff --git a/src/meson.build b/src/meson.build index 0a1262fe99a..5007b5cab4b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -392,6 +392,8 @@ mutter_sources = [ 'x11/meta-x11-selection-input-stream-private.h', 'x11/meta-x11-selection-output-stream.c', 'x11/meta-x11-selection-output-stream-private.h', + 'x11/meta-x11-stack.c', + 'x11/meta-x11-stack-private.h', 'x11/mutter-Xatomtype.h', 'x11/session.c', 'x11/session.h', diff --git a/src/x11/meta-x11-display-private.h b/src/x11/meta-x11-display-private.h index c7af182d9f0..d19cdd6881b 100644 --- a/src/x11/meta-x11-display-private.h +++ b/src/x11/meta-x11-display-private.h @@ -35,6 +35,7 @@ #include "meta/types.h" #include "meta/meta-x11-display.h" #include "meta-startup-notification-x11.h" +#include "meta-x11-stack-private.h" #include "ui/ui.h" typedef struct _MetaGroupPropHooks MetaGroupPropHooks; @@ -167,6 +168,7 @@ struct _MetaX11Display #define META_X11_DISPLAY_HAS_XINPUT_23(x11_display) ((x11_display)->have_xinput_23) MetaX11StartupNotification *startup_notification; + MetaX11Stack *x11_stack; }; MetaX11Display *meta_x11_display_new (MetaDisplay *display, GError **error); diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c index 2aece19a836..98c4e3e437d 100644 --- a/src/x11/meta-x11-display.c +++ b/src/x11/meta-x11-display.c @@ -108,6 +108,8 @@ meta_x11_display_dispose (GObject *object) meta_x11_selection_shutdown (x11_display); + g_clear_object (&x11_display->x11_stack); + if (x11_display->ui) { meta_ui_free (x11_display->ui); @@ -1270,6 +1272,7 @@ meta_x11_display_new (MetaDisplay *display, GError **error) set_desktop_geometry_hint (x11_display); x11_display->ui = meta_ui_new (x11_display); + x11_display->x11_stack = meta_x11_stack_new (x11_display); x11_display->keys_grabbed = FALSE; meta_x11_display_grab_keys (x11_display); diff --git a/src/x11/meta-x11-stack-private.h b/src/x11/meta-x11-stack-private.h new file mode 100644 index 00000000000..a00b8e7430f --- /dev/null +++ b/src/x11/meta-x11-stack-private.h @@ -0,0 +1,33 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2019 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef META_X11_STACK_H +#define META_X11_STACK_H + +#include + +#include "meta/types.h" + +#define META_TYPE_X11_STACK (meta_x11_stack_get_type ()) +G_DECLARE_FINAL_TYPE (MetaX11Stack, meta_x11_stack, META, X11_STACK, GObject) + +typedef struct _MetaX11Stack MetaX11Stack; + +MetaX11Stack * meta_x11_stack_new (MetaX11Display *x11_display); + +#endif /* META_X11_STACK_H */ diff --git a/src/x11/meta-x11-stack.c b/src/x11/meta-x11-stack.c new file mode 100644 index 00000000000..fa08fc4c5bc --- /dev/null +++ b/src/x11/meta-x11-stack.c @@ -0,0 +1,413 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2019 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "config.h" + +#include "core/frame.h" +#include "core/stack.h" +#include "core/window-private.h" +#include "x11/meta-x11-display-private.h" +#include "x11/meta-x11-stack-private.h" + +struct _MetaX11Stack +{ + GObject parent; + MetaX11Display *x11_display; + + /* + * A sequence of all the Windows (X handles, not MetaWindows) of the windows + * we manage, sorted in order. Suitable to be passed into _NET_CLIENT_LIST. + */ + GArray *xwindows; + + /* + * MetaWindows waiting to be added to the xwindows list, after + * being added to the MetaStack. + * + * The order of the elements in this list is not important; what is important + * is the stack_position element of each window. + */ + GList *added; + + /* + * Windows (X handles, not MetaWindows) waiting to be removed from the + * xwindows list, after being removed from the MetaStack. + * + * The order of the elements in this list is not important. + */ + GList *removed; +}; + +enum +{ + PROP_DISPLAY = 1, + N_PROPS +}; + +static GParamSpec *pspecs[N_PROPS] = { 0 }; + +G_DEFINE_TYPE (MetaX11Stack, meta_x11_stack, G_TYPE_OBJECT) + +static void +meta_x11_stack_init (MetaX11Stack *x11_stack) +{ + x11_stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window)); +} + +static void +meta_x11_stack_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaX11Stack *x11_stack = META_X11_STACK (object); + + switch (prop_id) + { + case PROP_DISPLAY: + x11_stack->x11_display = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_x11_stack_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaX11Stack *x11_stack = META_X11_STACK (object); + + switch (prop_id) + { + case PROP_DISPLAY: + g_value_set_object (value, x11_stack->x11_display); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +stack_window_added_cb (MetaStack *stack, + MetaWindow *window, + MetaX11Stack *x11_stack) +{ + if (window->client_type != META_WINDOW_CLIENT_TYPE_X11) + return; + + x11_stack->added = g_list_prepend (x11_stack->added, window); +} + +static void +stack_window_removed_cb (MetaStack *stack, + MetaWindow *window, + MetaX11Stack *x11_stack) +{ + if (window->client_type != META_WINDOW_CLIENT_TYPE_X11) + return; + + x11_stack->added = g_list_remove (x11_stack->added, window); + + x11_stack->removed = g_list_prepend (x11_stack->removed, + GUINT_TO_POINTER (window->xwindow)); + if (window->frame) + { + x11_stack->removed = g_list_prepend (x11_stack->removed, + GUINT_TO_POINTER (window->frame->xwindow)); + } +} + +/** + * stack_do_window_deletions: + * + * Go through "deleted" and take the matching windows + * out of "windows". + */ +static void +x11_stack_do_window_deletions (MetaX11Stack *x11_stack) +{ + GList *tmp; + int i; + + tmp = x11_stack->removed; + while (tmp != NULL) + { + Window xwindow; + xwindow = GPOINTER_TO_UINT (tmp->data); + + /* We go from the end figuring removals are more + * likely to be recent. + */ + i = x11_stack->xwindows->len; + while (i > 0) + { + --i; + + /* there's no guarantee we'll actually find windows to + * remove, e.g. the same xwindow could have been + * added/removed before we ever synced, and we put + * both the window->xwindow and window->frame->xwindow + * in the removal list. + */ + if (xwindow == g_array_index (x11_stack->xwindows, Window, i)) + { + g_array_remove_index (x11_stack->xwindows, i); + goto next; + } + } + + next: + tmp = tmp->next; + } + + g_clear_pointer (&x11_stack->removed, g_list_free); +} + +static void +x11_stack_do_window_additions (MetaX11Stack *x11_stack) +{ + GList *tmp; + gint n_added; + + n_added = g_list_length (x11_stack->added); + if (n_added > 0) + { + meta_topic (META_DEBUG_STACK, + "Adding %d windows to sorted list\n", + n_added); + + /* stack->added has the most recent additions at the + * front of the list, so we need to reverse it + */ + x11_stack->added = g_list_reverse (x11_stack->added); + + tmp = x11_stack->added; + while (tmp != NULL) + { + MetaWindow *w; + + w = tmp->data; + g_array_append_val (x11_stack->xwindows, w->xwindow); + tmp = tmp->next; + } + } + + g_clear_pointer (&x11_stack->added, g_list_free); +} + +/** + * x11_stack_sync_to_server: + * + * Order the windows on the X server to be the same as in our structure. + * We do this using XRestackWindows if we don't know the previous order, + * or XConfigureWindow on a few particular windows if we do and can figure + * out the minimum set of changes. After that, we set __NET_CLIENT_LIST + * and __NET_CLIENT_LIST_STACKING. + * + * FIXME: Now that we have a good view of the stacking order on the server + * with MetaStackTracker it should be possible to do a simpler and better + * job of computing the minimal set of stacking requests needed. + */ +static void +x11_stack_sync_to_xserver (MetaX11Stack *x11_stack) +{ + MetaX11Display *x11_display = x11_stack->x11_display; + MetaStack *stack = x11_display->display->stack; + GArray *x11_stacked; + GArray *all_root_children_stacked; /* wayland OR x11 */ + GList *tmp; + GArray *hidden_stack_ids; + uint64_t guard_window_id; + GList *sorted; + + meta_topic (META_DEBUG_STACK, "Syncing window stack to server\n"); + + /* Create stacked xwindow arrays, in bottom-to-top order + */ + x11_stacked = g_array_new (FALSE, FALSE, sizeof (Window)); + + all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (guint64)); + hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (guint64)); + + meta_topic (META_DEBUG_STACK, "Bottom to top: "); + meta_push_no_msg_prefix (); + + sorted = meta_stack_list_windows (stack, NULL); + + for (tmp = sorted; tmp; tmp = tmp->next) + { + MetaWindow *w = tmp->data; + guint64 top_level_window; + guint64 stack_id; + + if (w->unmanaging) + continue; + + meta_topic (META_DEBUG_STACK, "%u:%d - %s ", + w->layer, w->stack_position, w->desc); + + if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) + g_array_append_val (x11_stacked, w->xwindow); + + if (w->frame) + top_level_window = w->frame->xwindow; + else + top_level_window = w->xwindow; + + if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) + stack_id = top_level_window; + else + stack_id = w->stamp; + + /* We don't restack hidden windows along with the rest, though they are + * reflected in the _NET hints. Hidden windows all get pushed below + * the screens fullscreen guard_window. */ + if (w->hidden) + { + g_array_append_val (hidden_stack_ids, stack_id); + continue; + } + + g_array_append_val (all_root_children_stacked, stack_id); + } + + meta_topic (META_DEBUG_STACK, "\n"); + meta_pop_no_msg_prefix (); + + /* The screen guard window sits above all hidden windows and acts as + * a barrier to input reaching these windows. */ + guard_window_id = x11_stack->x11_display->guard_window; + g_array_append_val (hidden_stack_ids, guard_window_id); + + /* Sync to server */ + + meta_topic (META_DEBUG_STACK, "Restacking %u windows\n", + all_root_children_stacked->len); + + meta_stack_tracker_restack_managed (x11_display->display->stack_tracker, + (guint64 *)all_root_children_stacked->data, + all_root_children_stacked->len); + meta_stack_tracker_restack_at_bottom (x11_display->display->stack_tracker, + (guint64 *)hidden_stack_ids->data, + hidden_stack_ids->len); + + /* Sync _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING */ + + XChangeProperty (x11_stack->x11_display->xdisplay, + x11_stack->x11_display->xroot, + x11_stack->x11_display->atom__NET_CLIENT_LIST, + XA_WINDOW, + 32, PropModeReplace, + (unsigned char *) x11_stack->xwindows->data, + x11_stack->xwindows->len); + XChangeProperty (x11_stack->x11_display->xdisplay, + x11_stack->x11_display->xroot, + x11_stack->x11_display->atom__NET_CLIENT_LIST_STACKING, + XA_WINDOW, + 32, PropModeReplace, + (unsigned char *) x11_stacked->data, + x11_stacked->len); + + g_array_free (x11_stacked, TRUE); + g_array_free (hidden_stack_ids, TRUE); + g_array_free (all_root_children_stacked, TRUE); + g_list_free (sorted); +} + +static void +stack_changed_cb (MetaX11Stack *x11_stack) +{ + /* Do removals before adds, with paranoid idea that we might re-add + * the same window IDs. + */ + x11_stack_do_window_deletions (x11_stack); + x11_stack_do_window_additions (x11_stack); + x11_stack_sync_to_xserver (x11_stack); +} + +static void +meta_x11_stack_constructed (GObject *object) +{ + MetaX11Stack *x11_stack = META_X11_STACK (object); + MetaX11Display *x11_display = x11_stack->x11_display; + + G_OBJECT_CLASS (meta_x11_stack_parent_class)->constructed (object); + + g_signal_connect (x11_display->display->stack, + "window-added", + G_CALLBACK (stack_window_added_cb), + x11_stack); + g_signal_connect (x11_display->display->stack, + "window-removed", + G_CALLBACK (stack_window_removed_cb), + x11_stack); + g_signal_connect_swapped (x11_display->display->stack, + "changed", + G_CALLBACK (stack_changed_cb), + x11_stack); +} + +static void +meta_x11_stack_finalize (GObject *object) +{ + MetaX11Stack *x11_stack = META_X11_STACK (object); + MetaX11Display *x11_display = x11_stack->x11_display; + + if (x11_display->display && x11_display->display->stack) + { + g_signal_handlers_disconnect_by_data (x11_display->display->stack, + x11_stack); + } + + g_array_free (x11_stack->xwindows, TRUE); + g_list_free (x11_stack->added); + g_list_free (x11_stack->removed); + + G_OBJECT_CLASS (meta_x11_stack_parent_class)->finalize (object); +} + +static void +meta_x11_stack_class_init (MetaX11StackClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = meta_x11_stack_set_property; + object_class->get_property = meta_x11_stack_get_property; + object_class->constructed = meta_x11_stack_constructed; + object_class->finalize = meta_x11_stack_finalize; + + pspecs[PROP_DISPLAY] = + g_param_spec_object ("display", + "Display", + "Display", + META_TYPE_X11_DISPLAY, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, N_PROPS, pspecs); +} + +MetaX11Stack * +meta_x11_stack_new (MetaX11Display *x11_display) +{ + return g_object_new (META_TYPE_X11_STACK, + "display", x11_display, + NULL); +} -- GitLab From 103c469cc90fbee9c5eb437b9ebcb621ced9412c Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 30 Dec 2018 13:15:36 +0100 Subject: [PATCH 04/16] core: Avoid grab transfer shenanigans with non-X11 backend This explicit ungrab is made to ensure the other X11 display connection is able to start an active grab immediately on the device without receiving AlreadyGrabbed. This is just relevant if there's two X11 display connections to transfer grabs across, which may just happen on X11 windowing. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/core/display.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/core/display.c b/src/core/display.c index d36aaad8bf3..754d5a2e9c0 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -1677,14 +1677,17 @@ meta_display_begin_grab_op (MetaDisplay *display, if (pointer_already_grabbed) display->grab_have_pointer = TRUE; - /* Since grab operations often happen as a result of implicit - * pointer operations on the display X11 connection, we need - * to ungrab here to ensure that the backend's X11 can take - * the device grab. */ - XIUngrabDevice (display->x11_display->xdisplay, - META_VIRTUAL_CORE_POINTER_ID, - timestamp); - XSync (display->x11_display->xdisplay, False); + if (META_IS_BACKEND_X11 (meta_get_backend ()) && display->x11_display) + { + /* Since grab operations often happen as a result of implicit + * pointer operations on the display X11 connection, we need + * to ungrab here to ensure that the backend's X11 can take + * the device grab. */ + XIUngrabDevice (display->x11_display->xdisplay, + META_VIRTUAL_CORE_POINTER_ID, + timestamp); + XSync (display->x11_display->xdisplay, False); + } if (meta_backend_grab_device (backend, META_VIRTUAL_CORE_POINTER_ID, timestamp)) display->grab_have_pointer = TRUE; -- GitLab From dbe6e01e12e26464d999e498eb8d894bf176ed5f Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 30 Dec 2018 13:34:06 +0100 Subject: [PATCH 05/16] core: Separate checks for pointer barriers availability If the check happens on --nested (X11 backend) while there is no X11 display we would get a crash. Since the barriers are non-effective on nested, just take it out into a separate condition. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/core/display.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core/display.c b/src/core/display.c index 754d5a2e9c0..a9659fe9c11 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -49,6 +49,7 @@ #include "backends/meta-logical-monitor.h" #include "backends/meta-stage-private.h" #include "backends/x11/meta-backend-x11.h" +#include "backends/x11/cm/meta-backend-x11-cm.h" #include "clutter/x11/clutter-x11.h" #include "core/bell.h" #include "core/boxes-private.h" @@ -2597,13 +2598,14 @@ meta_display_supports_extended_barriers (MetaDisplay *display) return TRUE; #endif - if (META_IS_BACKEND_X11 (meta_get_backend ())) + if (META_IS_BACKEND_X11_CM (meta_get_backend ())) { - return (META_X11_DISPLAY_HAS_XINPUT_23 (display->x11_display) && - !meta_is_wayland_compositor()); + if (meta_is_wayland_compositor()) + return FALSE; + + return META_X11_DISPLAY_HAS_XINPUT_23 (display->x11_display); } - g_assert_not_reached (); return FALSE; } -- GitLab From 5e0523cc8bbcc639a48071d4021716319e356582 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 30 Dec 2018 13:55:52 +0100 Subject: [PATCH 06/16] x11: Move X11 calls to map/unmap a MetaWindow to MetaWindowX11 Add 2 vmethods so that MetaWindowX11 may handle the X11 calls itself. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/core/window-private.h | 3 +++ src/core/window.c | 13 +++---------- src/wayland/meta-window-wayland.c | 12 ++++++++++++ src/x11/window-x11.c | 23 +++++++++++++++++++++++ 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/core/window-private.h b/src/core/window-private.h index 06be5aad82f..eb497659f18 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -581,6 +581,9 @@ struct _MetaWindowClass gboolean (*is_stackable) (MetaWindow *window); gboolean (*can_ping) (MetaWindow *window); gboolean (*are_updates_frozen) (MetaWindow *window); + + void (* map) (MetaWindow *window); + void (* unmap) (MetaWindow *window); }; /* These differ from window->has_foo_func in that they consider diff --git a/src/core/window.c b/src/core/window.c index c37afa36b79..abd56bfe9a3 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -809,17 +809,10 @@ sync_client_window_mapped (MetaWindow *window) window->mapped = should_be_mapped; - meta_x11_error_trap_push (window->display->x11_display); - if (should_be_mapped) - { - XMapWindow (window->display->x11_display->xdisplay, window->xwindow); - } + if (window->mapped) + META_WINDOW_GET_CLASS (window)->map (window); else - { - XUnmapWindow (window->display->x11_display->xdisplay, window->xwindow); - window->unmaps_pending ++; - } - meta_x11_error_trap_pop (window->display->x11_display); + META_WINDOW_GET_CLASS (window)->unmap (window); } static gboolean diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c index c7c3785d8ec..0b0f6bb6618 100644 --- a/src/wayland/meta-window-wayland.c +++ b/src/wayland/meta-window-wayland.c @@ -611,6 +611,16 @@ meta_window_wayland_are_updates_frozen (MetaWindow *window) return !wl_window->has_been_shown; } +static void +meta_window_wayland_map (MetaWindow *window) +{ +} + +static void +meta_window_wayland_unmap (MetaWindow *window) +{ +} + static void meta_window_wayland_class_init (MetaWindowWaylandClass *klass) { @@ -634,6 +644,8 @@ meta_window_wayland_class_init (MetaWindowWaylandClass *klass) window_class->is_stackable = meta_window_wayland_is_stackable; window_class->can_ping = meta_window_wayland_can_ping; window_class->are_updates_frozen = meta_window_wayland_are_updates_frozen; + window_class->map = meta_window_wayland_map; + window_class->unmap = meta_window_wayland_unmap; } MetaWindow * diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c index edb378ae9ca..fd19766bb4f 100644 --- a/src/x11/window-x11.c +++ b/src/x11/window-x11.c @@ -1706,6 +1706,27 @@ meta_window_x11_are_updates_frozen (MetaWindow *window) return FALSE; } +static void +meta_window_x11_map (MetaWindow *window) +{ + MetaX11Display *x11_display = window->display->x11_display; + + meta_x11_error_trap_push (x11_display); + XMapWindow (x11_display->xdisplay, window->xwindow); + meta_x11_error_trap_pop (x11_display); +} + +static void +meta_window_x11_unmap (MetaWindow *window) +{ + MetaX11Display *x11_display = window->display->x11_display; + + meta_x11_error_trap_push (x11_display); + XUnmapWindow (x11_display->xdisplay, window->xwindow); + meta_x11_error_trap_pop (x11_display); + window->unmaps_pending ++; +} + static void meta_window_x11_class_init (MetaWindowX11Class *klass) { @@ -1733,6 +1754,8 @@ meta_window_x11_class_init (MetaWindowX11Class *klass) window_class->is_stackable = meta_window_x11_is_stackable; window_class->can_ping = meta_window_x11_can_ping; window_class->are_updates_frozen = meta_window_x11_are_updates_frozen; + window_class->map = meta_window_x11_map; + window_class->unmap = meta_window_x11_unmap; } void -- GitLab From 2f217109aabb097a66c2b963467990d2d92f9c40 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 30 Dec 2018 14:18:09 +0100 Subject: [PATCH 07/16] core: Relax requirement that MetaWindow shall have icon/mini-icon We use a GtkIconTheme (thus icon-theme, thus xsettings, thus x11) just to grab a "missing icon" icon to show in place. Relax this requirement that surfaces for icon/mini-icon will be set, and just let it have NULL here. It seems better to have the callers (presumably UI layers) aware of this and set a proper icon by themselves, but AFAICS there is none in sight, not even plain mutter seems to use MetaWindow::[mini-]icon. Probably worth a future cleanup. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/core/window.c | 57 ++--------------------------------------------- 1 file changed, 2 insertions(+), 55 deletions(-) diff --git a/src/core/window.c b/src/core/window.c index abd56bfe9a3..5721dadf1af 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -5373,50 +5373,6 @@ redraw_icon (MetaWindow *window) meta_frame_queue_draw (window->frame); } -static cairo_surface_t * -load_default_window_icon (int size) -{ - GtkIconTheme *theme = gtk_icon_theme_get_default (); - g_autoptr (GdkPixbuf) pixbuf = NULL; - const char *icon_name; - - if (gtk_icon_theme_has_icon (theme, META_DEFAULT_ICON_NAME)) - icon_name = META_DEFAULT_ICON_NAME; - else - icon_name = "image-missing"; - - pixbuf = gtk_icon_theme_load_icon (theme, icon_name, size, 0, NULL); - return gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL); -} - -static cairo_surface_t * -get_default_window_icon (void) -{ - static cairo_surface_t *default_icon = NULL; - - if (default_icon == NULL) - { - default_icon = load_default_window_icon (META_ICON_WIDTH); - g_assert (default_icon); - } - - return cairo_surface_reference (default_icon); -} - -static cairo_surface_t * -get_default_mini_icon (void) -{ - static cairo_surface_t *default_icon = NULL; - - if (default_icon == NULL) - { - default_icon = load_default_window_icon (META_MINI_ICON_WIDTH); - g_assert (default_icon); - } - - return cairo_surface_reference (default_icon); -} - static void meta_window_update_icon_now (MetaWindow *window, gboolean force) @@ -5433,17 +5389,11 @@ meta_window_update_icon_now (MetaWindow *window, { if (window->icon) cairo_surface_destroy (window->icon); - if (icon) - window->icon = icon; - else - window->icon = get_default_window_icon (); + window->icon = icon; if (window->mini_icon) cairo_surface_destroy (window->mini_icon); - if (mini_icon) - window->mini_icon = mini_icon; - else - window->mini_icon = get_default_mini_icon (); + window->mini_icon = mini_icon; g_object_freeze_notify (G_OBJECT (window)); g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_ICON]); @@ -5452,9 +5402,6 @@ meta_window_update_icon_now (MetaWindow *window, redraw_icon (window); } - - g_assert (window->icon); - g_assert (window->mini_icon); } static gboolean -- GitLab From 1d77641f0b00f7159168c18250c36ff7710f7954 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 30 Dec 2018 18:25:08 +0100 Subject: [PATCH 08/16] x11: Separate X11 focus handling into MetaX11Display method Updating the MetaWindow focus and the X Window focus is interrelated but independent. Call one after the other in the places we handle window focus changes. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/core/display-private.h | 13 +------------ src/core/display.c | 20 +++++--------------- src/x11/events.c | 24 +++++++++++++----------- src/x11/meta-x11-display-private.h | 13 +++++++++++++ src/x11/meta-x11-display.c | 23 ++++++++++++++++++----- 5 files changed, 50 insertions(+), 43 deletions(-) diff --git a/src/core/display-private.h b/src/core/display-private.h index ea683a39acb..be2f4443342 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -140,14 +140,6 @@ struct _MetaDisplay */ guint allow_terminal_deactivation : 1; - /* If true, server->focus_serial refers to us changing the focus; in - * this case, we can ignore focus events that have exactly focus_serial, - * since we take care to make another request immediately afterwards. - * But if focus is being changed by another client, we have to accept - * multiple events with the same serial. - */ - guint focused_by_us : 1; - /*< private-ish >*/ GHashTable *stamps; GHashTable *wayland_windows; @@ -371,10 +363,7 @@ gboolean meta_display_modifiers_accelerator_activate (MetaDisplay *display); void meta_display_sync_wayland_input_focus (MetaDisplay *display); void meta_display_update_focus_window (MetaDisplay *display, - MetaWindow *window, - Window xwindow, - gulong serial, - gboolean focused_by_us); + MetaWindow *window); void meta_display_sanity_check_timestamps (MetaDisplay *display, guint32 timestamp); diff --git a/src/core/display.c b/src/core/display.c index a9659fe9c11..413b62a0478 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -1238,16 +1238,9 @@ meta_display_sync_wayland_input_focus (MetaDisplay *display) void meta_display_update_focus_window (MetaDisplay *display, - MetaWindow *window, - Window xwindow, - gulong serial, - gboolean focused_by_us) + MetaWindow *window) { - display->x11_display->focus_serial = serial; - display->focused_by_us = focused_by_us; - - if (display->x11_display->focus_xwindow == xwindow && - display->focus_window == window) + if (display->focus_window == window) return; if (display->focus_window) @@ -1264,28 +1257,25 @@ meta_display_update_focus_window (MetaDisplay *display, */ previous = display->focus_window; display->focus_window = NULL; - display->x11_display->focus_xwindow = None; meta_window_set_focused_internal (previous, FALSE); } display->focus_window = window; - display->x11_display->focus_xwindow = xwindow; if (display->focus_window) { - meta_topic (META_DEBUG_FOCUS, "* Focus --> %s with serial %lu\n", - display->focus_window->desc, serial); + meta_topic (META_DEBUG_FOCUS, "* Focus --> %s\n", + display->focus_window->desc); meta_window_set_focused_internal (display->focus_window, TRUE); } else - meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL with serial %lu\n", serial); + meta_topic (META_DEBUG_FOCUS, "* Focus --> NULL\n"); if (meta_is_wayland_compositor ()) meta_display_sync_wayland_input_focus (display); g_object_notify (G_OBJECT (display), "focus-window"); - meta_x11_display_update_active_window_hint (display->x11_display); } gboolean diff --git a/src/x11/events.c b/src/x11/events.c index 5fdff162c13..02c8509dc5b 100644 --- a/src/x11/events.c +++ b/src/x11/events.c @@ -803,14 +803,15 @@ handle_window_focus_event (MetaX11Display *x11_display, * multiple focus events with the same serial. */ if (x11_display->server_focus_serial > x11_display->focus_serial || - (!display->focused_by_us && + (!x11_display->focused_by_us && x11_display->server_focus_serial == x11_display->focus_serial)) { - meta_display_update_focus_window (display, - focus_window, - focus_window ? focus_window->xwindow : None, - x11_display->server_focus_serial, - FALSE); + meta_display_update_focus_window (display, focus_window); + meta_x11_display_update_focus_window (x11_display, + focus_window ? + focus_window->xwindow : None, + x11_display->server_focus_serial, + FALSE); return TRUE; } else @@ -1792,7 +1793,7 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display, if (META_IS_BACKEND_X11 (backend)) meta_backend_x11_handle_event (META_BACKEND_X11 (backend), event); - if (display->focused_by_us && + if (x11_display->focused_by_us && event->xany.serial > x11_display->focus_serial && display->focus_window && !window_has_xwindow (display->focus_window, x11_display->server_focus_window)) @@ -1801,10 +1802,11 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display, display->focus_window->desc); meta_display_update_focus_window (display, meta_x11_display_lookup_x_window (x11_display, - x11_display->server_focus_window), - x11_display->server_focus_window, - x11_display->server_focus_serial, - FALSE); + x11_display->server_focus_window)); + meta_x11_display_update_focus_window (x11_display, + x11_display->server_focus_window, + x11_display->server_focus_serial, + FALSE); } if (event->xany.window == x11_display->xroot) diff --git a/src/x11/meta-x11-display-private.h b/src/x11/meta-x11-display-private.h index d19cdd6881b..0a6cafda0ff 100644 --- a/src/x11/meta-x11-display-private.h +++ b/src/x11/meta-x11-display-private.h @@ -134,6 +134,14 @@ struct _MetaX11Display GList *output_streams; } selection; + /* If true, server->focus_serial refers to us changing the focus; in + * this case, we can ignore focus events that have exactly focus_serial, + * since we take care to make another request immediately afterwards. + * But if focus is being changed by another client, we have to accept + * multiple events with the same serial. + */ + guint focused_by_us : 1; + guint keys_grabbed : 1; /* we use property updates as sentinels for certain window focus events @@ -233,4 +241,9 @@ void meta_x11_display_increment_focus_sentinel (MetaX11Display *x11_display); void meta_x11_display_decrement_focus_sentinel (MetaX11Display *x11_display); gboolean meta_x11_display_focus_sentinel_clear (MetaX11Display *x11_display); +void meta_x11_display_update_focus_window (MetaX11Display *x11_display, + Window xwindow, + gulong serial, + gboolean focused_by_us); + #endif /* META_X11_DISPLAY_PRIVATE_H */ diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c index 98c4e3e437d..4711ca0aae7 100644 --- a/src/x11/meta-x11-display.c +++ b/src/x11/meta-x11-display.c @@ -1822,6 +1822,22 @@ meta_x11_display_update_active_window_hint (MetaX11Display *x11_display) meta_x11_error_trap_pop (x11_display); } +void +meta_x11_display_update_focus_window (MetaX11Display *x11_display, + Window xwindow, + gulong serial, + gboolean focused_by_us) +{ + x11_display->focus_serial = serial; + x11_display->focused_by_us = !!focused_by_us; + + if (x11_display->focus_xwindow == xwindow) + return; + + x11_display->focus_xwindow = xwindow; + meta_x11_display_update_active_window_hint (x11_display); +} + static void request_xserver_input_focus_change (MetaX11Display *x11_display, MetaWindow *meta_window, @@ -1860,11 +1876,8 @@ request_xserver_input_focus_change (MetaX11Display *x11_display, XUngrabServer (x11_display->xdisplay); XFlush (x11_display->xdisplay); - meta_display_update_focus_window (x11_display->display, - meta_window, - xwindow, - serial, - TRUE); + meta_display_update_focus_window (x11_display->display, meta_window); + meta_x11_display_update_focus_window (x11_display, xwindow, serial, TRUE); meta_x11_error_trap_pop (x11_display); -- GitLab From 86de79cfc5a9cca30f18d04e9b408882d2d04856 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 30 Dec 2018 21:23:07 +0100 Subject: [PATCH 09/16] core: Untangle input focus management In all places (including src/wayland) we tap into meta_x11_display* focus API, which then calls meta_display* API. This relation is backwards, so rework input focus management so it's the other way around. We now have high-level meta_display_(un)set_input_focus functions, which perform the backend-independent maintenance, and calls into the X11 functions where relevant. These functions are what callers should use. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/core/display.c | 53 +++++++++++++++++++++++++++-- src/core/window.c | 3 +- src/core/workspace.c | 6 ++-- src/meta/display.h | 9 +++++ src/meta/meta-x11-display.h | 23 ------------- src/wayland/meta-window-wayland.c | 10 +++--- src/x11/meta-x11-display-private.h | 3 ++ src/x11/meta-x11-display.c | 54 +++++------------------------- src/x11/window-x11.c | 19 +++++------ 9 files changed, 89 insertions(+), 91 deletions(-) diff --git a/src/core/display.c b/src/core/display.c index 413b62a0478..01e97dafd67 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -779,10 +779,12 @@ meta_display_open (void) if (old_active_window) meta_window_focus (old_active_window, timestamp); else - meta_x11_display_focus_the_no_focus_window (display->x11_display, timestamp); + meta_display_unset_input_focus (display, timestamp); + } + else + { + meta_display_unset_input_focus (display, timestamp); } - else if (display->x11_display) - meta_x11_display_focus_the_no_focus_window (display->x11_display, timestamp); meta_idle_monitor_init_dbus (); @@ -1307,6 +1309,51 @@ meta_display_timestamp_too_old (MetaDisplay *display, return FALSE; } +void +meta_display_set_input_focus (MetaDisplay *display, + MetaWindow *window, + gboolean focus_frame, + guint32 timestamp) +{ + if (meta_display_timestamp_too_old (display, ×tamp)) + return; + + if (display->x11_display) + { + MetaX11Display *x11_display = display->x11_display; + Window xwindow; + gulong serial; + + meta_x11_error_trap_push (x11_display); + + if (window) + xwindow = focus_frame ? window->frame->xwindow : window->xwindow; + else + xwindow = x11_display->no_focus_window; + + meta_x11_display_set_input_focus (x11_display, xwindow, timestamp); + serial = XNextRequest (x11_display->xdisplay); + + meta_x11_display_update_focus_window (x11_display, xwindow, serial, TRUE); + + meta_x11_error_trap_pop (display->x11_display); + } + + meta_display_update_focus_window (display, window); + + display->last_focus_time = timestamp; + + if (window == NULL || window != display->autoraise_window) + meta_display_remove_autoraise_callback (display); +} + +void +meta_display_unset_input_focus (MetaDisplay *display, + guint32 timestamp) +{ + meta_display_set_input_focus (display, NULL, FALSE, timestamp); +} + void meta_display_register_wayland_window (MetaDisplay *display, MetaWindow *window) diff --git a/src/core/window.c b/src/core/window.c index 5721dadf1af..caa1059e383 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -8088,8 +8088,7 @@ mouse_mode_focus (MetaWindow *window, "Unsetting focus from %s due to mouse entering " "the DESKTOP window\n", display->focus_window->desc); - meta_x11_display_focus_the_no_focus_window (display->x11_display, - timestamp); + meta_display_unset_input_focus (display, timestamp); } } } diff --git a/src/core/workspace.c b/src/core/workspace.c index b4fd836c9a7..71c54d229c9 100644 --- a/src/core/workspace.c +++ b/src/core/workspace.c @@ -1308,8 +1308,7 @@ meta_workspace_focus_default_window (MetaWorkspace *workspace, meta_topic (META_DEBUG_FOCUS, "Setting focus to no_focus_window, since no valid " "window to focus found.\n"); - meta_x11_display_focus_the_no_focus_window (workspace->display->x11_display, - timestamp); + meta_display_unset_input_focus (workspace->display, timestamp); } } } @@ -1381,8 +1380,7 @@ focus_ancestor_or_top_window (MetaWorkspace *workspace, else { meta_topic (META_DEBUG_FOCUS, "No MRU window to focus found; focusing no_focus_window.\n"); - meta_x11_display_focus_the_no_focus_window (workspace->display->x11_display, - timestamp); + meta_display_unset_input_focus (workspace->display, timestamp); } } diff --git a/src/meta/display.h b/src/meta/display.h index 09c1f99ecf6..5cf99cfead2 100644 --- a/src/meta/display.h +++ b/src/meta/display.h @@ -297,4 +297,13 @@ MetaSoundPlayer * meta_display_get_sound_player (MetaDisplay *display); META_EXPORT MetaSelection * meta_display_get_selection (MetaDisplay *display); +META_EXPORT +void meta_display_set_input_focus (MetaDisplay *display, + MetaWindow *window, + gboolean focus_frame, + guint32 timestamp); +META_EXPORT +void meta_display_unset_input_focus (MetaDisplay *display, + guint32 timestamp); + #endif diff --git a/src/meta/meta-x11-display.h b/src/meta/meta-x11-display.h index f5167af7d2b..9c9adf9b7f0 100644 --- a/src/meta/meta-x11-display.h +++ b/src/meta/meta-x11-display.h @@ -63,27 +63,4 @@ META_EXPORT gboolean meta_x11_display_xwindow_is_a_no_focus_window (MetaX11Display *x11_display, Window xwindow); -/* meta_x11_display_set_input_focus_window is like XSetInputFocus, except - * that (a) it can't detect timestamps later than the current time, - * since Mutter isn't part of the XServer, and thus gives erroneous - * behavior in this circumstance (so don't do it), (b) it uses - * display->last_focus_time since we don't have access to the true - * Xserver one, (c) it makes use of display->user_time since checking - * whether a window should be allowed to be focused should depend - * on user_time events (see bug 167358, comment 15 in particular) - */ -META_EXPORT -void meta_x11_display_set_input_focus_window (MetaX11Display *x11_display, - MetaWindow *window, - gboolean focus_frame, - guint32 timestamp); - -/* meta_x11_display_focus_the_no_focus_window is called when the - * designated no_focus_window should be focused, but is otherwise the - * same as meta_display_set_input_focus_window - */ -META_EXPORT -void meta_x11_display_focus_the_no_focus_window (MetaX11Display *x11_display, - guint32 timestamp); - #endif /* META_X11_DISPLAY_H */ diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c index 0b0f6bb6618..8191adadd21 100644 --- a/src/wayland/meta-window-wayland.c +++ b/src/wayland/meta-window-wayland.c @@ -142,10 +142,12 @@ meta_window_wayland_focus (MetaWindow *window, guint32 timestamp) { if (meta_window_is_focusable (window)) - meta_x11_display_set_input_focus_window (window->display->x11_display, - window, - FALSE, - timestamp); + { + meta_display_set_input_focus (window->display, + window, + FALSE, + timestamp); + } } static void diff --git a/src/x11/meta-x11-display-private.h b/src/x11/meta-x11-display-private.h index 0a6cafda0ff..3f545ce2833 100644 --- a/src/x11/meta-x11-display-private.h +++ b/src/x11/meta-x11-display-private.h @@ -245,5 +245,8 @@ void meta_x11_display_update_focus_window (MetaX11Display *x11_display, Window xwindow, gulong serial, gboolean focused_by_us); +void meta_x11_display_set_input_focus (MetaX11Display *x11_display, + Window xwindow, + guint32 timestamp); #endif /* META_X11_DISPLAY_PRIVATE_H */ diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c index 4711ca0aae7..f7e0c2f5676 100644 --- a/src/x11/meta-x11-display.c +++ b/src/x11/meta-x11-display.c @@ -1838,17 +1838,11 @@ meta_x11_display_update_focus_window (MetaX11Display *x11_display, meta_x11_display_update_active_window_hint (x11_display); } -static void -request_xserver_input_focus_change (MetaX11Display *x11_display, - MetaWindow *meta_window, - Window xwindow, - guint32 timestamp) +void +meta_x11_display_set_input_focus (MetaX11Display *x11_display, + Window xwindow, + guint32 timestamp) { - gulong serial; - - if (meta_display_timestamp_too_old (x11_display->display, ×tamp)) - return; - meta_x11_error_trap_push (x11_display); /* In order for mutter to know that the focus request succeeded, we track @@ -1861,8 +1855,6 @@ request_xserver_input_focus_change (MetaX11Display *x11_display, */ XGrabServer (x11_display->xdisplay); - serial = XNextRequest (x11_display->xdisplay); - XSetInputFocus (x11_display->xdisplay, xwindow, RevertToPointerRoot, @@ -1876,27 +1868,7 @@ request_xserver_input_focus_change (MetaX11Display *x11_display, XUngrabServer (x11_display->xdisplay); XFlush (x11_display->xdisplay); - meta_display_update_focus_window (x11_display->display, meta_window); - meta_x11_display_update_focus_window (x11_display, xwindow, serial, TRUE); - meta_x11_error_trap_pop (x11_display); - - x11_display->display->last_focus_time = timestamp; - - if (meta_window == NULL || meta_window != x11_display->display->autoraise_window) - meta_display_remove_autoraise_callback (x11_display->display); -} - -void -meta_x11_display_set_input_focus_window (MetaX11Display *x11_display, - MetaWindow *window, - gboolean focus_frame, - guint32 timestamp) -{ - request_xserver_input_focus_change (x11_display, - window, - focus_frame ? window->frame->xwindow : window->xwindow, - timestamp); } void @@ -1904,20 +1876,12 @@ meta_x11_display_set_input_focus_xwindow (MetaX11Display *x11_display, Window window, guint32 timestamp) { - request_xserver_input_focus_change (x11_display, - NULL, - window, - timestamp); -} + gulong serial; -void -meta_x11_display_focus_the_no_focus_window (MetaX11Display *x11_display, - guint32 timestamp) -{ - request_xserver_input_focus_change (x11_display, - NULL, - x11_display->no_focus_window, - timestamp); + meta_display_unset_input_focus (x11_display->display, timestamp); + serial = XNextRequest (x11_display->xdisplay); + meta_x11_display_set_input_focus (x11_display, window, timestamp); + meta_x11_display_update_focus_window (x11_display, window, serial, TRUE); } static MetaX11DisplayLogicalMonitorData * diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c index fd19766bb4f..1f492984e0c 100644 --- a/src/x11/window-x11.c +++ b/src/x11/window-x11.c @@ -794,10 +794,10 @@ meta_window_x11_focus (MetaWindow *window, { meta_topic (META_DEBUG_FOCUS, "Focusing frame of %s\n", window->desc); - meta_x11_display_set_input_focus_window (window->display->x11_display, - window, - TRUE, - timestamp); + meta_display_set_input_focus (window->display, + window, + TRUE, + timestamp); } else { @@ -806,10 +806,10 @@ meta_window_x11_focus (MetaWindow *window, meta_topic (META_DEBUG_FOCUS, "Setting input focus on %s since input = true\n", window->desc); - meta_x11_display_set_input_focus_window (window->display->x11_display, - window, - FALSE, - timestamp); + meta_display_set_input_focus (window->display, + window, + FALSE, + timestamp); } if (priv->wm_take_focus) @@ -832,8 +832,7 @@ meta_window_x11_focus (MetaWindow *window, */ if (window->display->focus_window != NULL && window->display->focus_window->unmanaging) - meta_x11_display_focus_the_no_focus_window (window->display->x11_display, - timestamp); + meta_display_unset_input_focus (window->display, timestamp); } request_take_focus (window, timestamp); -- GitLab From 465e13128b12a352ccb47a584bbd3a88029d71ba Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 10 Dec 2018 13:40:54 +0100 Subject: [PATCH 10/16] core: Add explicit init/shutdown_x11() MetaDisplay calls The lifetime of MetaX11Display is still tied to MetaDisplay, but these calls will be useful when it's actually affordable to decouple those. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/core/display-private.h | 4 ++++ src/core/display.c | 47 +++++++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/core/display-private.h b/src/core/display-private.h index be2f4443342..7ff572a1c6a 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -427,4 +427,8 @@ MetaWindow *meta_display_get_window_from_id (MetaDisplay *display, uint64_t window_id); uint64_t meta_display_generate_window_id (MetaDisplay *display); +gboolean meta_display_init_x11 (MetaDisplay *display, + GError **error); +void meta_display_shutdown_x11 (MetaDisplay *display); + #endif diff --git a/src/core/display.c b/src/core/display.c index 01e97dafd67..1f352d5f2b9 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -631,6 +631,39 @@ on_ui_scaling_factor_changed (MetaSettings *settings, meta_display_reload_cursor (display); } +gboolean +meta_display_init_x11 (MetaDisplay *display, + GError **error) +{ + MetaX11Display *x11_display; + + g_assert (display->x11_display == NULL); + + x11_display = meta_x11_display_new (display, error); + if (!x11_display) + return FALSE; + + display->x11_display = x11_display; + g_signal_emit (display, display_signals[X11_DISPLAY_OPENED], 0); + meta_x11_display_create_guard_window (x11_display); + + if (!display->display_opening) + meta_display_manage_all_windows (display); + + return TRUE; +} + +void +meta_display_shutdown_x11 (MetaDisplay *display) +{ + if (!display->x11_display) + return; + + g_signal_emit (display, display_signals[X11_DISPLAY_CLOSING], 0); + g_object_run_dispose (G_OBJECT (display->x11_display)); + g_clear_object (&display->x11_display); +} + /** * meta_display_open: * @@ -646,7 +679,6 @@ meta_display_open (void) { GError *error = NULL; MetaDisplay *display; - MetaX11Display *x11_display; int i; guint32 timestamp; Window old_active_xwindow = None; @@ -730,10 +762,8 @@ meta_display_open (void) if (meta_should_autostart_x11_display ()) { - x11_display = meta_x11_display_new (display, &error); - g_assert (x11_display != NULL); /* Required, for now */ - display->x11_display = x11_display; - g_signal_emit (display, display_signals[X11_DISPLAY_OPENED], 0); + if (!meta_display_init_x11 (display, &error)) + g_error ("Failed to start Xwayland: %s", error->message); timestamp = display->x11_display->timestamp; } @@ -955,12 +985,7 @@ meta_display_close (MetaDisplay *display, if (display->compositor) meta_compositor_destroy (display->compositor); - if (display->x11_display) - { - g_signal_emit (display, display_signals[X11_DISPLAY_CLOSING], 0); - g_object_run_dispose (G_OBJECT (display->x11_display)); - g_clear_object (&display->x11_display); - } + meta_display_shutdown_x11 (display); meta_display_shutdown_keys (display); -- GitLab From 7713006f5bf68e4237bd00c0a44e81b7617c182e Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 10 Dec 2018 13:42:53 +0100 Subject: [PATCH 11/16] x11: Unmanage X11 windows on MetaX11Display finalization This used to be relied upon meta_display_close(), but MetaDisplay and MetaX11Display lifetimes may be unrelated. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/x11/meta-x11-display.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c index f7e0c2f5676..49f7abb5c46 100644 --- a/src/x11/meta-x11-display.c +++ b/src/x11/meta-x11-display.c @@ -95,6 +95,27 @@ static void unset_wm_check_hint (MetaX11Display *x11_display); static void prefs_changed_callback (MetaPreference pref, void *data); +static void +meta_x11_display_unmanage_windows (MetaX11Display *x11_display) +{ + GList *windows, *l; + MetaWindow *window; + + if (!x11_display->xids) + return; + + windows = g_hash_table_get_values (x11_display->xids); + g_list_foreach (windows, (GFunc) g_object_ref, NULL); + + for (l = windows; l; l = l->next) + { + window = l->data; + if (!window->unmanaging) + meta_window_unmanage (window, META_CURRENT_TIME); + } + g_list_free_full (windows, g_object_unref); +} + static void meta_x11_display_dispose (GObject *object) { @@ -107,6 +128,7 @@ meta_x11_display_dispose (GObject *object) meta_x11_display_ungrab_keys (x11_display); meta_x11_selection_shutdown (x11_display); + meta_x11_display_unmanage_windows (x11_display); g_clear_object (&x11_display->x11_stack); -- GitLab From 1cf4279745ab7cbedc5855f63abf7f1593a5a2a9 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 10 Dec 2018 13:59:27 +0100 Subject: [PATCH 12/16] x11: Initialize GdkDisplay together with MetaX11Display It's no longer a "singleton", since it might be closed and opened again. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/core/main.c | 16 ---------------- src/x11/meta-x11-display.c | 3 +++ 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/core/main.c b/src/core/main.c index e8464720f8d..492c74a9dd8 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -606,22 +606,6 @@ meta_init (void) meta_fatal ("Can't specify both SM save file and SM client id\n"); meta_main_loop = g_main_loop_new (NULL, FALSE); - - /* - * We need to make sure the first client connecting to the X server - * (e.g. Xwayland started from meta_wayland_init() above) is a permanent one, - * so prepare the GDK X11 connection now already. Without doing this, if - * there are any functionality that relies on X11 after here before - * meta_display_open(), the X server will terminate itself when such a client - * disconnects before the permanent GDK client connects. - */ - if (meta_should_autostart_x11_display ()) - { - GError *error = NULL; - - if (!meta_x11_init_gdk_display (&error)) - g_error ("Failed to open X11 display: %s", error->message); - } } /** diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c index 49f7abb5c46..e9a73b249da 100644 --- a/src/x11/meta-x11-display.c +++ b/src/x11/meta-x11-display.c @@ -1110,6 +1110,9 @@ meta_x11_display_new (MetaDisplay *display, GError **error) }; Atom atoms[G_N_ELEMENTS(atom_names)]; + if (!meta_x11_init_gdk_display (error)) + return NULL; + g_assert (prepared_gdk_display); gdk_display = g_steal_pointer (&prepared_gdk_display); -- GitLab From 430f354cd9f93e75a1e705ca6b0e4d0e99457a22 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 10 Dec 2018 14:24:43 +0100 Subject: [PATCH 13/16] wayland: Split Xwayland initialization in 2 steps It is now separated into meta_xwayland_start(), which picks an unused display and sets up the sockets, and meta_xwayland_init_xserver(), which does the actual exec of Xwayland and MetaX11Display initialization. This differentiation will be useful when Mutter is able to launch Xwayland lazily, currently the former calls into the latter. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/wayland/meta-wayland-private.h | 1 + src/wayland/meta-xwayland.c | 37 +++++++++++++++--------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h index 31a7fc74867..f2410be4c94 100644 --- a/src/wayland/meta-wayland-private.h +++ b/src/wayland/meta-wayland-private.h @@ -48,6 +48,7 @@ typedef struct char *lock_file; int abstract_fd; int unix_fd; + struct wl_display *wayland_display; struct wl_client *client; struct wl_resource *xserver_resource; char *display_name; diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c index 4233dc80988..e426f485ede 100644 --- a/src/wayland/meta-xwayland.c +++ b/src/wayland/meta-xwayland.c @@ -465,32 +465,27 @@ on_displayfd_ready (int fd, return G_SOURCE_REMOVE; } -gboolean -meta_xwayland_start (MetaXWaylandManager *manager, - struct wl_display *wl_display) +static gboolean +meta_xwayland_init_xserver (MetaXWaylandManager *manager) { int xwayland_client_fd[2]; int displayfd[2]; - gboolean started = FALSE; g_autoptr(GSubprocessLauncher) launcher = NULL; GSubprocessFlags flags; GError *error = NULL; - if (!choose_xdisplay (manager)) - goto out; - /* We want xwayland to be a wayland client so we make a socketpair to setup a * wayland protocol connection. */ if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, xwayland_client_fd) < 0) { g_warning ("xwayland_client_fd socketpair failed\n"); - goto out; + return FALSE; } if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, displayfd) < 0) { g_warning ("displayfd socketpair failed\n"); - goto out; + return FALSE; } /* xwayland, please. */ @@ -530,14 +525,15 @@ meta_xwayland_start (MetaXWaylandManager *manager, if (!manager->proc) { g_error ("Failed to spawn Xwayland: %s", error->message); - goto out; + return FALSE; } manager->xserver_died_cancellable = g_cancellable_new (); g_subprocess_wait_async (manager->proc, manager->xserver_died_cancellable, xserver_died, NULL); g_unix_fd_add (displayfd[0], G_IO_IN, on_displayfd_ready, manager); - manager->client = wl_client_create (wl_display, xwayland_client_fd[0]); + manager->client = wl_client_create (manager->wayland_display, + xwayland_client_fd[0]); /* We need to run a mainloop until we know xwayland has a binding * for our xserver interface at which point we can assume it's @@ -545,15 +541,18 @@ meta_xwayland_start (MetaXWaylandManager *manager, manager->init_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (manager->init_loop); - started = TRUE; + return TRUE; +} + +gboolean +meta_xwayland_start (MetaXWaylandManager *manager, + struct wl_display *wl_display) +{ + if (!choose_xdisplay (manager)) + return FALSE; -out: - if (!started) - { - unlink (manager->lock_file); - g_clear_pointer (&manager->lock_file, g_free); - } - return started; + manager->wayland_display = wl_display; + return meta_xwayland_init_xserver (manager); } static void -- GitLab From 38432da328c63ce80e2540007b6a0780bd608868 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 25 Feb 2019 18:45:30 +0100 Subject: [PATCH 14/16] compositor: Drop error trap Code underneath seems to handle errors properly, and this is apparently here to save a few XSync()s on X11. Just drop this windowing dependent bit to make things cleaner. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/compositor/compositor.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 2a2c8fb3b98..f015c92f436 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -692,11 +692,8 @@ meta_compositor_add_window (MetaCompositor *compositor, { MetaWindowActor *window_actor; ClutterActor *window_group; - MetaDisplay *display = compositor->display; GType window_actor_type = G_TYPE_INVALID; - meta_x11_error_trap_push (display->x11_display); - switch (window->client_type) { case META_WINDOW_CLIENT_TYPE_X11: @@ -724,8 +721,6 @@ meta_compositor_add_window (MetaCompositor *compositor, */ compositor->windows = g_list_append (compositor->windows, window_actor); sync_actor_stacking (compositor); - - meta_x11_error_trap_pop (display->x11_display); } void -- GitLab From ea9d8a895bbb7919a9f2f44fd57dd426e45134cc Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 25 Feb 2019 18:47:59 +0100 Subject: [PATCH 15/16] wayland: Drop error trap Code underneath seems to handle errors properly, or be x11-agnostic entirely, this is apparently here to save a few XSync()s on X11. Just drop this windowing dependent bit to make things cleaner. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/wayland/meta-window-wayland.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c index 8191adadd21..5ce67c6890f 100644 --- a/src/wayland/meta-window-wayland.c +++ b/src/wayland/meta-window-wayland.c @@ -655,7 +655,6 @@ meta_window_wayland_new (MetaDisplay *display, MetaWaylandSurface *surface) { XWindowAttributes attrs = { 0 }; - MetaWindow *window; /* * Set attributes used by _meta_window_shared_new, don't bother trying to fake @@ -670,26 +669,13 @@ meta_window_wayland_new (MetaDisplay *display, attrs.map_state = IsUnmapped; attrs.override_redirect = False; - /* XXX: Note: In the Wayland case we currently still trap X errors while - * creating a MetaWindow because we will still be making various redundant - * X requests (passing a window xid of None) until we thoroughly audit all - * the code to make sure it knows about non X based clients... - */ - meta_x11_error_trap_push (display->x11_display); /* Push a trap over all of window - * creation, to reduce XSync() calls - */ - - window = _meta_window_shared_new (display, - META_WINDOW_CLIENT_TYPE_WAYLAND, - surface, - None, - WithdrawnState, - META_COMP_EFFECT_CREATE, - &attrs); - - meta_x11_error_trap_pop (display->x11_display); /* pop the XSync()-reducing trap */ - - return window; + return _meta_window_shared_new (display, + META_WINDOW_CLIENT_TYPE_WAYLAND, + surface, + None, + WithdrawnState, + META_COMP_EFFECT_CREATE, + &attrs); } static gboolean -- GitLab From b1ea768949251aac72aba8c2cd9db8bf026800a5 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 24 May 2019 11:47:49 +0200 Subject: [PATCH 16/16] wayland: Drop -terminate argument to Xwayland This argument instructs Xwayland to exit when there are no further client connections. However we eventually want to handle restarts ourselves (where, notably, mutter's will be at least the last client connection). This behavior could also induce race conditions on startup with clients that quickly open and close a display, which is a more pressing issue. Also, add -noreset back (which was also removed in commit 054c25f693 that added -terminate). We don't want to reset the X server to a pristine state in that situation either. https://gitlab.gnome.org/GNOME/mutter/merge_requests/420 --- src/wayland/meta-xwayland.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c index e426f485ede..43bf4c1e374 100644 --- a/src/wayland/meta-xwayland.c +++ b/src/wayland/meta-xwayland.c @@ -506,16 +506,10 @@ meta_xwayland_init_xserver (MetaXWaylandManager *manager) g_subprocess_launcher_setenv (launcher, "WAYLAND_SOCKET", "3", TRUE); - /* Use the -terminate parameter to ensure that Xwayland exits cleanly - * after the last client disconnects. Fortunately that includes the window - * manager so it won't exit prematurely either. This ensures that Xwayland - * won't try to reconnect and crash, leaving uninteresting core dumps. We do - * want core dumps from Xwayland but only if a real bug occurs... - */ manager->proc = g_subprocess_launcher_spawn (launcher, &error, XWAYLAND_PATH, manager->display_name, "-rootless", - "-terminate", + "-noreset", "-accessx", "-core", "-listen", "4", -- GitLab