[gimp] app: add ability to remove an extension.



commit f7e483dd64023115a3ad3e428a569baf0b78ecb0
Author: Jehan <jehan girinstud io>
Date:   Mon Apr 29 14:33:45 2019 +0900

    app: add ability to remove an extension.
    
    Removing an extension means just unloading it and temporarily move it to
    an "uninstalled" list. The actual files will only be deleted when
    cleanly exiting the program, hence finalizing the extension manager.
    This will allow undoing an extension removal easily.

 app/core/gimpextension.c        |   8 +++
 app/core/gimpextension.h        |   1 +
 app/core/gimpextensionmanager.c | 143 ++++++++++++++++++++++++++++++++++++++++
 app/core/gimpextensionmanager.h |  13 +++-
 4 files changed, 162 insertions(+), 3 deletions(-)
---
diff --git a/app/core/gimpextension.c b/app/core/gimpextension.c
index 4618f2e03b..5675ca97f7 100644
--- a/app/core/gimpextension.c
+++ b/app/core/gimpextension.c
@@ -255,6 +255,14 @@ gimp_extension_get_description (GimpExtension *extension)
     as_app_get_description (extension->p->app, NULL);
 }
 
+const gchar *
+gimp_extension_get_path (GimpExtension *extension)
+{
+  g_return_val_if_fail (GIMP_IS_EXTENSION (extension), NULL);
+
+  return extension->p->path;
+}
+
 gchar *
 gimp_extension_get_markup_description (GimpExtension *extension)
 {
diff --git a/app/core/gimpextension.h b/app/core/gimpextension.h
index 41b6bf577f..bfb3531cee 100644
--- a/app/core/gimpextension.h
+++ b/app/core/gimpextension.h
@@ -55,6 +55,7 @@ GimpExtension * gimp_extension_new                     (const gchar    *dir,
 const gchar   * gimp_extension_get_name                (GimpExtension  *extension);
 const gchar   * gimp_extension_get_comment             (GimpExtension  *extension);
 const gchar   * gimp_extension_get_description         (GimpExtension  *extension);
+const gchar   * gimp_extension_get_path                (GimpExtension  *extension);
 
 gchar         * gimp_extension_get_markup_description  (GimpExtension  *extension);
 
diff --git a/app/core/gimpextensionmanager.c b/app/core/gimpextensionmanager.c
index 5b5de7c290..8ea1dec374 100644
--- a/app/core/gimpextensionmanager.c
+++ b/app/core/gimpextensionmanager.c
@@ -34,6 +34,7 @@
 
 #include "gimp.h"
 #include "gimpextension.h"
+#include "gimpextension-error.h"
 #include "gimpobject.h"
 #include "gimpmarshal.h"
 
@@ -58,6 +59,12 @@ enum
   PROP_PLUG_IN_PATHS,
 };
 
+enum
+{
+  EXTENSION_REMOVED,
+  LAST_SIGNAL
+};
+
 struct _GimpExtensionManagerPrivate
 {
   Gimp       *gimp;
@@ -66,6 +73,8 @@ struct _GimpExtensionManagerPrivate
   GList      *sys_extensions;
   /* Self-installed (read-write) extensions. */
   GList      *extensions;
+  /* Uninstalled extensions (cached to allow undo). */
+  GList      *uninstalled_extensions;
 
   /* Running extensions */
   GHashTable *running_extensions;
@@ -115,6 +124,10 @@ static void     gimp_extension_manager_extension_running   (GimpExtension
                                                             GParamSpec           *pspec,
                                                             GimpExtensionManager *manager);
 
+/* Utils. */
+static gboolean gimp_extension_manager_rec_delete          (GFile                *file,
+                                                            GError              **error);
+
 G_DEFINE_TYPE_WITH_CODE (GimpExtensionManager, gimp_extension_manager,
                          GIMP_TYPE_OBJECT,
                          G_ADD_PRIVATE (GimpExtensionManager)
@@ -123,6 +136,8 @@ G_DEFINE_TYPE_WITH_CODE (GimpExtensionManager, gimp_extension_manager,
 
 #define parent_class gimp_extension_manager_parent_class
 
+static guint signals[LAST_SIGNAL] = { 0, };
+
 static void
 gimp_extension_manager_class_init (GimpExtensionManagerClass *klass)
 {
@@ -178,6 +193,16 @@ gimp_extension_manager_class_init (GimpExtensionManagerClass *klass)
                                    g_param_spec_pointer ("plug-in-paths",
                                                          NULL, NULL,
                                                          GIMP_PARAM_READWRITE));
+
+  signals[EXTENSION_REMOVED] =
+    g_signal_new ("extension-removed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GimpExtensionManagerClass, extension_removed),
+                  NULL, NULL,
+                  gimp_marshal_VOID__STRING,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_STRING);
 }
 
 static void
@@ -365,12 +390,27 @@ gimp_extension_manager_deserialize (GimpConfig *config,
 static void
 gimp_extension_manager_finalize (GObject *object)
 {
+  GList *iter;
+
   GimpExtensionManager *manager = GIMP_EXTENSION_MANAGER (object);
 
   g_list_free_full (manager->p->sys_extensions, g_object_unref);
   g_list_free_full (manager->p->extensions, g_object_unref);
   g_hash_table_unref (manager->p->running_extensions);
 
+  for (iter = manager->p->uninstalled_extensions; iter; iter = iter->next)
+    {
+      /* Recursively delete folders of uninstalled extensions. */
+      GError *error = NULL;
+      GFile  *file;
+
+      file = g_file_new_for_path (gimp_extension_get_path (iter->data));
+      if (! gimp_extension_manager_rec_delete (file, &error))
+        g_warning ("%s: %s\n", G_STRFUNC, error->message);
+      g_object_unref (file);
+    }
+  g_list_free_full (manager->p->uninstalled_extensions, g_object_unref);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -671,6 +711,59 @@ gimp_extension_manager_can_run (GimpExtensionManager *manager,
   return TRUE;
 }
 
+/**
+ * gimp_extension_manager_remove:
+ * @manager:
+ * @extension:
+ * @error:
+ *
+ * Uninstall @extension. Technically this only move the object to a
+ * temporary list. The extension folder will be really deleted when GIMP
+ * will stop.
+ * This allows to undo a deletion for as long as the session runs.
+ */
+gboolean
+gimp_extension_manager_remove (GimpExtensionManager  *manager,
+                               GimpExtension         *extension,
+                               GError               **error)
+{
+  GList *iter;
+
+  g_return_val_if_fail (GIMP_IS_EXTENSION_MANAGER (manager), FALSE);
+  g_return_val_if_fail (GIMP_IS_EXTENSION (extension), FALSE);
+
+  iter = (GList *) gimp_extension_manager_get_system_extensions (manager);
+  for (; iter; iter = iter->next)
+    if (iter->data == extension)
+      {
+        /* System extensions cannot be uninstalled. */
+        if (error)
+          *error = g_error_new (GIMP_EXTENSION_ERROR,
+                                GIMP_EXTENSION_FAILED,
+                                _("System extensions cannot be uninstalled."));
+        return FALSE;
+      }
+
+  iter = (GList *) gimp_extension_manager_get_user_extensions (manager);
+  for (; iter; iter = iter->next)
+    if (gimp_extension_cmp (iter->data, extension) == 0)
+      break;
+
+  /* The extension has to be in the extension list. */
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  gimp_extension_stop (extension);
+
+  manager->p->extensions = g_list_remove_link (manager->p->extensions,
+                                               iter);
+  manager->p->uninstalled_extensions = g_list_concat (manager->p->uninstalled_extensions,
+                                                      iter);
+  g_signal_emit (manager, signals[EXTENSION_REMOVED], 0,
+                 gimp_object_get_name (extension));
+
+  return TRUE;
+}
+
 /* Private functions. */
 
 static void
@@ -874,3 +967,53 @@ gimp_extension_manager_extension_running (GimpExtension        *extension,
 
   gimp_extension_manager_refresh (manager);
 }
+
+static gboolean
+gimp_extension_manager_rec_delete (GFile   *file,
+                                   GError **error)
+{
+  gboolean success = TRUE;
+
+  if (g_file_query_exists (file, NULL))
+    {
+      if (g_file_query_file_type (file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                  NULL) == G_FILE_TYPE_DIRECTORY)
+        {
+          GFileEnumerator *enumerator;
+
+          enumerator = g_file_enumerate_children (file,
+                                                  G_FILE_ATTRIBUTE_STANDARD_NAME ","
+                                                  G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
+                                                  G_FILE_ATTRIBUTE_TIME_MODIFIED,
+                                                  G_FILE_QUERY_INFO_NONE,
+                                                  NULL, NULL);
+          if (enumerator)
+            {
+              GFileInfo *info;
+
+              while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)))
+                {
+                  GFile *child;
+
+                  child = g_file_enumerator_get_child (enumerator, info);
+                  g_object_unref (info);
+
+                  if (! gimp_extension_manager_rec_delete (child, error))
+                    success = FALSE;
+
+                  g_object_unref (child);
+                  if (! success)
+                    break;
+                }
+
+              g_object_unref (enumerator);
+            }
+        }
+
+      if (success)
+        /* Non-directory or empty directory. */
+        success = g_file_delete (file, NULL, error);
+    }
+
+  return success;
+}
diff --git a/app/core/gimpextensionmanager.h b/app/core/gimpextensionmanager.h
index 91384496dc..a4bc1edd3d 100644
--- a/app/core/gimpextensionmanager.h
+++ b/app/core/gimpextensionmanager.h
@@ -45,13 +45,16 @@ struct _GimpExtensionManager
 
 struct _GimpExtensionManagerClass
 {
-  GimpObjectClass              parent_class;
+  GimpObjectClass      parent_class;
+
+  void              (* extension_removed)   (GimpExtensionManager *manager,
+                                             gchar                *extension_id);
 };
 
 
-GType                  gimp_extension_manager_get_type   (void) G_GNUC_CONST;
+GType                  gimp_extension_manager_get_type              (void) G_GNUC_CONST;
 
-GimpExtensionManager * gimp_extension_manager_new        (Gimp *gimp);
+GimpExtensionManager * gimp_extension_manager_new                   (Gimp                 *gimp);
 
 void                   gimp_extension_manager_initialize            (GimpExtensionManager *manager);
 void                   gimp_extension_manager_exit                  (GimpExtensionManager *manager);
@@ -64,4 +67,8 @@ gboolean               gimp_extension_manager_is_running            (GimpExtensi
 gboolean               gimp_extension_manager_can_run               (GimpExtensionManager *manager,
                                                                      GimpExtension        *extension);
 
+gboolean               gimp_extension_manager_remove                (GimpExtensionManager *manager,
+                                                                     GimpExtension        *extension,
+                                                                     GError              **error);
+
 #endif  /* __GIMP_EXTENSION_MANAGER_H__ */


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