[geany/geany] 6bc43f: Merge pull request #1203 from codebrainz/document-data

Matthew Brush git-noreply at xxxxx
Sun Sep 11 02:40:38 UTC 2016


Branch:      refs/heads/master
Author:      Matthew Brush <mbrush at codebrainz.ca>
Committer:   GitHub <noreply at github.com>
Date:        Sun, 11 Sep 2016 02:40:38 UTC
Commit:      6bc43f745e27a45a7fd1b981ca452e8b97929c0e
             https://github.com/geany/geany/commit/6bc43f745e27a45a7fd1b981ca452e8b97929c0e

Log Message:
-----------
Merge pull request #1203 from codebrainz/document-data

Document data


Modified Paths:
--------------
    src/document.c
    src/document.h
    src/documentprivate.h
    src/plugins.c
    src/pluginutils.c
    src/pluginutils.h

Modified: src/document.c
23 lines changed, 23 insertions(+), 0 deletions(-)
===================================================================
@@ -657,6 +657,8 @@ static GeanyDocument *document_create(const gchar *utf8_filename)
 	doc->priv->last_check = time(NULL);
 #endif
 
+	g_datalist_init(&doc->priv->data);
+
 	sidebar_openfiles_add(doc);	/* sets doc->iter */
 
 	notebook_new_tab(doc);
@@ -712,6 +714,8 @@ static gboolean remove_page(guint page_num)
 	if (! main_status.closing_all && doc->real_path != NULL)
 		ui_add_recent_document(doc);
 
+	g_datalist_clear(&doc->priv->data);
+
 	doc->is_valid = FALSE;
 	doc->id = 0;
 
@@ -3839,3 +3843,22 @@ GEANY_API_SYMBOL
 GType document_get_type (void);
 
 G_DEFINE_BOXED_TYPE(GeanyDocument, document, copy_, free_);
+
+
+gpointer document_get_data(const GeanyDocument *doc, const gchar *key)
+{
+	return g_datalist_get_data(&doc->priv->data, key);
+}
+
+
+void document_set_data(GeanyDocument *doc, const gchar *key, gpointer data)
+{
+	g_datalist_set_data(&doc->priv->data, key, data);
+}
+
+
+void document_set_data_full(GeanyDocument *doc, const gchar *key,
+	gpointer data, GDestroyNotify free_func)
+{
+	g_datalist_set_data_full(&doc->priv->data, key, data, free_func);
+}


Modified: src/document.h
7 lines changed, 7 insertions(+), 0 deletions(-)
===================================================================
@@ -316,6 +316,13 @@ void document_grab_focus(GeanyDocument *doc);
 
 GeanyDocument *document_clone(GeanyDocument *old_doc);
 
+gpointer document_get_data(const GeanyDocument *doc, const gchar *key);
+
+void document_set_data(GeanyDocument *doc, const gchar *key, gpointer data);
+
+void document_set_data_full(GeanyDocument *doc, const gchar *key,
+	gpointer data, GDestroyNotify free_func);
+
 #endif /* GEANY_PRIVATE */
 
 G_END_DECLS


Modified: src/documentprivate.h
2 lines changed, 2 insertions(+), 0 deletions(-)
===================================================================
@@ -111,6 +111,8 @@ typedef struct GeanyDocumentPrivate
 	gint			 protected;
 	/* Save pointer to info bars allowing to cancel them programatically (to avoid multiple ones) */
 	GtkWidget		*info_bars[NUM_MSG_TYPES];
+	/* Keyed Data List to attach arbitrary data to the document */
+	GData			*data;
 }
 GeanyDocumentPrivate;
 


Modified: src/plugins.c
39 lines changed, 39 insertions(+), 0 deletions(-)
===================================================================
@@ -31,6 +31,7 @@
 
 #include "app.h"
 #include "dialogs.h"
+#include "documentprivate.h"
 #include "encodings.h"
 #include "geanyobject.h"
 #include "geanywraplabel.h"
@@ -59,6 +60,14 @@
 #include <string.h>
 
 
+typedef struct
+{
+	gchar *prefix;
+	GeanyDocument *document;
+}
+ForEachDocData;
+
+
 GList *active_plugin_list = NULL; /* list of only actually loaded plugins, always valid */
 
 
@@ -850,6 +859,35 @@ static gboolean is_active_plugin(Plugin *plugin)
 }
 
 
+static void remove_each_doc_data(GQuark key_id, gpointer data, gpointer user_data)
+{
+	const ForEachDocData *doc_data = user_data;
+	const gchar *key = g_quark_to_string(key_id);
+	if (g_str_has_prefix(key, doc_data->prefix))
+		g_datalist_remove_data(&doc_data->document->priv->data, key);
+}
+
+
+static void remove_doc_data(Plugin *plugin)
+{
+	ForEachDocData data;
+
+	data.prefix = g_strdup_printf("geany/plugins/%s/", plugin->public.info->name);
+
+	for (guint i = 0; i < documents_array->len; i++)
+	{
+		GeanyDocument *doc = documents_array->pdata[i];
+		if (DOC_VALID(doc))
+		{
+			data.document = doc;
+			g_datalist_foreach(&doc->priv->data, remove_each_doc_data, &data);
+		}
+	}
+
+	g_free(data.prefix);
+}
+
+
 /* Clean up anything used by an active plugin  */
 static void
 plugin_cleanup(Plugin *plugin)
@@ -859,6 +897,7 @@ plugin_cleanup(Plugin *plugin)
 	/* With geany_register_plugin cleanup is mandatory */
 	plugin->cbs.cleanup(&plugin->public, plugin->cb_data);
 
+	remove_doc_data(plugin);
 	remove_callbacks(plugin);
 	remove_sources(plugin);
 


Modified: src/pluginutils.c
153 lines changed, 153 insertions(+), 0 deletions(-)
===================================================================
@@ -44,6 +44,14 @@
 #include "utils.h"
 
 
+typedef struct
+{
+	gpointer data;
+	GDestroyNotify free_func;
+}
+PluginDocDataProxy;
+
+
 /** Inserts a toolbar item before the Quit button, or after the previous plugin toolbar item.
  * A separator is added on the first call to this function, and will be shown when @a item is
  * shown; hidden when @a item is hidden.
@@ -599,4 +607,149 @@ void geany_plugin_set_data(GeanyPlugin *plugin, gpointer pdata, GDestroyNotify f
 }
 
 
+static void plugin_doc_data_proxy_free(gpointer pdata)
+{
+	PluginDocDataProxy *prox = pdata;
+	if (prox != NULL)
+	{
+		if (prox->free_func)
+			prox->free_func(prox->data);
+		g_slice_free(PluginDocDataProxy, prox);
+	}
+}
+
+
+/**
+ * Retrieve plugin-specific data attached to a document.
+ *
+ * @param plugin The plugin who attached the data.
+ * @param doc The document which the data was attached to.
+ * @param key The key name of the attached data.
+ *
+ * @return The attached data pointer or `NULL` if the key is not found
+ * for the given plugin.
+ *
+ * @since 1.29 (Plugin API 228)
+ * @see plugin_set_document_data plugin_set_document_data_full
+ */
+GEANY_API_SYMBOL
+gpointer plugin_get_document_data(struct GeanyPlugin *plugin,
+	struct GeanyDocument *doc, const gchar *key)
+{
+	gchar *real_key;
+	PluginDocDataProxy *data;
+
+	g_return_val_if_fail(plugin != NULL, NULL);
+	g_return_val_if_fail(doc != NULL, NULL);
+	g_return_val_if_fail(key != NULL && *key != '\0', NULL);
+
+	real_key = g_strdup_printf("geany/plugins/%s/%s", plugin->info->name, key);
+	data = document_get_data(doc, real_key);
+	g_free(real_key);
+
+	return (data != NULL) ? data->data : NULL;
+}
+
+
+/**
+ * Attach plugin-specific data to a document.
+ *
+ * @param plugin The plugin attaching data to the document.
+ * @param doc The document to attach the data to.
+ * @param key The key name for the data.
+ * @param data The pointer to attach to the document.
+ *
+ * @since 1.29 (Plugin API 228)
+ * @see plugin_get_document_data plugin_set_document_data_full
+ */
+GEANY_API_SYMBOL
+void plugin_set_document_data(struct GeanyPlugin *plugin, struct GeanyDocument *doc,
+	const gchar *key, gpointer data)
+{
+	plugin_set_document_data_full(plugin, doc, key, data, NULL);
+}
+
+
+/**
+ * Attach plugin-specific data and a free function to a document.
+ *
+ * This is useful for plugins who want to keep some additional data with
+ * the document and even have it auto-released appropriately (see below).
+ *
+ * This is a simple example showing how a plugin might use this to
+ * attach a string to each document and print it when the document is
+ * saved:
+ *
+ * @code
+ * void on_document_open(GObject *unused, GeanyDocument *doc, GeanyPlugin *plugin)
+ * {
+ *     plugin_set_document_data_full(plugin, doc, "my-data",
+ *         g_strdup("some-data"), g_free);
+ * }
+ *
+ * void on_document_save(GObject *unused, GeanyDocument *doc, GeanyPlugin *plugin)
+ * {
+ *     const gchar *some_data = plugin_get_document_data(plugin, doc, "my-data");
+ *     g_print("my-data: %s", some_data);
+ * }
+ *
+ * gboolean plugin_init(GeanyPlugin *plugin, gpointer unused)
+ * {
+ *     plugin_signal_connect(plugin, NULL, "document-open", TRUE,
+ *         G_CALLBACK(on_document_open), plugin);
+ *     plugin_signal_connect(plugin, NULL, "document-new", TRUE,
+ *         G_CALLBACK(on_document_open), plugin);
+ *     plugin_signal_connect(plugin, NULL, "document-save", TRUE,
+ *         G_CALLBACK(on_document_save), plugin);
+ *     return TRUE;
+ * }
+ *
+ * void geany_load_module(GeanyPlugin *plugin)
+ * {
+ *   // ...
+ *   plugin->funcs->init = plugin_init;
+ *   // ...
+ * }
+ * @endcode
+ *
+ * The @a free_func can be used to tie the lifetime of the data to that
+ * of the @a doc and/or the @a plugin. The @a free_func will be called
+ * in any of the following cases:
+ *
+ *   - When a document is closed.
+ *   - When the plugin is unloaded.
+ *   - When the document data is set again using the same key.
+ *
+ * @param plugin The plugin attaching data to the document.
+ * @param doc The document to attach the data to.
+ * @param key The key name for the data.
+ * @param data The pointer to attach to the document.
+ * @param free_func The function to call with data when removed.
+ *
+ * @since 1.29 (Plugin API 228)
+ * @see plugin_get_document_data plugin_set_document_data
+ */
+GEANY_API_SYMBOL
+void plugin_set_document_data_full(struct GeanyPlugin *plugin,
+	struct GeanyDocument *doc, const gchar *key, gpointer data,
+	GDestroyNotify free_func)
+{
+	PluginDocDataProxy *prox;
+
+	g_return_if_fail(plugin != NULL);
+	g_return_if_fail(doc != NULL);
+	g_return_if_fail(key != NULL);
+
+	prox = g_slice_new(PluginDocDataProxy);
+	if (prox != NULL)
+	{
+		gchar *real_key = g_strdup_printf("geany/plugins/%s/%s", plugin->info->name, key);
+		prox->data = data;
+		prox->free_func = free_func;
+		document_set_data_full(doc, real_key, prox, plugin_doc_data_proxy_free);
+		g_free(real_key);
+	}
+}
+
+
 #endif


Modified: src/pluginutils.h
11 lines changed, 11 insertions(+), 0 deletions(-)
===================================================================
@@ -33,6 +33,7 @@ G_BEGIN_DECLS
 
 /* avoid including plugindata.h otherwise this redefines the GEANY() macro */
 struct GeanyPlugin;
+struct GeanyDocument;
 
 
 void plugin_add_toolbar_item(struct GeanyPlugin *plugin, GtkToolItem *item);
@@ -62,6 +63,16 @@ void plugin_show_configure(struct GeanyPlugin *plugin);
 void plugin_builder_connect_signals(struct GeanyPlugin *plugin,
 	GtkBuilder *builder, gpointer user_data);
 
+gpointer plugin_get_document_data(struct GeanyPlugin *plugin,
+	struct GeanyDocument *doc, const gchar *key);
+
+void plugin_set_document_data(struct GeanyPlugin *plugin, struct GeanyDocument *doc,
+	const gchar *key, gpointer data);
+
+void plugin_set_document_data_full(struct GeanyPlugin *plugin,
+	struct GeanyDocument *doc, const gchar *key, gpointer data,
+	GDestroyNotify free_func);
+
 G_END_DECLS
 
 #endif /* HAVE_PLUGINS */



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list