[gnome-builder/wip/chergert/glade3: 2/2] glade: start on basic glade plugin for gtk3 support



commit 43190147b372e740f81f9524928d0c9bcb2126ab
Author: Christian Hergert <chergert redhat com>
Date:   Wed Oct 17 20:47:37 2018 -0700

    glade: start on basic glade plugin for gtk3 support
    
    I'm not sure the lifetime of the glade plugin, because we know that
    we'll have to write something new for gtk4. But we have a couple of more
    releases with gtk3, so we can use this for now.
    
    We still need to add the signal panel, and do our modified version of
    the editor panel. We also need a couple accessor widgets.
    
    This is just a minimal prototype for the mechanics.

 build-aux/flatpak/org.gnome.Builder.json         |   9 +
 meson_options.txt                                |   1 +
 src/plugins/glade/gbp-glade-editor-addin.c       | 248 +++++++++++++++++++++++
 src/plugins/glade/gbp-glade-editor-addin.h       |  33 +++
 src/plugins/glade/gbp-glade-layout-stack-addin.c | 130 ++++++++++++
 src/plugins/glade/gbp-glade-layout-stack-addin.h |  31 +++
 src/plugins/glade/gbp-glade-plugin.c             |  36 ++++
 src/plugins/glade/gbp-glade-properties.c         |  65 ++++++
 src/plugins/glade/gbp-glade-properties.h         |  35 ++++
 src/plugins/glade/gbp-glade-properties.ui        |  10 +
 src/plugins/glade/gbp-glade-view.c               | 191 +++++++++++++++++
 src/plugins/glade/gbp-glade-view.h               |  43 ++++
 src/plugins/glade/glade.gresource.xml            |  13 ++
 src/plugins/glade/glade.plugin                   |   9 +
 src/plugins/glade/gtk/menus.ui                   |   4 +
 src/plugins/glade/meson.build                    |  24 +++
 src/plugins/glade/themes/Adwaita-dark.css        |   9 +
 src/plugins/glade/themes/Adwaita.css             |   9 +
 src/plugins/glade/themes/shared.css              |  19 ++
 src/plugins/meson.build                          |   2 +
 20 files changed, 921 insertions(+)
---
diff --git a/build-aux/flatpak/org.gnome.Builder.json b/build-aux/flatpak/org.gnome.Builder.json
index 83336470d..f94a58f8f 100644
--- a/build-aux/flatpak/org.gnome.Builder.json
+++ b/build-aux/flatpak/org.gnome.Builder.json
@@ -322,6 +322,15 @@
                 }
             ]
         },
+        {
+            "name" : "glade",
+            "sources" : [
+                {
+                    "type" : "git",
+                    "url" : "https://gitlab.gnome.org/GNOME/glade.git";
+                }
+            ]
+        },
         {
             "name" : "sysprof",
             "config-opts" : [
diff --git a/meson_options.txt b/meson_options.txt
index c87f021ab..24cc3dd8a 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -49,6 +49,7 @@ option('with_gdb', type: 'boolean')
 option('with_gettext', type: 'boolean')
 option('with_git', type: 'boolean')
 option('with_gjs_symbols', type: 'boolean')
+option('with_glade', type: 'boolean')
 option('with_gnome_code_assistance', type: 'boolean')
 option('with_go_langserv', type: 'boolean')
 option('with_history', type: 'boolean')
diff --git a/src/plugins/glade/gbp-glade-editor-addin.c b/src/plugins/glade/gbp-glade-editor-addin.c
new file mode 100644
index 000000000..d88288030
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-editor-addin.c
@@ -0,0 +1,248 @@
+/* gbp-glade-editor-addin.c
+ *
+ * Copyright 2018 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"
+
+#define G_LOG_DOMAIN "gbp-glade-editor-addin"
+
+#include "gbp-glade-editor-addin.h"
+#include "gbp-glade-properties.h"
+#include "gbp-glade-view.h"
+
+struct _GbpGladeEditorAddin
+{
+  GObject parent_instance;
+  IdeEditorPerspective *editor;
+  GbpGladeProperties *properties;
+  DzlSignalGroup *project_signals;
+  GActionGroup *actions;
+  guint has_hold : 1;
+};
+
+static void editor_addin_iface_init (IdeEditorAddinInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GbpGladeEditorAddin, gbp_glade_editor_addin, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_EDITOR_ADDIN, editor_addin_iface_init))
+
+static void
+gbp_glade_editor_addin_dispose (GObject *object)
+{
+  GbpGladeEditorAddin *self = (GbpGladeEditorAddin *)object;
+
+  dzl_signal_group_set_target (self->project_signals, NULL);
+  g_clear_object (&self->project_signals);
+  g_clear_object (&self->actions);
+
+  G_OBJECT_CLASS (gbp_glade_editor_addin_parent_class)->dispose (object);
+}
+
+static void
+gbp_glade_editor_addin_class_init (GbpGladeEditorAddinClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = gbp_glade_editor_addin_dispose;
+}
+
+static void
+gbp_glade_editor_addin_selection_changed_cb (GbpGladeEditorAddin *self,
+                                             GladeProject        *project)
+{
+  GList *selection = NULL;
+
+  g_assert (GBP_IS_GLADE_EDITOR_ADDIN (self));
+  g_assert (!project || GLADE_IS_PROJECT (project));
+
+  if (project != NULL)
+    selection = glade_project_selection_get (project);
+
+  if (selection != NULL && selection->next == NULL)
+    {
+      GtkWidget *widget = selection->data;
+      GladeWidget *glade = glade_widget_get_from_gobject (widget);
+      IdeLayoutTransientSidebar *transient;
+
+      gbp_glade_properties_set_widget (self->properties, glade);
+
+      transient = ide_editor_perspective_get_transient_sidebar (self->editor);
+    }
+}
+
+static void
+gbp_glade_editor_addin_bind_cb (GbpGladeEditorAddin *self,
+                                GladeProject        *project,
+                                DzlSignalGroup      *project_signals)
+{
+  g_assert (GBP_IS_GLADE_EDITOR_ADDIN (self));
+  g_assert (GLADE_IS_PROJECT (project));
+  g_assert (DZL_IS_SIGNAL_GROUP (project_signals));
+
+  gbp_glade_editor_addin_selection_changed_cb (self, project);
+}
+
+static void
+gbp_glade_editor_addin_open_glade_project (GSimpleAction *action,
+                                           GVariant      *param,
+                                           gpointer       user_data)
+{
+  GbpGladeEditorAddin *self = user_data;
+  g_autoptr(GFile) file = NULL;
+  GbpGladeView *view;
+  const gchar *path;
+
+  g_assert (G_IS_SIMPLE_ACTION (action));
+  g_assert (param != NULL);
+  g_assert (g_variant_is_of_type (param, G_VARIANT_TYPE_STRING));
+
+  path = g_variant_get_string (param, NULL);
+
+  view = gbp_glade_view_new ();
+  gtk_container_add (GTK_CONTAINER (self->editor), GTK_WIDGET (view));
+  gtk_widget_show (GTK_WIDGET (view));
+
+  file = g_file_new_for_path (path);
+  gbp_glade_view_load_file_async (view, file, NULL, NULL, NULL);
+}
+
+static void
+gbp_glade_editor_addin_init (GbpGladeEditorAddin *self)
+{
+  static GActionEntry actions[] = {
+    { "open-glade-project", gbp_glade_editor_addin_open_glade_project, "s" },
+  };
+
+  self->actions = G_ACTION_GROUP (g_simple_action_group_new ());
+  g_action_map_add_action_entries (G_ACTION_MAP (self->actions),
+                                   actions,
+                                   G_N_ELEMENTS (actions),
+                                   self);
+
+  self->project_signals = dzl_signal_group_new (GLADE_TYPE_PROJECT);
+
+  g_signal_connect_object (self->project_signals,
+                           "bind",
+                           G_CALLBACK (gbp_glade_editor_addin_bind_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  dzl_signal_group_connect_object (self->project_signals,
+                                   "selection-changed",
+                                   G_CALLBACK (gbp_glade_editor_addin_selection_changed_cb),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+}
+
+static void
+gbp_glade_editor_addin_set_project (GbpGladeEditorAddin *self,
+                                    GladeProject        *project)
+{
+  g_assert (GBP_IS_GLADE_EDITOR_ADDIN (self));
+  g_assert (!project || GLADE_IS_PROJECT (project));
+
+  dzl_signal_group_set_target (self->project_signals, project);
+}
+
+static void
+gbp_glade_editor_addin_view_set (IdeEditorAddin *addin,
+                                 IdeLayoutView  *view)
+{
+  GbpGladeEditorAddin *self = (GbpGladeEditorAddin *)addin;
+  IdeLayoutTransientSidebar *transient;
+  GladeProject *project = NULL;
+
+  g_assert (GBP_IS_GLADE_EDITOR_ADDIN (self));
+  g_assert (!view || IDE_IS_LAYOUT_VIEW (view));
+
+  transient = ide_editor_perspective_get_transient_sidebar (self->editor);
+
+  if (self->has_hold)
+    {
+      ide_layout_transient_sidebar_unlock (transient);
+      self->has_hold = FALSE;
+    }
+
+  if (GBP_IS_GLADE_VIEW (view))
+    {
+      project = gbp_glade_view_get_project (GBP_GLADE_VIEW (view));
+      ide_layout_transient_sidebar_set_view (transient, view);
+      ide_layout_transient_sidebar_lock (transient);
+      gtk_widget_show (GTK_WIDGET (transient));
+      dzl_dock_item_present (DZL_DOCK_ITEM (self->properties));
+      self->has_hold = TRUE;
+    }
+
+  gbp_glade_editor_addin_set_project (self, project);
+}
+
+static void
+gbp_glade_editor_addin_load (IdeEditorAddin       *addin,
+                             IdeEditorPerspective *editor)
+{
+  GbpGladeEditorAddin *self = (GbpGladeEditorAddin *)addin;
+  IdeLayoutTransientSidebar *transient;
+  g_autoptr(GFile) file = NULL;
+  GbpGladeView *view;
+
+  g_assert (GBP_IS_GLADE_EDITOR_ADDIN (self));
+  g_assert (IDE_IS_EDITOR_PERSPECTIVE (editor));
+
+  self->editor = editor;
+
+  gtk_widget_insert_action_group (GTK_WIDGET (editor), "glade", self->actions);
+
+  transient = ide_editor_perspective_get_transient_sidebar (self->editor);
+
+  self->properties = g_object_new (GBP_TYPE_GLADE_PROPERTIES,
+                                   "visible", TRUE,
+                                   NULL);
+  gtk_container_add (GTK_CONTAINER (transient), GTK_WIDGET (self->properties));
+}
+
+static void
+gbp_glade_editor_addin_unload (IdeEditorAddin       *addin,
+                               IdeEditorPerspective *editor)
+{
+  GbpGladeEditorAddin *self = (GbpGladeEditorAddin *)addin;
+  IdeLayoutTransientSidebar *transient;
+
+  g_assert (GBP_IS_GLADE_EDITOR_ADDIN (self));
+  g_assert (IDE_IS_EDITOR_PERSPECTIVE (editor));
+
+  transient = ide_editor_perspective_get_transient_sidebar (self->editor);
+
+  if (self->has_hold)
+    {
+      ide_layout_transient_sidebar_unlock (transient);
+      self->has_hold = FALSE;
+    }
+
+  gtk_widget_insert_action_group (GTK_WIDGET (editor), "glade", NULL);
+  gtk_widget_destroy (GTK_WIDGET (self->properties));
+
+  self->editor = NULL;
+}
+
+static void
+editor_addin_iface_init (IdeEditorAddinInterface *iface)
+{
+  iface->load = gbp_glade_editor_addin_load;
+  iface->unload = gbp_glade_editor_addin_unload;
+  iface->view_set = gbp_glade_editor_addin_view_set;
+}
diff --git a/src/plugins/glade/gbp-glade-editor-addin.h b/src/plugins/glade/gbp-glade-editor-addin.h
new file mode 100644
index 000000000..0124f88ff
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-editor-addin.h
@@ -0,0 +1,33 @@
+/* gbp-glade-editor-addin.h
+ *
+ * Copyright 2018 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
+ */
+
+
+#pragma once
+
+#include <gladeui/glade.h>
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_GLADE_EDITOR_ADDIN (gbp_glade_editor_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpGladeEditorAddin, gbp_glade_editor_addin, GBP, GLADE_EDITOR_ADDIN, GObject)
+
+G_END_DECLS
diff --git a/src/plugins/glade/gbp-glade-layout-stack-addin.c 
b/src/plugins/glade/gbp-glade-layout-stack-addin.c
new file mode 100644
index 000000000..41b931a48
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-layout-stack-addin.c
@@ -0,0 +1,130 @@
+/* gbp-glade-layout-stack-addin.c
+ *
+ * Copyright 2018 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"
+
+#define G_LOG_DOMAIN "gbp-glade-layout-stack-addin"
+
+#include <glib/gi18n.h>
+#include <gladeui/glade.h>
+
+#include "gbp-glade-layout-stack-addin.h"
+#include "gbp-glade-view.h"
+
+struct _GbpGladeLayoutStackAddin
+{
+  GObject         parent_instance;
+  GtkMenuButton  *button;
+  GladeInspector *inspector;
+};
+
+static void layout_stack_addin_iface_init (IdeLayoutStackAddinInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GbpGladeLayoutStackAddin, gbp_glade_layout_stack_addin, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_LAYOUT_STACK_ADDIN,
+                                                layout_stack_addin_iface_init))
+
+static void
+gbp_glade_layout_stack_addin_class_init (GbpGladeLayoutStackAddinClass *klass)
+{
+}
+
+static void
+gbp_glade_layout_stack_addin_init (GbpGladeLayoutStackAddin *self)
+{
+}
+
+static void
+gbp_glade_layout_stack_addin_load (IdeLayoutStackAddin *addin,
+                                   IdeLayoutStack      *stack)
+{
+  GbpGladeLayoutStackAddin *self = (GbpGladeLayoutStackAddin *)addin;
+  GtkPopover *popover;
+  GtkWidget *header;
+
+  g_assert (GBP_IS_GLADE_LAYOUT_STACK_ADDIN (self));
+  g_assert (IDE_IS_LAYOUT_STACK (stack));
+
+  header = ide_layout_stack_get_titlebar (stack);
+
+  popover = g_object_new (GTK_TYPE_POPOVER,
+                          "width-request", 400,
+                          "height-request", 400,
+                          "position", GTK_POS_BOTTOM,
+                          NULL);
+  dzl_gtk_widget_add_style_class (GTK_WIDGET (popover), "glade-stack-header");
+
+  self->button = g_object_new (GTK_TYPE_MENU_BUTTON,
+                               "label", _("Select Widget…"),
+                               "popover", popover,
+                               "visible", FALSE,
+                               NULL);
+  g_signal_connect (self->button,
+                    "destroy",
+                    G_CALLBACK (gtk_widget_destroyed),
+                    &self->button);
+  ide_layout_stack_header_add_custom_title (IDE_LAYOUT_STACK_HEADER (header),
+                                            GTK_WIDGET (self->button),
+                                            200);
+
+  self->inspector = g_object_new (GLADE_TYPE_INSPECTOR,
+                                  "visible", TRUE,
+                                  NULL);
+  gtk_container_add (GTK_CONTAINER (popover), GTK_WIDGET (self->inspector));
+}
+
+static void
+gbp_glade_layout_stack_addin_unload (IdeLayoutStackAddin *addin,
+                                     IdeLayoutStack      *stack)
+{
+  GbpGladeLayoutStackAddin *self = (GbpGladeLayoutStackAddin *)addin;
+
+  g_assert (GBP_IS_GLADE_LAYOUT_STACK_ADDIN (self));
+  g_assert (IDE_IS_LAYOUT_STACK (stack));
+
+  if (self->button != NULL)
+    gtk_widget_destroy (GTK_WIDGET (self->button));
+}
+
+static void
+gbp_glade_layout_stack_addin_set_view (IdeLayoutStackAddin *addin,
+                                       IdeLayoutView       *view)
+{
+  GbpGladeLayoutStackAddin *self = (GbpGladeLayoutStackAddin *)addin;
+  GladeProject *project = NULL;
+
+  g_assert (GBP_IS_GLADE_LAYOUT_STACK_ADDIN (self));
+  g_assert (!view || IDE_IS_LAYOUT_VIEW (view));
+
+  if (GBP_IS_GLADE_VIEW (view))
+    project = gbp_glade_view_get_project (GBP_GLADE_VIEW (view));
+
+  glade_inspector_set_project (self->inspector, project);
+  gtk_widget_set_visible (GTK_WIDGET (self->button), project != NULL);
+}
+
+static void
+layout_stack_addin_iface_init (IdeLayoutStackAddinInterface *iface)
+{
+  iface->load = gbp_glade_layout_stack_addin_load;
+  iface->unload = gbp_glade_layout_stack_addin_unload;
+  iface->set_view = gbp_glade_layout_stack_addin_set_view;
+}
+
diff --git a/src/plugins/glade/gbp-glade-layout-stack-addin.h 
b/src/plugins/glade/gbp-glade-layout-stack-addin.h
new file mode 100644
index 000000000..401762b53
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-layout-stack-addin.h
@@ -0,0 +1,31 @@
+/* gbp-glade-layout-stack-addin.h
+ *
+ * Copyright 2018 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
+ */
+
+#pragma once
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_GLADE_LAYOUT_STACK_ADDIN (gbp_glade_layout_stack_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpGladeLayoutStackAddin, gbp_glade_layout_stack_addin, GBP, GLADE_LAYOUT_STACK_ADDIN, 
GObject)
+
+G_END_DECLS
diff --git a/src/plugins/glade/gbp-glade-plugin.c b/src/plugins/glade/gbp-glade-plugin.c
new file mode 100644
index 000000000..a42abb02a
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-plugin.c
@@ -0,0 +1,36 @@
+/* gbp-glade-plugin.c
+ *
+ * Copyright 2018 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/>.
+ */
+
+#define G_LOG_DOMAIN "gbp-glade-plugin"
+
+#include <ide.h>
+#include <libpeas/peas.h>
+
+#include "gbp-glade-editor-addin.h"
+#include "gbp-glade-layout-stack-addin.h"
+
+void
+gbp_glade_register_types (PeasObjectModule *module)
+{
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_EDITOR_ADDIN,
+                                              GBP_TYPE_GLADE_EDITOR_ADDIN);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_LAYOUT_STACK_ADDIN,
+                                              GBP_TYPE_GLADE_LAYOUT_STACK_ADDIN);
+}
diff --git a/src/plugins/glade/gbp-glade-properties.c b/src/plugins/glade/gbp-glade-properties.c
new file mode 100644
index 000000000..aa61680b5
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-properties.c
@@ -0,0 +1,65 @@
+/* gbp-glade-properties.c
+ *
+ * Copyright 2018 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"
+
+#define G_LOG_DOMAIN "gbp-glade-properties"
+
+#include <glib/gi18n.h>
+
+#include "gbp-glade-properties.h"
+
+struct _GbpGladeProperties
+{
+  DzlDockWidget parent_instance;
+  GladeEditor *editor;
+};
+
+G_DEFINE_TYPE (GbpGladeProperties, gbp_glade_properties, DZL_TYPE_DOCK_WIDGET)
+
+static void
+gbp_glade_properties_class_init (GbpGladePropertiesClass *klass)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/plugins/glade-plugin/gbp-glade-properties.ui");
+  gtk_widget_class_set_css_name (widget_class, "gbpgladeproperties");
+  gtk_widget_class_bind_template_child (widget_class, GbpGladeProperties, editor);
+}
+
+static void
+gbp_glade_properties_init (GbpGladeProperties *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  dzl_dock_widget_set_title (DZL_DOCK_WIDGET (self), _("Unnamed Glade Project"));
+  dzl_dock_widget_set_icon_name (DZL_DOCK_WIDGET (self), "glade-symbolic");
+}
+
+void
+gbp_glade_properties_set_widget (GbpGladeProperties *self,
+                                 GladeWidget        *widget)
+{
+  g_return_if_fail (GBP_IS_GLADE_PROPERTIES (self));
+  g_return_if_fail (!widget || GLADE_IS_WIDGET (widget));
+
+  if (widget != NULL)
+    glade_editor_load_widget (self->editor, widget);
+}
diff --git a/src/plugins/glade/gbp-glade-properties.h b/src/plugins/glade/gbp-glade-properties.h
new file mode 100644
index 000000000..352b150b2
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-properties.h
@@ -0,0 +1,35 @@
+/* gbp-glade-properties.h
+ *
+ * Copyright 2018 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
+ */
+
+#pragma once
+
+#include <gladeui/glade.h>
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_GLADE_PROPERTIES (gbp_glade_properties_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpGladeProperties, gbp_glade_properties, GBP, GLADE_PROPERTIES, DzlDockWidget)
+
+void gbp_glade_properties_set_widget (GbpGladeProperties *self,
+                                      GladeWidget        *widget);
+
+G_END_DECLS
diff --git a/src/plugins/glade/gbp-glade-properties.ui b/src/plugins/glade/gbp-glade-properties.ui
new file mode 100644
index 000000000..c9a0981c4
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-properties.ui
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GbpGladeProperties" parent="DzlDockWidget">
+    <child>
+      <object class="GladeEditor" id="editor">
+        <property name="visible">true</property>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/plugins/glade/gbp-glade-view.c b/src/plugins/glade/gbp-glade-view.c
new file mode 100644
index 000000000..2f88ae0e0
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-view.c
@@ -0,0 +1,191 @@
+/* gbp-glade-view.c
+ *
+ * Copyright 2018 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"
+
+#define G_LOG_DOMAIN "gbp-glade-view"
+
+#include <glib/gi18n.h>
+#include <gladeui/glade.h>
+
+#include "gbp-glade-view.h"
+
+struct _GbpGladeView
+{
+  IdeLayoutView    parent_instance;
+  GladeProject    *project;
+  GladeDesignView *designer;
+};
+
+G_DEFINE_TYPE (GbpGladeView, gbp_glade_view, IDE_TYPE_LAYOUT_VIEW)
+
+/**
+ * gbp_glade_view_new:
+ *
+ * Create a new #GbpGladeView.
+ *
+ * Returns: (transfer full): a newly created #GbpGladeView
+ */
+GbpGladeView *
+gbp_glade_view_new (void)
+{
+  return g_object_new (GBP_TYPE_GLADE_VIEW, NULL);
+}
+
+static void
+gbp_glade_view_dispose (GObject *object)
+{
+  GbpGladeView *self = (GbpGladeView *)object;
+
+  g_clear_object (&self->project);
+
+  G_OBJECT_CLASS (gbp_glade_view_parent_class)->dispose (object);
+}
+
+static void
+gbp_glade_view_class_init (GbpGladeViewClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose = gbp_glade_view_dispose;
+
+  gtk_widget_class_set_css_name (widget_class, "gbpgladeview");
+}
+
+static void
+gbp_glade_view_init (GbpGladeView *self)
+{
+  ide_layout_view_set_menu_id (IDE_LAYOUT_VIEW (self), "gbp-glade-view-menu");
+  ide_layout_view_set_title (IDE_LAYOUT_VIEW (self), _("Unnamed Glade project"));
+  ide_layout_view_set_icon_name (IDE_LAYOUT_VIEW (self), "glade-symbolic");
+
+  self->project = glade_project_new ();
+  self->designer = g_object_new (GLADE_TYPE_DESIGN_VIEW,
+                                 "project", self->project,
+                                 "vexpand", TRUE,
+                                 "visible", TRUE,
+                                 NULL);
+  dzl_gtk_widget_add_style_class (GTK_WIDGET (self->designer), "glade-designer");
+  gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->designer));
+
+  glade_app_add_project (self->project);
+
+  g_object_bind_property (G_OBJECT (self->project), "modified", self, "modified", G_BINDING_DEFAULT);
+}
+
+/**
+ * gbp_glade_view_get_project:
+ *
+ * Returns: (transfer none): A #GladeProject or %NULL
+ */
+GladeProject *
+gbp_glade_view_get_project (GbpGladeView *self)
+{
+  g_return_val_if_fail (GBP_IS_GLADE_VIEW (self), NULL);
+
+  return self->project;
+}
+
+static void
+gbp_glade_view_load_file_map_cb (GladeDesignView *designer,
+                                 IdeTask         *task)
+{
+  g_autofree gchar *name = NULL;
+  GbpGladeView *self;
+  const gchar *path;
+  GFile *file;
+
+  g_assert (GLADE_IS_DESIGN_VIEW (designer));
+  g_assert (IDE_IS_TASK (task));
+  g_assert (gtk_widget_get_mapped (GTK_WIDGET (designer)));
+
+  self = ide_task_get_source_object (task);
+  file = ide_task_get_task_data (task);
+
+  g_signal_handlers_disconnect_by_func (self->designer,
+                                        G_CALLBACK (gbp_glade_view_load_file_map_cb),
+                                        task);
+
+  if (!g_file_is_native (file))
+    {
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_INVALID_FILENAME,
+                                 "File must be a local file");
+      return;
+    }
+
+  path = g_file_peek_path (file);
+
+  if (!glade_project_load_from_file (self->project, path))
+    ide_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_FAILED,
+                               "Failed to load glade project");
+  else
+    ide_task_return_boolean (task, TRUE);
+
+  name = glade_project_get_name (self->project);
+  ide_layout_view_set_title (IDE_LAYOUT_VIEW (self), name);
+}
+
+void
+gbp_glade_view_load_file_async (GbpGladeView        *self,
+                                GFile               *file,
+                                GCancellable        *cancellable,
+                                GAsyncReadyCallback  callback,
+                                gpointer             user_data)
+{
+  g_autoptr(IdeTask) task = NULL;
+
+  g_return_if_fail (GBP_IS_GLADE_VIEW (self));
+  g_return_if_fail (G_IS_FILE (file));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, gbp_glade_view_load_file_async);
+  ide_task_set_task_data (task, g_object_ref (file), g_object_unref);
+
+  /* We can't load the file until we have been mapped or else we see an issue
+   * where toplevels cannot be parented properly. If we come across that, then
+   * delay until the widget is mapped.
+   */
+  if (!gtk_widget_get_mapped (GTK_WIDGET (self->designer)))
+    g_signal_connect_data (self->designer,
+                           "map",
+                           G_CALLBACK (gbp_glade_view_load_file_map_cb),
+                           g_steal_pointer (&task),
+                           (GClosureNotify)g_object_unref,
+                           0);
+  else
+    gbp_glade_view_load_file_map_cb (self->designer, task);
+}
+
+gboolean
+gbp_glade_view_load_file_finish (GbpGladeView  *self,
+                                 GAsyncResult  *result,
+                                 GError       **error)
+{
+  g_return_val_if_fail (GBP_IS_GLADE_VIEW (self), FALSE);
+  g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+
+  return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
diff --git a/src/plugins/glade/gbp-glade-view.h b/src/plugins/glade/gbp-glade-view.h
new file mode 100644
index 000000000..c82a447ac
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-view.h
@@ -0,0 +1,43 @@
+/* gbp-glade-view.h
+ *
+ * Copyright 2018 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
+ */
+
+#pragma once
+
+#include <gladeui/glade.h>
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_GLADE_VIEW (gbp_glade_view_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpGladeView, gbp_glade_view, GBP, GLADE_VIEW, IdeLayoutView)
+
+GbpGladeView *gbp_glade_view_new              (void);
+void          gbp_glade_view_load_file_async  (GbpGladeView         *self,
+                                               GFile                *file,
+                                               GCancellable         *cancellable,
+                                               GAsyncReadyCallback   callback,
+                                               gpointer              user_data);
+gboolean      gbp_glade_view_load_file_finish (GbpGladeView         *self,
+                                               GAsyncResult         *result,
+                                               GError              **error);
+GladeProject *gbp_glade_view_get_project      (GbpGladeView         *self);
+
+G_END_DECLS
diff --git a/src/plugins/glade/glade.gresource.xml b/src/plugins/glade/glade.gresource.xml
new file mode 100644
index 000000000..c7261f130
--- /dev/null
+++ b/src/plugins/glade/glade.gresource.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/builder/plugins">
+    <file>glade.plugin</file>
+  </gresource>
+  <gresource prefix="/org/gnome/builder/plugins/glade-plugin">
+    <file>gtk/menus.ui</file>
+    <file>themes/shared.css</file>
+    <file>themes/Adwaita.css</file>
+    <file>themes/Adwaita-dark.css</file>
+    <file>gbp-glade-properties.ui</file>
+  </gresource>
+</gresources>
diff --git a/src/plugins/glade/glade.plugin b/src/plugins/glade/glade.plugin
new file mode 100644
index 000000000..d818163e1
--- /dev/null
+++ b/src/plugins/glade/glade.plugin
@@ -0,0 +1,9 @@
+[Plugin]
+Module=glade-plugin
+Name=Glade
+Description=Integration with Glade UI designer for Gtk
+Authors=Christian Hergert <christian hergert me>
+Copyright=Copyright © 2018 Christian Hergert
+Depends=editor;
+Builtin=true
+Embedded=gbp_glade_register_types
diff --git a/src/plugins/glade/gtk/menus.ui b/src/plugins/glade/gtk/menus.ui
new file mode 100644
index 000000000..35a5e0969
--- /dev/null
+++ b/src/plugins/glade/gtk/menus.ui
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<interface>
+</interface>
+
diff --git a/src/plugins/glade/meson.build b/src/plugins/glade/meson.build
new file mode 100644
index 000000000..e46c85cac
--- /dev/null
+++ b/src/plugins/glade/meson.build
@@ -0,0 +1,24 @@
+if get_option('with_glade')
+
+glade_resources = gnome.compile_resources(
+  'glade-resources',
+  'glade.gresource.xml',
+  c_name: 'gbp_glade',
+)
+
+glade_sources = [
+  'gbp-glade-editor-addin.c',
+  'gbp-glade-layout-stack-addin.c',
+  'gbp-glade-plugin.c',
+  'gbp-glade-properties.c',
+  'gbp-glade-view.c',
+]
+
+gnome_builder_plugins_deps += [
+  dependency('gladeui-2.0', version: '>=3.22.0'),
+]
+
+gnome_builder_plugins_sources += files(glade_sources)
+gnome_builder_plugins_sources += glade_resources[0]
+
+endif
diff --git a/src/plugins/glade/themes/Adwaita-dark.css b/src/plugins/glade/themes/Adwaita-dark.css
new file mode 100644
index 000000000..22630a640
--- /dev/null
+++ b/src/plugins/glade/themes/Adwaita-dark.css
@@ -0,0 +1,9 @@
+@import url("resource:///org/gnome/builder/plugins/glade-plugin/themes/shared.css");
+
+/* Draw our grid over the glade background pattern */
+gbpgladeview viewport {
+  background-color: #232729;
+  background-size: 8px 8px;
+  background-image: repeating-linear-gradient(0deg, #2e2e2e, #2e2e2e 1px, transparent 1px, transparent 8px),
+                    repeating-linear-gradient(-90deg, #2e2e2e, #2e2e2e 1px, transparent 1px, transparent 
8px);
+}
diff --git a/src/plugins/glade/themes/Adwaita.css b/src/plugins/glade/themes/Adwaita.css
new file mode 100644
index 000000000..5131ba34b
--- /dev/null
+++ b/src/plugins/glade/themes/Adwaita.css
@@ -0,0 +1,9 @@
+@import url("resource:///org/gnome/builder/plugins/glade-plugin/themes/shared.css");
+
+/* Draw our grid over the glade background pattern */
+gbpgladeview viewport {
+  background-color: #f6f7f8;
+  background-size: 8px 8px;
+  background-image: repeating-linear-gradient(0deg, #f0f1f2, #f0f1f2 1px, transparent 1px, transparent 8px),
+                    repeating-linear-gradient(-90deg, #f0f1f2, #f0f1f2 1px, transparent 1px, transparent 
8px);
+}
diff --git a/src/plugins/glade/themes/shared.css b/src/plugins/glade/themes/shared.css
new file mode 100644
index 000000000..dc2984a68
--- /dev/null
+++ b/src/plugins/glade/themes/shared.css
@@ -0,0 +1,19 @@
+popover.glade-stack-header {
+  padding: 12px;
+}
+
+popover.glade-stack-header treeview {
+  background: transparent;
+  margin: 12px;
+  color: @theme_fg_color;
+}
+
+popover.glade-stack-header scrolledwindow {
+  border: none;
+}
+
+popover.glade-stack-header entry {
+  margin-bottom: 12px;
+}
+
+
diff --git a/src/plugins/meson.build b/src/plugins/meson.build
index f5a60d7b0..9ca823dae 100644
--- a/src/plugins/meson.build
+++ b/src/plugins/meson.build
@@ -34,6 +34,7 @@ subdir('gdb')
 subdir('gettext')
 subdir('git')
 subdir('gjs-symbols')
+subdir('glade')
 subdir('gnome-code-assistance')
 subdir('go-langserv')
 subdir('history')
@@ -118,6 +119,7 @@ status += [
   'Gettext ............... : @0@'.format(get_option('with_gettext')),
   'Git ................... : @0@'.format(get_option('with_git')),
   'GJS Symbol Resolver ... : @0@'.format(get_option('with_gjs_symbols')),
+  'Glade ................. : @0@'.format(get_option('with_glade')),
   'GNOME Code Assistance . : @0@'.format(get_option('with_gnome_code_assistance')),
   'Go Language Server .... : @0@'.format(get_option('with_go_langserv')),
   'History ............... : @0@'.format(get_option('with_history')),



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