/* 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_chat.h"
#include "ggui.h"
#include "ggui_channels.h"
#include "ggui_config.h"
#include "ggui_files.h"
#include "ggui_properties.h"
#include "entry_dialog.h"
#include "pixmaps.h"
#include "util/util.h"
#include "util/jmgnet.h"
#include "jmchat/jmchat.h"
#include "jmchannel/jmchannel.h"
/* ******************** */
typedef struct _Chat
{
JMChat* chat;
gchar* text;
GURL* channel;
gchar* path;
} Chat;
static GladeXML* menu_xml;
static GtkCList* chat_clist;
static GtkText* chat_text;
static GtkEntry* chat_entry;
static GtkLabel* chat_nickname;
static GtkContainer* chat_container;
static GtkWidget* chat_popup;
static gchar* nickname;
static GHashTable* url_to_chat;
static Chat* selected_chat;
/* ******************** */
static void shutdown_hfunc (gpointer key, gpointer value, gpointer user_data);
static void load_chat_func (const ElfNode* elf);
static void load_chat_ann_func (const ElfNode* elf);
static void save_chat_hfunc (gpointer key, gpointer value, gpointer user_data);
static void save_chat_ann_hfunc (gpointer key, gpointer value, gpointer user_data);
static void create (const GURL* channel, const gchar* path, const gchar* name);
static void join (const GURL* url);
static Chat* chat_new (JMChat* jmchat);
static void chat_update (Chat* chat);
#define chat_get(U) ((Chat*) g_hash_table_lookup(url_to_chat, U))
static void chat_delete (Chat* chat);
void on_chat_select_row (GtkCList* list, gint row, gint column, GdkEvent* event);
void on_chat_unselect_row (GtkCList* list, gint row, gint column, GdkEvent* event);
gint on_chat_button_press (GtkCList* list, GdkEventButton *event, gpointer user_data);
void on_chat_entry_activate (GtkEditable* editable, gpointer user_data);
static void chat_info_cb (JMChat* chat, JMChatMember* member,
JMChatType type, gchar* text1, gchar* text2,
gpointer user_data);
static void chat_error_cb (JMChat* chat, gpointer user_data);
static void my_text_insert (GtkText* text, gchar* str);
typedef enum
{
IT_CREATE,
IT_OPEN,
IT_JOIN,
IT_LEAVE,
IT_REMOVE,
IT_SEPARATOR1,
IT_SEPARATOR2,
IT_PROPERTIES,
} Item;
static void toolbar_append (Item item, GdkPixmap* gpixmap, GdkBitmap* gbitmap,
const gchar* tooltip, void* func);
static void update_toolbar (void);
static void update_items (void* widget);
static void show_item (void* widget, Item it);
#define POPUPFUNC(F) void F(gpointer callback_data, guint callback_action, GtkWidget* widget)
POPUPFUNC(on_chat_join);
POPUPFUNC(on_chat_leave);
POPUPFUNC(on_chat_remove);
POPUPFUNC(on_chat_create);
POPUPFUNC(on_chat_open);
POPUPFUNC(on_chat_properties);
/* ************************************************************ */
void
ggui_chat_init(void)
{
menu_xml = ggui_get_glade_xml("chat_popup", "master_popup.glade");
g_assert (menu_xml != NULL);
glade_xml_signal_autoconnect(menu_xml);
chat_clist = GTK_CLIST(glade_xml_get_widget(jmw_xml, "chat_clist"));
chat_text = GTK_TEXT(glade_xml_get_widget(jmw_xml, "chat_text"));
chat_entry = GTK_ENTRY(glade_xml_get_widget(jmw_xml, "chat_entry"));
chat_nickname = GTK_LABEL(glade_xml_get_widget(jmw_xml, "chat_nickname"));
chat_container = GTK_CONTAINER(glade_xml_get_widget(jmw_xml, "chat_container"));
chat_popup = GTK_WIDGET(glade_xml_get_widget(menu_xml, "chat_popup"));
g_assert (chat_clist);
g_assert (chat_text);
g_assert (chat_entry);
g_assert (chat_nickname);
g_assert (chat_container);
g_assert (chat_popup);
gtk_widget_set_sensitive (GTK_WIDGET(chat_container), FALSE);
nickname = ggui_chat_get_nickname ();
gtk_label_set_text (chat_nickname, nickname);
url_to_chat = g_hash_table_new (gnet_url_hash, gnet_url_equal);
/* TODO: tooltips */
/* ggui_set_tooltip (GTK_WIDGET(channels_clist), _("Channels you have joined.")); */
}
void
ggui_chat_shutdown (void)
{
/* Delete chats */
g_hash_table_foreach (url_to_chat, shutdown_hfunc, NULL);
g_hash_table_destroy (url_to_chat);
url_to_chat = NULL;
selected_chat = NULL;
/* Save nickname */
if (nickname)
ggui_config_set_string ("/Jungle Monkey/Chat/Nickname", nickname);
}
void
shutdown_hfunc (gpointer key, gpointer value, gpointer user_data)
{
Chat* chat = (Chat*) value;
chat_delete (chat);
}
void
ggui_chat_load (void)
{
ggui_load_elf ("chat", load_chat_func);
ggui_load_elf ("chat-announce", load_chat_ann_func);
}
static void
load_chat_func (const ElfNode* elf)
{
const gchar* name;
const gchar* url_str;
GURL* url = NULL;
JMChat* jmchat = 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)
jmchat = jmchat_create (jm_btp_bpeer, name, nickname);
else if (!strcmp (elf->name, "join") && url && !chat_get(url))
jmchat = jmchat_join (jm_btp_bpeer, url, nickname);
else if (!strcmp (elf->name, "setup") && url && !chat_get(url))
jmchat = jmchat_setup (jm_btp_bpeer, url, nickname);
if (jmchat)
chat_new (jmchat);
gnet_url_delete (url);
}
static void
load_chat_ann_func (const ElfNode* elf)
{
const gchar* curl_str;
const gchar* url_str;
const gchar* path;
GURL* curl = NULL;
GURL* url = NULL;
Chat* chat;
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);
chat = chat_get (url);
if (!chat || chat->channel) goto done; /* TODO: Multiple paths */
ann = ggui_channel_add_path (curl, path, url);
if (!ann) goto done;
chat->channel = curl; curl = NULL;
chat->path = g_strdup (ann->path);
done:
gnet_url_delete (url);
gnet_url_delete (curl);
}
void
ggui_chat_save (void)
{
ggui_save_hashtable ("chat", url_to_chat, save_chat_hfunc);
ggui_save_hashtable ("chat-announce", url_to_chat, save_chat_ann_hfunc);
}
static void
save_chat_hfunc (gpointer key, gpointer value, gpointer user_data)
{
Chat* chat = (Chat*) value;
FILE* file = (FILE*) user_data;
ElfNode* elf;
gchar* buf;
gint len;
elf = elf_new (NULL);
if (chat->chat->is_local)
{
elf_set_name (elf, "create");
elf_set_attribute (elf, "name", gnet_url_basename (chat->chat->url));
}
else if (jmchat_is_up (chat->chat))
{
gchar* url_str;
elf_set_name (elf, "join");
url_str = gnet_url_get_nice_string (chat->chat->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 (chat->chat->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_chat_ann_hfunc (gpointer key, gpointer value, gpointer user_data)
{
Chat* chat = (Chat*) value;
FILE* file = (FILE*) user_data;
gchar* curl;
gchar* url;
ElfNode* elf;
gchar* buf;
gint len;
if (!(chat->channel && chat->path))
return;
url = gnet_url_get_nice_string (chat->chat->url);
curl = gnet_url_get_nice_string (chat->channel);
elf = elf_new_format ("ann", "sss", "curl", curl, "path", chat->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);
}
/* ******************** */
JMChat*
ggui_chat_get (const GURL* url)
{
Chat* chat;
g_return_val_if_fail (url, NULL);
chat = (Chat*) g_hash_table_lookup (url_to_chat, url);
if (!chat)
return NULL;
return chat->chat;
}
gboolean
ggui_chat_is_up (const GURL* url)
{
JMChat* jmchat;
g_return_val_if_fail (url, FALSE);
jmchat = ggui_chat_get (url);
if (!jmchat)
return FALSE;
return jmchat_is_up (jmchat);
}
gboolean
ggui_chat_is_down (const GURL* url)
{
JMChat* jmchat;
g_return_val_if_fail (url, FALSE);
jmchat = ggui_chat_get (url);
if (!jmchat)
return FALSE;
return jmchat_is_down (jmchat);
}
gchar*
ggui_chat_get_properties (const GURL* url)
{
JMChat* jmchat;
jmchat = ggui_chat_get (url);
if (!jmchat)
return g_strdup ("");
return g_strdup_printf (_("Chat %s\n"), gnet_url_basename(url));
}
/* ******************** */
static EntryDialog* create_chat_dialog;
static GURL* create_chat_channel;
static gchar* create_chat_path;
static void create_ok (gchar* chat_name, gchar* ignore);
static void create_cancel (void);
void
ggui_chat_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_chat_dialog)
{
entry_dialog_show (create_chat_dialog);
return;
}
if (channel && path)
{
create_chat_channel = gnet_url_clone (channel);
create_chat_path = g_strdup (path);
}
create_chat_dialog = entry_dialog_new(_("Create chat"),
_("Chat name"), NULL,
create_ok, create_cancel);
return;
}
create (channel, path, name);
}
static void
create_ok (gchar* chat_name, gchar* ignore)
{
create (create_chat_channel, create_chat_path, chat_name);
create_cancel ();
}
static void
create_cancel (void)
{
create_chat_dialog = NULL;
gnet_url_delete (create_chat_channel);
create_chat_channel = NULL;
g_free (create_chat_path);
create_chat_path = NULL;
}
static void
create (const GURL* channel, const gchar* path, const gchar* name)
{
JMChat* jmchat;
Chat* chat;
g_return_if_fail (name);
g_return_if_fail ((channel && path) || !(channel && path));
/* Check if path ok */
if (channel && path && !ggui_channel_check_path (channel, path, name))
return;
/* Create the channel */
jmchat = jmchat_create (jm_btp_bpeer, name, nickname);
if (!jmchat)
{
ggui_show_message ("warning", _("Could not create chat \"%s\"\n"), name);
return;
}
/* Add it */
chat = chat_new (jmchat);
g_return_if_fail (chat);
/* Announce it */
if (channel && path)
{
JMAnn* ann;
ann = ggui_channel_add (channel, path, name, jmchat->url);
g_return_if_fail (ann);
chat->channel = gnet_url_clone (channel);
chat->path = g_strdup (ann->path);
}
}
/* ********** */
static EntryDialog* join_dialog = NULL;
static void join_ok (gchar* url, gchar* ignore);
static void join_cancel (void);
void
ggui_chat_join (const GURL* url)
{
Chat* chat;
/* Prompt for name if not given */
if (!url)
{
if (join_dialog)
{
entry_dialog_show (join_dialog);
return;
}
join_dialog = entry_dialog_new(_("Open chat"),
_("Chat URL"), NULL,
join_ok, join_cancel);
return;
}
/* Check if chat exists */
chat = (Chat*) g_hash_table_lookup (url_to_chat, url);
if (chat)
{
if (!jmchat_is_up (chat->chat))
{
jmchat_rejoin (chat->chat);
chat_update (chat);
}
return;
}
/* Create it */
join (url);
}
static void
join_ok (gchar* url, gchar* ignore)
{
GURL* gurl;
gurl = gnet_url_new (url);
if (gurl && gnet_url_is_scheme(gurl, "jmchat"))
{
join (gurl);
gnet_url_delete (gurl);
}
else
{
ggui_show_message ("warning", _("Malformed URL: %s (should be jmchat://something)\n"));
}
join_cancel ();
}
static void
join_cancel(void)
{
join_dialog = NULL;
}
static void
join (const GURL* url)
{
Chat* chat;
JMChat* jmchat;
g_return_if_fail (url);
/* Check if chat exists */
chat = (Chat*) g_hash_table_lookup (url_to_chat, url);
if (chat)
{
if (!jmchat_is_up (chat->chat))
{
jmchat_rejoin (chat->chat);
chat_update (chat);
}
ggui_show_message ("warning", _("Chat is already open\n"));
return;
}
/* Create chat */
jmchat = jmchat_join (jm_btp_bpeer, url, nickname);
if (!jmchat)
{
ggui_show_message ("warning", _("Could not open chat\n"));
return;
}
/* Add it */
chat = chat_new (jmchat);
g_return_if_fail (chat);
}
/* ********** */
void
ggui_chat_leave (const GURL* url)
{
Chat* chat;
g_return_if_fail (url);
/* Get chat */
chat = (Chat*) g_hash_table_lookup (url_to_chat, url);
if (!chat)
return;
/* Leave group */
jmchat_leave (chat->chat);
g_free (chat->text);
chat->text = NULL;
/* Unselect chat */
if (chat == selected_chat)
{
gtk_editable_delete_text (GTK_EDITABLE(chat_text), 0, -1);
gtk_widget_set_sensitive (GTK_WIDGET(chat_container), FALSE);
}
chat_update (chat);
}
void
ggui_chat_remove (const GURL* url)
{
Chat* chat;
gint row;
g_return_if_fail (url);
/* Get chat */
chat = chat_get (url);
if (!chat)
return;
g_hash_table_remove (url_to_chat, url);
/* Remove the chat from the list (this will unselect the chat if it
is selected) */
row = gtk_clist_find_row_from_data (chat_clist, chat);
if (row >= 0)
gtk_clist_remove (chat_clist, row);
/* Send remove */
if (chat->chat->is_local && chat->channel && chat->path)
ggui_channel_remove_path (chat->channel, chat->path);
/* remove_path may delete url */
/* Delete group */
chat_delete (chat);
}
gchar*
ggui_chat_get_nickname (void)
{
/* Try using config */
if (nickname == NULL)
{
nickname =
ggui_config_get_string ("/Jungle Monkey/Chat/Nickname", NULL);
/* Try g_get_user_name */
if (!nickname && (nickname = g_get_user_name()))
nickname = g_strdup (nickname);
/* Try g_get_real_name */
if (!nickname && (nickname = g_get_real_name()))
nickname = g_strdup (nickname);
if (!nickname)
nickname = g_strdup ("Anonymous Monkey");
}
return nickname;
}
void
ggui_chat_set_nickname (const gchar* nick)
{
g_return_if_fail (nick);
if (nickname)
g_free (nickname);
nickname = g_strdup (nick);
gtk_label_set_text (chat_nickname, nickname);
}
void
ggui_chat_select (const GURL* url)
{
Chat* chat;
gint row;
g_return_if_fail (url);
/* Get chat */
chat = (Chat*) g_hash_table_lookup (url_to_chat, url);
if (!chat)
return;
row = gtk_clist_find_row_from_data (chat_clist, chat);
if (row >= 0)
gtk_clist_select_row (chat_clist, row, 0);
}
GURL*
ggui_chat_get_selected (void)
{
if (selected_chat)
return selected_chat->chat->url;
return NULL;
}
/* **************************************** */
static Chat*
chat_new (JMChat* jmchat)
{
Chat* chat;
gchar* texts[2] = {NULL, NULL};
gint row;
g_return_val_if_fail (jmchat, NULL);
g_return_val_if_fail (jmchat->url, NULL);
/* Make sure chat isn't there */
chat = (Chat*) g_hash_table_lookup (url_to_chat, jmchat->url);
g_return_val_if_fail (!chat, NULL);
/* Create new chat */
chat = g_new0 (Chat, 1);
chat->chat = jmchat;
g_hash_table_insert (url_to_chat, jmchat->url, chat);
/* Initialize it */
jmchat->info_func = chat_info_cb;
jmchat->error_func = chat_error_cb;
jmchat->user_data = chat;
/* Add to clist */
texts[0] = gnet_url_basename (jmchat->url);
row = gtk_clist_append (chat_clist, texts);
gtk_clist_set_row_data (chat_clist, row, chat);
/* Update */
chat_update (chat);
/* Select it if no other is selected */
if (!ggui_chat_get_selected())
ggui_chat_select (jmchat->url);
return chat;
}
static void
chat_update (Chat* chat)
{
GdkPixmap* pixmap;
GdkBitmap* mask;
gint row;
GURL* url;
g_return_if_fail (chat);
url = chat->chat->url;
/* Update icons */
ggui_get_pixmaps (url, &pixmap, &mask);
row = gtk_clist_find_row_from_data (chat_clist, chat);
gtk_clist_set_pixtext (chat_clist, row, 0,
gnet_url_basename(url), 5, pixmap, mask);
/* Set sensitivity */
if (chat == selected_chat)
{
update_toolbar ();
gtk_widget_set_sensitive (GTK_WIDGET(chat_container), jmchat_is_up(chat->chat));
}
/* Update files */
ggui_file_update (url);
}
static void
chat_delete (Chat* chat)
{
jmchat_leave (chat->chat);
jmchat_delete (chat->chat);
g_free (chat->text);
gnet_url_delete (chat->channel);
g_free (chat->path);
g_free (chat);
}
/* **************************************** */
static void
chat_info_cb (JMChat* jmchat, JMChatMember* member,
JMChatType type, gchar* text1, gchar* text2,
gpointer user_data)
{
Chat* chat = (Chat*) user_data;
gchar* str = NULL;
g_return_if_fail (member);
switch (type)
{
case JMCHAT_JOIN:
{
str = g_strdup_printf (_("-> %s has joined\n"), member->nick);
break;
}
case JMCHAT_LEAVE:
{
str = g_strdup_printf (_("<- %s has left\n"), member->nick);
break;
}
case JMCHAT_LEAVE_TIMEOUT:
{
str = g_strdup_printf (_("<- %s has left (timeout)\n"), member->nick);
break;
}
case JMCHAT_SAY:
{
g_return_if_fail (text1);
if (!text2)
str = g_strdup_printf (_("%s: %s\n"), member->nick, text1);
else
str = g_strdup_printf (_("%s %s\n"), member->nick, text1);
break;
}
default:
break;;
}
if (str)
{
if (chat == selected_chat)
{
my_text_insert (chat_text, str);
}
else
{
if (chat->text)
{
gchar* temp;
temp = g_strconcat (chat->text, str, NULL);
g_free (chat->text);
chat->text = temp;
}
else
chat->text = g_strdup (str);
}
g_free (str);
}
}
static void
chat_error_cb (JMChat* jmchat, gpointer user_data)
{
chat_update ((Chat*) user_data);
}
/* **************************************** */
void
on_chat_select_row (GtkCList* list, gint row, gint column, GdkEvent* event)
{
Chat* new_selected_chat;
new_selected_chat = (Chat*) gtk_clist_get_row_data(list, row);
if (new_selected_chat == selected_chat)
return;
/* Save the text of the old selected chat */
if (selected_chat)
{
gchar* text;
text = gtk_editable_get_chars (GTK_EDITABLE(chat_text), 0, -1);
g_return_if_fail (text);
if (selected_chat->text)
g_free (selected_chat->text);
selected_chat->text = text;
}
/* Restore the text of the new selected chat */
if (new_selected_chat)
{
gtk_editable_delete_text (GTK_EDITABLE(chat_text), 0, -1);
if (new_selected_chat->text)
{
gtk_text_insert (chat_text, NULL, NULL, NULL,
new_selected_chat->text,
strlen(new_selected_chat->text));
gtk_text_set_point (chat_text, gtk_text_get_length (chat_text));
}
}
selected_chat = new_selected_chat;
gtk_widget_set_sensitive (GTK_WIDGET(chat_container),
(selected_chat != NULL && jmchat_is_up (selected_chat->chat)));
update_toolbar();
}
void
on_chat_unselect_row (GtkCList* list, gint row, gint column, GdkEvent* event)
{
/* Save the text of the old selected chat */
if (selected_chat)
{
gchar* text;
text = gtk_editable_get_chars (GTK_EDITABLE(chat_text), 0, -1);
g_return_if_fail (text);
if (selected_chat->text)
g_free (selected_chat->text);
selected_chat->text = text;
gtk_editable_delete_text (GTK_EDITABLE(chat_text), 0, -1);
}
selected_chat = NULL;
gtk_widget_set_sensitive (GTK_WIDGET(chat_container), FALSE);
update_toolbar();
}
/* Return TRUE if we handle event; FALSE to pass on */
gint
on_chat_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 chats activates them. */
if (selected_chat && !jmchat_is_up(selected_chat->chat))
ggui_chat_join (selected_chat->chat->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(chat_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);
}
/* Update the popup menu */
update_items (NULL);
/* Pop up */
gtk_menu_popup (GTK_MENU(chat_popup), NULL, NULL,
NULL, NULL, 3, event->time);
rv = TRUE;
}
return rv;
}
void
on_chat_entry_activate (GtkEditable* editable, gpointer user_data)
{
gchar* text;
gchar* str;
g_return_if_fail (chat_entry);
g_return_if_fail (selected_chat);
text = gtk_entry_get_text (chat_entry);
if (!text)
return;
if (text[0] != '/')
{
/* Check if 'say' */
if (text[0] != ':')
{
str = g_strdup_printf (_("%s: %s\n"), nickname, text);
my_text_insert (chat_text, str);
g_free (str);
if (jmchat_is_up (selected_chat->chat))
jmchat_say (selected_chat->chat, text, FALSE);
}
/* Otherwise, is emote */
else
{
str = g_strdup_printf (_("%s %s\n"), nickname, &text[1]);
my_text_insert (chat_text, str);
g_free (str);
if (jmchat_is_up (selected_chat->chat))
jmchat_say (selected_chat->chat, &text[1], TRUE);
}
}
else
{
if (!SAFESTRCMP (&text[1], _("help")))
{
my_text_insert (chat_text,
_("\nCommands:\n"
"\t/who List users in this group\n"
"\t:<mesg> Emote <mesg>\n"
"\n"));
}
else if (!SAFESTRCMP (&text[1], "who"))
{
GSList* i;
my_text_insert (chat_text, _("\nMembers:\n"));
for (i = selected_chat->chat->members; i != NULL; i = i->next)
{
JMChatMember* member = (JMChatMember*) i->data;
gchar* str;
str = g_strdup_printf (_("\t%s\n"), member->nick);
my_text_insert (chat_text, str);
g_free (str);
}
my_text_insert (chat_text, "\n");
}
else
{
my_text_insert (chat_text, _("Unknown command. Try /help\n"));
}
}
gtk_entry_set_text (chat_entry, "");
}
void
ggui_chat_show_toolbar (void)
{
/* Add everything to the toolbar */
toolbar_append (IT_OPEN, chat_pixmap, chat_mask,
_("Open chat"), on_chat_open);
toolbar_append (IT_CREATE, create_chat_pixmap, create_chat_mask,
_("Create chat"), on_chat_create);
toolbar_append (IT_JOIN, join_chat_pixmap, join_chat_mask,
_("Join chat"), on_chat_join);
toolbar_append (IT_LEAVE, leave_chat_pixmap, leave_chat_mask,
_("Leave chat"), on_chat_leave);
/* FIX: X */
/* Update the toolbar */
update_toolbar();
}
static void
toolbar_append (Item item, GdkPixmap* gpixmap, GdkBitmap* gbitmap,
const gchar* tooltip, void* func)
{
GtkPixmap* pixmap;
GtkWidget* widget;
pixmap = (GtkPixmap*) gtk_pixmap_new (gpixmap, gbitmap);
g_return_if_fail (pixmap);
widget = gtk_toolbar_append_item (jmw_toolbar, NULL,
tooltip, "private",
GTK_WIDGET(pixmap),
(GtkSignalFunc) func, NULL);
g_return_if_fail (widget);
gtk_object_set_user_data (GTK_OBJECT(widget), (gpointer) item);
}
static void
update_toolbar (void)
{
GList* kids;
GList* i;
/* Hide all */
kids = gtk_container_children (GTK_CONTAINER(jmw_toolbar));
for (i = kids; i != NULL; i = i->next)
gtk_widget_set_sensitive (GTK_WIDGET(i->data), FALSE);
/* Update toolbar */
update_items (kids);
g_list_free (kids);
}
/* **************************************** */
static const char* item_mi_name[] =
{
"create_mi",
"open_mi",
"join_mi",
"leave_mi",
"remove_mi",
"separator1",
"separator2",
"properties_mi",
};
static void
update_items (void* widget)
{
show_item (widget, IT_OPEN);
show_item (widget, IT_CREATE);
/* Build the menu */
if (selected_chat)
{
show_item (widget, IT_SEPARATOR1);
if (selected_chat->chat->is_local)
show_item (widget, IT_REMOVE);
else if (jmchat_is_up (selected_chat->chat))
{
show_item (widget, IT_LEAVE);
show_item (widget, IT_REMOVE);
}
else
{
show_item (widget, IT_JOIN);
show_item (widget, IT_REMOVE);
}
show_item (widget, IT_SEPARATOR2);
show_item (widget, IT_PROPERTIES);
}
}
static void
show_item (void* widget, Item it)
{
if (!widget) /* Popup menu */
{
GtkWidget* menu_item = glade_xml_get_widget(menu_xml, item_mi_name[it]);
if (menu_item)
gtk_widget_show(menu_item);
}
else /* Toolbar */
{
GList* kids = (GList*) widget;
GList* i;
for (i = kids; i != NULL; i = i->next)
{
if (it == (guint) gtk_object_get_user_data(GTK_OBJECT(i->data)))
{
gtk_widget_set_sensitive (GTK_WIDGET(i->data), TRUE);
break;
}
}
}
}
POPUPFUNC(on_chat_join)
{
g_return_if_fail (selected_chat);
ggui_chat_join (selected_chat->chat->url);
}
POPUPFUNC(on_chat_leave)
{
g_return_if_fail (selected_chat);
ggui_chat_leave (selected_chat->chat->url);
}
POPUPFUNC(on_chat_remove)
{
GURL* url;
g_return_if_fail (selected_chat);
url = selected_chat->chat->url;
if (selected_chat->chat->is_local)
{
ggui_chat_remove (url);
}
else if (jmchat_is_up(selected_chat->chat))
{
ggui_chat_leave (url);
ggui_chat_remove (url);
}
else
{
ggui_chat_remove (url);
}
}
POPUPFUNC(on_chat_create)
{
ggui_chat_create (NULL, NULL, NULL);
}
POPUPFUNC(on_chat_open)
{
ggui_chat_join (NULL);
}
POPUPFUNC(on_chat_properties)
{
g_return_if_fail (selected_chat);
ggui_properties_show (selected_chat->chat->url);
}
/**
What I want to do is this:
If the scroll bar is at the bottom, insert the text and scroll down.
If the scroll bar is not at the bottom, insert the text without
moving the scroll bar.
I can't figure out how to do this.
*/
static void
my_text_insert (GtkText* text, gchar* str)
{
/* guint old_point; */
/* guint old_position; */
/* guint length; */
guint str_len;
/* gtk_text_freeze (text); */
/* old_point = gtk_text_get_point (text); */
/* old_position = gtk_editable_get_position (GTK_EDITABLE(text)); */
/* length = gtk_text_get_length (text); */
str_len = strlen(str);
/* g_print ("OLD: position = %d, point = %d, length = %d, str_len = %d\n", */
/* old_position, old_point, length, str_len); */
/* g_print ("OLD vert adj value = %f, upper = %f, stepinc = %f, pageinc = %f, pagesize = %f\n", text->vadj->value, text->vadj->upper, text->vadj->step_increment, text->vadj->page_increment, text->vadj->page_size); */
gtk_text_insert (text, NULL, NULL, NULL, str, str_len);
/* gtk_editable_insert_text (GTK_EDITABLE(text), str, str_len, &length); */
/* g_print ("NEW: position = %d, point = %d, length = %d\n", */
/* gtk_editable_get_position (GTK_EDITABLE(text)), */
/* gtk_text_get_point (text), */
/* gtk_text_get_length (text)); */
/* g_print ("NEW vert adj value = %f, upper = %f, stepinc = %f, pageinc = %f, pagesize = %f\n", text->vadj->value, text->vadj->upper, text->vadj->step_increment, text->vadj->page_increment, text->vadj->page_size); */
/* Move point back if they had scrolled up */
/* if (old_position == length) */
/* gtk_editable_set_position (GTK_EDITABLE(text), length + str_len); */
/* Otherwise move to the end */
/* else */
/* gtk_editable_set_position (GTK_EDITABLE(text), old_position); */
/* if (old_point == length) */
/* { */
/* g_print ("set old point\n"); */
/* gtk_text_set_point (text, length + str_len); */
/* } */
/* else */
/* { */
/* g_print ("set bottom point\n"); */
/* gtk_text_set_point (text, old_point); */
/* } */
/* gtk_editable_changed (GTK_EDITABLE (text)); */
/* gtk_text_thaw (text); */
}
syntax highlighted by Code2HTML, v. 0.9.1