SF.net SVN: geany:[3391] trunk

eht16 at users.sourceforge.net eht16 at xxxxx
Wed Dec 17 16:00:18 UTC 2008


Revision: 3391
          http://geany.svn.sourceforge.net/geany/?rev=3391&view=rev
Author:   eht16
Date:     2008-12-17 16:00:18 +0000 (Wed, 17 Dec 2008)

Log Message:
-----------
Add "editor-notify" to the plugin API.
This signal is emitted whenever something in an editor widget changes, e.g. a character was typed.

Modified Paths:
--------------
    trunk/ChangeLog
    trunk/doc/Doxyfile.in
    trunk/doc/plugins.dox
    trunk/plugins/demoplugin.c
    trunk/src/document.c
    trunk/src/editor.c
    trunk/src/editor.h
    trunk/src/geany.h
    trunk/src/geanyobject.c
    trunk/src/geanyobject.h
    trunk/src/plugindata.h

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2008-12-17 15:59:25 UTC (rev 3390)
+++ trunk/ChangeLog	2008-12-17 16:00:18 UTC (rev 3391)
@@ -6,6 +6,12 @@
    Retitle the Terminal/VTE preferences tab section.
    Change (again) the key combinations for creating
    rectangular selections.
+ * doc/Doxyfile.in, doc/plugins.dox, plugins/demoplugin.c, src/editor.c,
+   src/editor.h, src/document.c, src/geanyobject.c, src/geanyobject.h,
+   src/geany.h, src/plugindata.h:
+   Add "editor-notify" to the plugin API.
+   This signal is emitted whenever something in an editor widget
+   changes, e.g. a character was typed.
 
 
 2008-12-16  Nick Treleaven  <nick(dot)treleaven(at)btinternet(dot)com>

Modified: trunk/doc/Doxyfile.in
===================================================================
--- trunk/doc/Doxyfile.in	2008-12-17 15:59:25 UTC (rev 3390)
+++ trunk/doc/Doxyfile.in	2008-12-17 16:00:18 UTC (rev 3391)
@@ -40,7 +40,7 @@
                          "endsignaldef=  " \
                          "signalproto=@code  " \
                          "endsignalproto=@endcode  " \
-                         "signaldesc=@par Description:  " \
+                         "signaldesc=" \
                          "signals=@b Signals:  " \
                          "endsignals=  "
 OPTIMIZE_OUTPUT_FOR_C  = YES

Modified: trunk/doc/plugins.dox
===================================================================
--- trunk/doc/plugins.dox	2008-12-17 15:59:25 UTC (rev 3390)
+++ trunk/doc/plugins.dox	2008-12-17 16:00:18 UTC (rev 3391)
@@ -56,6 +56,7 @@
  *
  *  To use plugin signals in Geany, you simply create a PluginCallback array, list the signals
  *  you want to listen to and create the appropiate signal callbacks for each signal.
+ *  The callback array is read @a after plugin_init() has been called.
  *  @note The PluginCallback array has to be ended with a final NULL entry.
  *
  *  The following code demonstrates how to use signals in Geany plugins. The code can be inserted
@@ -185,8 +186,46 @@
  *  @param user_data user data.
  *  @endsignaldef
  *
+ *  @signaldef editor-notify
+ *  @signalproto
+ *  gboolean user_function(GObject *obj, GeanyEditor *editor, SCNotification *nt,
+ *  		gpointer user_data);
+ *  @endsignalproto
+ *  @signaldesc
+ *  This signal is sent whenever something in the editor widget changes (character added,
+ *  fold level changes, clicks to the line number margin, ...).
+ *  A detailed description of possible notifications and the SCNotification can be found at
+ *  http://www.scintilla.org/ScintillaDoc.html#Notifications.
  *
+ *  If you connect to this signal, you must check @c nt->nmhdr.code for the notification type
+ *  to prevent handling unwanted notifications. This is important because for instance SCN_UPDATEUI
+ *  is sent very often whereas you probably don't want to handle this notification.
  *
+ *  By default, the signal is sent before Geany's default handler is processing the event.
+ *  Your callback function should return FALSE to allow Geany processing the event as well. If you
+ *  want to prevent this for some reason, return TRUE.
+ *  Please use this with care as it can break basic functionality of Geany.
+ *
+ *  The signal can be sent after Geany's default handler has been run when you set
+ *  PluginCallback::after field to TRUE.
+ *
+ *  An example callback implemention of this signal can be found in the Demo plugin.
+ *
+ *  @warning This signal has much power and should be used carefully. You should especially
+ *           care about the return value; make sure to return TRUE only if it is necessary
+ *           and in the correct situations.
+ *
+ *  @param obj a GeanyObject instance, should be ignored.
+ *  @param editor The current GeanyEditor.
+ *  @param nt A pointer to the SCNotification struct which holds additional information for
+ *            the event.
+ *  @param user_data user data.
+ *  @return @c TRUE to stop other handlers from being invoked for the event.
+ * 	    @c FALSE to propagate the event further.
+ *  @endsignaldef
+ *
+ *
+ *
  *  @page howto Plugin Howto
  *
  *  @section intro Introduction

Modified: trunk/plugins/demoplugin.c
===================================================================
--- trunk/plugins/demoplugin.c	2008-12-17 15:59:25 UTC (rev 3390)
+++ trunk/plugins/demoplugin.c	2008-12-17 16:00:18 UTC (rev 3391)
@@ -38,11 +38,13 @@
 #include "geany.h"		/* for the GeanyApp data type */
 #include "support.h"	/* for the _() translation macro (see also po/POTFILES.in) */
 #include "ui_utils.h"
+#include "Scintilla.h" /* for the SCNotification struct */
 
 #include "plugindata.h"		/* this defines the plugin API */
 #include "geanyfunctions.h"	/* this wraps geany_functions function pointers */
 
 
+
 /* These items are set by Geany before plugin_init() is called. */
 GeanyPlugin		*geany_plugin;
 GeanyData		*geany_data;
@@ -62,6 +64,61 @@
 static gchar *welcome_text = NULL;
 
 
+
+static gboolean on_editor_notify(GObject *object, GeanyEditor *editor,
+								 SCNotification *nt, gpointer data)
+{
+	/* For detailed documentation about the SCNotification struct, please see
+	 * http://www.scintilla.org/ScintillaDoc.html#Notifications. */
+	switch (nt->nmhdr.code)
+	{
+		case SCN_UPDATEUI:
+			/* This notification is sent very often, you should not do time-consuming tasks here */
+			break;
+		case SCN_CHARADDED:
+			/* For demonstrating purposes simply print the typed character in the status bar */
+			ui_set_statusbar(FALSE, _("Typed character: %c"), nt->ch);
+			break;
+		case SCN_URIDROPPED:
+		{
+			/* Show a message dialog with the dropped URI list when files (i.e. a list of
+			 * filenames) is dropped to the editor widget) */
+			if (nt->text != NULL)
+			{
+				GtkWidget *dialog;
+
+				dialog = gtk_message_dialog_new(
+					GTK_WINDOW(geany->main_widgets->window),
+					GTK_DIALOG_DESTROY_WITH_PARENT,
+					GTK_MESSAGE_INFO,
+					GTK_BUTTONS_OK,
+					_("The following files were dropped:"));
+				gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
+					"%s", nt->text);
+
+				gtk_dialog_run(GTK_DIALOG(dialog));
+				gtk_widget_destroy(dialog);
+			}
+			/* we return TRUE here which prevents Geany from processing the SCN_URIDROPPED
+			 * notification, i.e. Geany won't open the passed files */
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+
+PluginCallback plugin_callbacks[] =
+{
+	/* Set 'after' (third field) to TRUE to run the callback @a after the default handler.
+	 * If 'after' is FALSE, the callback is run @a before the default handler, so the plugin
+	 * can prevent Geany from processing the notification. Use this with care. */
+	{ "editor-notify", (GCallback) &on_editor_notify, FALSE, NULL },
+	{ NULL, NULL, FALSE, NULL }
+};
+
+
 /* Callback when the menu item is clicked. */
 static void
 item_activate(GtkMenuItem *menuitem, gpointer gdata)

Modified: trunk/src/document.c
===================================================================
--- trunk/src/document.c	2008-12-17 15:59:25 UTC (rev 3390)
+++ trunk/src/document.c	2008-12-17 16:00:18 UTC (rev 3391)
@@ -595,7 +595,7 @@
 	sci_goto_pos(doc->editor->sci, 0, TRUE);
 
 	/* "the" SCI signal (connect after initial setup(i.e. adding text)) */
-	g_signal_connect(doc->editor->sci, "sci-notify", G_CALLBACK(on_editor_notification), doc);
+	g_signal_connect(doc->editor->sci, "sci-notify", G_CALLBACK(editor_sci_notify_cb), doc);
 
 	g_signal_emit_by_name(geany_object, "document-new", doc);
 
@@ -1118,7 +1118,7 @@
 		doc->real_path = get_real_path_from_utf8(doc->file_name);
 
 		/* "the" SCI signal (connect after initial setup(i.e. adding text)) */
-		g_signal_connect(doc->editor->sci, "sci-notify", G_CALLBACK(on_editor_notification), doc);
+		g_signal_connect(doc->editor->sci, "sci-notify", G_CALLBACK(editor_sci_notify_cb), doc);
 
 		use_ft = (ft != NULL) ? ft : filetypes_detect_from_document(doc);
 	}

Modified: trunk/src/editor.c
===================================================================
--- trunk/src/editor.c	2008-12-17 15:59:25 UTC (rev 3390)
+++ trunk/src/editor.c	2008-12-17 16:00:18 UTC (rev 3391)
@@ -249,8 +249,6 @@
 }
 
 
-typedef struct SCNotification SCNotification;
-
 static void fold_symbol_click(ScintillaObject *sci, SCNotification *nt)
 {
 	gint line = sci_get_line_from_position(sci, nt->position);
@@ -624,18 +622,29 @@
 }
 
 
-/* callback func called by all editors when a signal arises */
-void on_editor_notification(GtkWidget *widget, gint scn, gpointer lscn, gpointer user_data)
+/* Callback for the "sci-notify" signal to emit a "editor-notify" signal.
+ * Plugins can connect to the "editor-notify" signal. */
+void editor_sci_notify_cb(G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gint scn,
+						  gpointer scnt, gpointer data)
 {
-	SCNotification *nt;
+	GeanyDocument *doc = data;
+	gboolean retval;
+
+	g_return_if_fail(doc != NULL);
+
+	g_signal_emit_by_name(geany_object, "editor-notify", doc->editor, scnt, &retval);
+}
+
+
+static gboolean on_editor_notify(G_GNUC_UNUSED GeanyObject *object, GeanyEditor *editor,
+								 SCNotification *nt, gpointer data)
+{
 	ScintillaObject *sci;
-	GeanyDocument *doc = user_data;
-	GeanyEditor *editor;
+	GeanyDocument *doc = editor->document;
 
 	editor = doc->editor;
 	sci = editor->sci;
 
-	nt = lscn;
 	switch (nt->nmhdr.code)
 	{
 		case SCN_SAVEPOINTLEFT:
@@ -754,6 +763,8 @@
 			break;
 		}
 	}
+	/* we always return FALSE here to let plugins handle the event to */
+	return FALSE;
 }
 
 
@@ -4158,6 +4169,10 @@
 	memset(&editor_prefs, 0, sizeof(GeanyEditorPrefs));
 	memset(&indent_prefs, 0, sizeof(GeanyIndentPrefs));
 	editor_prefs.indentation = &indent_prefs;
+
+	/* use g_signal_connect_after() to allow plugins connecting to the signal before the default
+	 * handler (on_editor_notify) is called */
+	g_signal_connect_after(geany_object, "editor-notify", G_CALLBACK(on_editor_notify), NULL);
 }
 
 

Modified: trunk/src/editor.h
===================================================================
--- trunk/src/editor.h	2008-12-17 15:59:25 UTC (rev 3390)
+++ trunk/src/editor.h	2008-12-17 16:00:18 UTC (rev 3391)
@@ -131,7 +131,7 @@
 
 
 /** Editor-owned fields for each document. */
-typedef struct GeanyEditor
+struct GeanyEditor
 {
 	GeanyDocument	*document;		/**< The document associated with the editor. */
 	ScintillaObject	*sci;			/**< The Scintilla editor @c GtkWidget. */
@@ -141,8 +141,7 @@
 	gfloat			 scroll_percent;
 	GeanyIndentType	 indent_type;	/* Use editor_get_indent_prefs() instead. */
 	gboolean		 line_breaking;	/**< Whether to split long lines as you type. */
-}
-GeanyEditor;
+};
 
 
 typedef struct
@@ -153,9 +152,9 @@
 
 extern EditorInfo editor_info;
 
+typedef struct SCNotification SCNotification;
 
 
-
 void editor_init(void);
 
 GeanyEditor *editor_create(GeanyDocument *doc);
@@ -164,7 +163,7 @@
 
 ScintillaObject *editor_create_widget(GeanyEditor *editor);
 
-void on_editor_notification(GtkWidget* editor, gint scn, gpointer lscn, gpointer user_data);
+void editor_sci_notify_cb(GtkWidget *widget, gint scn, gpointer scnt, gpointer data);
 
 gboolean editor_start_auto_complete(GeanyEditor *editor, gint pos, gboolean force);
 

Modified: trunk/src/geany.h
===================================================================
--- trunk/src/geany.h	2008-12-17 15:59:25 UTC (rev 3390)
+++ trunk/src/geany.h	2008-12-17 16:00:18 UTC (rev 3391)
@@ -56,6 +56,7 @@
 
 /* Common forward declarations */
 typedef struct GeanyDocument GeanyDocument;
+typedef struct GeanyEditor GeanyEditor;
 typedef struct GeanyFiletype GeanyFiletype;
 
 

Modified: trunk/src/geanyobject.c
===================================================================
--- trunk/src/geanyobject.c	2008-12-17 15:59:25 UTC (rev 3390)
+++ trunk/src/geanyobject.c	2008-12-17 16:00:18 UTC (rev 3391)
@@ -81,10 +81,10 @@
 static void geany_cclosure_marshal_VOID__STRING_INT_POINTER(GClosure *closure, GValue *ret_val,
 				guint n_param_vals, const GValue *param_values, gpointer hint, gpointer mdata)
 {
-	typedef gboolean (*GMarshalFunc_VOID__STRING_INT_POINTER)
+	typedef gboolean (*GeanyMarshalFunc_VOID__STRING_INT_POINTER)
 		(gpointer data1, gconstpointer arg_1, gint arg_2, gpointer arg_3, gpointer data2);
 
-	register GMarshalFunc_VOID__STRING_INT_POINTER callback;
+	register GeanyMarshalFunc_VOID__STRING_INT_POINTER callback;
 	register GCClosure* cc = (GCClosure*) closure;
 	register gpointer data1, data2;
 
@@ -100,7 +100,7 @@
 		data1 = g_value_peek_pointer(param_values + 0);
 		data2 = closure->data;
 	}
-	callback = (GMarshalFunc_VOID__STRING_INT_POINTER) (mdata ? mdata : cc->callback);
+	callback = (GeanyMarshalFunc_VOID__STRING_INT_POINTER) (mdata ? mdata : cc->callback);
 	callback(data1,
 			  g_value_get_string(param_values + 1),
 			  g_value_get_int(param_values + 2),
@@ -109,8 +109,59 @@
 }
 
 
+static gboolean boolean_handled_accumulator(GSignalInvocationHint *ihint, GValue *return_accu,
+											const GValue *handler_return, gpointer dummy)
+{
+	gboolean continue_emission, signal_handled;
+
+	signal_handled = g_value_get_boolean(handler_return);
+	g_value_set_boolean(return_accu, signal_handled);
+	continue_emission = !signal_handled;
+
+	return continue_emission;
+}
+
+
+static void geany_cclosure_marshal_BOOL__POINTER_POINTER( GClosure *closure, GValue *return_value,
+								guint n_param_values, const GValue *param_values,
+								gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
+{
+	typedef gboolean (*GeanyMarshalFunc_BOOLEAN__POINTER_POINTER)
+		(gpointer data1, gpointer arg_1, gpointer arg_2, gpointer data2);
+
+	register GeanyMarshalFunc_BOOLEAN__POINTER_POINTER callback;
+	register GCClosure *cc = (GCClosure*) closure;
+	register gpointer data1, data2;
+	gboolean v_return;
+
+	g_return_if_fail(return_value != NULL);
+	g_return_if_fail(n_param_values == 3);
+
+	if (G_CCLOSURE_SWAP_DATA(closure))
+	{
+		data1 = closure->data;
+		data2 = g_value_peek_pointer(param_values + 0);
+	}
+	else
+	{
+		data1 = g_value_peek_pointer(param_values + 0);
+		data2 = closure->data;
+	}
+	callback = (GeanyMarshalFunc_BOOLEAN__POINTER_POINTER)
+		(marshal_data ? marshal_data : cc->callback);
+
+	v_return = callback(data1,
+					   g_value_get_pointer(param_values + 1),
+					   g_value_get_pointer(param_values + 2),
+					   data2);
+
+	g_value_set_boolean(return_value, v_return);
+}
+
+
 static void create_signals(GObjectClass *g_object_class)
 {
+	/* Document signals */
 	geany_object_signals[GCB_DOCUMENT_NEW] = g_signal_new (
 		"document-new",
 		G_OBJECT_CLASS_TYPE (g_object_class),
@@ -157,6 +208,7 @@
 		G_TYPE_NONE, 1,
 		G_TYPE_POINTER);
 
+	/* Project signals */
 	geany_object_signals[GCB_PROJECT_OPEN] = g_signal_new (
 		"project-open",
 		G_OBJECT_CLASS_TYPE (g_object_class),
@@ -184,6 +236,7 @@
 		g_cclosure_marshal_VOID__VOID,
 		G_TYPE_NONE, 0);
 
+	/* Editor signals */
 	geany_object_signals[GCB_UPDATE_EDITOR_MENU] = g_signal_new (
 		"update-editor-menu",
 		G_OBJECT_CLASS_TYPE (g_object_class),
@@ -193,6 +246,15 @@
 		geany_cclosure_marshal_VOID__STRING_INT_POINTER,
 		G_TYPE_NONE, 3,
 		G_TYPE_STRING, G_TYPE_INT, G_TYPE_POINTER);
+	geany_object_signals[GCB_EDITOR_NOTIFY] = g_signal_new (
+		"editor-notify",
+		G_OBJECT_CLASS_TYPE (g_object_class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (GeanyObjectClass, update_editor_menu),
+		boolean_handled_accumulator, NULL,
+		geany_cclosure_marshal_BOOL__POINTER_POINTER,
+		G_TYPE_BOOLEAN, 2,
+		G_TYPE_POINTER, G_TYPE_POINTER);
 }
 
 

Modified: trunk/src/geanyobject.h
===================================================================
--- trunk/src/geanyobject.h	2008-12-17 15:59:25 UTC (rev 3390)
+++ trunk/src/geanyobject.h	2008-12-17 16:00:18 UTC (rev 3391)
@@ -43,6 +43,7 @@
 	GCB_PROJECT_SAVE,
 	GCB_PROJECT_CLOSE,
 	GCB_UPDATE_EDITOR_MENU,
+	GCB_EDITOR_NOTIFY,
 	GCB_MAX
 } GeanyCallbackId;
 
@@ -81,6 +82,7 @@
 	void (*project_save)(GKeyFile *keyfile);
 	void (*project_close)(void);
 	void (*update_editor_menu)(const gchar *word, gint click_pos, GeanyDocument *doc);
+	gboolean (*editor_notify)(GeanyEditor *editor, gpointer scnt);
 };
 
 GType		geany_object_get_type	(void);

Modified: trunk/src/plugindata.h
===================================================================
--- trunk/src/plugindata.h	2008-12-17 15:59:25 UTC (rev 3390)
+++ trunk/src/plugindata.h	2008-12-17 16:00:18 UTC (rev 3391)
@@ -45,7 +45,7 @@
 enum {
 	/** The Application Programming Interface (API) version, incremented
 	 * whenever any plugin data types are modified or appended to. */
-	GEANY_API_VERSION = 118,
+	GEANY_API_VERSION = 119,
 
 	/** The Application Binary Interface (ABI) version, incremented whenever
 	 * existing fields in the plugin data types have to be changed or reordered. */


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the Commits mailing list