# HG changeset patch # User Sadrul Habib Chowdhury # Date 1210437066 0 # Node ID 6c4f47b9d2016cabb661abac84d3320feacc142f # Parent cb0759d9fe30d0f26c3f3570c474748cee00c47d Make PurpleSmiley a GObject. Removed some functions from the API that are not really necessary, including purple_smileys_add and purple_smileys_remove. They are called automatically when a new smiley is created or removed. PurpleSmiley has a 'destroy' signal, and 'shortcut' and 'image' properties. These might be of interest to UIs. diff -r cb0759d9fe30 -r 6c4f47b9d201 libpurple/smiley.c --- a/libpurple/smiley.c Wed May 07 18:53:13 2008 +0000 +++ b/libpurple/smiley.c Sat May 10 16:31:06 2008 +0000 @@ -31,19 +31,24 @@ #include "smiley.h" #include "util.h" - /**************************************************************************/ /* Main structures, members and constants */ /**************************************************************************/ struct _PurpleSmiley { - PurpleStoredImage *img; /**< The id of the stored image with the - the smiley data. */ - char *shortcut; /**< Shortcut associated with the custom - smiley. This field will work as a - unique key by this API. */ - char *checksum; /**< The smiley checksum. */ + GObject parent; + PurpleStoredImage *img; /**< The id of the stored image with the + the smiley data. */ + char *shortcut; /**< Shortcut associated with the custom + smiley. This field will work as a + unique key by this API. */ + char *checksum; /**< The smiley checksum. */ +}; + +struct _PurpleSmileyClass +{ + GObjectClass parent_class; }; static GHashTable *smiley_shortcut_index = NULL; /* shortcut (char *) => smiley (PurpleSmiley*) */ @@ -115,6 +120,11 @@ purple_smiley_set_data_impl(PurpleSmiley *smiley, guchar *smiley_data, size_t smiley_data_len, const char *filename); +static void +purple_smiley_data_store(PurpleStoredImage *stored_img); + +static void +purple_smiley_data_unstore(const char *filename); /********************************************************************* * Writing to disk * @@ -264,17 +274,174 @@ PurpleSmiley *smiley; smiley = parse_smiley(smiley_node); - - purple_smileys_add(smiley); } } xmlnode_free(root_node); } +/********************************************************************* + * GObject Stuff * + *********************************************************************/ +enum +{ + PROP_0, + PROP_SHORTCUT, + PROP_IMGSTORE, +}; + +#define PROP_SHORTCUT_S "shortcut" +#define PROP_IMGSTORE_S "image" + +enum +{ + SIG_DESTROY, + SIG_LAST +}; + +static guint signals[SIG_LAST]; + +static void +purple_smiley_init(GTypeInstance *instance, gpointer klass) +{ +} + +static void +purple_smiley_get_property(GObject *object, guint param_id, GValue *value, + GParamSpec *spec) +{ + PurpleSmiley *smiley = PURPLE_SMILEY(object); + switch (param_id) { + case PROP_SHORTCUT: + g_value_set_string(value, smiley->shortcut); + break; + case PROP_IMGSTORE: + g_value_set_pointer(value, smiley->img); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, spec); + break; + } +} + +static void +purple_smiley_set_property(GObject *object, guint param_id, const GValue *value, + GParamSpec *spec) +{ + PurpleSmiley *smiley = PURPLE_SMILEY(object); + switch (param_id) { + case PROP_SHORTCUT: + { + const char *shortcut = g_value_get_string(value); + purple_smiley_set_shortcut(smiley, shortcut); + } + break; + case PROP_IMGSTORE: + { + PurpleStoredImage *img = g_value_get_pointer(value); + + purple_imgstore_unref(smiley->img); + g_free(smiley->checksum); + + smiley->img = img; + if (img) { + smiley->checksum = purple_util_get_image_checksum( + purple_imgstore_get_data(img), + purple_imgstore_get_size(img)); + purple_smiley_data_store(img); + } else { + smiley->checksum = NULL; + } + + g_object_notify(object, PROP_IMGSTORE_S); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, spec); + break; + } +} + +static void +purple_smiley_finalize(GObject *obj) +{ + PurpleSmiley *smiley = PURPLE_SMILEY(obj); + g_signal_emit(obj, signals[SIG_DESTROY], 0); + + if (g_hash_table_lookup(smiley_shortcut_index, smiley->shortcut)) { + g_hash_table_remove(smiley_shortcut_index, smiley->shortcut); + g_hash_table_remove(smiley_checksum_index, smiley->checksum); + } + + g_free(smiley->shortcut); + g_free(smiley->checksum); + if (smiley->img) + purple_smiley_data_unstore(purple_imgstore_get_filename(smiley->img)); + purple_imgstore_unref(smiley->img); + + purple_smileys_save(); +} + +static void +purple_smiley_class_init(PurpleSmileyClass *klass) +{ + GObjectClass *gobj_class = G_OBJECT_CLASS(klass); + GParamSpec *pspec; + + gobj_class->get_property = purple_smiley_get_property; + gobj_class->set_property = purple_smiley_set_property; + gobj_class->finalize = purple_smiley_finalize; + + /* Shortcut */ + pspec = g_param_spec_string(PROP_SHORTCUT_S, _("Shortcut"), + _("The text-shortcut for the smiley"), + NULL, + G_PARAM_READWRITE); + g_object_class_install_property(gobj_class, PROP_SHORTCUT, pspec); + + /* Stored Image */ + pspec = g_param_spec_pointer(PROP_IMGSTORE_S, _("Stored Image"), + _("Stored Image. (that'll have to do for now)"), + G_PARAM_READWRITE); + g_object_class_install_property(gobj_class, PROP_IMGSTORE, pspec); + + signals[SIG_DESTROY] = g_signal_new("destroy", + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +GType +purple_smiley_get_type(void) +{ + static GType type = 0; + + if(type == 0) { + static const GTypeInfo info = { + sizeof(PurpleSmileyClass), + NULL, + NULL, + (GClassInitFunc)purple_smiley_class_init, + NULL, + NULL, + sizeof(PurpleSmiley), + 0, + purple_smiley_init, + NULL, + }; + + type = g_type_register_static(G_TYPE_OBJECT, + "PurpleSmiley", + &info, 0); + } + + return type; +} /********************************************************************* - * Stuff * + * Other Stuff * *********************************************************************/ static char *get_file_full_path(const char *filename) @@ -437,7 +604,7 @@ purple_smiley_set_data_impl(PurpleSmiley *smiley, guchar *smiley_data, size_t smiley_data_len, const char *filename) { - PurpleStoredImage *old_img; + PurpleStoredImage *old_img, *new_img; const char *old_filename = NULL; const char *new_filename = NULL; @@ -446,23 +613,19 @@ g_return_if_fail(smiley_data_len > 0); old_img = smiley->img; - smiley->img = NULL; if (filename) - smiley->img = purple_imgstore_add(smiley_data, - smiley_data_len, filename); + new_img = purple_imgstore_add(smiley_data, smiley_data_len, filename); else - smiley->img = purple_smiley_data_new(smiley_data, smiley_data_len); + new_img = purple_smiley_data_new(smiley_data, smiley_data_len); - g_free(smiley->checksum); - smiley->checksum = purple_util_get_image_checksum( - smiley_data, smiley_data_len); + g_object_set(G_OBJECT(smiley), PROP_IMGSTORE_S, new_img, NULL); + /* If the old and new image files have different names we need + * to unstore old image file. */ if (!old_img) return; - /* If the old and new image files have different names we need - * to unstore old image file. */ old_filename = purple_imgstore_get_filename(old_img); new_filename = purple_imgstore_get_filename(smiley->img); @@ -482,27 +645,11 @@ { PurpleSmiley *smiley; - smiley = g_slice_new0(PurpleSmiley); - if (!smiley) - return NULL; - - smiley->shortcut = g_strdup(shortcut); + smiley = PURPLE_SMILEY(g_object_new(PURPLE_TYPE_SMILEY, PROP_SHORTCUT_S, shortcut, NULL)); return smiley; } -static void -purple_smiley_destroy(PurpleSmiley *smiley) -{ - g_return_if_fail(smiley != NULL); - - g_free(smiley->shortcut); - g_free(smiley->checksum); - purple_imgstore_unref(smiley->img); - - g_slice_free(PurpleSmiley, smiley); -} - PurpleSmiley * purple_smiley_new(PurpleStoredImage *img, const char *shortcut) { @@ -519,17 +666,12 @@ if (!smiley) return NULL; - smiley->checksum = purple_util_get_image_checksum( - purple_imgstore_get_data(img), - purple_imgstore_get_size(img)); - - smiley->img = img; - purple_smiley_data_store(img); + g_object_set(G_OBJECT(smiley), PROP_IMGSTORE_S, img, NULL); return smiley; } -PurpleSmiley * +static PurpleSmiley * purple_smiley_new_from_stream(const char *shortcut, guchar *smiley_data, size_t smiley_data_len, const char *filename) { @@ -580,11 +722,7 @@ { g_return_if_fail(smiley != NULL); - purple_smileys_remove(smiley); - if (smiley->img) - purple_smiley_data_unstore(purple_imgstore_get_filename(smiley->img)); - - purple_smiley_destroy(smiley); + g_object_unref(smiley); } gboolean @@ -598,7 +736,8 @@ return FALSE; /* Remove the old shortcut. */ - g_hash_table_remove(smiley_shortcut_index, smiley->shortcut); + if (smiley->shortcut) + g_hash_table_remove(smiley_shortcut_index, smiley->shortcut); /* Insert the new shortcut. */ g_hash_table_insert(smiley_shortcut_index, g_strdup(shortcut), smiley); @@ -606,6 +745,8 @@ g_free(smiley->shortcut); smiley->shortcut = g_strdup(shortcut); + g_object_notify(G_OBJECT(smiley), PROP_SHORTCUT_S); + purple_smileys_save(); return TRUE; @@ -710,32 +851,6 @@ return returninglist; } -void -purple_smileys_add(PurpleSmiley *smiley) -{ - g_return_if_fail(smiley != NULL); - - if (!g_hash_table_lookup(smiley_shortcut_index, smiley->shortcut)) { - g_hash_table_insert(smiley_shortcut_index, g_strdup(smiley->shortcut), smiley); - g_hash_table_insert(smiley_checksum_index, g_strdup(smiley->checksum), smiley); - - purple_smileys_save(); - } -} - -void -purple_smileys_remove(PurpleSmiley *smiley) -{ - g_return_if_fail(smiley != NULL); - - if (g_hash_table_lookup(smiley_shortcut_index, smiley->shortcut)) { - g_hash_table_remove(smiley_shortcut_index, smiley->shortcut); - g_hash_table_remove(smiley_checksum_index, smiley->checksum); - - purple_smileys_save(); - } -} - PurpleSmiley * purple_smileys_find_by_shortcut(const char *shortcut) { diff -r cb0759d9fe30 -r 6c4f47b9d201 libpurple/smiley.h --- a/libpurple/smiley.h Wed May 07 18:53:13 2008 +0000 +++ b/libpurple/smiley.h Sat May 10 16:31:06 2008 +0000 @@ -1,5 +1,5 @@ /** - * @file Smiley.h Smiley API + * @file smiley.h Smiley API * @ingroup core */ @@ -28,6 +28,8 @@ #ifndef _PURPLE_SMILEY_H_ #define _PURPLE_SMILEY_H_ +#include + #include "imgstore.h" #include "util.h" @@ -35,8 +37,18 @@ * A custom smiley. * This contains everything Purple will ever need to know about a custom smiley. * Everything. + * + * PurpleSmiley is a GObject. */ -typedef struct _PurpleSmiley PurpleSmiley; +typedef struct _PurpleSmiley PurpleSmiley; +typedef struct _PurpleSmileyClass PurpleSmileyClass; + +#define PURPLE_TYPE_SMILEY (purple_smiley_get_type ()) +#define PURPLE_SMILEY(smiley) (G_TYPE_CHECK_INSTANCE_CAST ((smiley), PURPLE_TYPE_SMILEY, PurpleSmiley)) +#define PURPLE_SMILEY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PURPLE_TYPE_SMILEY, PurpleSmileyClass)) +#define PURPLE_IS_SMILEY(smiley) (G_TYPE_CHECK_INSTANCE_TYPE ((smiley), PURPLE_TYPE_SMILEY)) +#define PURPLE_IS_SMILEY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PURPLE_TYPE_SMILEY)) +#define PURPLE_SMILEY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PURPLE_TYPE_SMILEY, PurpleSmileyClass)) #ifdef __cplusplus extern "C" { @@ -48,6 +60,12 @@ /*@{*/ /** + * GObject foo. + * @internal. + */ +GType purple_smiley_get_type(void); + +/** * Creates a new custom smiley structure and populates it. * * If a custom smiley with the informed shortcut already exist, it @@ -64,22 +82,6 @@ /** * Creates a new custom smiley structure and populates it. * - * If a custom smiley with the informed shortcut already exist, it - * will be automaticaly returned. - * - * @param shortcut The custom smiley associated shortcut. - * @param smiley_data The custom smiley data. - * @param smiley_data_len The custom smiley data length. - * - * @return The custom smiley structure filled up. - */ -PurpleSmiley * -purple_smiley_new_from_stream(const char *shortcut, guchar *smiley_data, - size_t smiley_data_len, const char *filename); - -/** - * Creates a new custom smiley structure and populates it. - * * The data is retrieved from an already existent file. * * If a custom smiley with the informed shortcut already exist, it @@ -118,7 +120,7 @@ * Changes the custom smiley's data. * * When the filename controling is made outside this API, the param - * @keepfilename must be TRUE. + * #keepfilename must be TRUE. * Otherwise, the file and filename will be regenerated, and the * old one will be removed. * @@ -204,7 +206,7 @@ /**************************************************************************/ -/** @name Custom Smiley Subsistem API */ +/** @name Custom Smiley Subsystem API */ /**************************************************************************/ /*@{*/ @@ -217,24 +219,6 @@ purple_smileys_get_all(void); /** - * Adds the custom smiley to the library persistence. - * - * @param smiley The custom smiley. - * - */ -void -purple_smileys_add(PurpleSmiley *smiley); - -/** - * Remove the custom smiley from persistence. - * - * @param smiley The custom smiley. - * - */ -void -purple_smileys_remove(PurpleSmiley *smiley); - -/** * Returns the custom smiley given it's shortcut. * * @param shortcut The custom smiley's shortcut. diff -r cb0759d9fe30 -r 6c4f47b9d201 pidgin/gtksmiley.c --- a/pidgin/gtksmiley.c Wed May 07 18:53:13 2008 +0000 +++ b/pidgin/gtksmiley.c Sat May 10 16:31:06 2008 +0000 @@ -76,6 +76,7 @@ /****************************************************************************** * GtkIMHtmlSmileys stuff *****************************************************************************/ +/* Perhaps these should be in gtkimhtml.c instead. -- sadrul */ static void add_gtkimhtml_to_list(GtkIMHtmlSmiley *gtksmiley) { gtk_smileys = g_slist_prepend(gtk_smileys, gtksmiley); @@ -83,7 +84,13 @@ purple_debug_info("gtksmiley", "adding %s to gtk_smileys\n", gtksmiley->smile); } -/* Perhaps this should be in gtkimhtml.c instead. -- sad */ +static void +shortcut_changed_cb(PurpleSmiley *smiley, gpointer dontcare, GtkIMHtmlSmiley *gtksmiley) +{ + g_free(gtksmiley->smile); + gtksmiley->smile = g_strdup(purple_smiley_get_shortcut(smiley)); +} + static GtkIMHtmlSmiley *smiley_purple_to_gtkimhtml(PurpleSmiley *smiley) { GtkIMHtmlSmiley *gtksmiley; @@ -92,21 +99,17 @@ file = purple_imgstore_get_filename(purple_smiley_get_stored_image(smiley)); - filename = g_build_filename(purple_smileys_get_storing_dir(),file, NULL); + filename = g_build_filename(purple_smileys_get_storing_dir(), file, NULL); gtksmiley = gtk_imhtml_smiley_create(filename, purple_smiley_get_shortcut(smiley), FALSE, GTK_IMHTML_SMILEY_CUSTOM); g_free(filename); - return gtksmiley; -} + /* Make sure the shortcut for the GtkIMHtmlSmiley is updated with the PurpleSmiley */ + g_signal_connect(G_OBJECT(smiley), "notify::shortcut", + G_CALLBACK(shortcut_changed_cb), gtksmiley); -void pidgin_smiley_add_to_list(PurpleSmiley *smiley) -{ - GtkIMHtmlSmiley *gtksmiley; - - gtksmiley = smiley_purple_to_gtkimhtml(smiley); - add_gtkimhtml_to_list(gtksmiley); + return gtksmiley; } void pidgin_smiley_del_from_list(PurpleSmiley *smiley) @@ -126,6 +129,8 @@ continue; gtk_imhtml_smiley_destroy(gtksmiley); + g_signal_handlers_disconnect_matched(G_OBJECT(smiley), G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, gtksmiley); break; } @@ -133,6 +138,15 @@ gtk_smileys = g_slist_delete_link(gtk_smileys, list); } +void pidgin_smiley_add_to_list(PurpleSmiley *smiley) +{ + GtkIMHtmlSmiley *gtksmiley; + + gtksmiley = smiley_purple_to_gtkimhtml(smiley); + add_gtkimhtml_to_list(gtksmiley); + g_signal_connect(G_OBJECT(smiley), "destroy", G_CALLBACK(pidgin_smiley_del_from_list), NULL); +} + void pidgin_smileys_init(void) { GList *smileys; @@ -224,7 +238,6 @@ purple_debug_info("gtksmiley", "adding a new smiley\n"); emoticon = purple_smiley_new_from_file(entry, s->filename); - purple_smileys_add(emoticon); if (gtk_smileys != NULL) pidgin_smiley_add_to_list(emoticon); } @@ -371,36 +384,45 @@ static void delete_foreach(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { - PurpleSmiley *smiley; - char *shortcut; + PurpleSmiley *smiley = NULL; SmileyManager *dialog; dialog = (SmileyManager*)data; gtk_tree_model_get(model, iter, - SHORTCUT, &shortcut, + SMILEY, &smiley, -1); - purple_debug_info("gtksmiley", "delete_foreach shortcut = %s\n", shortcut); - - smiley = purple_smileys_find_by_shortcut(shortcut); - - if(smiley == NULL) - purple_debug_error("gtksmiley", "%s not found\n", shortcut); - else { + if(smiley != NULL) { + g_object_unref(G_OBJECT(smiley)); pidgin_smiley_del_from_list(smiley); purple_smiley_delete(smiley); } +} - g_free(shortcut); +static void append_to_list(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + GList **list = data; + *list = g_list_prepend(*list, gtk_tree_path_copy(path)); } static void smiley_delete(SmileyManager *dialog) { GtkTreeSelection *selection; + GList *list = NULL; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview)); gtk_tree_selection_selected_foreach(selection, delete_foreach, dialog); + gtk_tree_selection_selected_foreach(selection, append_to_list, &list); + + while (list) { + GtkTreeIter iter; + if (gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, list->data)) + gtk_list_store_remove(GTK_LIST_STORE(dialog->model), &iter); + gtk_tree_path_free(list->data); + list = g_list_delete_link(list, list); + } } /****************************************************************************** * The Smiley Manager @@ -499,6 +521,7 @@ gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path); gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, SMILEY, &smiley, -1); pidgin_smiley_edit(gtk_widget_get_toplevel(GTK_WIDGET(treeview)), smiley); + g_object_unref(G_OBJECT(smiley)); } static GtkWidget *smiley_list_create(SmileyManager *dialog) @@ -519,7 +542,7 @@ dialog->model = gtk_list_store_new(N_COL, GDK_TYPE_PIXBUF, /* ICON */ G_TYPE_STRING, /* SHORTCUT */ - G_TYPE_POINTER /* SMILEY */ + G_TYPE_OBJECT /* SMILEY */ ); /* the actual treeview */ @@ -557,7 +580,6 @@ break; case GTK_RESPONSE_NO: smiley_delete(dialog); - refresh_list(); break; case GTK_RESPONSE_DELETE_EVENT: case GTK_RESPONSE_CLOSE: