Move WorkspaceIndicators from JS to C

This avoids calling JS when switching workspace

Of course when adding/removing workspaces we still hit JS for ease(),
but this should keep us in C for more ‘idle’ cases
This commit is contained in:
Zander Brown 2023-10-24 19:02:32 +01:00
parent e6b101f9e2
commit e1763f630a
No known key found for this signature in database
GPG key ID: 25EE3C36E31E5F84
4 changed files with 300 additions and 56 deletions

View file

@ -285,61 +285,11 @@ class WorkspaceDot extends Shell.WorkspaceDot {
});
const WorkspaceIndicators = GObject.registerClass(
class WorkspaceIndicators extends St.BoxLayout {
constructor() {
super();
this._workspacesAdjustment = Main.createWorkspacesAdjustment(this);
this._workspacesAdjustment.connectObject(
'notify::value', () => this._updateExpansion(),
'notify::upper', () => this._recalculateDots(),
this);
for (let i = 0; i < this._workspacesAdjustment.upper; i++)
this.insert_child_at_index(new WorkspaceDot(), i);
this._updateExpansion();
}
_getActiveIndicators() {
return [...this].filter(i => !i.destroying);
}
_recalculateDots() {
const activeIndicators = this._getActiveIndicators();
const nIndicators = activeIndicators.length;
const targetIndicators = this._workspacesAdjustment.upper;
let remaining = Math.abs(nIndicators - targetIndicators);
while (remaining--) {
if (nIndicators < targetIndicators) {
const indicator = new WorkspaceDot();
this.add_child(indicator);
indicator.scale_in();
} else {
const indicator = activeIndicators[nIndicators - remaining - 1];
indicator.scale_out_and_destroy();
}
}
this._updateExpansion();
}
_updateExpansion() {
const nIndicators = this._getActiveIndicators().length;
const activeWorkspace = this._workspacesAdjustment.value;
let widthMultiplier;
if (nIndicators <= 2)
widthMultiplier = 3.625;
else if (nIndicators <= 5)
widthMultiplier = 3.25;
else
widthMultiplier = 2.75;
this.get_children().forEach((indicator, index) => {
const distance = Math.abs(index - activeWorkspace);
indicator.expansion = Math.clamp(1 - distance, 0, 1);
indicator.widthMultiplier = widthMultiplier;
class WorkspaceIndicators extends Shell.WorkspaceIndicators {
constructor(params = {}) {
super({
dot_type: WorkspaceDot.$gtype,
...params,
});
}
});
@ -357,7 +307,9 @@ class ActivitiesButton extends PanelMenu.Button {
accessible_name: _('Activities'),
});
this.add_child(new WorkspaceIndicators());
this.add_child(new WorkspaceIndicators({
workspaces_adjustment: Main.createWorkspacesAdjustment(this),
}));
Main.overview.connect('showing', () => {
this.add_style_pseudo_class('checked');

View file

@ -118,6 +118,7 @@ libshell_public_headers = [
'shell-wm.h',
'shell-workspace-background.h',
'shell-workspace-dot.h',
'shell-workspace-indicators.h',
]
if have_networkmanager
@ -164,6 +165,7 @@ libshell_sources = [
'shell-wm.c',
'shell-workspace-background.c',
'shell-workspace-dot.c',
'shell-workspace-indicators.c',
]
if have_networkmanager

View file

@ -0,0 +1,253 @@
/* shell-workspace-dot.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-workspace-dot.h"
#include "shell-workspace-indicators.h"
typedef struct _ShellWorkspaceIndicatorsPrivate ShellWorkspaceIndicatorsPrivate;
struct _ShellWorkspaceIndicatorsPrivate
{
GType dot_type;
StAdjustment *workspaces_adjustment;
};
enum
{
PROP_0,
PROP_DOT_TYPE,
PROP_WORKSPACES_ADJUSTMENT,
PROP_LAST
};
static GParamSpec *obj_props[PROP_LAST] = { NULL, };
G_DEFINE_TYPE_WITH_PRIVATE (ShellWorkspaceIndicators, shell_workspace_indicators, ST_TYPE_BOX_LAYOUT)
static void
shell_workspace_indicators_dispose (GObject *object)
{
ShellWorkspaceIndicatorsPrivate *priv =
shell_workspace_indicators_get_instance_private (SHELL_WORKSPACE_INDICATORS (object));
g_clear_object (&priv->workspaces_adjustment);
G_OBJECT_CLASS (shell_workspace_indicators_parent_class)->dispose (object);
}
static GPtrArray *
get_active_dots (ShellWorkspaceIndicators *self)
{
GPtrArray *active = g_ptr_array_new ();
ClutterActor *child;
for (child = clutter_actor_get_first_child (CLUTTER_ACTOR (self));
child != NULL;
child = clutter_actor_get_next_sibling (child))
{
if (!shell_workspace_dot_is_destroying (SHELL_WORKSPACE_DOT (child)))
g_ptr_array_add (active, child);
}
return active;
}
static void
update_expansion (ShellWorkspaceIndicators *self)
{
ShellWorkspaceIndicatorsPrivate *priv;
g_autoptr (GPtrArray) active_dots = NULL;
size_t n_indicators;
double active_workspace, width_multiplier;
size_t index = 0;
g_return_if_fail (SHELL_IS_WORKSPACE_INDICATORS (self));
priv = shell_workspace_indicators_get_instance_private (self);
active_dots = get_active_dots (self);
n_indicators = active_dots->len;
active_workspace = st_adjustment_get_value (priv->workspaces_adjustment);
if (n_indicators <= 2)
width_multiplier = 3.625;
else if (n_indicators <= 5)
width_multiplier = 3.25;
else
width_multiplier = 2.75;
for (ClutterActor *child = clutter_actor_get_first_child (CLUTTER_ACTOR (self));
child != NULL;
index++, child = clutter_actor_get_next_sibling (child))
{
double distance = fabs (((double) index) - active_workspace);
g_object_set (child,
"expansion", CLAMP (1.0 - distance, 0.0, 1.0),
"width-multiplier", width_multiplier,
NULL);
}
}
static void
recalculate_dots (ShellWorkspaceIndicators *self)
{
ShellWorkspaceIndicatorsPrivate *priv =
shell_workspace_indicators_get_instance_private (self);
ShellWorkspaceDot *dot;
g_autoptr (GPtrArray) active_dots = get_active_dots (self);
size_t remaining;
double target;
st_adjustment_get_values (priv->workspaces_adjustment,
NULL,
NULL,
&target,
NULL,
NULL,
NULL);
remaining = abs (active_dots->len - target);
while (remaining--)
if (active_dots->len < target)
{
dot = g_object_new (priv->dot_type, NULL);
clutter_actor_add_child (CLUTTER_ACTOR (self), CLUTTER_ACTOR (dot));
shell_workspace_dot_scale_in (dot);
}
else
{
dot = g_ptr_array_index (active_dots,
active_dots->len - remaining - 1);
shell_workspace_dot_scale_out_and_destroy (dot);
}
update_expansion (self);
}
static void
shell_workspace_indicators_set_property (GObject *object,
unsigned int property_id,
const GValue *value,
GParamSpec *pspec)
{
ShellWorkspaceIndicators *self = SHELL_WORKSPACE_INDICATORS (object);
ShellWorkspaceIndicatorsPrivate *priv =
shell_workspace_indicators_get_instance_private (self);
ShellWorkspaceDot *dot;
double upper;
switch (property_id)
{
case PROP_DOT_TYPE:
priv->dot_type = g_value_get_gtype (value);
g_object_notify_by_pspec (object, pspec);
break;
case PROP_WORKSPACES_ADJUSTMENT:
priv->workspaces_adjustment = g_value_dup_object (value);
g_signal_connect_object (priv->workspaces_adjustment,
"notify::value",
G_CALLBACK (update_expansion),
object,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->workspaces_adjustment,
"notify::upper",
G_CALLBACK (recalculate_dots),
object,
G_CONNECT_SWAPPED);
st_adjustment_get_values (priv->workspaces_adjustment,
NULL,
NULL,
&upper,
NULL,
NULL,
NULL);
for (size_t i = 0; i < ((size_t) upper); i++)
{
dot = g_object_new (priv->dot_type, NULL);
clutter_actor_insert_child_at_index (CLUTTER_ACTOR (self),
CLUTTER_ACTOR (dot),
i);
}
update_expansion (self);
g_object_notify_by_pspec (object, pspec);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
shell_workspace_indicators_get_property (GObject *object,
unsigned int property_id,
GValue *value,
GParamSpec *pspec)
{
ShellWorkspaceIndicators *self = SHELL_WORKSPACE_INDICATORS (object);
ShellWorkspaceIndicatorsPrivate *priv =
shell_workspace_indicators_get_instance_private (self);
switch (property_id)
{
case PROP_DOT_TYPE:
g_value_set_gtype (value, priv->dot_type);
break;
case PROP_WORKSPACES_ADJUSTMENT:
g_value_set_object (value, priv->workspaces_adjustment);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
shell_workspace_indicators_class_init (ShellWorkspaceIndicatorsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = shell_workspace_indicators_dispose;
object_class->set_property = shell_workspace_indicators_set_property;
object_class->get_property = shell_workspace_indicators_get_property;
obj_props[PROP_DOT_TYPE] =
g_param_spec_gtype ("dot-type", NULL, NULL,
SHELL_TYPE_WORKSPACE_DOT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
obj_props[PROP_WORKSPACES_ADJUSTMENT] =
g_param_spec_object ("workspaces-adjustment", NULL, NULL,
ST_TYPE_ADJUSTMENT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, PROP_LAST, obj_props);
}
static void
shell_workspace_indicators_init (ShellWorkspaceIndicators *self)
{
}

View file

@ -0,0 +1,37 @@
/* shell-workspace-indicators.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 "shell-workspace-dot.h"
G_BEGIN_DECLS
#define SHELL_TYPE_WORKSPACE_INDICATORS (shell_workspace_indicators_get_type ())
G_DECLARE_DERIVABLE_TYPE (ShellWorkspaceIndicators, shell_workspace_indicators, SHELL, WORKSPACE_INDICATORS, StBoxLayout)
struct _ShellWorkspaceIndicatorsClass
{
StBoxLayoutClass parent_class;
};
G_END_DECLS