SF.net SVN: geany: [2621] trunk
ntrel at users.sourceforge.net
ntrel at xxxxx
Wed May 28 13:05:13 UTC 2008
Revision: 2621
http://geany.svn.sourceforge.net/geany/?rev=2621&view=rev
Author: ntrel
Date: 2008-05-28 06:05:09 -0700 (Wed, 28 May 2008)
Log Message:
-----------
Note: this breaks the plugin API.
Remove plugin symbol configure().
Add plugin symbol plugin_configure() which is used to tell Geany a
widget to pack into the plugin preferences dialog, and connect a
response callback for when the dialog receives a user decision.
This allows Geany to in future implement a common preferences dialog
for all plugins, without breaking the plugin API/ABI.
Add Apply button for plugin preference dialogs (to indicate plugins
should handle the apply response as well as OK, as a multiple plugin
configuration dialog would want an apply button).
Modified Paths:
--------------
trunk/ChangeLog
trunk/doc/plugin-symbols.c
trunk/plugins/autosave.c
trunk/plugins/demoplugin.c
trunk/plugins/filebrowser.c
trunk/src/plugindata.h
trunk/src/plugins.c
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2008-05-27 17:03:43 UTC (rev 2620)
+++ trunk/ChangeLog 2008-05-28 13:05:09 UTC (rev 2621)
@@ -1,3 +1,19 @@
+2008-05-28 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+
+ * src/plugindata.h, src/plugins.c, doc/plugin-symbols.c,
+ plugins/demoplugin.c, plugins/filebrowser.c, plugins/autosave.c:
+ Note: this breaks the plugin API.
+ Remove plugin symbol configure().
+ Add plugin symbol plugin_configure() which is used to tell Geany a
+ widget to pack into the plugin preferences dialog, and connect a
+ response callback for when the dialog receives a user decision.
+ This allows Geany to in future implement a common preferences dialog
+ for all plugins, without breaking the plugin API/ABI.
+ Add Apply button for plugin preference dialogs (to indicate plugins
+ should handle the apply response as well as OK, as a multiple plugin
+ configuration dialog would want an apply button).
+
+
2008-05-27 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
* src/plugins.c:
Modified: trunk/doc/plugin-symbols.c
===================================================================
--- trunk/doc/plugin-symbols.c 2008-05-27 17:03:43 UTC (rev 2620)
+++ trunk/doc/plugin-symbols.c 2008-05-28 13:05:09 UTC (rev 2621)
@@ -76,10 +76,13 @@
KeyBindingGroup plugin_key_group[1];
-/** Called when the plugin should show a configure dialog to let the user set some basic
- * plugin configuration. Optionally, can be omitted when not needed.
- * @param parent The Plugin Manager dialog widget. */
-void configure(GtkWidget *parent);
+/** Called before showing the plugin preferences dialog to let the user set some basic
+ * plugin configuration options. Can be omitted when not needed.
+ * @param dialog The plugin preferences dialog widget - this should only be used to
+ * connect the @c "response" signal. If settings should be read from the dialog, the
+ * reponse will be either @c GTK_RESPONSE_OK or @c GTK_RESPONSE_APPLY.
+ * @return A container widget holding preference widgets. */
+GtkWidget* plugin_configure(GtkDialog *dialog);
/** Called after loading the plugin.
* @param data The same as #geany_data. */
Modified: trunk/plugins/autosave.c
===================================================================
--- trunk/plugins/autosave.c 2008-05-27 17:03:43 UTC (rev 2620)
+++ trunk/plugins/autosave.c 2008-05-28 13:05:09 UTC (rev 2621)
@@ -116,23 +116,67 @@
}
-void configure(GtkWidget *parent)
+static struct
{
- GtkWidget *dialog, *label, *spin, *vbox, *hbox, *checkbox, *radio1, *radio2;
+ GtkWidget *interval_spin;
+ GtkWidget *print_msg_checkbox;
+ GtkWidget *save_all_radio;
+}
+pref_widgets;
- dialog = gtk_dialog_new_with_buttons(_("Auto Save"),
- GTK_WINDOW(parent), GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
- vbox = p_ui->dialog_vbox_new(GTK_DIALOG(dialog));
- gtk_widget_set_name(dialog, "GeanyDialog");
- gtk_box_set_spacing(GTK_BOX(vbox), 6);
+static void
+on_configure_response(GtkDialog *dialog, gint response, G_GNUC_UNUSED gpointer user_data)
+{
+ if (response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY)
+ {
+ GKeyFile *config = g_key_file_new();
+ gchar *data;
+ gchar *config_dir = g_path_get_dirname(config_file);
+ interval = gtk_spin_button_get_value_as_int((GTK_SPIN_BUTTON(pref_widgets.interval_spin)));
+ print_msg = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pref_widgets.print_msg_checkbox));
+ save_all = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pref_widgets.save_all_radio));
+
+ g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL);
+
+ g_key_file_set_integer(config, "autosave", "interval", interval);
+ g_key_file_set_boolean(config, "autosave", "print_messages", print_msg);
+ g_key_file_set_boolean(config, "autosave", "save_all", save_all);
+
+ if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && p_utils->mkdir(config_dir, TRUE) != 0)
+ {
+ p_dialogs->show_msgbox(GTK_MESSAGE_ERROR,
+ _("Plugin configuration directory could not be created."));
+ }
+ else
+ {
+ /* write config to file */
+ data = g_key_file_to_data(config, NULL, NULL);
+ p_utils->write_file(config_file, data);
+ g_free(data);
+ }
+
+ set_timeout(); /* apply the changes */
+
+ g_free(config_dir);
+ g_key_file_free(config);
+ }
+}
+
+
+GtkWidget *plugin_configure(GtkDialog *dialog)
+{
+ GtkWidget *vbox, *label, *spin, *hbox, *checkbox, *radio1, *radio2;
+
+ vbox = gtk_vbox_new(FALSE, 6);
+
label = gtk_label_new(_("Auto save interval:"));
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
gtk_container_add(GTK_CONTAINER(vbox), label);
spin = gtk_spin_button_new_with_range(1, 1800, 1);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), interval);
+ pref_widgets.interval_spin = spin;
label = gtk_label_new(_("seconds"));
@@ -147,6 +191,7 @@
gtk_button_set_focus_on_click(GTK_BUTTON(checkbox), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), print_msg);
gtk_box_pack_start(GTK_BOX(vbox), checkbox, FALSE, FALSE, 5);
+ pref_widgets.print_msg_checkbox = checkbox;
radio1 = gtk_radio_button_new_with_label(NULL,
_("Save only current open file"));
@@ -158,45 +203,12 @@
gtk_button_set_focus_on_click(GTK_BUTTON(radio2), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio2), save_all);
gtk_container_add(GTK_CONTAINER(vbox), radio2);
+ pref_widgets.save_all_radio = radio2;
gtk_widget_show_all(vbox);
- /* run the dialog and check for the response code */
- if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
- {
- GKeyFile *config = g_key_file_new();
- gchar *data;
- gchar *config_dir = g_path_get_dirname(config_file);
-
- interval = gtk_spin_button_get_value_as_int((GTK_SPIN_BUTTON(spin)));
- print_msg = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox));
- save_all = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio2));
-
- g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL);
-
- g_key_file_set_integer(config, "autosave", "interval", interval);
- g_key_file_set_boolean(config, "autosave", "print_messages", print_msg);
- g_key_file_set_boolean(config, "autosave", "save_all", save_all);
-
- if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && p_utils->mkdir(config_dir, TRUE) != 0)
- {
- p_dialogs->show_msgbox(GTK_MESSAGE_ERROR,
- _("Plugin configuration directory could not be created."));
- }
- else
- {
- /* write config to file */
- data = g_key_file_to_data(config, NULL, NULL);
- p_utils->write_file(config_file, data);
- g_free(data);
- }
-
- set_timeout(); /* apply the changes */
-
- g_free(config_dir);
- g_key_file_free(config);
- }
- gtk_widget_destroy(dialog);
+ g_signal_connect(dialog, "response", G_CALLBACK(on_configure_response), NULL);
+ return vbox;
}
Modified: trunk/plugins/demoplugin.c
===================================================================
--- trunk/plugins/demoplugin.c 2008-05-27 17:03:43 UTC (rev 2620)
+++ trunk/plugins/demoplugin.c 2008-05-28 13:05:09 UTC (rev 2621)
@@ -101,48 +101,54 @@
}
+/* Callback connected in plugin_configure(). */
+static void
+on_configure_response(GtkDialog *dialog, gint response, gpointer user_data)
+{
+ /* catch OK or Apply clicked */
+ if (response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY)
+ {
+ /* We only have one pref here, but for more you would use a struct for user_data */
+ GtkWidget *entry = GTK_WIDGET(user_data);
+
+ g_free(welcome_text);
+ welcome_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
+ /* maybe the plugin should write here the settings into a file
+ * (e.g. using GLib's GKeyFile API)
+ * all plugin specific files should be created in:
+ * app->configdir G_DIR_SEPARATOR_S plugins G_DIR_SEPARATOR_S pluginname G_DIR_SEPARATOR_S
+ * e.g. this could be: ~/.geany/plugins/Demo/, please use app->configdir */
+ }
+}
+
+
/* Called by Geany to show the plugin's configure dialog. This function is always called after
* plugin_init() was called.
* You can omit this function if the plugin doesn't need to be configured.
* Note: parent is the parent window which can be used as the transient window for the created
* dialog. */
-void configure(GtkWidget *parent)
+GtkWidget *plugin_configure(GtkDialog *dialog)
{
- GtkWidget *dialog, *label, *entry, *vbox;
+ GtkWidget *label, *entry, *vbox;
/* example configuration dialog */
- dialog = gtk_dialog_new_with_buttons(_("Demo"),
- GTK_WINDOW(parent), GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
- vbox = p_ui->dialog_vbox_new(GTK_DIALOG(dialog));
- gtk_widget_set_name(dialog, "GeanyDialog");
- gtk_box_set_spacing(GTK_BOX(vbox), 6);
+ vbox = gtk_vbox_new(FALSE, 6);
/* add a label and a text entry to the dialog */
label = gtk_label_new(_("Welcome text to show:"));
- gtk_widget_show(label);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
entry = gtk_entry_new();
- gtk_widget_show(entry);
if (welcome_text != NULL)
gtk_entry_set_text(GTK_ENTRY(entry), welcome_text);
gtk_container_add(GTK_CONTAINER(vbox), label);
gtk_container_add(GTK_CONTAINER(vbox), entry);
- gtk_widget_show(vbox);
- /* run the dialog and check for the response code */
- if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
- {
- g_free(welcome_text);
- welcome_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
- /* maybe the plugin should write here the settings into a file
- * (e.g. using GLib's GKeyFile API)
- * all plugin specific files should be created in:
- * app->configdir G_DIR_SEPARATOR_S plugins G_DIR_SEPARATOR_S pluginname G_DIR_SEPARATOR_S
- * e.g. this could be: ~/.geany/plugins/Demo/, please use app->configdir */
- }
- gtk_widget_destroy(dialog);
+ gtk_widget_show_all(vbox);
+
+ /* Connect a callback for when the user clicks a dialog button */
+ g_signal_connect(dialog, "response", G_CALLBACK(on_configure_response), entry);
+ return vbox;
}
Modified: trunk/plugins/filebrowser.c
===================================================================
--- trunk/plugins/filebrowser.c 2008-05-27 17:03:43 UTC (rev 2620)
+++ trunk/plugins/filebrowser.c 2008-05-28 13:05:09 UTC (rev 2621)
@@ -952,17 +952,62 @@
}
-void configure(GtkWidget *parent)
+static struct
{
- GtkWidget *dialog, *label, *entry, *checkbox_of, *checkbox_hf, *vbox;
+ GtkWidget *open_cmd_entry;
+ GtkWidget *show_hidden_checkbox;
+ GtkWidget *hide_objects_checkbox;
+}
+pref_widgets;
+
+static void
+on_configure_response(GtkDialog *dialog, gint response, gpointer user_data)
+{
+ if (response == GTK_RESPONSE_OK || response == GTK_RESPONSE_APPLY)
+ {
+ GKeyFile *config = g_key_file_new();
+ gchar *data;
+ gchar *config_dir = g_path_get_dirname(config_file);
+
+ g_free(open_cmd);
+ open_cmd = g_strdup(gtk_entry_get_text(GTK_ENTRY(pref_widgets.open_cmd_entry)));
+ show_hidden_files = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pref_widgets.show_hidden_checkbox));
+ hide_object_files = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pref_widgets.hide_objects_checkbox));
+
+ g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL);
+
+ g_key_file_set_string(config, "filebrowser", "open_command", open_cmd);
+ g_key_file_set_boolean(config, "filebrowser", "show_hidden_files", show_hidden_files);
+ g_key_file_set_boolean(config, "filebrowser", "hide_object_files", hide_object_files);
+
+ if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && p_utils->mkdir(config_dir, TRUE) != 0)
+ {
+ p_dialogs->show_msgbox(GTK_MESSAGE_ERROR,
+ _("Plugin configuration directory could not be created."));
+ }
+ else
+ {
+ /* write config to file */
+ data = g_key_file_to_data(config, NULL, NULL);
+ p_utils->write_file(config_file, data);
+ g_free(data);
+ }
+
+ /* apply the changes */
+ refresh();
+
+ g_free(config_dir);
+ g_key_file_free(config);
+ }
+}
+
+
+GtkWidget *plugin_configure(GtkDialog *dialog)
+{
+ GtkWidget *label, *entry, *checkbox_of, *checkbox_hf, *vbox;
GtkTooltips *tooltips = gtk_tooltips_new();
- dialog = gtk_dialog_new_with_buttons(_("File Browser"),
- GTK_WINDOW(parent), GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
- vbox = p_ui->dialog_vbox_new(GTK_DIALOG(dialog));
- gtk_widget_set_name(dialog, "GeanyDialog");
- gtk_box_set_spacing(GTK_BOX(vbox), 6);
+ vbox = gtk_vbox_new(FALSE, 6);
label = gtk_label_new(_("External open command:"));
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
@@ -978,11 +1023,13 @@
"%d will be replaced with the path name of the selected file without the filename"),
NULL);
gtk_container_add(GTK_CONTAINER(vbox), entry);
+ pref_widgets.open_cmd_entry = entry;
checkbox_hf = gtk_check_button_new_with_label(_("Show hidden files"));
gtk_button_set_focus_on_click(GTK_BUTTON(checkbox_hf), FALSE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox_hf), show_hidden_files);
gtk_box_pack_start(GTK_BOX(vbox), checkbox_hf, FALSE, FALSE, 5);
+ pref_widgets.show_hidden_checkbox = checkbox_hf;
checkbox_of = gtk_check_button_new_with_label(_("Hide object files"));
gtk_button_set_focus_on_click(GTK_BUTTON(checkbox_of), FALSE);
@@ -992,48 +1039,12 @@
"*.o, *.obj. *.so, *.dll, *.a, *.lib"),
NULL);
gtk_box_pack_start(GTK_BOX(vbox), checkbox_of, FALSE, FALSE, 5);
+ pref_widgets.hide_objects_checkbox = checkbox_of;
-
gtk_widget_show_all(vbox);
- /* run the dialog and check for the response code */
- if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
- {
- GKeyFile *config = g_key_file_new();
- gchar *data;
- gchar *config_dir = g_path_get_dirname(config_file);
-
- g_free(open_cmd);
- open_cmd = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
- show_hidden_files = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox_hf));
- hide_object_files = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox_of));
-
- g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL);
-
- g_key_file_set_string(config, "filebrowser", "open_command", open_cmd);
- g_key_file_set_boolean(config, "filebrowser", "show_hidden_files", show_hidden_files);
- g_key_file_set_boolean(config, "filebrowser", "hide_object_files", hide_object_files);
-
- if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && p_utils->mkdir(config_dir, TRUE) != 0)
- {
- p_dialogs->show_msgbox(GTK_MESSAGE_ERROR,
- _("Plugin configuration directory could not be created."));
- }
- else
- {
- /* write config to file */
- data = g_key_file_to_data(config, NULL, NULL);
- p_utils->write_file(config_file, data);
- g_free(data);
- }
-
- /* apply the changes */
- refresh();
-
- g_free(config_dir);
- g_key_file_free(config);
- }
- gtk_widget_destroy(dialog);
+ g_signal_connect(dialog, "response", G_CALLBACK(on_configure_response), NULL);
+ return vbox;
}
Modified: trunk/src/plugindata.h
===================================================================
--- trunk/src/plugindata.h 2008-05-27 17:03:43 UTC (rev 2620)
+++ trunk/src/plugindata.h 2008-05-28 13:05:09 UTC (rev 2621)
@@ -36,7 +36,7 @@
/* The API version should be incremented whenever any plugin data types below are
* modified or appended to. */
-static const gint api_version = 64;
+static const gint api_version = 65;
/* The ABI version should be incremented whenever existing fields in the plugin
* data types below have to be changed or reordered. It should stay the same if fields
Modified: trunk/src/plugins.c
===================================================================
--- trunk/src/plugins.c 2008-05-27 17:03:43 UTC (rev 2620)
+++ trunk/src/plugins.c 2008-05-28 13:05:09 UTC (rev 2621)
@@ -74,9 +74,9 @@
gsize signal_ids_len;
KeyBindingGroup *key_group;
- void (*init) (GeanyData *data); /* Called when the plugin is enabled */
- void (*configure) (GtkWidget *parent); /* plugin configure dialog, optionally */
- void (*cleanup) (void); /* Called when the plugin is disabled or when Geany exits */
+ void (*init) (GeanyData *data); /* Called when the plugin is enabled */
+ GtkWidget* (*configure) (GtkDialog *dialog); /* plugin configure dialog, optional */
+ void (*cleanup) (void); /* Called when the plugin is disabled or when Geany exits */
}
Plugin;
@@ -467,9 +467,9 @@
plugin->init(&geany_data);
/* store some function pointers for later use */
- g_module_symbol(plugin->module, "configure", (void *) &plugin->configure);
+ g_module_symbol(plugin->module, "plugin_configure", (void *) &plugin->configure);
g_module_symbol(plugin->module, "plugin_cleanup", (void *) &plugin->cleanup);
- if (plugin->init != NULL && plugin->cleanup == NULL)
+ if (plugin->cleanup == NULL)
{
if (app->debug_mode)
g_warning("Plugin '%s' has no plugin_cleanup() function - there may be memory leaks!",
@@ -898,6 +898,7 @@
GtkWidget *description_label;
GtkWidget *configure_button;
} PluginManagerWidgets;
+
static PluginManagerWidgets pm_widgets;
@@ -1036,6 +1037,39 @@
}
+static void configure_plugin(Plugin *p)
+{
+ GtkWidget *parent = pm_widgets.dialog;
+ GtkWidget *prefs_page, *dialog, *vbox;
+
+ dialog = gtk_dialog_new_with_buttons(p->info.name,
+ GTK_WINDOW(parent), GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+ gtk_widget_set_name(dialog, "GeanyDialog");
+
+ vbox = ui_dialog_vbox_new(GTK_DIALOG(dialog));
+ gtk_widget_show(vbox);
+
+ prefs_page = p->configure(GTK_DIALOG(dialog));
+
+ if (! GTK_IS_WIDGET(prefs_page))
+ {
+ geany_debug("Invalid widget returned from plugin_configure() in plugin \"%s\"!",
+ p->info.name);
+ }
+ else
+ {
+ gtk_container_add(GTK_CONTAINER(vbox), prefs_page);
+
+ /* run the dialog */
+ while (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_APPLY);
+ }
+ gtk_widget_destroy(dialog);
+}
+
+
void pm_on_configure_button_clicked(GtkButton *button, gpointer user_data)
{
GtkTreeModel *model;
@@ -1050,7 +1084,7 @@
if (p != NULL)
{
- p->configure(pm_widgets.dialog);
+ configure_plugin(p);
}
}
}
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