Kaydet (Commit) d8d72775 authored tarafından Nick Treleaven's avatar Nick Treleaven

- API changes:

Replace p_ui->get_toolbar_insert_position() with
p_plugin->add_toolbar_item(), which also adds a separator when the
first item is added.
Add 'GeanyPlugin *geany_plugin' plugin symbol, partly to replace
plugin_info (now deprecated), mainly to identify a plugin and hold
private implementation fields for plugin utility functions.
(plugin_info will be removed after the 0.15 release.)
- Code changes:
Add ui_auto_separator_add_ref() to hide separator-like widgets when
their visible group elements are hidden or destroyed.


git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@3074 ea778897-0a13-0410-b9d1-a72fbfd435f5
üst be3849e3
2008-10-13 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
* src/ui_utils.h, src/plugindata.h, src/plugins.c, src/ui_utils.c,
doc/Doxyfile.in, doc/pluginsymbols.c, plugins/demoplugin.c,
plugins/pluginmacros.h:
- API changes:
Replace p_ui->get_toolbar_insert_position() with
p_plugin->add_toolbar_item(), which also adds a separator when the
first item is added.
Add 'GeanyPlugin *geany_plugin' plugin symbol, partly to replace
plugin_info (now deprecated), mainly to identify a plugin and hold
private implementation fields for plugin utility functions.
(plugin_info will be removed after the 0.15 release.)
- Code changes:
Add ui_auto_separator_add_ref() to hide separator-like widgets when
their visible group elements are hidden or destroyed.
2008-10-12 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
* src/highlighting.c:
......
......@@ -226,7 +226,7 @@ SEARCH_INCLUDES = NO
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
# make G_GNUC_PRINTF a no-op unless doxygen would ignore functions with varargs
PREDEFINED = "G_GNUC_PRINTF(x,y)=" GEANY_DISABLE_DEPRECATED
PREDEFINED = "G_GNUC_PRINTF(x,y)=" GEANY_DISABLE_DEPRECATED HAVE_PLUGINS
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = NO
#---------------------------------------------------------------------------
......
......@@ -43,22 +43,26 @@ gint plugin_version_check(gint);
* @param info The data struct which should be initialized by this function. */
void plugin_set_info(PluginInfo *info);
/** Basic information about a plugin, which is set in plugin_set_info(). */
const PluginInfo* plugin_info;
/** @deprecated Use geany_plugin->info instead.
* Basic information about a plugin, which is set in plugin_set_info(). */
const PluginInfo *plugin_info;
/** Basic information for the plugin and identification. */
const GeanyPlugin *geany_plugin;
/** Geany owned data pointers.
* Example: @c assert(geany_data->app->configdir != NULL); */
const GeanyData* geany_data;
const GeanyData *geany_data;
/** Geany owned function pointers, split into groups.
* Example: @c geany_functions->p_document->new_file(NULL, NULL, NULL);
*
* Note: Usually plugins would use the pluginmacros.h file and just call:
* @c p_document->new_file(NULL, NULL, NULL); */
const GeanyFunctions* geany_functions;
const GeanyFunctions *geany_functions;
/** Plugin owned fields, including flags. */
PluginFields* plugin_fields;
PluginFields *plugin_fields;
/** An array for connecting GeanyObject events, which should be terminated with
* @c {NULL, NULL, FALSE, NULL}. See @link signals Signal documentation @endlink. */
......
......@@ -44,15 +44,15 @@
/* These items are set by Geany before plugin_init() is called. */
PluginInfo *plugin_info;
GeanyPlugin *geany_plugin;
PluginFields *plugin_fields;
GeanyData *geany_data;
GeanyFunctions *geany_functions;
/* Check that Geany supports plugin API version 7 or later, and check
/* Check that the running Geany supports the plugin API used below, and check
* for binary compatibility. */
PLUGIN_VERSION_CHECK(64)
PLUGIN_VERSION_CHECK(99)
/* All plugins must set name, description, version and author. */
PLUGIN_SET_INFO(_("Demo"), _("Example plugin."), VERSION, _("The Geany developer team"))
......@@ -75,7 +75,7 @@ item_activate(GtkMenuItem *menuitem, gpointer gdata)
GTK_BUTTONS_OK,
"%s", welcome_text);
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
_("(From the %s plugin)"), plugin_info->name);
_("(From the %s plugin)"), geany_plugin->info->name);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
......
......@@ -52,6 +52,7 @@
#define p_main geany_functions->p_main /**< See main.h */
#define p_msgwindow geany_functions->p_msgwindow /**< See msgwindow.h */
#define p_navqueue geany_functions->p_navqueue /**< See navqueue.h */
#define p_plugin geany_functions->p_plugin /**< See plugins.c */
#define p_sci geany_functions->p_sci /**< See sciwrappers.h */
#define p_search geany_functions->p_search /**< See search.h */
#define p_support geany_functions->p_support /**< See support.h */
......
......@@ -41,13 +41,13 @@
enum {
/** The Application Programming Interface (API) version, incremented
* whenever any plugin data types are modified or appended to. */
GEANY_API_VERSION = 98,
GEANY_API_VERSION = 99,
/** The Application Binary Interface (ABI) version, incremented whenever
* existing fields in the plugin data types have to be changed or reordered. */
/* This should usually stay the same if fields are only appended, assuming only pointers to
* structs and not structs themselves are declared by plugins. */
GEANY_ABI_VERSION = 46
GEANY_ABI_VERSION = 47
};
/** Check the plugin can be loaded by Geany.
......@@ -65,8 +65,8 @@ enum {
}
/** Plugin info structure to hold basic information about a plugin.
* Should usually be set with PLUGIN_SET_INFO(). */
/** Basic information about a plugin available to Geany without loading the plugin.
* The fields are set in plugin_set_info(), usually with the PLUGIN_SET_INFO() macro. */
typedef struct PluginInfo
{
/** The name of the plugin. */
......@@ -80,6 +80,17 @@ typedef struct PluginInfo
}
PluginInfo;
/** Basic information for the plugin and identification. */
typedef struct GeanyPlugin
{
PluginInfo *info; /**< Fields set in plugin_set_info(). */
struct GeanyPluginPrivate *priv; /* private */
}
GeanyPlugin;
/** Set the plugin name and some other basic information about a plugin.
* This declares a function, so you can use the _() translation macro for arguments.
*
......@@ -198,6 +209,7 @@ typedef struct GeanyFunctions
struct NavQueueFuncs *p_navqueue; /**< See navqueue.h */
struct EditorFuncs *p_editor; /**< See editor.h */
struct MainFuncs *p_main; /**< See main.h */
struct PluginFuncs *p_plugin; /**< See plugins.c */
}
GeanyFunctions;
......@@ -336,7 +348,6 @@ typedef struct UIUtilsFuncs
void (*table_add_row) (GtkTable *table, gint row, ...) G_GNUC_NULL_TERMINATED;
GtkWidget* (*path_box_new) (const gchar *title, GtkFileChooserAction action, GtkEntry *entry);
GtkWidget* (*button_new_with_image) (const gchar *stock_id, const gchar *text);
gint (*get_toolbar_insert_position) (void);
}
UIUtilsFuncs;
......@@ -466,6 +477,14 @@ typedef struct EditorFuncs
EditorFuncs;
/* See plugins.c */
typedef struct PluginFuncs
{
void (*add_toolbar_item)(GeanyPlugin *plugin, GtkToolItem *item);
}
PluginFuncs;
/* Deprecated aliases */
#ifndef GEANY_DISABLE_DEPRECATED
......
......@@ -23,6 +23,8 @@
*/
/* Code to manage, load and unload plugins. */
/** @file plugins.c
* Plugin utility functions. */
#include "geany.h"
......@@ -65,12 +67,22 @@
#endif
typedef struct GeanyPluginPrivate
{
GeanyAutoSeparator toolbar_separator;
}
GeanyPluginPrivate;
typedef struct Plugin
{
GModule *module;
gchar *filename; /* plugin filename (/path/libname.so) */
PluginInfo info; /* plugin name, description, etc */
PluginFields fields;
GeanyPlugin public; /* fields the plugin can read */
GeanyPluginPrivate priv; /* GeanyPlugin type private data */
gulong *signal_ids; /* signal IDs to disconnect when unloading */
gsize signal_ids_len;
GeanyKeyGroup *key_group;
......@@ -93,6 +105,12 @@ static GtkWidget *menu_separator = NULL;
static void pm_show_dialog(GtkMenuItem *menuitem, gpointer user_data);
void plugin_add_toolbar_item(GeanyPlugin *plugin, GtkToolItem *item);
static PluginFuncs plugin_funcs = {
&plugin_add_toolbar_item
};
static DocumentFuncs doc_funcs = {
&document_new_file,
......@@ -185,7 +203,6 @@ static UIUtilsFuncs uiutils_funcs = {
&ui_table_add_row,
&ui_path_box_new,
&ui_button_new_with_image,
&ui_get_toolbar_insert_position
};
static DialogFuncs dialog_funcs = {
......@@ -265,7 +282,8 @@ static GeanyFunctions geany_functions = {
&filetype_funcs,
&navqueue_funcs,
&editor_funcs,
&main_funcs
&main_funcs,
&plugin_funcs
};
static GeanyData geany_data;
......@@ -454,6 +472,7 @@ add_kb_group(Plugin *plugin)
static void
plugin_init(Plugin *plugin)
{
GeanyPlugin **p_geany_plugin;
PluginCallback *callbacks;
PluginInfo **p_info;
PluginFields **plugin_fields;
......@@ -461,6 +480,9 @@ plugin_init(Plugin *plugin)
GeanyFunctions **p_geany_functions;
/* set these symbols before plugin_init() is called */
g_module_symbol(plugin->module, "geany_plugin", (void *) &p_geany_plugin);
if (p_geany_plugin)
*p_geany_plugin = &plugin->public;
g_module_symbol(plugin->module, "plugin_info", (void *) &p_info);
if (p_info)
*p_info = &plugin->info;
......@@ -608,6 +630,8 @@ plugin_new(const gchar *fname, gboolean init_plugin, gboolean add_to_list)
plugin->filename = g_strdup(fname);
plugin->module = module;
plugin->public.info = &plugin->info;
plugin->public.priv = &plugin->priv;
if (init_plugin)
plugin_init(plugin);
......@@ -641,6 +665,7 @@ static gboolean is_active_plugin(Plugin *plugin)
static void
plugin_unload(Plugin *plugin)
{
GtkWidget *widget;
if (is_active_plugin(plugin) && plugin->cleanup)
plugin->cleanup();
......@@ -650,6 +675,10 @@ plugin_unload(Plugin *plugin)
if (plugin->key_group)
g_ptr_array_remove_fast(keybinding_groups, plugin->key_group);
widget = plugin->priv.toolbar_separator.widget;
if (widget)
gtk_widget_destroy(widget);
active_plugin_list = g_list_remove(active_plugin_list, plugin);
geany_debug("Unloaded: %s", plugin->filename);
}
......@@ -1194,4 +1223,44 @@ static void pm_show_dialog(GtkMenuItem *menuitem, gpointer user_data)
gtk_widget_show_all(pm_widgets.dialog);
}
/** Insert 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.
* @note You should still destroy @a item yourself, usually in @ref plugin_cleanup().
* @param plugin Must be @ref geany_plugin.
* @param item The item to add. */
void plugin_add_toolbar_item(GeanyPlugin *plugin, GtkToolItem *item)
{
GtkToolbar *toolbar = GTK_TOOLBAR(main_widgets.toolbar);
gint pos;
GeanyAutoSeparator *autosep;
g_return_if_fail(plugin);
autosep = &plugin->priv->toolbar_separator;
if (!autosep->widget)
{
GtkToolItem *sep;
pos = ui_get_toolbar_insert_position();
/* pos should be valid even if the quit btn is hidden */
g_return_if_fail(pos >= 0);
gtk_toolbar_insert(toolbar, item, pos);
sep = gtk_separator_tool_item_new();
gtk_toolbar_insert(toolbar, sep, pos + 1);
autosep->widget = GTK_WIDGET(sep);
}
else
{
pos = gtk_toolbar_get_item_index(toolbar, GTK_TOOL_ITEM(autosep->widget));
g_return_if_fail(pos >= 0);
gtk_toolbar_insert(toolbar, item, pos);
}
/* hide the separator widget if there are no toolbar items showing for the plugin */
ui_auto_separator_add_ref(autosep, GTK_WIDGET(item));
}
#endif
......@@ -1531,7 +1531,7 @@ void ui_init(void)
}
/** Returns the position for adding new toolbar items. The returned position can be used
/* Returns the position for adding new toolbar items. The returned position can be used
* to add new toolbar items with @c gtk_toolbar_insert(). The toolbar object can be accessed
* with @a geany->main_widgets->toolbar.
* The position is always the last one before the Quit button (if it is shown).
......@@ -1550,3 +1550,59 @@ gint ui_get_toolbar_insert_position(void)
return pos;
}
static void auto_separator_update(GeanyAutoSeparator *autosep)
{
g_return_if_fail(autosep->ref_count >= 0);
if (autosep->widget)
ui_widget_show_hide(autosep->widget, autosep->ref_count > 0);
}
static void on_auto_separator_item_show_hide(GtkWidget *widget, gpointer user_data)
{
GeanyAutoSeparator *autosep = user_data;
if (GTK_WIDGET_VISIBLE(widget))
autosep->ref_count++;
else
autosep->ref_count--;
auto_separator_update(autosep);
}
static void on_auto_separator_item_destroy(GtkWidget *widget, gpointer user_data)
{
GeanyAutoSeparator *autosep = user_data;
/* GTK_WIDGET_VISIBLE won't work now the widget is being destroyed,
* so assume widget was visible */
autosep->ref_count--;
autosep->ref_count = MAX(autosep->ref_count, 0);
auto_separator_update(autosep);
}
/* Show the separator widget if @a item or another is visible. */
/* Note: This would be neater taking a widget argument, setting a "visible-count"
* property, and using reference counting to keep the widget alive whilst its visible group
* is alive. */
void ui_auto_separator_add_ref(GeanyAutoSeparator *autosep, GtkWidget *item)
{
/* set widget ptr NULL when widget destroyed */
if (autosep->ref_count == 0)
g_signal_connect(autosep->widget, "destroy",
G_CALLBACK(gtk_widget_destroyed), &autosep->widget);
if (GTK_WIDGET_VISIBLE(item))
{
autosep->ref_count++;
auto_separator_update(autosep);
}
g_signal_connect(item, "show", G_CALLBACK(on_auto_separator_item_show_hide), autosep);
g_signal_connect(item, "hide", G_CALLBACK(on_auto_separator_item_show_hide), autosep);
g_signal_connect(item, "destroy", G_CALLBACK(on_auto_separator_item_destroy), autosep);
}
......@@ -125,9 +125,17 @@ UIWidgets;
extern UIWidgets ui_widgets;
/* The following block of functions are more generic functions and closely related to
/* The following block of types & functions are more generic and closely related to
* certain GTK+ widgets. */
typedef struct GeanyAutoSeparator
{
GtkWidget *widget; /* e.g. GtkSeparatorToolItem, GtkSeparatorMenuItem */
gint ref_count; /* set to zero initially */
}
GeanyAutoSeparator;
void ui_widget_show_hide(GtkWidget *widget, gboolean show);
void ui_widget_modify_font_from_string(GtkWidget *wid, const gchar *str);
......@@ -151,6 +159,8 @@ void ui_setup_open_button_callback(GtkWidget *open_btn, const gchar *title,
void ui_table_add_row(GtkTable *table, gint row, ...) G_GNUC_NULL_TERMINATED;
void ui_auto_separator_add_ref(GeanyAutoSeparator *autosep, GtkWidget *item);
/* End of 'generic' functions */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment