[libpanel/wip/chergert/fix-14] layout: stub out layout widget




commit bef125a93aad5a89c2184ff3fc46ed709543f522
Author: Christian Hergert <chergert redhat com>
Date:   Sat Sep 10 18:06:21 2022 -0700

    layout: stub out layout widget

 src/libpanel.h          |   1 +
 src/meson.build         |   2 +
 src/panel-layout.c      | 226 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/panel-layout.h      |  40 +++++++++
 testsuite/meson.build   |   9 +-
 testsuite/test-layout.c |  39 +++++++++
 6 files changed, 315 insertions(+), 2 deletions(-)
---
diff --git a/src/libpanel.h b/src/libpanel.h
index 5d01ccb..550057a 100644
--- a/src/libpanel.h
+++ b/src/libpanel.h
@@ -31,6 +31,7 @@
 # include "panel-grid.h"
 # include "panel-grid-column.h"
 # include "panel-init.h"
+# include "panel-layout.h"
 # include "panel-omni-bar.h"
 # include "panel-paned.h"
 # include "panel-position.h"
diff --git a/src/meson.build b/src/meson.build
index b018115..a625a0b 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -40,6 +40,7 @@ libpanel_sources = [
   'panel-grid.c',
   'panel-grid-column.c',
   'panel-init.c',
+  'panel-layout.c',
   'panel-omni-bar.c',
   'panel-paned.c',
   'panel-position.c',
@@ -62,6 +63,7 @@ libpanel_headers = [
   'panel-grid.h',
   'panel-grid-column.h',
   'panel-init.h',
+  'panel-layout.h',
   'panel-omni-bar.h',
   'panel-paned.h',
   'panel-position.h',
diff --git a/src/panel-layout.c b/src/panel-layout.c
new file mode 100644
index 0000000..a31a061
--- /dev/null
+++ b/src/panel-layout.c
@@ -0,0 +1,226 @@
+/* panel-layout.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * 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 "panel-layout.h"
+#include "panel-position-private.h"
+
+struct _PanelLayout
+{
+  GObject  parent_instance;
+  GArray  *infos;
+};
+
+typedef struct
+{
+  PanelPosition *position;
+  char *id;
+  char *type_hint;
+  GVariant *metadata;
+} WidgetInfo;
+
+G_DEFINE_FINAL_TYPE (PanelLayout, panel_layout, G_TYPE_OBJECT)
+
+static void
+widget_info_clear (WidgetInfo *info)
+{
+  g_clear_object (&info->position);
+  g_clear_pointer (&info->id, g_free);
+  g_clear_pointer (&info->type_hint, g_free);
+  g_clear_pointer (&info->metadata, g_variant_unref);
+}
+
+static void
+panel_layout_dispose (GObject *object)
+{
+  PanelLayout *self = (PanelLayout *)object;
+
+  g_clear_pointer (&self->infos, g_array_unref);
+
+  G_OBJECT_CLASS (panel_layout_parent_class)->dispose (object);
+}
+
+static void
+panel_layout_class_init (PanelLayoutClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = panel_layout_dispose;
+}
+
+static void
+panel_layout_init (PanelLayout *self)
+{
+  self->infos = g_array_new (FALSE, FALSE, sizeof (WidgetInfo));
+  g_array_set_clear_func (self->infos, (GDestroyNotify)widget_info_clear);
+}
+
+/**
+ * panel_layout_to_variant:
+ * @self: a #PanelLayout
+ *
+ * Serializes a #PanelLayout as a #GVariant
+ *
+ * The result of this function may be passed to
+ * panel_layout_new_from_variant() to recreate a #PanelLayout.
+ *
+ * Returns: (transfer full): a #GVariant
+ */
+GVariant *
+panel_layout_to_variant (PanelLayout *self)
+{
+  GVariantBuilder builder;
+
+  g_return_val_if_fail (PANEL_IS_LAYOUT (self), NULL);
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+    g_variant_builder_add_parsed (&builder, "{'version',<%u>}", 1);
+    g_variant_builder_open (&builder, G_VARIANT_TYPE ("{sv}"));
+      g_variant_builder_add (&builder, "s", "widgets");
+      g_variant_builder_open (&builder, G_VARIANT_TYPE ("v"));
+        g_variant_builder_open (&builder, G_VARIANT_TYPE ("av"));
+        for (guint i = 0; i < self->infos->len; i++)
+          {
+            const WidgetInfo *info = &g_array_index (self->infos, WidgetInfo, i);
+            g_variant_builder_open (&builder, G_VARIANT_TYPE ("v"));
+              g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
+                g_variant_builder_add_parsed (&builder, "{'position',<%v>}", info->position);
+                g_variant_builder_add_parsed (&builder, "{'id',<%s>}", info->id ? info->id : "");
+                g_variant_builder_add_parsed (&builder, "{'type-hint',<%s>}", info->type_hint ? 
info->type_hint : "");
+                if (info->metadata)
+                  g_variant_builder_add_parsed (&builder, "{'metadata',<%v>}", info->metadata);
+              g_variant_builder_close (&builder);
+            g_variant_builder_close (&builder);
+          }
+        g_variant_builder_close (&builder);
+      g_variant_builder_close (&builder);
+    g_variant_builder_close (&builder);
+  return g_variant_builder_end (&builder);
+}
+
+static gboolean
+panel_layout_load_1 (PanelLayout  *self,
+                     GVariant     *variant,
+                     GError      **error)
+{
+  g_autoptr(GVariant) widgets = NULL;
+
+  g_assert (PANEL_IS_LAYOUT (self));
+  g_assert (variant != NULL);
+  g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_VARDICT));
+
+  if ((widgets = g_variant_lookup_value (variant, "widgets", G_VARIANT_TYPE_VARDICT)))
+    {
+      gsize n_children = g_variant_n_children (widgets);
+
+      for (gsize i = 0; i < n_children; i++)
+        {
+          g_autoptr(GVariant) widget = g_variant_get_child_value (widgets, i);
+          g_autoptr(GVariant) positionv = g_variant_lookup_value (widget, "position", G_VARIANT_TYPE_UINT32);
+          g_autoptr(GVariant) metadata = g_variant_lookup_value (widget, "metadata", G_VARIANT_TYPE_VARDICT);
+          g_autoptr(PanelPosition) position = NULL;
+          const char *id;
+          const char *type_hint;
+          WidgetInfo info;
+
+          if (positionv == NULL ||
+              !(position = _panel_position_new_from_variant (positionv)))
+            {
+              g_set_error_literal (error,
+                                   G_IO_ERROR,
+                                   G_IO_ERROR_INVALID_DATA,
+                                   "Failed to decode position variant");
+              return FALSE;
+            }
+
+          if (!g_variant_lookup (widget, "id", "&s", &id))
+            id = NULL;
+
+          if (!g_variant_lookup (widget, "type-hint", "&s", &type_hint))
+            type_hint = NULL;
+
+          info = (WidgetInfo) {
+            .position = g_object_ref (position),
+            .id = g_strdup (id),
+            .type_hint = g_strdup (type_hint),
+            .metadata = g_steal_pointer (&metadata),
+          };
+
+          g_array_append_val (self->infos, info);
+        }
+    }
+
+  return TRUE;
+}
+
+static gboolean
+panel_layout_load (PanelLayout  *self,
+                   GVariant     *variant,
+                   GError      **error)
+{
+  guint version = 0;
+
+  g_assert (PANEL_IS_LAYOUT (self));
+  g_assert (variant != NULL);
+  g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_VARDICT));
+
+  if (g_variant_lookup (variant, "version", "u", &version))
+    {
+      if (version == 1)
+        return panel_layout_load_1 (self, variant, error);
+    }
+
+  g_set_error_literal (error,
+                       G_IO_ERROR,
+                       G_IO_ERROR_INVALID_DATA,
+                       "Invalid version number in serialized layout");
+
+  return FALSE;
+}
+
+/**
+ * panel_layout_new_from_variant:
+ * @variant: a #GVariant from panel_layout_to_variant()
+ * @error: a location for a #GError, or %NULL
+ *
+ * Creates a new #PanelLayout from a #GVariant.
+ *
+ * This creates a new #PanelLayout instance from a previous layout
+ * which had been serialized to @variant.
+ *
+ * Returns: (transfer full): a #PanelLayout
+ */
+PanelLayout *
+panel_layout_new_from_variant (GVariant  *variant,
+                               GError   **error)
+{
+  PanelLayout *self;
+
+  g_return_val_if_fail (variant != NULL, NULL);
+  g_return_val_if_fail (g_variant_is_of_type (variant, G_VARIANT_TYPE_VARDICT), NULL);
+
+  self = g_object_new (PANEL_TYPE_LAYOUT, NULL);
+
+  if (!panel_layout_load (self, variant, error))
+    g_clear_object (&self);
+
+  return self;
+}
diff --git a/src/panel-layout.h b/src/panel-layout.h
new file mode 100644
index 0000000..e6a5552
--- /dev/null
+++ b/src/panel-layout.h
@@ -0,0 +1,40 @@
+/* panel-layout.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * This file 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 Lesser 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: LGPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+#include "panel-version-macros.h"
+
+G_BEGIN_DECLS
+
+#define PANEL_TYPE_LAYOUT (panel_layout_get_type())
+
+PANEL_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (PanelLayout, panel_layout, PANEL, LAYOUT, GObject)
+
+PANEL_AVAILABLE_IN_ALL
+PanelLayout *panel_layout_new_from_variant (GVariant     *variant,
+                                            GError      **error);
+PANEL_AVAILABLE_IN_ALL
+GVariant    *panel_layout_to_variant       (PanelLayout  *self);
+
+G_END_DECLS
diff --git a/testsuite/meson.build b/testsuite/meson.build
index 651c113..b6173ec 100644
--- a/testsuite/meson.build
+++ b/testsuite/meson.build
@@ -1,2 +1,7 @@
-executable('test-dock', 'test-dock.c', dependencies: [libpanel_static_dep])
-executable('test-paned', 'test-paned.c', dependencies: [libpanel_static_dep])
+test_dock = executable('test-dock', 'test-dock.c', dependencies: [libpanel_static_dep])
+test_paned = executable('test-paned', 'test-paned.c', dependencies: [libpanel_static_dep])
+
+test_layout = executable('test-layout', 'test-layout.c', dependencies: [libpanel_static_dep])
+test('test-layout', test_layout)
+
+
diff --git a/testsuite/test-layout.c b/testsuite/test-layout.c
new file mode 100644
index 0000000..b16c85e
--- /dev/null
+++ b/testsuite/test-layout.c
@@ -0,0 +1,39 @@
+#include <libpanel.h>
+
+static void
+test_layout (void)
+{
+  PanelLayout *layout;
+  PanelLayout *recreated;
+  GVariant *variant;
+  GError *error = NULL;
+
+  layout = g_object_new (PANEL_TYPE_LAYOUT, NULL);
+
+  variant = panel_layout_to_variant (layout);
+  g_assert_nonnull (variant);
+  g_assert_true (g_variant_is_of_type (variant, G_VARIANT_TYPE_VARDICT));
+
+  recreated = panel_layout_new_from_variant (variant, &error);
+  g_assert_no_error (error);
+  g_assert_true (PANEL_IS_LAYOUT (recreated));
+
+  g_assert_finalize_object (g_steal_pointer (&layout));
+  g_assert_finalize_object (g_steal_pointer (&recreated));
+  g_clear_pointer (&variant, g_variant_unref);
+
+  g_assert_null (error);
+  g_assert_null (layout);
+  g_assert_null (recreated);
+  g_assert_null (variant);
+}
+
+int
+main (int argc,
+      char *argv[])
+{
+  gtk_init ();
+  g_test_init (&argc, &argv, NULL);
+  g_test_add_func ("/Layout/basic", test_layout);
+  return g_test_run ();
+}


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