From 51295ea2536067f9aaf8bddafa25840235109801 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Sun, 17 Feb 2013 16:51:05 +0100 Subject: [PATCH] Add and use -[OFObject performSelectorOnGLibThread:] --- src/gui/gtk/JubGtkHelper.h | 2 + src/gui/gtk/JubGtkHelper.m | 6 + src/gui/gtk/JubGtkRosterUI.m | 209 +++++++++++++++--------------- src/gui/gtk/Makefile | 3 +- src/gui/gtk/OFObject+GLibThread.h | 47 +++++++ src/gui/gtk/OFObject+GLibThread.m | 82 ++++++++++++ 6 files changed, 245 insertions(+), 104 deletions(-) create mode 100644 src/gui/gtk/OFObject+GLibThread.h create mode 100644 src/gui/gtk/OFObject+GLibThread.m diff --git a/src/gui/gtk/JubGtkHelper.h b/src/gui/gtk/JubGtkHelper.h index 1168620..54272cb 100644 --- a/src/gui/gtk/JubGtkHelper.h +++ b/src/gui/gtk/JubGtkHelper.h @@ -1 +1,3 @@ +#import "OFObject+GLibThread.h" + void g_idle_add_block(void (^block)(void)); diff --git a/src/gui/gtk/JubGtkHelper.m b/src/gui/gtk/JubGtkHelper.m index f282673..10018d2 100644 --- a/src/gui/gtk/JubGtkHelper.m +++ b/src/gui/gtk/JubGtkHelper.m @@ -3,6 +3,12 @@ #import "JubGtkHelper.h" +/* References for static linking */ +void _references_to_categories_of_OFObject(void) +{ + _OFObject_JubGlibThread_reference = 1; +} + static gboolean call_block(gpointer data) { void (^block)(void) = data; diff --git a/src/gui/gtk/JubGtkRosterUI.m b/src/gui/gtk/JubGtkRosterUI.m index a742ba3..227837d 100644 --- a/src/gui/gtk/JubGtkRosterUI.m +++ b/src/gui/gtk/JubGtkRosterUI.m @@ -156,114 +156,109 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model, - (void)Jub_addRosterItem: (XMPPRosterItem*)item group: (OFString*)group { - g_idle_add_block(^{ - GtkTreeIter group_iter, contact_iter; - GtkTreeRowReference *group_ref, *contact_ref; - GtkTreePath *group_path, *contact_path; - OFString *bareJID = [item.JID bareJID]; - OFMapTable *contactRows; - - if (!(contactRows = [_contactMap objectForKey: bareJID])) { - contactRows = [OFMapTable - mapTableWithKeyFunctions: keyFunctions - valueFunctions: rowRefFunctions]; - - [_contactMap setObject: contactRows - forKey: bareJID]; - } - - group_ref = [_groupMap valueForKey: group]; - - if (!group_ref) { - // Create new group row - gtk_tree_store_append(_roster_model, &group_iter, NULL); - gtk_tree_store_set(_roster_model, &group_iter, - 0, [group UTF8String], -1); - - group_path = gtk_tree_model_get_path(GTK_TREE_MODEL( - _roster_model), &group_iter); - - group_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL( - _roster_model), group_path); + GtkTreeIter group_iter, contact_iter; + GtkTreeRowReference *group_ref, *contact_ref; + GtkTreePath *group_path, *contact_path; + OFString *bareJID = [item.JID bareJID]; + OFMapTable *contactRows; + + if (!(contactRows = [_contactMap objectForKey: bareJID])) { + contactRows = [OFMapTable + mapTableWithKeyFunctions: keyFunctions + valueFunctions: rowRefFunctions]; + + [_contactMap setObject: contactRows + forKey: bareJID]; + } - [_groupMap setValue: group_ref - forKey: group]; - } else { - // Get iter for existing group row - group_path = gtk_tree_row_reference_get_path(group_ref); + group_ref = [_groupMap valueForKey: group]; - gtk_tree_model_get_iter(GTK_TREE_MODEL(_roster_model), - &group_iter, group_path); - } - gtk_tree_path_free(group_path); - - // Create new contact row - gtk_tree_store_append(_roster_model, &contact_iter, - &group_iter); - if (item.name) - gtk_tree_store_set(_roster_model, &contact_iter, - 0, [item.name UTF8String], - 1, [bareJID UTF8String], - 2, "unavailable", -1); - else if (item.JID.node) - gtk_tree_store_set(_roster_model, &contact_iter, - 0, [item.JID.node UTF8String], - 1, [bareJID UTF8String], - 2, "unavailable", -1); - else - gtk_tree_store_set(_roster_model, &contact_iter, - 0, [item.JID.domain UTF8String], - 1, [bareJID UTF8String], - 2, "unavailable", -1); + if (!group_ref) { + // Create new group row + gtk_tree_store_append(_roster_model, &group_iter, NULL); + gtk_tree_store_set(_roster_model, &group_iter, + 0, [group UTF8String], -1); - contact_path = gtk_tree_model_get_path(GTK_TREE_MODEL( - _roster_model), &contact_iter); + group_path = gtk_tree_model_get_path(GTK_TREE_MODEL( + _roster_model), &group_iter); - contact_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL( - _roster_model), contact_path); + group_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL( + _roster_model), group_path); - gtk_tree_path_free(contact_path); + [_groupMap setValue: group_ref + forKey: group]; + } else { + // Get iter for existing group row + group_path = gtk_tree_row_reference_get_path(group_ref); - [contactRows setValue: contact_ref - forKey: group]; - }); + gtk_tree_model_get_iter(GTK_TREE_MODEL(_roster_model), + &group_iter, group_path); + } + gtk_tree_path_free(group_path); + + // Create new contact row + gtk_tree_store_append(_roster_model, &contact_iter, &group_iter); + if (item.name) + gtk_tree_store_set(_roster_model, &contact_iter, + 0, [item.name UTF8String], + 1, [bareJID UTF8String], + 2, "unavailable", -1); + else if (item.JID.node) + gtk_tree_store_set(_roster_model, &contact_iter, + 0, [item.JID.node UTF8String], + 1, [bareJID UTF8String], + 2, "unavailable", -1); + else + gtk_tree_store_set(_roster_model, &contact_iter, + 0, [item.JID.domain UTF8String], + 1, [bareJID UTF8String], + 2, "unavailable", -1); + + contact_path = gtk_tree_model_get_path(GTK_TREE_MODEL(_roster_model), + &contact_iter); + + contact_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(_roster_model), + contact_path); + + gtk_tree_path_free(contact_path); + + [contactRows setValue: contact_ref + forKey: group]; } - (void)Jub_removeRosterItem: (XMPPRosterItem*)item group: (OFString*)group { - g_idle_add_block(^{ - GtkTreeIter contact_iter, group_iter; - GtkTreePath *contact_path, *group_path; - GtkTreeRowReference *contact_ref, *group_ref; - OFString *bareJID = [item.JID bareJID]; - OFMapTable *contactRows = [_contactMap objectForKey: bareJID]; - - contact_ref = [contactRows valueForKey: group]; - contact_path = gtk_tree_row_reference_get_path(contact_ref); - gtk_tree_model_get_iter(GTK_TREE_MODEL(_roster_model), - &contact_iter, contact_path); - gtk_tree_path_free(contact_path); - - gtk_tree_store_remove(_roster_model, &contact_iter); - - group_ref = [_groupMap valueForKey: group]; - group_path = gtk_tree_row_reference_get_path(group_ref); - gtk_tree_model_get_iter(GTK_TREE_MODEL(_roster_model), - &group_iter, group_path); - - if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL( - _roster_model), &group_iter)) { - gtk_tree_store_remove(_roster_model, &group_iter); - [_groupMap removeValueForKey: group]; - } + GtkTreeIter contact_iter, group_iter; + GtkTreePath *contact_path, *group_path; + GtkTreeRowReference *contact_ref, *group_ref; + OFString *bareJID = [item.JID bareJID]; + OFMapTable *contactRows = [_contactMap objectForKey: bareJID]; + + contact_ref = [contactRows valueForKey: group]; + contact_path = gtk_tree_row_reference_get_path(contact_ref); + gtk_tree_model_get_iter(GTK_TREE_MODEL(_roster_model), &contact_iter, + contact_path); + gtk_tree_path_free(contact_path); + + gtk_tree_store_remove(_roster_model, &contact_iter); + + group_ref = [_groupMap valueForKey: group]; + group_path = gtk_tree_row_reference_get_path(group_ref); + gtk_tree_model_get_iter(GTK_TREE_MODEL(_roster_model), &group_iter, + group_path); + + if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL(_roster_model), + &group_iter)) { + gtk_tree_store_remove(_roster_model, &group_iter); + [_groupMap removeValueForKey: group]; + } - gtk_tree_path_free(group_path); + gtk_tree_path_free(group_path); - [contactRows removeValueForKey: group]; - if([contactRows count] == 0) - [_contactMap removeObjectForKey: bareJID]; - }); + [contactRows removeValueForKey: group]; + if([contactRows count] == 0) + [_contactMap removeObjectForKey: bareJID]; } - (void)contactManager: (XMPPContactManager*)manager @@ -276,8 +271,10 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model, groups = @[ @"General" ]; for (OFString *group in groups) - [self Jub_addRosterItem: rosterItem - group: group]; + [self performSelectorOnGLibThread: @selector( + Jub_addRosterItem:group:) + withObject: rosterItem + withObject: group]; } - (void)contactManager: (XMPPContactManager*)manager @@ -290,8 +287,10 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model, groups = @[ @"General" ]; for (OFString *group in groups) - [self Jub_removeRosterItem: rosterItem - group: group]; + [self performSelectorOnGLibThread: @selector( + Jub_removeRosterItem:group:) + withObject: rosterItem + withObject: group]; } - (void)contact: (XMPPContact*)contact @@ -305,8 +304,10 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model, groups = @[ @"General" ]; for (OFString *group in groups) - [self Jub_removeRosterItem: oldItem - group: group]; + [self performSelectorOnGLibThread: @selector( + Jub_removeRosterItem:group:) + withObject: oldItem + withObject: group]; // Add contact to new set of groups groups = rosterItem.groups; @@ -315,8 +316,10 @@ static gboolean filter_roster_by_presence(GtkTreeModel *model, groups = @[ @"General" ]; for (OFString *group in groups) - [self Jub_addRosterItem: rosterItem - group: group]; + [self performSelectorOnGLibThread: @selector( + Jub_addRosterItem:group:) + withObject: rosterItem + withObject: group]; } - (void)contact: (XMPPContact*)contact diff --git a/src/gui/gtk/Makefile b/src/gui/gtk/Makefile index 90ff0ca..2f37ecd 100644 --- a/src/gui/gtk/Makefile +++ b/src/gui/gtk/Makefile @@ -3,7 +3,8 @@ SRCS = JubGtkUI.m \ JubGtkChatUI.m \ JubGtkRosterUI.m \ JubGtkHelper.m \ - JubGObjectMap.m + JubGObjectMap.m \ + OFObject+GLibThread.m include ../../../buildsys.mk diff --git a/src/gui/gtk/OFObject+GLibThread.h b/src/gui/gtk/OFObject+GLibThread.h new file mode 100644 index 0000000..00098af --- /dev/null +++ b/src/gui/gtk/OFObject+GLibThread.h @@ -0,0 +1,47 @@ +#import + +#ifdef __cplusplus +extern "C" { +#endif +extern int _OFObject_JubGlibThread_reference; +#ifdef __cplusplus +} +#endif + +/** + * @brief A category that provides methods for running selectors + * on the GLib Thread + */ +@interface OFObject (JubGLibThread) +/** + * @brief Performs the specified selector on the GLib thread. + * + * @param selector The selector to perform + */ +- (void)performSelectorOnGLibThread: (SEL)selector; + +/** + * @brief Performs the specified selector on the GLib thread with the specified + * object. + * + * @param selector The selector to perform + * @param object The object that is passed to the method specified by the + * selector + */ +- (void)performSelectorOnGLibThread: (SEL)selector + withObject: (id)object; + +/** + * @brief Performs the specified selector on the GLib thread with the specified + * objects. + * + * @param selector The selector to perform + * @param object1 The first object that is passed to the method specified by the + * selector + * @param object2 The second object that is passed to the method specified by + * the selector + */ +- (void)performSelectorOnGLibThread: (SEL)selector + withObject: (id)object1 + withObject: (id)object2; +@end diff --git a/src/gui/gtk/OFObject+GLibThread.m b/src/gui/gtk/OFObject+GLibThread.m new file mode 100644 index 0000000..4fe6bce --- /dev/null +++ b/src/gui/gtk/OFObject+GLibThread.m @@ -0,0 +1,82 @@ +#include + +#import "OFObject+GLibThread.h" + +int _OFObject_JubGlibThread_reference; + +struct params0 { + id object; + SEL selector; +}; + +struct params1 { + id object; + SEL selector; + id param; +}; + +struct params2 { + id object; + SEL selector; + id param1; + id param2; +}; + +static gboolean callback0(gpointer object) +{ + struct params0 *parm = object; + [parm->object performSelector: parm->selector]; + [parm->object freeMemory: parm]; + return FALSE; +} + +static gboolean callback1(gpointer object) +{ + struct params1 *parm = object; + [parm->object performSelector: parm->selector + withObject: parm->param]; + [parm->object freeMemory: parm]; + return FALSE; +} + +static gboolean callback2(gpointer object) +{ + struct params2 *parm = object; + [parm->object performSelector: parm->selector + withObject: parm->param1 + withObject: parm->param2]; + [parm->object freeMemory: parm]; + return FALSE; +} + +@implementation OFObject (JubGlibThread) +- (void)performSelectorOnGLibThread: (SEL)selector +{ + struct params0 *parm = [self allocMemoryWithSize: sizeof(*parm)]; + parm->object = self; + parm->selector = selector; + g_idle_add(callback0, parm); +} + +- (void)performSelectorOnGLibThread: (SEL)selector + withObject: (id)object +{ + struct params1 *parm = [self allocMemoryWithSize: sizeof(*parm)]; + parm->object = self; + parm->selector = selector; + parm->param = object; + g_idle_add(callback1, parm); +} + +- (void)performSelectorOnGLibThread: (SEL)selector + withObject: (id)object1 + withObject: (id)object2 +{ + struct params2 *parm = [self allocMemoryWithSize: sizeof(*parm)]; + parm->object = self; + parm->selector = selector; + parm->param1 = object1; + parm->param2 = object2; + g_idle_add(callback2, parm); +} +@end -- 2.39.2