shell/monitor-group: Avoid doing extra work

A lot of our calculations only change based on (unlikely) external
events, simply cache those parts and only update when the underlying
properties actually change.

Notable is base_direction, which was previously being calculated
repeatedly per workspace per monitor on every interpolate — now it's
simply a private int.

This seriously cuts down the number of calls, vs just maths, we need to
do at each step including eliminating a repeated `g_object_get` in favour
of a gboolean flag.
This commit is contained in:
Zander Brown 2023-10-28 06:36:10 +01:00
parent fbce396f4a
commit 8271fda6e3
No known key found for this signature in database
GPG key ID: 25EE3C36E31E5F84

View file

@ -31,10 +31,18 @@
typedef struct _ShellMonitorGroupPrivate ShellMonitorGroupPrivate; typedef struct _ShellMonitorGroupPrivate ShellMonitorGroupPrivate;
struct _ShellMonitorGroupPrivate struct _ShellMonitorGroupPrivate
{ {
ShellGlobal *global;
MetaWorkspaceManager *workspace_manager;
StThemeContext *theme_context;
ClutterActor *container; ClutterActor *container;
GPtrArray *workspace_groups; GPtrArray *workspace_groups;
int index, width, height; int index, width, height;
float base_distance;
gboolean is_vertical;
gboolean is_rtl;
}; };
enum enum
@ -60,6 +68,16 @@ shell_monitor_group_dispose (GObject *object)
ShellMonitorGroupPrivate *priv = ShellMonitorGroupPrivate *priv =
shell_monitor_group_get_instance_private (SHELL_MONITOR_GROUP (object)); shell_monitor_group_get_instance_private (SHELL_MONITOR_GROUP (object));
g_clear_weak_pointer (&priv->global);
if (priv->workspace_manager)
g_signal_handlers_disconnect_by_data (priv->workspace_manager, object);
g_clear_weak_pointer (&priv->workspace_manager);
if (priv->theme_context)
g_signal_handlers_disconnect_by_data (priv->theme_context, object);
g_clear_weak_pointer (&priv->theme_context);
g_clear_weak_pointer (&priv->container); g_clear_weak_pointer (&priv->container);
g_clear_pointer (&priv->workspace_groups, g_ptr_array_unref); g_clear_pointer (&priv->workspace_groups, g_ptr_array_unref);
@ -82,11 +100,9 @@ shell_monitor_group_set_property (GObject *object,
break; break;
case PROP_MONITOR_WIDTH: case PROP_MONITOR_WIDTH:
priv->width = g_value_get_int (value); priv->width = g_value_get_int (value);
clutter_actor_set_size (CLUTTER_ACTOR (object), g_value_get_int (value), priv->height);
break; break;
case PROP_MONITOR_HEIGHT: case PROP_MONITOR_HEIGHT:
priv->height = g_value_get_int (value); priv->height = g_value_get_int (value);
clutter_actor_set_size (CLUTTER_ACTOR (object), priv->width, g_value_get_int (value));
break; break;
case PROP_PROGRESS: case PROP_PROGRESS:
shell_monitor_group_set_progress (SHELL_MONITOR_GROUP (object), shell_monitor_group_set_progress (SHELL_MONITOR_GROUP (object),
@ -131,6 +147,35 @@ shell_monitor_group_get_property (GObject *object,
} }
} }
static void
update_base_distance (ShellMonitorGroup *self)
{
ShellMonitorGroupPrivate *priv =
shell_monitor_group_get_instance_private (self);
int spacing =
WORKSPACE_SPACING * st_theme_context_get_scale_factor (priv->theme_context);
if (priv->is_vertical)
priv->base_distance = priv->height + spacing;
else
priv->base_distance = priv->width + spacing;
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_BASE_DISTANCE]);
}
static void
shell_monitor_group_constructed (GObject *object)
{
ShellMonitorGroup *self = SHELL_MONITOR_GROUP (object);
ShellMonitorGroupPrivate *priv =
shell_monitor_group_get_instance_private (self);
G_OBJECT_CLASS (shell_monitor_group_parent_class)->constructed (object);
clutter_actor_set_size (CLUTTER_ACTOR (object), priv->width, priv->height);
update_base_distance (self);
}
static void static void
shell_monitor_group_class_init (ShellMonitorGroupClass *klass) shell_monitor_group_class_init (ShellMonitorGroupClass *klass)
{ {
@ -139,6 +184,7 @@ shell_monitor_group_class_init (ShellMonitorGroupClass *klass)
object_class->dispose = shell_monitor_group_dispose; object_class->dispose = shell_monitor_group_dispose;
object_class->set_property = shell_monitor_group_set_property; object_class->set_property = shell_monitor_group_set_property;
object_class->get_property = shell_monitor_group_get_property; object_class->get_property = shell_monitor_group_get_property;
object_class->constructed = shell_monitor_group_constructed;
obj_props[PROP_INDEX] = obj_props[PROP_INDEX] =
g_param_spec_int ("index", NULL, NULL, g_param_spec_int ("index", NULL, NULL,
@ -164,71 +210,122 @@ shell_monitor_group_class_init (ShellMonitorGroupClass *klass)
g_object_class_install_properties (object_class, PROP_LAST, obj_props); g_object_class_install_properties (object_class, PROP_LAST, obj_props);
} }
static void
layout_rows_changed (ShellMonitorGroup *self)
{
ShellMonitorGroupPrivate *priv =
shell_monitor_group_get_instance_private (self);
int rows;
/*
* TODO: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3351
* priv->is_vertical =
* meta_workspace_manager_get_layout_rows (priv->workspace_manager) == -1;
*/
g_object_get (priv->workspace_manager, "layout-rows", &rows, NULL);
priv->is_vertical = rows == -1;
update_base_distance (self);
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PROGRESS]);
}
static void
scale_factor_changed (ShellMonitorGroup *self)
{
update_base_distance (self);
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PROGRESS]);
}
static void
text_direction_changed (ShellMonitorGroup *self)
{
ShellMonitorGroupPrivate *priv =
shell_monitor_group_get_instance_private (self);
priv->is_rtl =
clutter_actor_get_text_direction (CLUTTER_ACTOR (self)) == CLUTTER_TEXT_DIRECTION_RTL;
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PROGRESS]);
}
static void static void
shell_monitor_group_init (ShellMonitorGroup *self) shell_monitor_group_init (ShellMonitorGroup *self)
{ {
ShellMonitorGroupPrivate *priv = ShellMonitorGroupPrivate *priv =
shell_monitor_group_get_instance_private (self); shell_monitor_group_get_instance_private (self);
ShellGlobal *global = shell_global_get ();
MetaWorkspaceManager *workspace_manager =
shell_global_get_workspace_manager (global);
StThemeContext *theme_context =
st_theme_context_get_for_stage (shell_global_get_stage (global));
ClutterActor *container = clutter_actor_new (); ClutterActor *container = clutter_actor_new ();
g_set_weak_pointer (&priv->global, global);
g_set_weak_pointer (&priv->workspace_manager, workspace_manager);
g_set_weak_pointer (&priv->theme_context, theme_context);
g_set_weak_pointer (&priv->container, container); g_set_weak_pointer (&priv->container, container);
clutter_actor_add_child (CLUTTER_ACTOR (self), container); clutter_actor_add_child (CLUTTER_ACTOR (self), container);
priv->workspace_groups = g_ptr_array_new_with_free_func (g_object_unref); priv->workspace_groups = g_ptr_array_new_with_free_func (g_object_unref);
g_object_freeze_notify (G_OBJECT (self));
g_signal_connect_swapped (priv->workspace_manager,
"notify::layout-rows", G_CALLBACK (layout_rows_changed),
self);
layout_rows_changed (self);
g_signal_connect_swapped (priv->theme_context,
"notify::scale-factor", G_CALLBACK (scale_factor_changed),
self);
scale_factor_changed (self);
g_signal_connect_swapped (self,
"notify::text-direction", G_CALLBACK (text_direction_changed),
self);
text_direction_changed (self);
g_object_thaw_notify (G_OBJECT (self));
} }
float float
shell_monitor_group_get_base_distance (ShellMonitorGroup *self) shell_monitor_group_get_base_distance (ShellMonitorGroup *self)
{ {
ShellMonitorGroupPrivate *priv; ShellMonitorGroupPrivate *priv;
ShellGlobal *global = shell_global_get ();
StThemeContext *context;
int scale, spacing, rows;
g_return_val_if_fail (SHELL_IS_MONITOR_GROUP (self), 0.0); g_return_val_if_fail (SHELL_IS_MONITOR_GROUP (self), 0.0);
priv = shell_monitor_group_get_instance_private (self); priv = shell_monitor_group_get_instance_private (self);
context = st_theme_context_get_for_stage (shell_global_get_stage (global));
scale = st_theme_context_get_scale_factor (context);
/* TODO: Add mutter API? */
g_object_get (shell_global_get_workspace_manager (global),
"layout-rows", &rows,
NULL);
spacing = WORKSPACE_SPACING * scale;
if (rows == -1)
return priv->height + spacing;
return priv->width + spacing; return priv->base_distance;
}
static float
get_progress_from_actor (ShellMonitorGroup *self,
ClutterActor *actor)
{
ShellMonitorGroupPrivate *priv =
shell_monitor_group_get_instance_private (self);
if (priv->is_vertical)
return clutter_actor_get_y (actor) / priv->base_distance;
else if (priv->is_rtl)
return -clutter_actor_get_x (actor) / priv->base_distance;
else
return clutter_actor_get_x (actor) / priv->base_distance;
} }
float float
shell_monitor_group_get_progress (ShellMonitorGroup *self) shell_monitor_group_get_progress (ShellMonitorGroup *self)
{ {
ShellMonitorGroupPrivate *priv; ShellMonitorGroupPrivate *priv;
ShellGlobal *global = shell_global_get ();
int rows;
float base_distance;
g_return_val_if_fail (SHELL_IS_MONITOR_GROUP (self), 0.0); g_return_val_if_fail (SHELL_IS_MONITOR_GROUP (self), 0.0);
priv = shell_monitor_group_get_instance_private (self); priv = shell_monitor_group_get_instance_private (self);
/* TODO: Add mutter API? */ return -get_progress_from_actor (self, priv->container);
g_object_get (shell_global_get_workspace_manager (global),
"layout-rows", &rows,
NULL);
base_distance = shell_monitor_group_get_base_distance (self);
if (rows == -1)
return -clutter_actor_get_y (priv->container) / base_distance;
else if (clutter_actor_get_text_direction (CLUTTER_ACTOR (self)) == CLUTTER_TEXT_DIRECTION_RTL)
return clutter_actor_get_x (priv->container) / base_distance;
else
return -clutter_actor_get_x (priv->container) / base_distance;
} }
void void
@ -236,54 +333,21 @@ shell_monitor_group_set_progress (ShellMonitorGroup *self,
float progress) float progress)
{ {
ShellMonitorGroupPrivate *priv; ShellMonitorGroupPrivate *priv;
ShellGlobal *global = shell_global_get ();
int rows;
float base_distance;
g_return_if_fail (SHELL_IS_MONITOR_GROUP (self)); g_return_if_fail (SHELL_IS_MONITOR_GROUP (self));
priv = shell_monitor_group_get_instance_private (self); priv = shell_monitor_group_get_instance_private (self);
/* TODO: Add mutter API? */ if (priv->is_vertical)
g_object_get (shell_global_get_workspace_manager (global), clutter_actor_set_y (priv->container, -roundf (progress * priv->base_distance));
"layout-rows", &rows, else if (priv->is_rtl)
NULL); clutter_actor_set_x (priv->container, roundf (progress * priv->base_distance));
base_distance = shell_monitor_group_get_base_distance (self);
if (rows == -1)
clutter_actor_set_y (priv->container, -roundf (progress * base_distance));
else if (clutter_actor_get_text_direction (CLUTTER_ACTOR (self)) == CLUTTER_TEXT_DIRECTION_RTL)
clutter_actor_set_x (priv->container, roundf (progress * base_distance));
else else
clutter_actor_set_x (priv->container, -roundf (progress * base_distance)); clutter_actor_set_x (priv->container, -roundf (progress * priv->base_distance));
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PROGRESS]); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PROGRESS]);
} }
static float
get_workspace_group_progress (ShellMonitorGroup *self,
ShellWorkspaceGroup *group)
{
ShellGlobal *global = shell_global_get ();
int rows;
float base_distance;
/* TODO: Add mutter API? */
g_object_get (shell_global_get_workspace_manager (global),
"layout-rows", &rows,
NULL);
base_distance = shell_monitor_group_get_base_distance (self);
if (rows == -1)
return clutter_actor_get_y (CLUTTER_ACTOR (group)) / base_distance;
else if (clutter_actor_get_text_direction (CLUTTER_ACTOR (self)) == CLUTTER_TEXT_DIRECTION_RTL)
return -clutter_actor_get_x (CLUTTER_ACTOR (group)) / base_distance;
else
return clutter_actor_get_x (CLUTTER_ACTOR (group)) / base_distance;
}
float float
shell_monitor_group_get_workspace_progress (ShellMonitorGroup *self, shell_monitor_group_get_workspace_progress (ShellMonitorGroup *self,
MetaWorkspace *workspace) MetaWorkspace *workspace)
@ -304,7 +368,8 @@ shell_monitor_group_get_workspace_progress (ShellMonitorGroup *self,
workspace_group = g_ptr_array_index (priv->workspace_groups, i); workspace_group = g_ptr_array_index (priv->workspace_groups, i);
if (meta_workspace_index (shell_workspace_group_get_workspace (workspace_group)) == target_index) if (meta_workspace_index (shell_workspace_group_get_workspace (workspace_group)) == target_index)
return get_workspace_group_progress (self, workspace_group); return get_progress_from_actor (self,
CLUTTER_ACTOR (workspace_group));
} }
g_return_val_if_reached (0.0); g_return_val_if_reached (0.0);
@ -334,7 +399,8 @@ shell_monitor_group_get_snap_points (ShellMonitorGroup *self,
data = g_new0 (float, priv->workspace_groups->len + 1); data = g_new0 (float, priv->workspace_groups->len + 1);
for (size_t i = 0; i < priv->workspace_groups->len; i++) for (size_t i = 0; i < priv->workspace_groups->len; i++)
data[i] = get_workspace_group_progress (self, g_ptr_array_index (priv->workspace_groups, i)); data[i] = get_progress_from_actor (self,
g_ptr_array_index (priv->workspace_groups, i));
*points = data; *points = data;
} }
@ -433,7 +499,7 @@ shell_monitor_group_find_closest_workspace (ShellMonitorGroup *self,
for (size_t i = 0; i < priv->workspace_groups->len; i++) for (size_t i = 0; i < priv->workspace_groups->len; i++)
{ {
group = g_ptr_array_index (priv->workspace_groups, i); group = g_ptr_array_index (priv->workspace_groups, i);
distance = get_workspace_group_progress (self, group); distance = get_progress_from_actor (self, CLUTTER_ACTOR (group));
value = fabsf (distance - progress); value = fabsf (distance - progress);
if (G_UNLIKELY (min_distance < 0)) if (G_UNLIKELY (min_distance < 0))