[gnome-builder] pausable: add object helper for pausable operations



commit 5bbe3df23537bf84c2acbad7f1cc5ec70b512405
Author: Christian Hergert <chergert redhat com>
Date:   Tue Sep 5 01:15:07 2017 -0700

    pausable: add object helper for pausable operations
    
    This gives us something we can let the context own to describe pausable
    operations. We can then integrate it into the popover so that the user
    has an escape hatch on expensive background operations.

 libide/ide-context.c  |   74 ++++++++++++++-
 libide/ide-context.h  |    4 +
 libide/ide-internal.h |    1 +
 libide/ide-pausable.c |  251 +++++++++++++++++++++++++++++++++++++++++++++++++
 libide/ide-pausable.h |   42 ++++++++
 libide/ide-types.h    |    2 +
 libide/ide.h          |    1 +
 libide/meson.build    |   12 ++-
 8 files changed, 379 insertions(+), 8 deletions(-)
---
diff --git a/libide/ide-context.c b/libide/ide-context.c
index 72e0a78..66d877e 100644
--- a/libide/ide-context.c
+++ b/libide/ide-context.c
@@ -25,6 +25,7 @@
 #include "ide-debug.h"
 #include "ide-global.h"
 #include "ide-internal.h"
+#include "ide-pausable.h"
 #include "ide-service.h"
 
 #include "buffers/ide-buffer-manager.h"
@@ -72,6 +73,7 @@ struct _IdeContext
   IdeDeviceManager         *device_manager;
   IdeDoap                  *doap;
   IdeDocumentation         *documentation;
+  GListStore               *pausables;
   GtkRecentManager         *recent_manager;
   IdeRunManager            *run_manager;
   IdeRuntimeManager        *runtime_manager;
@@ -499,11 +501,11 @@ ide_context_loaded (IdeContext *self)
 static void
 ide_context_dispose (GObject *object)
 {
+  IdeContext *self = (IdeContext *)object;
+
   IDE_ENTRY;
 
-  /*
-   * TODO: Shutdown services.
-   */
+  g_list_store_remove_all (self->pausables);
 
   G_OBJECT_CLASS (ide_context_parent_class)->dispose (object);
 
@@ -518,6 +520,7 @@ ide_context_finalize (GObject *object)
   IDE_ENTRY;
 
   g_clear_object (&self->services);
+  g_clear_object (&self->pausables);
 
   g_clear_pointer (&self->build_system_hint, g_free);
   g_clear_pointer (&self->services_by_gtype, g_hash_table_unref);
@@ -769,6 +772,8 @@ ide_context_init (IdeContext *self)
 
   g_mutex_init (&self->unload_mutex);
 
+  self->pausables = g_list_store_new (IDE_TYPE_PAUSABLE);
+
   self->recent_manager = g_object_ref (gtk_recent_manager_get_default ());
 
   self->root_build_dir = g_build_filename (g_get_user_cache_dir (),
@@ -2337,3 +2342,66 @@ ide_context_get_debug_manager (IdeContext *self)
 
   return self->debug_manager;
 }
+
+/**
+ * ide_context_add_pausable:
+ * @self: an #IdeContext
+ * @pausable: an #IdePausable
+ *
+ * Adds a pausable which can be used to associate pausable actions with the
+ * context. Various UI in Builder may use this to present pausable actions to
+ * the user.
+ *
+ * Since: 3.26
+ */
+void
+ide_context_add_pausable (IdeContext  *self,
+                          IdePausable *pausable)
+{
+  g_return_if_fail (IDE_IS_CONTEXT (self));
+  g_return_if_fail (IDE_IS_PAUSABLE (pausable));
+
+  g_list_store_append (self->pausables, pausable);
+}
+
+/**
+ * ide_context_remove_pausable:
+ * @self: an #IdeContext
+ * @pausable: an #IdePausable
+ *
+ * Remove a previously registered #IdePausable.
+ *
+ * Since: 3.26
+ */
+void
+ide_context_remove_pausable (IdeContext  *self,
+                             IdePausable *pausable)
+{
+  guint n_items;
+
+  g_return_if_fail (IDE_IS_CONTEXT (self));
+  g_return_if_fail (IDE_IS_PAUSABLE (pausable));
+
+  n_items = g_list_model_get_n_items (G_LIST_MODEL (self->pausables));
+
+  for (guint i = 0; i < n_items; i++)
+    {
+      g_autoptr(IdePausable) item = NULL;
+
+      item = g_list_model_get_item (G_LIST_MODEL (self->pausables), i);
+
+      if (item == pausable)
+        {
+          g_list_store_remove (self->pausables, i);
+          break;
+        }
+    }
+}
+
+GListModel *
+_ide_context_get_pausables (IdeContext *self)
+{
+  g_return_val_if_fail (IDE_IS_CONTEXT (self), NULL);
+
+  return G_LIST_MODEL (self->pausables);
+}
diff --git a/libide/ide-context.h b/libide/ide-context.h
index 474bb0f..3231640 100644
--- a/libide/ide-context.h
+++ b/libide/ide-context.h
@@ -76,6 +76,10 @@ void                      ide_context_restore_async             (IdeContext
 gboolean                  ide_context_restore_finish            (IdeContext           *self,
                                                                  GAsyncResult         *result,
                                                                  GError              **error);
+void                      ide_context_add_pausable              (IdeContext           *self,
+                                                                 IdePausable          *pausable);
+void                      ide_context_remove_pausable           (IdeContext           *self,
+                                                                 IdePausable          *pausable);
 void                      ide_context_hold                      (IdeContext           *self);
 void                      ide_context_hold_for_object           (IdeContext           *self,
                                                                  gpointer              instance);
diff --git a/libide/ide-internal.h b/libide/ide-internal.h
index a3d9a7d..5654735 100644
--- a/libide/ide-internal.h
+++ b/libide/ide-internal.h
@@ -41,6 +41,7 @@ void                _ide_configuration_set_prebuild         (IdeConfiguration
 void                _ide_configuration_set_postbuild        (IdeConfiguration      *self,
                                                              IdeBuildCommandQueue  *postbuild);
 gboolean            _ide_context_is_restoring               (IdeContext            *self);
+GListModel         *_ide_context_get_pausables              (IdeContext            *self);
 const gchar        *_ide_file_get_content_type              (IdeFile               *self);
 GtkSourceFile      *_ide_file_set_content_type              (IdeFile               *self,
                                                              const gchar           *content_type);
diff --git a/libide/ide-pausable.c b/libide/ide-pausable.c
new file mode 100644
index 0000000..fc5d882
--- /dev/null
+++ b/libide/ide-pausable.c
@@ -0,0 +1,251 @@
+/* ide-pausable.c
+ *
+ * Copyright (C) 2017 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 "ide-pausable"
+
+#include "ide-pausable.h"
+
+struct _IdePausable
+{
+  GObject  parent_instance;
+
+  gchar   *title;
+  gchar   *subtitle;
+
+  guint    paused : 1;
+};
+
+enum {
+  PROP_0,
+  PROP_TITLE,
+  PROP_SUBTITLE,
+  PROP_PAUSED,
+  N_PROPS
+};
+
+enum {
+  PAUSED,
+  UNPAUSED,
+  N_SIGNALS
+};
+
+G_DEFINE_TYPE (IdePausable, ide_pausable, G_TYPE_OBJECT)
+
+static GParamSpec *properties [N_PROPS];
+static guint signals [N_SIGNALS];
+
+static void
+ide_pausable_finalize (GObject *object)
+{
+  IdePausable *self = (IdePausable *)object;
+
+  g_clear_pointer (&self->title, g_free);
+  g_clear_pointer (&self->subtitle, g_free);
+
+  G_OBJECT_CLASS (ide_pausable_parent_class)->finalize (object);
+}
+
+static void
+ide_pausable_get_property (GObject    *object,
+                           guint       prop_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+  IdePausable *self = IDE_PAUSABLE (object);
+
+  switch (prop_id)
+    {
+    case PROP_TITLE:
+      g_value_set_string (value, self->title);
+      break;
+
+    case PROP_SUBTITLE:
+      g_value_set_string (value, self->subtitle);
+      break;
+
+    case PROP_PAUSED:
+      g_value_set_boolean (value, ide_pausable_get_paused (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_pausable_set_property (GObject      *object,
+                           guint         prop_id,
+                           const GValue *value,
+                           GParamSpec   *pspec)
+{
+  IdePausable *self = IDE_PAUSABLE (object);
+
+  switch (prop_id)
+    {
+    case PROP_TITLE:
+      ide_pausable_set_title (self, g_value_get_string (value));
+      break;
+
+    case PROP_SUBTITLE:
+      ide_pausable_set_subtitle (self, g_value_get_string (value));
+      break;
+
+    case PROP_PAUSED:
+      ide_pausable_set_paused (self, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_pausable_class_init (IdePausableClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = ide_pausable_finalize;
+  object_class->get_property = ide_pausable_get_property;
+  object_class->set_property = ide_pausable_set_property;
+
+  properties [PROP_PAUSED] =
+    g_param_spec_boolean ("paused", NULL, NULL, FALSE,
+                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  properties [PROP_TITLE] =
+    g_param_spec_string ("title", NULL, NULL, NULL,
+                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  properties [PROP_SUBTITLE] =
+    g_param_spec_string ("subtitle", NULL, NULL, NULL,
+                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  signals [PAUSED] =
+    g_signal_new ("paused",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  signals [UNPAUSED] =
+    g_signal_new ("unpaused",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+}
+
+static void
+ide_pausable_init (IdePausable *self)
+{
+}
+
+IdePausable *
+ide_pausable_new (void)
+{
+  return g_object_new (IDE_TYPE_PAUSABLE, NULL);
+}
+
+const gchar *
+ide_pausable_get_title (IdePausable *self)
+{
+  g_return_val_if_fail (IDE_IS_PAUSABLE (self), NULL);
+
+  return self->title;
+}
+
+void
+ide_pausable_set_title (IdePausable *self,
+                        const gchar *title)
+{
+  if (g_strcmp0 (title, self->title) != 0)
+    {
+      g_free (self->title);
+      self->title = g_strdup (title);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
+    }
+}
+
+const gchar *
+ide_pausable_get_subtitle (IdePausable *self)
+{
+  g_return_val_if_fail (IDE_IS_PAUSABLE (self), NULL);
+
+  return self->subtitle;
+}
+
+void
+ide_pausable_set_subtitle (IdePausable *self,
+                           const gchar *subtitle)
+{
+  if (g_strcmp0 (subtitle, self->subtitle) != 0)
+    {
+      g_free (self->subtitle);
+      self->subtitle = g_strdup (subtitle);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SUBTITLE]);
+    }
+}
+
+gboolean
+ide_pausable_get_paused (IdePausable *self)
+{
+  g_return_val_if_fail (IDE_IS_PAUSABLE (self), FALSE);
+
+  return self->paused;
+}
+
+void
+ide_pausable_set_paused (IdePausable *self,
+                         gboolean     paused)
+{
+  g_return_if_fail (IDE_IS_PAUSABLE (self));
+
+  paused = !!paused;
+
+  if (self->paused != paused)
+    {
+      self->paused = paused;
+
+      if (paused)
+        g_signal_emit (self, signals [PAUSED], 0);
+      else
+        g_signal_emit (self, signals [UNPAUSED], 0);
+
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PAUSED]);
+    }
+}
+
+void
+ide_pausable_pause (IdePausable *self)
+{
+  g_return_if_fail (IDE_IS_PAUSABLE (self));
+
+  ide_pausable_set_paused (self, TRUE);
+}
+
+void
+ide_pausable_unpause (IdePausable *self)
+{
+  g_return_if_fail (IDE_IS_PAUSABLE (self));
+
+  ide_pausable_set_paused (self, FALSE);
+}
diff --git a/libide/ide-pausable.h b/libide/ide-pausable.h
new file mode 100644
index 0000000..b9b669f
--- /dev/null
+++ b/libide/ide-pausable.h
@@ -0,0 +1,42 @@
+/* ide-pausable.h
+ *
+ * Copyright (C) 2017 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/>.
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_PAUSABLE (ide_pausable_get_type())
+
+G_DECLARE_FINAL_TYPE (IdePausable, ide_pausable, IDE, PAUSABLE, GObject)
+
+IdePausable *ide_pausable_new          (void);
+gboolean     ide_pausable_get_paused   (IdePausable *self);
+void         ide_pausable_set_paused   (IdePausable *self,
+                                        gboolean     paused);
+void         ide_pausable_pause        (IdePausable *self);
+void         ide_pausable_unpause      (IdePausable *self);
+const gchar *ide_pausable_get_title    (IdePausable *self);
+void         ide_pausable_set_title    (IdePausable *self,
+                                        const gchar *title);
+const gchar *ide_pausable_get_subtitle (IdePausable *self);
+void         ide_pausable_set_subtitle (IdePausable *self,
+                                        const gchar *subtitle);
+
+G_END_DECLS
diff --git a/libide/ide-types.h b/libide/ide-types.h
index 0661c15..32f0f60 100644
--- a/libide/ide-types.h
+++ b/libide/ide-types.h
@@ -84,6 +84,8 @@ typedef struct _IdeIndenter                    IdeIndenter;
 
 typedef struct _IdeObject                      IdeObject;
 
+typedef struct _IdePausable                    IdePausable;
+
 typedef struct _IdeProgress                    IdeProgress;
 
 typedef struct _IdeProject                     IdeProject;
diff --git a/libide/ide.h b/libide/ide.h
index 71a52b7..421f901 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -33,6 +33,7 @@ G_BEGIN_DECLS
 #include "ide-global.h"
 #include "ide-macros.h"
 #include "ide-object.h"
+#include "ide-pausable.h"
 #include "ide-service.h"
 #include "ide-version.h"
 
diff --git a/libide/meson.build b/libide/meson.build
index 72b6d0f..d63e58e 100644
--- a/libide/meson.build
+++ b/libide/meson.build
@@ -49,13 +49,14 @@ libide_enums = gnome.mkenums('ide-enums',
 )
 
 libide_public_headers = [
+  'ide.h',
   'ide-context.h',
   'ide-global.h',
   'ide-macros.h',
   'ide-object.h',
+  'ide-pausable.h',
   'ide-service.h',
   'ide-types.h',
-  'ide.h',
   'application/ide-application-addin.h',
   'application/ide-application-credits.h',
   'application/ide-application-tool.h',
@@ -271,6 +272,11 @@ libide_icons_resources = gnome.compile_resources('ide-icons-resources',
 )
 
 libide_public_sources = [
+  'ide.c',
+  'ide-context.c',
+  'ide-object.c',
+  'ide-pausable.c',
+  'ide-service.c',
   'application/ide-application-addin.c',
   'application/ide-application-tool.c',
   'application/ide-application.c',
@@ -344,10 +350,6 @@ libide_public_sources = [
   'highlighting/ide-highlight-engine.c',
   'highlighting/ide-highlight-index.c',
   'highlighting/ide-highlighter.c',
-  'ide-context.c',
-  'ide-object.c',
-  'ide-service.c',
-  'ide.c',
   'langserv/ide-langserv-client.c',
   'langserv/ide-langserv-completion-provider.c',
   'langserv/ide-langserv-diagnostic-provider.c',


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