diff --git a/src/core/display-private.h b/src/core/display-private.h index 6b7821412..e91d73035 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -432,4 +432,12 @@ gboolean meta_display_init_x11_finish (MetaDisplay *display, void meta_display_shutdown_x11 (MetaDisplay *display); +void meta_display_queue_window (MetaDisplay *display, + MetaWindow *window, + MetaQueueType queue_types); + +void meta_display_unqueue_window (MetaDisplay *display, + MetaWindow *window, + MetaQueueType queue_types); + #endif diff --git a/src/core/display.c b/src/core/display.c index be1d85b20..5f99578a6 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -124,6 +124,9 @@ typedef struct typedef struct _MetaDisplayPrivate { MetaContext *context; + + guint queue_later_ids[META_N_QUEUE_TYPES]; + GList *queue_windows[META_N_QUEUE_TYPES]; } MetaDisplayPrivate; G_DEFINE_TYPE_WITH_PRIVATE (MetaDisplay, meta_display, G_TYPE_OBJECT) @@ -163,6 +166,7 @@ enum WORKAREAS_CHANGED, CLOSING, INIT_XSERVER, + WINDOW_VISIBILITY_UPDATED, LAST_SIGNAL }; @@ -525,6 +529,16 @@ meta_display_class_init (MetaDisplayClass *klass) NULL, NULL, G_TYPE_BOOLEAN, 1, G_TYPE_TASK); + display_signals[WINDOW_VISIBILITY_UPDATED] = + g_signal_new ("window-visibility-updated", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 3, + G_TYPE_POINTER, + G_TYPE_POINTER, + G_TYPE_POINTER); + g_object_class_install_property (object_class, PROP_COMPOSITOR_MODIFIERS, g_param_spec_flags ("compositor-modifiers", @@ -3933,3 +3947,192 @@ meta_display_get_selection (MetaDisplay *display) { return display->selection; } + +#ifdef WITH_VERBOSE_MODE +static const char* meta_window_queue_names[META_N_QUEUE_TYPES] = + { + "calc-showing", + "move-resize", + }; +#endif + +static int +window_stack_cmp (gconstpointer a, + gconstpointer b) +{ + MetaWindow *aw = (gpointer) a; + MetaWindow *bw = (gpointer) b; + + return meta_stack_windows_cmp (aw->display->stack, + aw, bw); +} + +static void +warn_on_incorrectly_unmanaged_window (MetaWindow *window) +{ + g_warn_if_fail (!window->unmanaging); +} + +static gboolean +update_window_visibilities_idle (gpointer user_data) +{ + MetaDisplay *display = META_DISPLAY (user_data); + MetaDisplayPrivate *priv = meta_display_get_instance_private (display); + int queue_idx; + g_autoptr (GList) windows = NULL; + g_autoptr (GList) unplaced = NULL; + g_autoptr (GList) should_show = NULL; + g_autoptr (GList) should_hide = NULL; + GList *l; + + COGL_TRACE_BEGIN_SCOPED (MetaDisplayUpdateVisibility, + "Display: Update visibility"); + + queue_idx = __builtin_ctz (META_QUEUE_CALC_SHOWING); + + windows = g_steal_pointer (&priv->queue_windows[queue_idx]); + priv->queue_later_ids[queue_idx] = 0; + + for (l = windows; l; l = l->next) + { + MetaWindow *window = l->data; + + if (!window->placed) + unplaced = g_list_prepend (unplaced, window); + else if (meta_window_should_be_showing (window)) + should_show = g_list_prepend (should_show, window); + else + should_hide = g_list_prepend (should_hide, window); + } + + /* Sort bottom to top */ + unplaced = g_list_sort (unplaced, window_stack_cmp); + should_hide = g_list_sort (should_hide, window_stack_cmp); + + /* Sort top to bottom */ + should_show = g_list_sort (should_show, window_stack_cmp); + should_show = g_list_reverse (should_show); + + COGL_TRACE_BEGIN (MetaDisplayShowUnplacedWindows, + "Display: Show unplaced windows"); + g_list_foreach (unplaced, (GFunc) meta_window_update_visibility, NULL); + COGL_TRACE_END (MetaDisplayShowUnplacedWindows); + + meta_stack_freeze (display->stack); + + COGL_TRACE_BEGIN (MetaDisplayShowWindows, "Display: Show windows"); + g_list_foreach (should_show, (GFunc) meta_window_update_visibility, NULL); + COGL_TRACE_END (MetaDisplayShowWindows); + + COGL_TRACE_BEGIN (MetaDisplayHideWindows, "Display: Show windows"); + g_list_foreach (should_hide, (GFunc) meta_window_update_visibility, NULL); + COGL_TRACE_END (MetaDisplayHideWindows); + + meta_stack_thaw (display->stack); + + g_list_foreach (windows, (GFunc) meta_window_clear_queued, NULL); + + g_signal_emit (display, display_signals[WINDOW_VISIBILITY_UPDATED], 0, + unplaced, should_show, should_hide); + + g_list_foreach (windows, (GFunc) warn_on_incorrectly_unmanaged_window, NULL); + + return G_SOURCE_REMOVE; +} + +static gboolean +move_resize_idle (gpointer user_data) +{ + MetaDisplay *display = META_DISPLAY (user_data); + MetaDisplayPrivate *priv = meta_display_get_instance_private (display); + int queue_idx; + g_autoptr (GList) windows = NULL; + + queue_idx = __builtin_ctz (META_QUEUE_MOVE_RESIZE); + + windows = g_steal_pointer (&priv->queue_windows[queue_idx]); + priv->queue_later_ids[queue_idx] = 0; + + g_list_foreach (windows, (GFunc) meta_window_update_layout, NULL); + g_list_foreach (windows, (GFunc) warn_on_incorrectly_unmanaged_window, NULL); + + return G_SOURCE_REMOVE; +} + +void +meta_display_queue_window (MetaDisplay *display, + MetaWindow *window, + MetaQueueType queue_types) +{ + MetaDisplayPrivate *priv = meta_display_get_instance_private (display); + MetaCompositor *compositor = display->compositor; + MetaLaters *laters = meta_compositor_get_laters (compositor); + int queue_idx; + + for (queue_idx = 0; queue_idx < META_N_QUEUE_TYPES; queue_idx++) + { + const MetaLaterType window_queue_later_when[META_N_QUEUE_TYPES] = + { + META_LATER_CALC_SHOWING, + META_LATER_RESIZE, + }; + + const GSourceFunc window_queue_later_handler[META_N_QUEUE_TYPES] = + { + update_window_visibilities_idle, + move_resize_idle, + }; + + if (!(queue_types & 1 << queue_idx)) + continue; + + meta_topic (META_DEBUG_WINDOW_STATE, + "Queueing %s for window '%s'", + meta_window_queue_names[queue_idx], + meta_window_get_description (window)); + + priv->queue_windows[queue_idx] = + g_list_prepend (priv->queue_windows[queue_idx], window); + + if (!priv->queue_later_ids[queue_idx]) + { + meta_laters_add (laters, + window_queue_later_when[queue_idx], + window_queue_later_handler[queue_idx], + display, NULL); + + } + } +} + +void +meta_display_unqueue_window (MetaDisplay *display, + MetaWindow *window, + MetaQueueType queue_types) +{ + MetaDisplayPrivate *priv = meta_display_get_instance_private (display); + MetaCompositor *compositor = display->compositor; + MetaLaters *laters = meta_compositor_get_laters (compositor); + int queue_idx; + + for (queue_idx = 0; queue_idx < META_N_QUEUE_TYPES; queue_idx++) + { + if (!(queue_types & 1 << queue_idx)) + continue; + + meta_topic (META_DEBUG_WINDOW_STATE, + "Unqueuing %s for window '%s'", + meta_window_queue_names[queue_idx], + window->desc); + + priv->queue_windows[queue_idx] = + g_list_remove (priv->queue_windows[queue_idx], window); + + if (!priv->queue_windows[queue_idx] && priv->queue_later_ids[queue_idx]) + { + meta_laters_remove (laters, + priv->queue_later_ids[queue_idx]); + priv->queue_later_ids[queue_idx] = 0; + } + } +} diff --git a/src/core/meta-private-enums.h b/src/core/meta-private-enums.h index 1a361c782..ae6a9bbe5 100644 --- a/src/core/meta-private-enums.h +++ b/src/core/meta-private-enums.h @@ -28,4 +28,10 @@ typedef enum _MetaX11DisplayPolicy META_X11_DISPLAY_POLICY_DISABLED, } MetaX11DisplayPolicy; +typedef enum +{ + META_QUEUE_CALC_SHOWING = 1 << 0, + META_QUEUE_MOVE_RESIZE = 1 << 1, +} MetaQueueType; + #endif /* META_PRIVATE_ENUMS_H */ diff --git a/src/core/stack.c b/src/core/stack.c index 1af59f5be..481e72232 100644 --- a/src/core/stack.c +++ b/src/core/stack.c @@ -416,6 +416,8 @@ meta_stack_thaw (MetaStack *stack) { g_return_if_fail (stack->freeze_count > 0); + COGL_TRACE_BEGIN_SCOPED (MetaStackThaw, "Stack: thaw"); + stack->freeze_count -= 1; meta_stack_changed (stack); meta_stack_update_window_tile_matches (stack, NULL); diff --git a/src/core/window-private.h b/src/core/window-private.h index 258445d98..ad1dd5a86 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -56,13 +56,7 @@ typedef enum META_CLIENT_TYPE_MAX_RECOGNIZED = 2 } MetaClientType; -typedef enum -{ - META_QUEUE_CALC_SHOWING = 1 << 0, - META_QUEUE_MOVE_RESIZE = 1 << 1, -} MetaQueueType; - -#define NUMBER_OF_QUEUES 2 +#define META_N_QUEUE_TYPES 2 typedef enum { @@ -397,9 +391,6 @@ struct _MetaWindow /* Are we in meta_window_new()? */ guint constructing : 1; - /* Are we in the various queues? (Bitfield: see META_WINDOW_IS_IN_QUEUE) */ - guint is_in_queues : NUMBER_OF_QUEUES; - /* Used by keybindings.c */ guint keys_grabbed : 1; /* normal keybindings grabbed */ guint grab_on_frame : 1; /* grabs are on the frame */ @@ -915,4 +906,10 @@ gboolean meta_window_unit_cgroup_equal (MetaWindow *window1, void meta_window_check_alive_on_event (MetaWindow *window, uint32_t timestamp); +void meta_window_update_visibility (MetaWindow *window); + +void meta_window_clear_queued (MetaWindow *window); + +void meta_window_update_layout (MetaWindow *window); + #endif diff --git a/src/core/window.c b/src/core/window.c index eacde2b47..4a0c6242e 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -109,8 +109,6 @@ #define SNAP_SECURITY_LABEL_PREFIX "snap." -static int destroying_windows_disallowed = 0; - /* Each window has a "stamp" which is a non-recycled 64-bit ID. They * start after the end of the XID space so that, for stacking * we can keep a guint64 that represents one or the other @@ -131,8 +129,6 @@ static void meta_window_save_rect (MetaWindow *window); static void ensure_mru_position_after (MetaWindow *window, MetaWindow *after_this_one); -static void meta_window_move_resize_now (MetaWindow *window); - static void meta_window_unqueue (MetaWindow *window, MetaQueueType queuebits); @@ -170,17 +166,12 @@ static MetaWindow * meta_window_find_tile_match (MetaWindow *window, MetaTileMode mode); static void update_edge_constraints (MetaWindow *window); -/* Idle handlers for the three queues (run with meta_later_add()). The - * "data" parameter in each case will be a GINT_TO_POINTER of the - * index into the queue arrays to use. - * - * TODO: Possibly there is still some code duplication among these, which we - * need to sort out at some point. - */ -static gboolean idle_calc_showing (gpointer data); -static gboolean idle_move_resize (gpointer data); +typedef struct _MetaWindowPrivate +{ + MetaQueueType queued_types; +} MetaWindowPrivate; -G_DEFINE_ABSTRACT_TYPE (MetaWindow, meta_window, G_TYPE_OBJECT); +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaWindow, meta_window, G_TYPE_OBJECT) enum { @@ -1083,7 +1074,6 @@ _meta_window_shared_new (MetaDisplay *display, window->placed = ((window->mapped && !window->hidden) || window->override_redirect); window->denied_focus_and_not_transient = FALSE; window->unmanaging = FALSE; - window->is_in_queues = 0; window->keys_grabbed = FALSE; window->grab_on_frame = FALSE; window->all_keys_grabbed = FALSE; @@ -1458,10 +1448,6 @@ meta_window_unmanage (MetaWindow *window, meta_compositor_remove_window (window->display->compositor, window); window->known_to_compositor = FALSE; - if (destroying_windows_disallowed > 0) - meta_bug ("Tried to destroy window %s while destruction was not allowed", - window->desc); - meta_display_unregister_stamp (window->display, window->stamp); if (meta_prefs_get_attach_modal_dialogs ()) @@ -1774,289 +1760,65 @@ implement_showing (MetaWindow *window, sync_client_window_mapped (window); } -static void -meta_window_calc_showing (MetaWindow *window) +void +meta_window_update_visibility (MetaWindow *window) { implement_showing (window, meta_window_should_be_showing (window)); } -static guint queue_later[NUMBER_OF_QUEUES] = {}; -static GSList *queue_pending[NUMBER_OF_QUEUES] = {}; - -static int -stackcmp (gconstpointer a, gconstpointer b) +void +meta_window_clear_queued (MetaWindow *window) { - MetaWindow *aw = (gpointer) a; - MetaWindow *bw = (gpointer) b; + MetaWindowPrivate *priv = meta_window_get_instance_private (window); - return meta_stack_windows_cmp (aw->display->stack, - aw, bw); + priv->queued_types &= ~META_QUEUE_CALC_SHOWING; } -static gboolean -idle_calc_showing (gpointer data) -{ - MetaDisplay *display = meta_get_display (); - GSList *tmp; - GSList *copy; - GSList *should_show; - GSList *should_hide; - GSList *unplaced; - GSList *displays; - guint queue_index = GPOINTER_TO_INT (data); - - COGL_TRACE_BEGIN_SCOPED (MetaWindowCalcShowing, "Window: Calc showing"); - - g_return_val_if_fail (queue_pending[queue_index] != NULL, FALSE); - - meta_topic (META_DEBUG_WINDOW_STATE, - "Clearing the calc_showing queue"); - - /* Work with a copy, for reentrancy. The allowed reentrancy isn't - * complete; destroying a window while we're in here would result in - * badness. But it's OK to queue/unqueue calc_showings. - */ - copy = g_slist_copy (queue_pending[queue_index]); - g_slist_free (queue_pending[queue_index]); - queue_pending[queue_index] = NULL; - queue_later[queue_index] = 0; - - destroying_windows_disallowed += 1; - - /* We map windows from top to bottom and unmap from bottom to - * top, to avoid extra expose events. The exception is - * for unplaced windows, which have to be mapped from bottom to - * top so placement works. - */ - should_show = NULL; - should_hide = NULL; - unplaced = NULL; - displays = NULL; - - COGL_TRACE_BEGIN (MetaWindowCalcShowingCalc, "Window: Calc showing (calc)"); - - tmp = copy; - while (tmp != NULL) - { - MetaWindow *window; - - window = tmp->data; - - if (!window->placed) - unplaced = g_slist_prepend (unplaced, window); - else if (meta_window_should_be_showing (window)) - should_show = g_slist_prepend (should_show, window); - else - should_hide = g_slist_prepend (should_hide, window); - - tmp = tmp->next; - } - - /* bottom to top */ - unplaced = g_slist_sort (unplaced, stackcmp); - should_hide = g_slist_sort (should_hide, stackcmp); - /* top to bottom */ - should_show = g_slist_sort (should_show, stackcmp); - should_show = g_slist_reverse (should_show); - - COGL_TRACE_END (MetaWindowCalcShowingCalc); - - COGL_TRACE_BEGIN (MetaWindowCalcShowingUnplaced, - "Window: Calc showing (calc unplaced)"); - - tmp = unplaced; - while (tmp != NULL) - { - MetaWindow *window; - - window = tmp->data; - - meta_window_calc_showing (window); - - tmp = tmp->next; - } - - COGL_TRACE_END (MetaWindowCalcShowingUnplaced); - - meta_stack_freeze (display->stack); - - COGL_TRACE_BEGIN (MetaWindowCalcShowingShow, "Window: Calc showing (show)"); - tmp = should_show; - while (tmp != NULL) - { - MetaWindow *window; - - window = tmp->data; - - implement_showing (window, TRUE); - - tmp = tmp->next; - } - COGL_TRACE_END (MetaWindowCalcShowingShow); - - COGL_TRACE_BEGIN (MetaWindowCalcShowingHide, "Window: Calc showing (hide)"); - tmp = should_hide; - while (tmp != NULL) - { - MetaWindow *window; - - window = tmp->data; - - implement_showing (window, FALSE); - - tmp = tmp->next; - } - COGL_TRACE_END (MetaWindowCalcShowingHide); - - COGL_TRACE_BEGIN (MetaWindowCalcShowingSync, - "Window: Calc showing (sync stack)"); - meta_stack_thaw (display->stack); - COGL_TRACE_END (MetaWindowCalcShowingSync); - - tmp = copy; - while (tmp != NULL) - { - MetaWindow *window; - - window = tmp->data; - - /* important to set this here for reentrancy - - * if we queue a window again while it's in "copy", - * then queue_calc_showing will just return since - * we are still in the calc_showing queue - */ - window->is_in_queues &= ~META_QUEUE_CALC_SHOWING; - - tmp = tmp->next; - } - - if (meta_prefs_get_focus_mode () != G_DESKTOP_FOCUS_MODE_CLICK) - { - /* When display->mouse_mode is false, we want to ignore - * EnterNotify events unless they come from mouse motion. To do - * that, we set a sentinel property on the root window if we're - * not in mouse_mode. - */ - tmp = should_show; - while (tmp != NULL) - { - MetaWindow *window = tmp->data; - MetaDisplay *display = window->display; - - if (display->x11_display && !display->mouse_mode) - meta_x11_display_increment_focus_sentinel (display->x11_display); - - tmp = tmp->next; - } - } - - g_slist_free (copy); - - g_slist_free (unplaced); - g_slist_free (should_show); - g_slist_free (should_hide); - g_slist_free (displays); - - destroying_windows_disallowed -= 1; - - return FALSE; -} - -#ifdef WITH_VERBOSE_MODE -static const gchar* meta_window_queue_names[NUMBER_OF_QUEUES] = - {"calc_showing", "move_resize", }; -#endif - static void meta_window_unqueue (MetaWindow *window, - MetaQueueType queuebits) + MetaQueueType queue_types) { - int queuenum; + MetaWindowPrivate *priv = meta_window_get_instance_private (window); - for (queuenum = 0; queuenum < NUMBER_OF_QUEUES; queuenum++) - { - if ((queuebits & 1 << queuenum) && - (window->is_in_queues & 1 << queuenum)) - { + queue_types &= priv->queued_types; - meta_topic (META_DEBUG_WINDOW_STATE, - "Removing %s from the %s queue", - window->desc, - meta_window_queue_names[queuenum]); + if (!queue_types) + return; - queue_pending[queuenum] = g_slist_remove (queue_pending[queuenum], window); - window->is_in_queues &= ~(1 << queuenum); - - if (queue_pending[queuenum] == NULL && queue_later[queuenum] != 0) - { - meta_later_remove (queue_later[queuenum]); - queue_later[queuenum] = 0; - } - } - } + meta_display_unqueue_window (window->display, window, queue_types); + priv->queued_types &= ~queue_types; } static void meta_window_flush_calc_showing (MetaWindow *window) { - if (window->is_in_queues & META_QUEUE_CALC_SHOWING) + MetaWindowPrivate *priv = meta_window_get_instance_private (window); + + if (priv->queued_types & META_QUEUE_CALC_SHOWING) { meta_window_unqueue (window, META_QUEUE_CALC_SHOWING); - meta_window_calc_showing (window); + meta_window_update_visibility (window); } } void meta_window_queue (MetaWindow *window, - MetaQueueType queuebits) + MetaQueueType queue_types) { - unsigned int queuenum; + MetaWindowPrivate *priv = meta_window_get_instance_private (window); g_return_if_fail (!window->override_redirect || - (queuebits & META_QUEUE_MOVE_RESIZE) == 0); + (queue_types & META_QUEUE_MOVE_RESIZE) == 0); - for (queuenum = 0; queuenum < NUMBER_OF_QUEUES; queuenum++) - { - if (queuebits & 1 << queuenum) - { - const MetaLaterType window_queue_later_when[NUMBER_OF_QUEUES] = - { - META_LATER_CALC_SHOWING, - META_LATER_RESIZE, - }; + if (window->unmanaging) + return; - const GSourceFunc window_queue_later_handler[NUMBER_OF_QUEUES] = - { - idle_calc_showing, - idle_move_resize, - }; + queue_types &= ~priv->queued_types; + if (!queue_types) + return; - if (window->unmanaging) - break; - - if (window->is_in_queues & 1 << queuenum) - break; - - meta_topic (META_DEBUG_WINDOW_STATE, - "Putting %s in the %s queue", - window->desc, - meta_window_queue_names[queuenum]); - - window->is_in_queues |= 1 << queuenum; - - if (queue_later[queuenum] == 0) - { - queue_later[queuenum] = - meta_later_add (window_queue_later_when[queuenum], - window_queue_later_handler[queuenum], - GUINT_TO_POINTER (queuenum), - NULL); - } - - queue_pending[queuenum] = g_slist_prepend (queue_pending[queuenum], - window); - } - } + priv->queued_types |= queue_types; + meta_display_queue_window (window->display, window, queue_types); } static gboolean @@ -4090,7 +3852,7 @@ meta_window_move_resize_internal (MetaWindow *window, } /* If we did placement, then we need to save the position that the window - * was placed at to make sure that meta_window_move_resize_now places the + * was placed at to make sure that meta_window_update_layout() places the * window correctly. */ if (did_placement) @@ -4367,8 +4129,8 @@ meta_window_resize_frame_with_gravity (MetaWindow *window, meta_window_move_resize_internal (window, flags, gravity, rect); } -static void -meta_window_move_resize_now (MetaWindow *window) +void +meta_window_update_layout (MetaWindow *window) { meta_window_move_resize_frame (window, FALSE, window->unconstrained_rect.x, @@ -4377,46 +4139,6 @@ meta_window_move_resize_now (MetaWindow *window) window->unconstrained_rect.height); } -static gboolean -idle_move_resize (gpointer data) -{ - GSList *tmp; - GSList *copy; - guint queue_index = GPOINTER_TO_INT (data); - - meta_topic (META_DEBUG_GEOMETRY, "Clearing the move_resize queue"); - - /* Work with a copy, for reentrancy. The allowed reentrancy isn't - * complete; destroying a window while we're in here would result in - * badness. But it's OK to queue/unqueue move_resizes. - */ - copy = g_slist_copy (queue_pending[queue_index]); - g_slist_free (queue_pending[queue_index]); - queue_pending[queue_index] = NULL; - queue_later[queue_index] = 0; - - destroying_windows_disallowed += 1; - - tmp = copy; - while (tmp != NULL) - { - MetaWindow *window; - - window = tmp->data; - - /* As a side effect, sets window->move_resize_queued = FALSE */ - meta_window_move_resize_now (window); - - tmp = tmp->next; - } - - g_slist_free (copy); - - destroying_windows_disallowed -= 1; - - return FALSE; -} - void meta_window_get_gravity_position (MetaWindow *window, MetaGravity gravity, diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c index 7b89cac24..d4b5ff425 100644 --- a/src/x11/meta-x11-display.c +++ b/src/x11/meta-x11-display.c @@ -1104,6 +1104,25 @@ meta_x11_init_gdk_display (GError **error) return TRUE; } +static void +on_window_visibility_updated (MetaDisplay *display, + GList *placed_windows, + GList *shown_windows, + GList *hidden_windows, + MetaX11Display *x11_display) +{ + GList *l; + + if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK) + return; + + if (display->mouse_mode) + return; + + for (l = shown_windows; l; l = l->next) + meta_x11_display_increment_focus_sentinel (x11_display); +} + /** * meta_x11_display_new: * @@ -1236,6 +1255,10 @@ meta_x11_display_new (MetaDisplay *display, GError **error) G_CALLBACK (update_cursor_theme), x11_display, G_CONNECT_SWAPPED); + g_signal_connect_object (display, + "window-visibility-updated", + G_CALLBACK (on_window_visibility_updated), + x11_display, 0); update_cursor_theme (x11_display);