diff --git a/js/ui/workspaceAnimation.js b/js/ui/workspaceAnimation.js index c64dae58b..e4e58b989 100644 --- a/js/ui/workspaceAnimation.js +++ b/js/ui/workspaceAnimation.js @@ -4,7 +4,6 @@ import Clutter from 'gi://Clutter'; import GObject from 'gi://GObject'; import Meta from 'gi://Meta'; import Shell from 'gi://Shell'; -import St from 'gi://St'; import * as Background from './background.js'; import * as Layout from './layout.js'; @@ -14,7 +13,6 @@ import * as Util from '../misc/util.js'; import * as Main from './main.js'; const WINDOW_ANIMATION_TIME = 250; -export const WORKSPACE_SPACING = 100; export const WorkspaceGroup = GObject.registerClass( class WorkspaceGroup extends Shell.WorkspaceGroup { @@ -141,33 +139,23 @@ class WorkspaceGroup extends Shell.WorkspaceGroup { } }); -export const MonitorGroup = GObject.registerClass({ - Properties: { - 'progress': GObject.ParamSpec.double( - 'progress', 'progress', 'progress', - GObject.ParamFlags.READWRITE, - -Infinity, Infinity, 0), - }, -}, class MonitorGroup extends St.Widget { +export const MonitorGroup = GObject.registerClass( +class MonitorGroup extends Shell.MonitorGroup { _init(monitor, workspaceIndices, movingWindow) { super._init({ clip_to_allocation: true, style_class: 'workspace-animation', + index: monitor.index, + monitor_width: monitor.width, + monitor_height: monitor.height, }); - this._monitor = monitor; - const constraint = new Layout.MonitorConstraint({index: monitor.index}); this.add_constraint(constraint); - this._container = new Clutter.Actor(); - this.add_child(this._container); - const stickyGroup = new WorkspaceGroup(null, monitor, movingWindow); this.add_child(stickyGroup); - this._workspaceGroups = []; - const workspaceManager = global.workspace_manager; const vertical = workspaceManager.layout_rows === -1; const activeWorkspace = workspaceManager.get_active_workspace(); @@ -186,21 +174,17 @@ export const MonitorGroup = GObject.registerClass({ y -= Main.panel.height; } - const group = new WorkspaceGroup(ws, monitor, movingWindow); - - this._workspaceGroups.push(group); - this._container.add_child(group); - group.set_position(x, y); + this.add_group(new WorkspaceGroup(ws, monitor, movingWindow), x, y); if (vertical) - y += this.baseDistance; + y += this.base_distance; else if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL) - x -= this.baseDistance; + x -= this.base_distance; else - x += this.baseDistance; + x += this.base_distance; } - this.progress = this.getWorkspaceProgress(activeWorkspace); + this.progress = this.get_workspace_progress(activeWorkspace); if (monitor.index === Main.layoutManager.primaryIndex) { this._workspacesAdjustment = Main.createWorkspacesAdjustment(this); @@ -221,88 +205,6 @@ export const MonitorGroup = GObject.registerClass({ }); } } - - get baseDistance() { - const spacing = WORKSPACE_SPACING * St.ThemeContext.get_for_stage(global.stage).scale_factor; - - if (global.workspace_manager.layout_rows === -1) - return this._monitor.height + spacing; - else - return this._monitor.width + spacing; - } - - get progress() { - if (global.workspace_manager.layout_rows === -1) - return -this._container.y / this.baseDistance; - else if (this.get_text_direction() === Clutter.TextDirection.RTL) - return this._container.x / this.baseDistance; - else - return -this._container.x / this.baseDistance; - } - - set progress(p) { - if (global.workspace_manager.layout_rows === -1) - this._container.y = -Math.round(p * this.baseDistance); - else if (this.get_text_direction() === Clutter.TextDirection.RTL) - this._container.x = Math.round(p * this.baseDistance); - else - this._container.x = -Math.round(p * this.baseDistance); - - this.notify('progress'); - } - - get index() { - return this._monitor.index; - } - - getWorkspaceProgress(workspace) { - const group = this._workspaceGroups.find(g => - g.workspace.index() === workspace.index()); - return this._getWorkspaceGroupProgress(group); - } - - _getWorkspaceGroupProgress(group) { - if (global.workspace_manager.layout_rows === -1) - return group.y / this.baseDistance; - else if (this.get_text_direction() === Clutter.TextDirection.RTL) - return -group.x / this.baseDistance; - else - return group.x / this.baseDistance; - } - - getSnapPoints() { - return this._workspaceGroups.map(g => - this._getWorkspaceGroupProgress(g)); - } - - findClosestWorkspace(progress) { - const distances = this.getSnapPoints().map(p => - Math.abs(p - progress)); - const index = distances.indexOf(Math.min(...distances)); - return this._workspaceGroups[index].workspace; - } - - _interpolateProgress(progress, monitorGroup) { - if (this.index === monitorGroup.index) - return progress; - - const points1 = monitorGroup.getSnapPoints(); - const points2 = this.getSnapPoints(); - - const upper = points1.indexOf(points1.find(p => p >= progress)); - const lower = points1.indexOf(points1.slice().reverse().find(p => p <= progress)); - - if (points1[upper] === points1[lower]) - return points2[upper]; - - const t = (progress - points1[lower]) / (points1[upper] - points1[lower]); - - return points2[lower] + (points2[upper] - points2[lower]) * t; - } - - updateSwipeForMonitor(progress, monitorGroup) { - this.progress = this._interpolateProgress(progress, monitorGroup); - } }); export class WorkspaceAnimationController { @@ -414,8 +316,8 @@ export class WorkspaceAnimationController { const toWs = global.workspace_manager.get_workspace_by_index(to); for (const monitorGroup of this._switchData.monitors) { - monitorGroup.progress = monitorGroup.getWorkspaceProgress(fromWs); - const progress = monitorGroup.getWorkspaceProgress(toWs); + monitorGroup.progress = monitorGroup.get_workspace_progress(fromWs); + const progress = monitorGroup.get_workspace_progress(toWs); const params = { duration: WINDOW_ANIMATION_TIME, @@ -461,12 +363,12 @@ export class WorkspaceAnimationController { } const monitorGroup = this._findMonitorGroup(monitor); - const baseDistance = monitorGroup.baseDistance; + const baseDistance = monitorGroup.base_distance; const progress = monitorGroup.progress; - const closestWs = monitorGroup.findClosestWorkspace(progress); - const cancelProgress = monitorGroup.getWorkspaceProgress(closestWs); - const points = monitorGroup.getSnapPoints(); + const closestWs = monitorGroup.find_closest_workspace(progress); + const cancelProgress = monitorGroup.get_workspace_progress(closestWs); + const points = monitorGroup.get_snap_points(); this._switchData.baseMonitorGroup = monitorGroup; @@ -478,7 +380,7 @@ export class WorkspaceAnimationController { return; for (const monitorGroup of this._switchData.monitors) - monitorGroup.updateSwipeForMonitor(progress, this._switchData.baseMonitorGroup); + monitorGroup.update_swipe_for_monitor(progress, this._switchData.baseMonitorGroup); } _switchWorkspaceEnd(tracker, duration, endProgress) { @@ -488,11 +390,11 @@ export class WorkspaceAnimationController { const switchData = this._switchData; switchData.gestureActivated = true; - const newWs = switchData.baseMonitorGroup.findClosestWorkspace(endProgress); + const newWs = switchData.baseMonitorGroup.find_closest_workspace(endProgress); const endTime = Clutter.get_current_event_time(); for (const monitorGroup of this._switchData.monitors) { - const progress = monitorGroup.getWorkspaceProgress(newWs); + const progress = monitorGroup.get_workspace_progress(newWs); const params = { duration, diff --git a/src/meson.build b/src/meson.build index ba8501b40..e9c7380f5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -104,6 +104,7 @@ libshell_public_headers = [ 'shell-global.h', 'shell-invert-lightness-effect.h', 'shell-action-modes.h', + 'shell-monitor-group.h', 'shell-mount-operation.h', 'shell-perf-log.h', 'shell-screenshot.h', @@ -146,6 +147,7 @@ libshell_sources = [ 'shell-invert-lightness-effect.c', 'shell-keyring-prompt.c', 'shell-keyring-prompt.h', + 'shell-monitor-group.c', 'shell-mount-operation.c', 'shell-perf-log.c', 'shell-polkit-authentication-agent.c', diff --git a/src/shell-monitor-group.c b/src/shell-monitor-group.c new file mode 100644 index 000000000..d9cfe59d2 --- /dev/null +++ b/src/shell-monitor-group.c @@ -0,0 +1,453 @@ +/* shell-monitor-group.c + * + * Copyright 2023 Zander Brown + * + * 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 3 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include + +#include "shell-monitor-group.h" +#include "shell-workspace-group.h" +#include "shell-global.h" + +#define WORKSPACE_SPACING 100 + +typedef struct _ShellMonitorGroupPrivate ShellMonitorGroupPrivate; +struct _ShellMonitorGroupPrivate +{ + ClutterActor *container; + GPtrArray *workspace_groups; + + int index, width, height; +}; + +enum +{ + PROP_0, + + PROP_INDEX, + PROP_MONITOR_WIDTH, + PROP_MONITOR_HEIGHT, + PROP_PROGRESS, + PROP_BASE_DISTANCE, + + PROP_LAST +}; + +static GParamSpec *obj_props[PROP_LAST] = { NULL, }; + +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ShellMonitorGroup, shell_monitor_group, ST_TYPE_WIDGET) + +static void +shell_monitor_group_dispose (GObject *object) +{ + ShellMonitorGroupPrivate *priv = + shell_monitor_group_get_instance_private (SHELL_MONITOR_GROUP (object)); + + g_clear_weak_pointer (&priv->container); + g_clear_pointer (&priv->workspace_groups, g_ptr_array_unref); + + G_OBJECT_CLASS (shell_monitor_group_parent_class)->dispose (object); +} + +static void +shell_monitor_group_set_property (GObject *object, + unsigned int property_id, + const GValue *value, + GParamSpec *pspec) +{ + ShellMonitorGroupPrivate *priv = + shell_monitor_group_get_instance_private (SHELL_MONITOR_GROUP (object)); + + switch (property_id) + { + case PROP_INDEX: + priv->index = g_value_get_int (value); + 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), + g_value_get_double (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +shell_monitor_group_get_property (GObject *object, + unsigned int property_id, + GValue *value, + GParamSpec *pspec) +{ + ShellMonitorGroup *self = SHELL_MONITOR_GROUP (object); + ShellMonitorGroupPrivate *priv = + shell_monitor_group_get_instance_private (self); + + switch (property_id) + { + case PROP_INDEX: + g_value_set_int (value, priv->index); + break; + case PROP_MONITOR_WIDTH: + g_value_set_int (value, priv->width); + break; + case PROP_MONITOR_HEIGHT: + g_value_set_int (value, priv->height); + break; + case PROP_PROGRESS: + g_value_set_double (value, + shell_monitor_group_get_progress (self)); + break; + case PROP_BASE_DISTANCE: + g_value_set_double (value, + shell_monitor_group_get_base_distance (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +shell_monitor_group_class_init (ShellMonitorGroupClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (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; + + obj_props[PROP_INDEX] = + g_param_spec_int ("index", NULL, NULL, + 0, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_props[PROP_MONITOR_WIDTH] = + g_param_spec_int ("monitor-width", NULL, NULL, + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_props[PROP_MONITOR_HEIGHT] = + g_param_spec_int ("monitor-height", NULL, NULL, + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_props[PROP_PROGRESS] = + g_param_spec_double ("progress", NULL, NULL, + -INFINITY, INFINITY, 0.0, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + obj_props[PROP_BASE_DISTANCE] = + g_param_spec_double ("base-distance", NULL, NULL, + -INFINITY, INFINITY, 0.0, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PROP_LAST, obj_props); +} + +static void +shell_monitor_group_init (ShellMonitorGroup *self) +{ + ShellMonitorGroupPrivate *priv = + shell_monitor_group_get_instance_private (self); + ClutterActor *container = clutter_actor_new (); + + 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); +} + +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; +} + +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; +} + +void +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)); + else + clutter_actor_set_x (priv->container, -roundf (progress * 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) +{ + ShellMonitorGroupPrivate *priv; + ShellWorkspaceGroup *workspace_group; + int target_index; + + g_return_val_if_fail (SHELL_IS_MONITOR_GROUP (self), 0.0); + g_return_val_if_fail (META_IS_WORKSPACE (workspace), 0.0); + + priv = shell_monitor_group_get_instance_private (self); + + target_index = meta_workspace_index (workspace); + + for (size_t i = 0; i < priv->workspace_groups->len; i++) + { + 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); + } + + g_return_val_if_reached (0.0); +} + +/** + * shell_monitor_group_get_snap_points: + * @self: the #ShellMonitorGroup + * @n_points: length of @points + * @points: (array length=n_points) (out): array of snap points + */ +void +shell_monitor_group_get_snap_points (ShellMonitorGroup *self, + size_t *n_points, + float *points[]) +{ + ShellMonitorGroupPrivate *priv; + float *data; + + g_return_if_fail (SHELL_IS_MONITOR_GROUP (self)); + g_return_if_fail (n_points != NULL); + g_return_if_fail (points != NULL); + + priv = shell_monitor_group_get_instance_private (self); + + *n_points = priv->workspace_groups->len; + 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)); + + *points = data; +} + +void +shell_monitor_group_add_group (ShellMonitorGroup *self, + ShellWorkspaceGroup *group, + float x, + float y) +{ + ShellMonitorGroupPrivate *priv; + + g_return_if_fail (SHELL_IS_MONITOR_GROUP (self)); + g_return_if_fail (SHELL_IS_WORKSPACE_GROUP (group)); + + priv = shell_monitor_group_get_instance_private (self); + + g_ptr_array_add (priv->workspace_groups, g_object_ref (group)); + clutter_actor_add_child (priv->container, CLUTTER_ACTOR (group)); + clutter_actor_set_position (CLUTTER_ACTOR (group), x, y); +} + +static float +interpolate_progress (ShellMonitorGroup *self, + float progress, + ShellMonitorGroup *monitor_group) +{ + ShellMonitorGroupPrivate *priv = + shell_monitor_group_get_instance_private (self); + ShellMonitorGroupPrivate *monitor_group_priv = + shell_monitor_group_get_instance_private (monitor_group); + size_t points1_len, points2_len; + g_autofree float *points1 = NULL, *points2 = NULL; + size_t upper = 0, lower = 0; + float t; + + if (priv->index == monitor_group_priv->index) + return progress; + + shell_monitor_group_get_snap_points (monitor_group, &points1_len, &points1); + shell_monitor_group_get_snap_points (self, &points2_len, &points2); + + for (size_t i = 0; i < points1_len; i++) + if (points1[i] >= progress) + { + upper = i; + break; + } + + for (size_t i = points2_len - 1; i >= 0; i--) + if (points2[i] <= progress) + { + lower = i; + break; + } + + if (G_APPROX_VALUE (points1[upper], points1[lower], FLT_EPSILON)) + return points2[upper]; + + t = (progress - points1[lower]) / (points1[upper] - points1[lower]); + + return points2[lower] + (points2[upper] - points2[lower]) * t; +} + +void +shell_monitor_group_update_swipe_for_monitor (ShellMonitorGroup *self, + float progress, + ShellMonitorGroup *monitor_group) +{ + g_return_if_fail (SHELL_IS_MONITOR_GROUP (self)); + g_return_if_fail (SHELL_IS_MONITOR_GROUP (monitor_group)); + + shell_monitor_group_set_progress (self, + interpolate_progress (self, progress, monitor_group)); +} + +/** + * shell_monitor_group_find_closest_workspace: + * @self: the #ShellMonitorGroup + * @progress: current progress + * + * Returns: (transfer none): the #MetaWorkspace + */ +MetaWorkspace * +shell_monitor_group_find_closest_workspace (ShellMonitorGroup *self, + float progress) +{ + ShellMonitorGroupPrivate *priv; + ShellWorkspaceGroup *group, *min_group = NULL; + float min_distance = -1.0, distance, value; + + g_return_val_if_fail (SHELL_IS_MONITOR_GROUP (self), NULL); + + priv = shell_monitor_group_get_instance_private (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); + value = fabsf (distance - progress); + + if (G_UNLIKELY (min_distance < 0)) + { + min_distance = value; + min_group = group; + } + else + { + min_distance = MIN (min_distance, value); + if (G_APPROX_VALUE (min_distance, value, FLT_EPSILON)) + min_group = group; + } + } + + return shell_workspace_group_get_workspace (min_group); +} diff --git a/src/shell-monitor-group.h b/src/shell-monitor-group.h new file mode 100644 index 000000000..dc75a6ef9 --- /dev/null +++ b/src/shell-monitor-group.h @@ -0,0 +1,57 @@ +/* shell-monitor-group.h + * + * Copyright 2023 Zander Brown + * + * 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 3 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include +#include + +#include "shell-workspace-group.h" + +G_BEGIN_DECLS + +#define SHELL_TYPE_MONITOR_GROUP (shell_monitor_group_get_type ()) +G_DECLARE_DERIVABLE_TYPE (ShellMonitorGroup, shell_monitor_group, SHELL, MONITOR_GROUP, StWidget) + +struct _ShellMonitorGroupClass +{ + StWidgetClass parent_class; +}; + +float shell_monitor_group_get_base_distance (ShellMonitorGroup *self); +float shell_monitor_group_get_progress (ShellMonitorGroup *self); +void shell_monitor_group_set_progress (ShellMonitorGroup *self, + float progress); +float shell_monitor_group_get_workspace_progress (ShellMonitorGroup *self, + MetaWorkspace *workspace); +void shell_monitor_group_get_snap_points (ShellMonitorGroup *self, + size_t *n_points, + float *points[]); +void shell_monitor_group_add_group (ShellMonitorGroup *self, + ShellWorkspaceGroup *group, + float x, + float y); +void shell_monitor_group_update_swipe_for_monitor (ShellMonitorGroup *self, + float progress, + ShellMonitorGroup *monitor_group); +MetaWorkspace *shell_monitor_group_find_closest_workspace (ShellMonitorGroup *self, + float progress); + +G_END_DECLS