[gnome-shell] Move WindowPreviewLayout from JS to C
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] Move WindowPreviewLayout from JS to C
- Date: Tue, 9 Mar 2021 15:48:59 +0000 (UTC)
commit 04c781674c884935ff28805a690554f0c67605bd
Author: Jonas Dreßler <verdre v0yd nl>
Date: Sat Jun 20 17:22:30 2020 +0200
Move WindowPreviewLayout from JS to C
This layout manager is used quite often and the time we spend calling
it's allocate and get_preferred_width/heigth functions increases with
every open window.
We can save a lot of precious time during the layout cycle by moving
this layout manager from JS to C, thus avoiding the overhead of
trampolining between C and JS land.
In a measurement where the average time spent in vfunc_allocate() of the
Workspace actor was measured while opening an overview with 20 windows,
the average time spent went down from 3.1 ms to 2.3 ms.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1743>
js/ui/windowPreview.js | 182 +--------------
src/meson.build | 2 +
src/shell-window-preview-layout.c | 472 ++++++++++++++++++++++++++++++++++++++
src/shell-window-preview-layout.h | 33 +++
4 files changed, 511 insertions(+), 178 deletions(-)
---
diff --git a/js/ui/windowPreview.js b/js/ui/windowPreview.js
index bb97ebc635..3bd213959f 100644
--- a/js/ui/windowPreview.js
+++ b/js/ui/windowPreview.js
@@ -22,180 +22,6 @@ const ICON_OVERLAP = 0.7;
const ICON_TITLE_SPACING = 6;
-var WindowPreviewLayout = GObject.registerClass({
- Properties: {
- 'bounding-box': GObject.ParamSpec.boxed(
- 'bounding-box', 'Bounding box', 'Bounding box',
- GObject.ParamFlags.READABLE,
- Clutter.ActorBox.$gtype),
- },
-}, class WindowPreviewLayout extends Clutter.LayoutManager {
- _init() {
- super._init();
-
- this._container = null;
- this._boundingBox = new Clutter.ActorBox();
- this._windows = new Map();
- }
-
- _layoutChanged() {
- let frameRect;
-
- for (const windowInfo of this._windows.values()) {
- const frame = windowInfo.metaWindow.get_frame_rect();
- frameRect = frameRect?.union(frame) ?? frame;
- }
-
- if (!frameRect)
- frameRect = new Meta.Rectangle();
-
- const oldBox = this._boundingBox.copy();
- this._boundingBox.set_origin(frameRect.x, frameRect.y);
- this._boundingBox.set_size(frameRect.width, frameRect.height);
-
- if (!this._boundingBox.equal(oldBox))
- this.notify('bounding-box');
-
- // Always call layout_changed(), a size or position change of an
- // attached dialog might not affect the boundingBox
- this.layout_changed();
- }
-
- vfunc_set_container(container) {
- this._container = container;
- }
-
- vfunc_get_preferred_height(_container, _forWidth) {
- return [0, this._boundingBox.get_height()];
- }
-
- vfunc_get_preferred_width(_container, _forHeight) {
- return [0, this._boundingBox.get_width()];
- }
-
- vfunc_allocate(container, box) {
- // If the scale isn't 1, we weren't allocated our preferred size
- // and have to scale the children allocations accordingly.
- const scaleX = this._boundingBox.get_width() > 0
- ? box.get_width() / this._boundingBox.get_width()
- : 1;
- const scaleY = this._boundingBox.get_height() > 0
- ? box.get_height() / this._boundingBox.get_height()
- : 1;
-
- const childBox = new Clutter.ActorBox();
-
- for (const child of container) {
- if (!child.visible)
- continue;
-
- const windowInfo = this._windows.get(child);
- if (windowInfo) {
- const bufferRect = windowInfo.metaWindow.get_buffer_rect();
- childBox.set_origin(
- bufferRect.x - this._boundingBox.x1,
- bufferRect.y - this._boundingBox.y1);
-
- const [, , natWidth, natHeight] = child.get_preferred_size();
- childBox.set_size(natWidth, natHeight);
-
- childBox.x1 *= scaleX;
- childBox.x2 *= scaleX;
- childBox.y1 *= scaleY;
- childBox.y2 *= scaleY;
-
- child.allocate(childBox);
- } else {
- child.allocate_preferred_size(0, 0);
- }
- }
- }
-
- /**
- * addWindow:
- * @param {Meta.Window} window: the MetaWindow instance
- *
- * Creates a ClutterActor drawing the texture of @window and adds it
- * to the container. If @window is already part of the preview, this
- * function will do nothing.
- *
- * @returns {Clutter.Actor} The newly created actor drawing @window
- */
- addWindow(window) {
- const index = [...this._windows.values()].findIndex(info =>
- info.metaWindow === window);
-
- if (index !== -1)
- return null;
-
- const windowActor = window.get_compositor_private();
- const actor = new Clutter.Clone({ source: windowActor });
-
- this._windows.set(actor, {
- metaWindow: window,
- windowActor,
- sizeChangedId: window.connect('size-changed', () =>
- this._layoutChanged()),
- positionChangedId: window.connect('position-changed', () =>
- this._layoutChanged()),
- windowActorDestroyId: windowActor.connect('destroy', () =>
- actor.destroy()),
- destroyId: actor.connect('destroy', () =>
- this.removeWindow(window)),
- });
-
- this._container.add_child(actor);
-
- this._layoutChanged();
-
- return actor;
- }
-
- /**
- * removeWindow:
- * @param {Meta.Window} window: the window to remove from the preview
- *
- * Removes a MetaWindow @window from the preview which has been added
- * previously using addWindow(). If @window is not part of preview,
- * this function will do nothing.
- */
- removeWindow(window) {
- const entry = [...this._windows].find(
- ([, i]) => i.metaWindow === window);
-
- if (!entry)
- return;
-
- const [actor, windowInfo] = entry;
-
- windowInfo.metaWindow.disconnect(windowInfo.sizeChangedId);
- windowInfo.metaWindow.disconnect(windowInfo.positionChangedId);
- windowInfo.windowActor.disconnect(windowInfo.windowActorDestroyId);
- actor.disconnect(windowInfo.destroyId);
-
- this._windows.delete(actor);
- this._container.remove_child(actor);
-
- this._layoutChanged();
- }
-
- /**
- * getWindows:
- *
- * Gets an array of all MetaWindows that were added to the layout
- * using addWindow(), ordered by the insertion order.
- *
- * @returns {Array} An array including all windows
- */
- getWindows() {
- return [...this._windows.values()].map(i => i.metaWindow);
- }
-
- get boundingBox() {
- return this._boundingBox;
- }
-});
-
var WindowPreview = GObject.registerClass({
Properties: {
'overlay-enabled': GObject.ParamSpec.boolean(
@@ -235,7 +61,7 @@ var WindowPreview = GObject.registerClass({
// the initialization of the actor if that layout manager keeps track
// of its container, so set the layout manager after creating the
// container
- this._windowContainer.layout_manager = new WindowPreviewLayout();
+ this._windowContainer.layout_manager = new Shell.WindowPreviewLayout();
this.add_child(this._windowContainer);
this._addWindow(metaWindow);
@@ -601,7 +427,7 @@ var WindowPreview = GObject.registerClass({
}
_addWindow(metaWindow) {
- const clone = this._windowContainer.layout_manager.addWindow(metaWindow);
+ const clone = this._windowContainer.layout_manager.add_window(metaWindow);
if (!clone)
return;
@@ -620,7 +446,7 @@ var WindowPreview = GObject.registerClass({
}
_deleteAll() {
- const windows = this._windowContainer.layout_manager.getWindows();
+ const windows = this._windowContainer.layout_manager.get_windows();
// Delete all windows, starting from the bottom-most (most-modal) one
for (const window of windows.reverse())
@@ -645,7 +471,7 @@ var WindowPreview = GObject.registerClass({
}
_hasAttachedDialogs() {
- return this._windowContainer.layout_manager.getWindows().length > 1;
+ return this._windowContainer.layout_manager.get_windows().length > 1;
}
_updateAttachedDialogs() {
diff --git a/src/meson.build b/src/meson.build
index a7c56bbcfe..d20134fd20 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -109,6 +109,7 @@ libshell_public_headers = [
'shell-tray-icon.h',
'shell-tray-manager.h',
'shell-util.h',
+ 'shell-window-preview-layout.h',
'shell-window-tracker.h',
'shell-wm.h'
]
@@ -151,6 +152,7 @@ libshell_sources = [
'shell-tray-icon.c',
'shell-tray-manager.c',
'shell-util.c',
+ 'shell-window-preview-layout.c',
'shell-window-tracker.c',
'shell-wm.c'
]
diff --git a/src/shell-window-preview-layout.c b/src/shell-window-preview-layout.c
new file mode 100644
index 0000000000..a759a74f17
--- /dev/null
+++ b/src/shell-window-preview-layout.c
@@ -0,0 +1,472 @@
+#include "config.h"
+
+#include <clutter/clutter.h>
+#include <meta/window.h>
+#include "shell-window-preview-layout.h"
+
+typedef struct _ShellWindowPreviewLayoutPrivate ShellWindowPreviewLayoutPrivate;
+struct _ShellWindowPreviewLayoutPrivate
+{
+ ClutterActor *container;
+ GHashTable *windows;
+
+ ClutterActorBox bounding_box;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_BOUNDING_BOX,
+
+ PROP_LAST
+};
+
+static GParamSpec *obj_props[PROP_LAST] = { NULL, };
+
+G_DEFINE_TYPE_WITH_PRIVATE (ShellWindowPreviewLayout, shell_window_preview_layout,
+ CLUTTER_TYPE_LAYOUT_MANAGER);
+
+typedef struct _WindowInfo
+{
+ MetaWindow *window;
+ ClutterActor *window_actor;
+
+ gulong size_changed_id;
+ gulong position_changed_id;
+ gulong window_actor_destroy_id;
+ gulong destroy_id;
+} WindowInfo;
+
+static void
+shell_window_preview_layout_get_property (GObject *object,
+ unsigned int property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ShellWindowPreviewLayout *self = SHELL_WINDOW_PREVIEW_LAYOUT (object);
+ ShellWindowPreviewLayoutPrivate *priv;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ switch (property_id)
+ {
+ case PROP_BOUNDING_BOX:
+ g_value_set_boxed (value, &priv->bounding_box);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+shell_window_preview_layout_set_container (ClutterLayoutManager *layout,
+ ClutterContainer *container)
+{
+ ShellWindowPreviewLayout *self = SHELL_WINDOW_PREVIEW_LAYOUT (layout);
+ ShellWindowPreviewLayoutPrivate *priv;
+ ClutterLayoutManagerClass *parent_class;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ priv->container = CLUTTER_ACTOR (container);
+
+ parent_class = CLUTTER_LAYOUT_MANAGER_CLASS (shell_window_preview_layout_parent_class);
+ parent_class->set_container (layout, container);
+}
+
+static void
+shell_window_preview_layout_get_preferred_width (ClutterLayoutManager *layout,
+ ClutterContainer *container,
+ float for_height,
+ float *min_width_p,
+ float *natural_width_p)
+{
+ ShellWindowPreviewLayout *self = SHELL_WINDOW_PREVIEW_LAYOUT (layout);
+ ShellWindowPreviewLayoutPrivate *priv;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ if (min_width_p)
+ *min_width_p = 0;
+
+ if (natural_width_p)
+ *natural_width_p = clutter_actor_box_get_width (&priv->bounding_box);
+}
+
+static void
+shell_window_preview_layout_get_preferred_height (ClutterLayoutManager *layout,
+ ClutterContainer *container,
+ float for_width,
+ float *min_height_p,
+ float *natural_height_p)
+{
+ ShellWindowPreviewLayout *self = SHELL_WINDOW_PREVIEW_LAYOUT (layout);
+ ShellWindowPreviewLayoutPrivate *priv;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ if (min_height_p)
+ *min_height_p = 0;
+
+ if (natural_height_p)
+ *natural_height_p = clutter_actor_box_get_height (&priv->bounding_box);
+}
+
+
+static void
+shell_window_preview_layout_allocate (ClutterLayoutManager *layout,
+ ClutterContainer *container,
+ const ClutterActorBox *box)
+{
+ ShellWindowPreviewLayout *self = SHELL_WINDOW_PREVIEW_LAYOUT (layout);
+ ShellWindowPreviewLayoutPrivate *priv;
+ float scale_x, scale_y;
+ float bounding_box_width, bounding_box_height;
+ ClutterActorIter iter;
+ ClutterActor *child;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ bounding_box_width = clutter_actor_box_get_width (&priv->bounding_box);
+ bounding_box_height = clutter_actor_box_get_height (&priv->bounding_box);
+
+ if (bounding_box_width == 0)
+ scale_x = 1.f;
+ else
+ scale_x = clutter_actor_box_get_width (box) / bounding_box_width;
+
+ if (bounding_box_height == 0)
+ scale_y = 1.f;
+ else
+ scale_y = clutter_actor_box_get_height (box) / bounding_box_height;
+
+ clutter_actor_iter_init (&iter, CLUTTER_ACTOR (container));
+ while (clutter_actor_iter_next (&iter, &child))
+ {
+ ClutterActorBox child_box = { 0, };
+ WindowInfo *window_info;
+
+ if (!clutter_actor_is_visible (child))
+ continue;
+
+ window_info = g_hash_table_lookup (priv->windows, child);
+
+ if (window_info)
+ {
+ MetaRectangle buffer_rect;
+ float child_nat_width, child_nat_height;
+
+ meta_window_get_buffer_rect (window_info->window, &buffer_rect);
+
+ clutter_actor_box_set_origin (&child_box,
+ buffer_rect.x - priv->bounding_box.x1,
+ buffer_rect.y - priv->bounding_box.y1);
+
+ clutter_actor_get_preferred_size (child, NULL, NULL,
+ &child_nat_width, &child_nat_height);
+
+ clutter_actor_box_set_size (&child_box, child_nat_width, child_nat_height);
+
+ child_box.x1 *= scale_x;
+ child_box.x2 *= scale_x;
+ child_box.y1 *= scale_y;
+ child_box.y2 *= scale_y;
+
+ clutter_actor_allocate (child, &child_box);
+ }
+ else
+ {
+ float x, y;
+
+ clutter_actor_get_fixed_position (child, &x, &y);
+ clutter_actor_allocate_preferred_size (child, x, y);
+ }
+ }
+}
+
+static void
+on_layout_changed (ShellWindowPreviewLayout *self)
+{
+ ShellWindowPreviewLayoutPrivate *priv;
+ GHashTableIter iter;
+ gpointer value;
+ gboolean first_rect = TRUE;
+ MetaRectangle bounding_rect = { 0, };
+ ClutterActorBox old_bounding_box;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ old_bounding_box =
+ (ClutterActorBox) CLUTTER_ACTOR_BOX_INIT (priv->bounding_box.x1,
+ priv->bounding_box.y1,
+ priv->bounding_box.x2,
+ priv->bounding_box.y2);
+
+ g_hash_table_iter_init (&iter, priv->windows);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ WindowInfo *window_info = value;
+ MetaRectangle frame_rect;
+
+ meta_window_get_frame_rect (window_info->window, &frame_rect);
+
+ if (first_rect)
+ {
+ bounding_rect = frame_rect;
+ first_rect = FALSE;
+ continue;
+ }
+
+ meta_rectangle_union (&frame_rect, &bounding_rect, &bounding_rect);
+ }
+
+ clutter_actor_box_set_origin (&priv->bounding_box,
+ (float) bounding_rect.x,
+ (float) bounding_rect.y);
+ clutter_actor_box_set_size (&priv->bounding_box,
+ (float) bounding_rect.width,
+ (float) bounding_rect.height);
+
+ if (!clutter_actor_box_equal (&priv->bounding_box, &old_bounding_box))
+ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_BOUNDING_BOX]);
+
+ clutter_layout_manager_layout_changed (CLUTTER_LAYOUT_MANAGER (self));
+}
+
+static void
+on_window_size_position_changed (MetaWindow *window,
+ ShellWindowPreviewLayout *self)
+{
+ on_layout_changed (self);
+}
+
+static void
+on_window_destroyed (ClutterActor *actor)
+{
+ clutter_actor_destroy (actor);
+}
+
+static void
+on_actor_destroyed (ClutterActor *actor,
+ ShellWindowPreviewLayout *self)
+{
+ ShellWindowPreviewLayoutPrivate *priv;
+ WindowInfo *window_info;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ window_info = g_hash_table_lookup (priv->windows, actor);
+ g_assert (window_info != NULL);
+
+ shell_window_preview_layout_remove_window (self, window_info->window);
+}
+
+static void
+shell_window_preview_layout_dispose (GObject *gobject)
+{
+ ShellWindowPreviewLayout *self = SHELL_WINDOW_PREVIEW_LAYOUT (gobject);
+ ShellWindowPreviewLayoutPrivate *priv;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ g_hash_table_iter_init (&iter, priv->windows);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ ClutterActor *actor = key;
+ WindowInfo *info = value;
+
+ g_clear_signal_handler (&info->size_changed_id, info->window);
+ g_clear_signal_handler (&info->position_changed_id, info->window);
+ g_clear_signal_handler (&info->window_actor_destroy_id, info->window_actor);
+ g_clear_signal_handler (&info->destroy_id, actor);
+
+ clutter_actor_remove_child (priv->container, actor);
+ }
+
+ g_hash_table_remove_all (priv->windows);
+
+ G_OBJECT_CLASS (shell_window_preview_layout_parent_class)->dispose (gobject);
+}
+
+static void
+shell_window_preview_layout_init (ShellWindowPreviewLayout *self)
+{
+ ShellWindowPreviewLayoutPrivate *priv;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ priv->windows = g_hash_table_new (NULL, NULL);
+}
+
+static void
+shell_window_preview_layout_class_init (ShellWindowPreviewLayoutClass *klass)
+{
+ ClutterLayoutManagerClass *layout_class = CLUTTER_LAYOUT_MANAGER_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ layout_class->get_preferred_width = shell_window_preview_layout_get_preferred_width;
+ layout_class->get_preferred_height = shell_window_preview_layout_get_preferred_height;
+ layout_class->allocate = shell_window_preview_layout_allocate;
+ layout_class->set_container = shell_window_preview_layout_set_container;
+
+ gobject_class->dispose = shell_window_preview_layout_dispose;
+ gobject_class->get_property = shell_window_preview_layout_get_property;
+
+ /**
+ * ShellWindowPreviewLayout:bounding-box:
+ */
+ obj_props[PROP_BOUNDING_BOX] =
+ g_param_spec_boxed ("bounding-box",
+ "Bounding Box",
+ "Bounding Box",
+ CLUTTER_TYPE_ACTOR_BOX,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
+}
+
+/**
+ * shell_window_preview_layout_add_window:
+ * @self: a #ShellWindowPreviewLayout
+ * @window: the #MetaWindow
+ *
+ * Creates a ClutterActor drawing the texture of @window and adds it
+ * to the container. If @window is already part of the preview, this
+ * function will do nothing.
+ *
+ * Returns: (transfer none): The newly created actor drawing @window
+ */
+ClutterActor *
+shell_window_preview_layout_add_window (ShellWindowPreviewLayout *self,
+ MetaWindow *window)
+{
+ ShellWindowPreviewLayoutPrivate *priv;
+ ClutterActor *window_actor, *actor;
+ WindowInfo *window_info;
+ GHashTableIter iter;
+ gpointer value;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ g_hash_table_iter_init (&iter, priv->windows);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ WindowInfo *info = value;
+
+ if (info->window == window)
+ return NULL;
+ }
+
+ window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
+ actor = clutter_clone_new (window_actor);
+
+ window_info = g_new0 (WindowInfo, 1);
+
+ window_info->window = window;
+ window_info->window_actor = window_actor;
+ window_info->size_changed_id =
+ g_signal_connect (window, "size-changed",
+ G_CALLBACK (on_window_size_position_changed), self);
+ window_info->position_changed_id =
+ g_signal_connect (window, "position-changed",
+ G_CALLBACK (on_window_size_position_changed), self);
+ window_info->window_actor_destroy_id =
+ g_signal_connect (window_actor, "destroy",
+ G_CALLBACK (on_window_destroyed), actor);
+ window_info->destroy_id =
+ g_signal_connect (actor, "destroy",
+ G_CALLBACK (on_actor_destroyed), self);
+
+ g_hash_table_insert (priv->windows, actor, window_info);
+
+ clutter_actor_add_child (priv->container, actor);
+
+ on_layout_changed (self);
+
+ return actor;
+}
+
+/**
+ * shell_window_preview_layout_remove_window:
+ * @self: a #ShellWindowPreviewLayout
+ * @window: the #MetaWindow
+ *
+ * Removes a MetaWindow @window from the preview which has been added
+ * previously using shell_window_preview_layout_add_window().
+ * If @window is not part of preview, this function will do nothing.
+ */
+void
+shell_window_preview_layout_remove_window (ShellWindowPreviewLayout *self,
+ MetaWindow *window)
+{
+ ShellWindowPreviewLayoutPrivate *priv;
+ ClutterActor *actor;
+ WindowInfo *window_info = NULL;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ g_hash_table_iter_init (&iter, priv->windows);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ WindowInfo *info = value;
+
+ if (info->window == window)
+ {
+ actor = CLUTTER_ACTOR (key);
+ window_info = info;
+ break;
+ }
+ }
+
+ if (window_info == NULL)
+ return;
+
+ g_clear_signal_handler (&window_info->size_changed_id, window);
+ g_clear_signal_handler (&window_info->position_changed_id, window);
+ g_clear_signal_handler (&window_info->window_actor_destroy_id, window_info->window_actor);
+ g_clear_signal_handler (&window_info->destroy_id, actor);
+
+ g_hash_table_remove (priv->windows, actor);
+
+ clutter_actor_remove_child (priv->container, actor);
+
+ on_layout_changed (self);
+}
+
+/**
+ * shell_window_preview_layout_get_windows:
+ * @self: a #ShellWindowPreviewLayout
+ *
+ * Gets an array of all MetaWindows that were added to the layout
+ * using shell_window_preview_layout_add_window(), ordered by the
+ * insertion order.
+ *
+ * Returns: (transfer container) (element-type Meta.Window): The list of windows
+ */
+GList *
+shell_window_preview_layout_get_windows (ShellWindowPreviewLayout *self)
+{
+ ShellWindowPreviewLayoutPrivate *priv;
+ GList *windows = NULL;
+ GHashTableIter iter;
+ gpointer value;
+
+ priv = shell_window_preview_layout_get_instance_private (self);
+
+ g_hash_table_iter_init (&iter, priv->windows);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ WindowInfo *window_info = value;
+
+ windows = g_list_prepend (windows, window_info->window);
+ }
+
+ return windows;
+}
diff --git a/src/shell-window-preview-layout.h b/src/shell-window-preview-layout.h
new file mode 100644
index 0000000000..9376b0da8f
--- /dev/null
+++ b/src/shell-window-preview-layout.h
@@ -0,0 +1,33 @@
+#ifndef __SHELL_WINDOW_PREVIEW_LAYOUT_H__
+#define __SHELL_WINDOW_PREVIEW_LAYOUT_H__
+
+G_BEGIN_DECLS
+
+#include <clutter/clutter.h>
+
+#define SHELL_TYPE_WINDOW_PREVIEW_LAYOUT (shell_window_preview_layout_get_type ())
+G_DECLARE_FINAL_TYPE (ShellWindowPreviewLayout, shell_window_preview_layout,
+ SHELL, WINDOW_PREVIEW_LAYOUT, ClutterLayoutManager)
+
+typedef struct _ShellWindowPreviewLayout ShellWindowPreviewLayout;
+typedef struct _ShellWindowPreviewLayoutPrivate ShellWindowPreviewLayoutPrivate;
+
+struct _ShellWindowPreviewLayout
+{
+ /*< private >*/
+ ClutterLayoutManager parent;
+
+ ShellWindowPreviewLayoutPrivate *priv;
+};
+
+ClutterActor * shell_window_preview_layout_add_window (ShellWindowPreviewLayout *self,
+ MetaWindow *window);
+
+void shell_window_preview_layout_remove_window (ShellWindowPreviewLayout *self,
+ MetaWindow *window);
+
+GList * shell_window_preview_layout_get_windows (ShellWindowPreviewLayout *self);
+
+G_END_DECLS
+
+#endif /* __SHELL_WINDOW_PREVIEW_LAYOUT_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]