/* 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: Emote \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); */ }