diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 2a2c8fb3b9852b9aeab7976efae6f5ee889dade4..f015c92f4369bb34298ab24e277f59675cd023ce 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 diff --git a/src/core/display-private.h b/src/core/display-private.h index 068c710af4405a47e799e4a4b9d493523f5d6885..7ff572a1c6adc4294b666dfa4868436008055cfe 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; @@ -203,10 +195,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 +351,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); @@ -379,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); @@ -446,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 adef7de5dc4f89e9a322a44c7306f6cc330d3a20..1f352d5f2b95fc38c9829a592aeb35f96afbe0ad 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" @@ -630,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: * @@ -645,7 +679,6 @@ meta_display_open (void) { GError *error = NULL; MetaDisplay *display; - MetaX11Display *x11_display; int i; guint32 timestamp; Window old_active_xwindow = None; @@ -683,7 +716,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; @@ -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; } @@ -779,10 +809,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 (); @@ -924,7 +956,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); @@ -953,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); @@ -1238,16 +1265,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 +1284,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 @@ -1317,6 +1334,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) @@ -1678,14 +1740,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; @@ -2490,37 +2555,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) @@ -2626,13 +2660,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; } diff --git a/src/core/main.c b/src/core/main.c index e8464720f8db56d9ea1302cfd369ba3eab297178..492c74a9dd8096aaac3f95d74c60734629153ea5 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/core/stack.c b/src/core/stack.c index 7ab590c98d51b5479621ea878695f338ec2dfeb4..5a2f83301738aa67c5065fce1bd91d98815d825e 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,51 +47,141 @@ #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); static void stack_ensure_sorted (MetaStack *stack); -MetaStack * -meta_stack_new (MetaDisplay *display) +enum { - MetaStack *stack; + PROP_DISPLAY = 1, + N_PROPS +}; - stack = g_new (MetaStack, 1); +enum +{ + CHANGED, + WINDOW_ADDED, + WINDOW_REMOVED, + N_SIGNALS +}; - stack->display = display; - stack->xwindows = g_array_new (FALSE, FALSE, sizeof (Window)); +static GParamSpec *pspecs[N_PROPS] = { 0 }; +static guint signals[N_SIGNALS] = { 0 }; - stack->sorted = NULL; - stack->added = NULL; - stack->removed = NULL; +G_DEFINE_TYPE (MetaStack, meta_stack, G_TYPE_OBJECT) - stack->freeze_count = 0; - stack->n_positions = 0; +static void +meta_stack_init (MetaStack *stack) +{ +} - stack->need_resort = FALSE; - stack->need_relayer = FALSE; - stack->need_constrain = FALSE; +static void +meta_stack_finalize (GObject *object) +{ + MetaStack *stack = META_STACK (object); + + g_list_free (stack->sorted); - return stack; + G_OBJECT_CLASS (meta_stack_parent_class)->finalize (object); } -void -meta_stack_free (MetaStack *stack) +static void +meta_stack_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - g_array_free (stack->xwindows, TRUE); + MetaStack *stack = META_STACK (object); - g_list_free (stack->sorted); - g_list_free (stack->added); - g_list_free (stack->removed); + 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); + } +} - g_free (stack); +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 @@ -112,7 +197,12 @@ 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; stack->n_positions += 1; @@ -120,7 +210,7 @@ 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); } @@ -140,25 +230,11 @@ 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); - /* 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)); - } + g_signal_emit (stack, signals[WINDOW_REMOVED], 0, window); - stack_sync_to_xserver (stack); + meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); } @@ -169,7 +245,7 @@ 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); } @@ -180,7 +256,7 @@ 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); } @@ -210,7 +286,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); } @@ -239,7 +315,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); } @@ -255,7 +331,7 @@ 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); } @@ -771,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: * @@ -981,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) { @@ -1415,7 +1278,7 @@ 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); } @@ -1480,7 +1343,7 @@ 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 fa7bcca455b33ec868f2c40964ec1a6bca974aab..00d1cfe543c7edfce4cb5ef82d2be82576a57dc2 100644 --- a/src/core/stack.h +++ b/src/core/stack.h @@ -51,38 +51,14 @@ */ struct _MetaStack { + GObject parent; + /** 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. @@ -121,6 +97,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 +110,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 diff --git a/src/core/window-private.h b/src/core/window-private.h index 06be5aad82f790d413f6c53a0e5cea98a2ee5757..eb497659f18899090c500ac4e2dbf05633788fce 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 89408081da0614a502f594bd514631279591a6ce..caa1059e383af2af54bef2ef74bfcd207c827bc9 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 @@ -1939,9 +1932,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 +2405,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 +2572,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 +2580,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); } } @@ -5378,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) @@ -5438,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]); @@ -5457,9 +5402,6 @@ meta_window_update_icon_now (MetaWindow *window, redraw_icon (window); } - - g_assert (window->icon); - g_assert (window->mini_icon); } static gboolean @@ -8146,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 b4fd836c9a790cdf27a094a28c93a3a67f8b36be..71c54d229c9d88e2d2d44d306cd8c46cf5388a79 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/meson.build b/src/meson.build index 0a1262fe99a36e046c240e49db2e19d9113fe939..5007b5cab4b71b96d11bdc2bfb6b5c905767b48b 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/meta/display.h b/src/meta/display.h index 09c1f99ecf697074ce84a5753beae89fc8f87b6b..5cf99cfead2cefea7dc2c108606d5c931c732b58 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 f5167af7d2b7bb05f14143259aef832296748f68..9c9adf9b7f03f0f9fc03076dc3e1a5b35199677d 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-wayland-private.h b/src/wayland/meta-wayland-private.h index 31a7fc74867152d5dd4053bf84a0ccfa9e1eaa80..f2410be4c94b7d20f9c79556ce1aadb41e5cbd7b 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-window-wayland.c b/src/wayland/meta-window-wayland.c index c7c3785d8ecf833ac8ca5c8cc25400a030e0c93c..5ce67c6890f5f4a427928eff6ac189f74beae36f 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 @@ -611,6 +613,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 +646,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 * @@ -641,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 @@ -656,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 diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c index 4233dc80988bdec1c1886dea58cd3bcef257fd33..43bf4c1e374555ba7d90a347cdd1edb239ec5a2a 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. */ @@ -511,16 +506,10 @@ meta_xwayland_start (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", @@ -530,14 +519,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 +535,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; +} -out: - if (!started) - { - unlink (manager->lock_file); - g_clear_pointer (&manager->lock_file, g_free); - } - return started; +gboolean +meta_xwayland_start (MetaXWaylandManager *manager, + struct wl_display *wl_display) +{ + if (!choose_xdisplay (manager)) + return FALSE; + + manager->wayland_display = wl_display; + return meta_xwayland_init_xserver (manager); } static void diff --git a/src/x11/events.c b/src/x11/events.c index 92b5d70156bb723bb690a5df1f4fdc3b43a600ee..02c8509dc5be0a215355ba0eb3996ab663a4ac8d 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 @@ -882,7 +883,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 +1526,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); } } } @@ -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 9a8ab83b209cf773f4b3e711c13b7beb99c9f012..3f545ce2833f487288b3db4a7f83f9aad7f67569 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; @@ -133,8 +134,21 @@ 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 + * to avoid some race conditions on EnterNotify events + */ + int sentinel_counter; + int composite_event_base; int composite_error_base; int composite_major_version; @@ -162,6 +176,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); @@ -222,4 +237,16 @@ 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); + +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 af8ae7a8d6d8a4e2a7fe635501bef91130d6d1c6..e9a73b249dafcbda1f1619b89d4b4a95615e5ab1 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,9 @@ 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); if (x11_display->ui) { @@ -1086,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); @@ -1270,6 +1297,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); @@ -1819,17 +1847,27 @@ meta_x11_display_update_active_window_hint (MetaX11Display *x11_display) meta_x11_error_trap_pop (x11_display); } -static void -request_xserver_input_focus_change (MetaX11Display *x11_display, - MetaWindow *meta_window, - Window xwindow, - guint32 timestamp) +void +meta_x11_display_update_focus_window (MetaX11Display *x11_display, + Window xwindow, + gulong serial, + gboolean focused_by_us) { - gulong serial; + x11_display->focus_serial = serial; + x11_display->focused_by_us = !!focused_by_us; - if (meta_display_timestamp_too_old (x11_display->display, ×tamp)) + if (x11_display->focus_xwindow == xwindow) return; + x11_display->focus_xwindow = xwindow; + meta_x11_display_update_active_window_hint (x11_display); +} + +void +meta_x11_display_set_input_focus (MetaX11Display *x11_display, + Window xwindow, + guint32 timestamp) +{ meta_x11_error_trap_push (x11_display); /* In order for mutter to know that the focus request succeeded, we track @@ -1842,8 +1880,6 @@ request_xserver_input_focus_change (MetaX11Display *x11_display, */ XGrabServer (x11_display->xdisplay); - serial = XNextRequest (x11_display->xdisplay); - XSetInputFocus (x11_display->xdisplay, xwindow, RevertToPointerRoot, @@ -1857,30 +1893,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, - 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 @@ -1888,20 +1901,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 * @@ -2177,3 +2182,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); +} diff --git a/src/x11/meta-x11-stack-private.h b/src/x11/meta-x11-stack-private.h new file mode 100644 index 0000000000000000000000000000000000000000..a00b8e7430f6b418ff9fd00502eceb40cdb9be24 --- /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 0000000000000000000000000000000000000000..fa08fc4c5bc57c436c7b074ba742204c7b3b66ae --- /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); +} diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c index edb378ae9ca9aa3370609796617758e674b2392b..1f492984e0cecdde3d745605753da15f247e3eac 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); @@ -1706,6 +1705,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 +1753,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