diff --git a/gnoemoe/mcp/gm-mcp-icecrew-userlist.c b/gnoemoe/mcp/gm-mcp-icecrew-userlist.c index 6836eb6..57f8cc7 100644 --- a/gnoemoe/mcp/gm-mcp-icecrew-userlist.c +++ b/gnoemoe/mcp/gm-mcp-icecrew-userlist.c @@ -5,6 +5,7 @@ #include #include "gm-mcp-icecrew-userlist.h" +#include "gm-iuserlist.h" #include "gm-mcp-userlist-view.h" #include "gm-mcp-icecrew-playerdb.h" #include "gm-mcp-session.h" @@ -50,6 +51,8 @@ struct _GmMcpIcecrewUserlistPrivate { gchar *rank_dir; gchar *state_dir; + GList *menu; + gboolean initializing; }; @@ -73,9 +76,12 @@ enum { NUM_SIGNALS }; +static void gm_mcp_icecrew_userlist_iface_init(GmIUserlistInterface *iface); static guint gm_mcp_icecrew_userlist_signals[NUM_SIGNALS] = {0}; -G_DEFINE_TYPE(GmMcpIcecrewUserlist, gm_mcp_icecrew_userlist, GM_TYPE_MCP_PACKAGE) +G_DEFINE_TYPE_EXTENDED(GmMcpIcecrewUserlist, gm_mcp_icecrew_userlist, \ + GM_TYPE_MCP_PACKAGE, 0, G_IMPLEMENT_INTERFACE(GM_TYPE_IUSERLIST, \ + gm_mcp_icecrew_userlist_iface_init)) void on_gm_mcp_icecrew_userlist_add(GmMcpIcecrewPlayerdb *playerdb, GmPlayerdbPlayerInfo *ppi, GmMcpIcecrewUserlist *userlist); @@ -100,6 +106,14 @@ void gm_mcp_icecrew_userlist_create_view(GmMcpPackage *package, void gm_mcp_icecrew_userlist_fetch_progress(GmFetchHandle *g, GmMcpIcecrewUserlist *package); +GList *gm_mcp_icecrew_userlist_get_menu(GmIUserlist *userlist, gint id); + +static void +gm_mcp_icecrew_userlist_iface_init( + GmIUserlistInterface *iface) { + iface->get_menu = gm_mcp_icecrew_userlist_get_menu; +} + void gm_mcp_icecrew_userlist_pair_free(GmKeyValuePair *pair) { g_free(pair->key); @@ -118,6 +132,12 @@ gm_mcp_icecrew_userlist_free_list(GList *rs) { g_list_free(rs); } +static void +gm_mcp_icecrew_userlist_free_menu(GmMcpIcecrewUserlist *obj) { + gm_mcp_icecrew_userlist_free_list(obj->priv->menu); + obj->priv->menu = NULL; +} + static void gm_mcp_icecrew_userlist_finalize(GObject *object) { GmMcpIcecrewUserlist *obj = GM_MCP_ICECREW_USERLIST(object); @@ -132,14 +152,7 @@ gm_mcp_icecrew_userlist_finalize(GObject *object) { g_signal_handlers_disconnect_by_func(playerdb, on_gm_mcp_icecrew_userlist_delete, obj); } - - gm_mcp_icecrew_userlist_free_list(obj->priv->state_icons); - gm_mcp_icecrew_userlist_free_list(obj->priv->rank_icons); - gm_mcp_icecrew_userlist_free_list(obj->priv->key_datatags); - - g_free(obj->priv->rank_dir); - g_free(obj->priv->state_dir); - + if (obj->priv->rank_fetch) { obj->priv->rank_fetch->aborted = TRUE; } @@ -147,6 +160,16 @@ gm_mcp_icecrew_userlist_finalize(GObject *object) { if (obj->priv->state_fetch) { obj->priv->state_fetch->aborted = TRUE; } + + gm_mcp_icecrew_userlist_free_list(obj->priv->state_icons); + gm_mcp_icecrew_userlist_free_list(obj->priv->rank_icons); + gm_mcp_icecrew_userlist_free_list(obj->priv->key_datatags); + gm_mcp_icecrew_userlist_free_menu(obj); + gm_mcp_icecrew_userlist_free_list(obj->priv->rank_alternatives); + gm_mcp_icecrew_userlist_free_list(obj->priv->state_alternatives); + + g_free(obj->priv->rank_dir); + g_free(obj->priv->state_dir); G_OBJECT_CLASS(gm_mcp_icecrew_userlist_parent_class)->finalize(object); } @@ -682,28 +705,18 @@ void gm_mcp_icecrew_userlist_fetch_progress(GmFetchHandle *g, GmMcpIcecrewUserlist *package) { gchar *path; - gboolean rank = (package->priv->rank_fetch == g); + gboolean rank; GdkPixbuf *pixtest; GError *err = NULL; - if (g->aborted) { - if (rank) { - package->priv->rank_fetch = NULL; - gm_mcp_icecrew_userlist_free_list( - package->priv->rank_alternatives); - package->priv->rank_alternatives = NULL; - } else { - package->priv->state_fetch = NULL; - gm_mcp_icecrew_userlist_free_list( - package->priv->state_alternatives); - package->priv->state_alternatives = NULL; - } - + if (g->aborted) { gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.FetchProgress: " "fetch aborted!"); return; } - + + rank = (package->priv->rank_fetch == g); + if (g->done) { gm_debug_msg(DEBUG_MCP, "GmMcpIcecrewUserlist.FetchProgress: " "fetch done!"); @@ -791,13 +804,156 @@ gm_mcp_icecrew_userlist_process_triggers(GmMcpIcecrewUserlist *package, } +gchar * +gm_mcp_icecrew_userlist_menu_item_subst(GmMcpIcecrewUserlist *package, + gchar *str, GmPlayerdbPlayerInfo *info) { + GString *result; + gchar *ptr = str, *subst, *tmp, *prop; + gchar const *value; + gunichar ch, cnum; + gboolean substituted; + + if (str == NULL) { + return NULL; + } + + result = g_string_sized_new(strlen(str)); + + while ((ch = g_utf8_get_char(ptr)) != '\0') { + substituted = FALSE; + + if (ch == '$') { + tmp = subst = g_utf8_next_char(ptr); + + while ((cnum = g_utf8_get_char(subst)) && (cnum == '_' || + g_unichar_isalpha(cnum))) { + subst = g_utf8_next_char(subst); + } + + prop = g_strndup(tmp, subst - tmp); + + if (strcmp(prop, "ID") == 0) { + tmp = g_strdup_printf("#%d", info->id); + result = g_string_append(result, tmp); + g_free(tmp); + + substituted = TRUE; + } else { + value = gm_playerdb_player_info_get_prop(info, prop); + + if (value) { + for (; *value != '\0'; value = g_utf8_next_char(value)) { + ch = g_utf8_get_char(value); + + if (ch == '_') { + result = g_string_append_c(result, '_'); + } + + result = g_string_append_unichar(result, ch); + } + + substituted = TRUE; + } + } + + if (substituted) { + ptr = subst; + } + } + + if (!substituted) { + result = g_string_append_unichar(result, ch); + } + + if (*ptr == '\0') { + break; + } + + ptr = g_utf8_next_char(ptr); + } + + ptr = result->str; + g_string_free(result, FALSE); + + return ptr; +} + +GmKeyValuePair * +gm_mcp_icecrew_userlist_get_menu_item(GmMcpIcecrewUserlist *package, + GmKeyValuePair *menuitem, GmPlayerdbPlayerInfo *info) { + GmKeyValuePair *result = g_new0(GmKeyValuePair, 1); + + if (!menuitem) { + return result; + } + + result->key = gm_mcp_icecrew_userlist_menu_item_subst(package, + menuitem->key, info); + result->value = gm_mcp_icecrew_userlist_menu_item_subst(package, + menuitem->value, info); + + return result; +} + +GList * +gm_mcp_icecrew_userlist_get_menu(GmIUserlist *userlist, gint id) { + GmMcpIcecrewUserlist *object = GM_MCP_ICECREW_USERLIST(userlist); + GmMcpIcecrewPlayerdb *playerdb = GM_MCP_ICECREW_PLAYERDB( + gm_mcp_session_find_package(GM_MCP_PACKAGE_SESSION(userlist), + "dns-nl-icecrew-playerdb")); + GmPlayerdbPlayerInfo *info = gm_mcp_icecrew_playerdb_find(playerdb, id); + GList *item, *result = NULL; + + for (item = object->priv->menu; item; item = item->next) { + result = g_list_append(result, gm_mcp_icecrew_userlist_get_menu_item( + object, (GmKeyValuePair *)(item->data), info)); + } + + return result; +} + +void +gm_mcp_icecrew_userlist_handle_menu(GmMcpIcecrewUserlist *package, + GList *values) { + GmKeyValuePair *pair; + GList *item, *data; + + gm_mcp_icecrew_userlist_free_menu(package); + + for (item = values; item; item = item->next) { + data = (GList *)(item->data); + pair = g_new0(GmKeyValuePair, 1); + + if (g_list_length(data) == 2) { + pair->key = g_strdup(data->data); + pair->value = g_strdup(data->next->data); + } + + package->priv->menu = g_list_append(package->priv->menu, + pair); + } +} + void gm_mcp_icecrew_userlist_handle_ranks_states(GmMcpIcecrewUserlist *package, GList *values, gboolean rank) { GList *tmp, *data, *new_list = NULL; gchar *name, **alternatives, *path, **ptr; gchar const *cpath; - + + /* Abort a previous fetch if needed */ + if (rank && package->priv->rank_fetch) { + package->priv->rank_fetch = NULL; + gm_mcp_icecrew_userlist_free_list(package->priv->rank_alternatives); + package->priv->rank_alternatives = NULL; + package->priv->rank_fetch->aborted = TRUE; + } else if (!rank && package->priv->state_fetch) { + package->priv->state_fetch = NULL; + gm_mcp_icecrew_userlist_free_list(package->priv->state_alternatives); + package->priv->state_alternatives = NULL; + package->priv->state_fetch->aborted = TRUE; + } + for (tmp = values; tmp; tmp = tmp->next) { data = (GList *)(tmp->data); @@ -873,19 +1029,6 @@ gm_mcp_icecrew_userlist_handle_ranks_states(GmMcpIcecrewUserlist *package, package->priv->state_icons = new_list; } - /* Abort a previous fetch if needed */ - if (rank && package->priv->rank_fetch) { - package->priv->rank_fetch->aborted = TRUE; - } else if (!rank && package->priv->state_fetch) { - package->priv->state_fetch->aborted = TRUE; - } - - /* Wait for vfs async to be aborted */ - while ((rank && package->priv->rank_fetch != NULL) || - (!rank && package->priv->state_fetch != NULL)) { - gm_do_events(); - } - if (rank && package->priv->rank_alternatives) { gm_mcp_icecrew_userlist_fetch_next_alternatives(package, rank); } else if (!rank && package->priv->state_alternatives) { @@ -921,6 +1064,8 @@ gm_mcp_icecrew_userlist_handle_multi(GmMcpPackage *package, gm_mcp_icecrew_userlist_handle_ranks_states(userlist, vals, TRUE); } else if (strcmp(key, "state") == 0) { gm_mcp_icecrew_userlist_handle_ranks_states(userlist, vals, FALSE); + } else if (strcmp(key, "menu") == 0) { + gm_mcp_icecrew_userlist_handle_menu(userlist, vals); } gm_mcp_icecrew_userlist_remove_datatag(userlist, data_tag); diff --git a/gnoemoe/mcp/gm-mcp-userlist-view.c b/gnoemoe/mcp/gm-mcp-userlist-view.c index aeb290d..67d8fc6 100644 --- a/gnoemoe/mcp/gm-mcp-userlist-view.c +++ b/gnoemoe/mcp/gm-mcp-userlist-view.c @@ -2,6 +2,7 @@ #include "gm-mcp-package.h" #include "gm-mcp-userlist-view.h" +#include "gm-iuserlist.h" #include "../widgets/gm-world-view.h" #include "../gm-pixbuf.h" #include "../gm-debug.h" @@ -23,25 +24,28 @@ typedef struct _GmMcpUserlistView { GtkListStore *store; GtkTreeView *tree_view; GtkScrolledWindow *scrolled_window; - + GtkWidget *popup_menu; + gboolean initializing; } GmMcpUserlistView; -void on_gm_mcp_userlist_view_weak_notify(gpointer data, GObject *obj); +static void on_gm_mcp_userlist_view_weak_notify(gpointer data, GObject *obj); -void on_gm_mcp_userlist_view_player_added(GmMcpPackage *package, gint id, +static void on_gm_mcp_userlist_view_player_added(GmMcpPackage *package, gint id, gchar const *name, gchar const *icon, gchar const *sort, GmMcpUserlistView *view); -void on_gm_mcp_userlist_view_player_removed(GmMcpPackage *package, gint id, +static void on_gm_mcp_userlist_view_player_removed(GmMcpPackage *package, gint id, GmMcpUserlistView *view); -void on_gm_mcp_userlist_view_name_changed(GmMcpPackage *package, gint id, +static void on_gm_mcp_userlist_view_name_changed(GmMcpPackage *package, gint id, gchar const *name, gchar const *sort, GmMcpUserlistView *view); -void on_gm_mcp_userlist_view_rank_changed(GmMcpPackage *package, gint id, +static void on_gm_mcp_userlist_view_rank_changed(GmMcpPackage *package, gint id, gchar const *icon, gchar const *sort, GmMcpUserlistView *view); -void on_gm_mcp_userlist_view_state_changed(GmMcpPackage *package, gint id, +static void on_gm_mcp_userlist_view_state_changed(GmMcpPackage *package, gint id, gchar const *icon, gchar const *sort, GmMcpUserlistView *view); -void on_gm_mcp_userlist_view_initializing(GmMcpPackage *package, - gboolean initializing, GmMcpUserlistView *view); +static gboolean on_gm_mcp_userlist_view_popup_menu(GtkWidget *widget, + GmMcpUserlistView *view); +static gboolean on_gm_mcp_userlist_view_button_press(GtkWidget *widget, + GdkEventButton *event, GmMcpUserlistView *view); GtkTreeModel * gm_mcp_userlist_view_model_create(GmMcpUserlistView *view) { @@ -88,7 +92,13 @@ gm_mcp_userlist_view_create_userlist(GmMcpUserlistView *view) { gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), GM_USERLIST_SORT, GTK_SORT_ASCENDING); - GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(tree_view), GTK_CAN_FOCUS); + GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(tree_view), GTK_CAN_FOCUS); + + gtk_widget_modify_base(GTK_WIDGET(tree_view), GTK_STATE_ACTIVE, + &(GTK_WIDGET(tree_view)->style->base[GTK_STATE_SELECTED])); + gtk_widget_modify_text(GTK_WIDGET(tree_view), GTK_STATE_ACTIVE, + &(GTK_WIDGET(tree_view)->style->text[GTK_STATE_SELECTED])); + gtk_tree_view_columns_autosize(GTK_TREE_VIEW(tree_view)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE); @@ -108,7 +118,7 @@ gm_mcp_userlist_view_new(GmMcpPackage *package, GObject *parent) { return; } - view = g_new(GmMcpUserlistView, 1); + view = g_new0(GmMcpUserlistView, 1); view->view = GM_WORLD_VIEW(parent); view->package = package; @@ -125,6 +135,11 @@ gm_mcp_userlist_view_new(GmMcpPackage *package, GObject *parent) { gtk_box_pack_end(GTK_BOX(vbox), child, TRUE, TRUE, 0); gtk_widget_show_all(vbox); + g_signal_connect(view->tree_view, "popup-menu", + G_CALLBACK(on_gm_mcp_userlist_view_popup_menu), view); + g_signal_connect(view->tree_view, "button-press-event", + G_CALLBACK(on_gm_mcp_userlist_view_button_press), view); + g_signal_connect(package, "player_added", G_CALLBACK(on_gm_mcp_userlist_view_player_added), view); g_signal_connect(package, "player_removed", @@ -141,7 +156,7 @@ gm_mcp_userlist_view_new(GmMcpPackage *package, GObject *parent) { } /* Callbacks */ -void +static void on_gm_mcp_userlist_view_weak_notify(gpointer data, GObject *obj) { GmMcpUserlistView *view = (GmMcpUserlistView *)(data); GtkWidget *vbox; @@ -162,11 +177,11 @@ on_gm_mcp_userlist_view_weak_notify(gpointer data, GObject *obj) { g_list_free(children); } } - + g_free(data); } -gboolean +static gboolean gm_mcp_userlist_view_find(GmMcpUserlistView *view, gint id, GtkTreeIter *iter) { GtkTreeModel *model = GTK_TREE_MODEL(view->store); gint iterid; @@ -184,7 +199,7 @@ gm_mcp_userlist_view_find(GmMcpUserlistView *view, gint id, GtkTreeIter *iter) { return FALSE; } -void +static void on_gm_mcp_userlist_view_player_added(GmMcpPackage *package, gint id, gchar const *name, gchar const *icon, gchar const *sort, GmMcpUserlistView *view) { @@ -203,7 +218,7 @@ on_gm_mcp_userlist_view_player_added(GmMcpPackage *package, gint id, sort, -1); } -void +static void on_gm_mcp_userlist_view_player_removed(GmMcpPackage *package, gint id, GmMcpUserlistView *view) { GtkTreeIter iter; @@ -217,7 +232,8 @@ on_gm_mcp_userlist_view_player_removed(GmMcpPackage *package, gint id, gtk_list_store_remove(view->store, &iter); } -void on_gm_mcp_userlist_view_name_changed(GmMcpPackage *package, gint id, +static void +on_gm_mcp_userlist_view_name_changed(GmMcpPackage *package, gint id, gchar const *name, gchar const *sort, GmMcpUserlistView *view) { GtkTreeIter iter; @@ -234,7 +250,8 @@ void on_gm_mcp_userlist_view_name_changed(GmMcpPackage *package, gint id, } } -void on_gm_mcp_userlist_view_rank_changed(GmMcpPackage *package, gint id, +static void +on_gm_mcp_userlist_view_rank_changed(GmMcpPackage *package, gint id, gchar const *icon, gchar const *sort, GmMcpUserlistView *view) { GtkTreeIter iter; @@ -253,7 +270,8 @@ void on_gm_mcp_userlist_view_rank_changed(GmMcpPackage *package, gint id, } } -void on_gm_mcp_userlist_view_state_changed(GmMcpPackage *package, gint id, +static void +on_gm_mcp_userlist_view_state_changed(GmMcpPackage *package, gint id, gchar const *icon, gchar const *sort, GmMcpUserlistView *view) { GtkTreeIter iter; @@ -271,3 +289,121 @@ void on_gm_mcp_userlist_view_state_changed(GmMcpPackage *package, gint id, gtk_list_store_set(view->store, &iter, GM_USERLIST_SORT, sort, -1); } } + +static void +popup_menu_detach(GtkWidget *attach_widget, GtkMenu *menu) { + GmMcpUserlistView *view = (GmMcpUserlistView *)g_object_get_data( + G_OBJECT(menu), "McpUserlistView"); + + view->popup_menu = NULL; +} + +static void +on_gm_mcp_userlist_view_menuitem_activate(GtkMenuItem *item, + GmMcpUserlistView *view) { + gchar *action = (gchar *)g_object_get_data(G_OBJECT(item), + "UserlistAction"); + + if (action) { + gm_world_sendln(GM_MCP_SESSION_WORLD(GM_MCP_PACKAGE_SESSION( + view->package)), action); + } +} + +static gboolean +gm_mcp_userlist_view_do_popup(GmMcpUserlistView *view, GdkEventButton *event) { + GList *menu; + GList *item; + GmKeyValuePair *pair; + GtkWidget *menuitem; + GtkTreeSelection *selection = gtk_tree_view_get_selection(view->tree_view); + gint id; + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreePath *path; + + if (!event) { + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) { + return FALSE; + } + + gtk_tree_model_get(model, &iter, GM_USERLIST_ID, &id, -1); + } else { + if (!gtk_tree_view_get_path_at_pos(view->tree_view, event->x, event->y, + &path, NULL, NULL, NULL)) { + return FALSE; + } else { + gtk_tree_model_get_iter(view->model, &iter, path); + gtk_tree_path_free(path); + + gtk_tree_model_get(view->model, &iter, GM_USERLIST_ID, &id, -1); + } + } + + menu = gm_iuserlist_get_menu(GM_IUSERLIST(view->package), id); + + if (view->popup_menu) { + gtk_widget_destroy(view->popup_menu); + } + + if (!menu) { + return FALSE; + } + + view->popup_menu = gtk_menu_new(); + g_object_set_data(G_OBJECT(view->popup_menu), "McpUserlistView", view); + + gtk_menu_attach_to_widget(GTK_MENU(view->popup_menu), + GTK_WIDGET(view->tree_view), popup_menu_detach); + + for (item = menu; item; item = item->next) { + pair = (GmKeyValuePair *)(item->data); + + if (pair->key == NULL) { + menuitem = gtk_separator_menu_item_new(); + g_free(pair->value); + } else { + menuitem = gtk_menu_item_new_with_mnemonic(pair->key); + g_object_set_data_full(G_OBJECT(menuitem), "UserlistAction", + pair->value, g_free); + + g_signal_connect(menuitem, "activate", + G_CALLBACK(on_gm_mcp_userlist_view_menuitem_activate), + view); + } + + gtk_widget_show(menuitem); + gtk_menu_shell_append(GTK_MENU_SHELL(view->popup_menu), menuitem); + + g_free(pair->key); + g_free(pair); + } + + g_list_free(menu); + + if (!event) { + gtk_menu_popup(GTK_MENU(view->popup_menu), NULL, NULL, NULL, NULL, 0, + gtk_get_current_event_time()); + } else { + gtk_menu_popup(GTK_MENU(view->popup_menu), NULL, NULL, NULL, NULL, + event->button, event->time); + } + + return TRUE; +} + +static gboolean +on_gm_mcp_userlist_view_popup_menu(GtkWidget *widget, + GmMcpUserlistView *view) { + return gm_mcp_userlist_view_do_popup(view, NULL); +} + +static gboolean +on_gm_mcp_userlist_view_button_press(GtkWidget *widget, GdkEventButton *event, + GmMcpUserlistView *view) { + if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { + gm_mcp_userlist_view_do_popup(view, event); + } + + return FALSE; +} diff --git a/gnoemoe/mcp/gm-mcp-vmoo-userlist.c b/gnoemoe/mcp/gm-mcp-vmoo-userlist.c index 9a3b0ea..941ecc1 100644 --- a/gnoemoe/mcp/gm-mcp-vmoo-userlist.c +++ b/gnoemoe/mcp/gm-mcp-vmoo-userlist.c @@ -2,6 +2,7 @@ #include #include "gm-mcp-vmoo-userlist.h" #include "gm-mcp-userlist-view.h" +#include "gm-iuserlist.h" #include "gm-mcp-session.h" #include "gm-mcp.h" #include "../gm-support.h" @@ -44,7 +45,7 @@ struct _GmMcpVmooUserlistPrivate { GList *fields; GList *icons; GList *users; - + GList *menu; gboolean initializing; }; @@ -59,9 +60,12 @@ enum { NUM_SIGNALS }; +static void gm_mcp_vmoo_userlist_iface_init(GmIUserlistInterface *iface); static guint gm_mcp_vmoo_userlist_signals[NUM_SIGNALS] = {0}; -G_DEFINE_TYPE(GmMcpVmooUserlist, gm_mcp_vmoo_userlist, GM_TYPE_MCP_PACKAGE) +G_DEFINE_TYPE_EXTENDED(GmMcpVmooUserlist, gm_mcp_vmoo_userlist, \ + GM_TYPE_MCP_PACKAGE, 0, G_IMPLEMENT_INTERFACE(GM_TYPE_IUSERLIST, \ + gm_mcp_vmoo_userlist_iface_init)) void gm_mcp_vmoo_userlist_handle_simple(GmMcpPackage *package, gchar *suffix, GList *fields); @@ -71,6 +75,13 @@ gboolean gm_mcp_vmoo_userlist_handle_multi(GmMcpPackage *package, void gm_mcp_vmoo_userlist_create_view(GmMcpPackage *package, GObject *parent); +GList *gm_mcp_vmoo_userlist_get_menu(GmIUserlist *userlist, gint id); + +static void +gm_mcp_vmoo_userlist_iface_init( + GmIUserlistInterface *iface) { + iface->get_menu = gm_mcp_vmoo_userlist_get_menu; +} void gm_mcp_vmoo_userlist_remove_users(GmMcpVmooUserlist *package) { @@ -89,6 +100,22 @@ gm_mcp_vmoo_userlist_remove_users(GmMcpVmooUserlist *package) { g_list_free(users); } +static void +gm_mcp_vmoo_userlist_free_menu(GmMcpVmooUserlist *obj) { + GList *field; + GmKeyValuePair *pair; + + for (field = obj->priv->menu; field; field = field->next) { + pair = (GmKeyValuePair *)(field->data); + + g_free(pair->key); + g_free(pair->value); + g_free(pair); + } + + obj->priv->menu = NULL; +} + static void gm_mcp_vmoo_userlist_finalize(GObject *object) { GmMcpVmooUserlist *obj = GM_MCP_VMOO_USERLIST(object); @@ -105,6 +132,8 @@ gm_mcp_vmoo_userlist_finalize(GObject *object) { } g_list_free(obj->priv->icons); + + gm_mcp_vmoo_userlist_free_menu(obj); gm_mcp_vmoo_userlist_remove_users(obj); g_list_free(obj->priv->users); @@ -303,6 +332,27 @@ gm_mcp_vmoo_userlist_handle_icons(GmMcpVmooUserlist *package, MOOVar *list) { } } +void +gm_mcp_vmoo_userlist_handle_menu(GmMcpVmooUserlist *package, MOOVar *list) { + MOOVar *field; + GmKeyValuePair *pair; + + for (field = list->list; field; field = field->next) { + pair = g_new0(GmKeyValuePair, 1); + + if (field->type == LIST && field->i == 2) { + pair->key = g_strdup(field->list->s); + pair->value = g_strdup(field->list->next->s); + package->priv->menu = g_list_append(package->priv->menu, + pair); + } else if (field->type != LIST) { + package->priv->menu = g_list_append(package->priv->menu, pair); + } else { + g_free(pair); + } + } +} + gchar * gm_mcp_vmoo_userlist_get_string(GmMcpVmooUserlist *package, MOOVar *v, MOOType type, gchar *cmp) { @@ -359,6 +409,118 @@ gm_mcp_vmoo_userlist_find_user(GmMcpVmooUserlist *package, gint nr) { return NULL; } +gchar * +gm_mcp_vmoo_userlist_menu_item_subst(GmMcpVmooUserlist *package, + gchar *str, UserInfo *info) { + GString *result; + gchar *ptr = str, *subst, *tmp; + gunichar ch, cnum; + gint num; + gboolean substituted; + + if (str == NULL) { + return NULL; + } + + result = g_string_sized_new(strlen(str)); + + while ((ch = g_utf8_get_char(ptr)) != '\0') { + substituted = FALSE; + + if (ch == '&') { + result = g_string_append_c(result, '_'); + substituted = TRUE; + } else if (ch == '$') { + subst = g_utf8_next_char(ptr); + + if (g_utf8_get_char(subst) == '(') { + subst = g_utf8_next_char(subst); + num = 0; + + while (g_unichar_isdigit((cnum = g_utf8_get_char(subst)))) { + num = (num * 10) + g_unichar_digit_value(cnum); + subst = g_utf8_next_char(subst); + } + + if (g_utf8_get_char(subst) == ')') { + switch (num) { + case 1: + tmp = g_strdup_printf("#%d", info->nr); + result = g_string_append(result, tmp); + g_free(tmp); + break; + case 2: + for (tmp = info->name; *tmp != '\0'; + tmp = g_utf8_next_char(tmp)) { + ch = g_utf8_get_char(tmp); + + if (ch == '_') { + result = g_string_append_c(result, '_'); + } + + result = g_string_append_unichar(result, ch); + } + break; + default: + break; + } + + ptr = subst; + substituted = TRUE; + } + } + } + + if (!substituted) { + result = g_string_append_unichar(result, ch); + } + + ptr = g_utf8_next_char(ptr); + } + + ptr = result->str; + g_string_free(result, FALSE); + + return ptr; +} + +GmKeyValuePair * +gm_mcp_vmoo_userlist_get_menu_item(GmMcpVmooUserlist *package, + GmKeyValuePair *menuitem, UserInfo *info) { + GmKeyValuePair *result = g_new0(GmKeyValuePair, 1); + + if (!menuitem) { + return result; + } + + result->key = gm_mcp_vmoo_userlist_menu_item_subst(package, + menuitem->key, info); + result->value = gm_mcp_vmoo_userlist_menu_item_subst(package, + menuitem->value, info); + + return result; +} + +GList * +gm_mcp_vmoo_userlist_get_menu(GmIUserlist *userlist, gint id) { + GmMcpVmooUserlist *package = (GmMcpVmooUserlist *)(userlist); + UserInfo *info = gm_mcp_vmoo_userlist_find_user(package, id); + GList *item, *menu = NULL; + GmKeyValuePair *pair; + + if (!info) { + return NULL; + } + + for (item = package->priv->menu; item; item = item->next) { + pair = (GmKeyValuePair *)(item->data); + menu = g_list_append(menu, gm_mcp_vmoo_userlist_get_menu_item(package, + pair, info)); + } + + return menu; +} + void gm_mcp_vmoo_userlist_remove_user(GmMcpVmooUserlist *package, gint nr) { GList *elem; @@ -573,10 +735,10 @@ gm_mcp_vmoo_userlist_handle_state(GmMcpVmooUserlist *package, MOOVar *v, g_free(sort); } else { - GM_DEBUG("User %d does not exist!", nr->i); + gm_debug_msg(DEBUG_MCP, "User %d does not exist!", nr->i); } } else { - GM_DEBUG("Nr is not an object: %d", nr->type); + gm_debug_msg(DEBUG_MCP, "Nr is not an object: %d", nr->type); } } } @@ -584,20 +746,37 @@ gm_mcp_vmoo_userlist_handle_state(GmMcpVmooUserlist *package, MOOVar *v, void gm_mcp_vmoo_userlist_handle_simple(GmMcpPackage *package, gchar *suffix, GList *fields) { - MOOVar *you; + MOOVar *v = NULL; GmMcpVmooUserlist *userlist = GM_MCP_VMOO_USERLIST(package); + gchar const *value; - if (suffix && strcmp(suffix, "you") == 0) { - you = MOOVar_parse(gm_mcp_find_value(fields, "nr")); - - if (you->type == OBJECT) { - userlist->priv->you = you->i; - MOOVar_free(you); - } else { - gm_debug_msg(DEBUG_MCP, "GmMcpVmooUserlist.HandleSimple: " - "you is not an object!"); + if (suffix) { + if (strcmp(suffix, "you") == 0) { + v = MOOVar_parse(gm_mcp_find_value(fields, "nr")); + + if (v->type == OBJECT) { + userlist->priv->you = v->i; + } else { + gm_debug_msg(DEBUG_MCP, "GmMcpVmooUserlist.HandleSimple: " + "you is not an object!"); + } + } else if (strcmp(suffix, "menu") == 0) { + value = gm_mcp_find_value(fields, "menu"); + v = MOOVar_parse(value); + + if (!v || v->type != LIST) { + gm_debug_msg(DEBUG_MCP, "GmMcpVmooUserlist.HandleMulti: " + "invalid value: %s", value); + } else { + gm_mcp_vmoo_userlist_free_menu(userlist); + gm_mcp_vmoo_userlist_handle_menu(userlist, v); + } } } + + if (v) { + MOOVar_free(v); + } } gboolean