[gnome-builder/wip/commands] commands: wip on command bar and commands api



commit bf5a9940bf804b8e6d19835f853c93136407a7df
Author: Christian Hergert <christian hergert me>
Date:   Mon Oct 6 19:43:52 2014 -0700

    commands: wip on command bar and commands api

 src/commandbar/gb-command-bar.c           |  152 ++++++++++++++++++++
 src/commandbar/gb-command-bar.h           |   58 ++++++++
 src/commands/gb-command-manager.c         |  103 +++++++++++++
 src/commands/gb-command-manager.h         |   59 ++++++++
 src/commands/gb-command-result.c          |  221 +++++++++++++++++++++++++++++
 src/commands/gb-command-result.h          |   65 +++++++++
 src/commands/gb-command.c                 |  203 ++++++++++++++++++++++++++
 src/commands/gb-command.h                 |   88 ++++++++++++
 src/gnome-builder.mk                      |   10 ++
 src/resources/css/builder.Adwaita.css     |   17 +++
 src/resources/gnome-builder.gresource.xml |    1 +
 src/resources/ui/gb-command-bar.ui        |   60 ++++++++
 test-command-bar                          |  Bin 0 -> 127641 bytes
 tests/test-command-bar.c                  |   49 +++++++
 tests/tests.mk                            |    5 +
 15 files changed, 1091 insertions(+), 0 deletions(-)
---
diff --git a/src/commandbar/gb-command-bar.c b/src/commandbar/gb-command-bar.c
new file mode 100644
index 0000000..45c0d19
--- /dev/null
+++ b/src/commandbar/gb-command-bar.c
@@ -0,0 +1,152 @@
+/* gb-command-bar.c
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#include "gb-command-bar.h"
+#include "gb-string.h"
+
+struct _GbCommandBarPrivate
+{
+  GtkEntry          *entry;
+  GtkFrame          *frame;
+  GtkListBox        *list_box;
+  GtkScrolledWindow *scroller;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GbCommandBar, gb_command_bar, GTK_TYPE_REVEALER)
+
+GtkWidget *
+gb_command_bar_new (void)
+{
+  return g_object_new (GB_TYPE_COMMAND_BAR, NULL);
+}
+
+/**
+ * gb_command_bar_hide:
+ * @bar: A #GbCommandBar
+ * 
+ * Hides the command bar in an animated fashion.
+ */
+void
+gb_command_bar_hide (GbCommandBar *bar)
+{
+  g_return_if_fail (GB_IS_COMMAND_BAR (bar));
+
+  gtk_revealer_set_reveal_child (GTK_REVEALER (bar), FALSE);
+}
+
+/**
+ * gb_command_bar_show:
+ * @bar: A #GbCommandBar
+ * 
+ * Shows the command bar in an animated fashion.
+ */
+void
+gb_command_bar_show (GbCommandBar *bar)
+{
+  g_return_if_fail (GB_IS_COMMAND_BAR (bar));
+
+  gtk_revealer_set_reveal_child (GTK_REVEALER (bar), TRUE);
+}
+
+static void
+gb_command_bar_on_entry_activate (GbCommandBar *bar,
+                                  GtkEntry     *entry)
+{
+  const gchar *text;
+
+  g_return_if_fail (GB_IS_COMMAND_BAR (bar));
+  g_return_if_fail (GTK_IS_ENTRY (entry));
+
+  text = gtk_entry_get_text (entry);
+
+  if (gb_str_empty0 (text))
+    {
+      gb_command_bar_hide (bar);
+      return;
+    }
+}
+
+static gboolean
+gb_command_bar_on_entry_key_press_event (GbCommandBar *bar,
+                                         GdkEventKey  *event,
+                                         GtkEntry     *entry)
+{
+  g_return_val_if_fail (GB_IS_COMMAND_BAR (bar), FALSE);
+  g_return_val_if_fail (event, FALSE);
+  g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
+
+  if (event->keyval == GDK_KEY_Escape)
+    {
+      gb_command_bar_hide (bar);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+gb_command_bar_constructed (GObject *object)
+{
+  GbCommandBar *bar = (GbCommandBar *)object;
+
+  G_OBJECT_CLASS (gb_command_bar_parent_class)->constructed (object);
+
+  g_signal_connect_object (bar->priv->entry,
+                           "activate",
+                           G_CALLBACK (gb_command_bar_on_entry_activate),
+                           bar,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (bar->priv->entry,
+                           "key-press-event",
+                           G_CALLBACK (gb_command_bar_on_entry_key_press_event),
+                           bar,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+gb_command_bar_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (gb_command_bar_parent_class)->finalize (object);
+}
+
+static void
+gb_command_bar_class_init (GbCommandBarClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->constructed = gb_command_bar_constructed;
+  object_class->finalize = gb_command_bar_finalize;
+
+  gtk_widget_class_set_template_from_resource (widget_class,
+                                               "/org/gnome/builder/ui/gb-command-bar.ui");
+
+  gtk_widget_class_bind_template_child_private (widget_class, GbCommandBar, entry);
+  gtk_widget_class_bind_template_child_private (widget_class, GbCommandBar, frame);
+  gtk_widget_class_bind_template_child_private (widget_class, GbCommandBar, list_box);
+  gtk_widget_class_bind_template_child_private (widget_class, GbCommandBar, scroller);
+}
+
+static void
+gb_command_bar_init (GbCommandBar *self)
+{
+  self->priv = gb_command_bar_get_instance_private (self);
+
+  gtk_widget_init_template (GTK_WIDGET (self));
+}
diff --git a/src/commandbar/gb-command-bar.h b/src/commandbar/gb-command-bar.h
new file mode 100644
index 0000000..7f120b8
--- /dev/null
+++ b/src/commandbar/gb-command-bar.h
@@ -0,0 +1,58 @@
+/* gb-command-bar.h
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#ifndef GB_COMMAND_BAR_H
+#define GB_COMMAND_BAR_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_COMMAND_BAR            (gb_command_bar_get_type())
+#define GB_COMMAND_BAR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND_BAR, 
GbCommandBar))
+#define GB_COMMAND_BAR_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND_BAR, GbCommandBar 
const))
+#define GB_COMMAND_BAR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_COMMAND_BAR, 
GbCommandBarClass))
+#define GB_IS_COMMAND_BAR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_COMMAND_BAR))
+#define GB_IS_COMMAND_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_COMMAND_BAR))
+#define GB_COMMAND_BAR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_COMMAND_BAR, 
GbCommandBarClass))
+
+typedef struct _GbCommandBar        GbCommandBar;
+typedef struct _GbCommandBarClass   GbCommandBarClass;
+typedef struct _GbCommandBarPrivate GbCommandBarPrivate;
+
+struct _GbCommandBar
+{
+  GtkRevealer parent;
+
+  /*< private >*/
+  GbCommandBarPrivate *priv;
+};
+
+struct _GbCommandBarClass
+{
+  GtkRevealerClass parent;
+};
+
+GType      gb_command_bar_get_type (void) G_GNUC_CONST;
+GtkWidget *gb_command_bar_new      (void);
+void       gb_command_bar_show     (GbCommandBar *bar);
+void       gb_command_bar_hide     (GbCommandBar *bar);
+
+G_END_DECLS
+
+#endif /* GB_COMMAND_BAR_H */
diff --git a/src/commands/gb-command-manager.c b/src/commands/gb-command-manager.c
new file mode 100644
index 0000000..83c6fe8
--- /dev/null
+++ b/src/commands/gb-command-manager.c
@@ -0,0 +1,103 @@
+/* gb-command-manager.c
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#include "gb-command-manager.h"
+
+/**
+ * SECTION:gb-command-manager:
+ * @title: GbCommandManager
+ * @short_description: command management
+ * 
+ * This class is responsible for storing available commands in the process.
+ * It is also responsible for looking them up to dispatch an operation to the
+ * right command instance.
+ * 
+ * Typically, you want to use the default #GbCommandManager instance which
+ * can be fetched with gb_command_manager_get_default().
+ * 
+ * Note that GbCommandManager is NOT thread safe. It should only be used
+ * from the main thread. However, Some commands may asynchronously perform
+ * their work in a background thread.
+ */
+
+struct _GbCommandManagerPrivate
+{
+  GHashTable *commands;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GbCommandManager, gb_command_manager, G_TYPE_OBJECT)
+
+GbCommandManager *
+gb_command_manager_new (void)
+{
+  return g_object_new (GB_TYPE_COMMAND_MANAGER, NULL);
+}
+
+GbCommandManager *
+gb_command_manager_get_default (void)
+{
+  static GbCommandManager *instance;
+
+  if (!instance)
+    instance = gb_command_manager_new ();
+  
+  return instance;
+}
+
+void
+gb_command_manager_register (GbCommandManager *manager,
+                             GbCommand        *command)
+{
+  gchar *name;
+
+  g_return_if_fail (GB_IS_COMMAND_MANAGER (manager));
+  g_return_if_fail (GB_IS_COMMAND (command));
+
+  name = g_strdup (gb_command_get_name (command));
+
+  if (g_hash_table_lookup (manager->priv->commands, name))
+    g_warning ("A command named \"%s\" has already been registered.", name);
+
+  g_hash_table_replace (manager->priv->commands, name, g_object_ref (command));
+}
+
+static void
+gb_command_manager_finalize (GObject *object)
+{
+  GbCommandManagerPrivate *priv = GB_COMMAND_MANAGER (object)->priv;
+
+  g_clear_pointer (&priv->commands, g_hash_table_unref);
+
+  G_OBJECT_CLASS (gb_command_manager_parent_class)->finalize (object);
+}
+
+static void
+gb_command_manager_class_init (GbCommandManagerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gb_command_manager_finalize;
+}
+
+static void
+gb_command_manager_init (GbCommandManager *self)
+{
+  self->priv = gb_command_manager_get_instance_private (self);
+  self->priv->commands = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                g_free, g_object_unref);
+}
diff --git a/src/commands/gb-command-manager.h b/src/commands/gb-command-manager.h
new file mode 100644
index 0000000..fff6da3
--- /dev/null
+++ b/src/commands/gb-command-manager.h
@@ -0,0 +1,59 @@
+/* gb-command-manager.h
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#ifndef GB_COMMAND_MANAGER_H
+#define GB_COMMAND_MANAGER_H
+
+#include "gb-command.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_COMMAND_MANAGER            (gb_command_manager_get_type())
+#define GB_COMMAND_MANAGER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND_MANAGER, 
GbCommandManager))
+#define GB_COMMAND_MANAGER_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND_MANAGER, 
GbCommandManager const))
+#define GB_COMMAND_MANAGER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_COMMAND_MANAGER, 
GbCommandManagerClass))
+#define GB_IS_COMMAND_MANAGER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_COMMAND_MANAGER))
+#define GB_IS_COMMAND_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_COMMAND_MANAGER))
+#define GB_COMMAND_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_COMMAND_MANAGER, 
GbCommandManagerClass))
+
+typedef struct _GbCommandManager        GbCommandManager;
+typedef struct _GbCommandManagerClass   GbCommandManagerClass;
+typedef struct _GbCommandManagerPrivate GbCommandManagerPrivate;
+
+struct _GbCommandManager
+{
+  GObject parent;
+
+  /*< private >*/
+  GbCommandManagerPrivate *priv;
+};
+
+struct _GbCommandManagerClass
+{
+  GObjectClass parent;
+};
+
+GType             gb_command_manager_get_type    (void) G_GNUC_CONST;
+GbCommandManager *gb_command_manager_new         (void);
+GbCommandManager *gb_command_manager_get_default (void);
+void              gb_command_manager_register    (GbCommandManager *manager,
+                                                  GbCommand        *command);
+
+G_END_DECLS
+
+#endif /* GB_COMMAND_MANAGER_H */
diff --git a/src/commands/gb-command-result.c b/src/commands/gb-command-result.c
new file mode 100644
index 0000000..7c60997
--- /dev/null
+++ b/src/commands/gb-command-result.c
@@ -0,0 +1,221 @@
+/* gb-command-result.c
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#include <glib/gi18n.h>
+
+#include "gb-command-result.h"
+
+struct _GbCommandResultPrivate
+{
+  gchar *text;
+  guint  success : 1;
+  guint  use_markup : 1;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GbCommandResult, gb_command_result, G_TYPE_OBJECT)
+
+enum {
+  PROP_0,
+  PROP_SUCCESS,
+  PROP_TEXT,
+  PROP_USE_MARKUP,
+  LAST_PROP
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+
+GbCommandResult *
+gb_command_result_new (void)
+{
+  return g_object_new (GB_TYPE_COMMAND_RESULT, NULL);
+}
+
+gboolean
+gb_command_result_get_success (GbCommandResult *result)
+{
+  g_return_val_if_fail (GB_IS_COMMAND_RESULT (result), NULL);
+
+  return result->priv->success;
+}
+
+void
+gb_command_result_set_success (GbCommandResult *result,
+                               gboolean         success)
+{
+  g_return_if_fail (GB_IS_COMMAND_RESULT (result));
+  
+  if (success != result->priv->success)
+    {
+      result->priv->success = success;
+      g_object_notify_by_pspec (G_OBJECT (result), gParamSpecs [PROP_SUCCESS]);
+    }
+}
+
+const gchar *
+gb_command_result_get_text (GbCommandResult *result)
+{
+  g_return_val_if_fail (GB_IS_COMMAND_RESULT (result), NULL);
+
+  return result->priv->text;
+}
+
+void
+gb_command_result_set_text (GbCommandResult *result,
+                            const gchar     *text)
+{
+  g_return_if_fail (GB_IS_COMMAND_RESULT (result));
+
+  if (text != result->priv->text)
+    {
+      g_free (result->priv->text);
+      result->priv->text = g_strdup (text);
+      g_object_notify_by_pspec (G_OBJECT (result), gParamSpecs [PROP_TEXT]);
+    }
+}
+
+gboolean
+gb_command_result_get_use_markup (GbCommandResult *result)
+{
+  g_return_val_if_fail (GB_IS_COMMAND_RESULT (result), FALSE);
+
+  return result->priv->use_markup;
+}
+
+void
+gb_command_result_set_use_markup (GbCommandResult *result,
+                                  gboolean         use_markup)
+{
+  g_return_if_fail (GB_IS_COMMAND_RESULT (result));
+  
+  if (result->priv->use_markup != use_markup)
+    {
+      result->priv->use_markup = use_markup;
+      g_object_notify_by_pspec (G_OBJECT (result),
+                                gParamSpecs [PROP_USE_MARKUP]);
+    }
+}
+
+static void
+gb_command_result_finalize (GObject *object)
+{
+  GbCommandResultPrivate *priv = GB_COMMAND_RESULT (object)->priv;
+
+  g_clear_pointer (&priv->text, g_free);
+
+  G_OBJECT_CLASS (gb_command_result_parent_class)->finalize (object);
+}
+
+static void
+gb_command_result_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  GbCommandResult *self = GB_COMMAND_RESULT (object);
+
+  switch (prop_id)
+    {
+    case PROP_SUCCESS:
+      g_value_set_boolean (value, gb_command_result_get_success (self));
+      break;
+
+    case PROP_TEXT:
+      g_value_set_string (value, gb_command_result_get_text (self));
+      break;
+
+    case PROP_USE_MARKUP:
+      g_value_set_boolean (value, gb_command_result_get_use_markup (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gb_command_result_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  GbCommandResult *self = GB_COMMAND_RESULT (object);
+
+  switch (prop_id)
+    {
+    case PROP_SUCCESS:
+      gb_command_result_set_success (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_TEXT:
+      gb_command_result_set_text (self, g_value_get_string (value));
+      break;
+
+    case PROP_USE_MARKUP:
+      gb_command_result_set_use_markup (self, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gb_command_result_class_init (GbCommandResultClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gb_command_result_finalize;
+  object_class->get_property = gb_command_result_get_property;
+  object_class->set_property = gb_command_result_set_property;
+  
+  gParamSpecs [PROP_SUCCESS] =
+    g_param_spec_boolean ("success",
+                          _("Success"),
+                          _("If the command was successful."),
+                          FALSE,
+                          (G_PARAM_READWRITE |
+                           G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_SUCCESS,
+                                   gParamSpecs [PROP_SUCCESS]);
+  
+  gParamSpecs [PROP_TEXT] =
+    g_param_spec_string ("text",
+                         _("Text"),
+                         _("The text for the results view."),
+                         NULL,
+                         (G_PARAM_READWRITE |
+                          G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_TEXT,
+                                   gParamSpecs [PROP_TEXT]);
+  
+  gParamSpecs [PROP_USE_MARKUP] =
+    g_param_spec_boolean ("use-markup",
+                          _("Use Markup"),
+                          _("If the text property contains markup."),
+                          FALSE,
+                          (G_PARAM_READWRITE |
+                           G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_USE_MARKUP,
+                                   gParamSpecs [PROP_USE_MARKUP]);
+}
+
+static void
+gb_command_result_init (GbCommandResult *self)
+{
+  self->priv = gb_command_result_get_instance_private (self);
+}
diff --git a/src/commands/gb-command-result.h b/src/commands/gb-command-result.h
new file mode 100644
index 0000000..51a82bb
--- /dev/null
+++ b/src/commands/gb-command-result.h
@@ -0,0 +1,65 @@
+/* gb-command-result.h
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#ifndef GB_COMMAND_RESULT_H
+#define GB_COMMAND_RESULT_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_COMMAND_RESULT            (gb_command_result_get_type())
+#define GB_COMMAND_RESULT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND_RESULT, 
GbCommandResult))
+#define GB_COMMAND_RESULT_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND_RESULT, 
GbCommandResult const))
+#define GB_COMMAND_RESULT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_COMMAND_RESULT, 
GbCommandResultClass))
+#define GB_IS_COMMAND_RESULT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_COMMAND_RESULT))
+#define GB_IS_COMMAND_RESULT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_COMMAND_RESULT))
+#define GB_COMMAND_RESULT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_COMMAND_RESULT, 
GbCommandResultClass))
+
+typedef struct _GbCommandResult        GbCommandResult;
+typedef struct _GbCommandResultClass   GbCommandResultClass;
+typedef struct _GbCommandResultPrivate GbCommandResultPrivate;
+
+struct _GbCommandResult
+{
+  GObject parent;
+
+  /*< private >*/
+  GbCommandResultPrivate *priv;
+};
+
+struct _GbCommandResultClass
+{
+  GObjectClass parent;
+};
+
+GType            gb_command_result_get_type       (void) G_GNUC_CONST;
+GbCommandResult *gb_command_result_new            (void);
+gboolean         gb_command_result_get_success    (GbCommandResult *result);
+void             gb_command_result_set_success    (GbCommandResult *result,
+                                                   gboolean         success);
+const gchar     *gb_command_result_get_text       (GbCommandResult *result);
+void             gb_command_result_set_text       (GbCommandResult *result,
+                                                   const gchar     *text);
+gboolean         gb_command_result_get_use_markup (GbCommandResult *result);
+void             gb_command_result_set_use_markup (GbCommandResult *result,
+                                                   gboolean         use_markup);
+
+G_END_DECLS
+
+#endif /* GB_COMMAND_RESULT_H */
diff --git a/src/commands/gb-command.c b/src/commands/gb-command.c
new file mode 100644
index 0000000..35b6969
--- /dev/null
+++ b/src/commands/gb-command.c
@@ -0,0 +1,203 @@
+/* gb-command.c
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#include <glib/gi18n.h>
+
+#include "gb-command.h"
+
+struct _GbCommandPrivate
+{
+  gchar *description;
+  gchar *name;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GbCommand, gb_command, G_TYPE_OBJECT)
+
+enum {
+  PROP_0,
+  PROP_DESCRIPTION,
+  PROP_NAME,
+  LAST_PROP
+};
+
+enum {
+  EXECUTE_ASYNC,
+  EXECUTE_FINISH,
+  LAST_SIGNAL
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+static guint       gSignals [LAST_SIGNAL];
+
+GbCommand *
+gb_command_new (void)
+{
+  return g_object_new (GB_TYPE_COMMAND, NULL);
+}
+
+const gchar *
+gb_command_get_name (GbCommand *command)
+{
+  g_return_val_if_fail (GB_IS_COMMAND (command), NULL);
+
+  return command->priv->name;
+}
+
+void
+gb_command_set_name (GbCommand   *command,
+                     const gchar *name)
+{
+  g_return_if_fail (GB_IS_COMMAND (command));
+  
+  if (name != command->priv->name)
+    {
+      g_free (command->priv->name);
+      command->priv->name = g_strdup (name);
+      g_object_notify_by_pspec (G_OBJECT (command), gParamSpecs [PROP_NAME]);
+    }
+}
+
+void
+gb_command_set_description (GbCommand   *command,
+                            const gchar *description)
+{
+  g_return_if_fail (GB_IS_COMMAND (command));
+  
+  if (description != command->priv->description)
+    {
+      g_free (command->priv->description);
+      command->priv->description = g_strdup (description);
+      g_object_notify_by_pspec (G_OBJECT (command),
+                                gParamSpecs [PROP_DESCRIPTION]);
+    }
+}
+
+void
+gb_command_execute_async (GbCommand           *command,
+                          GVariant            *parameter,
+                          GCancellable        *cancellable,
+                          GAsyncReadyCallback  callback,
+                          gpointer             user_data)
+{
+  g_return_if_fail (GB_IS_COMMAND (command));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+}
+
+GbCommandResult *
+gb_command_execute_finish (GbCommand     *command,
+                           GAsyncResult  *result,
+                           GError       **error)
+{
+  g_return_if_fail (GB_IS_COMMAND (command));
+  g_return_if_fail (G_IS_ASYNC_RESULT (result));
+}
+
+static void
+gb_command_finalize (GObject *object)
+{
+  GbCommandPrivate *priv = GB_COMMAND (object)->priv;
+
+  g_clear_pointer (&priv->description, g_free);
+  g_clear_pointer (&priv->name, g_free);
+
+  G_OBJECT_CLASS (gb_command_parent_class)->finalize (object);
+}
+
+static void
+gb_command_get_property (GObject    *object,
+                         guint       prop_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
+{
+  GbCommand *self = GB_COMMAND (object);
+
+  switch (prop_id)
+    {
+    case PROP_DESCRIPTION:
+      g_value_set_string (value, gb_command_get_description (self));
+      break;
+
+    case PROP_NAME:
+      g_value_set_string (value, gb_command_get_name (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gb_command_set_property (GObject      *object,
+                         guint         prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+  GbCommand *self = GB_COMMAND (object);
+
+  switch (prop_id)
+    {
+    case PROP_DESCRIPTION:
+      gb_command_set_description (self, g_value_get_string (value));
+      break;
+      
+    case PROP_NAME:
+      gb_command_set_name (self, g_value_get_string (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gb_command_class_init (GbCommandClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gb_command_finalize;
+  object_class->get_property = gb_command_get_property;
+  object_class->set_property = gb_command_set_property;
+  
+  gParamSpecs [PROP_DESCRIPTION] =
+    g_param_spec_string ("description",
+                         _("Description"),
+                         _("The description of the command"),
+                         NULL,
+                         (G_PARAM_READWRITE |
+                          G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_DESCRIPTION,
+                                   gParamSpecs [PROP_DESCRIPTION]);
+  
+  gParamSpecs [PROP_NAME] =
+    g_param_spec_string ("name",
+                         _("Name"),
+                         _("The name of the command."),
+                         NULL,
+                         (G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_NAME,
+                                   gParamSpecs [PROP_NAME]);
+}
+
+static void
+gb_command_init (GbCommand *self)
+{
+  self->priv = gb_command_get_instance_private (self);
+}
diff --git a/src/commands/gb-command.h b/src/commands/gb-command.h
new file mode 100644
index 0000000..560cb52
--- /dev/null
+++ b/src/commands/gb-command.h
@@ -0,0 +1,88 @@
+/* gb-command.h
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#ifndef GB_COMMAND_H
+#define GB_COMMAND_H
+
+#include <gio/gio.h>
+
+#include "gb-command-result.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_COMMAND            (gb_command_get_type())
+#define GB_COMMAND(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND, GbCommand))
+#define GB_COMMAND_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_COMMAND, GbCommand const))
+#define GB_COMMAND_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_COMMAND, GbCommandClass))
+#define GB_IS_COMMAND(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_COMMAND))
+#define GB_IS_COMMAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_COMMAND))
+#define GB_COMMAND_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_COMMAND, GbCommandClass))
+
+typedef struct _GbCommand        GbCommand;
+typedef struct _GbCommandClass   GbCommandClass;
+typedef struct _GbCommandPrivate GbCommandPrivate;
+
+struct _GbCommand
+{
+  GObject parent;
+
+  /*< private >*/
+  GbCommandPrivate *priv;
+};
+
+struct _GbCommandClass
+{
+  GObjectClass parent;
+  
+  void             (*execute_async)  (GbCommand            *command,
+                                      GVariant             *parameter,
+                                      GCancellable         *cancellable,
+                                      GAsyncReadyCallback   callback,
+                                      gpointer              user_data);
+  GbCommandResult *(*execute_finish) (GbCommand            *command,
+                                      GAsyncResult         *result,
+                                      GError              **error);
+
+  gpointer _padding1;
+  gpointer _padding2;
+  gpointer _padding3;
+  gpointer _padding4;
+  gpointer _padding5;
+  gpointer _padding6;
+};
+
+GType           gb_command_get_type        (void) G_GNUC_CONST;
+GbCommand      *gb_command_new             (void);
+const gchar    *gb_command_get_name        (GbCommand            *command);
+void            gb_command_set_name        (GbCommand            *command,
+                                            const gchar          *name);
+const gchar    *gb_command_get_description (GbCommand            *command);
+void            gb_command_set_description (GbCommand            *command,
+                                            const gchar          *description);
+void            gb_command_execute_async   (GbCommand            *command,
+                                            GVariant             *parameter,
+                                            GCancellable         *cancellable,
+                                            GAsyncReadyCallback   callback,
+                                            gpointer              user_data);
+GbCommandResult *gb_command_execute_finish (GbCommand            *command,
+                                            GAsyncResult         *result,
+                                            GError              **error);
+
+G_END_DECLS
+
+#endif /* GB_COMMAND_H */
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index 0f212d3..9522d6e 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -9,6 +9,14 @@ libgnome_builder_la_SOURCES = \
        src/animation/gb-frame-source.h \
        src/app/gb-application.c \
        src/app/gb-application.h \
+       src/commandbar/gb-command-bar.c \
+       src/commandbar/gb-command-bar.h \
+       src/commands/gb-command.c \
+       src/commands/gb-command.h \
+       src/commands/gb-command-manager.c \
+       src/commands/gb-command-manager.h \
+       src/commands/gb-command-result.c \
+       src/commands/gb-command-result.h \
        src/devhelp/gb-devhelp-navigation-item.c \
        src/devhelp/gb-devhelp-navigation-item.h \
        src/devhelp/gb-devhelp-tab.c \
@@ -136,6 +144,8 @@ libgnome_builder_la_CFLAGS = \
        $(WEBKIT_CFLAGS) \
        -I$(top_srcdir)/src/animation \
        -I$(top_srcdir)/src/app \
+       -I$(top_srcdir)/src/commandbar \
+       -I$(top_srcdir)/src/commands \
        -I$(top_srcdir)/src/devhelp \
        -I$(top_srcdir)/src/editor \
        -I$(top_srcdir)/src/gd \
diff --git a/src/resources/css/builder.Adwaita.css b/src/resources/css/builder.Adwaita.css
index 9910e7f..754e5cd 100644
--- a/src/resources/css/builder.Adwaita.css
+++ b/src/resources/css/builder.Adwaita.css
@@ -139,3 +139,20 @@ GtkStackSwitcher.gb-workspace-switcher > GtkRadioButton:active {
     padding: 10px;
 }
 
+
+/*
+ * Command bar styling.
+ */
+.gb-command-bar-frame {
+    background-color: shade (@theme_base_color, 0.8);
+    padding: 6px;
+    border-color: shade (@theme_base_color, 0.6);
+    border-radius: 3px 3px 0 0;
+    border-width: 1px 1px 0 1px;
+    border-style: solid;
+}
+GtkEntry.gb-command-bar {
+    padding: 10px;
+    font-family: Monospace;
+    font-size: 1.1em;
+}
diff --git a/src/resources/gnome-builder.gresource.xml b/src/resources/gnome-builder.gresource.xml
index 15a2508..710cbd7 100644
--- a/src/resources/gnome-builder.gresource.xml
+++ b/src/resources/gnome-builder.gresource.xml
@@ -17,6 +17,7 @@
     <file>snippets/c.snippets</file>
     <file>snippets/chdr.snippets</file>
 
+    <file>ui/gb-command-bar.ui</file>
     <file>ui/gb-devhelp-tab.ui</file>
     <file>ui/gb-editor-tab.ui</file>
     <file>ui/gb-preferences-window.ui</file>
diff --git a/src/resources/ui/gb-command-bar.ui b/src/resources/ui/gb-command-bar.ui
new file mode 100644
index 0000000..3b42f6d
--- /dev/null
+++ b/src/resources/ui/gb-command-bar.ui
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.8 -->
+  <template class="GbCommandBar" parent="GtkRevealer">
+    <property name="visible">True</property>
+    <property name="transition-type">GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP</property>
+    <child>
+      <object class="GtkFrame" id="frame">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <property name="vexpand">True</property>
+        <style>
+          <class name="gb-command-bar-frame"/>
+        </style>
+        <child>
+          <object class="GtkBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="can-focus">False</property>
+            <property name="orientation">vertical</property>
+            <style>
+              <class name="linked"/>
+            </style>
+            <child>
+              <object class="GtkScrolledWindow" id="scroller">
+                <property name="visible">False</property>
+                <property name="expand">True</property>
+                <child>
+                  <object class="GtkListBox" id="list_box">
+                    <property name="visible">True</property>
+                    <property name="expand">True</property>
+                  </object>
+                  <style>
+                    <class name="view"/>
+                  </style>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkSeparator" id="hsep1">
+                <property name="visible">True</property>
+                <property name="orientation">horizontal</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkEntry" id="entry">
+                <property name="visible">True</property>
+                <property name="has-frame">False</property>
+                <property name="expand">False</property>
+                <property name="valign">end</property>
+                <style>
+                  <class name="gb-command-bar"/>
+                </style>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/test-command-bar b/test-command-bar
new file mode 100755
index 0000000..32d49b6
Binary files /dev/null and b/test-command-bar differ
diff --git a/tests/test-command-bar.c b/tests/test-command-bar.c
new file mode 100644
index 0000000..fc736a9
--- /dev/null
+++ b/tests/test-command-bar.c
@@ -0,0 +1,49 @@
+#include "gb-command-bar.h"
+#include "gb-resources.h"
+
+gint
+main (gint argc,
+      gchar *argv[])
+{
+  GtkWindow *win;
+  GtkWidget *bar;
+
+  gtk_init (&argc, &argv);
+  
+  g_resources_register (gb_get_resource ());
+
+  {
+    GtkCssProvider *provider;
+    GdkScreen *screen;
+    GFile *file;
+  
+    provider = gtk_css_provider_new ();
+    file = g_file_new_for_uri ("resource:///org/gnome/builder/css/builder.Adwaita.css");
+    gtk_css_provider_load_from_file (provider, file, NULL);
+    g_object_unref (file);
+
+    screen = gdk_screen_get_default ();
+    gtk_style_context_add_provider_for_screen (screen,
+                                               GTK_STYLE_PROVIDER (provider),
+                                               GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+  }
+
+  win = g_object_new (GTK_TYPE_WINDOW,
+                      "decorated", FALSE,
+                      "default-width", 600,
+                      "title", "command-bar-test",
+                      NULL);
+
+  bar = g_object_new (GB_TYPE_COMMAND_BAR,
+                      "visible", TRUE,
+                      NULL);
+  gtk_container_add (GTK_CONTAINER (win), bar);
+
+  gb_command_bar_show (GB_COMMAND_BAR (bar));
+
+  g_signal_connect (win, "delete-event", gtk_main_quit, NULL);
+  gtk_window_present (win);
+  gtk_main ();
+
+  return 0;
+}
diff --git a/tests/tests.mk b/tests/tests.mk
index ec7438b..889595e 100644
--- a/tests/tests.mk
+++ b/tests/tests.mk
@@ -10,3 +10,8 @@ TESTS += test-navigation-list
 test_navigation_list_SOURCES = tests/test-navigation-list.c
 test_navigation_list_CFLAGS = $(libgnome_builder_la_CFLAGS)
 test_navigation_list_LDADD = libgnome-builder.la
+
+noinst_PROGRAMS += test-command-bar
+test_command_bar_SOURCES = tests/test-command-bar.c $(gnome_builder_built_sources)
+test_command_bar_CFLAGS = $(libgnome_builder_la_CFLAGS)
+test_command_bar_LDADD = libgnome-builder.la



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