window: Move some display level window processing to MetaDisplay

meta_window_(un)queue() was implemented with global arrays in window.c
that managed MetaLater handle IDs and lists of window queues. In order
to rely less on scattered static variables and making it clearer that
we're dealing with per display window management and not something
specific to a single window, move the window resize/calc-showing queue
management to MetaDisplay.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2264>
This commit is contained in:
Jonas Ådahl 2022-01-29 00:49:50 +01:00 committed by Marge Bot
parent ac5d728abd
commit 169dd2fb7a
7 changed files with 284 additions and 323 deletions

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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);