From 9a38b7ac209dcf319f1b5fa97d6081b96f031b4a Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Wed, 16 Sep 2015 17:02:18 +0200 Subject: [PATCH 1/2] plugin api: convert TMSourceFile to GBoxed internally Because the tm_source_file_new() is an exported API, it has to be at least a boxed type to be usable for gobject introspection. The boxed type uses reference counting as opposed to memory duplication. The obligatory tm_source_file_dup() is not exported (doesn't have to). --- tagmanager/src/tm_source_file.c | 52 ++++++++++++++++++++++++++++----- tagmanager/src/tm_source_file.h | 3 ++ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/tagmanager/src/tm_source_file.c b/tagmanager/src/tm_source_file.c index 2dbdaa34d0..ca764a5e74 100644 --- a/tagmanager/src/tm_source_file.c +++ b/tagmanager/src/tm_source_file.c @@ -35,6 +35,14 @@ #include "tm_source_file.h" #include "tm_tag.h" +typedef struct +{ + TMSourceFile public; + guint refcount; +} TMSourceFilePriv; + +#define SOURCE_FILE_NEW(S) ((S) = g_slice_new(TMSourceFilePriv)) +#define SOURCE_FILE_FREE(S) g_slice_free(TMSourceFilePriv, (TMSourceFilePriv *) S) static TMSourceFile *current_source_file = NULL; @@ -199,12 +207,26 @@ static gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_ GEANY_API_SYMBOL TMSourceFile *tm_source_file_new(const char *file_name, const char *name) { - TMSourceFile *source_file = g_new(TMSourceFile, 1); - if (TRUE != tm_source_file_init(source_file, file_name, name)) + TMSourceFilePriv *priv; + + SOURCE_FILE_NEW(priv); + if (TRUE != tm_source_file_init(&priv->public, file_name, name)) { - g_free(source_file); + SOURCE_FILE_FREE(priv); return NULL; } + priv->refcount = 1; + return &priv->public; +} + + +static TMSourceFile *tm_source_file_dup(TMSourceFile *source_file) +{ + TMSourceFilePriv *priv = (TMSourceFilePriv *) source_file; + + g_return_val_if_fail(NULL != source_file, NULL); + + g_atomic_int_inc(&priv->refcount); return source_file; } @@ -223,20 +245,34 @@ static void tm_source_file_destroy(TMSourceFile *source_file) source_file->tags_array = NULL; } -/** Frees a TMSourceFile structure, including all contents. Before calling this - function the TMSourceFile has to be removed from the TMWorkspace. - @param source_file The source file to free. +/** Decrements the reference count of @a source_file + * + * If the reference count drops to 0, then @a source_file is freed, including all contents. + * Make sure the @a source_file is already removed from any TMWorkSpace before the + * this happens. + * @param source_file The source file to free. + * @see tm_workspace_remove_source_file() */ GEANY_API_SYMBOL void tm_source_file_free(TMSourceFile *source_file) { - if (NULL != source_file) + TMSourceFilePriv *priv = (TMSourceFilePriv *) source_file; + + if (NULL != priv && g_atomic_int_dec_and_test(&priv->refcount)) { tm_source_file_destroy(source_file); - g_free(source_file); + SOURCE_FILE_FREE(priv); } } +/** Gets the GBoxed-derived GType for TMSourceFile + * + * @return TMSourceFile type . */ +GEANY_API_SYMBOL +GType tm_source_file_get_type(void); + +G_DEFINE_BOXED_TYPE(TMSourceFile, tm_source_file, tm_source_file_dup, tm_source_file_free); + /* Parses the text-buffer or source file and regenarates the tags. @param source_file The source file to parse @param text_buf The text buffer to parse diff --git a/tagmanager/src/tm_source_file.h b/tagmanager/src/tm_source_file.h index 173b14a111..f2bdf4b1c9 100644 --- a/tagmanager/src/tm_source_file.h +++ b/tagmanager/src/tm_source_file.h @@ -12,6 +12,7 @@ #include #include +#include #ifndef LIBCTAGS_DEFINED typedef int langType; @@ -44,6 +45,8 @@ typedef struct GPtrArray *tags_array; /**< Sorted tag array obtained by parsing the object */ } TMSourceFile; +GType tm_source_file_get_type(void); + TMSourceFile *tm_source_file_new(const char *file_name, const char *name); void tm_source_file_free(TMSourceFile *source_file); From 43737733acc46eee7dff88eb922622694faba29b Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Wed, 16 Sep 2015 22:42:14 +0200 Subject: [PATCH 2/2] plugin api: convert StashGroup to GBoxed internally Because the stash_group_new() is an exported API, it has to be at least a boxed type to be usable for gobject introspection. The boxed type uses reference counting as opposed to memory duplication. The obligatory stash_group_dup() is not exported (doesn't have to). --- src/stash.c | 46 +++++++++++++++++++++++++++++++++------------- src/stash.h | 1 + 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/stash.c b/src/stash.c index d4a5b698d8..6b7c5d3e6a 100644 --- a/src/stash.c +++ b/src/stash.c @@ -123,6 +123,7 @@ typedef struct StashPref StashPref; struct StashGroup { + guint refcount; /* ref count for GBoxed implementation */ const gchar *name; /* group name to use in the keyfile */ GPtrArray *entries; /* array of (StashPref*) */ gboolean various; /* mark group for display/edit in stash treeview */ @@ -347,17 +348,27 @@ gint stash_group_save_to_file(StashGroup *group, const gchar *filename, } +static void free_stash_pref(StashPref *pref) +{ + if (pref->widget_type == GTK_TYPE_RADIO_BUTTON) + g_free(pref->extra.radio_buttons); + + g_slice_free(StashPref, pref); +} + + /** Creates a new group. * @param name Name used for @c GKeyFile group. * @return Group. */ GEANY_API_SYMBOL StashGroup *stash_group_new(const gchar *name) { - StashGroup *group = g_new0(StashGroup, 1); + StashGroup *group = g_slice_new0(StashGroup); group->name = name; - group->entries = g_ptr_array_new(); + group->entries = g_ptr_array_new_with_free_func((GDestroyNotify) free_stash_pref); group->use_defaults = TRUE; + group->refcount = 1; return group; } @@ -386,27 +397,36 @@ void stash_group_free_settings(StashGroup *group) } +static StashGroup *stash_group_dup(StashGroup *src) +{ + g_atomic_int_inc(&src->refcount); + + return src; +} + + /** Frees a group. * @param group . */ GEANY_API_SYMBOL void stash_group_free(StashGroup *group) { - StashPref *entry; - guint i; - - foreach_ptr_array(entry, i, group->entries) + if (g_atomic_int_dec_and_test(&group->refcount)) { - if (entry->widget_type == GTK_TYPE_RADIO_BUTTON) - { - g_free(entry->extra.radio_buttons); - } - g_slice_free(StashPref, entry); + g_ptr_array_free(group->entries, TRUE); + g_slice_free(StashGroup, group); } - g_ptr_array_free(group->entries, TRUE); - g_free(group); } +/** Gets the GBoxed-derived GType for StashGroup + * + * @return StashGroup type . */ +GEANY_API_SYMBOL +GType stash_group_get_type(void); + +G_DEFINE_BOXED_TYPE(StashGroup, stash_group, stash_group_dup, stash_group_free); + + /* Used for selecting groups passed to stash_tree_setup(). * @c FALSE by default. */ void stash_group_set_various(StashGroup *group, gboolean various) diff --git a/src/stash.h b/src/stash.h index 5e44674266..e92563656d 100644 --- a/src/stash.h +++ b/src/stash.h @@ -33,6 +33,7 @@ typedef struct StashGroup StashGroup; * stash_group_display() and stash_group_update(). */ typedef gconstpointer StashWidgetID; +GType stash_group_get_type(void); StashGroup *stash_group_new(const gchar *name);