[gnome-shell] workspace: Port WorkspaceBackground allocate to C



commit 83564e59b3f041954238ffc89060adc84973bc98
Author: Ivan Molodetskikh <yalterz gmail com>
Date:   Sat Jul 9 22:13:15 2022 -0700

    workspace: Port WorkspaceBackground allocate to C
    
    WorkspaceBackground's allocate is a hot function called every frame
    during overview animations. Port it to C.
    
    While we're at it, cache the work area and the monitor geometry, which
    do not need to be re-fetched on every allocation.
    
    This reduces the average WorkspaceBackground allocation time from
    0.134 ms to 0.017 ms. With four workspaces, scrolling the overview sees
    an average WorkspacesView allocation time improvement from
    1.104 ms to 0.678 ms.
    
    Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2394>

 js/ui/workspace.js               |  57 ++--------
 src/meson.build                  |   6 +-
 src/shell-workspace-background.c | 226 +++++++++++++++++++++++++++++++++++++++
 src/shell-workspace-background.h |  14 +++
 4 files changed, 251 insertions(+), 52 deletions(-)
---
diff --git a/js/ui/workspace.js b/js/ui/workspace.js
index 0e22af59b6..0069cdd004 100644
--- a/js/ui/workspace.js
+++ b/js/ui/workspace.js
@@ -1,7 +1,7 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 /* exported Workspace */
 
-const { Clutter, GLib, GObject, Graphene, Meta, St } = imports.gi;
+const {Clutter, GLib, GObject, Graphene, Meta, Shell, St} = imports.gi;
 
 const Background = imports.ui.background;
 const DND = imports.ui.dnd;
@@ -24,7 +24,6 @@ var LAYOUT_SCALE_WEIGHT = 1;
 var LAYOUT_SPACE_WEIGHT = 0.1;
 
 const BACKGROUND_CORNER_RADIUS_PIXELS = 30;
-const BACKGROUND_MARGIN = 12;
 
 // Window Thumbnail Layout Algorithm
 // =================================
@@ -940,13 +939,13 @@ var WorkspaceLayout = GObject.registerClass({
 });
 
 var WorkspaceBackground = GObject.registerClass(
-class WorkspaceBackground extends St.Widget {
+class WorkspaceBackground extends Shell.WorkspaceBackground {
     _init(monitorIndex, stateAdjustment) {
         super._init({
             style_class: 'workspace-background',
-            layout_manager: new Clutter.BinLayout(),
             x_expand: true,
             y_expand: true,
+            monitor_index: monitorIndex,
         });
 
         this._monitorIndex = monitorIndex;
@@ -957,6 +956,10 @@ class WorkspaceBackground extends St.Widget {
             this._updateBorderRadius();
             this.queue_relayout();
         }, this);
+        this._stateAdjustment.bind_property(
+            'value', this, 'state-adjustment-value',
+            GObject.BindingFlags.SYNC_CREATE
+        );
 
         this._bin = new Clutter.Actor({
             layout_manager: new Clutter.BinLayout(),
@@ -1011,52 +1014,6 @@ class WorkspaceBackground extends St.Widget {
         this._bgManager.backgroundActor.content.set_rounded_clip_bounds(rect);
     }
 
-    vfunc_allocate(box) {
-        const [width, height] = box.get_size();
-        const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage);
-        const scaledHeight = height - (BACKGROUND_MARGIN * 2 * scaleFactor);
-        const scaledWidth = (scaledHeight / height) * width;
-
-        const scaledBox = box.copy();
-        scaledBox.set_origin(
-            box.x1 + (width - scaledWidth) / 2,
-            box.y1 + (height - scaledHeight) / 2);
-        scaledBox.set_size(scaledWidth, scaledHeight);
-
-        const progress = this._stateAdjustment.value;
-
-        if (progress === 1)
-            box = scaledBox;
-        else if (progress !== 0)
-            box = box.interpolate(scaledBox, progress);
-
-        this.set_allocation(box);
-
-        const themeNode = this.get_theme_node();
-        const contentBox = themeNode.get_content_box(box);
-
-        this._bin.allocate(contentBox);
-
-        const [contentWidth, contentHeight] = contentBox.get_size();
-        const monitor = Main.layoutManager.monitors[this._monitorIndex];
-        const [mX1, mX2] = [monitor.x, monitor.x + monitor.width];
-        const [mY1, mY2] = [monitor.y, monitor.y + monitor.height];
-        const [wX1, wX2] = [this._workarea.x, this._workarea.x + this._workarea.width];
-        const [wY1, wY2] = [this._workarea.y, this._workarea.y + this._workarea.height];
-        const xScale = contentWidth / this._workarea.width;
-        const yScale = contentHeight / this._workarea.height;
-        const leftOffset = wX1 - mX1;
-        const topOffset = wY1 - mY1;
-        const rightOffset = mX2 - wX2;
-        const bottomOffset = mY2 - wY2;
-
-        contentBox.set_origin(-leftOffset * xScale, -topOffset * yScale);
-        contentBox.set_size(
-            contentWidth + (leftOffset + rightOffset) * xScale,
-            contentHeight + (topOffset + bottomOffset) * yScale);
-        this._backgroundGroup.allocate(contentBox);
-    }
-
     _onDestroy() {
         if (this._bgManager) {
             this._bgManager.destroy();
diff --git a/src/meson.build b/src/meson.build
index e784a5132f..fc7f8bfcce 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -112,7 +112,8 @@ libshell_public_headers = [
   'shell-window-preview.h',
   'shell-window-preview-layout.h',
   'shell-window-tracker.h',
-  'shell-wm.h'
+  'shell-wm.h',
+  'shell-workspace-background.h'
 ]
 
 if have_networkmanager
@@ -157,7 +158,8 @@ libshell_sources = [
   'shell-window-preview.c',
   'shell-window-preview-layout.c',
   'shell-window-tracker.c',
-  'shell-wm.c'
+  'shell-wm.c',
+  'shell-workspace-background.c'
 ]
 
 if have_networkmanager
diff --git a/src/shell-workspace-background.c b/src/shell-workspace-background.c
new file mode 100644
index 0000000000..1c0bbc3800
--- /dev/null
+++ b/src/shell-workspace-background.c
@@ -0,0 +1,226 @@
+#include "config.h"
+
+#include "shell-workspace-background.h"
+
+#include "shell-global.h"
+#include <meta/meta-workspace-manager.h>
+
+#define BACKGROUND_MARGIN 12
+
+enum
+{
+  PROP_0,
+
+  PROP_MONITOR_INDEX,
+  PROP_STATE_ADJUSTMENT_VALUE,
+
+  PROP_LAST
+};
+
+static GParamSpec *obj_props[PROP_LAST] = { NULL, };
+
+struct _ShellWorkspaceBackground
+{
+  /*< private >*/
+  StWidget parent_instance;
+
+  int monitor_index;
+  double state_adjustment_value;
+
+  MetaRectangle work_area;
+  MetaRectangle monitor_geometry;
+};
+
+G_DEFINE_TYPE (ShellWorkspaceBackground, shell_workspace_background, ST_TYPE_WIDGET);
+
+static void
+on_workareas_changed (ShellWorkspaceBackground *self)
+{
+  ShellGlobal *global = shell_global_get ();
+  MetaDisplay *display = shell_global_get_display (global);
+  MetaWorkspaceManager *workspace_manager = shell_global_get_workspace_manager (global);
+  MetaWorkspace *workspace =
+    meta_workspace_manager_get_workspace_by_index (workspace_manager, 0);
+
+  meta_workspace_get_work_area_for_monitor (workspace,
+                                            self->monitor_index,
+                                            &self->work_area);
+
+  meta_display_get_monitor_geometry (display,
+                                     self->monitor_index,
+                                     &self->monitor_geometry);
+}
+
+static void
+shell_workspace_background_allocate (ClutterActor          *actor,
+                                     const ClutterActorBox *box)
+{
+  ShellWorkspaceBackground *self = SHELL_WORKSPACE_BACKGROUND (actor);
+  ShellGlobal *global = shell_global_get ();
+  ClutterStage *stage = shell_global_get_stage (global);
+  StThemeContext *context = st_theme_context_get_for_stage (stage);
+  StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
+  ClutterActorBox scaled_box, my_box, content_box;
+  ClutterActor *child;
+  float content_width, content_height;
+  float scaled_width, scaled_height;
+  float x_scale, y_scale;
+  float width, height;
+  int left_offset, right_offset;
+  int top_offset, bottom_offset;
+  int scale_factor;
+
+  scale_factor = st_theme_context_get_scale_factor (context);
+
+  clutter_actor_box_get_size (box, &width, &height);
+  scaled_height = height - BACKGROUND_MARGIN * 2 * scale_factor;
+  scaled_width = (scaled_height / height) * width;
+
+  scaled_box.x1 = box->x1 + (width - scaled_width) / 2;
+  scaled_box.y1 = box->y1 + (height - scaled_height) / 2;
+  clutter_actor_box_set_size (&scaled_box, scaled_width, scaled_height);
+
+  clutter_actor_box_interpolate(box, &scaled_box,
+                                self->state_adjustment_value, &my_box);
+
+  clutter_actor_set_allocation (actor, &my_box);
+
+  st_theme_node_get_content_box (theme_node, &my_box, &content_box);
+
+  child = clutter_actor_get_first_child (actor);
+  clutter_actor_allocate (child, &content_box);
+
+  clutter_actor_box_get_size (&content_box, &content_width, &content_height);
+  x_scale = content_width / self->work_area.width;
+  y_scale = content_height / self->work_area.height;
+
+  left_offset = self->work_area.x - self->monitor_geometry.x;
+  top_offset = self->work_area.y - self->monitor_geometry.y;
+  right_offset = self->monitor_geometry.width - self->work_area.width - left_offset;
+  bottom_offset = self->monitor_geometry.height - self->work_area.height - top_offset;
+
+  clutter_actor_box_set_origin (&content_box,
+                                -left_offset * x_scale,
+                                -top_offset * y_scale);
+  clutter_actor_box_set_size (&content_box,
+                              content_width + (left_offset + right_offset) * x_scale,
+                              content_height + (top_offset + bottom_offset) * y_scale);
+
+  child = clutter_actor_get_first_child (child);
+  clutter_actor_allocate (child, &content_box);
+}
+
+static void
+shell_workspace_background_constructed (GObject *object)
+{
+  G_OBJECT_CLASS (shell_workspace_background_parent_class)->constructed (object);
+
+  on_workareas_changed (SHELL_WORKSPACE_BACKGROUND (object));
+}
+
+static void
+shell_workspace_background_get_property (GObject      *gobject,
+                                         unsigned int  property_id,
+                                         GValue       *value,
+                                         GParamSpec   *pspec)
+{
+  ShellWorkspaceBackground *self = SHELL_WORKSPACE_BACKGROUND (gobject);
+
+  switch (property_id)
+    {
+    case PROP_MONITOR_INDEX:
+      g_value_set_int (value, self->monitor_index);
+      break;
+
+    case PROP_STATE_ADJUSTMENT_VALUE:
+      g_value_set_double (value, self->state_adjustment_value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
+    }
+}
+
+static void
+shell_workspace_background_set_property (GObject      *gobject,
+                                         unsigned int  property_id,
+                                         const GValue *value,
+                                         GParamSpec   *pspec)
+{
+  ShellWorkspaceBackground *self = SHELL_WORKSPACE_BACKGROUND (gobject);
+
+  switch (property_id)
+    {
+    case PROP_MONITOR_INDEX:
+      {
+        int new_value = g_value_get_int (value);
+        if (self->monitor_index != new_value)
+        {
+          self->monitor_index = new_value;
+          g_object_notify_by_pspec (gobject, obj_props[PROP_MONITOR_INDEX]);
+        }
+      }
+      break;
+
+    case PROP_STATE_ADJUSTMENT_VALUE:
+      {
+        double new_value = g_value_get_double (value);
+        if (self->state_adjustment_value != new_value)
+        {
+          self->state_adjustment_value = new_value;
+          g_object_notify_by_pspec (gobject, obj_props[PROP_STATE_ADJUSTMENT_VALUE]);
+        }
+      }
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
+    }
+}
+
+static void
+shell_workspace_background_class_init (ShellWorkspaceBackgroundClass *klass)
+{
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  actor_class->allocate = shell_workspace_background_allocate;
+
+  gobject_class->constructed = shell_workspace_background_constructed;
+  gobject_class->get_property = shell_workspace_background_get_property;
+  gobject_class->set_property = shell_workspace_background_set_property;
+
+  /**
+   * ShellWorkspaceBackground:monitor-index:
+   */
+  obj_props[PROP_MONITOR_INDEX] =
+    g_param_spec_int ("monitor-index", "", "",
+                      0, G_MAXINT, 0,
+                      G_PARAM_READWRITE |
+                      G_PARAM_CONSTRUCT_ONLY |
+                      G_PARAM_STATIC_STRINGS |
+                      G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * ShellWorkspaceBackground:state-adjustment-value:
+   */
+  obj_props[PROP_STATE_ADJUSTMENT_VALUE] =
+    g_param_spec_double ("state-adjustment-value", "", "",
+                         -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+                         G_PARAM_READWRITE |
+                         G_PARAM_STATIC_STRINGS |
+                         G_PARAM_EXPLICIT_NOTIFY);
+
+  g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
+}
+
+static void
+shell_workspace_background_init (ShellWorkspaceBackground *self)
+{
+  ShellGlobal *global = shell_global_get ();
+  MetaDisplay *display = shell_global_get_display (global);
+
+  g_signal_connect_object (display, "workareas-changed",
+                           G_CALLBACK (on_workareas_changed),
+                           self, G_CONNECT_SWAPPED);
+}
diff --git a/src/shell-workspace-background.h b/src/shell-workspace-background.h
new file mode 100644
index 0000000000..48b2bd68fa
--- /dev/null
+++ b/src/shell-workspace-background.h
@@ -0,0 +1,14 @@
+#ifndef __SHELL_WORKSPACE_BACKGROUND_H__
+#define __SHELL_WORKSPACE_BACKGROUND_H__
+
+#include <st/st.h>
+
+G_BEGIN_DECLS
+
+#define SHELL_TYPE_WORKSPACE_BACKGROUND (shell_workspace_background_get_type ())
+G_DECLARE_FINAL_TYPE (ShellWorkspaceBackground, shell_workspace_background,
+                      SHELL, WORKSPACE_BACKGROUND, StWidget)
+
+G_END_DECLS
+
+#endif /* __SHELL_WORKSPACE_BACKGROUND_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]