This repository has been archived on 2020-04-11. You can view files and clone it, but cannot push or open issues or pull requests.
gnoemoe/gnoemoe/mcp/gm-mcp-userlist-view.c

805 lines
22 KiB
C

#include <gtk/gtk.h>
#include <string.h>
#include "gm-mcp-package.h"
#include "gm-mcp-userlist-view.h"
#include "gm-cell-renderer-text.h"
#include "gm-iuserlist.h"
#include "widgets/gm-world-view.h"
#include "gm-pixbuf.h"
#include "gm-app.h"
#include "gm-debug.h"
#define GM_USERLIST_ICON_SIZE 22
typedef struct _GmMcpUserlistView {
GmWorldView *view;
GmMcpPackage *package;
GtkTreeModel *model;
GtkListStore *store;
GtkTreeView *tree_view;
GtkWidget *label;
GtkScrolledWindow *scrolled_window;
GtkWidget *popup_menu;
GtkWidget *vbox;
gboolean initializing;
GmUserlistSortType sort_type;
gboolean show_object;
gboolean show_status;
gboolean use_state_icon;
gint num_players;
gint num_active;
GdkColor status_color;
} GmMcpUserlistView;
static void on_gm_mcp_userlist_view_weak_notify(gpointer data, GObject *obj);
static void on_gm_mcp_userlist_view_player_added(GmMcpPackage *package, gint id,
GmMcpUserlistView *view);
static void on_gm_mcp_userlist_view_player_removed(GmMcpPackage *package, gint id,
GmMcpUserlistView *view);
static void on_gm_mcp_userlist_view_name_changed(GmMcpPackage *package, gint id,
GmMcpUserlistView *view);
static void on_gm_mcp_userlist_view_rank_changed(GmMcpPackage *package, gint id,
GmMcpUserlistView *view);
static void on_gm_mcp_userlist_view_state_changed(GmMcpPackage *package, gint id,
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);
static void on_gm_mcp_userlist_view_option_changed(GmOptions *options,
gchar const *key, GmMcpUserlistView *view);
typedef struct _SortInfo {
gchar *name;
gint rank_priority;
gint state_priority;
} SortInfo;
static gint gm_mcp_userlist_view_sort_state_rank_name(SortInfo *info1,
SortInfo *info2);
static gint gm_mcp_userlist_view_sort_rank_name(SortInfo *info1,
SortInfo *info2);
static gint gm_mcp_userlist_view_sort_state_name(SortInfo *info1,
SortInfo *info2);
static gint gm_mcp_userlist_view_sort_name(SortInfo *info1,
SortInfo *info2);
typedef gint (*GmUserlistCompareFunc) (SortInfo *info1, SortInfo *info2);
static GmUserlistCompareFunc compare_functions[] = {
gm_mcp_userlist_view_sort_state_rank_name,
gm_mcp_userlist_view_sort_rank_name,
gm_mcp_userlist_view_sort_state_name,
gm_mcp_userlist_view_sort_name
};
GtkTreeModel *
gm_mcp_userlist_view_model_create(GmMcpUserlistView *view) {
GtkListStore *store = gtk_list_store_new(GM_USERLIST_N_COLUMNS,
GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
GtkTreeModel *model = gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(
store));
view->store = store;
view->model = model;
return model;
}
gint
gm_userlist_view_strcmp_safe(gchar const *str1, gchar const *str2) {
gchar *u1, *u2;
gint result;
if (str1 == NULL || str2 == NULL) {
if (str1 == NULL && str2 == NULL) {
result = 0;
} else if (str1 == NULL) {
result = -1;
} else {
result = 1;
}
} else {
u1 = g_utf8_casefold(str1, -1);
u2 = g_utf8_casefold(str2, -1);
result = g_utf8_collate(u1, u2);
g_free(u1);
g_free(u2);
}
return result;
}
static gint
gm_mcp_userlist_view_sort_state_rank_name(SortInfo *info1, SortInfo *info2) {
// Sort by 'icon' (so first by state, then if state is avail sort by rank
// and then by name, otherwise sort by name)
if (info1->state_priority == info2->state_priority) {
// The same state, if state is 0 then go by rank and then name,
// otherwise go by name
if (info1->state_priority == 0) {
if (info1->rank_priority == info2->rank_priority) {
return gm_userlist_view_strcmp_safe(info1->name, info2->name);
} else {
return info1->rank_priority - info2->rank_priority;
}
} else {
return gm_userlist_view_strcmp_safe(info1->name, info2->name);
}
} else {
return info1->state_priority - info2->state_priority;
}
}
static gint
gm_mcp_userlist_view_sort_rank_name(SortInfo *info1, SortInfo *info2) {
// First sort by rank, then sort by name
if (info1->rank_priority == info2->rank_priority) {
return gm_userlist_view_strcmp_safe(info1->name, info2->name);
} else {
return info1->rank_priority - info2->rank_priority;
}
}
static gint
gm_mcp_userlist_view_sort_state_name(SortInfo *info1, SortInfo *info2) {
// First sort by state, then sort by name
if (info1->state_priority == info2->state_priority) {
return gm_userlist_view_strcmp_safe(info1->name, info2->name);
} else {
return info1->state_priority - info2->state_priority;
}
}
static gint
gm_mcp_userlist_view_sort_name(SortInfo *info1, SortInfo *info2) {
// Sort by name
return gm_userlist_view_strcmp_safe(info1->name, info2->name);
}
gint
gm_mcp_userlist_view_sort_func(GtkTreeModel *model, GtkTreeIter *a,
GtkTreeIter *b, GmMcpUserlistView *view) {
/* a < b => -1
a == b => 0
a > b => 1 */
SortInfo info1, info2;
gint result;
gtk_tree_model_get(model, a,
GM_USERLIST_RANK_PRIORITY, &(info1.rank_priority),
GM_USERLIST_STATE_PRIORITY, &(info1.state_priority),
GM_USERLIST_NAME, &(info1.name), -1);
gtk_tree_model_get(model, b,
GM_USERLIST_RANK_PRIORITY, &(info2.rank_priority),
GM_USERLIST_STATE_PRIORITY, &(info2.state_priority),
GM_USERLIST_NAME, &(info2.name), -1);
result = (* compare_functions[view->sort_type]) (&info1, &info2);
g_free(info1.name);
g_free(info2.name);
return result;
}
static void
gm_mcp_userlist_view_update_label(GmMcpUserlistView *view) {
gchar *label;
label = g_strdup_printf(_("Players: %d, active: %d"), view->num_players,
view->num_active);
gtk_label_set_label(GTK_LABEL(view->label), label);
g_free(label);
}
GtkWidget *
gm_mcp_userlist_view_create_label(GmMcpUserlistView *view) {
view->label = gtk_label_new(NULL);
gm_mcp_userlist_view_update_label(view);
return view->label;
}
GtkWidget *
gm_mcp_userlist_view_create_userlist(GmMcpUserlistView *view) {
GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
GtkTreeModel *model = gm_mcp_userlist_view_model_create(view);
GtkWidget *tree_view = gtk_tree_view_new_with_model(model);
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
GTK_SHADOW_IN);
gtk_widget_set_size_request(scrolled_window, 150, -1);
gtk_widget_set_size_request(tree_view, 150, -1);
gtk_container_add(GTK_CONTAINER(scrolled_window), tree_view);
renderer = gtk_cell_renderer_pixbuf_new();
column = gtk_tree_view_column_new_with_attributes(_("I"), renderer,
"pixbuf", GM_USERLIST_ICON, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
gtk_tree_view_column_set_min_width(column, 30);
renderer = gm_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer,
"name", GM_USERLIST_NAME, "status", GM_USERLIST_STATUS, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model),
GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(model),
(GtkTreeIterCompareFunc)gm_mcp_userlist_view_sort_func, view, NULL);
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);
view->tree_view = GTK_TREE_VIEW(tree_view);
view->scrolled_window = GTK_SCROLLED_WINDOW(scrolled_window);
return scrolled_window;
}
void
gm_mcp_userlist_view_new(GmMcpPackage *package, GObject *parent) {
GmMcpUserlistView *view;
GtkPaned *paned;
GtkWidget *vbox, *child;
GmOptions *options;
if (!GM_IS_WORLD_VIEW(parent)) {
return;
}
view = g_new0(GmMcpUserlistView, 1);
view->view = GM_WORLD_VIEW(parent);
view->package = package;
paned = GTK_PANED(gm_world_view_hpaned(view->view));
vbox = gtk_paned_get_child2(paned);
if (vbox == NULL) {
vbox = gtk_vbox_new(FALSE, 3);
view->vbox = vbox;
gtk_paned_pack2(paned, view->vbox, FALSE, FALSE);
} else {
vbox = view->vbox;
}
child = gm_mcp_userlist_view_create_userlist(view);
gtk_box_pack_end(GTK_BOX(vbox), child, TRUE, TRUE, 0);
gtk_box_pack_end(GTK_BOX(vbox), gm_mcp_userlist_view_create_label(view),
FALSE, FALSE, 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",
G_CALLBACK(on_gm_mcp_userlist_view_player_removed), view);
g_signal_connect(package, "name_changed",
G_CALLBACK(on_gm_mcp_userlist_view_name_changed), view);
g_signal_connect(package, "state_changed",
G_CALLBACK(on_gm_mcp_userlist_view_state_changed), view);
g_signal_connect(package, "rank_changed",
G_CALLBACK(on_gm_mcp_userlist_view_rank_changed), view);
// Userlist options
options = gm_app_options(gm_app_instance());
view->show_object = gm_options_get_int(options,
"userlist_show_object_number");
view->sort_type = gm_options_get_int(options, "userlist_sort_type");
view->show_status = gm_options_get_int(options, "userlist_show_status");
view->use_state_icon = gm_options_get_int(options,
"userlist_use_state_icon");
if (!gm_options_get_int(options, "show_userlist"))
gtk_widget_hide(vbox);
g_signal_connect(options, "option-changed",
G_CALLBACK(on_gm_mcp_userlist_view_option_changed), view);
g_object_weak_ref(G_OBJECT(package), on_gm_mcp_userlist_view_weak_notify,
view);
}
static gchar *
gm_mcp_userlist_view_get_status(GmMcpUserlistView *view, gint id) {
if (!view->show_status ||
!gm_iuserlist_supports_status(GM_IUSERLIST(view->package))) {
return NULL;
}
return gm_iuserlist_get_status(GM_IUSERLIST(view->package), id);
}
static gchar *
gm_mcp_userlist_view_get_name(GmMcpUserlistView *view, gint id) {
gchar const *name;
name = gm_iuserlist_get_name(GM_IUSERLIST(view->package), id);
if (view->show_object) {
return g_strdup_printf("%s (#%d)", name, id);
} else {
return g_strdup(name);
}
}
static void
gm_mcp_userlist_view_update_sort_type(GmMcpUserlistView *view,
GmUserlistSortType sort_type) {
if (sort_type == view->sort_type) {
return;
}
if (sort_type < 0 || sort_type >= GM_USERLIST_SORT_TYPE_NUM) {
return;
}
view->sort_type = sort_type;
gtk_tree_model_sort_reset_default_sort_func(GTK_TREE_MODEL_SORT(
view->model));
gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(view->model),
(GtkTreeIterCompareFunc)gm_mcp_userlist_view_sort_func, view, NULL);
}
static void
gm_mcp_userlist_view_update_names(GmMcpUserlistView *view) {
GtkTreeModel *model = GTK_TREE_MODEL(view->store);
gint iterid;
GtkTreeIter iter;
gchar *name;
gchar *status;
if (gtk_tree_model_get_iter_first(model, &iter)) {
do {
gtk_tree_model_get(model, &iter, GM_USERLIST_ID, &iterid, -1);
name = gm_mcp_userlist_view_get_name(view, iterid);
status = gm_mcp_userlist_view_get_status(view, iterid);
gtk_list_store_set(view->store, &iter, GM_USERLIST_NAME, name,
GM_USERLIST_STATUS, status, -1);
g_free(name);
g_free(status);
} while (gtk_tree_model_iter_next(model, &iter));
}
}
static void
gm_mcp_userlist_view_update_show_object_number(GmMcpUserlistView *view,
gboolean show_object) {
if (view->show_object == show_object) {
return;
}
view->show_object = show_object;
gm_mcp_userlist_view_update_names(view);
}
static void
gm_mcp_userlist_view_update_show_status(GmMcpUserlistView *view,
gboolean show_status) {
if (view->show_status == show_status) {
return;
}
view->show_status = show_status;
gm_mcp_userlist_view_update_names(view);
}
static void
gm_mcp_userlist_view_update_use_state_icon(GmMcpUserlistView *view,
gboolean use_state_icon) {
gchar const *icon;
GtkTreeModel *model = GTK_TREE_MODEL(view->store);
GtkTreeIter iter;
gint iterid;
if (view->use_state_icon == use_state_icon) {
return;
}
view->use_state_icon = use_state_icon;
// Update icons for all players
if (gtk_tree_model_get_iter_first(model, &iter)) {
do {
gtk_tree_model_get(model, &iter, GM_USERLIST_ID, &iterid, -1);
icon = gm_iuserlist_get_icon(GM_IUSERLIST(view->package), iterid,
use_state_icon);
gtk_list_store_set(view->store, &iter, GM_USERLIST_ICON,
gm_pixbuf_get_at_size(icon, GM_USERLIST_ICON_SIZE,
GM_USERLIST_ICON_SIZE), -1);
} while (gtk_tree_model_iter_next(model, &iter));
}
}
static gboolean
gm_mcp_userlist_view_player_active(GmMcpUserlistView *view, GtkTreeIter *iter) {
gint state;
gtk_tree_model_get(GTK_TREE_MODEL(view->store), iter,
GM_USERLIST_STATE_PRIORITY, &state, -1);
return (state == 0);
}
/* Callbacks */
static void
on_gm_mcp_userlist_view_weak_notify(gpointer data, GObject *obj) {
GmMcpUserlistView *view = (GmMcpUserlistView *)(data);
GtkWidget *vbox;
GList *children;
if (GM_IS_WORLD_VIEW(view->view)) {
gtk_widget_destroy(GTK_WIDGET(view->scrolled_window));
gtk_widget_destroy(view->label);
vbox = gtk_paned_get_child2(GTK_PANED(gm_world_view_hpaned(
view->view)));
if (vbox != NULL) {
children = gtk_container_get_children(GTK_CONTAINER(vbox));
if (children == NULL) {
gtk_widget_destroy(vbox);
}
g_list_free(children);
}
}
g_object_unref(G_OBJECT(view->store));
g_object_unref(G_OBJECT(view->model));
g_signal_handlers_disconnect_by_func(gm_app_options(gm_app_instance()),
G_CALLBACK(on_gm_mcp_userlist_view_option_changed), view);
g_free(data);
}
static void
on_gm_mcp_userlist_view_option_changed(GmOptions *options, gchar const *key,
GmMcpUserlistView *view) {
if (strcmp(key, "userlist_sort_type") == 0) {
gm_mcp_userlist_view_update_sort_type(view,
gm_options_get_int(options, "userlist_sort_type"));
} else if (strcmp(key, "userlist_show_status") == 0) {
gm_mcp_userlist_view_update_show_status(view,
gm_options_get_int(options, "userlist_show_status"));
} else if (strcmp(key, "userlist_use_state_icon") == 0) {
gm_mcp_userlist_view_update_use_state_icon(view,
gm_options_get_int(options, "userlist_use_state_icon"));
} else if (strcmp(key, "userlist_show_object_number") == 0) {
gm_mcp_userlist_view_update_show_object_number(view,
gm_options_get_int(options, "userlist_show_object_number"));
} else if (strcmp(key, "show_userlist") == 0) {
if (gm_options_get_int(options, "show_userlist"))
gtk_widget_show(view->vbox);
else
gtk_widget_hide(view->vbox);
}
}
static gboolean
gm_mcp_userlist_view_find(GmMcpUserlistView *view, gint id, GtkTreeIter *iter) {
GtkTreeModel *model = GTK_TREE_MODEL(view->store);
gint iterid;
if (gtk_tree_model_get_iter_first(model, iter)) {
do {
gtk_tree_model_get(model, iter, GM_USERLIST_ID, &iterid, -1);
if (iterid == id) {
return TRUE;
}
} while (gtk_tree_model_iter_next(model, iter));
}
return FALSE;
}
static void
on_gm_mcp_userlist_view_player_added(GmMcpPackage *package, gint id,
GmMcpUserlistView *view) {
GtkTreeIter iter;
gchar *name, *status;
GmIUserlist *userlist = GM_IUSERLIST(package);
if (gm_mcp_userlist_view_find(view, id, &iter)) {
gm_debug_msg(DEBUG_MCP, "GmMcpUserlistView.OnPlayerAdded: player %d "
"is already in the list, can't be added twice!", id);
return;
}
name = gm_mcp_userlist_view_get_name(view, id);
status = gm_mcp_userlist_view_get_status(view, id);
gtk_list_store_insert_with_values(view->store, &iter,
gtk_tree_model_iter_n_children(GTK_TREE_MODEL(view->store), NULL),
GM_USERLIST_ID, id,
GM_USERLIST_ICON, gm_pixbuf_get_at_size(
gm_iuserlist_get_icon(userlist, id, view->use_state_icon),
GM_USERLIST_ICON_SIZE, GM_USERLIST_ICON_SIZE),
GM_USERLIST_NAME, name,
GM_USERLIST_STATUS, status,
GM_USERLIST_RANK_PRIORITY,
gm_iuserlist_get_rank_priority(userlist, id),
GM_USERLIST_STATE_PRIORITY,
gm_iuserlist_get_state_priority(userlist, id),
-1);
g_free(name);
g_free(status);
view->num_players = view->num_players + 1;
if (gm_mcp_userlist_view_player_active(view, &iter)) {
view->num_active = view->num_active + 1;
}
gm_mcp_userlist_view_update_label(view);
}
static void
on_gm_mcp_userlist_view_player_removed(GmMcpPackage *package, gint id,
GmMcpUserlistView *view) {
GtkTreeIter iter;
if (!gm_mcp_userlist_view_find(view, id, &iter)) {
gm_debug_msg(DEBUG_MCP, "GmMcpUserlistView.OnPlayerRemoved: player %d "
"is not in the list, can't be removed!", id);
return;
}
view->num_players = view->num_players - 1;
if (gm_mcp_userlist_view_player_active(view, &iter)) {
view->num_active = view->num_active - 1;
}
gm_mcp_userlist_view_update_label(view);
gtk_list_store_remove(view->store, &iter);
}
static void
on_gm_mcp_userlist_view_name_changed(GmMcpPackage *package, gint id,
GmMcpUserlistView *view) {
GtkTreeIter iter;
gchar *name;
if (!gm_mcp_userlist_view_find(view, id, &iter)) {
gm_debug_msg(DEBUG_MCP, "GmMcpUserlistView.OnNameChanged: player %d "
"is not in the list!", id);
return;
}
name = gm_mcp_userlist_view_get_name(view, id);
if (name != NULL) {
gtk_list_store_set(view->store, &iter, GM_USERLIST_NAME, name, -1);
g_free(name);
}
}
static void
on_gm_mcp_userlist_view_rank_changed(GmMcpPackage *package, gint id,
GmMcpUserlistView *view) {
GtkTreeIter iter;
gchar const *icon;
if (!gm_mcp_userlist_view_find(view, id, &iter)) {
gm_debug_msg(DEBUG_MCP, "GmMcpUserlistView.OnRankChanged: player %d "
"is not in the list!", id);
return;
}
icon = gm_iuserlist_get_icon(GM_IUSERLIST(package),
id, view->use_state_icon);
gtk_list_store_set(view->store, &iter, GM_USERLIST_ICON,
gm_pixbuf_get_at_size(icon, GM_USERLIST_ICON_SIZE,
GM_USERLIST_ICON_SIZE),
GM_USERLIST_RANK_PRIORITY, gm_iuserlist_get_rank_priority(
GM_IUSERLIST(package), id),
-1);
}
static void
on_gm_mcp_userlist_view_state_changed(GmMcpPackage *package, gint id,
GmMcpUserlistView *view) {
GtkTreeIter iter;
gchar *name, *status;
gchar const *icon;
gboolean active;
if (!gm_mcp_userlist_view_find(view, id, &iter)) {
gm_debug_msg(DEBUG_MCP, "GmMcpUserlistView.OnStateChanged: player %d "
"is not in the list!", id);
return;
}
active = gm_mcp_userlist_view_player_active(view, &iter);
name = gm_mcp_userlist_view_get_name(view, id);
status = gm_mcp_userlist_view_get_status(view, id);
icon = gm_iuserlist_get_icon(GM_IUSERLIST(package), id,
view->use_state_icon);
gtk_list_store_set(view->store, &iter, GM_USERLIST_ICON,
gm_pixbuf_get_at_size(icon, GM_USERLIST_ICON_SIZE,
GM_USERLIST_ICON_SIZE),
GM_USERLIST_NAME, name,
GM_USERLIST_STATUS, status,
GM_USERLIST_STATE_PRIORITY, gm_iuserlist_get_state_priority(
GM_IUSERLIST(package), id),
-1);
g_free(name);
g_free(status);
if (gm_mcp_userlist_view_player_active(view, &iter) != active) {
if (active) {
// no longer active
view->num_active = view->num_active - 1;
} else {
// now active
view->num_active = view->num_active + 1;
}
}
gm_mcp_userlist_view_update_label(view);
}
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;
}