[Commits] Makefile.am 1.3 1.4 callbacks.c 1.13 1.14 contactwindow.c 1.11 1.12 extension-loader.c 1.1 1.2 extension-loader.h 1.1 1.2 extension.c 1.1 NONE extension.h 1.1 1.2 gtk-utils.c 1.4 1.5 mainwindow.c 1.5 1.6 mainwindow.h 1.3 1.4
miras at claws-mail.org
miras at claws-mail.org
Sat Dec 10 00:01:23 CET 2011
Update of /home/claws-mail/contacts/src
In directory claws-mail:/tmp/cvs-serv2085/src
Modified Files:
Makefile.am callbacks.c contactwindow.c extension-loader.c
extension-loader.h extension.h gtk-utils.c mainwindow.c
mainwindow.h
Removed Files:
extension.c
Log Message:
2011-12-09 [mir] 0.6.0cvs38
* claws-contacts.pc.in
* configure.ac
* extensions/Makefile.am
* extensions/example/Makefile.am
* extensions/example/configure.ac
* extensions/example/config/Makefile.am
* extensions/example/src/Makefile.am
* extensions/example/src/example-extension.c
* extensions/export/ldifexport_extension.c
* plugins/Makefile.am
* plugins/example/Makefile.am
* plugins/example/configure.ac
* src/Makefile.am
* src/callbacks.c
* src/contactwindow.c
* src/extension-loader.c
* src/extension-loader.h
* src/extension.c
* src/extension.h
* src/gtk-utils.c
* src/mainwindow.c
* src/mainwindow.h
Fix a number of bugs
Refined the build system
Added a plugable extension framework
--- extension.c DELETED ---
Index: mainwindow.h
===================================================================
RCS file: /home/claws-mail/contacts/src/mainwindow.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- mainwindow.h 30 Nov 2011 23:35:12 -0000 1.3
+++ mainwindow.h 9 Dec 2011 23:01:21 -0000 1.4
@@ -59,7 +59,11 @@
GtkWidget* window;
GtkWidget* left_scroll;
GtkWidget* right_scroll;
+ GtkAccelGroup* accel;
GtkWidget* menu;
+ GtkWidget* tools_menu;
+ GtkWidget* help_menu;
+ GtkWidget* file_menu;
GtkWidget* toolbar;
GtkWidget* abook_list;
GtkWidget* contact_list;
@@ -80,6 +84,7 @@
guint source_id;
gchar* default_book;
gboolean compose_mode;
+ gboolean use_extensions;
} MainWindow;
enum {
Index: contactwindow.c
===================================================================
RCS file: /home/claws-mail/contacts/src/contactwindow.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- contactwindow.c 30 Nov 2011 16:37:59 -0000 1.11
+++ contactwindow.c 9 Dec 2011 23:01:21 -0000 1.12
@@ -47,6 +47,7 @@
#include "gtk-utils.h"
#include "mainwindow.h"
#include "callbacks.h"
+#include "extension-loader.h"
#define CONTACT_WINDOW_WIDTH 480
#define CONTACT_WINDOW_HEIGHT 400
@@ -67,7 +68,7 @@
} ContactEntryData;
typedef struct {
- MainWindow* main;
+ MainWindow* main;
AddressBook* abook;
Plugin* plugin;
Contact* contact;
@@ -151,10 +152,16 @@
GtkTreeSelection* row;
if (contact) {
- if (contact_is_new)
+ if (contact_is_new) {
cw->plugin->set_contact(cw->abook, contact, &err);
- else
+ if (cw->main->use_extensions) {
+ debug_print("AFTER_INIT_CONTACT_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_INIT_CONTACT_HOOK, contact);
+ }
+ }
+ else {
err = contact_write_to_backend(cw->plugin, cw->abook, cw->old, contact);
+ }
if (err) {
show_message(cw->window, GTK_UTIL_MESSAGE_WARNING, "%s", err);
g_free(err);
@@ -447,19 +454,35 @@
gchar* error = NULL;
if (strcmp(label, GTK_STOCK_OK) == 0) {
+ if (cw->main->use_extensions) {
+ debug_print("BEFORE_ADD_CONTACT_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_ADD_CONTACT_HOOK, cw->contact);
+ }
save_contact(cw, &error);
if (error) {
show_message(cw->window, GTK_UTIL_MESSAGE_ERROR, "%s", error);
g_free(error);
}
+ if (cw->main->use_extensions) {
+ debug_print("AFTER_ADD_CONTACT_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_ADD_CONTACT_HOOK, cw->contact);
+ }
quit_cb(widget, data);
}
else if (strcmp(label, GTK_STOCK_APPLY) == 0) {
+ if (cw->main->use_extensions) {
+ debug_print("AFTER_ADD_CONTACT_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_ADD_CONTACT_HOOK, cw->contact);
+ }
save_contact(cw, &error);
if (error) {
show_message(cw->window, GTK_UTIL_MESSAGE_ERROR, "%s", error);
g_free(error);
}
+ if (cw->main->use_extensions) {
+ debug_print("AFTER_ADD_CONTACT_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_ADD_CONTACT_HOOK, cw->contact);
+ }
}
else {
/* we should never end here */
Index: extension.h
===================================================================
RCS file: /home/claws-mail/contacts/src/extension.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- extension.h 30 Nov 2011 23:35:12 -0000 1.1
+++ extension.h 9 Dec 2011 23:01:21 -0000 1.2
@@ -38,20 +38,29 @@
G_BEGIN_DECLS
#include "mainwindow.h"
+#include "plugin.h"
+/* Available hooks */
typedef enum {
+ /* After main window but before plugins */
EXTENSION_BEFORE_INIT_HOOK,
+ /* After plugins */
EXTENSION_AFTER_INIT_HOOK,
+ EXTENSION_BEFORE_EDIT_ABOOK_HOOK,
+ EXTENSION_AFTER_EDIT_ABOOK_HOOK,
EXTENSION_BEFORE_OPEN_ABOOK_HOOK,
EXTENSION_AFTER_OPEN_ABOOK_HOOK,
EXTENSION_BEFORE_CLOSE_ABOOK_HOOK,
EXTENSION_AFTER_CLOSE_ABOOK_HOOK,
EXTENSION_BEFORE_DELETE_ABOOK_HOOK,
EXTENSION_AFTER_DELETE_ABOOK_HOOK,
+ /* Object will be searched address book (basic_search) */
EXTENSION_BEFORE_SEARCH_ABOOK_HOOK,
+ /* Object will be a GSList of found contact(s) */
EXTENSION_AFTER_SEARCH_ABOOK_HOOK,
EXTENSION_BEFORE_ADD_ABOOK_HOOK,
EXTENSION_AFTER_ADD_ABOOK_HOOK,
+ /* Object will be NULL */
EXTENSION_BEFORE_INIT_ABOOK_HOOK,
EXTENSION_AFTER_INIT_ABOOK_HOOK,
EXTENSION_BEFORE_OPEN_CONTACT_HOOK,
@@ -60,19 +69,116 @@
EXTENSION_AFTER_CLOSE_CONTACT_HOOK,
EXTENSION_BEFORE_DELETE_CONTACT_HOOK,
EXTENSION_AFTER_DELETE_CONTACT_HOOK,
+ /* Object will be a Contact containing search data */
EXTENSION_BEFORE_SEARCH_CONTACT_HOOK,
+ /* Object will be a GSList of found contact(s) */
EXTENSION_AFTER_SEARCH_CONTACT_HOOK,
EXTENSION_BEFORE_ADD_CONTACT_HOOK,
EXTENSION_AFTER_ADD_CONTACT_HOOK,
+ /* Object will be NULL */
EXTENSION_BEFORE_INIT_CONTACT_HOOK,
EXTENSION_AFTER_INIT_CONTACT_HOOK,
EXTENSION_HOOK_N
} ExtensionHook;
+typedef enum {
+ CONTACTS_NONE,
+ CONTACTS_MAIN_MENU,
+ CONTACTS_CONTACT_MENU,
+ CONTACTS_ADDRESSBOOK_MENU
+} ContactsMenu;
+
+typedef struct {
+ ContactsMenu menu;
+ gboolean submenu;
+ const gchar* parent;
+ const gchar* sublabel;
+/* GtkWidget* root;*/
+} MenuItem;
+
typedef void (*HOOKFUNC) (const MainWindow* mainwindow, gpointer object);
/* Any extension must implement these functions */
+/**
+ * The main application will call this function after loading the
+ * extension providing a uniq id for the extension which is to be
+ * used for further references
+ * @param id uniq id provided by main application
+ * @return 0 if success 1 otherwise
+ */
+gint extension_init(guint id);
+
+/**
+ * Called by main application when the extension should be unloaded
+ * @return TRUE if success FALSE otherwise
+ */
+gboolean extension_done(void);
+
+/**
+ * Called by main application to ensure extension license is compatible
+ * @return license
+ */
+const gchar* extension_license(void);
+
+/**
+ * Called by main application to get name of extension
+ * @return name
+ */
+const gchar* extension_name(void);
+
+/**
+ * Called by main application to get extension's describtion
+ * @return description
+ */
+const gchar* extension_describtion(void);
+
+/* Functions provided by claws-contacts */
+
+/**
+ * Extensions should call this function to register a callback hook
+ * @param id uniq id identifying the extension provided by the
+ * main application when extension_init was called
+ * @param hook_type what kind of hook to subscribe
+ * @param callback a pointer to the callback function
+ * @param error a place holder for error messages
+ * @return 0 if success 1 otherwise
+ */
+gint register_hook_function(guint id,
+ ExtensionHook hook_type,
+ HOOKFUNC callback,
+ gchar** error);
+
+/**
+ * Extensions should call this function to unregister a previous
+ * registred callback hook
+ * @param id uniq id identifying the extension provided by the
+ * main application when extension_init was called
+ * @param hook_type what kind of hook to unsubscribe
+ * @param error a place holder for error messages
+ */
+void unregister_hook_function(guint id,
+ ExtensionHook hook_type,
+ gchar** error);
+
+/**
+ * If an extension wants to add an new MenuItem to the application menu
+ * it can call this function. The predefined top-level menus 'File',
+ * 'Tools' and 'Help' is accessable to extensions. If parent is not
+ * found a new menu will be craeted with the name 'parent'
+ * @param id uniq id identifying the extension provided by the
+ * main application when extension_init was called
+ * @param image_menu GtkImageMenuItem
+ * @param menu_item 'Menu' to attach to. Do not free!
+ * @return TRUE if error FALSE otherwise
+ */
+/*
+gboolean add_menu_item(guint id, GtkImageMenuItem* image_menu, MenuItem* menu_item);
+*/
+MenuItem* menu_item_new(void);
+
+gboolean add_menu_item(GtkImageMenuItem* image_menu, MenuItem* menu_item);
+
G_END_DECLS
#endif
Index: mainwindow.c
===================================================================
RCS file: /home/claws-mail/contacts/src/mainwindow.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- mainwindow.c 30 Nov 2011 23:35:12 -0000 1.5
+++ mainwindow.c 9 Dec 2011 23:01:21 -0000 1.6
@@ -130,84 +130,82 @@
}
static void create_menu(MainWindow* mainwindow) {
- GtkAccelGroup* accel;
GtkWidget *item_space,
- *file_menu, *file, *file_quit, *file_plugin, *page_setup,
+ *file, *file_quit, *file_plugin, *page_setup,
*abook_menu, *abook, *abook_new, *abook_open,
*abook_delete, *abook_close, *abook_edit,
*contact_menu, *contact, *contact_new, *contact_edit,
- *contact_print, *contact_delete,
- *tools_menu, *tools, *tools_prefs, *tools_attribs,
- *help_menu, *help, *help_text, *help_about;
+ *contact_print, *contact_delete, *tools, *tools_prefs,
+ *tools_attribs, *help, *help_text, *help_about;
- accel = g_object_new(GTK_TYPE_ACCEL_GROUP, NULL);
- gtk_window_add_accel_group(GTK_WINDOW(mainwindow->window), accel);
+ mainwindow->accel = g_object_new(GTK_TYPE_ACCEL_GROUP, NULL);
+ gtk_window_add_accel_group(GTK_WINDOW(mainwindow->window), mainwindow->accel);
mainwindow->menu = gtk_menu_bar_new();
- file_menu = gtk_menu_new();
+ mainwindow->file_menu = gtk_menu_new();
file_plugin = gtk_image_menu_item_new_with_mnemonic("_Manage plugins");
- gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(file_plugin), accel);
- gtk_widget_add_accelerator(file_plugin, "activate", accel,
+ gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(file_plugin), mainwindow->accel);
+ gtk_widget_add_accelerator(file_plugin, "activate", mainwindow->accel,
GDK_M, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(file_plugin, "activate",
G_CALLBACK(file_plugin_cb), mainwindow);
- gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_plugin);
+ gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->file_menu), file_plugin);
page_setup = gtk_image_menu_item_new_with_mnemonic("_Page setup");
- gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(page_setup), accel);
- gtk_widget_add_accelerator(page_setup, "activate", accel,
+ gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(page_setup), mainwindow->accel);
+ gtk_widget_add_accelerator(page_setup, "activate", mainwindow->accel,
GDK_P, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(page_setup, "activate",
G_CALLBACK(printer_page_setup_cb), mainwindow);
- gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), page_setup);
+ gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->file_menu), page_setup);
item_space = gtk_separator_menu_item_new();
- gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), item_space);
+ gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->file_menu), item_space);
- file_quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel);
+ file_quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, mainwindow->accel);
g_signal_connect(file_quit, "activate", G_CALLBACK(menu_quit_cb), mainwindow);
- gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_quit);
+ gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->file_menu), file_quit);
file = gtk_menu_item_new_with_mnemonic("_File");
gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->menu), file);
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), file_menu);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), mainwindow->file_menu);
abook_menu = gtk_menu_new();
abook_new = gtk_image_menu_item_new_with_mnemonic("_New");
- gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(abook_new), accel);
- gtk_widget_add_accelerator(abook_new, "activate", accel,
+ gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(abook_new), mainwindow->accel);
+ gtk_widget_add_accelerator(abook_new, "activate", mainwindow->accel,
GDK_N, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(abook_new, "activate",
G_CALLBACK(abook_new_cb), mainwindow);
gtk_menu_shell_append(GTK_MENU_SHELL(abook_menu), abook_new);
- abook_edit = gtk_image_menu_item_new_from_stock(GTK_STOCK_EDIT, accel);
- gtk_widget_add_accelerator(abook_edit, "activate", accel,
+ abook_edit = gtk_image_menu_item_new_from_stock(GTK_STOCK_EDIT, mainwindow->accel);
+ gtk_widget_add_accelerator(abook_edit, "activate", mainwindow->accel,
GDK_E, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(abook_edit, "activate",
G_CALLBACK(abook_edit_cb), mainwindow);
gtk_menu_shell_append(GTK_MENU_SHELL(abook_menu), abook_edit);
abook_open = gtk_image_menu_item_new_with_mnemonic("_Open");
- gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(abook_open), accel);
- gtk_widget_add_accelerator(abook_open, "activate", accel,
+ gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(abook_open), mainwindow->accel);
+ gtk_widget_add_accelerator(abook_open, "activate", mainwindow->accel,
GDK_O, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(abook_open, "activate",
G_CALLBACK(abook_open_cb), mainwindow);
gtk_menu_shell_append(GTK_MENU_SHELL(abook_menu), abook_open);
abook_close = gtk_image_menu_item_new_with_mnemonic("_Close");
- gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(abook_close), accel);
- gtk_widget_add_accelerator(abook_close, "activate", accel,
+ gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(abook_close), mainwindow->accel);
+ gtk_widget_add_accelerator(abook_close, "activate", mainwindow->accel,
GDK_L, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(abook_close, "activate",
G_CALLBACK(abook_close_cb), mainwindow);
gtk_menu_shell_append(GTK_MENU_SHELL(abook_menu), abook_close);
- abook_delete = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, accel);
- gtk_widget_add_accelerator(abook_delete, "activate", accel,
+ abook_delete = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, mainwindow->accel);
+ gtk_widget_add_accelerator(abook_delete, "activate", mainwindow->accel,
GDK_D, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(abook_delete, "activate",
G_CALLBACK(abook_delete_cb), mainwindow);
@@ -220,30 +218,30 @@
contact_menu = gtk_menu_new();
contact_new = gtk_image_menu_item_new_with_mnemonic("_New");
- gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(contact_new), accel);
- gtk_widget_add_accelerator(contact_new, "activate", accel,
+ gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(contact_new), mainwindow->accel);
+ gtk_widget_add_accelerator(contact_new, "activate", mainwindow->accel,
GDK_N, GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(contact_new, "activate",
G_CALLBACK(contact_new_cb), mainwindow);
gtk_menu_shell_append(GTK_MENU_SHELL(contact_menu), contact_new);
- contact_edit = gtk_image_menu_item_new_from_stock(GTK_STOCK_EDIT, accel);
- gtk_widget_add_accelerator(contact_edit, "activate", accel,
+ contact_edit = gtk_image_menu_item_new_from_stock(GTK_STOCK_EDIT, mainwindow->accel);
+ gtk_widget_add_accelerator(contact_edit, "activate", mainwindow->accel,
GDK_E, GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(contact_edit, "activate",
G_CALLBACK(contact_edit_cb), mainwindow);
gtk_menu_shell_append(GTK_MENU_SHELL(contact_menu), contact_edit);
- contact_print = gtk_image_menu_item_new_from_stock(GTK_STOCK_PRINT, accel);
- gtk_widget_add_accelerator(contact_print, "activate", accel,
+ contact_print = gtk_image_menu_item_new_from_stock(GTK_STOCK_PRINT, mainwindow->accel);
+ gtk_widget_add_accelerator(contact_print, "activate", mainwindow->accel,
GDK_P, GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(contact_print, "activate",
G_CALLBACK(contact_print_prepare_cb), mainwindow);
gtk_menu_shell_append(GTK_MENU_SHELL(contact_menu), contact_print);
contact_delete = gtk_image_menu_item_new_from_stock(
- GTK_STOCK_DELETE, accel);
- gtk_widget_add_accelerator(contact_delete, "activate", accel,
+ GTK_STOCK_DELETE, mainwindow->accel);
+ gtk_widget_add_accelerator(contact_delete, "activate", mainwindow->accel,
GDK_D, GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(contact_delete, "activate",
G_CALLBACK(contact_delete_cb), mainwindow);
@@ -253,36 +251,36 @@
gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->menu), contact);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(contact), contact_menu);
- tools_menu = gtk_menu_new();
+ mainwindow->tools_menu = gtk_menu_new();
tools_prefs = gtk_image_menu_item_new_from_stock(
- GTK_STOCK_PREFERENCES, accel);
- gtk_widget_add_accelerator(tools_prefs, "activate", accel,
+ GTK_STOCK_PREFERENCES, mainwindow->accel);
+ gtk_widget_add_accelerator(tools_prefs, "activate", mainwindow->accel,
GDK_P, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(tools_prefs, "activate",
G_CALLBACK(tools_prefs_cb), mainwindow);
- gtk_menu_shell_append(GTK_MENU_SHELL(tools_menu), tools_prefs);
+ gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->tools_menu), tools_prefs);
tools_attribs = gtk_image_menu_item_new_with_mnemonic("_Attributes");
- gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(tools_attribs), accel);
- gtk_widget_add_accelerator(tools_attribs, "activate", accel,
+ gtk_image_menu_item_set_accel_group(GTK_IMAGE_MENU_ITEM(tools_attribs), mainwindow->accel);
+ gtk_widget_add_accelerator(tools_attribs, "activate", mainwindow->accel,
GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
g_signal_connect(tools_attribs, "activate",
G_CALLBACK(tools_attribs_cb), mainwindow);
- gtk_menu_shell_append(GTK_MENU_SHELL(tools_menu), tools_attribs);
+ gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->tools_menu), tools_attribs);
tools = gtk_menu_item_new_with_mnemonic("_Tools");
gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->menu), tools);
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(tools), tools_menu);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(tools), mainwindow->tools_menu);
- help_menu = gtk_menu_new();
- help_text = gtk_image_menu_item_new_from_stock(GTK_STOCK_HELP, accel);
- help_about = gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, accel);
- gtk_menu_shell_append(GTK_MENU_SHELL(help_menu), help_text);
- gtk_menu_shell_append(GTK_MENU_SHELL(help_menu), help_about);
+ mainwindow->help_menu = gtk_menu_new();
+ help_text = gtk_image_menu_item_new_from_stock(GTK_STOCK_HELP, mainwindow->accel);
+ help_about = gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, mainwindow->accel);
+ gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->help_menu), help_text);
+ gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->help_menu), help_about);
help = gtk_menu_item_new_with_mnemonic("_Help");
gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->menu), help);
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(help), help_menu);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(help), mainwindow->help_menu);
g_signal_connect(help_about, "activate",
G_CALLBACK(show_about), mainwindow);
g_signal_connect(help_text, "activate",
@@ -638,14 +636,19 @@
g_string_free(msg, TRUE);
}
-void application_start(gboolean compose, gboolean avoid_extensions) {
+void application_start(gboolean compose, gboolean no_extensions) {
MainWindow* mainwindow = g_new0(MainWindow, 1);
+ gchar* error;
mainwindow->compose_mode = compose;
+ mainwindow->use_extensions = ! no_extensions;
mainwindow_create(mainwindow);
- if (! avoid_extensions) {
+ if (mainwindow->use_extensions) {
+ debug_set_mode(TRUE);
init_hooks(mainwindow);
+ load_extensions(&error);
+ debug_set_mode(FALSE);
}
GList* pixmaps = load_pixmaps();
Index: Makefile.am
===================================================================
RCS file: /home/claws-mail/contacts/src/Makefile.am,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- Makefile.am 30 Nov 2011 23:35:12 -0000 1.3
+++ Makefile.am 9 Dec 2011 23:01:21 -0000 1.4
@@ -17,7 +17,7 @@
AM_CPPFLAGS = \
-DG_LOG_DOMAIN=\"Claws-Contacts\" \
-DPLUGINDIR=\"@PLUGINDIR@\" \
- -DEXTENSIONDIR=\"@EXTENSIONDIR@\" \
+ -DEXTENSIONDIR=\"@CLAWS_CONTACTS_EXTENSIONDIR@\" \
$(LIBGCRYPT_CFLAGS)
claws_contacts_SOURCES = \
@@ -38,7 +38,6 @@
printing.h \
settings.c \
settings.h \
- extension.c \
extension-loader.c \
extension-loader.h
Index: extension-loader.c
===================================================================
RCS file: /home/claws-mail/contacts/src/extension-loader.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- extension-loader.c 30 Nov 2011 23:35:12 -0000 1.1
+++ extension-loader.c 9 Dec 2011 23:01:21 -0000 1.2
@@ -35,38 +35,89 @@
#include <glib.h>
#include <glib/gi18n.h>
+#include <gtk/gtk.h>
#include "mainwindow.h"
#include "extension.h"
#include "extension-loader.h"
+#include "utils.h"
+#include "gtk-utils.h"
-static const GSList* active_hooks[EXTENSION_HOOK_N];
+static GSList* active_hooks[EXTENSION_HOOK_N];
+static GSList* user_menu_items = NULL;
+static GtkWidget* abook_context = NULL;
+static GtkWidget* contact_context = NULL;
+/* The number corresponts to the default number of GtkMenu - 1 */
+static guint menu_count = 4;
+/* The number corresponts to the default number of GtkMenu - separator and quit */
+static guint file_menu_count = 2;
+static GHashTable* extensions = NULL;
static const MainWindow* mainwindow = NULL;
-static gint NEXT_ID = 0;
+static guint NEXT_ID = 1;
+static const gchar* valid_license[] = {
+ "gpl3",
+ "gpl3+",
+ "gpl2+",
+ NULL
+};
-static gint next_id() {
- gint id = NEXT_ID;
+typedef struct {
+ guint id;
+ HOOKFUNC callback;
+ ExtensionHook type;
+} Callback;
+
+static guint next_id() {
+ guint id = NEXT_ID;
NEXT_ID++;
return id;
}
-Extension* extension_new(HOOKFUNC callback) {
+static Extension* extension_new(const gchar* filename) {
Extension* extension = g_new0(Extension, 1);
- extension->callback = callback;
+ extension->filename = g_strdup(filename);
extension->id = next_id();
return extension;
}
-void extension_free(void) {
+static gboolean compatible_license(Extension* extension) {
+ gboolean res = TRUE;
+ gchar* license;
+ gchar** valid = (gchar **) valid_license;
+
+ license = g_utf8_strdown(extension->license(), -1);
+ while(*valid && res) {
+ if (utf8_collate(license, *valid++) == 0)
+ res = FALSE;
+ }
+
+ g_free(license);
+ return res;
}
-gint install_hook_function(ExtensionHook hook_type,
- HOOKFUNC callback,
- gchar** error) {
+void extension_free(gpointer extension) {
+ Extension* ext = (Extension *) extension;
+ if (! ext)
+ return;
+
+ debug_print("%s: Unloading\n", ext->name ? ext->name() : ext->filename);
+ g_free(ext->filename);
+ if (ext->module) {
+ if (ext->done)
+ ext->done();
+ g_module_close(ext->module);
+ }
+ g_free(ext);
+}
+
+gint register_hook_function(guint id,
+ ExtensionHook hook_type,
+ HOOKFUNC callback,
+ gchar** error) {
gint result = 0;
- Extension* extension;
+ Callback* cb;
if (! callback) {
if (error)
@@ -74,35 +125,38 @@
return TRUE;
}
- extension = extension_new(callback);
- active_hooks[hook_type] = g_slist_prepend(active_hooks[hook_type], extension);
+ debug_print("Registrering hook function [%d]\n", id);
+ cb = g_new0(Callback, 1);
+ cb->id = id;
+ cb->callback = callback;
+ cb->type = hook_type;
+ active_hooks[hook_type] = g_slist_prepend(active_hooks[hook_type], cb);
return result;
}
-void uninstall_hook_function(gint id, gchar** error) {
- ExtensionHook i;
- Extension* ext = NULL;
+void unregister_hook_function(guint id,
+ ExtensionHook hook_type,
+ gchar** error) {
+ Callback* cb = NULL;
GSList* cur;
gboolean found = FALSE;
- for (i = EXTENSION_BEFORE_INIT_HOOK; i < EXTENSION_HOOK_N && ! ext; i++) {
- cur = active_hooks[i];
- while (cur && ! found) {
- ext = (Extension *) cur->data;
- if (ext && ext->id == id)
- found = TRUE;
- else {
- ext = NULL;
- cur = cur->next;
- }
+ cur = active_hooks[hook_type];
+ while (cur && ! found) {
+ cb = (Callback *) cur->data;
+ if (cb && cb->id == id)
+ found = TRUE;
+ else {
+ cb = NULL;
+ cur = cur->next;
}
}
- if (ext) {
- active_hooks[i] = g_slist_remove(active_hooks[i], ext);
- g_free(ext);
- ext = NULL;
+ if (cb) {
+ debug_print("Unregistrering hook function [%d]\n", cb->id);
+ active_hooks[hook_type] = g_slist_remove(active_hooks[hook_type], cb);
+ g_free(cb);
}
else {
if (error)
@@ -116,18 +170,418 @@
mainwindow = (const MainWindow *) main;
for (i = EXTENSION_BEFORE_INIT_HOOK; i < EXTENSION_HOOK_N; i++)
active_hooks[i] = NULL;
-
+ extensions = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, extension_free);
}
+void done_hooks() {
+ ExtensionHook i;
+ GSList* cur;
+
+ for (i = EXTENSION_BEFORE_INIT_HOOK; i < EXTENSION_HOOK_N; i++) {
+ cur = active_hooks[i];
+ while (cur) {
+ g_free(cur->data);
+ cur = cur->next;
+ }
+ g_slist_free(active_hooks[i]);
+ active_hooks[i] = NULL;
+ }
+
+}
+
void run_hook_callbacks(ExtensionHook hook, gpointer object) {
GSList* cur;
- if (! object)
+ if (! (EXTENSION_BEFORE_INIT_HOOK || EXTENSION_AFTER_INIT_HOOK) && ! object)
return;
-
+
for (cur = active_hooks[hook]; cur; cur = g_slist_next(cur)) {
- Extension* ext = (Extension *) cur->data;
- if (ext && ext->callback)
- ext->callback(mainwindow, object);
+ Callback* cb = (Callback *) cur->data;
+ if (cb && cb->callback)
+ cb->callback(mainwindow, object);
+ }
+}
+
+Extension* extension_load(const gchar* filename, gchar** error) {
+ Extension* extension;
+ gpointer extension_init, extension_done, extension_license,
+ extension_name, extension_describtion;
+
+ if (! filename) {
+ if (error)
+ *error = g_strdup(_("Missing filename"));
+ return NULL;
+ }
+
+ extension = extension_new(filename);
+
+ debug_print("trying to load `%s'\n", filename);
+ extension->module = g_module_open(filename, 0);
+ if (extension->module == NULL) {
+ if (error)
+ *error = g_strdup(g_module_error());
+ extension_free(extension);
+ return NULL;
+ }
+
+ if (!g_module_symbol(extension->module, "extension_init", &extension_init) ||
+ !g_module_symbol(extension->module, "extension_done", &extension_done) ||
+ !g_module_symbol(extension->module, "extension_name", &extension_name) ||
+ !g_module_symbol(extension->module, "extension_describtion", &extension_describtion) ||
+ !g_module_symbol(extension->module, "extension_license", &extension_license)) {
+ if (error)
+ *error = g_strdup(g_module_error());
+ extension_free(extension);
+ return NULL;
+ }
+
+ extension->init = extension_init;
+ extension->done = extension_done;
+ extension->license = extension_license;
+ extension->name = extension_name;
+ extension->describtion = extension_describtion;
+
+ if (compatible_license(extension)) {
+ if (error)
+ *error = g_strconcat(extension->license(), ": not compatible!", NULL);
+ extension_free(extension);
+ return NULL;
+ }
+
+ g_hash_table_replace(extensions, &extension->id, extension);
+
+ return extension;
+}
+
+void extension_unload(Extension** extension, gchar** error) {
+ if (! g_hash_table_remove(extensions, &(*extension)->id)) {
+ if (error)
+ *error = g_strdup(_("Extension was not found"));
+ }
+ else
+ *extension = NULL;
+}
+
+void extension_loader_done() {
+ done_hooks();
+ if (extensions) {
+ g_hash_table_destroy(extensions);
+ extensions = NULL;
+ }
+ mainwindow = NULL;
+ NEXT_ID = 1;
+
+ gslist_free(&user_menu_items, NULL);
+}
+
+static GSList* get_extension_path(gchar** error) {
+ GDir *ext_dir, *ext_sub_dir;
+ GError *err = NULL;
+ const gchar *filename, *ext_name;
+ gchar *path, *ext, *ext_file = NULL;
+ GSList* files = NULL;
+
+ ext_dir = g_dir_open(CLAWS_CONTACTS_EXTENSIONDIR, 0, &err);
+ if (err) {
+ g_warning("g_dir_open() failed: %s\n", err->message);
+ if (error)
+ *error = g_strdup(err->message);
+ g_clear_error(&err);
+ return NULL;
+ }
+ debug_print("Extension dir: %s\n", CLAWS_CONTACTS_EXTENSIONDIR);
+ if (EXTENSIONSUBDIR) {
+ while ((filename = g_dir_read_name(ext_dir))) {
+ g_free(ext_file);
+ ext_file = NULL;
+ path = g_build_filename(CLAWS_CONTACTS_EXTENSIONDIR, filename, NULL);
+ debug_print("Extension dir: %s\n", path);
+ if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
+ ext = g_build_filename(path, "src", ".libs", NULL);
+ ext_sub_dir = g_dir_open(ext, 0, &err);
+ if (err) {
+ g_free(ext);
+ g_clear_error(&err);
+ ext = g_build_filename(path, ".libs", NULL);
+ ext_sub_dir = g_dir_open(ext, 0, &err);
+ if (err) {
+ g_clear_error(&err);
+ continue;
+ }
+ }
+ while ((ext_name = g_dir_read_name(ext_sub_dir)) && ! ext_file) {
+ debug_print("Extension dir: %s\n", ext_name);
+ if (g_str_has_suffix(ext_name, G_MODULE_SUFFIX)) {
+ ext_file = g_build_filename(ext, ext_name, NULL);
+ }
+ }
+ g_dir_close(ext_sub_dir);
+ g_free(ext);
+ if (ext_file)
+ files = g_slist_append(files, g_strdup(ext_file));
+ g_free(ext_file);
+ ext_file = NULL;
+ }
+ g_free(path);
+ }
+ }
+ else {
+ while ((filename = g_dir_read_name(ext_dir))) {
+ if (g_str_has_suffix(filename, G_MODULE_SUFFIX)) {
+ debug_print("Extension dir: %s\n", path);
+ files = g_slist_append(files, g_strdup(filename));
+ }
+ }
+ }
+
+ g_dir_close(ext_dir);
+
+ return files;
+}
+
+void load_extensions(gchar** error) {
+ Extension* extension;
+ GSList *exts, *cur;
+
+ exts = get_extension_path(error);
+ for (cur = exts; cur; cur = g_slist_next(cur)) {
+ gchar* ext = (gchar *) cur->data;
+ extension = extension_load(ext, error);
+ if (extension) {
+ extension->init(extension->id);
+ debug_print("%s: Loaded\n", extension->name());
+ }
+ else
+ debug_print("%s: %s\n", ext, *error ? *error : "Unknown error");
+ }
+ gslist_free(&exts, g_free);
+}
+
+void unload_extensions() {
+ GHashTableIter iter;
+ gpointer key, value;
+ gchar* error = NULL;
+ GSList *exts = NULL, *cur;
+
+ if (extensions) {
+ g_hash_table_iter_init(&iter, extensions);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ exts = g_slist_prepend(exts, (Extension *) value);
+ }
+ cur = exts;
+ while (cur) {
+ Extension* extension = (Extension *) cur->data;
+ extension_unload(&extension, &error);
+ if (error) {
+ debug_print("%s\n", error);
+ }
+ g_free(error);
+ error = NULL;
+ cur = cur->next;
+ }
+ gslist_free(&exts, NULL);
+ }
+ extension_loader_done();
+}
+
+GtkWidget* get_menu_items(ContactsMenu menu) {
+ GtkWidget* widget = NULL;
+
+ switch (menu) {
+ case CONTACTS_ADDRESSBOOK_MENU:
+ widget = abook_context;
+ break;
+ case CONTACTS_CONTACT_MENU:
+ widget = contact_context;
+ break;
+ default:
+ break;
}
+
+ return widget;
+}
+
+static GtkWidget* create_menu_item(GtkWidget** widget, const gchar* label) {
+ GtkWidget* menu = NULL;
+
+ if (! *widget) {
+ menu = gtk_menu_new();
+ gtk_widget_show(menu);
+ gtk_menu_set_accel_group(GTK_MENU(menu), mainwindow->accel);
+ *widget = gtk_image_menu_item_new_with_mnemonic(label);
+ gtk_widget_show(*widget);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(*widget), menu);
+ }
+
+ return menu;
+}
+
+static GtkWidget* insert_sub_menu(GtkImageMenuItem* image_menu,
+ MenuItem* menu_item,
+ UserMenuItem* user_menu) {
+ GtkWidget *widget = NULL, *menu = NULL, *tmp;
+ GSList* cur;
+ gboolean force = FALSE;
+
+ if (menu_item->submenu) {
+ for (cur = user_menu_items; cur && ! menu; cur = g_slist_next(cur)) {
+ UserMenuItem* item = (UserMenuItem *) cur->data;
+ if (utf8_collate(item->parent, menu_item->parent) == 0) {
+ if (utf8_collate(item->sublabel, menu_item->sublabel) == 0 ||
+ utf8_collate(item->parent, item->sublabel) == 0) {
+ menu = item->menu;
+ if (utf8_collate(item->parent, item->sublabel) == 0)
+ force = TRUE;
+ }
+ }
+ }
+ if (! menu || force) {
+ if (force) {
+ tmp = create_menu_item(&widget, menu_item->sublabel);
+ gtk_menu_shell_append(GTK_MENU_SHELL(tmp), GTK_WIDGET(image_menu));
+ }
+ else
+ menu = create_menu_item(&widget, menu_item->sublabel);
+ user_menu->menu = (force)? tmp : menu;
+ user_menu->sublabel = menu_item->sublabel;
+ }
+ if (menu) {
+ if (force) {
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), widget);
+ widget = NULL;
+ }
+ else
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), GTK_WIDGET(image_menu));
+ }
+ }
+ else
+ widget = GTK_WIDGET(image_menu);
+
+ return widget;
+}
+
+MenuItem* menu_item_new(void) {
+ MenuItem* item;
+
+ item = g_new0(MenuItem, 1);
+
+ return item;
+}
+
+gboolean add_menu_item(GtkImageMenuItem* image_menu, MenuItem* menu_item) {
+ gboolean added = TRUE;
+ GtkWidget* menu_elem;
+ UserMenuItem* menu;
+
+ if (! mainwindow)
+ return added;
+
+ if (! menu_item || ! menu_item->parent) {
+ g_critical("Missing menu_item or menu_item invalid");
+ return added;
+ }
+
+ if (! GTK_IS_IMAGE_MENU_ITEM(image_menu)) {
+ g_critical("menu is not GtkImageMenuItem");
+ return added;
+ }
+
+ if (menu_item->submenu && ! menu_item->sublabel) {
+ g_critical("Submenu is missing label for widget");
+ return added;
+ }
+
+ debug_print("Inserting %s in menu\n", menu_item->parent);
+
+ menu = g_new0(UserMenuItem, 1);
+ gtk_widget_show(GTK_WIDGET(image_menu));
+ if (strcasecmp("file", menu_item->parent) == 0) {
+ // add to 'File'
+ menu_elem = insert_sub_menu(image_menu, menu_item, menu);
+ if (menu->sublabel && menu_item->parent)
+ menu->parent = menu_item->parent;
+ else {
+ g_free(menu);
+ menu = NULL;
+ }
+ gtk_menu_shell_insert(GTK_MENU_SHELL(mainwindow->file_menu),
+ menu_elem, file_menu_count);
+ file_menu_count++;
+ }
+ else if (strcasecmp("tools", menu_item->parent) == 0) {
+ // add to 'Tools'
+ menu_elem = insert_sub_menu(image_menu, menu_item, menu);
+ if (menu->sublabel && menu_item->parent)
+ menu->parent = menu_item->parent;
+ else {
+ g_free(menu);
+ menu = NULL;
+ }
+ gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->tools_menu), menu_elem);
+ }
+ else if (strcasecmp("help", menu_item->parent) == 0) {
+ // add to 'Help'
+ menu_elem = insert_sub_menu(image_menu, menu_item, menu);
+ if (menu->sublabel && menu_item->parent)
+ menu->parent = menu_item->parent;
+ else {
+ g_free(menu);
+ menu = NULL;
+ }
+ gtk_menu_shell_append(GTK_MENU_SHELL(mainwindow->help_menu), menu_elem);
+ }
+ else if (menu_item->menu == CONTACTS_MAIN_MENU) {
+ if (! menu_item->sublabel) {
+ menu_item->sublabel = menu_item->parent;
+ menu_item->submenu = TRUE;
+ }
+ menu_elem = insert_sub_menu(image_menu, menu_item, menu);
+ if (menu->sublabel && menu_item->parent)
+ menu->parent = menu_item->parent;
+ else {
+ g_free(menu);
+ menu = NULL;
+ }
+ if (menu_elem) {
+ gtk_menu_shell_insert(GTK_MENU_SHELL(mainwindow->menu), menu_elem, menu_count);
+ menu_count++;
+ }
+ }
+ else {
+ // context menu
+ if (menu_item->menu == CONTACTS_CONTACT_MENU) {
+ menu_elem = insert_sub_menu(image_menu, menu_item, menu);
+ if (menu->sublabel && menu_item->parent)
+ menu->parent = menu_item->parent;
+ else {
+ g_free(menu);
+ menu = NULL;
+ }
+ if (! contact_context)
+ contact_context = menu_elem;
+ else
+ gtk_menu_shell_append(GTK_MENU_SHELL(contact_context), menu_elem);
+ }
+ else if (menu_item->menu == CONTACTS_ADDRESSBOOK_MENU) {
+ menu_elem = insert_sub_menu(image_menu, menu_item, menu);
+ if (menu->sublabel && menu_item->parent)
+ menu->parent = menu_item->parent;
+ else {
+ g_free(menu);
+ menu = NULL;
+ }
+ if (! abook_context)
+ abook_context = menu_elem;
+ else
+ gtk_menu_shell_append(GTK_MENU_SHELL(abook_context), menu_elem);
+ }
+ else {
+ // error!!!!
+ }
+ }
+
+ if (menu)
+ user_menu_items = g_slist_prepend(user_menu_items, menu);
+
+ return added;
}
Index: callbacks.c
===================================================================
RCS file: /home/claws-mail/contacts/src/callbacks.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- callbacks.c 28 Nov 2011 21:45:28 -0000 1.13
+++ callbacks.c 9 Dec 2011 23:01:21 -0000 1.14
@@ -51,6 +51,8 @@
#include "printing.h"
#include "dbus-service.h"
#include "settings.h"
+#include "extension-loader.h"
+#include "extension.h"
#define PLUGINGROUP "loaded plugins"
@@ -155,6 +157,7 @@
debug_print("Unloading all plugins\n");
plugin_unload_all();
+ unload_extensions();
if (win) {
debug_print("Closing application\n");
@@ -230,7 +233,8 @@
*contact_print, *contact_delete;
GtkAccelGroup* accel;
const gchar* name = widget->name;
-
+ GtkWidget* context;
+
debug_print("Popup called from %s\n", name);
if (! (strcmp(name, "abook_list") == 0 ||
strcmp(name, "contact_list") == 0))
@@ -304,6 +308,12 @@
G_CALLBACK(abook_delete_cb), win);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), abook_delete);
}
+ /* Insert requested menu_items from extensions */
+ context = get_menu_items(CONTACTS_ADDRESSBOOK_MENU);
+ if (context) {
+ gtk_widget_unparent(context);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), g_object_ref(context));
+ }
}
else if (strcmp(name, "contact_list") == 0) {
if (new_row) {
@@ -349,11 +359,17 @@
G_CALLBACK(contact_delete_cb), win);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), contact_delete);
}
+ /* Insert requested menu_items from extensions */
+ context = get_menu_items(CONTACTS_CONTACT_MENU);
+ if (context) {
+ gtk_widget_unparent(context);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), g_object_ref(context));
+ }
}
else {
return;
}
-
+
gtk_widget_show_all(menu);
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, event_time);
}
@@ -421,6 +437,7 @@
}
}
+
config_get_value(config, PLUGINGROUP, "plugins", &plugins);
if (mainwindow) {
@@ -436,6 +453,10 @@
g_free(tmp);
}
}
+ if (mainwindow->use_extensions) {
+ debug_print("BEFORE_INIT_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_INIT_HOOK, NULL);
+ }
}
plugin_load_all(window, plugins);
@@ -443,8 +464,13 @@
gslist_free(&book, g_free);
g_free(configrc);
- if (mainwindow)
+ if (mainwindow) {
destroy_progress_dialog(mainwindow);
+ if (mainwindow->use_extensions) {
+ debug_print("AFTER_INIT_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_INIT_HOOK, NULL);
+ }
+ }
}
void list_view_clear(GtkTreeView* view, MainWindow* mainwindow) {
@@ -737,6 +763,10 @@
}
}
if (abook && plugin) {
+ if (win->use_extensions) {
+ debug_print("BEFORE_EDIT_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_EDIT_ABOOK_HOOK, abook);
+ }
new = address_book_copy(abook, TRUE);
address_book_contacts_free(new);
if (address_book_edit(win->window, plugin, &new)) {
@@ -765,6 +795,10 @@
update_abook_list(win);
win->selected_abook = NULL;
address_book_free(&abook);
+ if (win->use_extensions) {
+ debug_print("AFTER_EDIT_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_EDIT_ABOOK_HOOK, abook);
+ }
}
else {
address_book_free(&new);
@@ -804,6 +838,10 @@
}
plugin = get_selected_plugin(GTK_TREE_VIEW(win->abook_list));
if (abook && plugin) {
+ if (win->use_extensions) {
+ debug_print("BEFORE_DELETE_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_DELETE_ABOOK_HOOK, abook);
+ }
if (show_question(win->window, _("Remove '%s'?"), abook->abook_name)) {
plugin->abook_delete(abook, &error);
if (error) {
@@ -814,6 +852,10 @@
address_book_free(&abook);
update_abook_list(win);
}
+ if (win->use_extensions) {
+ debug_print("AFTER_DELETE_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_DELETE_ABOOK_HOOK, abook);
+ }
}
else {
show_message(win->window, GTK_UTIL_MESSAGE_INFO,
@@ -882,7 +924,11 @@
else
address_book_free(&book);
}
- if (book) {
+ if (book) {
+ if (win->use_extensions) {
+ debug_print("BEFORE_OPEN_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_OPEN_ABOOK_HOOK, book);
+ }
if (plugin->abook_open(book, &error))
update_abook_list(win);
if (error) {
@@ -890,6 +936,10 @@
g_free(error);
address_book_free(&book);
}
+ if (win->use_extensions) {
+ debug_print("AFTER_OPEN_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_OPEN_ABOOK_HOOK, book);
+ }
}
if (closed) {
for (cur = closed; cur; cur = g_list_next(cur)) {
@@ -930,10 +980,18 @@
}
plugin = get_selected_plugin(GTK_TREE_VIEW(win->abook_list));
if (abook && plugin) {
+ if (win->use_extensions) {
+ debug_print("BEFORE_CLOSE_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_CLOSE_ABOOK_HOOK, abook);
+ }
if (show_question(win->window, _("Close '%s' ?"), abook->abook_name)) {
plugin->abook_close(abook, &error);
update_abook_list(win);
}
+ if (win->use_extensions) {
+ debug_print("AFTER_CLOSE_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_CLOSE_ABOOK_HOOK, abook);
+ }
}
else {
show_message(win->window, GTK_UTIL_MESSAGE_INFO,
@@ -960,6 +1018,10 @@
if (response) {
plugin = plugin_get_plugin(plugin_name);
if (plugin) {
+ if (win->use_extensions) {
+ debug_print("BEFORE_INIT_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_INIT_ABOOK_HOOK, NULL);
+ }
if (address_book_edit(win->window, plugin, &book)) {
if (address_book_name_exists(plugin, book)) {
error = g_strdup_printf("%s: Name is in use!",
@@ -967,6 +1029,10 @@
address_book_free(&book);
goto error;
}
+ if (win->use_extensions) {
+ debug_print("AFTER_INIT_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_INIT_ABOOK_HOOK, book);
+ }
if (plugin->file_filter() && strcmp("xml", plugin->file_filter()) == 0 &&
g_file_test(book->URL, G_FILE_TEST_EXISTS)) {
AddressBook* abook =
@@ -991,12 +1057,20 @@
}
}
}
+ if (win->use_extensions) {
+ debug_print("BEFORE_ADD_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_ADD_ABOOK_HOOK, book);
+ }
if (! plugin->abook_set_config(book, NULL, &error)) {
if (plugin->abook_open(book, &error))
update_abook_list(win);
}
else
address_book_free(&book);
+ if (win->use_extensions) {
+ debug_print("AFTER_ADD_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_ADD_ABOOK_HOOK, book);
+ }
error:
if (error) {
show_message(win->window, GTK_UTIL_MESSAGE_WARNING, "%s", error);
@@ -1613,12 +1687,20 @@
g_free(p);
}
contact = get_selected_contact(tree_view);
+ if (win->use_extensions) {
+ debug_print("BEFORE_OPEN_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_OPEN_CONTACT_HOOK, contact);
+ }
contact_show(win, contact, &error);
if (error) {
show_message(win->window, GTK_UTIL_MESSAGE_ERROR, "%s", error);
g_free(error);
}
+ if (win->use_extensions) {
+ debug_print("AFTER_OPEN_ABOOK_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_OPEN_CONTACT_HOOK, contact);
+ }
}
void contact_cell_edited_cb(GtkCellRendererText *cell,
@@ -1786,7 +1868,12 @@
plugin = get_selected_plugin(view);
if (plugin && ! plugin->readonly) {
+ if (win->use_extensions) {
+ debug_print("BEFORE_INIT_CONTACT_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_INIT_CONTACT_HOOK, NULL);
+ }
contact_show(win, NULL, &error);
+ /* EXTENSION_AFTER_INIT_CONTACT_HOOK -> contactwindow->contact_update */
}
else
error = g_strdup(_("Plugin does not support updates"));
@@ -1881,10 +1968,18 @@
}
if (show_question(win->window,
_("Should contact '%s' be deleted?"), con_id ? con_id : "Unknown")) {
+ if (win->use_extensions) {
+ debug_print("BEFORE_DELETE_CONTACT_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_DELETE_CONTACT_HOOK, contact);
+ }
plugin->delete_contact(abook, contact, &error);
if (iter && !error) {
gtk_list_store_remove(GTK_LIST_STORE(model), iter);
abook->contacts = g_list_remove(abook->contacts, contact);
+ if (win->use_extensions) {
+ debug_print("BEFORE_DELETE_CONTACT_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_DELETE_CONTACT_HOOK, contact);
+ }
contact_free(contact);
g_free(contact);
}
@@ -2036,6 +2131,10 @@
plugin = get_selected_plugin(view);
if (abook && plugin) {
+ if (win->use_extensions) {
+ debug_print("BEFORE_SEARCH_CONTACT_HOOK\n");
+ run_hook_callbacks(EXTENSION_BEFORE_SEARCH_ABOOK_HOOK, abook);
+ }
contacts = plugin->get_contact(abook, search, &error);
g_free(search);
if (error) {
@@ -2043,6 +2142,10 @@
g_free(error);
}
else {
+ if (win->use_extensions) {
+ debug_print("AFTER_SEARCH_CONTACT_HOOK\n");
+ run_hook_callbacks(EXTENSION_AFTER_SEARCH_ABOOK_HOOK, contacts);
+ }
view = GTK_TREE_VIEW(win->contact_list);
list_view_clear(view, win);
for (cur = contacts; cur; cur = g_slist_next(cur)) {
@@ -2098,6 +2201,10 @@
g_free(error);
}
else if (contact) {
+ if (win->use_extensions) {
+ debug_print("BEFORE_SEARCH_CONTACT_HOOK (advanced)\n");
+ run_hook_callbacks(EXTENSION_BEFORE_SEARCH_CONTACT_HOOK, contact);
+ }
contacts = plugin->search_contact(abook, contact, is_and, &error);
if (error) {
show_message(win->window, GTK_UTIL_MESSAGE_WARNING, "%s", error);
@@ -2106,6 +2213,10 @@
else {
contact_free(contact);
g_free(contact);
+ if (win->use_extensions) {
+ debug_print("AFTER_SEARCH_CONTACT_HOOK (advanced)\n");
+ run_hook_callbacks(EXTENSION_AFTER_SEARCH_CONTACT_HOOK, contacts);
+ }
view = GTK_TREE_VIEW(win->contact_list);
list_view_clear(view, win);
for (cur = contacts; cur; cur = g_slist_next(cur)) {
Index: gtk-utils.c
===================================================================
RCS file: /home/claws-mail/contacts/src/gtk-utils.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- gtk-utils.c 4 Oct 2011 20:21:40 -0000 1.4
+++ gtk-utils.c 9 Dec 2011 23:01:21 -0000 1.5
@@ -298,7 +298,11 @@
gchar* reply = NULL;
GSList *cur, *choices = NULL;
- if (button_cb->remaining_attribs) {
+ if (button_cb->remaining_attribs && ! button_cb->remaining_attribs->data) {
+ show_message(button_cb->parent, GTK_MESSAGE_INFO,
+ "Plugin does not support user defined attributes");
+ }
+ else if (button_cb->remaining_attribs) {
for (cur = button_cb->remaining_attribs; cur; cur = g_slist_next(cur)) {
AttribDef* attr = (AttribDef *) cur->data;
choices = g_slist_prepend(choices, g_strdup(attr->attrib_name));
Index: extension-loader.h
===================================================================
RCS file: /home/claws-mail/contacts/src/extension-loader.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- extension-loader.h 30 Nov 2011 23:35:12 -0000 1.1
+++ extension-loader.h 9 Dec 2011 23:01:21 -0000 1.2
@@ -42,21 +42,31 @@
#include "mainwindow.h"
typedef struct {
- gint id;
- HOOKFUNC callback;
- gchar* parent;
- GtkWidget* menu_item;
+ gchar* filename;
+ guint id;
+ GModule* module;
+ gint (*init) (guint id);
+ gboolean (*done) (void);
+ const gchar* (*license) (void);
+ const gchar* (*name) (void);
+ const gchar* (*describtion) (void);
} Extension;
-Extension* extension_new(HOOKFUNC callback);
-void extension_free(void);
+typedef struct {
+ const gchar* parent;
+ const gchar* sublabel;
+ GtkWidget* menu;
+} UserMenuItem;
+
void init_hooks(MainWindow* main);
void run_hook_callbacks(ExtensionHook hook, gpointer object);
-gint install_hook_function(ExtensionHook hook_type,
- HOOKFUNC callback,
- gchar** error);
-void uninstall_hook_function(gint id, gchar** error);
-
+void done_hooks(void);
+Extension* extension_load(const gchar* filename, gchar** error);
+void extension_unload(Extension** extension, gchar** error);
+void extension_loader_done(void);
+void load_extensions(gchar** error);
+void unload_extensions(void);
+GtkWidget* get_menu_items(ContactsMenu menu);
G_END_DECLS
More information about the Commits
mailing list