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



commit 14b75f38e2a6de252fd24f40d17a8e4efd482ff2
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 +
 po/POTFILES.in                                   |   6 +
 src/plugins/glade/gbp-glade-editor-addin.c       | 286 +++++++++++++++++++++++
 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-private.h            |  40 ++++
 src/plugins/glade/gbp-glade-properties.c         | 125 ++++++++++
 src/plugins/glade/gbp-glade-properties.h         |  35 +++
 src/plugins/glade/gbp-glade-properties.ui        |  77 ++++++
 src/plugins/glade/gbp-glade-view-actions.c       |  71 ++++++
 src/plugins/glade/gbp-glade-view.c               | 189 +++++++++++++++
 src/plugins/glade/gbp-glade-view.h               |  43 ++++
 src/plugins/glade/glade.gresource.xml            |  16 ++
 src/plugins/glade/glade.plugin                   |   9 +
 src/plugins/glade/gtk/menus.ui                   |  14 ++
 src/plugins/glade/meson.build                    |  25 ++
 src/plugins/glade/themes/Adwaita-dark.css        |   9 +
 src/plugins/glade/themes/Adwaita-shared.css      |  37 +++
 src/plugins/glade/themes/Adwaita.css             |   9 +
 src/plugins/glade/themes/shared.css              |  23 ++
 src/plugins/meson.build                          |   2 +
 24 files changed, 1256 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/po/POTFILES.in b/po/POTFILES.in
index 6a8372693..dfc7093f3 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -182,6 +182,12 @@ src/plugins/git/ide-git-pipeline-addin.c
 src/plugins/git/ide-git-remote-callbacks.c
 src/plugins/git/ide-git-submodule-stage.c
 src/plugins/git/ide-git-vcs.c
+src/plugins/glade/gbp-glade-editor-addin.c
+src/plugins/glade/gbp-glade-layout-stack-addin.c
+src/plugins/glade/gbp-glade-properties.c
+src/plugins/glade/gbp-glade-properties.ui
+src/plugins/glade/gbp-glade-view.c
+src/plugins/glade/gbp-glade-view-actions.c
 src/plugins/gnome-code-assistance/ide-gca-diagnostic-provider.c
 src/plugins/gnome-code-assistance/ide-gca-preferences-addin.c
 src/plugins/gnome-code-assistance/ide-gca-service.c
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..9964e7c25
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-editor-addin.c
@@ -0,0 +1,286 @@
+/* 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 <glib/gi18n.h>
+
+#include "gbp-glade-editor-addin.h"
+#include "gbp-glade-properties.h"
+#include "gbp-glade-view.h"
+
+struct _GbpGladeEditorAddin
+{
+  GObject               parent_instance;
+
+  /* Widgets */
+  IdeEditorPerspective *editor;
+  GbpGladeProperties   *properties;
+  GladeSignalEditor    *signals;
+  DzlDockWidget        *signals_dock;
+
+  /* Owned references */
+  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);
+
+      gbp_glade_properties_set_widget (self->properties, glade);
+      glade_signal_editor_load_widget (self->signals, glade);
+      gtk_widget_show (GTK_WIDGET (self->signals_dock));
+    }
+  else
+    {
+      gbp_glade_properties_set_widget (self->properties, NULL);
+      glade_signal_editor_load_widget (self->signals, NULL);
+      gtk_widget_hide (GTK_WIDGET (self->signals_dock));
+    }
+}
+
+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_autofree gchar *freeme = NULL;
+  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);
+
+  if (!g_path_is_absolute (path))
+    {
+      IdeContext *context = ide_widget_get_context (GTK_WIDGET (self->editor));
+      path = freeme = ide_context_build_filename (context, path, NULL);
+    }
+
+  file = g_file_new_for_path (path);
+
+  view = gbp_glade_view_new ();
+  gtk_container_add (GTK_CONTAINER (self->editor), GTK_WIDGET (view));
+  gtk_widget_show (GTK_WIDGET (view));
+
+  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;
+    }
+  else
+    {
+      gtk_widget_hide (GTK_WIDGET (self->signals_dock));
+    }
+
+  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;
+  GtkWidget *utils;
+
+  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);
+  utils = ide_editor_perspective_get_utilities (self->editor);
+
+  self->properties = g_object_new (GBP_TYPE_GLADE_PROPERTIES,
+                                   "visible", TRUE,
+                                   NULL);
+  gtk_container_add (GTK_CONTAINER (transient), GTK_WIDGET (self->properties));
+
+  self->signals_dock = g_object_new (DZL_TYPE_DOCK_WIDGET,
+                                     "title", _("Signals"),
+                                     "icon-name", "glade-symbolic",
+                                     "visible", TRUE,
+                                     NULL);
+  gtk_container_add (GTK_CONTAINER (utils), GTK_WIDGET (self->signals_dock));
+
+  self->signals = g_object_new (GLADE_TYPE_SIGNAL_EDITOR,
+                                "visible", TRUE,
+                                NULL);
+  gtk_container_add (GTK_CONTAINER (self->signals_dock), GTK_WIDGET (self->signals));
+}
+
+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-private.h b/src/plugins/glade/gbp-glade-private.h
new file mode 100644
index 000000000..f577b751c
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-private.h
@@ -0,0 +1,40 @@
+/* gbp-glade-private.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>
+#include <gladeui/glade.h>
+
+#include "gbp-glade-view.h"
+
+G_BEGIN_DECLS
+
+struct _GbpGladeView
+{
+  IdeLayoutView    parent_instance;
+  GFile           *file;
+  GladeProject    *project;
+  GladeDesignView *designer;
+};
+
+void _gbp_glade_view_init_actions (GbpGladeView *self);
+
+G_END_DECLS
diff --git a/src/plugins/glade/gbp-glade-properties.c b/src/plugins/glade/gbp-glade-properties.c
new file mode 100644
index 000000000..3b5b0e53a
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-properties.c
@@ -0,0 +1,125 @@
+/* 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;
+  GtkStackSwitcher *stack_switcher;
+  GtkStack         *stack;
+  DzlDockWidget    *a11y_dock;
+  DzlDockWidget    *common_dock;
+  DzlDockWidget    *general_dock;
+  DzlDockWidget    *packing_dock;
+};
+
+G_DEFINE_TYPE (GbpGladeProperties, gbp_glade_properties, DZL_TYPE_DOCK_WIDGET)
+
+static void
+adjust_radio_hexpand (GtkWidget *widget,
+                      gpointer   user_data)
+{
+  gtk_widget_set_hexpand (widget, TRUE);
+}
+
+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, stack);
+  gtk_widget_class_bind_template_child (widget_class, GbpGladeProperties, stack_switcher);
+  gtk_widget_class_bind_template_child (widget_class, GbpGladeProperties, a11y_dock);
+  gtk_widget_class_bind_template_child (widget_class, GbpGladeProperties, common_dock);
+  gtk_widget_class_bind_template_child (widget_class, GbpGladeProperties, general_dock);
+  gtk_widget_class_bind_template_child (widget_class, GbpGladeProperties, packing_dock);
+}
+
+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");
+
+  gtk_container_foreach (GTK_CONTAINER (self->stack_switcher), adjust_radio_hexpand, NULL);
+}
+
+void
+gbp_glade_properties_set_widget (GbpGladeProperties *self,
+                                 GladeWidget        *widget)
+{
+  GladeWidgetAdaptor *adapter;
+  GladeEditable *editable;
+  GladeWidget *parent;
+
+  g_return_if_fail (GBP_IS_GLADE_PROPERTIES (self));
+  g_return_if_fail (!widget || GLADE_IS_WIDGET (widget));
+
+  gtk_container_foreach (GTK_CONTAINER (self->a11y_dock), (GtkCallback)gtk_widget_destroy, NULL);
+  gtk_container_foreach (GTK_CONTAINER (self->general_dock), (GtkCallback)gtk_widget_destroy, NULL);
+  gtk_container_foreach (GTK_CONTAINER (self->common_dock), (GtkCallback)gtk_widget_destroy, NULL);
+  gtk_container_foreach (GTK_CONTAINER (self->packing_dock), (GtkCallback)gtk_widget_destroy, NULL);
+
+  if (widget == NULL)
+    return;
+
+  adapter = glade_widget_get_adaptor (widget);
+
+  /* General page */
+  editable = glade_widget_adaptor_create_editable (adapter, GLADE_PAGE_GENERAL);
+  gtk_container_add (GTK_CONTAINER (self->general_dock), GTK_WIDGET (editable));
+  glade_editable_load (editable, widget);
+  gtk_widget_show (GTK_WIDGET (editable));
+
+  /* Packing page */
+  if ((parent = glade_widget_get_parent (widget)))
+    {
+      GladeWidgetAdaptor *parent_adapter;
+
+      parent_adapter = glade_widget_get_adaptor (parent);
+      editable = glade_widget_adaptor_create_editable (parent_adapter, GLADE_PAGE_PACKING);
+      gtk_container_add (GTK_CONTAINER (self->packing_dock), GTK_WIDGET (editable));
+      glade_editable_load (editable, widget);
+      gtk_widget_show (GTK_WIDGET (editable));
+    }
+
+  /* Common page */
+  editable = glade_widget_adaptor_create_editable (adapter, GLADE_PAGE_COMMON);
+  gtk_container_add (GTK_CONTAINER (self->common_dock), GTK_WIDGET (editable));
+  glade_editable_load (editable, widget);
+  gtk_widget_show (GTK_WIDGET (editable));
+
+  /* A11y page */
+  editable = glade_widget_adaptor_create_editable (adapter, GLADE_PAGE_ATK);
+  gtk_container_add (GTK_CONTAINER (self->a11y_dock), GTK_WIDGET (editable));
+  glade_editable_load (editable, widget);
+  gtk_widget_show (GTK_WIDGET (editable));
+}
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..b748d0726
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-properties.ui
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GbpGladeProperties" parent="DzlDockWidget">
+    <child>
+      <object class="GtkScrolledWindow">
+        <property name="hscrollbar-policy">never</property>
+        <property name="visible">true</property>
+        <child>
+          <object class="GtkBox">
+            <property name="border-width">6</property>
+            <property name="spacing">6</property>
+            <property name="vexpand">true</property>
+            <property name="orientation">vertical</property>
+            <property name="visible">true</property>
+            <child>
+              <object class="GtkStackSwitcher" id="stack_switcher">
+                <property name="halign">fill</property>
+                <property name="hexpand">true</property>
+                <property name="stack">stack</property>
+                <property name="visible">true</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkStack" id="stack">
+                <property name="interpolate-size">true</property>
+                <property name="transition-type">crossfade</property>
+                <property name="homogeneous">false</property>
+                <property name="vexpand">true</property>
+                <property name="visible">true</property>
+                <child>
+                  <object class="DzlDockWidget" id="general_dock">
+                    <property name="visible">true</property>
+                  </object>
+                  <packing>
+                    <property name="name">general</property>
+                    <property name="title" translatable="yes">General</property>
+                    <property name="icon-name">system-run-symbolic</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="DzlDockWidget" id="packing_dock">
+                    <property name="visible">true</property>
+                  </object>
+                  <packing>
+                    <property name="name">packing</property>
+                    <property name="title" translatable="yes">Packing</property>
+                    <property name="icon-name">system-run-symbolic</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="DzlDockWidget" id="common_dock">
+                    <property name="visible">true</property>
+                  </object>
+                  <packing>
+                    <property name="name">common</property>
+                    <property name="title" translatable="yes">Common</property>
+                    <property name="icon-name">system-run-symbolic</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="DzlDockWidget" id="a11y_dock">
+                    <property name="visible">true</property>
+                  </object>
+                  <packing>
+                    <property name="name">a11y</property>
+                    <property name="title" translatable="yes">Accessibility</property>
+                    <property name="icon-name">preferences-desktop-accessibility-symbolic</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/plugins/glade/gbp-glade-view-actions.c b/src/plugins/glade/gbp-glade-view-actions.c
new file mode 100644
index 000000000..2de792da3
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-view-actions.c
@@ -0,0 +1,71 @@
+/* gbp-glade-view-actions.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-actions"
+
+#include <glib/gi18n.h>
+
+#include "gbp-glade-private.h"
+
+static void
+gbp_glade_view_action_save (GSimpleAction *action,
+                            GVariant      *param,
+                            gpointer       user_data)
+{
+  GbpGladeView *self = user_data;
+  g_autoptr(GError) error = NULL;
+  const gchar *path;
+
+  g_assert (G_IS_SIMPLE_ACTION (action));
+  g_assert (GBP_IS_GLADE_VIEW (self));
+
+  if (self->file == NULL || !(path = g_file_peek_path (self->file)))
+    {
+      g_warning ("GbpGladeView is missing a file");
+      return;
+    }
+
+  if (!glade_project_save (self->project, path, &error))
+    /* translators: %s is replaced with the specific error message */
+    ide_widget_warning (self, _("Failed to save glade document: %s"), error->message);
+}
+
+static GActionEntry actions[] = {
+  { "save", gbp_glade_view_action_save },
+};
+
+void
+_gbp_glade_view_init_actions (GbpGladeView *self)
+{
+  g_autoptr(GSimpleActionGroup) group = NULL;
+
+  g_assert (GBP_IS_GLADE_VIEW (self));
+
+  group = g_simple_action_group_new ();
+  g_action_map_add_action_entries (G_ACTION_MAP (group),
+                                   actions,
+                                   G_N_ELEMENTS (actions),
+                                   self);
+  gtk_widget_insert_action_group (GTK_WIDGET (self),
+                                  "glade-view",
+                                  G_ACTION_GROUP (group));
+}
diff --git a/src/plugins/glade/gbp-glade-view.c b/src/plugins/glade/gbp-glade-view.c
new file mode 100644
index 000000000..2993871a6
--- /dev/null
+++ b/src/plugins/glade/gbp-glade-view.c
@@ -0,0 +1,189 @@
+/* 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 "gbp-glade-view.h"
+#include "gbp-glade-private.h"
+
+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");
+  ide_layout_view_set_menu_id (IDE_LAYOUT_VIEW (self), "gbp-glade-view-document-menu");
+
+  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_init_actions (self);
+}
+
+/**
+ * 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);
+
+  g_set_object (&self->file, file);
+
+  /* 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..fc9b5e994
--- /dev/null
+++ b/src/plugins/glade/glade.gresource.xml
@@ -0,0 +1,16 @@
+<?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>gbp-glade-properties.ui</file>
+
+    <file>themes/shared.css</file>
+    <file>themes/Adwaita.css</file>
+    <file>themes/Adwaita-dark.css</file>
+    <file>themes/Adwaita-shared.css</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..9c18b6883
--- /dev/null
+++ b/src/plugins/glade/gtk/menus.ui
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<interface>
+  <menu id="gbp-glade-view-document-menu">
+    <section id="glade-document-section">
+      <attribute name="label" translatable="yes">Glade</attribute>
+      <item>
+        <attribute name="action">glade-view.save</attribute>
+        <attribute name="label" translatable="yes">_Save</attribute>
+        <attribute name="accel">&lt;primary&gt;s</attribute>
+      </item>
+    </section>
+  </menu>
+</interface>
+
diff --git a/src/plugins/glade/meson.build b/src/plugins/glade/meson.build
new file mode 100644
index 000000000..c20e16779
--- /dev/null
+++ b/src/plugins/glade/meson.build
@@ -0,0 +1,25 @@
+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',
+  'gbp-glade-view-actions.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..d07260036
--- /dev/null
+++ b/src/plugins/glade/themes/Adwaita-dark.css
@@ -0,0 +1,9 @@
+@import url("resource:///org/gnome/builder/plugins/glade-plugin/themes/Adwaita-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-shared.css b/src/plugins/glade/themes/Adwaita-shared.css
new file mode 100644
index 000000000..600aafbdb
--- /dev/null
+++ b/src/plugins/glade/themes/Adwaita-shared.css
@@ -0,0 +1,37 @@
+@import url("resource:///org/gnome/builder/plugins/glade-plugin/themes/shared.css");
+
+gbpgladeproperties {
+  font-size: 0.83333em;
+}
+
+gbpgladeproperties entry,
+gbpgladeproperties spinbutton {
+  min-height: 24px;
+}
+
+gbpgladeproperties checkbutton check {
+  min-width: 10px;
+  min-height: 10px;
+}
+
+gbpgladeproperties spinbutton button {
+  min-height: 0px;
+  min-width: 0px;
+  padding: 0 4px;
+}
+
+gbpgladeproperties spinbutton entry {
+  min-height: 0px;
+  min-width: 0px;
+  padding: 0 4px;
+}
+
+gbpgladeproperties switch slider {
+  min-height: 18px;
+  min-width: 32px;
+}
+
+gbpgladeproperties button.combo {
+  min-height: 18px;
+  padding: 2px;
+}
diff --git a/src/plugins/glade/themes/Adwaita.css b/src/plugins/glade/themes/Adwaita.css
new file mode 100644
index 000000000..f7efb392b
--- /dev/null
+++ b/src/plugins/glade/themes/Adwaita.css
@@ -0,0 +1,9 @@
+@import url("resource:///org/gnome/builder/plugins/glade-plugin/themes/Adwaita-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..d1a3e856e
--- /dev/null
+++ b/src/plugins/glade/themes/shared.css
@@ -0,0 +1,23 @@
+gbpgladeproperties {
+  font-size: 0.83333em;
+}
+
+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]