diff --git a/src/shell-monitor-group.c b/src/shell-monitor-group.c index d9cfe59d2..5aa1bfabd 100644 --- a/src/shell-monitor-group.c +++ b/src/shell-monitor-group.c @@ -31,10 +31,18 @@ typedef struct _ShellMonitorGroupPrivate ShellMonitorGroupPrivate; struct _ShellMonitorGroupPrivate { + ShellGlobal *global; + MetaWorkspaceManager *workspace_manager; + StThemeContext *theme_context; + ClutterActor *container; GPtrArray *workspace_groups; - + int index, width, height; + float base_distance; + + gboolean is_vertical; + gboolean is_rtl; }; enum @@ -60,6 +68,16 @@ shell_monitor_group_dispose (GObject *object) ShellMonitorGroupPrivate *priv = 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_pointer (&priv->workspace_groups, g_ptr_array_unref); @@ -82,11 +100,9 @@ shell_monitor_group_set_property (GObject *object, break; case PROP_MONITOR_WIDTH: priv->width = g_value_get_int (value); - clutter_actor_set_size (CLUTTER_ACTOR (object), g_value_get_int (value), priv->height); break; case PROP_MONITOR_HEIGHT: priv->height = g_value_get_int (value); - clutter_actor_set_size (CLUTTER_ACTOR (object), priv->width, g_value_get_int (value)); break; case PROP_PROGRESS: 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 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->set_property = shell_monitor_group_set_property; object_class->get_property = shell_monitor_group_get_property; + object_class->constructed = shell_monitor_group_constructed; obj_props[PROP_INDEX] = 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); } +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 shell_monitor_group_init (ShellMonitorGroup *self) { ShellMonitorGroupPrivate *priv = 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 (); + 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); clutter_actor_add_child (CLUTTER_ACTOR (self), container); 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 shell_monitor_group_get_base_distance (ShellMonitorGroup *self) { 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); 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 shell_monitor_group_get_progress (ShellMonitorGroup *self) { ShellMonitorGroupPrivate *priv; - ShellGlobal *global = shell_global_get (); - int rows; - float base_distance; g_return_val_if_fail (SHELL_IS_MONITOR_GROUP (self), 0.0); priv = shell_monitor_group_get_instance_private (self); - /* 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 (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; + return -get_progress_from_actor (self, priv->container); } void @@ -236,54 +333,21 @@ shell_monitor_group_set_progress (ShellMonitorGroup *self, float progress) { ShellMonitorGroupPrivate *priv; - ShellGlobal *global = shell_global_get (); - int rows; - float base_distance; g_return_if_fail (SHELL_IS_MONITOR_GROUP (self)); priv = shell_monitor_group_get_instance_private (self); - /* 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) - 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)); + if (priv->is_vertical) + clutter_actor_set_y (priv->container, -roundf (progress * priv->base_distance)); + else if (priv->is_rtl) + clutter_actor_set_x (priv->container, roundf (progress * priv->base_distance)); 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]); } -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 shell_monitor_group_get_workspace_progress (ShellMonitorGroup *self, MetaWorkspace *workspace) @@ -304,7 +368,8 @@ shell_monitor_group_get_workspace_progress (ShellMonitorGroup *self, workspace_group = g_ptr_array_index (priv->workspace_groups, i); 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); @@ -334,7 +399,8 @@ shell_monitor_group_get_snap_points (ShellMonitorGroup *self, data = g_new0 (float, priv->workspace_groups->len + 1); 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; } @@ -433,7 +499,7 @@ shell_monitor_group_find_closest_workspace (ShellMonitorGroup *self, for (size_t i = 0; i < priv->workspace_groups->len; 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); if (G_UNLIKELY (min_distance < 0))