Add "editor-notify" to the plugin API.
This signal is emitted whenever something in an editor widget changes, e.g. a character was typed. git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@3391 ea778897-0a13-0410-b9d1-a72fbfd435f5
This commit is contained in:
parent
5ceb85d214
commit
44b7d27b50
@ -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>
|
||||
|
@ -40,7 +40,7 @@ ALIASES = "signal=- @ref " \
|
||||
"endsignaldef= " \
|
||||
"signalproto=@code " \
|
||||
"endsignalproto=@endcode " \
|
||||
"signaldesc=@par Description: " \
|
||||
"signaldesc=" \
|
||||
"signals=@b Signals: " \
|
||||
"endsignals= "
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
|
@ -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,6 +186,44 @@ PluginCallback plugin_callbacks[] =
|
||||
* @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
|
||||
|
@ -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 GtkWidget *main_menu_item = NULL;
|
||||
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)
|
||||
|
@ -595,7 +595,7 @@ GeanyDocument *document_new_file(const gchar *utf8_filename, GeanyFiletype *ft,
|
||||
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 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
|
||||
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);
|
||||
}
|
||||
|
31
src/editor.c
31
src/editor.c
@ -249,8 +249,6 @@ static gboolean is_style_php(gint style)
|
||||
}
|
||||
|
||||
|
||||
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 @@ static void auto_update_margin_width(GeanyDocument *doc)
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
SCNotification *nt;
|
||||
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 @@ void on_editor_notification(GtkWidget *widget, gint scn, gpointer lscn, gpointer
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* we always return FALSE here to let plugins handle the event to */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@ -4158,6 +4169,10 @@ void editor_init(void)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -131,7 +131,7 @@ extern GeanyEditorPrefs editor_prefs;
|
||||
|
||||
|
||||
/** 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 @@ typedef struct GeanyEditor
|
||||
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,7 +152,7 @@ typedef struct
|
||||
|
||||
extern EditorInfo editor_info;
|
||||
|
||||
|
||||
typedef struct SCNotification SCNotification;
|
||||
|
||||
|
||||
void editor_init(void);
|
||||
@ -164,7 +163,7 @@ void editor_destroy(GeanyEditor *editor);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -56,6 +56,7 @@
|
||||
|
||||
/* Common forward declarations */
|
||||
typedef struct GeanyDocument GeanyDocument;
|
||||
typedef struct GeanyEditor GeanyEditor;
|
||||
typedef struct GeanyFiletype GeanyFiletype;
|
||||
|
||||
|
||||
|
@ -81,10 +81,10 @@ GType geany_object_get_type(void)
|
||||
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 @@ static void geany_cclosure_marshal_VOID__STRING_INT_POINTER(GClosure *closure, G
|
||||
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 void geany_cclosure_marshal_VOID__STRING_INT_POINTER(GClosure *closure, G
|
||||
}
|
||||
|
||||
|
||||
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 @@ static void create_signals(GObjectClass *g_object_class)
|
||||
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 @@ static void create_signals(GObjectClass *g_object_class)
|
||||
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 @@ static void create_signals(GObjectClass *g_object_class)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -43,6 +43,7 @@ typedef enum
|
||||
GCB_PROJECT_SAVE,
|
||||
GCB_PROJECT_CLOSE,
|
||||
GCB_UPDATE_EDITOR_MENU,
|
||||
GCB_EDITOR_NOTIFY,
|
||||
GCB_MAX
|
||||
} GeanyCallbackId;
|
||||
|
||||
@ -81,6 +82,7 @@ struct _GeanyObjectClass
|
||||
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);
|
||||
|
@ -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. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user