mirror of
https://github.com/edu4rdshl/gnome-shell.git
synced 2026-07-17 23:24:51 +00:00
Move MonitorGroup from JS to C
Mostly, anyway. This commit does a fairly 1:1 port of the objects methods, leaving the constructor in JS land, with the goal of cutting down on the time spent in `_interpolateProgress` (which has been sufficient to drop frames)
This commit is contained in:
parent
4bcad31904
commit
fbce396f4a
4 changed files with 531 additions and 117 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
453
src/shell-monitor-group.c
Normal file
453
src/shell-monitor-group.c
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
/* shell-monitor-group.c
|
||||
*
|
||||
* Copyright 2023 Zander Brown <zbrown@gnome.org>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
57
src/shell-monitor-group.h
Normal file
57
src/shell-monitor-group.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* shell-monitor-group.h
|
||||
*
|
||||
* Copyright 2023 Zander Brown <zbrown@gnome.org>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <st/st.h>
|
||||
#include <meta/workspace.h>
|
||||
|
||||
#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
|
||||
Loading…
Add table
Add a link
Reference in a new issue