diff options
author | Michael Zucci <zucchi@src.gnome.org> | 2001-10-17 03:13:31 +0800 |
---|---|---|
committer | Michael Zucci <zucchi@src.gnome.org> | 2001-10-17 03:13:31 +0800 |
commit | 8c85ed61ba64bd548460543dd87445b9a21dbf6a (patch) | |
tree | 76d2bc77eb83263b4d5b4122bf47127a1666214b | |
parent | e1d0f3dc45692a04dbd93c7ef82c24af74e05f25 (diff) | |
download | gsoc2013-evolution-8c85ed61ba64bd548460543dd87445b9a21dbf6a.tar.gz gsoc2013-evolution-8c85ed61ba64bd548460543dd87445b9a21dbf6a.tar.zst gsoc2013-evolution-8c85ed61ba64bd548460543dd87445b9a21dbf6a.zip |
Added an async_event handler to store_info. (mail_note_store): Setup async
* mail-folder-cache.c: Added an async_event handler to store_info.
(mail_note_store): Setup async event handler here.
(store_finalised): Flush out async events here.
(folder_changed): Use async event handler to emit event.
(mail_note_folder): Chagned, do most of the work in the calling
context, only do the corba stuff in main.
(store_folder_subscribed): Use async event, and do more work locally.
(store_folder_unsubscribed): Same.
(store_folder_deleted): Call store_folder_unsubscribed if we have
to do any work.
(store_folder_created): Call store_folder_subscribed if we have to
do any work.
(store_folder_unsubscribed): Ref store while busy.
(real_folder_deleted): And unref here.
(store_folder_subscribed): Reg store while busy.
(real_folder_created): Unref here.
(mail_note_folder): Ref folder while busy.
(real_note_folder): And unref here.
(mail_note_folder): Hook onto folder_deleted event.
(folder_deleted): Just mark this folder as no longer available.
* mail-session.c (register_timeout): Use mail_call_main instead of
proxy_event.
(remove_timeout): Same here.
* folder-browser.c (folder_changed): use the new mail_async_event
stuff.
(folder_changed_main): Remove old async event handling stuff.
(FOLDER_BROWSER_LOCK/UNLOCK): Removed.
(FolderBrowserPrivate): Removed too, sigh.
* mail-mt.c (mail_async_event_new, mail_async_event_emit,
mail_async_event_destroy): New functions to handle async events.
(mail_proxy_event, mail_proxy_event_id): Removed old functions for
async events.
(do_call): Add suport for MAIL_CALL_p_pp.
(mail_msg_free): Use mail_async_event instead of proxy_event.
* message-list.c (message_changed): Promote the message_changed to
a folder_changed and use main_folder_changed to process it.
(main_message_changed): Remove.d
(message_list_init): Setup async event handler.
(message_list_destroy): Remove async handler.
(folder_changed): Use async hanler to emit event in main loop.
(message_changed): Same.
svn path=/trunk/; revision=13698
-rw-r--r-- | mail/ChangeLog | 46 | ||||
-rw-r--r-- | mail/folder-browser.c | 94 | ||||
-rw-r--r-- | mail/folder-browser.h | 7 | ||||
-rw-r--r-- | mail/mail-folder-cache.c | 108 | ||||
-rw-r--r-- | mail/mail-mt.c | 68 | ||||
-rw-r--r-- | mail/mail-mt.h | 18 | ||||
-rw-r--r-- | mail/mail-session.c | 22 | ||||
-rw-r--r-- | mail/message-list.c | 27 | ||||
-rw-r--r-- | mail/message-list.h | 3 |
9 files changed, 224 insertions, 169 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index b2422fe53b..4b8eb79b34 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,5 +1,51 @@ 2001-10-16 <NotZed@Ximian.com> + * mail-folder-cache.c: Added an async_event handler to store_info. + (mail_note_store): Setup async event handler here. + (store_finalised): Flush out async events here. + (folder_changed): Use async event handler to emit event. + (mail_note_folder): Chagned, do most of the work in the calling + context, only do the corba stuff in main. + (store_folder_subscribed): Use async event, and do more work locally. + (store_folder_unsubscribed): Same. + (store_folder_deleted): Call store_folder_unsubscribed if we have + to do any work. + (store_folder_created): Call store_folder_subscribed if we have to + do any work. + (store_folder_unsubscribed): Ref store while busy. + (real_folder_deleted): And unref here. + (store_folder_subscribed): Reg store while busy. + (real_folder_created): Unref here. + (mail_note_folder): Ref folder while busy. + (real_note_folder): And unref here. + (mail_note_folder): Hook onto folder_deleted event. + (folder_deleted): Just mark this folder as no longer available. + + * mail-session.c (register_timeout): Use mail_call_main instead of + proxy_event. + (remove_timeout): Same here. + + * folder-browser.c (folder_changed): use the new mail_async_event + stuff. + (folder_changed_main): Remove old async event handling stuff. + (FOLDER_BROWSER_LOCK/UNLOCK): Removed. + (FolderBrowserPrivate): Removed too, sigh. + + * mail-mt.c (mail_async_event_new, mail_async_event_emit, + mail_async_event_destroy): New functions to handle async events. + (mail_proxy_event, mail_proxy_event_id): Removed old functions for + async events. + (do_call): Add suport for MAIL_CALL_p_pp. + (mail_msg_free): Use mail_async_event instead of proxy_event. + + * message-list.c (message_changed): Promote the message_changed to + a folder_changed and use main_folder_changed to process it. + (main_message_changed): Remove.d + (message_list_init): Setup async event handler. + (message_list_destroy): Remove async handler. + (folder_changed): Use async hanler to emit event in main loop. + (message_changed): Same. + * mail-mt.c (mail_proxy_event_id): New function to return the id of the currently executing proxied event. diff --git a/mail/folder-browser.c b/mail/folder-browser.c index bd0c4bbb2f..455542808f 100644 --- a/mail/folder-browser.c +++ b/mail/folder-browser.c @@ -58,18 +58,6 @@ #define d(x) - -typedef struct _FolderBrowserPrivate { - GMutex *lock; - - /* If we have outstanding tasks running */ - GSList *tasks; - GSList *tasks_done; -} FolderBrowserPrivate; - -#define FOLDER_BROWSER_LOCK(fb) g_mutex_lock(((FolderBrowser *)(fb))->priv->lock); -#define FOLDER_BROWSER_UNLOCK(fb) g_mutex_unlock(((FolderBrowser *)(fb))->priv->lock); - #define PARENT_TYPE (gtk_table_get_type ()) static void folder_changed(CamelObject *o, void *event_data, void *data); @@ -124,28 +112,8 @@ folder_browser_finalise (GtkObject *object) { FolderBrowser *folder_browser; CORBA_Environment ev; - FolderBrowserPrivate *p; folder_browser = FOLDER_BROWSER(object); - p = folder_browser->priv; - - /* This @#$#@ is to make sure we dont have any outstanding implicit - refs on us from outstanding async tasks */ - FOLDER_BROWSER_LOCK(folder_browser); - while (p->tasks) { - int id; - - id = (int)p->tasks->data; - FOLDER_BROWSER_UNLOCK(folder_browser); - mail_msg_wait(id); - FOLDER_BROWSER_LOCK(folder_browser); - } - /* the tasks_done list is just to avoid races, we can simply free it now */ - g_slist_free(p->tasks_done); - p->tasks_done = NULL; - FOLDER_BROWSER_UNLOCK(folder_browser); - - CORBA_exception_init (&ev); if (folder_browser->seen_id != 0) { gtk_timeout_remove (folder_browser->seen_id); @@ -156,7 +124,22 @@ folder_browser_finalise (GtkObject *object) gtk_timeout_remove(folder_browser->loading_id); folder_browser->loading_id = 0; } - + + /* wait for all outstanding async events against us */ + mail_async_event_destroy(folder_browser->async_event); + + if (folder_browser->folder) { + camel_object_unhook_event(CAMEL_OBJECT(folder_browser->folder), "folder_changed", + folder_changed, folder_browser); + camel_object_unhook_event(CAMEL_OBJECT(folder_browser->folder), "message_changed", + folder_changed, folder_browser); + mail_sync_folder (folder_browser->folder, NULL, NULL); + camel_object_unref (CAMEL_OBJECT (folder_browser->folder)); + folder_browser->folder = NULL; + } + + CORBA_exception_init (&ev); + if (folder_browser->search_full) gtk_object_unref (GTK_OBJECT (folder_browser->search_full)); @@ -179,15 +162,6 @@ folder_browser_finalise (GtkObject *object) g_free (folder_browser->uri); folder_browser->uri = NULL; - if (folder_browser->folder) { - camel_object_unhook_event(CAMEL_OBJECT(folder_browser->folder), "folder_changed", - folder_changed, folder_browser); - camel_object_unhook_event(CAMEL_OBJECT(folder_browser->folder), "message_changed", - folder_changed, folder_browser); - mail_sync_folder (folder_browser->folder, NULL, NULL); - camel_object_unref (CAMEL_OBJECT (folder_browser->folder)); - folder_browser->folder = NULL; - } CORBA_exception_free (&ev); @@ -207,9 +181,6 @@ folder_browser_finalise (GtkObject *object) if (folder_browser->clipboard_selection) g_byte_array_free (folder_browser->clipboard_selection, TRUE); - g_mutex_free(p->lock); - g_free(p); - folder_browser_parent_class->finalize(object); } @@ -821,43 +792,18 @@ update_status_bar(FolderBrowser *fb) static void main_folder_changed(CamelObject *o, void *event_data, void *data) { FolderBrowser *fb = data; - FolderBrowserPrivate *p = fb->priv; - int id; /* so some corba unref doesnt blow us away while we're busy */ gtk_object_ref((GtkObject *)fb); update_status_bar(fb); - - id = mail_proxy_event_id(); - if (id != -1) { - FOLDER_BROWSER_LOCK(fb); - if (g_slist_find(p->tasks, (void *)id)) - p->tasks = g_slist_remove(p->tasks, (void *)id); - else - p->tasks_done = g_slist_prepend(p->tasks_done, (void *)id); - FOLDER_BROWSER_UNLOCK(fb); - } gtk_object_unref((GtkObject *)fb); } static void folder_changed(CamelObject *o, void *event_data, void *data) { - int id; FolderBrowser *fb = data; - FolderBrowserPrivate *p = fb->priv; - - /* this snot is so we can implicitly and asynchronosly ref - the folder browser, since we can't actually ref it because - gtk_object_ref isn't threadsafe ... #@$@ */ - id = mail_proxy_event(main_folder_changed, o, event_data, data); - if (id != -1) { - FOLDER_BROWSER_LOCK(fb); - if (g_slist_find(p->tasks_done, (void *)id)) - p->tasks_done = g_slist_remove(p->tasks_done, (void *)id); - else - p->tasks = g_slist_prepend(p->tasks, (void *)id); - FOLDER_BROWSER_UNLOCK(fb); - } + + mail_async_event_emit(fb->async_event, main_folder_changed, o, NULL, data); } static void @@ -1966,10 +1912,8 @@ static void folder_browser_init (GtkObject *object) { FolderBrowser *fb = (FolderBrowser *)object; - FolderBrowserPrivate *p; - p = fb->priv = g_malloc0(sizeof(*fb->priv)); - p->lock = g_mutex_new(); + fb->async_event = mail_async_event_new(); } static void diff --git a/mail/folder-browser.h b/mail/folder-browser.h index fcedd9e352..68a678bf4d 100644 --- a/mail/folder-browser.h +++ b/mail/folder-browser.h @@ -17,7 +17,6 @@ #include "mail-types.h" #include "shell/Evolution.h" - #define FOLDER_BROWSER_TYPE (folder_browser_get_type ()) #define FOLDER_BROWSER(o) (GTK_CHECK_CAST ((o), FOLDER_BROWSER_TYPE, FolderBrowser)) #define FOLDER_BROWSER_CLASS(k) (GTK_CHECK_CLASS_CAST((k), FOLDER_BROWSER_TYPE, FolderBrowserClass)) @@ -36,8 +35,6 @@ typedef enum _FolderBrowserSelectionState { struct _FolderBrowser { GtkTable parent; - struct _FolderBrowserPrivate *priv; - BonoboPropertyBag *properties; GNOME_Evolution_Shell shell; @@ -83,8 +80,10 @@ struct _FolderBrowser { GtkWidget *invisible; GByteArray *clipboard_selection; -}; + /* for async events */ + struct _MailAsyncEvent *async_event; +}; typedef struct { GtkTableClass parent_class; diff --git a/mail/mail-folder-cache.c b/mail/mail-folder-cache.c index b1bf92bee0..ccff8f7555 100644 --- a/mail/mail-folder-cache.c +++ b/mail/mail-folder-cache.c @@ -70,6 +70,7 @@ struct _store_info { /* only 1 should be set */ EvolutionStorage *storage; GNOME_Evolution_Storage corba_storage; + MailAsyncEvent *async_event; }; static GHashTable *stores; @@ -195,9 +196,8 @@ folder_changed(CamelObject *o, gpointer event_data, gpointer user_data) return; d(printf("Fodler changed!\n")); - /* hopefully our mfi isn't lost while this is executing ... */ camel_object_ref((CamelObject *)o); - mail_proxy_event((CamelObjectEventHookFunc)real_folder_changed, o, NULL, mfi); + mail_async_event_emit(mfi->store_info->async_event, (CamelObjectEventHookFunc)real_folder_changed, o, NULL, mfi); } static void @@ -210,74 +210,90 @@ folder_finalised(CamelObject *o, gpointer event_data, gpointer user_data) } static void +folder_deleted(CamelObject *o, gpointer event_data, gpointer user_data) +{ + struct _folder_info *mfi = user_data; + + (printf("Folder deleted '%s'!\n", ((CamelFolder *)o)->full_name)); + mfi->folder = NULL; +} + +static void real_note_folder(CamelFolder *folder, void *event_data, void *data) { + struct _folder_info *mfi = event_data; + + update_1folder(mfi, NULL); + camel_object_unref((CamelObject *)folder); +} + +void mail_note_folder(CamelFolder *folder) +{ CamelStore *store = folder->parent_store; struct _store_info *si; struct _folder_info *mfi; + if (stores == NULL) { + g_warning("Adding a folder `%s' to a store which hasn't been added yet?\n", folder->full_name); + return; + } + LOCK(info_lock); si = g_hash_table_lookup(stores, store); - UNLOCK(info_lock); if (si == NULL) { g_warning("Adding a folder `%s' to a store %p which hasn't been added yet?\n", folder->full_name, store); - camel_object_unref((CamelObject *)folder); + UNLOCK(info_lock); return; } - LOCK(info_lock); mfi = g_hash_table_lookup(si->folders, folder->full_name); - UNLOCK(info_lock); - if (mfi == NULL) { g_warning("Adding a folder `%s' that I dont know about yet?", folder->full_name); - camel_object_unref((CamelObject *)folder); + UNLOCK(info_lock); return; } /* dont do anything if we already have this */ if (mfi->folder == folder) { - camel_object_unref (CAMEL_OBJECT (folder)); + UNLOCK(info_lock); return; } mfi->folder = folder; - update_1folder(mfi, NULL); camel_object_hook_event((CamelObject *)folder, "folder_changed", folder_changed, mfi); camel_object_hook_event((CamelObject *)folder, "message_changed", folder_changed, mfi); + camel_object_hook_event((CamelObject *)folder, "deleted", folder_deleted, mfi); camel_object_hook_event((CamelObject *)folder, "finalize", folder_finalised, mfi); - camel_object_unref((CamelObject *)folder); + camel_object_ref((CamelObject *)folder); + + UNLOCK(info_lock); + + mail_async_event_emit(si->async_event, (CamelObjectEventHookFunc)real_note_folder, (CamelObject *)folder, (void *)mfi, NULL); } -void mail_note_folder(CamelFolder *folder) +static void +real_folder_created(CamelStore *store, struct _store_info *si, CamelFolderInfo *fi) { - if (stores == NULL) { - g_warning("Adding a folder `%s' to a store which hasn't been added yet?\n", folder->full_name); - return; - } - - camel_object_ref((CamelObject *)folder); - mail_proxy_event((CamelObjectEventHookFunc)real_note_folder, (CamelObject *)folder, NULL, NULL); + setup_folder(fi, si); + camel_object_unref((CamelObject *)store); } static void -real_folder_created(CamelStore *store, void *event_data, CamelFolderInfo *fi) +store_folder_subscribed(CamelObject *o, void *event_data, void *data) { struct _store_info *si; - d(printf("real_folder_created: %s (%s)\n", fi->full_name, fi->url)); - LOCK(info_lock); - si = g_hash_table_lookup(stores, store); + si = g_hash_table_lookup(stores, o); + if (si) + camel_object_ref(o); UNLOCK(info_lock); + if (si) - setup_folder(fi, si); - else - /* leaks, so what */ - g_warning("real_folder_created: can't find store: %s\n", - camel_url_to_string(((CamelService *)store)->url, 0)); + mail_async_event_emit(si->async_event, + (CamelObjectEventHookFunc)real_folder_created, o, si, event_data); } static void @@ -285,14 +301,9 @@ store_folder_created(CamelObject *o, void *event_data, void *data) { /* we only want created events to do more work if we dont support subscriptions */ if (!camel_store_supports_subscriptions(CAMEL_STORE(o))) - mail_msg_wait(mail_proxy_event((CamelObjectEventHookFunc)real_folder_created, o, NULL, event_data)); + store_folder_subscribed(o, event_data, data); } -static void -store_folder_subscribed(CamelObject *o, void *event_data, void *data) -{ - mail_msg_wait(mail_proxy_event((CamelObjectEventHookFunc)real_folder_created, o, NULL, event_data)); -} static void real_folder_deleted(CamelStore *store, void *event_data, CamelFolderInfo *fi) @@ -301,22 +312,35 @@ real_folder_deleted(CamelStore *store, void *event_data, CamelFolderInfo *fi) if (strstr(fi->url, ";noselect") == NULL) mail_vfolder_remove_uri(store, fi->url); + + camel_object_unref((CamelObject *)store); } static void -store_folder_deleted(CamelObject *o, void *event_data, void *data) +store_folder_unsubscribed(CamelObject *o, void *event_data, void *data) { - /* we only want deleted events to do more work if we dont support subscriptions */ - if (!camel_store_supports_subscriptions(CAMEL_STORE(o))) - mail_msg_wait(mail_proxy_event((CamelObjectEventHookFunc)real_folder_deleted, o, NULL, event_data)); + struct _store_info *si; + + LOCK(info_lock); + si = g_hash_table_lookup(stores, o); + if (si) + camel_object_ref(o); + UNLOCK(info_lock); + + if (si) + mail_async_event_emit(si->async_event, + (CamelObjectEventHookFunc)real_folder_deleted, o, si, event_data); } static void -store_folder_unsubscribed(CamelObject *o, void *event_data, void *data) +store_folder_deleted(CamelObject *o, void *event_data, void *data) { - mail_msg_wait(mail_proxy_event((CamelObjectEventHookFunc)real_folder_deleted, o, NULL, event_data)); + /* we only want deleted events to do more work if we dont support subscriptions */ + if (!camel_store_supports_subscriptions(CAMEL_STORE(o))) + store_folder_unsubscribed(o, event_data, data); } + static void free_folder_info(char *path, struct _folder_info *info, void *data) { @@ -336,6 +360,9 @@ store_finalised(CamelObject *o, void *event_data, void *data) si = g_hash_table_lookup(stores, store); if (si) { g_hash_table_remove(stores, store); + UNLOCK(info_lock); + mail_async_event_destroy(si->async_event); + LOCK(info_lock); g_hash_table_foreach(si->folders, (GHFunc)free_folder_info, NULL); g_hash_table_destroy(si->folders); g_free(si); @@ -408,6 +435,7 @@ mail_note_store(CamelStore *store, EvolutionStorage *storage, GNOME_Evolution_St si->corba_storage = corba_storage; si->store = store; g_hash_table_insert(stores, store, si); + si->async_event = mail_async_event_new(); camel_object_hook_event((CamelObject *)store, "folder_created", store_folder_created, NULL); camel_object_hook_event((CamelObject *)store, "folder_deleted", store_folder_deleted, NULL); diff --git a/mail/mail-mt.c b/mail/mail-mt.c index 0892688853..cf64485d85 100644 --- a/mail/mail-mt.c +++ b/mail/mail-mt.c @@ -69,6 +69,8 @@ static pthread_cond_t mail_msg_cond = PTHREAD_COND_INITIALIZER; pthread_t mail_gui_thread; +MailAsyncEvent *mail_async_event; + static void mail_msg_destroy(EThread *e, EMsg *msg, void *data); void *mail_msg_new(mail_msg_op_t *ops, EMsgPort *reply_port, size_t size) @@ -184,7 +186,7 @@ void mail_msg_free(void *msg) g_free(m); if (activity) - mail_proxy_event(destroy_objects, NULL, activity, NULL); + mail_async_event_emit(mail_async_event, destroy_objects, NULL, activity, NULL); } /* hash table of ops->dialogue of active errors */ @@ -473,6 +475,8 @@ void mail_msg_init(void) mail_msg_active = g_hash_table_new(NULL, NULL); mail_gui_thread = pthread_self(); + + mail_async_event = mail_async_event_new(); } /* ********************************************************************** */ @@ -764,65 +768,88 @@ mail_user_message (const char *type, const char *prompt, gboolean allow_cancel) struct _proxy_msg { struct _mail_msg msg; + MailAsyncEvent *ea; CamelObjectEventHookFunc func; CamelObject *o; void *event_data; void *data; }; -static int mail_proxy_event_current = -1; - static void -do_proxy_event(struct _mail_msg *mm) +do_async_event(struct _mail_msg *mm) { struct _proxy_msg *m = (struct _proxy_msg *)mm; - mail_proxy_event_current = mm->seq; m->func(m->o, m->event_data, m->data); - mail_proxy_event_current = -1; + + g_mutex_lock(m->ea->lock); + m->ea->tasks = g_slist_remove(m->ea->tasks, (void *)mm->seq); + g_mutex_unlock(m->ea->lock); + } -struct _mail_msg_op proxy_event_op = { +struct _mail_msg_op async_event_op = { NULL, - do_proxy_event, + do_async_event, NULL, NULL, }; -/* returns the current id of the executing proxy event */ -int mail_proxy_event_id(void) +MailAsyncEvent *mail_async_event_new(void) { - return mail_proxy_event_current; + MailAsyncEvent *ea; + + ea = g_malloc0(sizeof(*ea)); + ea->lock = g_mutex_new(); + + return ea; } -int mail_proxy_event(CamelObjectEventHookFunc func, CamelObject *o, void *event_data, void *data) +int mail_async_event_emit(MailAsyncEvent *ea, CamelObjectEventHookFunc func, CamelObject *o, void *event_data, void *data) { struct _proxy_msg *m; int id; int ismain = pthread_self() == mail_gui_thread; if (ismain) { - /* save the current id incase we're proxying an event in a proxied event */ - id = mail_proxy_event_current; - mail_proxy_event_current = -1; func(o, event_data, data); - mail_proxy_event_current = id; /* id of -1 is 'always finished' */ return -1; } else { /* we dont have a reply port for this, we dont care when/if it gets executed, just queue it */ - m = mail_msg_new(&proxy_event_op, NULL, sizeof(*m)); + m = mail_msg_new(&async_event_op, NULL, sizeof(*m)); m->func = func; m->o = o; m->event_data = event_data; m->data = data; - + m->ea = ea; + id = m->msg.seq; + g_mutex_lock(ea->lock); + ea->tasks = g_slist_prepend(ea->tasks, (void *)id); + g_mutex_unlock(ea->lock); e_msgport_put(mail_gui_port, (EMsg *)m); return id; } } +void mail_async_event_destroy(MailAsyncEvent *ea) +{ + int id; + + g_mutex_lock(ea->lock); + while (ea->tasks) { + id = (int)ea->tasks->data; + g_mutex_unlock(ea->lock); + mail_msg_wait(id); + g_mutex_lock(ea->lock); + } + g_mutex_unlock(ea->lock); + + g_mutex_free(ea->lock); + g_free(ea); +} + /* ********************************************************************** */ struct _call_msg { @@ -846,6 +873,11 @@ do_call(struct _mail_msg *mm) p1 = va_arg(ap, void *); m->ret = m->func(p1); break; + case MAIL_CALL_p_pp: + p1 = va_arg(ap, void *); + p2 = va_arg(ap, void *); + m->ret = m->func(p1, p2); + break; case MAIL_CALL_p_ppp: p1 = va_arg(ap, void *); p2 = va_arg(ap, void *); diff --git a/mail/mail-mt.h b/mail/mail-mt.h index 057de1ddb0..e3aebab7c5 100644 --- a/mail/mail-mt.h +++ b/mail/mail-mt.h @@ -68,14 +68,23 @@ char *mail_get_password (CamelService *service, const char *prompt, */ gboolean mail_user_message (const char *type, const char *prompt, gboolean allow_cancel); +/* asynchronous event proxies */ +typedef struct _MailAsyncEvent { + GMutex *lock; + GSList *tasks; +} MailAsyncEvent; + +/* create a new async event handler */ +MailAsyncEvent *mail_async_event_new(void); /* forward a camel event (or other call) to the gui thread */ -int mail_proxy_event(CamelObjectEventHookFunc func, CamelObject *o, void *event_data, void *data); -/* in main (only), get the current event id */ -int mail_proxy_event_id(void); +int mail_async_event_emit(MailAsyncEvent *ea, CamelObjectEventHookFunc func, CamelObject *o, void *event_data, void *data); +/* wait for all outstanding async events to complete */ +void mail_async_event_destroy(MailAsyncEvent *ea); /* Call a function in the gui thread, wait for it to return, type is the marshaller to use */ typedef enum { MAIL_CALL_p_p, + MAIL_CALL_p_pp, MAIL_CALL_p_ppp, MAIL_CALL_p_pppp, MAIL_CALL_p_ppippp, @@ -98,5 +107,8 @@ extern EThread *mail_thread_queued_slow; /* for operations that can (or should) /* The main thread. */ extern pthread_t mail_gui_thread; +/* A generic proxy event for anything that can be proxied during the life of the mailer (almost nothing) */ +/* Note that almost all objects care about the lifecycle of their events, so this cannot be used */ +extern MailAsyncEvent *mail_async_event; #endif /* ! _MAIL_MT */ diff --git a/mail/mail-session.c b/mail/mail-session.c index bf8d5560c3..0101845f74 100644 --- a/mail/mail-session.c +++ b/mail/mail-session.c @@ -271,19 +271,11 @@ camel_timeout (gpointer data) } static void -do_register_timeout(CamelObject *o, void *edata, void *data) +main_register_timeout(struct _timeout_data *td) { - struct _timeout_data *td = (struct _timeout_data *)edata; - td->result = gtk_timeout_add_full(td->interval, camel_timeout, NULL, td, g_free); } -static void -do_remove_timeout(CamelObject *o, void *edata, void *data) -{ - gtk_timeout_remove(*((int *)edata)); -} - static guint register_timeout (CamelSession *session, guint32 interval, CamelTimeoutCallback cb, gpointer camel_data) { @@ -298,7 +290,7 @@ register_timeout (CamelSession *session, guint32 interval, CamelTimeoutCallback g_warning("Timeout %u too small, increased to 1000", interval); interval = 1000; } - + /* This is extremely messy, we need to proxy to gtk thread for this */ td = g_malloc (sizeof (*td)); td->interval = interval; @@ -306,7 +298,7 @@ register_timeout (CamelSession *session, guint32 interval, CamelTimeoutCallback td->cb = cb; td->camel_data = camel_data; - mail_msg_wait(mail_proxy_event(do_register_timeout, (CamelObject *)session, td, NULL)); + mail_call_main(MAIL_CALL_p_p, (MailMainFunc)main_register_timeout, td); if (td->result == 0) { g_free(td); @@ -316,10 +308,16 @@ register_timeout (CamelSession *session, guint32 interval, CamelTimeoutCallback return td->result; } +static void +main_remove_timeout(guint *edata) +{ + gtk_timeout_remove(*edata); +} + static gboolean remove_timeout (CamelSession *session, guint handle) { - mail_msg_wait(mail_proxy_event(do_remove_timeout, (CamelObject *)session, &handle, NULL)); + mail_call_main(MAIL_CALL_p_p, (MailMainFunc)main_remove_timeout, &handle); return TRUE; } diff --git a/mail/message-list.c b/mail/message-list.c index fdb6e912c7..2cb0f081c2 100644 --- a/mail/message-list.c +++ b/mail/message-list.c @@ -1120,6 +1120,7 @@ message_list_init (GtkObject *object) message_list->hide_lock = g_mutex_new(); message_list->uid_nodemap = g_hash_table_new (g_str_hash, g_str_equal); + message_list->async_event = mail_async_event_new(); } static void @@ -1127,6 +1128,8 @@ message_list_destroy (GtkObject *object) { MessageList *message_list = MESSAGE_LIST (object); + mail_async_event_destroy(message_list->async_event); + if (message_list->folder) { save_tree_state(message_list); hide_save_state(message_list); @@ -1868,9 +1871,8 @@ main_folder_changed (CamelObject *o, gpointer event_data, gpointer user_data) static void folder_changed (CamelObject *o, gpointer event_data, gpointer user_data) { - /* similarly to message_changed, copy the change list and propagate it to - the main thread and free it */ CamelFolderChangeInfo *changes; + MessageList *ml = MESSAGE_LIST (user_data); if (event_data) { changes = camel_folder_change_info_new(); @@ -1878,29 +1880,20 @@ folder_changed (CamelObject *o, gpointer event_data, gpointer user_data) } else { changes = NULL; } - mail_proxy_event (main_folder_changed, o, changes, user_data); + + mail_async_event_emit(ml->async_event, main_folder_changed, o, changes, user_data); } static void -main_message_changed (CamelObject *o, gpointer uid, gpointer user_data) +message_changed (CamelObject *o, gpointer event_data, gpointer user_data) { - MessageList *ml = MESSAGE_LIST (user_data); CamelFolderChangeInfo *changes; + MessageList *ml = MESSAGE_LIST (user_data); changes = camel_folder_change_info_new(); - camel_folder_change_info_change_uid(changes, uid); - main_folder_changed(o, changes, ml); - g_free(uid); -} + camel_folder_change_info_change_uid(changes, (char *)event_data); -static void -message_changed (CamelObject *o, gpointer event_data, gpointer user_data) -{ - /* Here we copy the data because our thread may free the copy that we would reference. - * The other thread would be passed a uid parameter that pointed to freed data. - * We copy it and free it in the handler. - */ - mail_proxy_event (main_message_changed, o, g_strdup ((gchar *)event_data), user_data); + mail_async_event_emit(ml->async_event, main_folder_changed, o, changes, user_data); } void diff --git a/mail/message-list.h b/mail/message-list.h index 380d57d46d..2846c04ec4 100644 --- a/mail/message-list.h +++ b/mail/message-list.h @@ -81,6 +81,9 @@ struct _MessageList { /* locks */ GMutex *hide_lock; /* for any 'hide' info above */ + + /* for message/folder chagned event handling */ + struct _MailAsyncEvent *async_event; }; typedef struct { |