/* Jungle Monkey
* Copyright (C) 1999-2001 The Regents of the University of Michigan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ggui.h"
#include "ggui_channels.h"
#include "ggui_config.h"
#include "ggui_debug.h"
#include "ggui_files.h"
#include "ggui_properties.h"
#include "entry_dialog.h"
#include "util/util.h"
#include "util/jmgnet.h"
/* ******************** */
typedef struct _Channel
{
JMChannel* jmchannel;
JMAnn* shown;
/* TODO: This should be a list so we can support arbitrary
linking. */
GURL* channel;
gchar* path;
} Channel;
static GladeXML* menu_xml;
static GtkCList* channel_clist;
static GtkWidget* channel_popup;
static Channel* selected_channel;
static GHashTable* url_to_channel;
/* ******************** */
static void shutdown_hfunc (gpointer key, gpointer value, gpointer user_data);
static void load_channel_func (const ElfNode* elf);
static void load_channel_ann_func (const ElfNode* elf);
static void save_channel_hfunc (gpointer key, gpointer value, gpointer user_data);
static void save_channel_ann_hfunc (gpointer key, gpointer value, gpointer user_data);
static Channel* channel_new (JMChannel* jmchannel);
static void channel_update (Channel* channel);
static void channel_delete (Channel* channel);
#define channel_get(U) ((Channel*) g_hash_table_lookup (url_to_channel, (U)))
static void channel_info (JMChannel* channel, JMChannelType type,
JMAnn* ann, gpointer user_data);
static void channel_error (JMChannel* jmchannel, gpointer user_data);
void on_channels_select_row(GtkCList* list, gint row, gint column, GdkEvent* event);
void on_channels_unselect_row(GtkCList* list, gint row, gint column, GdkEvent* event);
gint on_channels_button_press (GtkCList* list, GdkEventButton *event, gpointer user_data);
void on_channels_properties(gpointer callback_data, guint callback_action, GtkWidget* widget);
#define POPUPFUNC(F) void F(gpointer callback_data, guint callback_action, GtkWidget* widget)
/* ************************************************************ */
void
ggui_channel_init (void)
{
/* Setup GUI */
menu_xml = ggui_get_glade_xml ("channels_popup", "master_popup.glade");
g_assert (menu_xml != NULL);
glade_xml_signal_autoconnect(menu_xml);
channel_clist = GTK_CLIST(glade_xml_get_widget(jmw_xml, "channels_clist"));
channel_popup = GTK_WIDGET(glade_xml_get_widget(menu_xml, "channels_popup"));
g_assert (channel_clist);
g_assert (channel_popup);
ggui_set_tooltip (GTK_WIDGET(channel_clist), _("Channels you have joined."));
url_to_channel = g_hash_table_new (gnet_url_hash, gnet_url_equal);
selected_channel = NULL;
}
void
ggui_channel_shutdown (void)
{
/* Delete channels */
g_hash_table_foreach (url_to_channel, shutdown_hfunc, NULL);
g_hash_table_destroy (url_to_channel);
url_to_channel = NULL;
selected_channel = NULL;
}
void
shutdown_hfunc (gpointer key, gpointer value, gpointer user_data)
{
Channel* channel = (Channel*) value;
channel_delete (channel);
}
void
ggui_channel_load (void)
{
GURL* mc_url;
Channel* mc_channel;
ggui_load_elf ("channel", load_channel_func);
ggui_load_elf ("channel-announce", load_channel_ann_func);
/* Setup Monkey Central, if it isn't there already */
mc_url = gnet_url_new (JM_DEFAULT_CHANNEL);
g_return_if_fail (mc_url);
mc_channel = channel_get (mc_url);
if (!mc_channel)
{
JMChannel* jmchannel;
/* Create channel */
jmchannel = jmchannel_setup (jm_btp_bpeer, mc_url);
g_return_if_fail (jmchannel);
if (jm_mtp_rvous_url && jm_mtp_server)
jmchannel_set_mtp (jmchannel, jm_mtp_rvous_url, jm_mtp_server);
/* Add it */
channel_new (jmchannel);
}
gnet_url_delete (mc_url);
}
static void
load_channel_func (const ElfNode* elf)
{
const gchar* name;
const gchar* url_str;
GURL* url = NULL;
JMChannel* jmchannel = NULL;
name = elf_get_attribute (elf, "name");
url_str = elf_get_attribute (elf, "url");
if (url_str) url = gnet_url_new (url_str);
if (!strcmp (elf->name, "create") && name)
jmchannel = jmchannel_create (jm_btp_bpeer, name);
else if (!strcmp (elf->name, "join") && url && !channel_get(url))
jmchannel = jmchannel_join (jm_btp_bpeer, url);
else if (!strcmp (elf->name, "setup") && url && !channel_get(url))
jmchannel = jmchannel_setup (jm_btp_bpeer, url);
if (jmchannel)
{
if (jm_mtp_rvous_url && jm_mtp_server)
jmchannel_set_mtp (jmchannel, jm_mtp_rvous_url, jm_mtp_server);
channel_new (jmchannel);
}
gnet_url_delete (url);
}
static void
load_channel_ann_func (const ElfNode* elf)
{
const gchar* curl_str;
const gchar* url_str;
const gchar* path;
GURL* curl = NULL;
GURL* url = NULL;
Channel* channel;
JMAnn* ann;
curl_str = elf_get_attribute (elf, "curl");
url_str = elf_get_attribute (elf, "url");
path = elf_get_attribute (elf, "path");
if (!curl_str || !url_str || !path) return;
curl = gnet_url_new (curl_str);
url = gnet_url_new (url_str);
if (!url || !curl) goto done;
/* Change URL's */
if (!SAFESTRCMP(jm_hostname, curl->hostname) &&
(!jm_btp_last_port || curl->port == jm_btp_last_port))
gnet_url_set_port (curl, jm_btp_bpeer->port);
if (!SAFESTRCMP(jm_hostname, url->hostname) &&
(!jm_btp_last_port || url->port == jm_btp_last_port))
gnet_url_set_port (url, jm_btp_bpeer->port);
channel = channel_get (url);
if (!channel || channel->channel) goto done; /* TODO: Multiple paths */
ann = ggui_channel_add_path (curl, path, url);
if (!ann) goto done;
channel->channel = curl; curl = NULL;
channel->path = g_strdup (ann->path);
done:
gnet_url_delete (url);
gnet_url_delete (curl);
}
void
ggui_channel_save (void)
{
ggui_save_hashtable ("channel", url_to_channel, save_channel_hfunc);
ggui_save_hashtable ("channel-announce", url_to_channel, save_channel_ann_hfunc);
}
static void
save_channel_hfunc (gpointer key, gpointer value, gpointer user_data)
{
Channel* channel = (Channel*) value;
FILE* file = (FILE*) user_data;
ElfNode* elf;
gchar* buf;
gint len;
elf = elf_new (NULL);
if (channel->jmchannel->is_local)
{
elf_set_name (elf, "create");
elf_set_attribute (elf, "name", gnet_url_basename (channel->jmchannel->url));
}
else if (jmchannel_is_up (channel->jmchannel))
{
gchar* url_str;
elf_set_name (elf, "join");
url_str = gnet_url_get_nice_string (channel->jmchannel->url);
elf_set_attribute (elf, "url", url_str);
g_free (url_str);
}
else
{
gchar* url_str;
elf_set_name (elf, "setup");
url_str = gnet_url_get_nice_string (channel->jmchannel->url);
elf_set_attribute (elf, "url", url_str);
g_free (url_str);
}
elf_write (elf, &buf, &len);
fwrite (buf, len, 1, file);
elf_delete (elf);
g_free (buf);
}
static void
save_channel_ann_hfunc (gpointer key, gpointer value, gpointer user_data)
{
Channel* channel = (Channel*) value;
FILE* file = (FILE*) user_data;
gchar* curl;
gchar* url;
ElfNode* elf;
gchar* buf;
gint len;
if (!(channel->channel && channel->path))
return;
url = gnet_url_get_nice_string (channel->jmchannel->url);
curl = gnet_url_get_nice_string (channel->channel);
elf = elf_new_format ("ann", "sss", "curl", curl, "path", channel->path,
"url", url);
elf_write (elf, &buf, &len);
fwrite (buf, len, 1, file);
elf_delete (elf);
g_free (buf);
g_free (url);
g_free (curl);
}
/* **************************************** */
JMChannel*
ggui_channel_get (const GURL* url)
{
Channel* channel;
channel = channel_get (url);
if (!channel)
return NULL;
return channel->jmchannel;
}
JMAnn*
ggui_channel_get_ann (const GURL* url, const gchar* path)
{
JMChannel* channel;
channel = ggui_channel_get (url);
if (!channel)
return NULL;
return jmchannel_get (channel, path);
}
gboolean
ggui_channel_check_path (const GURL* channel, const gchar* path, const gchar* name)
{
JMChannel* pchannel;
JMAnn* pann;
g_return_val_if_fail (channel, FALSE);
g_return_val_if_fail (path, FALSE);
g_return_val_if_fail (name, FALSE);
/* Check channel */
pchannel = ggui_channel_get (channel);
if (!pchannel)
{
ggui_show_message ("warning", _("Channel %s no longer exists\n"),
gnet_url_basename(channel));
return FALSE;
}
/* Check path */
pann = jmchannel_get (pchannel, path);
if (!pann)
{
ggui_show_message ("warning", _("Path %s no longer exists on channel %s\n"),
path, jmchannel_get_name(pchannel));
return FALSE;
}
/* Check if already exists */
if (jmann_get_child (pann, name))
{
ggui_show_message ("warning", _("%s already exists in %s:%s\n"),
name, jmchannel_get_name(pchannel), pann->path);
return FALSE;
}
return TRUE;
}
gboolean
ggui_channel_is_up (const GURL* url)
{
JMChannel* jmchannel;
jmchannel = ggui_channel_get (url);
if (!jmchannel)
return FALSE;
return jmchannel_is_up (jmchannel);
}
gboolean
ggui_channel_is_down (const GURL* url)
{
JMChannel* jmchannel;
jmchannel = ggui_channel_get (url);
if (!jmchannel)
return FALSE;
return jmchannel_is_down (jmchannel);
}
gchar*
ggui_channel_get_properties (const GURL* url)
{
JMChannel* jmchannel;
jmchannel = ggui_channel_get (url);
if (!jmchannel)
return g_strdup ("");
return g_strdup_printf (_("Channel %s\n"), gnet_url_basename(url));
}
/* ******************** */
static EntryDialog* create_dialog = NULL;
static GURL* create_channel = NULL;
static gchar* create_path = NULL;
static void create_ok (gchar* channel_name, gchar* ignore);
static void create_cancel (void);
static void create (const GURL* pchannel, const gchar* path, const gchar* name);
void
ggui_channel_create (const GURL* channel, const gchar* path, const gchar* name)
{
g_return_if_fail ((channel && path) || !(channel && path));
/* Prompt for name if not given */
if (!name)
{
if (create_dialog)
{
entry_dialog_show (create_dialog);
return;
}
if (channel && path)
{
create_channel = gnet_url_clone (channel);
create_path = g_strdup (path);
}
create_dialog = entry_dialog_new(_("Create channel"),
_("Channel name"), NULL,
create_ok, create_cancel);
return;
}
create (channel, path, name);
}
static void
create_ok (gchar* channel_name, gchar* ignore)
{
create (create_channel, create_path, channel_name);
create_cancel ();
}
static void
create_cancel (void)
{
create_dialog = NULL;
gnet_url_delete (create_channel);
create_channel = NULL;
g_free (create_path);
create_path = NULL;
}
static void
create (const GURL* pchannel, const gchar* path, const gchar* name)
{
JMChannel* jmchannel;
Channel* channel;
g_return_if_fail (name);
g_return_if_fail ((pchannel && path) || !(pchannel && path));
/* Check if path ok */
if (pchannel && path && !ggui_channel_check_path (pchannel, path, name))
return;
/* Create the channel */
jmchannel = jmchannel_create (jm_btp_bpeer, name);
if (!jmchannel)
{
ggui_show_message ("warning", _("Could not create channel \"%s\"\n"), name);
return;
}
if (jm_mtp_rvous_url && jm_mtp_server)
jmchannel_set_mtp (jmchannel, jm_mtp_rvous_url, jm_mtp_server);
/* Add it */
channel = channel_new (jmchannel);
g_return_if_fail (channel);
if (pchannel && path)
{
JMAnn* ann;
ann = ggui_channel_add (pchannel, path, name, jmchannel->url);
g_return_if_fail (ann);
channel->channel = gnet_url_clone (pchannel);
channel->path = g_strdup (ann->path);
}
}
/* ********** */
static EntryDialog* join_dialog = NULL;
static void join_ok (gchar* url, gchar* ignore);
static void join_cancel (void);
static void join (const GURL* url);
void
ggui_channel_join (const GURL* url)
{
Channel* channel;
/* Prompt for name if not given */
if (!url)
{
if (join_dialog)
{
entry_dialog_show (join_dialog);
return;
}
join_dialog = entry_dialog_new(_("Open channel"),
_("Channel URL"), NULL,
join_ok, join_cancel);
return;
}
/* Check if channel exists */
channel = channel_get (url);
if (channel)
{
if (!jmchannel_is_up (channel->jmchannel))
{
jmchannel_rejoin (channel->jmchannel);
channel_update (channel);
}
return;
}
/* Create it */
join (url);
}
static void
join_ok (gchar* url, gchar* ignore)
{
GURL* gurl;
gurl = gnet_url_new (url);
if (gurl || !SAFESTRCMP(gurl->protocol, "jm"))
{
join (gurl);
gnet_url_delete (gurl);
}
else
{
ggui_show_message ("warning", _("Malformed URL: %s (should be jm://something)\n"));
}
join_cancel ();
}
static void
join_cancel(void)
{
join_dialog = NULL;
}
static void
join (const GURL* url)
{
Channel* channel;
JMChannel* jmchannel;
g_return_if_fail (url);
/* Check if channel exists */
channel = channel_get (url);
if (channel)
{
if (!jmchannel_is_up (channel->jmchannel))
{
jmchannel_rejoin (channel->jmchannel);
channel_update (channel);
}
ggui_show_message ("warning", _("Channel is already open\n"));
return;
}
/* Create channel */
jmchannel = jmchannel_join (jm_btp_bpeer, url);
if (!jmchannel)
{
ggui_show_message ("warning", _("Could not open channel\n"));
return;
}
if (jm_mtp_rvous_url && jm_mtp_server)
jmchannel_set_mtp (jmchannel, jm_mtp_rvous_url, jm_mtp_server);
/* Add it */
channel = channel_new (jmchannel);
g_return_if_fail (channel);
}
void
ggui_channel_leave (const GURL* url)
{
Channel* channel;
g_return_if_fail (url);
/* Get channel */
channel = channel_get (url);
if (!channel)
return;
/* Remove files */
ggui_file_leave (url);
/* Leave group */
jmchannel_leave (channel->jmchannel);
channel_update (channel);
}
void
ggui_channel_delete (const GURL* url)
{
Channel* channel;
gint row;
g_return_if_fail (url);
/* Remove files */
ggui_file_leave (url);
/* Get channel */
channel = channel_get (url);
if (!channel)
return;
g_hash_table_remove (url_to_channel, url);
/* Remove the channel from the list (this will unselect the channel
if it is selected) */
row = gtk_clist_find_row_from_data (channel_clist, channel);
if (row >= 0)
gtk_clist_remove (channel_clist, row);
/* Send remove */
if (channel->jmchannel->is_local && channel->channel && channel->path)
ggui_channel_remove_path (channel->channel, channel->path);
/* remove_path may delete url */
/* Delete group */
channel_delete (channel);
}
/* ********** */
static Channel*
channel_new (JMChannel* jmchannel)
{
Channel* channel;
gchar* texts[2] = {NULL, NULL};
gint row;
g_return_val_if_fail (jmchannel, NULL);
g_return_val_if_fail (jmchannel->url, NULL);
/* Make sure channel isn't there */
g_return_val_if_fail (!channel_get(jmchannel->url), NULL);
/* Create new channel */
channel = g_new0 (Channel, 1);
channel->jmchannel = jmchannel;
g_hash_table_insert (url_to_channel, jmchannel->url, channel);
/* Initialize it */
jmchannel->info_func = channel_info;
jmchannel->error_func = channel_error;
jmchannel->user_data = channel;
/* Add to clist */
texts[0] = gnet_url_basename (jmchannel->url);
row = gtk_clist_append (channel_clist, texts);
gtk_clist_set_row_data (channel_clist, row, channel);
/* Update */
channel_update (channel);
/* Select it if no other is selected */
if (!ggui_channel_get_selected())
ggui_channel_select (jmchannel->url);
return channel;
}
static void
channel_update (Channel* channel)
{
GdkPixmap* pixmap;
GdkBitmap* mask;
gint row;
g_return_if_fail (channel);
/* Update icons */
ggui_get_pixmaps (channel->jmchannel->url, &pixmap, &mask);
row = gtk_clist_find_row_from_data (channel_clist, channel);
gtk_clist_set_pixtext (channel_clist, row, 0,
gnet_url_basename(channel->jmchannel->url),
5, pixmap, mask);
/* Update ggui_file */
if (channel == selected_channel)
{
if (jmchannel_is_up (channel->jmchannel))
{
if (!channel->shown)
channel->shown = channel->jmchannel->root_ann;
ggui_file_show (channel->jmchannel, channel->shown);
}
else
ggui_file_show (NULL, NULL);
}
}
static void
channel_delete (Channel* channel)
{
jmchannel_leave (channel->jmchannel);
jmchannel_delete (channel->jmchannel);
gnet_url_delete (channel->channel);
g_free (channel->path);
g_free (channel);
}
static void
channel_info (JMChannel* jmchannel, JMChannelType type,
JMAnn* ann, gpointer user_data)
{
/* Channel* channel = (Channel*) user_data; */
switch (type)
{
case JMCHANNEL_UPDATE:
{
ggui_file_announce_update (jmchannel, ann);
break;
}
case JMCHANNEL_REMOVE:
case JMCHANNEL_REMOVE_TIMEOUT:
{
Channel* channel;
g_return_if_fail (ann != jmchannel->root_ann);
channel = channel_get (jmchannel->url);
if (channel && channel->shown == ann)
{
channel->shown = jmchannel->root_ann;
ggui_file_show (channel->jmchannel, channel->shown);
}
ggui_file_announce_remove (jmchannel, ann);
break;
}
default:
g_assert_not_reached();
}
}
static void
channel_error (JMChannel* jmchannel, gpointer user_data)
{
Channel* channel = (Channel*) user_data;
channel_update (channel);
}
/* ******************** */
JMAnn*
ggui_channel_add_sha (const GURL* curl, const gchar* path,
const gchar* name, const GURL* url,
const GSHA* sha)
{
Channel* channel;
JMAnn* pann;
ElfNode* elf;
JMAnn* ann;
/* Get channel */
channel = channel_get (curl);
if (!channel)
return NULL;
/* Attempt to get parent */
pann = jmchannel_get (channel->jmchannel, path);
if (!pann)
return NULL;
if (jmann_get_child (pann, name))
return NULL;
elf = elf_new (NULL);
if (sha)
{
gchar shastr[2 * GNET_SHA_HASH_LENGTH + 1];
gnet_sha_copy_string (sha, shastr);
shastr[2 * GNET_SHA_HASH_LENGTH] = '\0';
elf_set_attribute (elf, "sha", shastr);
}
ann = jmchannel_add_elf (channel->jmchannel, pann, name, url, elf);
/* jmchannel_add will call our channel_info */
elf_delete (elf);
return ann;
}
JMAnn*
ggui_channel_add_path_sha (const GURL* curl, const gchar* path,
const GURL* url, const GSHA* sha)
{
Channel* channel;
ElfNode* elf;
JMAnn* ann;
/* Get channel */
channel = channel_get (curl);
if (!channel)
return NULL;
/* Get ann */
if (jmchannel_get (channel->jmchannel, path))
return NULL;
elf = elf_new (NULL);
if (sha)
{
gchar shastr[2 * GNET_SHA_HASH_LENGTH + 1];
gnet_sha_copy_string (sha, shastr);
shastr[2 * GNET_SHA_HASH_LENGTH] = '\0';
elf_set_attribute (elf, "sha", shastr);
}
ann = jmchannel_add_path_elf (channel->jmchannel, path, url, elf);
/* jmchannel_add will call our channel_info */
elf_delete (elf);
return ann;
}
void
ggui_channel_remove (const GURL* url, const gchar* path, const gchar* name)
{
Channel* channel;
JMAnn* pann;
JMAnn* ann;
channel = channel_get (url);
if (!channel)
return;
pann = jmchannel_get (channel->jmchannel, path);
if (!pann)
return;
if ((ann = jmann_get_child (pann, name)) == NULL)
return;
jmchannel_remove (channel->jmchannel, ann);
/* jmchannel_remove will call our channel_info */
}
void
ggui_channel_remove_path (const GURL* url, const gchar* path)
{
Channel* channel;
JMAnn* ann;
channel = channel_get (url);
if (!channel)
return;
ann = jmchannel_get (channel->jmchannel, path);
if (!ann)
return;
jmchannel_remove (channel->jmchannel, ann);
/* jmchannel_remove will call our channel_info */
}
/* ******************** */
void
ggui_channel_select (const GURL* url)
{
Channel* channel;
gint row;
g_return_if_fail (url);
channel = channel_get (url);
if (!channel)
return;
row = gtk_clist_find_row_from_data (channel_clist, channel);
if (row < 0) return;
gtk_clist_select_row (channel_clist, row, 0);
}
GURL*
ggui_channel_get_selected (void)
{
if (!selected_channel)
return NULL;
return selected_channel->jmchannel->url;
}
/* **************************************** */
void
on_channels_select_row (GtkCList* list, gint row, gint column, GdkEvent* event)
{
selected_channel = (Channel*) gtk_clist_get_row_data(list, row);
if (selected_channel)
{
if (jmchannel_is_up (selected_channel->jmchannel))
{
if (!selected_channel->shown)
selected_channel->shown = selected_channel->jmchannel->root_ann;
ggui_file_show (selected_channel->jmchannel, selected_channel->shown);
}
else
ggui_file_show (NULL, NULL);
}
else
ggui_file_show (NULL, NULL);
}
void
on_channels_unselect_row (GtkCList* list, gint row, gint column, GdkEvent* event)
{
/* Save selected file */
if (selected_channel)
{
JMChannel* chan = NULL;
JMAnn* ann = NULL;
ggui_file_get_shown (&chan, &ann);
if (chan == selected_channel->jmchannel)
selected_channel->shown = ann;
/* Otherwise, we may have previously called ggui_file_show.
This happens when we leave a channel then unselect the
channel. */
}
selected_channel = NULL;
ggui_file_show (NULL, NULL);
}
#define HIDE_MENUITEM(MI) do { \
GtkWidget* menu_item = glade_xml_get_widget(menu_xml, (MI)); \
g_return_val_if_fail (menu_item != NULL, TRUE); \
gtk_widget_hide(menu_item);} while (0)
#define SHOW_MENUITEM(MI) do { \
GtkWidget* menu_item = glade_xml_get_widget(menu_xml, (MI)); \
g_return_val_if_fail (menu_item != NULL, TRUE); \
gtk_widget_show(menu_item);} while (0)
/* Return TRUE if we handle event; FALSE to pass on */
gint
on_channels_button_press (GtkCList* list, GdkEventButton *event, gpointer user_data)
{
gint row, column;
gboolean rv = FALSE;
/* User double clicked - activate the thing selected */
if (event->type == GDK_2BUTTON_PRESS &&
(event->button == 1 || event->button == 2))
{
/* Get the selection information */
if (gtk_clist_get_selection_info(list, event->x, event->y, &row, &column))
{
/* Select the clicked row, if there is one */
gtk_clist_select_row (list, row, 0);
/* Double clicks on files and channels activate them. We
don't do anything for directories because that might be
annoying. */
if (selected_channel)
ggui_channel_join (selected_channel->jmchannel->url);
}
else
gtk_clist_unselect_all (list);
rv = TRUE;
}
/* User right-clicked - show context menu */
else if (event->type == GDK_BUTTON_PRESS && event->button == 3)
{
GList* i;
/* Select the clicked row, if there is one */
if (gtk_clist_get_selection_info (list, event->x, event->y, &row, &column))
gtk_clist_select_row (list, row, 0);
else
gtk_clist_unselect_all(list);
/* Hide everything */
for (i = GTK_MENU_SHELL(channel_popup)->children; i != NULL; i = i->next)
{
GtkWidget* menu_item = GTK_WIDGET(i->data);
g_return_val_if_fail (GTK_MENU_ITEM(menu_item) != NULL, FALSE);
gtk_widget_hide(menu_item);
}
SHOW_MENUITEM("open_channel_mi");
SHOW_MENUITEM("create_root_channel_mi");
/* Build the menu */
if (selected_channel)
{
if (selected_channel->jmchannel->is_local)
{
SHOW_MENUITEM("remove_channel_mi");
SHOW_MENUITEM("separator1");
}
else if (jmchannel_is_up(selected_channel->jmchannel))
{
SHOW_MENUITEM("leave_channel_mi");
SHOW_MENUITEM("remove_channel_mi");
SHOW_MENUITEM("separator1");
}
else
{
SHOW_MENUITEM("join_channel_mi");
SHOW_MENUITEM("remove_channel_mi");
SHOW_MENUITEM("separator1");
}
SHOW_MENUITEM("separator3");
SHOW_MENUITEM("properties_mi");
}
else
{
SHOW_MENUITEM("separator2");
SHOW_MENUITEM("exit_mi");
}
gtk_menu_popup (GTK_MENU(channel_popup), NULL, NULL, NULL,
NULL, 3, event->time);
rv = TRUE;
}
return rv;
}
POPUPFUNC (on_channels_join_channel)
{
g_return_if_fail (selected_channel);
ggui_channel_join (selected_channel->jmchannel->url);
}
POPUPFUNC (on_channels_open_channel)
{
ggui_channel_join (NULL);
}
POPUPFUNC (on_channels_create_root_channel)
{
ggui_channel_create (NULL, NULL, NULL);
}
POPUPFUNC (on_channels_remove_channel)
{
GURL* url;
g_return_if_fail (selected_channel);
url = selected_channel->jmchannel->url;
/*
TODO:
We do not elegantly handle the case where I'm leaving a channel
where I'm offering stuff. We might want to ask the user if
they're sure they want to leave the channel.
*/
if (selected_channel->jmchannel->is_local)
{
ggui_channel_delete (url);
}
else if (jmchannel_is_up(selected_channel->jmchannel))
{
ggui_channel_leave (url);
ggui_channel_delete (url);
}
else
{
ggui_channel_delete (url);
}
}
POPUPFUNC (on_channels_leave_channel)
{
g_return_if_fail (selected_channel);
ggui_channel_leave (selected_channel->jmchannel->url);
}
POPUPFUNC (on_channels_properties)
{
g_return_if_fail (selected_channel);
ggui_properties_show (selected_channel->jmchannel->url);
}
syntax highlighted by Code2HTML, v. 0.9.1