comparison src/gtkconv.c @ 11581:9b3833da6840

[gaim-migrate @ 13851] goodbye GaimConvWindow. Still some problems with this patch: - Scarey warnings console with gaim -d when closing tab - I tried to seperate gtkconv and gtkconvwin, but failed, as a result it has its own header, but the code is in the same file, which is rather weird. Also some code got moved around for no good reason. Feel free to move it back or reorganize it. - I broke the gesters plugin, and just disabled it. Hopefully someone with more time will fix it, it shouldn't take long, but I didn't feel like bothering. - This list is incomplete. committer: Tailor Script <tailor@pidgin.im>
author Tim Ringenbach <marv@pidgin.im>
date Sun, 02 Oct 2005 00:32:49 +0000
parents 7fbf5e4e8f5f
children d35e4f1e9f43
comparison
equal deleted inserted replaced
11580:24169af08585 11581:9b3833da6840
50 #include "util.h" 50 #include "util.h"
51 51
52 #include "gtkdnd-hints.h" 52 #include "gtkdnd-hints.h"
53 #include "gtkblist.h" 53 #include "gtkblist.h"
54 #include "gtkconv.h" 54 #include "gtkconv.h"
55 #include "gtkconvwin.c"
55 #include "gtkdialogs.h" 56 #include "gtkdialogs.h"
56 #include "gtkimhtml.h" 57 #include "gtkimhtml.h"
57 #include "gtkimhtmltoolbar.h" 58 #include "gtkimhtmltoolbar.h"
58 #include "gtklog.h" 59 #include "gtklog.h"
59 #include "gtkmenutray.h" 60 #include "gtkmenutray.h"
98 {0, 9728, 50944, 9728} /* Accent Green Dark */ 99 {0, 9728, 50944, 9728} /* Accent Green Dark */
99 }; 100 };
100 101
101 #define NUM_NICK_COLORS (sizeof(nick_colors) / sizeof(*nick_colors)) 102 #define NUM_NICK_COLORS (sizeof(nick_colors) / sizeof(*nick_colors))
102 103
103 typedef struct 104 typedef struct {
104 {
105 GtkWidget *window; 105 GtkWidget *window;
106 106
107 GtkWidget *entry; 107 GtkWidget *entry;
108 GtkWidget *message; 108 GtkWidget *message;
109 109
111 111
112 } InviteBuddyInfo; 112 } InviteBuddyInfo;
113 113
114 static GtkWidget *invite_dialog = NULL; 114 static GtkWidget *invite_dialog = NULL;
115 static GtkWidget *warn_close_dialog = NULL; 115 static GtkWidget *warn_close_dialog = NULL;
116
117 static gboolean update_send_as_selection(GaimGtkWindow *win);
118 static void generate_send_as_items(GaimGtkWindow *win, GaimConversation *deleted_conv);
119
120
116 121
117 /* Prototypes. <-- because Paco-Paco hates this comment. */ 122 /* Prototypes. <-- because Paco-Paco hates this comment. */
118 static void got_typing_keypress(GaimGtkConversation *gtkconv, gboolean first); 123 static void got_typing_keypress(GaimGtkConversation *gtkconv, gboolean first);
119 static GList *generate_invite_user_names(GaimConnection *gc); 124 static GList *generate_invite_user_names(GaimConnection *gc);
120 static void add_chat_buddy_common(GaimConversation *conv, const char *name, 125 static void add_chat_buddy_common(GaimConversation *conv, const char *name,
121 const char *alias, const char *old_name); 126 const char *alias, const char *old_name);
122 static gboolean tab_complete(GaimConversation *conv); 127 static gboolean tab_complete(GaimConversation *conv);
123 static void update_typing_icon(GaimGtkConversation *gtkconv); 128 static void update_typing_icon(GaimGtkConversation *gtkconv);
124 static gboolean update_send_as_selection(GaimConvWindow *win);
125 static char *item_factory_translate_func (const char *path, gpointer func_data); 129 static char *item_factory_translate_func (const char *path, gpointer func_data);
126 130
127 static GdkColor *get_nick_color(GaimGtkConversation *gtkconv, const char *name) { 131 static GdkColor *get_nick_color(GaimGtkConversation *gtkconv, const char *name) {
128 static GdkColor col; 132 static GdkColor col;
129 GtkStyle *style = gtk_widget_get_style(gtkconv->imhtml); 133 GtkStyle *style = gtk_widget_get_style(gtkconv->imhtml);
141 } 145 }
142 146
143 return &col; 147 return &col;
144 } 148 }
145 149
146 static void
147 do_close(GtkWidget *w, int resp, GaimConvWindow *win)
148 {
149 gtk_widget_destroy(warn_close_dialog);
150 warn_close_dialog = NULL;
151
152 if (resp == GTK_RESPONSE_OK)
153 gaim_conv_window_destroy(win);
154 }
155
156 static void build_warn_close_dialog(GaimConvWindow *win)
157 {
158 GaimGtkWindow *gtkwin;
159 GtkWidget *label;
160 GtkWidget *vbox, *hbox;
161 GtkWidget *img;
162
163 g_return_if_fail(warn_close_dialog == NULL);
164
165 gtkwin = GAIM_GTK_WINDOW(win);
166
167 warn_close_dialog = gtk_dialog_new_with_buttons(
168 _("Confirm close"),
169 GTK_WINDOW(gtkwin->window), GTK_DIALOG_MODAL,
170 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
171 GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL);
172
173 gtk_dialog_set_default_response(GTK_DIALOG(warn_close_dialog),
174 GTK_RESPONSE_OK);
175
176 gtk_container_set_border_width(GTK_CONTAINER(warn_close_dialog),
177 6);
178 gtk_window_set_resizable(GTK_WINDOW(warn_close_dialog), FALSE);
179 gtk_dialog_set_has_separator(GTK_DIALOG(warn_close_dialog),
180 FALSE);
181
182 /* Setup the outside spacing. */
183 vbox = GTK_DIALOG(warn_close_dialog)->vbox;
184
185 gtk_box_set_spacing(GTK_BOX(vbox), 12);
186 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
187
188 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_WARNING,
189 GTK_ICON_SIZE_DIALOG);
190 /* Setup the inner hbox and put the dialog's icon in it. */
191 hbox = gtk_hbox_new(FALSE, 12);
192 gtk_container_add(GTK_CONTAINER(vbox), hbox);
193 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
194 gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
195
196 /* Setup the right vbox. */
197 vbox = gtk_vbox_new(FALSE, 12);
198 gtk_container_add(GTK_CONTAINER(hbox), vbox);
199
200 label = gtk_label_new(_("You have unread messages. Are you sure you want to close the window?"));
201 gtk_widget_set_size_request(label, 350, -1);
202 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
203 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
204 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
205
206 /* Connect the signals. */
207 g_signal_connect(G_OBJECT(warn_close_dialog), "response",
208 G_CALLBACK(do_close), win);
209
210 }
211
212 /************************************************************************** 150 /**************************************************************************
213 * Callbacks 151 * Callbacks
214 **************************************************************************/ 152 **************************************************************************/
215 static gboolean
216 close_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d)
217 {
218 GaimConvWindow *win = (GaimConvWindow *)d;
219 GList *l;
220
221 /* If there are unread messages then show a warning dialog */
222 for (l = gaim_conv_window_get_conversations(win);
223 l != NULL; l = l->next)
224 {
225 GaimConversation *conv = l->data;
226 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM &&
227 gaim_conversation_get_unseen(conv) == GAIM_UNSEEN_TEXT)
228 {
229 build_warn_close_dialog(win);
230 gtk_widget_show_all(warn_close_dialog);
231
232 return TRUE;
233 }
234 }
235
236 gaim_conv_window_destroy(win);
237
238 return TRUE;
239 }
240
241 /*
242 * When a conversation window is focused, we know the user
243 * has looked at it so we know there are no longer unseen
244 * messages.
245 */
246 static gint
247 focus_win_cb(GtkWidget *w, GdkEventFocus *e, gpointer d)
248 {
249 GaimConvWindow *win = (GaimConvWindow *)d;
250 GaimConversation *conv = gaim_conv_window_get_active_conversation(win);
251
252 gaim_conversation_set_unseen(conv, GAIM_UNSEEN_NONE);
253
254 return FALSE;
255 }
256 153
257 static gint 154 static gint
258 close_conv_cb(GtkWidget *w, GaimGtkConversation *gtkconv) 155 close_conv_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
259 { 156 {
260 GList *list = g_list_copy(gtkconv->convs), *l; 157 GList *list = g_list_copy(gtkconv->convs), *l;
304 if (w == gtkconv->entry) 201 if (w == gtkconv->entry)
305 gaim_prefs_set_int("/gaim/gtk/conversations/chat/entry_height", allocation->height); 202 gaim_prefs_set_int("/gaim/gtk/conversations/chat/entry_height", allocation->height);
306 } 203 }
307 204
308 return FALSE; 205 return FALSE;
309 }
310
311 /* Courtesy of Galeon! */
312 static void
313 tab_close_button_state_changed_cb(GtkWidget *widget, GtkStateType prev_state)
314 {
315 if (GTK_WIDGET_STATE(widget) == GTK_STATE_ACTIVE)
316 gtk_widget_set_state(widget, GTK_STATE_NORMAL);
317 } 206 }
318 207
319 static void 208 static void
320 default_formatize(GaimGtkConversation *c) 209 default_formatize(GaimGtkConversation *c)
321 { 210 {
857 GaimConversation *conv = gtkconv->active_conv; 746 GaimConversation *conv = gtkconv->active_conv;
858 InviteBuddyInfo *info = NULL; 747 InviteBuddyInfo *info = NULL;
859 748
860 if (invite_dialog == NULL) { 749 if (invite_dialog == NULL) {
861 GaimConnection *gc; 750 GaimConnection *gc;
862 GaimConvWindow *win;
863 GaimGtkWindow *gtkwin; 751 GaimGtkWindow *gtkwin;
864 GtkWidget *label; 752 GtkWidget *label;
865 GtkWidget *vbox, *hbox; 753 GtkWidget *vbox, *hbox;
866 GtkWidget *table; 754 GtkWidget *table;
867 GtkWidget *img; 755 GtkWidget *img;
868 756
869 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION, 757 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION,
870 GTK_ICON_SIZE_DIALOG); 758 GTK_ICON_SIZE_DIALOG);
871 759
872 info = g_new0(InviteBuddyInfo, 1); 760 info = g_new0(InviteBuddyInfo, 1);
873 info->conv = conv; 761 info->conv = conv;
874 762
875 gc = gaim_conversation_get_gc(conv); 763 gc = gaim_conversation_get_gc(conv);
876 win = gaim_conversation_get_window(conv); 764 gtkwin = gaim_gtkconv_get_window(gtkconv);
877 gtkwin = GAIM_GTK_WINDOW(win);
878 765
879 /* Create the new dialog. */ 766 /* Create the new dialog. */
880 invite_dialog = gtk_dialog_new_with_buttons( 767 invite_dialog = gtk_dialog_new_with_buttons(
881 _("Invite Buddy Into Chat Room"), 768 _("Invite Buddy Into Chat Room"),
882 GTK_WINDOW(gtkwin->window), 0, 769 GTK_WINDOW(gtkwin->window), 0,
883 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 770 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
884 GAIM_STOCK_INVITE, GTK_RESPONSE_OK, NULL); 771 GAIM_STOCK_INVITE, GTK_RESPONSE_OK, NULL);
885 772
886 gtk_dialog_set_default_response(GTK_DIALOG(invite_dialog), 773 gtk_dialog_set_default_response(GTK_DIALOG(invite_dialog),
887 GTK_RESPONSE_OK); 774 GTK_RESPONSE_OK);
888 gtk_container_set_border_width(GTK_CONTAINER(invite_dialog), GAIM_HIG_BOX_SPACE); 775 gtk_container_set_border_width(GTK_CONTAINER(invite_dialog), GAIM_HIG_BOX_SPACE);
889 gtk_window_set_resizable(GTK_WINDOW(invite_dialog), FALSE); 776 gtk_window_set_resizable(GTK_WINDOW(invite_dialog), FALSE);
890 gtk_dialog_set_has_separator(GTK_DIALOG(invite_dialog), FALSE); 777 gtk_dialog_set_has_separator(GTK_DIALOG(invite_dialog), FALSE);
891 778
892 info->window = GTK_WIDGET(invite_dialog); 779 info->window = GTK_WIDGET(invite_dialog);
1028 * plaintext v. HTML file. 915 * plaintext v. HTML file.
1029 */ 916 */
1030 static void 917 static void
1031 menu_save_as_cb(gpointer data, guint action, GtkWidget *widget) 918 menu_save_as_cb(gpointer data, guint action, GtkWidget *widget)
1032 { 919 {
1033 GaimConvWindow *win = (GaimConvWindow *)data; 920 GaimGtkWindow *win = data;
1034 GaimConversation *conv = gaim_conv_window_get_active_conversation(win); 921 GaimConversation *conv = gaim_gtk_conv_window_get_active_conversation(win);
1035 gchar *buf; 922 gchar *buf;
1036 923
1037 buf = g_strdup_printf("%s.html", gaim_normalize(conv->account, conv->name)); 924 buf = g_strdup_printf("%s.html", gaim_normalize(conv->account, conv->name));
1038 925
1039 gaim_request_file(conv, _("Save Conversation"), gaim_escape_filename(buf), 926 gaim_request_file(conv, _("Save Conversation"), gaim_escape_filename(buf),
1043 } 930 }
1044 931
1045 static void 932 static void
1046 menu_view_log_cb(gpointer data, guint action, GtkWidget *widget) 933 menu_view_log_cb(gpointer data, guint action, GtkWidget *widget)
1047 { 934 {
1048 GaimConvWindow *win = (GaimConvWindow *)data; 935 GaimGtkWindow *win = data;
1049 GaimConversation *conv; 936 GaimConversation *conv;
1050 GaimLogType type; 937 GaimLogType type;
1051 const char *name; 938 const char *name;
1052 GaimAccount *account; 939 GaimAccount *account;
1053 GSList *buddies, *cur; 940 GSList *buddies, *cur;
1054 941
1055 conv = gaim_conv_window_get_active_conversation(win); 942 conv = gaim_gtk_conv_window_get_active_conversation(win);
1056 943
1057 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) 944 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
1058 type = GAIM_LOG_IM; 945 type = GAIM_LOG_IM;
1059 else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) 946 else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)
1060 type = GAIM_LOG_CHAT; 947 type = GAIM_LOG_CHAT;
1081 } 968 }
1082 969
1083 static void 970 static void
1084 menu_clear_cb(gpointer data, guint action, GtkWidget *widget) 971 menu_clear_cb(gpointer data, guint action, GtkWidget *widget)
1085 { 972 {
1086 GaimConvWindow *win = (GaimConvWindow *)data; 973 GaimGtkWindow *win = data;
1087 GaimConversation *conv; 974 GaimConversation *conv;
1088 GaimGtkConversation *gtkconv; 975 GaimGtkConversation *gtkconv;
1089 976
1090 conv = gaim_conv_window_get_active_conversation(win); 977 conv = gaim_gtk_conv_window_get_active_conversation(win);
1091 gtkconv = GAIM_GTK_CONVERSATION(conv); 978 gtkconv = GAIM_GTK_CONVERSATION(conv);
1092 979
1093 gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml)); 980 gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml));
1094 } 981 }
1095 982
1117 } 1004 }
1118 1005
1119 static void 1006 static void
1120 menu_find_cb(gpointer data, guint action, GtkWidget *widget) 1007 menu_find_cb(gpointer data, guint action, GtkWidget *widget)
1121 { 1008 {
1122 GaimConvWindow *win = (GaimConvWindow *)data; 1009 GaimGtkWindow *gtkwin = data;
1123 GaimConversation *conv = gaim_conv_window_get_active_conversation(win); 1010 GaimConversation *conv = gaim_gtk_conv_window_get_active_conversation(gtkwin);
1124 GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(win);
1125 GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv); 1011 GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv);
1126 GtkWidget *hbox; 1012 GtkWidget *hbox;
1127 GtkWidget *img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION, 1013 GtkWidget *img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_QUESTION,
1128 GTK_ICON_SIZE_DIALOG); 1014 GTK_ICON_SIZE_DIALOG);
1129 GtkWidget *label; 1015 GtkWidget *label;
1179 } 1065 }
1180 1066
1181 static void 1067 static void
1182 menu_send_file_cb(gpointer data, guint action, GtkWidget *widget) 1068 menu_send_file_cb(gpointer data, guint action, GtkWidget *widget)
1183 { 1069 {
1184 GaimConvWindow *win = (GaimConvWindow *)data; 1070 GaimGtkWindow *win = data;
1185 GaimConversation *conv = gaim_conv_window_get_active_conversation(win); 1071 GaimConversation *conv = gaim_gtk_conv_window_get_active_conversation(win);
1186 1072
1187 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) { 1073 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) {
1188 serv_send_file(gaim_conversation_get_gc(conv), gaim_conversation_get_name(conv), NULL); 1074 serv_send_file(gaim_conversation_get_gc(conv), gaim_conversation_get_name(conv), NULL);
1189 } 1075 }
1190 1076
1191 } 1077 }
1192 1078
1193 static void 1079 static void
1194 menu_add_pounce_cb(gpointer data, guint action, GtkWidget *widget) 1080 menu_add_pounce_cb(gpointer data, guint action, GtkWidget *widget)
1195 { 1081 {
1196 GaimConvWindow *win = (GaimConvWindow *)data; 1082 GaimGtkWindow *win = data;
1197 GaimConversation *conv; 1083 GaimConversation *conv;
1198 1084
1199 conv = gaim_conv_window_get_active_conversation(win); 1085 conv = gaim_gtk_conv_window_get_active_gtkconv(win)->active_conv;
1200 1086
1201 gaim_gtkpounce_dialog_show(gaim_conversation_get_account(conv), 1087 gaim_gtkpounce_dialog_show(gaim_conversation_get_account(conv),
1202 gaim_conversation_get_name(conv), NULL); 1088 gaim_conversation_get_name(conv), NULL);
1203 } 1089 }
1204 1090
1205 static void 1091 static void
1206 menu_insert_link_cb(gpointer data, guint action, GtkWidget *widget) 1092 menu_insert_link_cb(gpointer data, guint action, GtkWidget *widget)
1207 { 1093 {
1208 GaimConvWindow *win = (GaimConvWindow *)data; 1094 GaimGtkWindow *win = data;
1095 GaimGtkConversation *gtkconv;
1096 GtkIMHtmlToolbar *toolbar;
1097
1098 gtkconv = gaim_gtk_conv_window_get_active_gtkconv(win);
1099 toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar);
1100
1101 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->link),
1102 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->link)));
1103 }
1104
1105 static void
1106 menu_insert_image_cb(gpointer data, guint action, GtkWidget *widget)
1107 {
1108 GaimGtkWindow *win = data;
1209 GaimConversation *conv; 1109 GaimConversation *conv;
1210 GaimGtkConversation *gtkconv; 1110 GaimGtkConversation *gtkconv;
1211 GtkIMHtmlToolbar *toolbar; 1111 GtkIMHtmlToolbar *toolbar;
1212 1112
1213 conv = gaim_conv_window_get_active_conversation(win); 1113 gtkconv = gaim_gtk_conv_window_get_active_gtkconv(win);
1214 gtkconv = GAIM_GTK_CONVERSATION(conv); 1114 conv = gtkconv->active_conv;
1215 toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar);
1216
1217 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->link),
1218 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->link)));
1219 }
1220
1221 static void
1222 menu_insert_image_cb(gpointer data, guint action, GtkWidget *widget)
1223 {
1224 GaimConvWindow *win = (GaimConvWindow *)data;
1225 GaimConversation *conv;
1226 GaimGtkConversation *gtkconv;
1227 GtkIMHtmlToolbar *toolbar;
1228
1229 conv = gaim_conv_window_get_active_conversation(win);
1230 gtkconv = GAIM_GTK_CONVERSATION(gaim_conv_window_get_active_conversation(win));
1231 toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar); 1115 toolbar = GTK_IMHTMLTOOLBAR(gtkconv->toolbar);
1232 1116
1233 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->image), 1117 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toolbar->image),
1234 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->image))); 1118 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toolbar->image)));
1235 } 1119 }
1236 1120
1237 static void 1121 static void
1238 menu_alias_cb(gpointer data, guint action, GtkWidget *widget) 1122 menu_alias_cb(gpointer data, guint action, GtkWidget *widget)
1239 { 1123 {
1240 GaimConvWindow *win = (GaimConvWindow *)data; 1124 GaimGtkWindow *win = data;
1241 GaimConversation *conv; 1125 GaimConversation *conv;
1242 GaimAccount *account; 1126 GaimAccount *account;
1243 const char *name; 1127 const char *name;
1244 1128
1245 conv = gaim_conv_window_get_active_conversation(win); 1129 conv = gaim_gtk_conv_window_get_active_conversation(win);
1246 account = gaim_conversation_get_account(conv); 1130 account = gaim_conversation_get_account(conv);
1247 name = gaim_conversation_get_name(conv); 1131 name = gaim_conversation_get_name(conv);
1248 1132
1249 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) { 1133 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) {
1250 GaimBuddy *b; 1134 GaimBuddy *b;
1262 } 1146 }
1263 1147
1264 static void 1148 static void
1265 menu_get_info_cb(gpointer data, guint action, GtkWidget *widget) 1149 menu_get_info_cb(gpointer data, guint action, GtkWidget *widget)
1266 { 1150 {
1267 GaimConvWindow *win = (GaimConvWindow *)data; 1151 GaimGtkWindow *win = data;
1268 GaimConversation *conv; 1152 GaimConversation *conv;
1269 1153
1270 conv = gaim_conv_window_get_active_conversation(win); 1154 conv = gaim_gtk_conv_window_get_active_conversation(win);
1271 1155
1272 info_cb(NULL, GAIM_GTK_CONVERSATION(conv)); 1156 info_cb(NULL, GAIM_GTK_CONVERSATION(conv));
1273 } 1157 }
1274 1158
1275 static void 1159 static void
1276 menu_invite_cb(gpointer data, guint action, GtkWidget *widget) 1160 menu_invite_cb(gpointer data, guint action, GtkWidget *widget)
1277 { 1161 {
1278 GaimConvWindow *win = (GaimConvWindow *)data; 1162 GaimGtkWindow *win = data;
1279 GaimConversation *conv; 1163 GaimConversation *conv;
1280 1164
1281 conv = gaim_conv_window_get_active_conversation(win); 1165 conv = gaim_gtk_conv_window_get_active_conversation(win);
1282 1166
1283 invite_cb(NULL, GAIM_GTK_CONVERSATION(conv)); 1167 invite_cb(NULL, GAIM_GTK_CONVERSATION(conv));
1284 } 1168 }
1285 1169
1286 static void 1170 static void
1287 menu_block_cb(gpointer data, guint action, GtkWidget *widget) 1171 menu_block_cb(gpointer data, guint action, GtkWidget *widget)
1288 { 1172 {
1289 GaimConvWindow *win = (GaimConvWindow *)data; 1173 GaimGtkWindow *win = data;
1290 GaimConversation *conv; 1174 GaimConversation *conv;
1291 1175
1292 conv = gaim_conv_window_get_active_conversation(win); 1176 conv = gaim_gtk_conv_window_get_active_conversation(win);
1293 1177
1294 block_cb(NULL, GAIM_GTK_CONVERSATION(conv)); 1178 block_cb(NULL, GAIM_GTK_CONVERSATION(conv));
1295 } 1179 }
1296 1180
1297 static void 1181 static void
1298 menu_add_remove_cb(gpointer data, guint action, GtkWidget *widget) 1182 menu_add_remove_cb(gpointer data, guint action, GtkWidget *widget)
1299 { 1183 {
1300 GaimConvWindow *win = (GaimConvWindow *)data; 1184 GaimGtkWindow *win = data;
1301 GaimConversation *conv; 1185 GaimConversation *conv;
1302 1186
1303 conv = gaim_conv_window_get_active_conversation(win); 1187 conv = gaim_gtk_conv_window_get_active_conversation(win);
1304 1188
1305 add_remove_cb(NULL, GAIM_GTK_CONVERSATION(conv)); 1189 add_remove_cb(NULL, GAIM_GTK_CONVERSATION(conv));
1306 } 1190 }
1307 1191
1308 static void 1192 static void
1309 menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget) 1193 menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget)
1310 { 1194 {
1311 GaimConvWindow *win = (GaimConvWindow *)data; 1195 GaimGtkWindow *win = data;
1312 1196
1313 close_conv_cb(NULL, GAIM_GTK_CONVERSATION(gaim_conv_window_get_active_conversation(win))); 1197 close_conv_cb(NULL, GAIM_GTK_CONVERSATION(gaim_gtk_conv_window_get_active_conversation(win)));
1314 } 1198 }
1315 1199
1316 static void 1200 static void
1317 menu_logging_cb(gpointer data, guint action, GtkWidget *widget) 1201 menu_logging_cb(gpointer data, guint action, GtkWidget *widget)
1318 { 1202 {
1319 GaimConvWindow *win = (GaimConvWindow *)data; 1203 GaimGtkWindow *win = data;
1320 GaimConversation *conv; 1204 GaimConversation *conv;
1321 1205
1322 conv = gaim_conv_window_get_active_conversation(win); 1206 conv = gaim_gtk_conv_window_get_active_conversation(win);
1323 1207
1324 if (conv == NULL) 1208 if (conv == NULL)
1325 return; 1209 return;
1326 1210
1327 gaim_conversation_set_logging(conv, 1211 gaim_conversation_set_logging(conv,
1328 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))); 1212 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
1329 } 1213 }
1330 1214
1331 static void 1215 static void
1332 menu_toolbar_cb(gpointer data, guint action, GtkWidget *widget) 1216 menu_toolbar_cb(gpointer data, guint action, GtkWidget *widget)
1333 { 1217 {
1334 GaimConvWindow *win = (GaimConvWindow *)data; 1218 GaimGtkWindow *win = data;
1335 GaimConversation *conv; 1219 GaimConversation *conv;
1336 GaimGtkConversation *gtkconv; 1220 GaimGtkConversation *gtkconv;
1337 1221
1338 conv = gaim_conv_window_get_active_conversation(win); 1222 conv = gaim_gtk_conv_window_get_active_conversation(win);
1339 1223
1340 if (conv == NULL) 1224 if (conv == NULL)
1341 return; 1225 return;
1342 1226
1343 gtkconv = GAIM_GTK_CONVERSATION(conv); 1227 gtkconv = GAIM_GTK_CONVERSATION(conv);
1344 1228
1345 gaim_prefs_set_bool("/gaim/gtk/conversations/show_formatting_toolbar", 1229 gaim_prefs_set_bool("/gaim/gtk/conversations/show_formatting_toolbar",
1346 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))); 1230 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)));
1347 } 1231 }
1348 1232
1349 static void 1233 static void
1350 menu_sounds_cb(gpointer data, guint action, GtkWidget *widget) 1234 menu_sounds_cb(gpointer data, guint action, GtkWidget *widget)
1351 { 1235 {
1352 GaimConvWindow *win = (GaimConvWindow *)data; 1236 GaimGtkWindow *win = data;
1353 GaimConversation *conv; 1237 GaimConversation *conv;
1354 GaimGtkConversation *gtkconv; 1238 GaimGtkConversation *gtkconv;
1355 1239
1356 conv = gaim_conv_window_get_active_conversation(win); 1240 conv = gaim_gtk_conv_window_get_active_conversation(win);
1357 1241
1358 if (!conv) 1242 if (!conv)
1359 return; 1243 return;
1360 1244
1361 gtkconv = GAIM_GTK_CONVERSATION(conv); 1245 gtkconv = GAIM_GTK_CONVERSATION(conv);
1365 } 1249 }
1366 1250
1367 static void 1251 static void
1368 menu_timestamps_cb(gpointer data, guint action, GtkWidget *widget) 1252 menu_timestamps_cb(gpointer data, guint action, GtkWidget *widget)
1369 { 1253 {
1370 GaimConvWindow *win = (GaimConvWindow *)data; 1254 GaimGtkWindow *win = data;
1371 GaimConversation *conv; 1255 GaimConversation *conv;
1372 GaimGtkConversation *gtkconv; 1256 GaimGtkConversation *gtkconv;
1373 1257
1374 conv = gaim_conv_window_get_active_conversation(win); 1258 conv = gaim_gtk_conv_window_get_active_conversation(win);
1375 1259
1376 if (!conv) 1260 if (!conv)
1377 return; 1261 return;
1378 1262
1379 gtkconv = GAIM_GTK_CONVERSATION(conv); 1263 gtkconv = GAIM_GTK_CONVERSATION(conv);
1711 1595
1712 static void 1596 static void
1713 move_to_next_unread_tab(GaimGtkConversation *gtkconv, gboolean forward) 1597 move_to_next_unread_tab(GaimGtkConversation *gtkconv, gboolean forward)
1714 { 1598 {
1715 GaimGtkConversation *next_gtkconv = NULL; 1599 GaimGtkConversation *next_gtkconv = NULL;
1716 GaimConvWindow *win; 1600 GaimGtkWindow *win;
1717 GList *l; 1601 GList *l;
1718 int index, i, total, found = 0; 1602 int index, i, total, found = 0;
1719 1603
1720 win = gaim_conversation_get_window(gtkconv->active_conv); 1604 win = gtkconv->win;
1721 index = gtk_notebook_page_num(GTK_NOTEBOOK(GAIM_GTK_WINDOW(win)->notebook), gtkconv->tab_cont); 1605 index = gtk_notebook_page_num(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont);
1722 total = gaim_conv_window_get_conversation_count(win); 1606 total = gaim_gtk_conv_window_get_gtkconv_count(win);
1723 1607
1724 /* First check the tabs after (forward) or before (!forward) this position. */ 1608 /* First check the tabs after (forward) or before (!forward) this position. */
1725 for (i = index; 1609 for (i = index;
1726 !found && (next_gtkconv = gaim_gtk_get_gtkconv_at_index(win, i)); 1610 !found && (next_gtkconv = gaim_gtk_conv_window_get_gtkconv_at_index(win, i));
1727 forward ? i++ : i--) { 1611 forward ? i++ : i--) {
1728 if (i == -1) { 1612 if (i == -1) {
1729 break; 1613 break;
1730 } 1614 }
1731 for (l = next_gtkconv->convs; l; l = forward ? l->next : l->prev) { 1615 for (l = next_gtkconv->convs; l; l = forward ? l->next : l->prev) {
1739 } 1623 }
1740 1624
1741 if (!found) { 1625 if (!found) {
1742 /* Now check from the beginning up to (forward) or end back to (!forward) this position. */ 1626 /* Now check from the beginning up to (forward) or end back to (!forward) this position. */
1743 for (i = forward ? 0 : total - 1; 1627 for (i = forward ? 0 : total - 1;
1744 !found && (forward ? i < index : i >= 0) && (next_gtkconv = gaim_gtk_get_gtkconv_at_index(win, i)); 1628 !found && (forward ? i < index : i >= 0) && (next_gtkconv = gaim_gtk_conv_window_get_gtkconv_at_index(win, i));
1745 forward ? i++ : i--) { 1629 forward ? i++ : i--) {
1746 for (l = next_gtkconv->convs; l; l = forward ? l->next : l->prev) { 1630 for (l = next_gtkconv->convs; l; l = forward ? l->next : l->prev) {
1747 GaimConversation *c = l->data; 1631 GaimConversation *c = l->data;
1748 if (gaim_conversation_get_unseen(c) > 0) { 1632 if (gaim_conversation_get_unseen(c) > 0) {
1749 found = 1; 1633 found = 1;
1758 index++; 1642 index++;
1759 } 1643 }
1760 else { 1644 else {
1761 index = (index == 0) ? total - 1 : index - 1; 1645 index = (index == 0) ? total - 1 : index - 1;
1762 } 1646 }
1763 if (!(next_gtkconv = gaim_gtk_get_gtkconv_at_index(win, index))) 1647 if (!(next_gtkconv = gaim_gtk_conv_window_get_gtkconv_at_index(win, index)))
1764 next_gtkconv = gaim_gtk_get_gtkconv_at_index(win, 0); 1648 next_gtkconv = gaim_gtk_conv_window_get_gtkconv_at_index(win, 0);
1765 } 1649 }
1766 } 1650 }
1767 1651
1768 if (next_gtkconv != NULL && next_gtkconv != gtkconv) 1652 if (next_gtkconv != NULL && next_gtkconv != gtkconv)
1769 gaim_conv_window_switch_conversation(win,next_gtkconv->active_conv); 1653 gaim_gtk_conv_window_switch_gtkconv(win, next_gtkconv);
1770 } 1654 }
1771 1655
1772 static gboolean 1656 static gboolean
1773 entry_key_press_cb(GtkWidget *entry, GdkEventKey *event, gpointer data) 1657 entry_key_press_cb(GtkWidget *entry, GdkEventKey *event, gpointer data)
1774 { 1658 {
1775 GaimConvWindow *win; 1659 GaimGtkWindow *win;
1776 GaimConversation *conv; 1660 GaimConversation *conv;
1777 GaimGtkConversation *gtkconv; 1661 GaimGtkConversation *gtkconv;
1778 GaimGtkWindow *gtkwin;
1779 int curconv; 1662 int curconv;
1780 1663
1781 gtkconv = (GaimGtkConversation *)data; 1664 gtkconv = (GaimGtkConversation *)data;
1782 conv = gtkconv->active_conv; 1665 conv = gtkconv->active_conv;
1783 win = gaim_conversation_get_window(conv); 1666 win = gtkconv->win;
1784 gtkwin = GAIM_GTK_WINDOW(win); 1667 curconv = gtk_notebook_get_current_page(GTK_NOTEBOOK(win->notebook));
1785 curconv = gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkwin->notebook));
1786 1668
1787 /* If CTRL was held down... */ 1669 /* If CTRL was held down... */
1788 if (event->state & GDK_CONTROL_MASK) { 1670 if (event->state & GDK_CONTROL_MASK) {
1789 switch (event->keyval) { 1671 switch (event->keyval) {
1790 case GDK_Up: 1672 case GDK_Up:
1876 return TRUE; 1758 return TRUE;
1877 break; 1759 break;
1878 1760
1879 case GDK_Page_Down: 1761 case GDK_Page_Down:
1880 case ']': 1762 case ']':
1881 if (!gaim_gtk_get_gtkconv_at_index(win, curconv + 1)) 1763 if (!gaim_gtk_conv_window_get_gtkconv_at_index(win, curconv + 1))
1882 gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), 0); 1764 gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), 0);
1883 else 1765 else
1884 gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), curconv + 1); 1766 gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), curconv + 1);
1885 return TRUE; 1767 return TRUE;
1886 break; 1768 break;
1887 1769
1888 case GDK_Page_Up: 1770 case GDK_Page_Up:
1889 case '[': 1771 case '[':
1890 if (!gaim_gtk_get_gtkconv_at_index(win, curconv - 1)) 1772 if (!gaim_gtk_conv_window_get_gtkconv_at_index(win, curconv - 1))
1891 gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), -1); 1773 gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), -1);
1892 else 1774 else
1893 gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), curconv - 1); 1775 gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), curconv - 1);
1894 return TRUE; 1776 return TRUE;
1895 break; 1777 break;
1896 1778
1897 case GDK_Tab: 1779 case GDK_Tab:
1898 case GDK_ISO_Left_Tab: 1780 case GDK_ISO_Left_Tab:
1904 1786
1905 return TRUE; 1787 return TRUE;
1906 break; 1788 break;
1907 1789
1908 case GDK_comma: 1790 case GDK_comma:
1909 gtk_notebook_reorder_child(GTK_NOTEBOOK(gtkwin->notebook), 1791 gtk_notebook_reorder_child(GTK_NOTEBOOK(win->notebook),
1910 gtk_notebook_get_nth_page(GTK_NOTEBOOK(gtkwin->notebook), curconv), 1792 gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), curconv),
1911 curconv - 1); 1793 curconv - 1);
1912 break; 1794 break;
1913 1795
1914 case GDK_period: 1796 case GDK_period:
1915 gtk_notebook_reorder_child(GTK_NOTEBOOK(gtkwin->notebook), 1797 gtk_notebook_reorder_child(GTK_NOTEBOOK(win->notebook),
1916 gtk_notebook_get_nth_page(GTK_NOTEBOOK(gtkwin->notebook), curconv), 1798 gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), curconv),
1917 (curconv + 1) % gtk_notebook_get_n_pages(GTK_NOTEBOOK(gtkwin->notebook))); 1799 (curconv + 1) % gtk_notebook_get_n_pages(GTK_NOTEBOOK(win->notebook)));
1918 break; 1800 break;
1919 1801
1920 } /* End of switch */ 1802 } /* End of switch */
1921 } 1803 }
1922 1804
1924 else if (event->state & GDK_MOD1_MASK) 1806 else if (event->state & GDK_MOD1_MASK)
1925 { 1807 {
1926 if (event->keyval > '0' && event->keyval <= '9') 1808 if (event->keyval > '0' && event->keyval <= '9')
1927 { 1809 {
1928 int switchto = event->keyval - '1'; 1810 int switchto = event->keyval - '1';
1929 if (switchto < gaim_conv_window_get_conversation_count(win)) 1811 if (switchto < gaim_gtk_conv_window_get_gtkconv_count(win))
1930 gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), switchto); 1812 gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), switchto);
1931 1813
1932 return TRUE; 1814 return TRUE;
1933 } 1815 }
1934 } 1816 }
1935 1817
2014 } 1896 }
2015 1897
2016 static void 1898 static void
2017 menu_conv_sel_send_cb(GObject *m, gpointer data) 1899 menu_conv_sel_send_cb(GObject *m, gpointer data)
2018 { 1900 {
2019 GaimConvWindow *win = g_object_get_data(m, "user_data"); 1901 GaimGtkWindow *win = g_object_get_data(m, "user_data");
2020 GaimAccount *account = g_object_get_data(m, "gaim_account"); 1902 GaimAccount *account = g_object_get_data(m, "gaim_account");
2021 GaimConversation *conv; 1903 GaimConversation *conv;
2022 GaimGtkConversation *gtkconv; 1904 GaimGtkConversation *gtkconv;
2023 1905
2024 if (gtk_check_menu_item_get_active((GtkCheckMenuItem*) m) == FALSE) 1906 if (gtk_check_menu_item_get_active((GtkCheckMenuItem*) m) == FALSE)
2025 return; 1907 return;
2026 1908
2027 conv = gaim_conv_window_get_active_conversation(win); 1909 conv = gaim_gtk_conv_window_get_active_conversation(win);
2028 1910
2029 gaim_conversation_set_account(conv, account); 1911 gaim_conversation_set_account(conv, account);
2030 1912
2031 gtkconv = GAIM_GTK_CONVERSATION(conv); 1913 gtkconv = GAIM_GTK_CONVERSATION(conv);
2032 gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->entry), 1914 gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->entry),
2082 /* We're deleting, but not all of it, so it counts as typing. */ 1964 /* We're deleting, but not all of it, so it counts as typing. */
2083 got_typing_keypress(gtkconv, FALSE); 1965 got_typing_keypress(gtkconv, FALSE);
2084 } 1966 }
2085 } 1967 }
2086 1968
2087 static void
2088 notebook_init_grab(GaimGtkWindow *gtkwin, GtkWidget *widget)
2089 {
2090 static GdkCursor *cursor = NULL;
2091
2092 gtkwin->in_drag = TRUE;
2093
2094 if (gtkwin->drag_leave_signal) {
2095 g_signal_handler_disconnect(G_OBJECT(widget),
2096 gtkwin->drag_leave_signal);
2097
2098 gtkwin->drag_leave_signal = 0;
2099 }
2100
2101 if (cursor == NULL)
2102 cursor = gdk_cursor_new(GDK_FLEUR);
2103
2104 /* Grab the pointer */
2105 gtk_grab_add(gtkwin->notebook);
2106 #ifndef _WIN32
2107 /* Currently for win32 GTK+ (as of 2.2.1), gdk_pointer_is_grabbed will
2108 always be true after a button press. */
2109 if (!gdk_pointer_is_grabbed())
2110 #endif
2111 gdk_pointer_grab(gtkwin->notebook->window, FALSE,
2112 GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
2113 NULL, cursor, GDK_CURRENT_TIME);
2114 }
2115
2116 static gboolean
2117 notebook_motion_cb(GtkWidget *widget, GdkEventButton *e, GaimConvWindow *win)
2118 {
2119 GaimGtkWindow *gtkwin;
2120
2121 gtkwin = GAIM_GTK_WINDOW(win);
2122
2123 /*
2124 * Make sure the user moved the mouse far enough for the
2125 * drag to be initiated.
2126 */
2127 if (gtkwin->in_predrag) {
2128 if (e->x_root < gtkwin->drag_min_x ||
2129 e->x_root >= gtkwin->drag_max_x ||
2130 e->y_root < gtkwin->drag_min_y ||
2131 e->y_root >= gtkwin->drag_max_y) {
2132
2133 gtkwin->in_predrag = FALSE;
2134 notebook_init_grab(gtkwin, widget);
2135 }
2136 }
2137 else { /* Otherwise, draw the arrows. */
2138 GaimConvWindow *dest_win;
2139 GaimGtkWindow *dest_gtkwin;
2140 GtkNotebook *dest_notebook;
2141 GtkWidget *tab;
2142 gint nb_x, nb_y, page_num;
2143 gint arrow1_x, arrow1_y, arrow2_x, arrow2_y;
2144 gboolean horiz_tabs = FALSE;
2145
2146 /* Get the window that the cursor is over. */
2147 dest_win = gaim_gtkwin_get_at_xy(e->x_root, e->y_root);
2148
2149 if (dest_win == NULL) {
2150 dnd_hints_hide_all();
2151
2152 return TRUE;
2153 }
2154
2155 dest_gtkwin = GAIM_GTK_WINDOW(dest_win);
2156
2157 dest_notebook = GTK_NOTEBOOK(dest_gtkwin->notebook);
2158
2159 gdk_window_get_origin(GTK_WIDGET(dest_notebook)->window, &nb_x, &nb_y);
2160
2161 arrow1_x = arrow2_x = nb_x;
2162 arrow1_y = arrow2_y = nb_y;
2163
2164 page_num = gaim_gtkconv_get_tab_at_xy(dest_win,
2165 e->x_root, e->y_root);
2166
2167 if (gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_TOP ||
2168 gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_BOTTOM) {
2169
2170 horiz_tabs = TRUE;
2171 }
2172
2173 tab = gaim_gtk_get_gtkconv_at_index(dest_win, page_num)->tabby;
2174
2175 if (horiz_tabs) {
2176 arrow1_x = arrow2_x = nb_x + tab->allocation.x;
2177
2178 if ((gpointer)gtkwin == (gpointer)dest_gtkwin && gtkwin->drag_tab < page_num) {
2179 arrow1_x += tab->allocation.width;
2180 arrow2_x += tab->allocation.width;
2181 }
2182
2183 arrow1_y = nb_y + tab->allocation.y;
2184 arrow2_y = nb_y + tab->allocation.y +
2185 tab->allocation.height;
2186 }
2187 else {
2188 arrow1_x = nb_x + tab->allocation.x;
2189 arrow2_x = nb_x + tab->allocation.x +
2190 tab->allocation.width;
2191 arrow1_y = arrow2_y = nb_y + tab->allocation.y + tab->allocation.height/2;
2192
2193 if ((gpointer)gtkwin == (gpointer)dest_win && gtkwin->drag_tab < page_num) {
2194 arrow1_y += tab->allocation.height;
2195 arrow2_y += tab->allocation.height;
2196 }
2197 }
2198
2199 if (horiz_tabs) {
2200 dnd_hints_show(HINT_ARROW_DOWN, arrow1_x, arrow1_y);
2201 dnd_hints_show(HINT_ARROW_UP, arrow2_x, arrow2_y);
2202 }
2203 else {
2204 dnd_hints_show(HINT_ARROW_RIGHT, arrow1_x, arrow1_y);
2205 dnd_hints_show(HINT_ARROW_LEFT, arrow2_x, arrow2_y);
2206 }
2207 }
2208
2209 return TRUE;
2210 }
2211
2212 static gboolean
2213 notebook_leave_cb(GtkWidget *widget, GdkEventCrossing *e, GaimConvWindow *win)
2214 {
2215 GaimGtkWindow *gtkwin;
2216
2217 gtkwin = GAIM_GTK_WINDOW(win);
2218
2219 if (gtkwin->in_drag)
2220 return FALSE;
2221
2222 if (e->x_root < gtkwin->drag_min_x ||
2223 e->x_root >= gtkwin->drag_max_x ||
2224 e->y_root < gtkwin->drag_min_y ||
2225 e->y_root >= gtkwin->drag_max_y) {
2226
2227 gtkwin->in_predrag = FALSE;
2228 notebook_init_grab(gtkwin, widget);
2229 }
2230
2231 return TRUE;
2232 }
2233
2234 /*
2235 * THANK YOU GALEON!
2236 */
2237 static gboolean
2238 notebook_press_cb(GtkWidget *widget, GdkEventButton *e, GaimConvWindow *win)
2239 {
2240 GaimGtkWindow *gtkwin;
2241 gint nb_x, nb_y, x_rel, y_rel;
2242 int tab_clicked;
2243 GtkWidget *page;
2244 GtkWidget *tab;
2245
2246 if (e->button != 1 || e->type != GDK_BUTTON_PRESS)
2247 return FALSE;
2248
2249 gtkwin = GAIM_GTK_WINDOW(win);
2250
2251 if (gtkwin->in_drag) {
2252 gaim_debug(GAIM_DEBUG_WARNING, "gtkconv",
2253 "Already in the middle of a window drag at tab_press_cb\n");
2254 return TRUE;
2255 }
2256
2257 /*
2258 * Make sure a tab was actually clicked. The arrow buttons
2259 * mess things up.
2260 */
2261 tab_clicked = gaim_gtkconv_get_tab_at_xy(win, e->x_root, e->y_root);
2262
2263 if (tab_clicked == -1)
2264 return FALSE;
2265
2266 /*
2267 * Get the relative position of the press event, with regards to
2268 * the position of the notebook.
2269 */
2270 gdk_window_get_origin(gtkwin->notebook->window, &nb_x, &nb_y);
2271
2272 x_rel = e->x_root - nb_x;
2273 y_rel = e->y_root - nb_y;
2274
2275 /* Reset the min/max x/y */
2276 gtkwin->drag_min_x = 0;
2277 gtkwin->drag_min_y = 0;
2278 gtkwin->drag_max_x = 0;
2279 gtkwin->drag_max_y = 0;
2280
2281 /* Find out which tab was dragged. */
2282 page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(gtkwin->notebook), tab_clicked);
2283 tab = gtk_notebook_get_tab_label(GTK_NOTEBOOK(gtkwin->notebook), page);
2284
2285 gtkwin->drag_min_x = tab->allocation.x + nb_x;
2286 gtkwin->drag_min_y = tab->allocation.y + nb_y;
2287 gtkwin->drag_max_x = tab->allocation.width + gtkwin->drag_min_x;
2288 gtkwin->drag_max_y = tab->allocation.height + gtkwin->drag_min_y;
2289
2290 /* Make sure the click occurred in the tab. */
2291 if (e->x_root < gtkwin->drag_min_x ||
2292 e->x_root >= gtkwin->drag_max_x ||
2293 e->y_root < gtkwin->drag_min_y ||
2294 e->y_root >= gtkwin->drag_max_y) {
2295
2296 return FALSE;
2297 }
2298
2299 gtkwin->in_predrag = TRUE;
2300 gtkwin->drag_tab = tab_clicked;
2301
2302 /* Connect the new motion signals. */
2303 gtkwin->drag_motion_signal =
2304 g_signal_connect(G_OBJECT(widget), "motion_notify_event",
2305 G_CALLBACK(notebook_motion_cb), win);
2306
2307 gtkwin->drag_leave_signal =
2308 g_signal_connect(G_OBJECT(widget), "leave_notify_event",
2309 G_CALLBACK(notebook_leave_cb), win);
2310
2311 return FALSE;
2312 }
2313
2314 static gboolean
2315 notebook_release_cb(GtkWidget *widget, GdkEventButton *e, GaimConvWindow *win)
2316 {
2317 GaimConvWindow *dest_win;
2318 GaimGtkWindow *gtkwin;
2319 GaimConversation *conv;
2320 GaimGtkConversation *gtkconv;
2321 gint dest_page_num = 0;
2322 gboolean new_window = FALSE;
2323
2324 /*
2325 * Don't check to make sure that the event's window matches the
2326 * widget's, because we may be getting an event passed on from the
2327 * close button.
2328 */
2329 if (e->button != 1 && e->type != GDK_BUTTON_RELEASE)
2330 return FALSE;
2331
2332 if (gdk_pointer_is_grabbed()) {
2333 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2334 gtk_grab_remove(widget);
2335 }
2336
2337 gtkwin = GAIM_GTK_WINDOW(win);
2338
2339 if (!gtkwin->in_predrag && !gtkwin->in_drag)
2340 return FALSE;
2341
2342 /* Disconnect the motion signal. */
2343 if (gtkwin->drag_motion_signal) {
2344 g_signal_handler_disconnect(G_OBJECT(widget),
2345 gtkwin->drag_motion_signal);
2346
2347 gtkwin->drag_motion_signal = 0;
2348 }
2349
2350 /*
2351 * If we're in a pre-drag, we'll also need to disconnect the leave
2352 * signal.
2353 */
2354 if (gtkwin->in_predrag) {
2355 gtkwin->in_predrag = FALSE;
2356
2357 if (gtkwin->drag_leave_signal) {
2358 g_signal_handler_disconnect(G_OBJECT(widget),
2359 gtkwin->drag_leave_signal);
2360
2361 gtkwin->drag_leave_signal = 0;
2362 }
2363 }
2364
2365 /* If we're not in drag... */
2366 /* We're perfectly normal people! */
2367 if (!gtkwin->in_drag)
2368 return FALSE;
2369
2370 gtkwin->in_drag = FALSE;
2371
2372 dnd_hints_hide_all();
2373
2374 dest_win = gaim_gtkwin_get_at_xy(e->x_root, e->y_root);
2375
2376 conv = gaim_conv_window_get_active_conversation(win);
2377
2378 if (dest_win == NULL) {
2379 /* If the current window doesn't have any other conversations,
2380 * there isn't much point transferring the conv to a new window. */
2381 if (gaim_conv_window_get_conversation_count(win) > 1) {
2382 /* Make a new window to stick this to. */
2383 dest_win = gaim_conv_window_new();
2384 new_window = TRUE;
2385 }
2386 }
2387
2388 if (dest_win == NULL)
2389 return FALSE;
2390
2391 gaim_signal_emit(gaim_gtk_conversations_get_handle(),
2392 "conversation-dragging", win, dest_win);
2393
2394 /* Get the destination page number. */
2395 if (!new_window)
2396 dest_page_num = gaim_gtkconv_get_tab_at_xy(dest_win,
2397 e->x_root, e->y_root);
2398
2399 gtkconv = GAIM_GTK_CONVERSATION(conv);
2400
2401 if (win == dest_win) {
2402 gtk_notebook_reorder_child(GTK_NOTEBOOK(gtkwin->notebook), gtkconv->tab_cont, dest_page_num);
2403 }
2404 else {
2405 gaim_conv_window_remove_conversation(win, conv);
2406 gaim_conv_window_add_conversation(dest_win, conv);
2407 gtk_notebook_reorder_child(GTK_NOTEBOOK(GAIM_GTK_WINDOW(dest_win)->notebook), gtkconv->tab_cont, dest_page_num);
2408 gaim_conv_window_switch_conversation(dest_win, conv);
2409 if (new_window) {
2410 GaimGtkWindow *dest_gtkwin = GAIM_GTK_WINDOW(dest_win);
2411 gint win_width, win_height;
2412
2413 gtk_window_get_size(GTK_WINDOW(dest_gtkwin->window),
2414 &win_width, &win_height);
2415
2416 gtk_window_move(GTK_WINDOW(dest_gtkwin->window),
2417 e->x_root - (win_width / 2),
2418 e->y_root - (win_height / 2));
2419
2420 gaim_conv_window_show(dest_win);
2421 }
2422 }
2423
2424 gtk_widget_grab_focus(GAIM_GTK_CONVERSATION(conv)->entry);
2425
2426 return TRUE;
2427 }
2428
2429 /************************************************************************** 1969 /**************************************************************************
2430 * A bunch of buddy icon functions 1970 * A bunch of buddy icon functions
2431 **************************************************************************/ 1971 **************************************************************************/
2432 static GdkPixbuf * 1972 GdkPixbuf *
2433 get_tab_icon(GaimConversation *conv, gboolean small_icon) 1973 gaim_gtkconv_get_tab_icon(GaimConversation *conv, gboolean small_icon)
2434 { 1974 {
2435 GaimAccount *account = NULL; 1975 GaimAccount *account = NULL;
2436 const char *name = NULL; 1976 const char *name = NULL;
2437 GdkPixbuf *status = NULL; 1977 GdkPixbuf *status = NULL;
2438 1978
2470 2010
2471 static void 2011 static void
2472 update_tab_icon(GaimConversation *conv) 2012 update_tab_icon(GaimConversation *conv)
2473 { 2013 {
2474 GaimGtkConversation *gtkconv; 2014 GaimGtkConversation *gtkconv;
2475 GaimConvWindow *win = gaim_conversation_get_window(conv); 2015 GaimGtkWindow *win;
2476 GaimAccount *account; 2016 GaimAccount *account;
2477 const char *name; 2017 const char *name;
2478 GdkPixbuf *status = NULL; 2018 GdkPixbuf *status = NULL;
2479 2019
2480 g_return_if_fail(conv != NULL); 2020 g_return_if_fail(conv != NULL);
2481 2021
2482 gtkconv = GAIM_GTK_CONVERSATION(conv); 2022 gtkconv = GAIM_GTK_CONVERSATION(conv);
2023 win = gtkconv->win;
2483 name = gaim_conversation_get_name(conv); 2024 name = gaim_conversation_get_name(conv);
2484 account = gaim_conversation_get_account(conv); 2025 account = gaim_conversation_get_account(conv);
2485 2026
2486 status = get_tab_icon(conv, TRUE); 2027 status = gaim_gtkconv_get_tab_icon(conv, TRUE);
2487 2028
2488 g_return_if_fail(status != NULL); 2029 g_return_if_fail(status != NULL);
2489 2030
2490 gtk_image_set_from_pixbuf(GTK_IMAGE(gtkconv->icon), status); 2031 gtk_image_set_from_pixbuf(GTK_IMAGE(gtkconv->icon), status);
2491 gtk_image_set_from_pixbuf(GTK_IMAGE(gtkconv->menu_icon), status); 2032 gtk_image_set_from_pixbuf(GTK_IMAGE(gtkconv->menu_icon), status);
2492 2033
2493 if (status != NULL) 2034 if (status != NULL)
2494 g_object_unref(status); 2035 g_object_unref(status);
2495 2036
2496 if (gaim_conv_window_get_active_conversation(win) == conv && 2037 if (gaim_gtk_conv_window_get_active_conversation(win) == conv &&
2497 (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_IM || 2038 (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_IM ||
2498 gtkconv->u.im->anim == NULL)) 2039 gtkconv->u.im->anim == NULL))
2499 { 2040 {
2500 status = get_tab_icon(conv, FALSE); 2041 status = gaim_gtkconv_get_tab_icon(conv, FALSE);
2501 2042
2502 gtk_window_set_icon(GTK_WINDOW(GAIM_GTK_WINDOW(win)->window), status); 2043 gtk_window_set_icon(GTK_WINDOW(win->window), status);
2503 2044
2504 if (status != NULL) 2045 if (status != NULL)
2505 g_object_unref(status); 2046 g_object_unref(status);
2506 } 2047 }
2507 } 2048 }
2588 2129
2589 gtkconv->u.im->icon_timer = g_timeout_add(delay, redraw_icon, conv); 2130 gtkconv->u.im->icon_timer = g_timeout_add(delay, redraw_icon, conv);
2590 } 2131 }
2591 2132
2592 static void 2133 static void
2593 stop_anim(GtkObject *obj, GaimGtkConversation *gtkconv)
2594 {
2595 if (gtkconv->u.im->icon_timer != 0)
2596 g_source_remove(gtkconv->u.im->icon_timer);
2597
2598 gtkconv->u.im->icon_timer = 0;
2599 }
2600
2601 static void
2602 toggle_icon_animate_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
2603 {
2604 gtkconv->u.im->animate =
2605 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
2606
2607 if (gtkconv->u.im->animate)
2608 start_anim(NULL, gtkconv);
2609 else
2610 stop_anim(NULL, gtkconv);
2611 }
2612
2613 static void
2614 remove_icon(GaimGtkConversation *gtkconv) 2134 remove_icon(GaimGtkConversation *gtkconv)
2615 { 2135 {
2616 GaimConversation *conv = gtkconv->active_conv; 2136 GaimConversation *conv = gtkconv->active_conv;
2617 GaimGtkWindow *gtkwin; 2137 GaimGtkWindow *gtkwin;
2618 2138
2635 gtkconv->u.im->anim = NULL; 2155 gtkconv->u.im->anim = NULL;
2636 gtkconv->u.im->iter = NULL; 2156 gtkconv->u.im->iter = NULL;
2637 gtkconv->u.im->icon_container = NULL; 2157 gtkconv->u.im->icon_container = NULL;
2638 gtkconv->u.im->show_icon = FALSE; 2158 gtkconv->u.im->show_icon = FALSE;
2639 2159
2640 gtkwin = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv)); 2160 gtkwin = gtkconv->win;
2641 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.show_icon), FALSE); 2161 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.show_icon), FALSE);
2642 } 2162 }
2643 2163
2644 static void 2164 static void
2645 saveicon_writefile_cb(void *user_data, const char *filename) 2165 saveicon_writefile_cb(void *user_data, const char *filename)
2687 G_CALLBACK(saveicon_writefile_cb), NULL, conv); 2207 G_CALLBACK(saveicon_writefile_cb), NULL, conv);
2688 2208
2689 g_free(buf); 2209 g_free(buf);
2690 } 2210 }
2691 2211
2212 static void
2213 stop_anim(GtkObject *obj, GaimGtkConversation *gtkconv)
2214 {
2215 if (gtkconv->u.im->icon_timer != 0)
2216 g_source_remove(gtkconv->u.im->icon_timer);
2217
2218 gtkconv->u.im->icon_timer = 0;
2219 }
2220
2221
2222 static void
2223 toggle_icon_animate_cb(GtkWidget *w, GaimGtkConversation *gtkconv)
2224 {
2225 gtkconv->u.im->animate =
2226 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
2227
2228 if (gtkconv->u.im->animate)
2229 start_anim(NULL, gtkconv);
2230 else
2231 stop_anim(NULL, gtkconv);
2232 }
2233
2692 static gboolean 2234 static gboolean
2693 icon_menu(GtkObject *obj, GdkEventButton *e, GaimGtkConversation *gtkconv) 2235 icon_menu(GtkObject *obj, GdkEventButton *e, GaimGtkConversation *gtkconv)
2694 { 2236 {
2695 GaimConversation *conv = gtkconv->active_conv; 2237 GaimConversation *conv = gtkconv->active_conv;
2696 static GtkWidget *menu = NULL; 2238 static GtkWidget *menu = NULL;
2732 } 2274 }
2733 2275
2734 static void 2276 static void
2735 menu_buddyicon_cb(gpointer data, guint action, GtkWidget *widget) 2277 menu_buddyicon_cb(gpointer data, guint action, GtkWidget *widget)
2736 { 2278 {
2737 GaimConvWindow *win = (GaimConvWindow *)data; 2279 GaimGtkWindow *win = data;
2738 GaimConversation *conv; 2280 GaimConversation *conv;
2739 GaimGtkConversation *gtkconv; 2281 GaimGtkConversation *gtkconv;
2740 gboolean active; 2282 gboolean active;
2741 2283
2742 conv = gaim_conv_window_get_active_conversation(win); 2284 conv = gaim_gtk_conv_window_get_active_conversation(win);
2743 2285
2744 if (!conv) 2286 if (!conv)
2745 return; 2287 return;
2746 2288
2747 g_return_if_fail(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM); 2289 g_return_if_fail(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM);
2758 2300
2759 /************************************************************************** 2301 /**************************************************************************
2760 * End of the bunch of buddy icon functions 2302 * End of the bunch of buddy icon functions
2761 **************************************************************************/ 2303 **************************************************************************/
2762 2304
2763 2305 GaimGtkWindow *
2764 /* 2306 gaim_gtkconv_get_window(GaimGtkConversation *gtkconv)
2765 * Makes sure all the menu items and all the buttons are hidden/shown and 2307 {
2766 * sensitive/insensitive. This is called after changing tabs and when an 2308 g_return_val_if_fail(gtkconv != NULL, NULL);
2767 * account signs on or off. 2309 return gtkconv->win;
2768 */ 2310 }
2769 static void 2311
2770 gray_stuff_out(GaimGtkConversation *gtkconv) 2312 static GtkItemFactoryEntry menu_items[] =
2771 { 2313 {
2772 GaimConvWindow *win; 2314 /* Conversation menu */
2773 GaimGtkWindow *gtkwin; 2315 { N_("/_Conversation"), NULL, NULL, 0, "<Branch>" },
2774 GaimConversation *conv = gtkconv->active_conv; 2316
2775 GaimConnection *gc; 2317 { N_("/Conversation/New Instant _Message..."), "<CTL>M", menu_new_conv_cb,
2776 GaimPluginProtocolInfo *prpl_info = NULL; 2318 0, "<StockItem>", GAIM_STOCK_IM },
2777 GdkPixbuf *window_icon = NULL; 2319
2778 GtkIMHtmlButtons buttons; 2320 { "/Conversation/sep0", NULL, NULL, 0, "<Separator>" },
2779 GaimAccount *account; 2321
2780 2322 { N_("/Conversation/_Find..."), NULL, menu_find_cb, 0,
2781 win = gaim_conversation_get_window(conv); 2323 "<StockItem>", GTK_STOCK_FIND },
2782 gtkwin = GAIM_GTK_WINDOW(win); 2324 { N_("/Conversation/View _Log"), NULL, menu_view_log_cb, 0, NULL },
2783 gtkconv = GAIM_GTK_CONVERSATION(conv); 2325 { N_("/Conversation/_Save As..."), NULL, menu_save_as_cb, 0,
2784 gc = gaim_conversation_get_gc(conv); 2326 "<StockItem>", GTK_STOCK_SAVE_AS },
2785 account = gaim_conversation_get_account(conv); 2327 { N_("/Conversation/Clear"), "<CTL>L", menu_clear_cb, 0, "<StockItem>", GTK_STOCK_CLEAR },
2786 2328
2787 if (gc != NULL) 2329 { "/Conversation/sep1", NULL, NULL, 0, "<Separator>" },
2788 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); 2330
2789 2331 { N_("/Conversation/Se_nd File..."), NULL, menu_send_file_cb, 0, "<StockItem>", GAIM_STOCK_FILE_TRANSFER },
2790 if (gtkwin->menu.send_as != NULL) 2332 { N_("/Conversation/Add Buddy _Pounce..."), NULL, menu_add_pounce_cb,
2791 g_timeout_add(0, (GSourceFunc)update_send_as_selection, win); 2333 0, NULL },
2792 2334 { N_("/Conversation/_Get Info"), "<CTL>O", menu_get_info_cb, 0,
2793 /* 2335 "<StockItem>", GAIM_STOCK_INFO },
2794 * Handle hiding and showing stuff based on what type of conv this is. 2336 { N_("/Conversation/In_vite..."), NULL, menu_invite_cb, 0,
2795 * Stuff that Gaim IMs support in general should be shown for IM 2337 "<StockItem>", GAIM_STOCK_INVITE },
2796 * conversations. Stuff that Gaim chats support in general should be 2338
2797 * shown for chat conversations. It doesn't matter whether the PRPL 2339 { "/Conversation/sep2", NULL, NULL, 0, "<Separator>" },
2798 * supports it or not--that only affects if the button or menu item 2340
2799 * is sensitive or not. 2341 { N_("/Conversation/Al_ias..."), NULL, menu_alias_cb, 0,
2800 */ 2342 "<StockItem>", GAIM_STOCK_EDIT },
2801 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) { 2343 { N_("/Conversation/_Block..."), NULL, menu_block_cb, 0,
2802 /* Show stuff that applies to IMs, hide stuff that applies to chats */ 2344 "<StockItem>", GAIM_STOCK_BLOCK },
2803 2345 { N_("/Conversation/_Add..."), NULL, menu_add_remove_cb, 0,
2804 /* Deal with menu items */ 2346 "<StockItem>", GTK_STOCK_ADD },
2805 gtk_widget_show(gtkwin->menu.view_log); 2347 { N_("/Conversation/_Remove..."), NULL, menu_add_remove_cb, 0,
2806 gtk_widget_show(gtkwin->menu.send_file); 2348 "<StockItem>", GTK_STOCK_REMOVE },
2807 gtk_widget_show(gtkwin->menu.add_pounce); 2349
2808 gtk_widget_show(gtkwin->menu.get_info); 2350 { "/Conversation/sep3", NULL, NULL, 0, "<Separator>" },
2809 gtk_widget_hide(gtkwin->menu.invite); 2351
2810 gtk_widget_show(gtkwin->menu.alias); 2352 { N_("/Conversation/Insert Lin_k..."), NULL, menu_insert_link_cb, 0,
2811 gtk_widget_show(gtkwin->menu.block); 2353 "<StockItem>", GAIM_STOCK_LINK },
2812 2354 { N_("/Conversation/Insert Imag_e..."), NULL, menu_insert_image_cb, 0,
2813 if (gaim_find_buddy(account, gaim_conversation_get_name(conv)) == NULL) { 2355 "<StockItem>", GAIM_STOCK_IMAGE },
2814 gtk_widget_show(gtkwin->menu.add); 2356
2815 gtk_widget_hide(gtkwin->menu.remove); 2357 { "/Conversation/sep4", NULL, NULL, 0, "<Separator>" },
2816 } else { 2358
2817 gtk_widget_show(gtkwin->menu.remove); 2359 { N_("/Conversation/_Close"), NULL, menu_close_conv_cb, 0,
2818 gtk_widget_hide(gtkwin->menu.add); 2360 "<StockItem>", GTK_STOCK_CLOSE },
2819 } 2361
2820 2362 /* Options */
2821 gtk_widget_show(gtkwin->menu.insert_link); 2363 { N_("/_Options"), NULL, NULL, 0, "<Branch>" },
2822 gtk_widget_show(gtkwin->menu.insert_image); 2364 { N_("/Options/Enable _Logging"), NULL, menu_logging_cb, 0, "<CheckItem>" },
2823 gtk_widget_show(gtkwin->menu.show_icon); 2365 { N_("/Options/Enable _Sounds"), NULL, menu_sounds_cb, 0, "<CheckItem>" },
2824 } else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) { 2366 { N_("/Options/Show Formatting _Toolbars"), NULL, menu_toolbar_cb, 0, "<CheckItem>" },
2825 /* Show stuff that applies to Chats, hide stuff that applies to IMs */ 2367 { N_("/Options/Show Ti_mestamps"), "F2", menu_timestamps_cb, 0, "<CheckItem>" },
2826 2368 { N_("/Options/Show Buddy _Icon"), NULL, menu_buddyicon_cb, 0, "<CheckItem>" },
2827 /* Deal with menu items */ 2369 };
2828 gtk_widget_show(gtkwin->menu.view_log); 2370
2829 gtk_widget_hide(gtkwin->menu.send_file); 2371 static const int menu_item_count =
2830 gtk_widget_hide(gtkwin->menu.add_pounce); 2372 sizeof(menu_items) / sizeof(*menu_items);
2831 gtk_widget_hide(gtkwin->menu.get_info); 2373
2832 gtk_widget_show(gtkwin->menu.invite); 2374 static char *
2833 gtk_widget_show(gtkwin->menu.alias); 2375 item_factory_translate_func (const char *path, gpointer func_data)
2834 gtk_widget_hide(gtkwin->menu.block); 2376 {
2835 gtk_widget_hide(gtkwin->menu.show_icon); 2377 return _((char *)path);
2836 2378 }
2837 if (gaim_blist_find_chat(account, gaim_conversation_get_name(conv)) == NULL) { 2379
2838 /* If the chat is NOT in the buddy list */ 2380 static GtkWidget *
2839 gtk_widget_show(gtkwin->menu.add); 2381 setup_menubar(GaimGtkWindow *win)
2840 gtk_widget_hide(gtkwin->menu.remove); 2382 {
2841 } else { 2383 GtkAccelGroup *accel_group;
2842 /* If the chat IS in the buddy list */ 2384
2843 gtk_widget_hide(gtkwin->menu.add); 2385 accel_group = gtk_accel_group_new ();
2844 gtk_widget_show(gtkwin->menu.remove); 2386 gtk_window_add_accel_group(GTK_WINDOW(win->window), accel_group);
2845 } 2387 g_object_unref(accel_group);
2846 2388
2847 gtk_widget_show(gtkwin->menu.insert_link); 2389 win->menu.item_factory =
2848 gtk_widget_hide(gtkwin->menu.insert_image); 2390 gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
2849 } 2391
2850 2392 gtk_item_factory_set_translate_func(win->menu.item_factory,
2851 /* 2393 item_factory_translate_func,
2852 * Handle graying stuff out based on whether an account is connected 2394 NULL, NULL);
2853 * and what features that account supports. 2395
2854 */ 2396 gtk_item_factory_create_items(win->menu.item_factory, menu_item_count,
2855 if ((gc != NULL) && 2397 menu_items, win);
2856 ( (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_CHAT) || 2398 g_signal_connect(G_OBJECT(accel_group), "accel-changed",
2857 !gaim_conv_chat_has_left(GAIM_CONV_CHAT(conv)) )) { 2399 G_CALLBACK(gaim_gtk_save_accels_cb), NULL);
2858 /* Account is online */ 2400
2859 /* Deal with the toolbar */ 2401
2860 if (conv->features & GAIM_CONNECTION_HTML) { 2402 win->menu.menubar =
2861 buttons = GTK_IMHTML_ALL; /* Everything on */ 2403 gtk_item_factory_get_widget(win->menu.item_factory, "<main>");
2862 if (!(prpl_info->options & OPT_PROTO_IM_IMAGE) || 2404
2863 conv->features & GAIM_CONNECTION_NO_IMAGES) 2405
2864 buttons &= ~GTK_IMHTML_IMAGE; 2406 win->menu.view_log =
2865 if (conv->features & GAIM_CONNECTION_NO_BGCOLOR) 2407 gtk_item_factory_get_widget(win->menu.item_factory,
2866 buttons &= ~GTK_IMHTML_BACKCOLOR; 2408 N_("/Conversation/View Log"));
2867 if (conv->features & GAIM_CONNECTION_NO_FONTSIZE) { 2409
2868 buttons &= ~GTK_IMHTML_GROW; 2410 /* --- */
2869 buttons &= ~GTK_IMHTML_SHRINK; 2411
2870 } 2412 win->menu.send_file =
2871 if (conv->features & GAIM_CONNECTION_NO_URLDESC) 2413 gtk_item_factory_get_widget(win->menu.item_factory,
2872 buttons &= ~GTK_IMHTML_LINKDESC; 2414 N_("/Conversation/Send File..."));
2873 } else { 2415
2874 buttons = GTK_IMHTML_SMILEY; 2416 win->menu.add_pounce =
2875 } 2417 gtk_item_factory_get_widget(win->menu.item_factory,
2876 gtk_imhtml_set_format_functions(GTK_IMHTML(gtkconv->entry), buttons); 2418 N_("/Conversation/Add Buddy Pounce..."));
2877 gtk_imhtmltoolbar_associate_smileys(GTK_IMHTMLTOOLBAR(gtkconv->toolbar), gaim_account_get_protocol_id(account)); 2419
2878 2420 /* --- */
2879 /* Deal with menu items */ 2421
2880 gtk_widget_set_sensitive(gtkwin->menu.view_log, TRUE); 2422 win->menu.get_info =
2881 gtk_widget_set_sensitive(gtkwin->menu.add_pounce, TRUE); 2423 gtk_item_factory_get_widget(win->menu.item_factory,
2882 gtk_widget_set_sensitive(gtkwin->menu.get_info, (prpl_info->get_info != NULL)); 2424 N_("/Conversation/Get Info"));
2883 gtk_widget_set_sensitive(gtkwin->menu.invite, (prpl_info->chat_invite != NULL)); 2425
2884 gtk_widget_set_sensitive(gtkwin->menu.block, (prpl_info->add_deny != NULL)); 2426 win->menu.invite =
2885 gtk_widget_set_sensitive(gtkwin->menu.insert_link, (conv->features & GAIM_CONNECTION_HTML)); 2427 gtk_item_factory_get_widget(win->menu.item_factory,
2886 gtk_widget_set_sensitive(gtkwin->menu.insert_image, (prpl_info->options & OPT_PROTO_IM_IMAGE)); 2428 N_("/Conversation/Invite..."));
2887 2429
2888 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) { 2430 /* --- */
2889 gtk_widget_set_sensitive(gtkwin->menu.add, (prpl_info->add_buddy != NULL)); 2431
2890 gtk_widget_set_sensitive(gtkwin->menu.remove, (prpl_info->remove_buddy != NULL)); 2432 win->menu.alias =
2891 gtk_widget_set_sensitive(gtkwin->menu.send_file, 2433 gtk_item_factory_get_widget(win->menu.item_factory,
2892 (prpl_info->send_file != NULL && (!prpl_info->can_receive_file || 2434 N_("/Conversation/Alias..."));
2893 prpl_info->can_receive_file(gc, gaim_conversation_get_name(conv))))); 2435
2894 gtk_widget_set_sensitive(gtkwin->menu.alias, 2436 win->menu.block =
2895 (gaim_find_buddy(account, gaim_conversation_get_name(conv)) != NULL)); 2437 gtk_item_factory_get_widget(win->menu.item_factory,
2896 } else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) { 2438 N_("/Conversation/Block..."));
2897 gtk_widget_set_sensitive(gtkwin->menu.add, (prpl_info->join_chat != NULL)); 2439
2898 gtk_widget_set_sensitive(gtkwin->menu.remove, (prpl_info->join_chat != NULL)); 2440 win->menu.add =
2899 gtk_widget_set_sensitive(gtkwin->menu.alias, 2441 gtk_item_factory_get_widget(win->menu.item_factory,
2900 (gaim_blist_find_chat(account, gaim_conversation_get_name(conv)) != NULL)); 2442 N_("/Conversation/Add..."));
2901 } 2443
2902 2444 win->menu.remove =
2903 /* Deal with chat userlist buttons */ 2445 gtk_item_factory_get_widget(win->menu.item_factory,
2904 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) 2446 N_("/Conversation/Remove..."));
2905 { 2447
2906 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_im, TRUE); 2448 /* --- */
2907 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_ignore, TRUE); 2449
2908 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_info, (prpl_info->get_info != NULL)); 2450 win->menu.insert_link =
2909 } 2451 gtk_item_factory_get_widget(win->menu.item_factory,
2910 } else { 2452 N_("/Conversation/Insert Link..."));
2911 /* Account is offline */ 2453
2912 /* Or it's a chat that we've left. */ 2454 win->menu.insert_image =
2913 2455 gtk_item_factory_get_widget(win->menu.item_factory,
2914 /* Then deal with menu items */ 2456 N_("/Conversation/Insert Image..."));
2915 gtk_widget_set_sensitive(gtkwin->menu.view_log, TRUE); 2457
2916 gtk_widget_set_sensitive(gtkwin->menu.send_file, FALSE); 2458 /* --- */
2917 gtk_widget_set_sensitive(gtkwin->menu.add_pounce, TRUE); 2459
2918 gtk_widget_set_sensitive(gtkwin->menu.get_info, FALSE); 2460 win->menu.logging =
2919 gtk_widget_set_sensitive(gtkwin->menu.invite, FALSE); 2461 gtk_item_factory_get_widget(win->menu.item_factory,
2920 gtk_widget_set_sensitive(gtkwin->menu.alias, FALSE); 2462 N_("/Options/Enable Logging"));
2921 gtk_widget_set_sensitive(gtkwin->menu.block, FALSE); 2463 win->menu.sounds =
2922 gtk_widget_set_sensitive(gtkwin->menu.add, FALSE); 2464 gtk_item_factory_get_widget(win->menu.item_factory,
2923 gtk_widget_set_sensitive(gtkwin->menu.remove, FALSE); 2465 N_("/Options/Enable Sounds"));
2924 gtk_widget_set_sensitive(gtkwin->menu.insert_link, TRUE); 2466 win->menu.show_formatting_toolbar =
2925 gtk_widget_set_sensitive(gtkwin->menu.insert_image, FALSE); 2467 gtk_item_factory_get_widget(win->menu.item_factory,
2926 2468 N_("/Options/Show Formatting Toolbars"));
2927 /* Deal with chat userlist buttons */ 2469 win->menu.show_timestamps =
2928 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) 2470 gtk_item_factory_get_widget(win->menu.item_factory,
2929 { 2471 N_("/Options/Show Timestamps"));
2930 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_im, FALSE); 2472 win->menu.show_icon =
2931 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_ignore, FALSE); 2473 gtk_item_factory_get_widget(win->menu.item_factory,
2932 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_info, FALSE); 2474 N_("/Options/Show Buddy Icon"));
2933 } 2475
2934 } 2476 generate_send_as_items(win, NULL);
2935 2477
2936 /* 2478 win->menu.tray = gaim_gtk_menu_tray_new();
2937 * Update the window's icon 2479 gtk_menu_shell_append(GTK_MENU_SHELL(win->menu.menubar),
2938 */ 2480 win->menu.tray);
2939 if ((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) && 2481 gtk_widget_show(win->menu.tray);
2940 (gtkconv->u.im->anim)) 2482
2941 { 2483 gtk_widget_show(win->menu.menubar);
2942 window_icon = 2484
2943 gdk_pixbuf_animation_get_static_image(gtkconv->u.im->anim); 2485 return win->menu.menubar;
2944 g_object_ref(window_icon); 2486 }
2945 } else { 2487
2946 window_icon = get_tab_icon(conv, FALSE);
2947 }
2948 gtk_window_set_icon(GTK_WINDOW(gtkwin->window), window_icon);
2949 if (window_icon != NULL)
2950 g_object_unref(G_OBJECT(window_icon));
2951 }
2952
2953 static void
2954 before_switch_conv_cb(GtkNotebook *notebook, GtkWidget *page, gint page_num,
2955 gpointer user_data)
2956 {
2957 GaimConvWindow *win;
2958 GaimConversation *conv;
2959 GaimGtkConversation *gtkconv;
2960
2961 win = (GaimConvWindow *)user_data;
2962 conv = gaim_conv_window_get_active_conversation(win);
2963
2964 g_return_if_fail(conv != NULL);
2965
2966 if (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_IM)
2967 return;
2968
2969 gtkconv = GAIM_GTK_CONVERSATION(conv);
2970
2971 stop_anim(NULL, gtkconv);
2972 }
2973
2974 static void
2975 switch_conv_cb(GtkNotebook *notebook, GtkWidget *page, gint page_num,
2976 gpointer user_data)
2977 {
2978 GaimConvWindow *win;
2979 GaimConversation *conv;
2980 GaimGtkConversation *gtkconv;
2981 GaimGtkWindow *gtkwin;
2982
2983 win = (GaimConvWindow *)user_data;
2984 gtkconv = gaim_gtk_get_gtkconv_at_index(win, page_num);
2985 conv = gtkconv->active_conv;
2986
2987 g_return_if_fail(conv != NULL);
2988
2989 gtkwin = GAIM_GTK_WINDOW(win);
2990
2991 /*
2992 * Only set "unseen" to "none" if the window has focus
2993 */
2994 if (gaim_conv_window_has_focus(win))
2995 gaim_conversation_set_unseen(conv, GAIM_UNSEEN_NONE);
2996
2997 /* Update the menubar */
2998 gray_stuff_out(gtkconv);
2999
3000 update_typing_icon(gtkconv);
3001
3002 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.logging),
3003 gaim_conversation_is_logging(conv));
3004
3005 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.sounds),
3006 gtkconv->make_sound);
3007
3008 gtk_check_menu_item_set_active(
3009 GTK_CHECK_MENU_ITEM(gtkwin->menu.show_formatting_toolbar),
3010 gaim_prefs_get_bool("/gaim/gtk/conversations/show_formatting_toolbar"));
3011
3012 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.show_timestamps),
3013 gtkconv->show_timestamps);
3014
3015 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
3016 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.show_icon),
3017 gtkconv->u.im->show_icon);
3018 /*
3019 * We pause icons when they are not visible. If this icon should
3020 * be animated then start it back up again.
3021 */
3022 if ((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) &&
3023 (gtkconv->u.im->animate))
3024 start_anim(NULL, gtkconv);
3025
3026 gtk_window_set_title(GTK_WINDOW(gtkwin->window),
3027 gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
3028 }
3029 2488
3030 /************************************************************************** 2489 /**************************************************************************
3031 * Utility functions 2490 * Utility functions
3032 **************************************************************************/ 2491 **************************************************************************/
3033 2492
3068 { 2527 {
3069 GaimGtkWindow *gtkwin; 2528 GaimGtkWindow *gtkwin;
3070 GaimConvIm *im = NULL; 2529 GaimConvIm *im = NULL;
3071 GaimConversation *conv = gtkconv->active_conv; 2530 GaimConversation *conv = gtkconv->active_conv;
3072 2531
3073 gtkwin = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv)); 2532 gtkwin = gtkconv->win;
3074 2533
3075 if(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) 2534 if(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
3076 im = GAIM_CONV_IM(conv); 2535 im = GAIM_CONV_IM(conv);
3077 2536
3078 if(gtkwin->menu.typing_icon) { 2537 if(gtkwin->menu.typing_icon) {
3097 gtkwin->menu.typing_icon); 2556 gtkwin->menu.typing_icon);
3098 } 2557 }
3099 } 2558 }
3100 2559
3101 static gboolean 2560 static gboolean
3102 update_send_as_selection(GaimConvWindow *win) 2561 update_send_as_selection(GaimGtkWindow *win)
3103 { 2562 {
3104 GaimAccount *account; 2563 GaimAccount *account;
3105 GaimConversation *conv; 2564 GaimConversation *conv;
3106 GaimGtkWindow *gtkwin;
3107 GtkWidget *menu; 2565 GtkWidget *menu;
3108 GList *child; 2566 GList *child;
3109 2567
3110 if (g_list_find(gaim_get_windows(), win) == NULL) 2568 /* what does this do again? */
2569 /*
2570 if (g_list_find(gaim_gtk_get_windows(), win) == NULL)
3111 return FALSE; 2571 return FALSE;
3112 2572 */
3113 conv = gaim_conv_window_get_active_conversation(win); 2573
2574 conv = gaim_gtk_conv_window_get_active_conversation(win);
3114 2575
3115 if (conv == NULL) 2576 if (conv == NULL)
3116 return FALSE; 2577 return FALSE;
3117 2578
3118 account = gaim_conversation_get_account(conv); 2579 account = gaim_conversation_get_account(conv);
3119 gtkwin = GAIM_GTK_WINDOW(win); 2580
3120 2581 if (win->menu.send_as == NULL)
3121 if (gtkwin->menu.send_as == NULL)
3122 return FALSE; 2582 return FALSE;
3123 2583
3124 gtk_widget_show(gtkwin->menu.send_as); 2584 gtk_widget_show(win->menu.send_as);
3125 2585
3126 menu = gtk_menu_item_get_submenu( 2586 menu = gtk_menu_item_get_submenu(
3127 GTK_MENU_ITEM(gtkwin->menu.send_as)); 2587 GTK_MENU_ITEM(win->menu.send_as));
3128 2588
3129 for (child = gtk_container_get_children(GTK_CONTAINER(menu)); 2589 for (child = gtk_container_get_children(GTK_CONTAINER(menu));
3130 child != NULL; 2590 child != NULL;
3131 child = child->next) { 2591 child = child->next) {
3132 2592
3142 2602
3143 return FALSE; 2603 return FALSE;
3144 } 2604 }
3145 2605
3146 static void 2606 static void
3147 generate_send_as_items(GaimConvWindow *win, GaimConversation *deleted_conv) 2607 generate_send_as_items(GaimGtkWindow *win, GaimConversation *deleted_conv)
3148 { 2608 {
3149 GaimGtkWindow *gtkwin;
3150 GtkWidget *menu; 2609 GtkWidget *menu;
3151 GtkWidget *menuitem; 2610 GtkWidget *menuitem;
3152 GList *gcs; 2611 GList *gcs;
3153 GList *convs; 2612 GList *convs;
3154 GSList *group = NULL; 2613 GSList *group = NULL;
3155 gboolean first_offline = TRUE; 2614 gboolean first_offline = TRUE;
3156 gboolean found_online = FALSE; 2615 gboolean found_online = FALSE;
3157 GtkSizeGroup *sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); 2616 GtkSizeGroup *sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
3158 2617
3159 gtkwin = GAIM_GTK_WINDOW(win); 2618 if (win->menu.send_as != NULL)
3160 2619 gtk_widget_destroy(win->menu.send_as);
3161 if (gtkwin->menu.send_as != NULL)
3162 gtk_widget_destroy(gtkwin->menu.send_as);
3163 2620
3164 /* See if we have > 1 connection active. */ 2621 /* See if we have > 1 connection active. */
3165 if (g_list_length(gaim_connections_get_all()) < 2) { 2622 if (g_list_length(gaim_connections_get_all()) < 2) {
3166 /* Now make sure we don't have any Offline entries. */ 2623 /* Now make sure we don't have any Offline entries. */
3167 gboolean found_offline = FALSE; 2624 gboolean found_offline = FALSE;
3168 2625
3169 for (convs = gaim_get_conversations(); 2626 for (convs = gaim_get_conversations();
3170 convs != NULL; 2627 convs != NULL;
3171 convs = convs->next) { 2628 convs = convs->next) {
3172 2629
3173 GaimConversation *conv; 2630 GaimConversation *conv;
3174 GaimAccount *account; 2631 GaimAccount *account;
3175 2632
3176 conv = (GaimConversation *)convs->data; 2633 conv = (GaimConversation *)convs->data;
3181 break; 2638 break;
3182 } 2639 }
3183 } 2640 }
3184 2641
3185 if (!found_offline) { 2642 if (!found_offline) {
3186 gtkwin->menu.send_as = NULL; 2643 win->menu.send_as = NULL;
3187 return; 2644 return;
3188 } 2645 }
3189 } 2646 }
3190 2647
3191 /* Build the Send As menu */ 2648 /* Build the Send As menu */
3192 gtkwin->menu.send_as = gtk_menu_item_new_with_mnemonic(_("_Send As")); 2649 win->menu.send_as = gtk_menu_item_new_with_mnemonic(_("_Send As"));
3193 gtk_widget_show(gtkwin->menu.send_as); 2650 gtk_widget_show(win->menu.send_as);
3194 2651
3195 menu = gtk_menu_new(); 2652 menu = gtk_menu_new();
3196 gtk_menu_shell_insert(GTK_MENU_SHELL(gtkwin->menu.menubar), 2653 gtk_menu_shell_insert(GTK_MENU_SHELL(win->menu.menubar),
3197 gtkwin->menu.send_as, 2); 2654 win->menu.send_as, 2);
3198 gtk_menu_item_set_submenu(GTK_MENU_ITEM(gtkwin->menu.send_as), menu); 2655 gtk_menu_item_set_submenu(GTK_MENU_ITEM(win->menu.send_as), menu);
3199 2656
3200 gtk_widget_show(menu); 2657 gtk_widget_show(menu);
3201 2658
3202 /* Fill it with entries. */ 2659 /* Fill it with entries. */
3203 for (gcs = gaim_connections_get_all(); gcs != NULL; gcs = gcs->next) { 2660 for (gcs = gaim_connections_get_all(); gcs != NULL; gcs = gcs->next) {
3346 } 2803 }
3347 } 2804 }
3348 2805
3349 g_object_unref(sg); 2806 g_object_unref(sg);
3350 2807
3351 gtk_widget_show(gtkwin->menu.send_as); 2808 gtk_widget_show(win->menu.send_as);
3352 update_send_as_selection(win); 2809 update_send_as_selection(win);
3353 } 2810 }
3354 2811
3355 static GList * 2812 static GList *
3356 generate_invite_user_names(GaimConnection *gc) 2813 generate_invite_user_names(GaimConnection *gc)
3687 3144
3688 g_free(entered); 3145 g_free(entered);
3689 g_free(partial); 3146 g_free(partial);
3690 3147
3691 return TRUE; 3148 return TRUE;
3692 }
3693
3694 static GtkItemFactoryEntry menu_items[] =
3695 {
3696 /* Conversation menu */
3697 { N_("/_Conversation"), NULL, NULL, 0, "<Branch>" },
3698
3699 { N_("/Conversation/New Instant _Message..."), "<CTL>M", menu_new_conv_cb,
3700 0, "<StockItem>", GAIM_STOCK_IM },
3701
3702 { "/Conversation/sep0", NULL, NULL, 0, "<Separator>" },
3703
3704 { N_("/Conversation/_Find..."), NULL, menu_find_cb, 0,
3705 "<StockItem>", GTK_STOCK_FIND },
3706 { N_("/Conversation/View _Log"), NULL, menu_view_log_cb, 0, NULL },
3707 { N_("/Conversation/_Save As..."), NULL, menu_save_as_cb, 0,
3708 "<StockItem>", GTK_STOCK_SAVE_AS },
3709 { N_("/Conversation/Clear"), "<CTL>L", menu_clear_cb, 0, "<StockItem>", GTK_STOCK_CLEAR },
3710
3711 { "/Conversation/sep1", NULL, NULL, 0, "<Separator>" },
3712
3713 { N_("/Conversation/Se_nd File..."), NULL, menu_send_file_cb, 0, "<StockItem>", GAIM_STOCK_FILE_TRANSFER },
3714 { N_("/Conversation/Add Buddy _Pounce..."), NULL, menu_add_pounce_cb,
3715 0, NULL },
3716 { N_("/Conversation/_Get Info"), "<CTL>O", menu_get_info_cb, 0,
3717 "<StockItem>", GAIM_STOCK_INFO },
3718 { N_("/Conversation/In_vite..."), NULL, menu_invite_cb, 0,
3719 "<StockItem>", GAIM_STOCK_INVITE },
3720
3721 { "/Conversation/sep2", NULL, NULL, 0, "<Separator>" },
3722
3723 { N_("/Conversation/Al_ias..."), NULL, menu_alias_cb, 0,
3724 "<StockItem>", GAIM_STOCK_EDIT },
3725 { N_("/Conversation/_Block..."), NULL, menu_block_cb, 0,
3726 "<StockItem>", GAIM_STOCK_BLOCK },
3727 { N_("/Conversation/_Add..."), NULL, menu_add_remove_cb, 0,
3728 "<StockItem>", GTK_STOCK_ADD },
3729 { N_("/Conversation/_Remove..."), NULL, menu_add_remove_cb, 0,
3730 "<StockItem>", GTK_STOCK_REMOVE },
3731
3732 { "/Conversation/sep3", NULL, NULL, 0, "<Separator>" },
3733
3734 { N_("/Conversation/Insert Lin_k..."), NULL, menu_insert_link_cb, 0,
3735 "<StockItem>", GAIM_STOCK_LINK },
3736 { N_("/Conversation/Insert Imag_e..."), NULL, menu_insert_image_cb, 0,
3737 "<StockItem>", GAIM_STOCK_IMAGE },
3738
3739 { "/Conversation/sep4", NULL, NULL, 0, "<Separator>" },
3740
3741 { N_("/Conversation/_Close"), NULL, menu_close_conv_cb, 0,
3742 "<StockItem>", GTK_STOCK_CLOSE },
3743
3744 /* Options */
3745 { N_("/_Options"), NULL, NULL, 0, "<Branch>" },
3746 { N_("/Options/Enable _Logging"), NULL, menu_logging_cb, 0, "<CheckItem>" },
3747 { N_("/Options/Enable _Sounds"), NULL, menu_sounds_cb, 0, "<CheckItem>" },
3748 { N_("/Options/Show Formatting _Toolbars"), NULL, menu_toolbar_cb, 0, "<CheckItem>" },
3749 { N_("/Options/Show Ti_mestamps"), "F2", menu_timestamps_cb, 0, "<CheckItem>" },
3750 { N_("/Options/Show Buddy _Icon"), NULL, menu_buddyicon_cb, 0, "<CheckItem>" },
3751 };
3752
3753 static const int menu_item_count =
3754 sizeof(menu_items) / sizeof(*menu_items);
3755
3756 static char *
3757 item_factory_translate_func (const char *path, gpointer func_data)
3758 {
3759 return _((char *)path);
3760 }
3761
3762 static GtkWidget *
3763 setup_menubar(GaimConvWindow *win)
3764 {
3765 GaimGtkWindow *gtkwin;
3766 GtkAccelGroup *accel_group;
3767
3768 gtkwin = GAIM_GTK_WINDOW(win);
3769
3770 accel_group = gtk_accel_group_new ();
3771 gtk_window_add_accel_group (GTK_WINDOW (gtkwin->window), accel_group);
3772 g_object_unref (accel_group);
3773
3774 gtkwin->menu.item_factory =
3775 gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accel_group);
3776
3777 gtk_item_factory_set_translate_func(gtkwin->menu.item_factory,
3778 item_factory_translate_func,
3779 NULL, NULL);
3780
3781 gtk_item_factory_create_items(gtkwin->menu.item_factory, menu_item_count,
3782 menu_items, win);
3783 g_signal_connect(G_OBJECT(accel_group), "accel-changed",
3784 G_CALLBACK(gaim_gtk_save_accels_cb), NULL);
3785
3786
3787 gtkwin->menu.menubar =
3788 gtk_item_factory_get_widget(gtkwin->menu.item_factory, "<main>");
3789
3790
3791 gtkwin->menu.view_log =
3792 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3793 N_("/Conversation/View Log"));
3794
3795 /* --- */
3796
3797 gtkwin->menu.send_file =
3798 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3799 N_("/Conversation/Send File..."));
3800
3801 gtkwin->menu.add_pounce =
3802 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3803 N_("/Conversation/Add Buddy Pounce..."));
3804
3805 /* --- */
3806
3807 gtkwin->menu.get_info =
3808 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3809 N_("/Conversation/Get Info"));
3810
3811 gtkwin->menu.invite =
3812 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3813 N_("/Conversation/Invite..."));
3814
3815 /* --- */
3816
3817 gtkwin->menu.alias =
3818 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3819 N_("/Conversation/Alias..."));
3820
3821 gtkwin->menu.block =
3822 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3823 N_("/Conversation/Block..."));
3824
3825 gtkwin->menu.add =
3826 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3827 N_("/Conversation/Add..."));
3828
3829 gtkwin->menu.remove =
3830 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3831 N_("/Conversation/Remove..."));
3832
3833 /* --- */
3834
3835 gtkwin->menu.insert_link =
3836 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3837 N_("/Conversation/Insert Link..."));
3838
3839 gtkwin->menu.insert_image =
3840 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3841 N_("/Conversation/Insert Image..."));
3842
3843 /* --- */
3844
3845 gtkwin->menu.logging =
3846 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3847 N_("/Options/Enable Logging"));
3848 gtkwin->menu.sounds =
3849 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3850 N_("/Options/Enable Sounds"));
3851 gtkwin->menu.show_formatting_toolbar =
3852 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3853 N_("/Options/Show Formatting Toolbars"));
3854 gtkwin->menu.show_timestamps =
3855 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3856 N_("/Options/Show Timestamps"));
3857 gtkwin->menu.show_icon =
3858 gtk_item_factory_get_widget(gtkwin->menu.item_factory,
3859 N_("/Options/Show Buddy Icon"));
3860
3861 generate_send_as_items(win, NULL);
3862
3863 gtkwin->menu.tray = gaim_gtk_menu_tray_new();
3864 gtk_menu_shell_append(GTK_MENU_SHELL(gtkwin->menu.menubar),
3865 gtkwin->menu.tray);
3866 gtk_widget_show(gtkwin->menu.tray);
3867
3868 gtk_widget_show(gtkwin->menu.menubar);
3869
3870 return gtkwin->menu.menubar;
3871 } 3149 }
3872 3150
3873 static void topic_callback(GtkWidget *w, GaimGtkConversation *gtkconv) 3151 static void topic_callback(GtkWidget *w, GaimGtkConversation *gtkconv)
3874 { 3152 {
3875 GaimPluginProtocolInfo *prpl_info = NULL; 3153 GaimPluginProtocolInfo *prpl_info = NULL;
4436 conv_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, 3714 conv_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y,
4437 GtkSelectionData *sd, guint info, guint t, 3715 GtkSelectionData *sd, guint info, guint t,
4438 GaimGtkConversation *gtkconv) 3716 GaimGtkConversation *gtkconv)
4439 { 3717 {
4440 GaimConversation *conv = gtkconv->active_conv; 3718 GaimConversation *conv = gtkconv->active_conv;
4441 GaimConvWindow *win = conv->window; 3719 GaimGtkWindow *win = gtkconv->win;
4442 GaimConversation *c; 3720 GaimConversation *c;
4443 if (sd->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE)) 3721 if (sd->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE))
4444 { 3722 {
4445 GaimBlistNode *n = NULL; 3723 GaimBlistNode *n = NULL;
4446 GaimBuddy *b; 3724 GaimBuddy *b;
3725 GaimGtkConversation *gtkconv = NULL;
4447 3726
4448 memcpy(&n, sd->data, sizeof(n)); 3727 memcpy(&n, sd->data, sizeof(n));
4449 3728
4450 if (GAIM_BLIST_NODE_IS_CONTACT(n)) 3729 if (GAIM_BLIST_NODE_IS_CONTACT(n))
4451 b = gaim_contact_get_priority_buddy((GaimContact*)n); 3730 b = gaim_contact_get_priority_buddy((GaimContact*)n);
4459 * just move the conv to this window. Otherwise, create a new 3738 * just move the conv to this window. Otherwise, create a new
4460 * conv and add it to this window. 3739 * conv and add it to this window.
4461 */ 3740 */
4462 c = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, b->name, b->account); 3741 c = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, b->name, b->account);
4463 if (c != NULL) { 3742 if (c != NULL) {
4464 GaimConvWindow *oldwin; 3743 GaimGtkWindow *oldwin;
4465 oldwin = gaim_conversation_get_window(c); 3744 gtkconv = GAIM_GTK_CONVERSATION(c);
3745 oldwin = gtkconv->win;
4466 if (oldwin != win) { 3746 if (oldwin != win) {
4467 gaim_conv_window_remove_conversation(oldwin, c); 3747 gaim_gtk_conv_window_remove_gtkconv(oldwin, gtkconv);
4468 gaim_conv_window_add_conversation(win, c); 3748 gaim_gtk_conv_window_add_gtkconv(win, gtkconv);
4469 } 3749 }
4470 } else { 3750 } else {
4471 c = gaim_conversation_new(GAIM_CONV_TYPE_IM, b->account, b->name); 3751 c = gaim_conversation_new(GAIM_CONV_TYPE_IM, b->account, b->name);
4472 gaim_conv_window_add_conversation(win, c); 3752 gtkconv = GAIM_GTK_CONVERSATION(c);
3753 gaim_gtk_conv_window_add_gtkconv(win, gtkconv);
4473 } 3754 }
4474 3755
4475 /* Make this conversation the active conversation */ 3756 /* Make this conversation the active conversation */
4476 gaim_conv_window_switch_conversation(win, c); 3757 gaim_gtk_conv_window_switch_gtkconv(win, gtkconv);
4477 3758
4478 gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); 3759 gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t);
4479 } 3760 }
4480 else if (sd->target == gdk_atom_intern("application/x-im-contact", FALSE)) 3761 else if (sd->target == gdk_atom_intern("application/x-im-contact", FALSE))
4481 { 3762 {
4482 char *protocol = NULL; 3763 char *protocol = NULL;
4483 char *username = NULL; 3764 char *username = NULL;
4484 GaimAccount *account; 3765 GaimAccount *account;
3766 GaimGtkConversation *gtkconv;
4485 3767
4486 if (gaim_gtk_parse_x_im_contact((const char *)sd->data, FALSE, &account, 3768 if (gaim_gtk_parse_x_im_contact((const char *)sd->data, FALSE, &account,
4487 &protocol, &username, NULL)) 3769 &protocol, &username, NULL))
4488 { 3770 {
4489 if (account == NULL) 3771 if (account == NULL)
4493 "can add that buddy."), NULL); 3775 "can add that buddy."), NULL);
4494 } 3776 }
4495 else 3777 else
4496 { 3778 {
4497 c = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, username); 3779 c = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, username);
4498 gaim_conv_window_add_conversation(win, c); 3780 gtkconv = GAIM_GTK_CONVERSATION(c);
3781 gaim_gtk_conv_window_add_gtkconv(win, gtkconv);
4499 } 3782 }
4500 } 3783 }
4501 3784
4502 if (username != NULL) g_free(username); 3785 if (username != NULL) g_free(username);
4503 if (protocol != NULL) g_free(protocol); 3786 if (protocol != NULL) g_free(protocol);
4511 } 3794 }
4512 else 3795 else
4513 gtk_drag_finish(dc, FALSE, FALSE, t); 3796 gtk_drag_finish(dc, FALSE, FALSE, t);
4514 } 3797 }
4515 3798
4516 /**************************************************************************
4517 * GTK+ window ops
4518 **************************************************************************/
4519 static void
4520 gaim_gtk_new_window(GaimConvWindow *win)
4521 {
4522 GaimGtkWindow *gtkwin;
4523 GtkPositionType pos;
4524 GtkWidget *testidea;
4525 GtkWidget *menubar;
4526
4527 gtkwin = g_malloc0(sizeof(GaimGtkWindow));
4528
4529 win->ui_data = gtkwin;
4530
4531 /* Create the window. */
4532 gtkwin->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4533 gtk_window_set_role(GTK_WINDOW(gtkwin->window), "conversation");
4534 gtk_window_set_resizable(GTK_WINDOW(gtkwin->window), TRUE);
4535 gtk_container_set_border_width(GTK_CONTAINER(gtkwin->window), 0);
4536 GTK_WINDOW(gtkwin->window)->allow_shrink = TRUE;
4537
4538 g_signal_connect(G_OBJECT(gtkwin->window), "delete_event",
4539 G_CALLBACK(close_win_cb), win);
4540
4541 g_signal_connect(G_OBJECT(gtkwin->window), "focus_in_event",
4542 G_CALLBACK(focus_win_cb), win);
4543
4544 /* Create the notebook. */
4545 gtkwin->notebook = gtk_notebook_new();
4546
4547 pos = gaim_prefs_get_int("/gaim/gtk/conversations/tab_side");
4548
4549 #if 0
4550 gtk_notebook_set_tab_hborder(GTK_NOTEBOOK(gtkwin->notebook), 0);
4551 gtk_notebook_set_tab_vborder(GTK_NOTEBOOK(gtkwin->notebook), 0);
4552 #endif
4553 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkwin->notebook), pos);
4554 gtk_notebook_set_scrollable(GTK_NOTEBOOK(gtkwin->notebook), TRUE);
4555 gtk_notebook_popup_enable(GTK_NOTEBOOK(gtkwin->notebook));
4556 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkwin->notebook), FALSE);
4557 gtk_notebook_set_show_border(GTK_NOTEBOOK(gtkwin->notebook), FALSE);
4558
4559 gtk_widget_show(gtkwin->notebook);
4560
4561 g_signal_connect(G_OBJECT(gtkwin->notebook), "switch_page",
4562 G_CALLBACK(before_switch_conv_cb), win);
4563 g_signal_connect_after(G_OBJECT(gtkwin->notebook), "switch_page",
4564 G_CALLBACK(switch_conv_cb), win);
4565
4566 /* Setup the tab drag and drop signals. */
4567 gtk_widget_add_events(gtkwin->notebook,
4568 GDK_BUTTON1_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
4569 g_signal_connect(G_OBJECT(gtkwin->notebook), "button_press_event",
4570 G_CALLBACK(notebook_press_cb), win);
4571 g_signal_connect(G_OBJECT(gtkwin->notebook), "button_release_event",
4572 G_CALLBACK(notebook_release_cb), win);
4573
4574 testidea = gtk_vbox_new(FALSE, 0);
4575
4576 /* Setup the menubar. */
4577 menubar = setup_menubar(win);
4578 gtk_box_pack_start(GTK_BOX(testidea), menubar, FALSE, TRUE, 0);
4579
4580 gtk_box_pack_start(GTK_BOX(testidea), gtkwin->notebook, TRUE, TRUE, 0);
4581
4582 gtk_container_add(GTK_CONTAINER(gtkwin->window), testidea);
4583
4584 gtk_widget_show(testidea);
4585 }
4586
4587 static void
4588 gaim_gtk_destroy_window(GaimConvWindow *win)
4589 {
4590 GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(win);
4591
4592 gtk_widget_destroy(gtkwin->window);
4593
4594 g_object_unref(G_OBJECT(gtkwin->menu.item_factory));
4595
4596 g_free(gtkwin);
4597 win->ui_data = NULL;
4598 }
4599
4600 static void
4601 gaim_gtk_show(GaimConvWindow *win)
4602 {
4603 GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(win);
4604
4605 gtk_widget_show(gtkwin->window);
4606 }
4607
4608 static void
4609 gaim_gtk_hide(GaimConvWindow *win)
4610 {
4611 GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(win);
4612
4613 gtk_widget_hide(gtkwin->window);
4614 }
4615
4616 static void
4617 gaim_gtk_raise(GaimConvWindow *win)
4618 {
4619 GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(win);
4620
4621 gtk_widget_show(gtkwin->window);
4622 gtk_window_deiconify(GTK_WINDOW(gtkwin->window));
4623 gdk_window_raise(gtkwin->window->window);
4624 }
4625
4626 static void
4627 gaim_gtk_switch_conversation(GaimConvWindow *win, GaimConversation *conv)
4628 {
4629 GaimGtkWindow *gtkwin;
4630 GaimGtkConversation *gtkconv = conv->ui_data;
4631
4632 gtkwin = GAIM_GTK_WINDOW(win);
4633
4634 gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), gtk_notebook_page_num(GTK_NOTEBOOK(gtkwin->notebook), gtkconv->tab_cont));
4635 }
4636 3799
4637 static const GtkTargetEntry te[] = 3800 static const GtkTargetEntry te[] =
4638 { 3801 {
4639 GTK_IMHTML_DND_TARGETS, 3802 GTK_IMHTML_DND_TARGETS,
4640 {"GAIM_BLIST_NODE", GTK_TARGET_SAME_APP, GTK_IMHTML_DRAG_NUM}, 3803 {"GAIM_BLIST_NODE", GTK_TARGET_SAME_APP, GTK_IMHTML_DRAG_NUM},
4664 } 3827 }
4665 3828
4666 return NULL; 3829 return NULL;
4667 } 3830 }
4668 3831
4669 static void 3832 /**************************************************************************
4670 gaim_gtk_add_conversation(GaimConvWindow *win, GaimConversation *conv) 3833 * Conversation UI operations
4671 { 3834 **************************************************************************/
4672 GaimGtkWindow *gtkwin; 3835 void
4673 GaimGtkConversation *gtkconv, *focus_gtkconv; 3836 gaim_gtkconv_new(GaimConversation *conv)
4674 GaimConversation *focus_conv; 3837 {
3838 GaimGtkConversation *gtkconv;
3839 GaimConversationType conv_type = gaim_conversation_get_type(conv);
4675 GtkWidget *pane = NULL; 3840 GtkWidget *pane = NULL;
4676 GtkWidget *tab_cont; 3841 GtkWidget *tab_cont;
4677 GtkWidget *tabby, *menu_tabby; 3842
4678 GtkWidget *close_image; 3843 if (conv_type == GAIM_CONV_TYPE_IM && (gtkconv = gaim_gtk_conv_find_gtkconv(conv))) {
4679 gboolean new_ui;
4680 GaimConversationType conv_type;
4681 const char *name;
4682 const gchar *tmp_lab;
4683 gint close_button_width, close_button_height, focus_width, focus_pad;
4684
4685 name = gaim_conversation_get_name(conv);
4686 conv_type = gaim_conversation_get_type(conv);
4687 gtkwin = GAIM_GTK_WINDOW(win);
4688
4689 if (conv->ui_data != NULL) {
4690 gtkconv = (GaimGtkConversation *)conv->ui_data;
4691
4692 tab_cont = gtkconv->tab_cont;
4693
4694 new_ui = FALSE;
4695 } else if (conv_type == GAIM_CONV_TYPE_IM && (gtkconv = gaim_gtk_conv_find_gtkconv(conv))) {
4696 conv->ui_data = gtkconv; 3844 conv->ui_data = gtkconv;
4697 gtkconv->active_conv = conv; 3845 gtkconv->active_conv = conv;
4698 if (!g_list_find(gtkconv->convs, conv)) 3846 if (!g_list_find(gtkconv->convs, conv))
4699 gtkconv->convs = g_list_prepend(gtkconv->convs, conv); 3847 gtkconv->convs = g_list_prepend(gtkconv->convs, conv);
4700 return; 3848 return;
4701 } else { 3849 }
4702 gtkconv = g_malloc0(sizeof(GaimGtkConversation)); 3850
4703 conv->ui_data = gtkconv; 3851 gtkconv = g_new0(GaimGtkConversation, 1);
4704 gtkconv->active_conv = conv; 3852 conv->ui_data = gtkconv;
4705 gtkconv->convs = g_list_prepend(gtkconv->convs, conv); 3853 gtkconv->active_conv = conv;
4706 3854 gtkconv->convs = g_list_prepend(gtkconv->convs, conv);
4707 /* Setup some initial variables. */ 3855
4708 gtkconv->sg = gtk_size_group_new(GTK_SIZE_GROUP_BOTH); 3856 /* Setup some initial variables. */
4709 gtkconv->tooltips = gtk_tooltips_new(); 3857 gtkconv->sg = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
4710 3858 gtkconv->tooltips = gtk_tooltips_new();
4711 if (conv_type == GAIM_CONV_TYPE_IM) { 3859
4712 gtkconv->u.im = g_malloc0(sizeof(GaimGtkImPane)); 3860 if (conv_type == GAIM_CONV_TYPE_IM) {
4713 gtkconv->u.im->a_virgin = TRUE; 3861 gtkconv->u.im = g_malloc0(sizeof(GaimGtkImPane));
4714 3862 gtkconv->u.im->a_virgin = TRUE;
4715 pane = setup_im_pane(gtkconv); 3863
4716 } 3864 pane = setup_im_pane(gtkconv);
4717 else if (conv_type == GAIM_CONV_TYPE_CHAT) { 3865 } else if (conv_type == GAIM_CONV_TYPE_CHAT) {
4718 gtkconv->u.chat = g_malloc0(sizeof(GaimGtkChatPane)); 3866 gtkconv->u.chat = g_malloc0(sizeof(GaimGtkChatPane));
4719 3867 pane = setup_chat_pane(gtkconv);
4720 pane = setup_chat_pane(gtkconv); 3868 }
4721 } 3869
4722 3870 if (pane == NULL) {
4723 if (pane == NULL) { 3871 if (conv_type == GAIM_CONV_TYPE_CHAT)
4724 if (conv_type == GAIM_CONV_TYPE_CHAT) g_free(gtkconv->u.chat); 3872 g_free(gtkconv->u.chat);
4725 else if (conv_type == GAIM_CONV_TYPE_IM) g_free(gtkconv->u.im); 3873 else if (conv_type == GAIM_CONV_TYPE_IM)
4726 3874 g_free(gtkconv->u.im);
4727 g_free(gtkconv); 3875
4728 conv->ui_data = NULL; 3876 g_free(gtkconv);
4729 3877 conv->ui_data = NULL;
4730 return; 3878 return;
4731 } 3879 }
4732 3880
4733 /* Setup drag-and-drop */ 3881 /* Setup drag-and-drop */
4734 gtk_drag_dest_set(pane, 3882 gtk_drag_dest_set(pane,
4735 GTK_DEST_DEFAULT_MOTION | 3883 GTK_DEST_DEFAULT_MOTION |
4736 GTK_DEST_DEFAULT_DROP, 3884 GTK_DEST_DEFAULT_DROP,
4737 te, sizeof(te) / sizeof(GtkTargetEntry), 3885 te, sizeof(te) / sizeof(GtkTargetEntry),
4738 GDK_ACTION_COPY); 3886 GDK_ACTION_COPY);
4739 gtk_drag_dest_set(pane, 3887 gtk_drag_dest_set(pane,
4740 GTK_DEST_DEFAULT_MOTION | 3888 GTK_DEST_DEFAULT_MOTION |
4741 GTK_DEST_DEFAULT_DROP, 3889 GTK_DEST_DEFAULT_DROP,
4742 te, sizeof(te) / sizeof(GtkTargetEntry), 3890 te, sizeof(te) / sizeof(GtkTargetEntry),
4743 GDK_ACTION_COPY); 3891 GDK_ACTION_COPY);
4744 gtk_drag_dest_set(gtkconv->imhtml, 0, 3892 gtk_drag_dest_set(gtkconv->imhtml, 0,
4745 te, sizeof(te) / sizeof(GtkTargetEntry), 3893 te, sizeof(te) / sizeof(GtkTargetEntry),
4746 GDK_ACTION_COPY); 3894 GDK_ACTION_COPY);
4747 3895
4748 gtk_drag_dest_set(gtkconv->entry, 0, 3896 gtk_drag_dest_set(gtkconv->entry, 0,
4749 te, sizeof(te) / sizeof(GtkTargetEntry), 3897 te, sizeof(te) / sizeof(GtkTargetEntry),
4750 GDK_ACTION_COPY); 3898 GDK_ACTION_COPY);
4751 3899
4752 g_signal_connect(G_OBJECT(pane), "drag_data_received", 3900 g_signal_connect(G_OBJECT(pane), "drag_data_received",
4753 G_CALLBACK(conv_dnd_recv), gtkconv); 3901 G_CALLBACK(conv_dnd_recv), gtkconv);
4754 g_signal_connect(G_OBJECT(gtkconv->imhtml), "drag_data_received", 3902 g_signal_connect(G_OBJECT(gtkconv->imhtml), "drag_data_received",
4755 G_CALLBACK(conv_dnd_recv), gtkconv); 3903 G_CALLBACK(conv_dnd_recv), gtkconv);
4756 g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received", 3904 g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received",
4757 G_CALLBACK(conv_dnd_recv), gtkconv); 3905 G_CALLBACK(conv_dnd_recv), gtkconv);
4758 3906
4759 /* Setup the container for the tab. */ 3907 /* Setup the container for the tab. */
4760 gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE); 3908 gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
4761 g_object_set_data(G_OBJECT(tab_cont), "GaimGtkConversation", gtkconv); 3909 g_object_set_data(G_OBJECT(tab_cont), "GaimGtkConversation", gtkconv);
4762 gtk_container_set_border_width(GTK_CONTAINER(tab_cont), GAIM_HIG_BOX_SPACE); 3910 gtk_container_set_border_width(GTK_CONTAINER(tab_cont), GAIM_HIG_BOX_SPACE);
4763 gtk_container_add(GTK_CONTAINER(tab_cont), pane); 3911 gtk_container_add(GTK_CONTAINER(tab_cont), pane);
4764 gtk_widget_show(pane); 3912 gtk_widget_show(pane);
4765 3913
4766 new_ui = TRUE; 3914 gtkconv->make_sound = TRUE;
4767 3915
4768 gtkconv->make_sound = TRUE; 3916 if (gaim_prefs_get_bool("/gaim/gtk/conversations/show_formatting_toolbar"))
4769 3917 gtk_widget_show(gtkconv->toolbar);
4770 if (gaim_prefs_get_bool("/gaim/gtk/conversations/show_formatting_toolbar"))
4771 gtk_widget_show(gtkconv->toolbar);
4772 else
4773 gtk_widget_hide(gtkconv->toolbar);
4774
4775 gtkconv->show_timestamps = TRUE;
4776 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), TRUE);
4777
4778 g_signal_connect_swapped(G_OBJECT(pane), "focus",
4779 G_CALLBACK(gtk_widget_grab_focus),
4780 gtkconv->entry);
4781 }
4782
4783 gtkconv->tabby = tabby = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
4784 gtkconv->menu_tabby = menu_tabby = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
4785
4786 /* Close button. */
4787 gtkconv->close = gtk_button_new();
4788 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &close_button_width, &close_button_height);
4789 if (gtk_check_version(2, 4, 2) == NULL)
4790 {
4791 /* Need to account for extra padding around the gtkbutton */
4792 gtk_widget_style_get(GTK_WIDGET(gtkconv->close),
4793 "focus-line-width", &focus_width,
4794 "focus-padding", &focus_pad,
4795 NULL);
4796 close_button_width += (focus_width + focus_pad) * 2;
4797 close_button_height += (focus_width + focus_pad) * 2;
4798 }
4799 gtk_widget_set_size_request(GTK_WIDGET(gtkconv->close),
4800 close_button_width, close_button_height);
4801
4802 gtk_button_set_relief(GTK_BUTTON(gtkconv->close), GTK_RELIEF_NONE);
4803 close_image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
4804 gtk_widget_show(close_image);
4805 gtk_container_add(GTK_CONTAINER(gtkconv->close), close_image);
4806 gtk_tooltips_set_tip(gtkconv->tooltips, gtkconv->close,
4807 _("Close conversation"), NULL);
4808
4809 g_signal_connect(G_OBJECT(gtkconv->close), "clicked",
4810 G_CALLBACK(close_conv_cb), gtkconv);
4811
4812 /*
4813 * I love Galeon. They have a fix for that stupid annoying visible
4814 * border bug. I love you guys! -- ChipX86
4815 */
4816 g_signal_connect(G_OBJECT(gtkconv->close), "state_changed",
4817 G_CALLBACK(tab_close_button_state_changed_cb), NULL);
4818
4819 /* Status icon. */
4820 gtkconv->icon = gtk_image_new();
4821 gtkconv->menu_icon = gtk_image_new();
4822 update_tab_icon(conv);
4823
4824 /* Tab label. */
4825 gtkconv->tab_label = gtk_label_new(tmp_lab = gaim_conversation_get_title(conv));
4826 #if GTK_CHECK_VERSION(2,6,0)
4827 g_object_set(G_OBJECT(gtkconv->tab_label), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
4828 gtk_label_set_width_chars(GTK_LABEL(gtkconv->tab_label), 6);
4829 #endif
4830 gtkconv->menu_label = gtk_label_new(gaim_conversation_get_title(conv));
4831 #if 0
4832 gtk_misc_set_alignment(GTK_MISC(gtkconv->tab_label), 0.00, 0.5);
4833 gtk_misc_set_padding(GTK_MISC(gtkconv->tab_label), 4, 0);
4834 #endif
4835
4836 /* Pack it all together. */
4837 gtk_box_pack_start(GTK_BOX(tabby), gtkconv->icon, FALSE, FALSE, 0);
4838 gtk_box_pack_start(GTK_BOX(menu_tabby), gtkconv->menu_icon,
4839 FALSE, FALSE, 0);
4840
4841 gtk_widget_show_all(gtkconv->icon);
4842 gtk_widget_show_all(gtkconv->menu_icon);
4843
4844 gtk_box_pack_start(GTK_BOX(tabby), gtkconv->tab_label, TRUE, TRUE, 0);
4845 gtk_box_pack_start(GTK_BOX(menu_tabby), gtkconv->menu_label, TRUE, TRUE, 0);
4846 gtk_widget_show(gtkconv->tab_label);
4847 gtk_widget_show(gtkconv->menu_label);
4848 gtk_misc_set_alignment(GTK_MISC(gtkconv->menu_label), 0, 0);
4849
4850 gtk_box_pack_start(GTK_BOX(tabby), gtkconv->close, FALSE, FALSE, 0);
4851 if (gaim_prefs_get_bool("/gaim/gtk/conversations/close_on_tabs"))
4852 gtk_widget_show(gtkconv->close);
4853
4854 gtk_widget_show(tabby);
4855 gtk_widget_show(menu_tabby);
4856
4857 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
4858 gaim_gtkconv_update_buddy_icon(conv);
4859
4860 /* Add this pane to the conversation's notebook. */
4861 gtk_notebook_append_page_menu(GTK_NOTEBOOK(gtkwin->notebook), tab_cont, tabby, menu_tabby);
4862 gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(gtkwin->notebook), tab_cont, TRUE, TRUE, GTK_PACK_START);
4863
4864
4865 gtk_widget_show(tab_cont);
4866
4867 if (gaim_conv_window_get_conversation_count(win) == 1) {
4868 /* Er, bug in notebooks? Switch to the page manually. */
4869 gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), 0);
4870
4871 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkwin->notebook),
4872 gaim_prefs_get_bool("/gaim/gtk/conversations/tabs"));
4873 }
4874 else 3918 else
4875 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkwin->notebook), TRUE); 3919 gtk_widget_hide(gtkconv->toolbar);
4876 3920
4877 focus_conv = g_list_nth_data(gaim_conv_window_get_conversations(win), 3921 gtkconv->show_timestamps = TRUE;
4878 gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkwin->notebook))); 3922 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), TRUE);
4879 focus_gtkconv = GAIM_GTK_CONVERSATION(focus_conv); 3923
4880 gtk_widget_grab_focus(focus_gtkconv->entry); 3924 g_signal_connect_swapped(G_OBJECT(pane), "focus",
4881 3925 G_CALLBACK(gtk_widget_grab_focus),
4882 if (!new_ui) 3926 gtkconv->entry);
4883 g_object_unref(gtkconv->tab_cont); 3927
4884 3928 gaim_gtkconv_placement_place(gtkconv);
4885 if (gaim_conv_window_get_conversation_count(win) == 1) 3929 }
4886 g_timeout_add(0, (GSourceFunc)update_send_as_selection, win); 3930
4887 }
4888
4889 static void
4890 gaim_gtk_remove_conversation(GaimConvWindow *win, GaimConversation *conv)
4891 {
4892 GaimGtkWindow *gtkwin;
4893 GaimGtkConversation *gtkconv;
4894 unsigned int index;
4895 GaimConversationType conv_type;
4896
4897 conv_type = gaim_conversation_get_type(conv);
4898 gtkwin = GAIM_GTK_WINDOW(win);
4899 gtkconv = GAIM_GTK_CONVERSATION(conv);
4900 index = gtk_notebook_page_num(GTK_NOTEBOOK(gtkwin->notebook), gtkconv->tab_cont);
4901
4902 g_object_ref(gtkconv->tab_cont);
4903 gtk_object_sink(GTK_OBJECT(gtkconv->tab_cont));
4904
4905 gtk_notebook_remove_page(GTK_NOTEBOOK(gtkwin->notebook), index);
4906
4907 /* go back to tabless if need be */
4908 if (gaim_conv_window_get_conversation_count(win) <= 2) {
4909 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gtkwin->notebook),
4910 gaim_prefs_get_bool("/gaim/gtk/conversations/tabs"));
4911 }
4912
4913
4914 /* If this window is setup with an inactive gc, regenerate the menu. */
4915 if (conv_type == GAIM_CONV_TYPE_IM &&
4916 gaim_conversation_get_gc(conv) == NULL) {
4917
4918 generate_send_as_items(win, conv);
4919 }
4920 }
4921
4922 GaimGtkConversation *
4923 gaim_gtk_get_gtkconv_at_index(const GaimConvWindow *win, int index)
4924 {
4925 GaimGtkWindow *gtkwin;
4926 GtkWidget *tab_cont;
4927
4928 gtkwin = GAIM_GTK_WINDOW(win);
4929
4930 if (index == -1)
4931 index = 0;
4932 tab_cont = gtk_notebook_get_nth_page(GTK_NOTEBOOK(gtkwin->notebook), index);
4933 return g_object_get_data(G_OBJECT(tab_cont), "GaimGtkConversation");
4934 }
4935
4936 static GaimConversation *
4937 gaim_gtk_get_active_conversation(const GaimConvWindow *win)
4938 {
4939 GaimGtkWindow *gtkwin;
4940 GaimGtkConversation *gtkconv;
4941 int index;
4942 GtkWidget *tab_cont;
4943
4944 gtkwin = GAIM_GTK_WINDOW(win);
4945
4946 index = gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkwin->notebook));
4947 if (index == -1)
4948 index = 0;
4949 tab_cont = gtk_notebook_get_nth_page(GTK_NOTEBOOK(gtkwin->notebook), index);
4950 if (!tab_cont)
4951 return NULL;
4952 gtkconv = g_object_get_data(G_OBJECT(tab_cont), "GaimGtkConversation");
4953 return gtkconv->active_conv;
4954 }
4955
4956 static gboolean
4957 gaim_gtk_has_focus(GaimConvWindow *win)
4958 {
4959 GaimGtkWindow *gtkwin;
4960 gboolean has_focus = FALSE;
4961
4962 gtkwin = GAIM_GTK_WINDOW(win);
4963 g_object_get(G_OBJECT(gtkwin->window), "has-toplevel-focus", &has_focus, NULL);
4964
4965 return has_focus;
4966 }
4967
4968 static GaimConvWindowUiOps window_ui_ops =
4969 {
4970 gaim_gtk_conversations_get_conv_ui_ops,
4971 gaim_gtk_new_window,
4972 gaim_gtk_destroy_window,
4973 gaim_gtk_show,
4974 gaim_gtk_hide,
4975 gaim_gtk_raise,
4976 gaim_gtk_switch_conversation,
4977 gaim_gtk_add_conversation,
4978 gaim_gtk_remove_conversation,
4979 gaim_gtk_get_active_conversation,
4980 gaim_gtk_has_focus
4981 };
4982
4983 GaimConvWindowUiOps *
4984 gaim_gtk_conversations_get_win_ui_ops(void)
4985 {
4986 return &window_ui_ops;
4987 }
4988
4989 /**************************************************************************
4990 * Conversation UI operations
4991 **************************************************************************/
4992 static void 3931 static void
4993 gaim_gtkconv_destroy(GaimConversation *conv) 3932 gaim_gtkconv_destroy(GaimConversation *conv)
4994 { 3933 {
4995 GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv); 3934 GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv);
4996 3935
4997 gtkconv->convs = g_list_remove(gtkconv->convs, conv); 3936 gtkconv->convs = g_list_remove(gtkconv->convs, conv);
4998 /* Don't destroy ourselves until all our convos are gone */ 3937 /* Don't destroy ourselves until all our convos are gone */
4999 if (gtkconv->convs) 3938 if (gtkconv->convs)
5000 return; 3939 return;
5001 3940
3941 gaim_gtk_conv_window_remove_gtkconv(gtkconv->win, gtkconv);
3942 /* should we be doing this here or in gaim_gtk_conv_window_remove_gtkconv()? */
3943 if (!gtkconv->win->gtkconvs)
3944 gaim_gtk_conv_window_destroy(gtkconv->win);
3945
5002 /* If the "Save Conversation" or "Save Icon" dialogs are open then close them */ 3946 /* If the "Save Conversation" or "Save Icon" dialogs are open then close them */
5003 gaim_request_close_with_handle(conv); 3947 gaim_request_close_with_handle(conv);
5004 3948
5005 gtk_widget_destroy(gtkconv->tab_cont); 3949 gtk_widget_destroy(gtkconv->tab_cont);
5006 g_object_unref(gtkconv->tab_cont); 3950 g_object_unref(gtkconv->tab_cont);
5011 3955
5012 if (gtkconv->u.im->anim != NULL) 3956 if (gtkconv->u.im->anim != NULL)
5013 g_object_unref(G_OBJECT(gtkconv->u.im->anim)); 3957 g_object_unref(G_OBJECT(gtkconv->u.im->anim));
5014 3958
5015 g_free(gtkconv->u.im); 3959 g_free(gtkconv->u.im);
5016 } 3960 } else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
5017 else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
5018 gaim_signals_disconnect_by_handle(gtkconv->u.chat); 3961 gaim_signals_disconnect_by_handle(gtkconv->u.chat);
5019 g_free(gtkconv->u.chat); 3962 g_free(gtkconv->u.chat);
5020 } 3963 }
5021 3964
5022 gtk_object_sink(GTK_OBJECT(gtkconv->tooltips)); 3965 gtk_object_sink(GTK_OBJECT(gtkconv->tooltips));
5136 gaim_gtkconv_write_conv(GaimConversation *conv, const char *name, const char *alias, 4079 gaim_gtkconv_write_conv(GaimConversation *conv, const char *name, const char *alias,
5137 const char *message, GaimMessageFlags flags, 4080 const char *message, GaimMessageFlags flags,
5138 time_t mtime) 4081 time_t mtime)
5139 { 4082 {
5140 GaimGtkConversation *gtkconv; 4083 GaimGtkConversation *gtkconv;
5141 GaimConvWindow *win; 4084 GaimGtkWindow *win;
5142 GaimConnection *gc; 4085 GaimConnection *gc;
5143 GaimAccount *account; 4086 GaimAccount *account;
5144 GaimPluginProtocolInfo *prpl_info; 4087 GaimPluginProtocolInfo *prpl_info;
5145 int gtk_font_options = 0; 4088 int gtk_font_options = 0;
5146 int max_scrollback_lines = gaim_prefs_get_int( 4089 int max_scrollback_lines = gaim_prefs_get_int(
5153 char *with_font_tag; 4096 char *with_font_tag;
5154 char *sml_attrib = NULL; 4097 char *sml_attrib = NULL;
5155 size_t length = strlen(message) + 1; 4098 size_t length = strlen(message) + 1;
5156 4099
5157 gtkconv = GAIM_GTK_CONVERSATION(conv); 4100 gtkconv = GAIM_GTK_CONVERSATION(conv);
4101
4102 /* Set the active conversation to the one that just messaged us. */
4103 /* TODO: consider not doing this if the account is offline or something */
5158 gtkconv->active_conv = conv; 4104 gtkconv->active_conv = conv;
4105
5159 gc = gaim_conversation_get_gc(conv); 4106 gc = gaim_conversation_get_gc(conv);
5160 account = gaim_conversation_get_account(conv); 4107 account = gaim_conversation_get_account(conv);
5161 win = gaim_conversation_get_window(conv); 4108 win = gtkconv->win;
5162 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); 4109 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
5163 4110
5164 line_count = gtk_text_buffer_get_line_count( 4111 line_count = gtk_text_buffer_get_line_count(
5165 gtk_text_view_get_buffer(GTK_TEXT_VIEW( 4112 gtk_text_view_get_buffer(GTK_TEXT_VIEW(
5166 gtkconv->imhtml))); 4113 gtkconv->imhtml)));
5303 /* Are we in a chat where we can tell which users are buddies? */ 4250 /* Are we in a chat where we can tell which users are buddies? */
5304 if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME) && 4251 if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME) &&
5305 gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) { 4252 gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
5306 4253
5307 /* Bold buddies to make them stand out from non-buddies. */ 4254 /* Bold buddies to make them stand out from non-buddies. */
5308 if (flags & GAIM_MESSAGE_SEND || 4255 if (flags & GAIM_MESSAGE_SEND ||
5309 flags & GAIM_MESSAGE_NICK || 4256 flags & GAIM_MESSAGE_NICK ||
5310 gaim_find_buddy(account, name) != NULL) { 4257 gaim_find_buddy(account, name) != NULL) {
5311 g_snprintf(buf2, BUF_LONG, 4258 g_snprintf(buf2, BUF_LONG,
5312 "<FONT COLOR=\"%s\" %s><FONT SIZE=\"2\"><!--(%s) --></FONT>" 4259 "<FONT COLOR=\"%s\" %s><FONT SIZE=\"2\"><!--(%s) --></FONT>"
5313 "<B>%s</B></FONT> ", 4260 "<B>%s</B></FONT> ",
5608 4555
5609 add_chat_buddy_common(conv, user, alias, NULL); 4556 add_chat_buddy_common(conv, user, alias, NULL);
5610 g_free(alias); 4557 g_free(alias);
5611 } 4558 }
5612 4559
5613 static gboolean 4560 gboolean
5614 gaim_gtkconv_has_focus(GaimConversation *conv) 4561 gaim_gtkconv_has_focus(GaimConversation *conv)
5615 { 4562 {
5616 GaimConvWindow *win; 4563 GaimGtkConversation *gtkconv = GAIM_GTK_CONVERSATION(conv);
5617 GaimGtkWindow *gtkwin; 4564 GaimGtkWindow *win;
5618 gboolean has_focus; 4565 gboolean has_focus;
5619 4566
5620 win = gaim_conversation_get_window(conv); 4567 win = gtkconv->win;
5621 gtkwin = GAIM_GTK_WINDOW(win); 4568
5622 4569 g_object_get(G_OBJECT(win->window), "has-toplevel-focus", &has_focus, NULL);
5623 g_object_get(G_OBJECT(gtkwin->window), "has-toplevel-focus", &has_focus, NULL);
5624 4570
5625 return has_focus; 4571 return has_focus;
5626 } 4572 }
5627 4573
5628 static gboolean 4574 static gboolean
5782 gdk_pixbuf_loader_close(loader, NULL); 4728 gdk_pixbuf_loader_close(loader, NULL);
5783 g_object_unref(G_OBJECT(loader)); 4729 g_object_unref(G_OBJECT(loader));
5784 smiley->loader = NULL; 4730 smiley->loader = NULL;
5785 } 4731 }
5786 4732
4733 /*
4734 * Makes sure all the menu items and all the buttons are hidden/shown and
4735 * sensitive/insensitive. This is called after changing tabs and when an
4736 * account signs on or off.
4737 */
4738 static void
4739 gray_stuff_out(GaimGtkConversation *gtkconv)
4740 {
4741 GaimGtkWindow *win;
4742 GaimConversation *conv = gtkconv->active_conv;
4743 GaimConnection *gc;
4744 GaimPluginProtocolInfo *prpl_info = NULL;
4745 GdkPixbuf *window_icon = NULL;
4746 GtkIMHtmlButtons buttons;
4747 GaimAccount *account;
4748
4749 win = gaim_gtkconv_get_window(gtkconv);
4750 gc = gaim_conversation_get_gc(conv);
4751 account = gaim_conversation_get_account(conv);
4752
4753 if (gc != NULL)
4754 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
4755
4756 if (win->menu.send_as != NULL)
4757 g_timeout_add(0, (GSourceFunc)update_send_as_selection, win);
4758
4759 /*
4760 * Handle hiding and showing stuff based on what type of conv this is.
4761 * Stuff that Gaim IMs support in general should be shown for IM
4762 * conversations. Stuff that Gaim chats support in general should be
4763 * shown for chat conversations. It doesn't matter whether the PRPL
4764 * supports it or not--that only affects if the button or menu item
4765 * is sensitive or not.
4766 */
4767 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) {
4768 /* Show stuff that applies to IMs, hide stuff that applies to chats */
4769
4770 /* Deal with menu items */
4771 gtk_widget_show(win->menu.view_log);
4772 gtk_widget_show(win->menu.send_file);
4773 gtk_widget_show(win->menu.add_pounce);
4774 gtk_widget_show(win->menu.get_info);
4775 gtk_widget_hide(win->menu.invite);
4776 gtk_widget_show(win->menu.alias);
4777 gtk_widget_show(win->menu.block);
4778
4779 if (gaim_find_buddy(account, gaim_conversation_get_name(conv)) == NULL) {
4780 gtk_widget_show(win->menu.add);
4781 gtk_widget_hide(win->menu.remove);
4782 } else {
4783 gtk_widget_show(win->menu.remove);
4784 gtk_widget_hide(win->menu.add);
4785 }
4786
4787 gtk_widget_show(win->menu.insert_link);
4788 gtk_widget_show(win->menu.insert_image);
4789 gtk_widget_show(win->menu.show_icon);
4790 } else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
4791 /* Show stuff that applies to Chats, hide stuff that applies to IMs */
4792
4793 /* Deal with menu items */
4794 gtk_widget_show(win->menu.view_log);
4795 gtk_widget_hide(win->menu.send_file);
4796 gtk_widget_hide(win->menu.add_pounce);
4797 gtk_widget_hide(win->menu.get_info);
4798 gtk_widget_show(win->menu.invite);
4799 gtk_widget_show(win->menu.alias);
4800 gtk_widget_hide(win->menu.block);
4801 gtk_widget_hide(win->menu.show_icon);
4802
4803 if (gaim_blist_find_chat(account, gaim_conversation_get_name(conv)) == NULL) {
4804 /* If the chat is NOT in the buddy list */
4805 gtk_widget_show(win->menu.add);
4806 gtk_widget_hide(win->menu.remove);
4807 } else {
4808 /* If the chat IS in the buddy list */
4809 gtk_widget_hide(win->menu.add);
4810 gtk_widget_show(win->menu.remove);
4811 }
4812
4813 gtk_widget_show(win->menu.insert_link);
4814 gtk_widget_hide(win->menu.insert_image);
4815 }
4816
4817 /*
4818 * Handle graying stuff out based on whether an account is connected
4819 * and what features that account supports.
4820 */
4821 if ((gc != NULL) &&
4822 ( (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_CHAT) ||
4823 !gaim_conv_chat_has_left(GAIM_CONV_CHAT(conv)) )) {
4824 /* Account is online */
4825 /* Deal with the toolbar */
4826 if (conv->features & GAIM_CONNECTION_HTML) {
4827 buttons = GTK_IMHTML_ALL; /* Everything on */
4828 if (!(prpl_info->options & OPT_PROTO_IM_IMAGE) ||
4829 conv->features & GAIM_CONNECTION_NO_IMAGES)
4830 buttons &= ~GTK_IMHTML_IMAGE;
4831 if (conv->features & GAIM_CONNECTION_NO_BGCOLOR)
4832 buttons &= ~GTK_IMHTML_BACKCOLOR;
4833 if (conv->features & GAIM_CONNECTION_NO_FONTSIZE) {
4834 buttons &= ~GTK_IMHTML_GROW;
4835 buttons &= ~GTK_IMHTML_SHRINK;
4836 }
4837 if (conv->features & GAIM_CONNECTION_NO_URLDESC)
4838 buttons &= ~GTK_IMHTML_LINKDESC;
4839 } else {
4840 buttons = GTK_IMHTML_SMILEY;
4841 }
4842 gtk_imhtml_set_format_functions(GTK_IMHTML(gtkconv->entry), buttons);
4843 gtk_imhtmltoolbar_associate_smileys(GTK_IMHTMLTOOLBAR(gtkconv->toolbar), gaim_account_get_protocol_id(account));
4844
4845 /* Deal with menu items */
4846 gtk_widget_set_sensitive(win->menu.view_log, TRUE);
4847 gtk_widget_set_sensitive(win->menu.add_pounce, TRUE);
4848 gtk_widget_set_sensitive(win->menu.get_info, (prpl_info->get_info != NULL));
4849 gtk_widget_set_sensitive(win->menu.invite, (prpl_info->chat_invite != NULL));
4850 gtk_widget_set_sensitive(win->menu.block, (prpl_info->add_deny != NULL));
4851 gtk_widget_set_sensitive(win->menu.insert_link, (conv->features & GAIM_CONNECTION_HTML));
4852 gtk_widget_set_sensitive(win->menu.insert_image, (prpl_info->options & OPT_PROTO_IM_IMAGE));
4853
4854 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) {
4855 gtk_widget_set_sensitive(win->menu.add, (prpl_info->add_buddy != NULL));
4856 gtk_widget_set_sensitive(win->menu.remove, (prpl_info->remove_buddy != NULL));
4857 gtk_widget_set_sensitive(win->menu.send_file,
4858 (prpl_info->send_file != NULL && (!prpl_info->can_receive_file ||
4859 prpl_info->can_receive_file(gc, gaim_conversation_get_name(conv)))));
4860 gtk_widget_set_sensitive(win->menu.alias,
4861 (gaim_find_buddy(account, gaim_conversation_get_name(conv)) != NULL));
4862 } else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
4863 gtk_widget_set_sensitive(win->menu.add, (prpl_info->join_chat != NULL));
4864 gtk_widget_set_sensitive(win->menu.remove, (prpl_info->join_chat != NULL));
4865 gtk_widget_set_sensitive(win->menu.alias,
4866 (gaim_blist_find_chat(account, gaim_conversation_get_name(conv)) != NULL));
4867 }
4868
4869 /* Deal with chat userlist buttons */
4870 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)
4871 {
4872 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_im, TRUE);
4873 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_ignore, TRUE);
4874 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_info, (prpl_info->get_info != NULL));
4875 }
4876 } else {
4877 /* Account is offline */
4878 /* Or it's a chat that we've left. */
4879
4880 /* Then deal with menu items */
4881 gtk_widget_set_sensitive(win->menu.view_log, TRUE);
4882 gtk_widget_set_sensitive(win->menu.send_file, FALSE);
4883 gtk_widget_set_sensitive(win->menu.add_pounce, TRUE);
4884 gtk_widget_set_sensitive(win->menu.get_info, FALSE);
4885 gtk_widget_set_sensitive(win->menu.invite, FALSE);
4886 gtk_widget_set_sensitive(win->menu.alias, FALSE);
4887 gtk_widget_set_sensitive(win->menu.block, FALSE);
4888 gtk_widget_set_sensitive(win->menu.add, FALSE);
4889 gtk_widget_set_sensitive(win->menu.remove, FALSE);
4890 gtk_widget_set_sensitive(win->menu.insert_link, TRUE);
4891 gtk_widget_set_sensitive(win->menu.insert_image, FALSE);
4892
4893 /* Deal with chat userlist buttons */
4894 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)
4895 {
4896 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_im, FALSE);
4897 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_ignore, FALSE);
4898 gtk_widget_set_sensitive(gtkconv->u.chat->userlist_info, FALSE);
4899 }
4900 }
4901
4902 /*
4903 * Update the window's icon
4904 */
4905 if ((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) &&
4906 (gtkconv->u.im->anim))
4907 {
4908 window_icon =
4909 gdk_pixbuf_animation_get_static_image(gtkconv->u.im->anim);
4910 g_object_ref(window_icon);
4911 } else {
4912 window_icon = gaim_gtkconv_get_tab_icon(conv, FALSE);
4913 }
4914 gtk_window_set_icon(GTK_WINDOW(win->window), window_icon);
4915 if (window_icon != NULL)
4916 g_object_unref(G_OBJECT(window_icon));
4917 }
4918
5787 4919
5788 static void 4920 static void
5789 gaim_gtkconv_updated(GaimConversation *conv, GaimConvUpdateType type) 4921 gaim_gtkconv_updated(GaimConversation *conv, GaimConvUpdateType type)
5790 { 4922 {
5791 GaimConvWindow *win; 4923 GaimGtkWindow *win;
5792 GaimGtkWindow *gtkwin;
5793 GaimGtkConversation *gtkconv; 4924 GaimGtkConversation *gtkconv;
5794 GaimGtkChatPane *gtkchat; 4925 GaimGtkChatPane *gtkchat;
5795 GaimConvChat *chat; 4926 GaimConvChat *chat;
5796 4927
5797 g_return_if_fail(conv != NULL); 4928 g_return_if_fail(conv != NULL);
5798 4929
5799 win = gaim_conversation_get_window(conv);
5800 gtkwin = GAIM_GTK_WINDOW(win);
5801 gtkconv = GAIM_GTK_CONVERSATION(conv); 4930 gtkconv = GAIM_GTK_CONVERSATION(conv);
4931 win = gtkconv->win;
5802 conv = gtkconv->active_conv; /* Gross hack */ 4932 conv = gtkconv->active_conv; /* Gross hack */
4933 /* Maybe we should just ignore it if conv != gtkconv->active_conv,
4934 * instead of the gross hack?
4935 */
5803 4936
5804 if (type == GAIM_CONV_UPDATE_ACCOUNT) 4937 if (type == GAIM_CONV_UPDATE_ACCOUNT)
5805 { 4938 {
5806 gaim_conversation_autoset_title(conv); 4939 gaim_conversation_autoset_title(conv);
5807 4940
5874 g_free(label); 5007 g_free(label);
5875 } 5008 }
5876 else 5009 else
5877 gtk_label_set_text(GTK_LABEL(gtkconv->tab_label), title); 5010 gtk_label_set_text(GTK_LABEL(gtkconv->tab_label), title);
5878 5011
5879 if (conv == gaim_conv_window_get_active_conversation(win)) 5012 if (conv == gaim_gtk_conv_window_get_active_conversation(win))
5880 update_typing_icon(gtkconv); 5013 update_typing_icon(gtkconv);
5881 5014
5882 if (type == GAIM_CONV_UPDATE_TITLE) { 5015 if (type == GAIM_CONV_UPDATE_TITLE) {
5883 gtk_label_set_text(GTK_LABEL(gtkconv->menu_label), title); 5016 gtk_label_set_text(GTK_LABEL(gtkconv->menu_label), title);
5884 if (conv == gaim_conv_window_get_active_conversation(win)) 5017 if (conv == gaim_gtk_conv_window_get_active_conversation(win))
5885 gtk_window_set_title(GTK_WINDOW(gtkwin->window), title); 5018 gtk_window_set_title(GTK_WINDOW(win->window), title);
5886 } 5019 }
5887 5020
5888 g_free(title); 5021 g_free(title);
5889 } 5022 }
5890 else if (type == GAIM_CONV_UPDATE_TOPIC) 5023 else if (type == GAIM_CONV_UPDATE_TOPIC)
5900 topic ? topic : "", NULL); 5033 topic ? topic : "", NULL);
5901 } 5034 }
5902 else if (type == GAIM_CONV_ACCOUNT_ONLINE || 5035 else if (type == GAIM_CONV_ACCOUNT_ONLINE ||
5903 type == GAIM_CONV_ACCOUNT_OFFLINE) 5036 type == GAIM_CONV_ACCOUNT_OFFLINE)
5904 { 5037 {
5905 gray_stuff_out(GAIM_GTK_CONVERSATION(gaim_conv_window_get_active_conversation(win))); 5038 gray_stuff_out(GAIM_GTK_CONVERSATION(gaim_gtk_conv_window_get_active_conversation(win)));
5906 generate_send_as_items(win, NULL); 5039 generate_send_as_items(win, NULL);
5907 update_tab_icon(conv); 5040 update_tab_icon(conv);
5908 gaim_conversation_autoset_title(conv); 5041 gaim_conversation_autoset_title(conv);
5909 } 5042 }
5910 else if (type == GAIM_CONV_UPDATE_AWAY) 5043 else if (type == GAIM_CONV_UPDATE_AWAY)
5927 } 5060 }
5928 } 5061 }
5929 5062
5930 static GaimConversationUiOps conversation_ui_ops = 5063 static GaimConversationUiOps conversation_ui_ops =
5931 { 5064 {
5065 gaim_gtkconv_new,
5932 gaim_gtkconv_destroy, /* destroy_conversation */ 5066 gaim_gtkconv_destroy, /* destroy_conversation */
5933 gaim_gtkconv_write_chat, /* write_chat */ 5067 gaim_gtkconv_write_chat, /* write_chat */
5934 gaim_gtkconv_write_im, /* write_im */ 5068 gaim_gtkconv_write_im, /* write_im */
5935 gaim_gtkconv_write_conv, /* write_conv */ 5069 gaim_gtkconv_write_conv, /* write_conv */
5936 gaim_gtkconv_chat_add_users, /* chat_add_users */ 5070 gaim_gtkconv_chat_add_users, /* chat_add_users */
5937 gaim_gtkconv_chat_rename_user, /* chat_rename_user */ 5071 gaim_gtkconv_chat_rename_user, /* chat_rename_user */
5938 gaim_gtkconv_chat_remove_user, /* chat_remove_user */ 5072 gaim_gtkconv_chat_remove_user, /* chat_remove_user */
5939 gaim_gtkconv_chat_remove_users, /* chat_remove_users */ 5073 gaim_gtkconv_chat_remove_users, /* chat_remove_users */
5940 gaim_gtkconv_chat_update_user, /* chat_update_user */ 5074 gaim_gtkconv_chat_update_user, /* chat_update_user */
5941 NULL, /* update_progress */
5942 gaim_gtkconv_has_focus, /* has_focus */ 5075 gaim_gtkconv_has_focus, /* has_focus */
5943 gaim_gtkconv_custom_smiley_add, /* custom_smiley_add */ 5076 gaim_gtkconv_custom_smiley_add, /* custom_smiley_add */
5944 gaim_gtkconv_custom_smiley_write, /* custom_smiley_write */ 5077 gaim_gtkconv_custom_smiley_write, /* custom_smiley_write */
5945 gaim_gtkconv_custom_smiley_close, /* custom_smiley_close */ 5078 gaim_gtkconv_custom_smiley_close, /* custom_smiley_close */
5946 gaim_gtkconv_updated /* updated */ 5079 gaim_gtkconv_updated /* updated */
5957 **************************************************************************/ 5090 **************************************************************************/
5958 void 5091 void
5959 gaim_gtkconv_update_buddy_icon(GaimConversation *conv) 5092 gaim_gtkconv_update_buddy_icon(GaimConversation *conv)
5960 { 5093 {
5961 GaimGtkConversation *gtkconv; 5094 GaimGtkConversation *gtkconv;
5962 GaimGtkWindow *gtkwin = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv)); 5095 GaimGtkWindow *win;
5963 5096
5964 GdkPixbufLoader *loader; 5097 GdkPixbufLoader *loader;
5965 GdkPixbufAnimation *anim; 5098 GdkPixbufAnimation *anim;
5966 GError *err = NULL; 5099 GError *err = NULL;
5967 5100
5985 g_return_if_fail(conv != NULL); 5118 g_return_if_fail(conv != NULL);
5986 g_return_if_fail(GAIM_IS_GTK_CONVERSATION(conv)); 5119 g_return_if_fail(GAIM_IS_GTK_CONVERSATION(conv));
5987 g_return_if_fail(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM); 5120 g_return_if_fail(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM);
5988 5121
5989 gtkconv = GAIM_GTK_CONVERSATION(conv); 5122 gtkconv = GAIM_GTK_CONVERSATION(conv);
5123 win = gtkconv->win;
5990 5124
5991 if (!gtkconv->u.im->show_icon) 5125 if (!gtkconv->u.im->show_icon)
5992 return; 5126 return;
5993 5127
5994 account = gaim_conversation_get_account(conv); 5128 account = gaim_conversation_get_account(conv);
6103 gtk_widget_show(gtkconv->u.im->icon_container); 5237 gtk_widget_show(gtkconv->u.im->icon_container);
6104 gtk_widget_show(frame); 5238 gtk_widget_show(frame);
6105 5239
6106 /* The buddy icon code needs badly to be fixed. */ 5240 /* The buddy icon code needs badly to be fixed. */
6107 buf = gdk_pixbuf_animation_get_static_image(gtkconv->u.im->anim); 5241 buf = gdk_pixbuf_animation_get_static_image(gtkconv->u.im->anim);
6108 if(conv == gaim_conv_window_get_active_conversation(gaim_conversation_get_window(conv))) 5242 if(conv == gaim_gtk_conv_window_get_active_conversation(gtkconv->win))
6109 gtk_window_set_icon(GTK_WINDOW(gtkwin->window), buf); 5243 gtk_window_set_icon(GTK_WINDOW(win->window), buf);
6110 } 5244 }
6111 5245
6112 void 5246 void
6113 gaim_gtkconv_update_buttons_by_protocol(GaimConversation *conv) 5247 gaim_gtkconv_update_buttons_by_protocol(GaimConversation *conv)
6114 { 5248 {
6115 GaimConvWindow *win; 5249 GaimGtkWindow *win;
6116 5250
6117 if (!GAIM_IS_GTK_CONVERSATION(conv)) 5251 if (!GAIM_IS_GTK_CONVERSATION(conv))
6118 return; 5252 return;
6119 5253
6120 win = gaim_conversation_get_window(conv); 5254 win = GAIM_GTK_CONVERSATION(conv)->win;
6121 5255
6122 if (win != NULL && gaim_conv_window_get_active_conversation(win) == conv) 5256 if (win != NULL && gaim_gtk_conv_window_is_active_conversation(conv))
6123 gray_stuff_out(GAIM_GTK_CONVERSATION(conv)); 5257 gray_stuff_out(GAIM_GTK_CONVERSATION(conv));
6124 } 5258 }
6125 5259
6126 GaimConvWindow *
6127 gaim_gtkwin_get_at_xy(int x, int y)
6128 {
6129 GaimConvWindow *win = NULL;
6130 GaimGtkWindow *gtkwin;
6131 GdkWindow *gdkwin;
6132 GList *l;
6133
6134 gdkwin = gdk_window_at_pointer(&x, &y);
6135
6136 if (gdkwin)
6137 gdkwin = gdk_window_get_toplevel(gdkwin);
6138
6139 for (l = gaim_get_windows(); l != NULL; l = l->next) {
6140 win = (GaimConvWindow *)l->data;
6141
6142 if (!GAIM_IS_GTK_WINDOW(win))
6143 continue;
6144
6145 gtkwin = GAIM_GTK_WINDOW(win);
6146
6147 if (gdkwin == gtkwin->window->window)
6148 return win;
6149 }
6150
6151 return NULL;
6152 }
6153
6154 int 5260 int
6155 gaim_gtkconv_get_tab_at_xy(GaimConvWindow *win, int x, int y) 5261 gaim_gtkconv_get_tab_at_xy(GaimGtkWindow *win, int x, int y)
6156 { 5262 {
6157 GaimGtkWindow *gtkwin;
6158 gint nb_x, nb_y, x_rel, y_rel; 5263 gint nb_x, nb_y, x_rel, y_rel;
6159 GtkNotebook *notebook; 5264 GtkNotebook *notebook;
6160 GtkWidget *page, *tab; 5265 GtkWidget *page, *tab;
6161 gint i, page_num = -1; 5266 gint i, page_num = -1;
6162 gint count; 5267 gint count;
6163 gboolean horiz; 5268 gboolean horiz;
6164 5269
6165 if (!GAIM_IS_GTK_WINDOW(win)) 5270 notebook = GTK_NOTEBOOK(win->notebook);
6166 return -1; 5271
6167 5272 gdk_window_get_origin(win->notebook->window, &nb_x, &nb_y);
6168 gtkwin = GAIM_GTK_WINDOW(win);
6169 notebook = GTK_NOTEBOOK(gtkwin->notebook);
6170
6171 gdk_window_get_origin(gtkwin->notebook->window, &nb_x, &nb_y);
6172 x_rel = x - nb_x; 5273 x_rel = x - nb_x;
6173 y_rel = y - nb_y; 5274 y_rel = y - nb_y;
6174 5275
6175 horiz = (gtk_notebook_get_tab_pos(notebook) == GTK_POS_TOP || 5276 horiz = (gtk_notebook_get_tab_pos(notebook) == GTK_POS_TOP ||
6176 gtk_notebook_get_tab_pos(notebook) == GTK_POS_BOTTOM); 5277 gtk_notebook_get_tab_pos(notebook) == GTK_POS_BOTTOM);
6256 tab_side_pref_cb(const char *name, GaimPrefType type, gpointer value, 5357 tab_side_pref_cb(const char *name, GaimPrefType type, gpointer value,
6257 gpointer data) 5358 gpointer data)
6258 { 5359 {
6259 GList *l; 5360 GList *l;
6260 GtkPositionType pos; 5361 GtkPositionType pos;
6261 GaimConvWindow *win; 5362 GaimGtkWindow *win;
6262 GaimGtkWindow *gtkwin;
6263 5363
6264 pos = GPOINTER_TO_INT(value); 5364 pos = GPOINTER_TO_INT(value);
6265 5365
6266 for (l = gaim_get_windows(); l != NULL; l = l->next) { 5366 for (l = gaim_gtk_conv_windows_get_list(); l != NULL; l = l->next) {
6267 win = (GaimConvWindow *)l->data; 5367 win = l->data;
6268 5368
6269 if (!GAIM_IS_GTK_WINDOW(win)) 5369 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(win->notebook), pos);
6270 continue;
6271
6272 gtkwin = GAIM_GTK_WINDOW(win);
6273
6274 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkwin->notebook), pos);
6275 } 5370 }
6276 } 5371 }
6277 5372
6278 static void 5373 static void
6279 show_formatting_toolbar_pref_cb(const char *name, GaimPrefType type, 5374 show_formatting_toolbar_pref_cb(const char *name, GaimPrefType type,
6280 gpointer value, gpointer data) 5375 gpointer value, gpointer data)
6281 { 5376 {
6282 GList *l; 5377 GList *l;
6283 GaimConversation *conv; 5378 GaimConversation *conv;
6284 GaimGtkConversation *gtkconv; 5379 GaimGtkConversation *gtkconv;
6285 GaimConvWindow *win; 5380 GaimGtkWindow *win;
6286 GaimGtkWindow *gtkwin;
6287 5381
6288 for (l = gaim_get_conversations(); l != NULL; l = l->next) 5382 for (l = gaim_get_conversations(); l != NULL; l = l->next)
6289 { 5383 {
6290 conv = (GaimConversation *)l->data; 5384 conv = (GaimConversation *)l->data;
6291 5385
6292 if (!GAIM_IS_GTK_CONVERSATION(conv)) 5386 if (!GAIM_IS_GTK_CONVERSATION(conv))
6293 continue; 5387 continue;
6294 5388
6295 gtkconv = GAIM_GTK_CONVERSATION(conv); 5389 gtkconv = GAIM_GTK_CONVERSATION(conv);
6296 win = gaim_conversation_get_window(conv); 5390 win = gtkconv->win;
6297 gtkwin = GAIM_GTK_WINDOW(win);
6298 5391
6299 gtk_check_menu_item_set_active( 5392 gtk_check_menu_item_set_active(
6300 GTK_CHECK_MENU_ITEM(gtkwin->menu.show_formatting_toolbar), 5393 GTK_CHECK_MENU_ITEM(win->menu.show_formatting_toolbar),
6301 (gboolean)GPOINTER_TO_INT(value)); 5394 (gboolean)GPOINTER_TO_INT(value));
6302 5395
6303 if ((gboolean)GPOINTER_TO_INT(value)) 5396 if ((gboolean)GPOINTER_TO_INT(value))
6304 gtk_widget_show(gtkconv->toolbar); 5397 gtk_widget_show(gtkconv->toolbar);
6305 else 5398 else
6306 gtk_widget_hide(gtkconv->toolbar); 5399 gtk_widget_hide(gtkconv->toolbar);
6312 gpointer value, gpointer data) 5405 gpointer value, gpointer data)
6313 { 5406 {
6314 GList *l; 5407 GList *l;
6315 GaimConversation *conv; 5408 GaimConversation *conv;
6316 GaimGtkConversation *gtkconv; 5409 GaimGtkConversation *gtkconv;
6317 GaimConvWindow *win; 5410 GaimGtkWindow *win;
6318 5411
6319 if (!gaim_prefs_get_bool("/gaim/gtk/conversations/im/show_buddy_icons")) 5412 if (!gaim_prefs_get_bool("/gaim/gtk/conversations/im/show_buddy_icons"))
6320 return; 5413 return;
6321 5414
6322 /* Set the "animate" flag for each icon based on the new preference */ 5415 /* Set the "animate" flag for each icon based on the new preference */
6325 gtkconv = GAIM_GTK_CONVERSATION(conv); 5418 gtkconv = GAIM_GTK_CONVERSATION(conv);
6326 gtkconv->u.im->animate = GPOINTER_TO_INT(value); 5419 gtkconv->u.im->animate = GPOINTER_TO_INT(value);
6327 } 5420 }
6328 5421
6329 /* Now either stop or start animation for the active conversation in each window */ 5422 /* Now either stop or start animation for the active conversation in each window */
6330 for (l = gaim_get_windows(); l != NULL; l = l->next) { 5423 for (l = gaim_gtk_conv_windows_get_list(); l != NULL; l = l->next) {
6331 win = (GaimConvWindow *)l->data; 5424 win = l->data;
6332 conv = gaim_conv_window_get_active_conversation(win); 5425 conv = gaim_gtk_conv_window_get_active_conversation(win);
6333 gaim_gtkconv_update_buddy_icon(conv); 5426 gaim_gtkconv_update_buddy_icon(conv);
6334 } 5427 }
6335 } 5428 }
6336 5429
6337 static void 5430 static void
6355 GaimConvPlacementFunc func; 5448 GaimConvPlacementFunc func;
6356 5449
6357 if (strcmp(name, "/gaim/gtk/conversations/placement")) 5450 if (strcmp(name, "/gaim/gtk/conversations/placement"))
6358 return; 5451 return;
6359 5452
6360 func = gaim_conv_placement_get_fnc(value); 5453 func = gaim_gtkconv_placement_get_fnc(value);
6361 5454
6362 if (func == NULL) 5455 if (func == NULL)
6363 return; 5456 return;
6364 5457
6365 gaim_conv_placement_set_current_func(func); 5458 gaim_gtkconv_placement_set_current_func(func);
6366 } 5459 }
6367 5460
6368 void * 5461 void *
6369 gaim_gtk_conversations_get_handle(void) 5462 gaim_gtk_conversations_get_handle(void)
6370 { 5463 {
6463 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL, 5556 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM, NULL,
6464 clear_command_cb, _("clear: Clears the conversation scrollback."), NULL); 5557 clear_command_cb, _("clear: Clears the conversation scrollback."), NULL);
6465 gaim_cmd_register("help", "w", GAIM_CMD_P_DEFAULT, 5558 gaim_cmd_register("help", "w", GAIM_CMD_P_DEFAULT,
6466 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, NULL, 5559 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_ALLOW_WRONG_ARGS, NULL,
6467 help_command_cb, _("help &lt;command&gt;: Help on a specific command."), NULL); 5560 help_command_cb, _("help &lt;command&gt;: Help on a specific command."), NULL);
5561
5562 gaim_conversations_set_ui_ops(&conversation_ui_ops);
6468 } 5563 }
6469 5564
6470 void 5565 void
6471 gaim_gtk_conversations_uninit(void) 5566 gaim_gtk_conversations_uninit(void)
6472 { 5567 {
6473 gaim_prefs_disconnect_by_handle(gaim_gtk_conversations_get_handle()); 5568 gaim_prefs_disconnect_by_handle(gaim_gtk_conversations_get_handle());
6474 gaim_signals_unregister_by_instance(gaim_gtk_conversations_get_handle()); 5569 gaim_signals_unregister_by_instance(gaim_gtk_conversations_get_handle());
6475 } 5570 }
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587 /* down here is where gtkconvwin.c ought to start. except they share like every freaking function,
5588 * and touch each others' private members all day long */
5589
5590 /**
5591 * @file gtkconvwin.c GTK+ Conversation Window API
5592 * @ingroup gtkui
5593 *
5594 * gaim
5595 *
5596 * Gaim is the legal property of its developers, whose names are too numerous
5597 * to list here. Please refer to the COPYRIGHT file distributed with this
5598 * source distribution.
5599 *
5600 * This program is free software; you can redistribute it and/or modify
5601 * it under the terms of the GNU General Public License as published by
5602 * the Free Software Foundation; either version 2 of the License, or
5603 * (at your option) any later version.
5604 *
5605 * This program is distributed in the hope that it will be useful,
5606 * but WITHOUT ANY WARRANTY; without even the implied warranty of
5607 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5608 * GNU General Public License for more details.
5609 *
5610 * You should have received a copy of the GNU General Public License
5611 * along with this program; if not, write to the Free Software
5612 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
5613 *
5614 */
5615 #include "internal.h"
5616 #include "gtkgaim.h"
5617
5618
5619 #include <gdk/gdkkeysyms.h>
5620
5621 #include "account.h"
5622 #include "cmds.h"
5623 #include "debug.h"
5624 #include "imgstore.h"
5625 #include "log.h"
5626 #include "notify.h"
5627 #include "prpl.h"
5628 #include "request.h"
5629 #include "util.h"
5630
5631 #include "gtkdnd-hints.h"
5632 #include "gtkblist.h"
5633 #include "gtkconv.h"
5634 #include "gtkdialogs.h"
5635 #include "gtkmenutray.h"
5636 #include "gtkpounce.h"
5637 #include "gtkprefs.h"
5638 #include "gtkprivacy.h"
5639 #include "gtkutils.h"
5640 #include "gtkstock.h"
5641 #include "gtkimhtml.h"
5642 #include "gtkimhtmltoolbar.h"
5643
5644
5645
5646
5647
5648 static void
5649 do_close(GtkWidget *w, int resp, GaimGtkWindow *win)
5650 {
5651 gtk_widget_destroy(warn_close_dialog);
5652 warn_close_dialog = NULL;
5653
5654 if (resp == GTK_RESPONSE_OK)
5655 gaim_gtk_conv_window_destroy(win);
5656 }
5657
5658 static void
5659 build_warn_close_dialog(GaimGtkWindow *gtkwin)
5660 {
5661 GtkWidget *label;
5662 GtkWidget *vbox, *hbox;
5663 GtkWidget *img;
5664
5665 g_return_if_fail(warn_close_dialog == NULL);
5666
5667
5668 warn_close_dialog = gtk_dialog_new_with_buttons(
5669 _("Confirm close"),
5670 GTK_WINDOW(gtkwin->window), GTK_DIALOG_MODAL,
5671 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
5672 GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL);
5673
5674 gtk_dialog_set_default_response(GTK_DIALOG(warn_close_dialog),
5675 GTK_RESPONSE_OK);
5676
5677 gtk_container_set_border_width(GTK_CONTAINER(warn_close_dialog),
5678 6);
5679 gtk_window_set_resizable(GTK_WINDOW(warn_close_dialog), FALSE);
5680 gtk_dialog_set_has_separator(GTK_DIALOG(warn_close_dialog),
5681 FALSE);
5682
5683 /* Setup the outside spacing. */
5684 vbox = GTK_DIALOG(warn_close_dialog)->vbox;
5685
5686 gtk_box_set_spacing(GTK_BOX(vbox), 12);
5687 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
5688
5689 img = gtk_image_new_from_stock(GAIM_STOCK_DIALOG_WARNING,
5690 GTK_ICON_SIZE_DIALOG);
5691 /* Setup the inner hbox and put the dialog's icon in it. */
5692 hbox = gtk_hbox_new(FALSE, 12);
5693 gtk_container_add(GTK_CONTAINER(vbox), hbox);
5694 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
5695 gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
5696
5697 /* Setup the right vbox. */
5698 vbox = gtk_vbox_new(FALSE, 12);
5699 gtk_container_add(GTK_CONTAINER(hbox), vbox);
5700
5701 label = gtk_label_new(_("You have unread messages. Are you sure you want to close the window?"));
5702 gtk_widget_set_size_request(label, 350, -1);
5703 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
5704 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
5705 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
5706
5707 /* Connect the signals. */
5708 g_signal_connect(G_OBJECT(warn_close_dialog), "response",
5709 G_CALLBACK(do_close), gtkwin);
5710
5711 }
5712
5713 /**************************************************************************
5714 * Callbacks
5715 **************************************************************************/
5716
5717 static gboolean
5718 close_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d)
5719 {
5720 GaimGtkWindow *win = d;
5721 GList *l, *j;
5722
5723 /* If there are unread messages then show a warning dialog */
5724 for (l = gaim_gtk_conv_window_get_gtkconvs(win);
5725 l != NULL; l = l->next)
5726 {
5727 GaimGtkConversation *gtkconv = l->data;
5728
5729 for (j = gtkconv->convs; j != NULL; j = j->next) {
5730 GaimConversation *conv = j->data;
5731 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM &&
5732 gaim_conversation_get_unseen(conv) == GAIM_UNSEEN_TEXT)
5733 {
5734 build_warn_close_dialog(win);
5735 gtk_widget_show_all(warn_close_dialog);
5736
5737 return TRUE;
5738 }
5739 }
5740 }
5741
5742 gaim_gtk_conv_window_destroy(win);
5743
5744 return TRUE;
5745 }
5746
5747 /*
5748 * When a conversation window is focused, we know the user
5749 * has looked at it so we know there are no longer unseen
5750 * messages.
5751 */
5752 static gint
5753 focus_win_cb(GtkWidget *w, GdkEventFocus *e, gpointer d)
5754 {
5755 GaimGtkWindow *win = d;
5756 GaimConversation *conv = gaim_gtk_conv_window_get_active_conversation(win);
5757
5758 gaim_conversation_set_unseen(conv, GAIM_UNSEEN_NONE);
5759
5760 return FALSE;
5761 }
5762
5763 /* Courtesy of Galeon! */
5764 static void
5765 tab_close_button_state_changed_cb(GtkWidget *widget, GtkStateType prev_state)
5766 {
5767 if (GTK_WIDGET_STATE(widget) == GTK_STATE_ACTIVE)
5768 gtk_widget_set_state(widget, GTK_STATE_NORMAL);
5769 }
5770
5771
5772
5773
5774 static void
5775 notebook_init_grab(GaimGtkWindow *gtkwin, GtkWidget *widget)
5776 {
5777 static GdkCursor *cursor = NULL;
5778
5779 gtkwin->in_drag = TRUE;
5780
5781 if (gtkwin->drag_leave_signal) {
5782 g_signal_handler_disconnect(G_OBJECT(widget),
5783 gtkwin->drag_leave_signal);
5784 gtkwin->drag_leave_signal = 0;
5785 }
5786
5787 if (cursor == NULL)
5788 cursor = gdk_cursor_new(GDK_FLEUR);
5789
5790 /* Grab the pointer */
5791 gtk_grab_add(gtkwin->notebook);
5792 #ifndef _WIN32
5793 /* Currently for win32 GTK+ (as of 2.2.1), gdk_pointer_is_grabbed will
5794 always be true after a button press. */
5795 if (!gdk_pointer_is_grabbed())
5796 #endif
5797 gdk_pointer_grab(gtkwin->notebook->window, FALSE,
5798 GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
5799 NULL, cursor, GDK_CURRENT_TIME);
5800 }
5801
5802 static gboolean
5803 notebook_motion_cb(GtkWidget *widget, GdkEventButton *e, GaimGtkWindow *win)
5804 {
5805
5806 /*
5807 * Make sure the user moved the mouse far enough for the
5808 * drag to be initiated.
5809 */
5810 if (win->in_predrag) {
5811 if (e->x_root < win->drag_min_x ||
5812 e->x_root >= win->drag_max_x ||
5813 e->y_root < win->drag_min_y ||
5814 e->y_root >= win->drag_max_y) {
5815
5816 win->in_predrag = FALSE;
5817 notebook_init_grab(win, widget);
5818 }
5819 }
5820 else { /* Otherwise, draw the arrows. */
5821 GaimGtkWindow *dest_win;
5822 GtkNotebook *dest_notebook;
5823 GtkWidget *tab;
5824 gint nb_x, nb_y, page_num;
5825 gint arrow1_x, arrow1_y, arrow2_x, arrow2_y;
5826 gboolean horiz_tabs = FALSE;
5827
5828 /* Get the window that the cursor is over. */
5829 dest_win = gaim_gtk_conv_window_get_at_xy(e->x_root, e->y_root);
5830
5831 if (dest_win == NULL) {
5832 dnd_hints_hide_all();
5833
5834 return TRUE;
5835 }
5836
5837
5838 dest_notebook = GTK_NOTEBOOK(dest_win->notebook);
5839
5840 gdk_window_get_origin(GTK_WIDGET(dest_notebook)->window, &nb_x, &nb_y);
5841
5842 arrow1_x = arrow2_x = nb_x;
5843 arrow1_y = arrow2_y = nb_y;
5844
5845 page_num = gaim_gtkconv_get_tab_at_xy(dest_win,
5846 e->x_root, e->y_root);
5847
5848 if (gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_TOP ||
5849 gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_BOTTOM) {
5850
5851 horiz_tabs = TRUE;
5852 }
5853
5854 tab = gaim_gtk_conv_window_get_gtkconv_at_index(dest_win, page_num)->tabby;
5855
5856 if (horiz_tabs) {
5857 arrow1_x = arrow2_x = nb_x + tab->allocation.x;
5858
5859 if ((gpointer)win == (gpointer)dest_win && win->drag_tab < page_num) {
5860 arrow1_x += tab->allocation.width;
5861 arrow2_x += tab->allocation.width;
5862 }
5863
5864 arrow1_y = nb_y + tab->allocation.y;
5865 arrow2_y = nb_y + tab->allocation.y +
5866 tab->allocation.height;
5867 } else {
5868 arrow1_x = nb_x + tab->allocation.x;
5869 arrow2_x = nb_x + tab->allocation.x +
5870 tab->allocation.width;
5871 arrow1_y = arrow2_y = nb_y + tab->allocation.y + tab->allocation.height/2;
5872
5873 if ((gpointer)win == (gpointer)dest_win && win->drag_tab < page_num) {
5874 arrow1_y += tab->allocation.height;
5875 arrow2_y += tab->allocation.height;
5876 }
5877 }
5878
5879 if (horiz_tabs) {
5880 dnd_hints_show(HINT_ARROW_DOWN, arrow1_x, arrow1_y);
5881 dnd_hints_show(HINT_ARROW_UP, arrow2_x, arrow2_y);
5882 } else {
5883 dnd_hints_show(HINT_ARROW_RIGHT, arrow1_x, arrow1_y);
5884 dnd_hints_show(HINT_ARROW_LEFT, arrow2_x, arrow2_y);
5885 }
5886 }
5887
5888 return TRUE;
5889 }
5890
5891 static gboolean
5892 notebook_leave_cb(GtkWidget *widget, GdkEventCrossing *e, GaimGtkWindow *win)
5893 {
5894 if (win->in_drag)
5895 return FALSE;
5896
5897 if (e->x_root < win->drag_min_x ||
5898 e->x_root >= win->drag_max_x ||
5899 e->y_root < win->drag_min_y ||
5900 e->y_root >= win->drag_max_y) {
5901
5902 win->in_predrag = FALSE;
5903 notebook_init_grab(win, widget);
5904 }
5905
5906 return TRUE;
5907 }
5908
5909 /*
5910 * THANK YOU GALEON!
5911 */
5912 static gboolean
5913 notebook_press_cb(GtkWidget *widget, GdkEventButton *e, GaimGtkWindow *win)
5914 {
5915 gint nb_x, nb_y, x_rel, y_rel;
5916 int tab_clicked;
5917 GtkWidget *page;
5918 GtkWidget *tab;
5919
5920 if (e->button != 1 || e->type != GDK_BUTTON_PRESS)
5921 return FALSE;
5922
5923
5924 if (win->in_drag) {
5925 gaim_debug(GAIM_DEBUG_WARNING, "gtkconv",
5926 "Already in the middle of a window drag at tab_press_cb\n");
5927 return TRUE;
5928 }
5929
5930 /*
5931 * Make sure a tab was actually clicked. The arrow buttons
5932 * mess things up.
5933 */
5934 tab_clicked = gaim_gtkconv_get_tab_at_xy(win, e->x_root, e->y_root);
5935
5936 if (tab_clicked == -1)
5937 return FALSE;
5938
5939 /*
5940 * Get the relative position of the press event, with regards to
5941 * the position of the notebook.
5942 */
5943 gdk_window_get_origin(win->notebook->window, &nb_x, &nb_y);
5944
5945 x_rel = e->x_root - nb_x;
5946 y_rel = e->y_root - nb_y;
5947
5948 /* Reset the min/max x/y */
5949 win->drag_min_x = 0;
5950 win->drag_min_y = 0;
5951 win->drag_max_x = 0;
5952 win->drag_max_y = 0;
5953
5954 /* Find out which tab was dragged. */
5955 page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), tab_clicked);
5956 tab = gtk_notebook_get_tab_label(GTK_NOTEBOOK(win->notebook), page);
5957
5958 win->drag_min_x = tab->allocation.x + nb_x;
5959 win->drag_min_y = tab->allocation.y + nb_y;
5960 win->drag_max_x = tab->allocation.width + win->drag_min_x;
5961 win->drag_max_y = tab->allocation.height + win->drag_min_y;
5962
5963 /* Make sure the click occurred in the tab. */
5964 if (e->x_root < win->drag_min_x ||
5965 e->x_root >= win->drag_max_x ||
5966 e->y_root < win->drag_min_y ||
5967 e->y_root >= win->drag_max_y) {
5968
5969 return FALSE;
5970 }
5971
5972 win->in_predrag = TRUE;
5973 win->drag_tab = tab_clicked;
5974
5975 /* Connect the new motion signals. */
5976 win->drag_motion_signal =
5977 g_signal_connect(G_OBJECT(widget), "motion_notify_event",
5978 G_CALLBACK(notebook_motion_cb), win);
5979
5980 win->drag_leave_signal =
5981 g_signal_connect(G_OBJECT(widget), "leave_notify_event",
5982 G_CALLBACK(notebook_leave_cb), win);
5983
5984 return FALSE;
5985 }
5986
5987 static gboolean
5988 notebook_release_cb(GtkWidget *widget, GdkEventButton *e, GaimGtkWindow *win)
5989 {
5990 GaimGtkWindow *dest_win;
5991 GaimConversation *conv;
5992 GaimGtkConversation *gtkconv;
5993 gint dest_page_num = 0;
5994 gboolean new_window = FALSE;
5995
5996 /*
5997 * Don't check to make sure that the event's window matches the
5998 * widget's, because we may be getting an event passed on from the
5999 * close button.
6000 */
6001 if (e->button != 1 && e->type != GDK_BUTTON_RELEASE)
6002 return FALSE;
6003
6004 if (gdk_pointer_is_grabbed()) {
6005 gdk_pointer_ungrab(GDK_CURRENT_TIME);
6006 gtk_grab_remove(widget);
6007 }
6008
6009 if (!win->in_predrag && !win->in_drag)
6010 return FALSE;
6011
6012 /* Disconnect the motion signal. */
6013 if (win->drag_motion_signal) {
6014 g_signal_handler_disconnect(G_OBJECT(widget),
6015 win->drag_motion_signal);
6016
6017 win->drag_motion_signal = 0;
6018 }
6019
6020 /*
6021 * If we're in a pre-drag, we'll also need to disconnect the leave
6022 * signal.
6023 */
6024 if (win->in_predrag) {
6025 win->in_predrag = FALSE;
6026
6027 if (win->drag_leave_signal) {
6028 g_signal_handler_disconnect(G_OBJECT(widget),
6029 win->drag_leave_signal);
6030
6031 win->drag_leave_signal = 0;
6032 }
6033 }
6034
6035 /* If we're not in drag... */
6036 /* We're perfectly normal people! */
6037 if (!win->in_drag)
6038 return FALSE;
6039
6040 win->in_drag = FALSE;
6041
6042 dnd_hints_hide_all();
6043
6044 dest_win = gaim_gtk_conv_window_get_at_xy(e->x_root, e->y_root);
6045
6046 conv = gaim_gtk_conv_window_get_active_conversation(win);
6047
6048 if (dest_win == NULL) {
6049 /* If the current window doesn't have any other conversations,
6050 * there isn't much point transferring the conv to a new window. */
6051 if (gaim_gtk_conv_window_get_gtkconv_count(win) > 1) {
6052 /* Make a new window to stick this to. */
6053 dest_win = gaim_gtk_conv_window_new();
6054 new_window = TRUE;
6055 }
6056 }
6057
6058 if (dest_win == NULL)
6059 return FALSE;
6060
6061 gaim_signal_emit(gaim_gtk_conversations_get_handle(),
6062 "conversation-dragging", win, dest_win);
6063
6064 /* Get the destination page number. */
6065 if (!new_window)
6066 dest_page_num = gaim_gtkconv_get_tab_at_xy(dest_win,
6067 e->x_root, e->y_root);
6068
6069 gtkconv = GAIM_GTK_CONVERSATION(conv);
6070
6071 if (win == dest_win) {
6072 gtk_notebook_reorder_child(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont, dest_page_num);
6073 } else {
6074 gaim_gtk_conv_window_remove_gtkconv(win, gtkconv);
6075 gaim_gtk_conv_window_add_gtkconv(dest_win, gtkconv);
6076 gtk_notebook_reorder_child(GTK_NOTEBOOK(dest_win->notebook), gtkconv->tab_cont, dest_page_num);
6077 gaim_gtk_conv_window_switch_gtkconv(dest_win, gtkconv);
6078 if (new_window) {
6079 gint win_width, win_height;
6080
6081 gtk_window_get_size(GTK_WINDOW(dest_win->window),
6082 &win_width, &win_height);
6083
6084 gtk_window_move(GTK_WINDOW(dest_win->window),
6085 e->x_root - (win_width / 2),
6086 e->y_root - (win_height / 2));
6087
6088 gaim_gtk_conv_window_show(dest_win);
6089 }
6090 }
6091
6092 gtk_widget_grab_focus(GAIM_GTK_CONVERSATION(conv)->entry);
6093
6094 return TRUE;
6095 }
6096
6097
6098 static void
6099 before_switch_conv_cb(GtkNotebook *notebook, GtkWidget *page, gint page_num,
6100 gpointer user_data)
6101 {
6102 GaimGtkWindow *win;
6103 GaimConversation *conv;
6104 GaimGtkConversation *gtkconv;
6105
6106 win = user_data;
6107 conv = gaim_gtk_conv_window_get_active_conversation(win);
6108
6109 g_return_if_fail(conv != NULL);
6110
6111 if (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_IM)
6112 return;
6113
6114 gtkconv = GAIM_GTK_CONVERSATION(conv);
6115
6116 stop_anim(NULL, gtkconv);
6117 }
6118
6119 static void
6120 switch_conv_cb(GtkNotebook *notebook, GtkWidget *page, gint page_num,
6121 gpointer user_data)
6122 {
6123 GaimGtkWindow *win;
6124 GaimConversation *conv;
6125 GaimGtkConversation *gtkconv;
6126
6127 win = user_data;
6128 gtkconv = gaim_gtk_conv_window_get_gtkconv_at_index(win, page_num);
6129 conv = gtkconv->active_conv;
6130
6131 g_return_if_fail(conv != NULL);
6132
6133 /*
6134 * Only set "unseen" to "none" if the window has focus
6135 */
6136 if (gaim_gtk_conv_window_has_focus(win))
6137 gaim_conversation_set_unseen(conv, GAIM_UNSEEN_NONE);
6138
6139 /* Update the menubar */
6140 gray_stuff_out(gtkconv);
6141
6142 update_typing_icon(gtkconv);
6143
6144 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.logging),
6145 gaim_conversation_is_logging(conv));
6146
6147 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.sounds),
6148 gtkconv->make_sound);
6149
6150 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.show_formatting_toolbar),
6151 gaim_prefs_get_bool("/gaim/gtk/conversations/show_formatting_toolbar"));
6152
6153 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.show_timestamps),
6154 gtkconv->show_timestamps);
6155
6156 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
6157 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(win->menu.show_icon),
6158 gtkconv->u.im->show_icon);
6159 /*
6160 * We pause icons when they are not visible. If this icon should
6161 * be animated then start it back up again.
6162 */
6163 if ((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) &&
6164 (gtkconv->u.im->animate))
6165 start_anim(NULL, gtkconv);
6166
6167 gtk_window_set_title(GTK_WINDOW(win->window),
6168 gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
6169 }
6170
6171 /**************************************************************************
6172 * GTK+ window ops
6173 **************************************************************************/
6174
6175 static GList *window_list = NULL;
6176
6177 GList *
6178 gaim_gtk_conv_windows_get_list()
6179 {
6180 return window_list;
6181 }
6182
6183 GaimGtkWindow *
6184 gaim_gtk_conv_window_new()
6185 {
6186 GaimGtkWindow *win;
6187 GtkPositionType pos;
6188 GtkWidget *testidea;
6189 GtkWidget *menubar;
6190
6191 win = g_malloc0(sizeof(GaimGtkWindow));
6192
6193 window_list = g_list_append(window_list, win);
6194
6195 /* Create the window. */
6196 win->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
6197 gtk_window_set_role(GTK_WINDOW(win->window), "conversation");
6198 gtk_window_set_resizable(GTK_WINDOW(win->window), TRUE);
6199 gtk_container_set_border_width(GTK_CONTAINER(win->window), 0);
6200 GTK_WINDOW(win->window)->allow_shrink = TRUE;
6201
6202 g_signal_connect(G_OBJECT(win->window), "delete_event",
6203 G_CALLBACK(close_win_cb), win);
6204
6205 g_signal_connect(G_OBJECT(win->window), "focus_in_event",
6206 G_CALLBACK(focus_win_cb), win);
6207
6208 /* Create the notebook. */
6209 win->notebook = gtk_notebook_new();
6210
6211 pos = gaim_prefs_get_int("/gaim/gtk/conversations/tab_side");
6212
6213 #if 0
6214 gtk_notebook_set_tab_hborder(GTK_NOTEBOOK(win->notebook), 0);
6215 gtk_notebook_set_tab_vborder(GTK_NOTEBOOK(win->notebook), 0);
6216 #endif
6217 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(win->notebook), pos);
6218 gtk_notebook_set_scrollable(GTK_NOTEBOOK(win->notebook), TRUE);
6219 gtk_notebook_popup_enable(GTK_NOTEBOOK(win->notebook));
6220 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook), FALSE);
6221 gtk_notebook_set_show_border(GTK_NOTEBOOK(win->notebook), FALSE);
6222
6223 gtk_widget_show(win->notebook);
6224
6225 g_signal_connect(G_OBJECT(win->notebook), "switch_page",
6226 G_CALLBACK(before_switch_conv_cb), win);
6227 g_signal_connect_after(G_OBJECT(win->notebook), "switch_page",
6228 G_CALLBACK(switch_conv_cb), win);
6229
6230 /* Setup the tab drag and drop signals. */
6231 gtk_widget_add_events(win->notebook,
6232 GDK_BUTTON1_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
6233 g_signal_connect(G_OBJECT(win->notebook), "button_press_event",
6234 G_CALLBACK(notebook_press_cb), win);
6235 g_signal_connect(G_OBJECT(win->notebook), "button_release_event",
6236 G_CALLBACK(notebook_release_cb), win);
6237
6238 testidea = gtk_vbox_new(FALSE, 0);
6239
6240 /* Setup the menubar. */
6241 menubar = setup_menubar(win);
6242 gtk_box_pack_start(GTK_BOX(testidea), menubar, FALSE, TRUE, 0);
6243
6244 gtk_box_pack_start(GTK_BOX(testidea), win->notebook, TRUE, TRUE, 0);
6245
6246 gtk_container_add(GTK_CONTAINER(win->window), testidea);
6247
6248 gtk_widget_show(testidea);
6249
6250 return win;
6251 }
6252
6253 void
6254 gaim_gtk_conv_window_destroy(GaimGtkWindow *win)
6255 {
6256 window_list = g_list_remove(window_list, win);
6257
6258 gtk_widget_destroy(win->window);
6259
6260 g_object_unref(G_OBJECT(win->menu.item_factory));
6261
6262 g_free(win);
6263 }
6264
6265 void
6266 gaim_gtk_conv_window_show(GaimGtkWindow *win)
6267 {
6268 gtk_widget_show(win->window);
6269 }
6270
6271 void
6272 gaim_gtk_conv_window_hide(GaimGtkWindow *win)
6273 {
6274 gtk_widget_hide(win->window);
6275 }
6276
6277 void
6278 gaim_gtk_conv_window_raise(GaimGtkWindow *win)
6279 {
6280 gtk_widget_show(win->window);
6281 gtk_window_deiconify(GTK_WINDOW(win->window));
6282 gdk_window_raise(win->window->window);
6283 }
6284
6285 void
6286 gaim_gtk_conv_window_switch_gtkconv(GaimGtkWindow *win, GaimGtkConversation *gtkconv)
6287 {
6288 gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook),
6289 gtk_notebook_page_num(GTK_NOTEBOOK(win->notebook),
6290 gtkconv->tab_cont));
6291 }
6292
6293 void
6294 gaim_gtk_conv_window_add_gtkconv(GaimGtkWindow *win, GaimGtkConversation *gtkconv)
6295 {
6296 GaimConversation *conv = gtkconv->active_conv;
6297 GaimGtkConversation *focus_gtkconv;
6298 GtkWidget *tabby, *menu_tabby;
6299 GtkWidget *tab_cont = gtkconv->tab_cont;
6300 GtkWidget *close_image;
6301 GaimConversationType conv_type;
6302 const char *name;
6303 const gchar *tmp_lab;
6304 gint close_button_width, close_button_height, focus_width, focus_pad;
6305
6306 name = gaim_conversation_get_name(conv);
6307 conv_type = gaim_conversation_get_type(conv);
6308
6309
6310 win->gtkconvs = g_list_append(win->gtkconvs, gtkconv);
6311 gtkconv->win = win;
6312
6313 gtkconv->tabby = tabby = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
6314 gtkconv->menu_tabby = menu_tabby = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
6315
6316 /* Close button. */
6317 gtkconv->close = gtk_button_new();
6318 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &close_button_width, &close_button_height);
6319 if (gtk_check_version(2, 4, 2) == NULL) {
6320 /* Need to account for extra padding around the gtkbutton */
6321 gtk_widget_style_get(GTK_WIDGET(gtkconv->close),
6322 "focus-line-width", &focus_width,
6323 "focus-padding", &focus_pad,
6324 NULL);
6325 close_button_width += (focus_width + focus_pad) * 2;
6326 close_button_height += (focus_width + focus_pad) * 2;
6327 }
6328 gtk_widget_set_size_request(GTK_WIDGET(gtkconv->close),
6329 close_button_width, close_button_height);
6330
6331 gtk_button_set_relief(GTK_BUTTON(gtkconv->close), GTK_RELIEF_NONE);
6332 close_image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
6333 gtk_widget_show(close_image);
6334 gtk_container_add(GTK_CONTAINER(gtkconv->close), close_image);
6335 gtk_tooltips_set_tip(gtkconv->tooltips, gtkconv->close,
6336 _("Close conversation"), NULL);
6337
6338 g_signal_connect(G_OBJECT(gtkconv->close), "clicked",
6339 G_CALLBACK(close_conv_cb), gtkconv);
6340
6341 /*
6342 * I love Galeon. They have a fix for that stupid annoying visible
6343 * border bug. I love you guys! -- ChipX86
6344 */
6345 g_signal_connect(G_OBJECT(gtkconv->close), "state_changed",
6346 G_CALLBACK(tab_close_button_state_changed_cb), NULL);
6347
6348 /* Status icon. */
6349 gtkconv->icon = gtk_image_new();
6350 gtkconv->menu_icon = gtk_image_new();
6351 update_tab_icon(conv);
6352
6353 /* Tab label. */
6354 gtkconv->tab_label = gtk_label_new(tmp_lab = gaim_conversation_get_title(conv));
6355 #if GTK_CHECK_VERSION(2,6,0)
6356 g_object_set(G_OBJECT(gtkconv->tab_label), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
6357 gtk_label_set_width_chars(GTK_LABEL(gtkconv->tab_label), 6);
6358 #endif
6359 gtkconv->menu_label = gtk_label_new(gaim_conversation_get_title(conv));
6360 #if 0
6361 gtk_misc_set_alignment(GTK_MISC(gtkconv->tab_label), 0.00, 0.5);
6362 gtk_misc_set_padding(GTK_MISC(gtkconv->tab_label), 4, 0);
6363 #endif
6364
6365 /* Pack it all together. */
6366 gtk_box_pack_start(GTK_BOX(tabby), gtkconv->icon, FALSE, FALSE, 0);
6367 gtk_box_pack_start(GTK_BOX(menu_tabby), gtkconv->menu_icon,
6368 FALSE, FALSE, 0);
6369
6370 gtk_widget_show_all(gtkconv->icon);
6371 gtk_widget_show_all(gtkconv->menu_icon);
6372
6373 gtk_box_pack_start(GTK_BOX(tabby), gtkconv->tab_label, TRUE, TRUE, 0);
6374 gtk_box_pack_start(GTK_BOX(menu_tabby), gtkconv->menu_label, TRUE, TRUE, 0);
6375 gtk_widget_show(gtkconv->tab_label);
6376 gtk_widget_show(gtkconv->menu_label);
6377 gtk_misc_set_alignment(GTK_MISC(gtkconv->menu_label), 0, 0);
6378
6379 gtk_box_pack_start(GTK_BOX(tabby), gtkconv->close, FALSE, FALSE, 0);
6380 if (gaim_prefs_get_bool("/gaim/gtk/conversations/close_on_tabs"))
6381 gtk_widget_show(gtkconv->close);
6382
6383 gtk_widget_show(tabby);
6384 gtk_widget_show(menu_tabby);
6385
6386 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
6387 gaim_gtkconv_update_buddy_icon(conv);
6388
6389 /* Add this pane to the conversation's notebook. */
6390 gtk_notebook_append_page_menu(GTK_NOTEBOOK(win->notebook), tab_cont, tabby, menu_tabby);
6391 gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(win->notebook), tab_cont, TRUE, TRUE, GTK_PACK_START);
6392
6393
6394 gtk_widget_show(tab_cont);
6395
6396 if (gaim_gtk_conv_window_get_gtkconv_count(win) == 1) {
6397 /* Er, bug in notebooks? Switch to the page manually. */
6398 gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), 0);
6399
6400 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook),
6401 gaim_prefs_get_bool("/gaim/gtk/conversations/tabs"));
6402 } else
6403 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook), TRUE);
6404
6405 focus_gtkconv = g_list_nth_data(gaim_gtk_conv_window_get_gtkconvs(win),
6406 gtk_notebook_get_current_page(GTK_NOTEBOOK(win->notebook)));
6407 gtk_widget_grab_focus(focus_gtkconv->entry);
6408
6409 if (gaim_gtk_conv_window_get_gtkconv_count(win) == 1)
6410 g_timeout_add(0, (GSourceFunc)update_send_as_selection, win);
6411 }
6412
6413 void
6414 gaim_gtk_conv_window_remove_gtkconv(GaimGtkWindow *win, GaimGtkConversation *gtkconv)
6415 {
6416 unsigned int index;
6417 GaimConversationType conv_type;
6418
6419 conv_type = gaim_conversation_get_type(gtkconv->active_conv);
6420 index = gtk_notebook_page_num(GTK_NOTEBOOK(win->notebook), gtkconv->tab_cont);
6421
6422 g_object_ref(gtkconv->tab_cont);
6423 gtk_object_sink(GTK_OBJECT(gtkconv->tab_cont));
6424
6425 gtk_notebook_remove_page(GTK_NOTEBOOK(win->notebook), index);
6426
6427 /* go back to tabless if need be */
6428 if (gaim_gtk_conv_window_get_gtkconv_count(win) <= 2) {
6429 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(win->notebook),
6430 gaim_prefs_get_bool("/gaim/gtk/conversations/tabs"));
6431 }
6432
6433
6434 /* If this window is setup with an inactive gc, regenerate the menu. */
6435
6436 if (conv_type == GAIM_CONV_TYPE_IM &&
6437 gaim_conversation_get_gc(gtkconv->active_conv) == NULL) {
6438 generate_send_as_items(win, gtkconv->active_conv);
6439 }
6440
6441 win->gtkconvs = g_list_remove(win->gtkconvs, gtkconv);
6442 }
6443
6444 GaimGtkConversation *
6445 gaim_gtk_conv_window_get_gtkconv_at_index(const GaimGtkWindow *win, int index)
6446 {
6447 GtkWidget *tab_cont;
6448
6449 if (index == -1)
6450 index = 0;
6451 tab_cont = gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), index);
6452 return g_object_get_data(G_OBJECT(tab_cont), "GaimGtkConversation");
6453 }
6454
6455 GaimGtkConversation *
6456 gaim_gtk_conv_window_get_active_gtkconv(const GaimGtkWindow *win)
6457 {
6458 int index;
6459 GtkWidget *tab_cont;
6460
6461 index = gtk_notebook_get_current_page(GTK_NOTEBOOK(win->notebook));
6462 if (index == -1)
6463 index = 0;
6464 tab_cont = gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->notebook), index);
6465 if (!tab_cont)
6466 return NULL;
6467 return g_object_get_data(G_OBJECT(tab_cont), "GaimGtkConversation");
6468 }
6469
6470
6471 GaimConversation *
6472 gaim_gtk_conv_window_get_active_conversation(const GaimGtkWindow *win)
6473 {
6474 GaimGtkConversation *gtkconv;
6475
6476 gtkconv = gaim_gtk_conv_window_get_active_gtkconv(win);
6477 return gtkconv ? gtkconv->active_conv : NULL;
6478 }
6479
6480 gboolean
6481 gaim_gtk_conv_window_is_active_conversation(const GaimConversation *conv)
6482 {
6483 return conv == gaim_gtk_conv_window_get_active_conversation(GAIM_GTK_CONVERSATION(conv)->win);
6484 }
6485
6486 gboolean
6487 gaim_gtk_conv_window_has_focus(GaimGtkWindow *win)
6488 {
6489 gboolean has_focus = FALSE;
6490
6491 g_object_get(G_OBJECT(win->window), "has-toplevel-focus", &has_focus, NULL);
6492
6493 return has_focus;
6494 }
6495
6496 GaimGtkWindow *
6497 gaim_gtk_conv_window_get_at_xy(int x, int y)
6498 {
6499 GaimGtkWindow *win;
6500 GdkWindow *gdkwin;
6501 GList *l;
6502
6503 gdkwin = gdk_window_at_pointer(&x, &y);
6504
6505 if (gdkwin)
6506 gdkwin = gdk_window_get_toplevel(gdkwin);
6507
6508 for (l = gaim_gtk_conv_windows_get_list(); l != NULL; l = l->next) {
6509 win = l->data;
6510
6511 if (gdkwin == win->window->window)
6512 return win;
6513 }
6514
6515 return NULL;
6516 }
6517
6518 GList *
6519 gaim_gtk_conv_window_get_gtkconvs(GaimGtkWindow *win)
6520 {
6521 return win->gtkconvs;
6522 }
6523
6524 guint
6525 gaim_gtk_conv_window_get_gtkconv_count(GaimGtkWindow *win)
6526 {
6527 return g_list_length(win->gtkconvs);
6528 }
6529
6530 GaimGtkWindow *
6531 gaim_gtk_conv_window_first_with_type(GaimConversationType type)
6532 {
6533 GList *wins, *convs;
6534 GaimGtkWindow *win;
6535 GaimGtkConversation *conv;
6536
6537 if (type == GAIM_CONV_TYPE_UNKNOWN)
6538 return NULL;
6539
6540 for (wins = gaim_gtk_conv_windows_get_list(); wins != NULL; wins = wins->next) {
6541 win = wins->data;
6542
6543 for (convs = win->gtkconvs;
6544 convs != NULL;
6545 convs = convs->next) {
6546
6547 conv = convs->data;
6548
6549 if (gaim_conversation_get_type(conv->active_conv) == type)
6550 return win;
6551 }
6552 }
6553
6554 return NULL;
6555 }
6556
6557 GaimGtkWindow *
6558 gaim_gtk_conv_window_last_with_type(GaimConversationType type)
6559 {
6560 GList *wins, *convs;
6561 GaimGtkWindow *win;
6562 GaimGtkConversation *conv;
6563
6564 if (type == GAIM_CONV_TYPE_UNKNOWN)
6565 return NULL;
6566
6567 for (wins = g_list_last(gaim_gtk_conv_windows_get_list());
6568 wins != NULL;
6569 wins = wins->prev) {
6570
6571 win = wins->data;
6572
6573 for (convs = win->gtkconvs;
6574 convs != NULL;
6575 convs = convs->next) {
6576
6577 conv = convs->data;
6578
6579 if (gaim_conversation_get_type(conv->active_conv) == type)
6580 return win;
6581 }
6582 }
6583
6584 return NULL;
6585 }
6586
6587
6588 /**************************************************************************
6589 * Conversation placement functions
6590 **************************************************************************/
6591 typedef struct
6592 {
6593 char *id;
6594 char *name;
6595 GaimConvPlacementFunc fnc;
6596
6597 } ConvPlacementData;
6598
6599 static GList *conv_placement_fncs = NULL;
6600 static GaimConvPlacementFunc place_conv = NULL;
6601
6602 /* This one places conversations in the last made window. */
6603 static void
6604 conv_placement_last_created_win(GaimGtkConversation *conv)
6605 {
6606 GaimGtkWindow *win;
6607
6608 GList *l = g_list_last(gaim_gtk_conv_windows_get_list());
6609 win = l ? l->data : NULL;;
6610
6611 if (win == NULL) {
6612 win = gaim_gtk_conv_window_new();
6613
6614 gaim_gtk_conv_window_add_gtkconv(win, conv);
6615 gaim_gtk_conv_window_show(win);
6616 } else {
6617 gaim_gtk_conv_window_add_gtkconv(win, conv);
6618 }
6619 }
6620
6621 /* This one places conversations in the last made window of the same type. */
6622 static void
6623 conv_placement_last_created_win_type(GaimGtkConversation *conv)
6624 {
6625 GaimGtkWindow *win;
6626
6627 win = gaim_gtk_conv_window_last_with_type(gaim_conversation_get_type(conv->active_conv));
6628
6629 if (win == NULL) {
6630 win = gaim_gtk_conv_window_new();
6631
6632 gaim_gtk_conv_window_add_gtkconv(win, conv);
6633 gaim_gtk_conv_window_show(win);
6634 } else
6635 gaim_gtk_conv_window_add_gtkconv(win, conv);
6636 }
6637
6638 /* This one places each conversation in its own window. */
6639 static void
6640 conv_placement_new_window(GaimGtkConversation *conv)
6641 {
6642 GaimGtkWindow *win;
6643
6644 win = gaim_gtk_conv_window_new();
6645
6646 gaim_gtk_conv_window_add_gtkconv(win, conv);
6647
6648 gaim_gtk_conv_window_show(win);
6649 }
6650
6651 static GaimGroup *
6652 conv_get_group(GaimGtkConversation *conv)
6653 {
6654 GaimGroup *group = NULL;
6655
6656 if (gaim_conversation_get_type(conv->active_conv) == GAIM_CONV_TYPE_IM) {
6657 GaimBuddy *buddy;
6658
6659 buddy = gaim_find_buddy(gaim_conversation_get_account(conv->active_conv),
6660 gaim_conversation_get_name(conv->active_conv));
6661
6662 if (buddy != NULL)
6663 group = gaim_find_buddys_group(buddy);
6664
6665 } else if (gaim_conversation_get_type(conv->active_conv) == GAIM_CONV_TYPE_CHAT) {
6666 GaimChat *chat;
6667
6668 chat = gaim_blist_find_chat(gaim_conversation_get_account(conv->active_conv),
6669 gaim_conversation_get_name(conv->active_conv));
6670
6671 if (chat != NULL)
6672 group = gaim_chat_get_group(chat);
6673 }
6674
6675 return group;
6676 }
6677
6678 /*
6679 * This groups things by, well, group. Buddies from groups will always be
6680 * grouped together, and a buddy from a group not belonging to any currently
6681 * open windows will get a new window.
6682 */
6683 static void
6684 conv_placement_by_group(GaimGtkConversation *conv)
6685 {
6686 GaimConversationType type;
6687 GaimGroup *group = NULL;
6688 GList *wl, *cl;
6689
6690 type = gaim_conversation_get_type(conv->active_conv);
6691
6692 group = conv_get_group(conv);
6693
6694 /* Go through the list of IMs and find one with this group. */
6695 for (wl = gaim_gtk_conv_windows_get_list(); wl != NULL; wl = wl->next) {
6696 GaimGtkWindow *win2;
6697 GaimGtkConversation *conv2;
6698 GaimGroup *group2 = NULL;
6699
6700 win2 = wl->data;
6701
6702 for (cl = win2->gtkconvs;
6703 cl != NULL;
6704 cl = cl->next) {
6705 conv2 = cl->data;
6706
6707 group2 = conv_get_group(conv2);
6708
6709 if (group == group2) {
6710 gaim_gtk_conv_window_add_gtkconv(win2, conv);
6711
6712 return;
6713 }
6714 }
6715 }
6716
6717 /* Make a new window. */
6718 conv_placement_new_window(conv);
6719 }
6720
6721 /* This groups things by account. Otherwise, the same semantics as above */
6722 static void
6723 conv_placement_by_account(GaimGtkConversation *conv)
6724 {
6725 GaimConversationType type;
6726 GList *wins, *convs;
6727 GaimAccount *account;
6728
6729 account = gaim_conversation_get_account(conv->active_conv);
6730 type = gaim_conversation_get_type(conv->active_conv);
6731
6732 /* Go through the list of IMs and find one with this group. */
6733 for (wins = gaim_gtk_conv_windows_get_list(); wins != NULL; wins = wins->next) {
6734 GaimGtkWindow *win2;
6735 GaimGtkConversation *conv2;
6736
6737 win2 = wins->data;
6738
6739 for (convs = win2->gtkconvs;
6740 convs != NULL;
6741 convs = convs->next) {
6742 conv2 = convs->data;
6743
6744 if (account == gaim_conversation_get_account(conv2->active_conv)) {
6745 gaim_gtk_conv_window_add_gtkconv(win2, conv);
6746 return;
6747 }
6748 }
6749 }
6750
6751 /* Make a new window. */
6752 conv_placement_new_window(conv);
6753 }
6754
6755 static ConvPlacementData *
6756 get_conv_placement_data(const char *id)
6757 {
6758 ConvPlacementData *data = NULL;
6759 GList *n;
6760
6761 for (n = conv_placement_fncs; n; n = n->next) {
6762 data = n->data;
6763 if (!strcmp(data->id, id))
6764 return data;
6765 }
6766
6767 return NULL;
6768 }
6769
6770 static void
6771 add_conv_placement_fnc(const char *id, const char *name,
6772 GaimConvPlacementFunc fnc)
6773 {
6774 ConvPlacementData *data;
6775
6776 data = g_new(ConvPlacementData, 1);
6777
6778 data->id = g_strdup(id);
6779 data->name = g_strdup(name);
6780 data->fnc = fnc;
6781
6782 conv_placement_fncs = g_list_append(conv_placement_fncs, data);
6783 }
6784
6785 static void
6786 ensure_default_funcs(void)
6787 {
6788 if (conv_placement_fncs == NULL) {
6789 add_conv_placement_fnc("last", _("Last created window"),
6790 conv_placement_last_created_win);
6791 add_conv_placement_fnc("im_chat", _("Separate IM and Chat windows"),
6792 conv_placement_last_created_win_type);
6793 add_conv_placement_fnc("new", _("New window"),
6794 conv_placement_new_window);
6795 add_conv_placement_fnc("group", _("By group"),
6796 conv_placement_by_group);
6797 add_conv_placement_fnc("account", _("By account"),
6798 conv_placement_by_account);
6799 }
6800 }
6801
6802 GList *
6803 gaim_gtkconv_placement_get_options(void)
6804 {
6805 GList *n, *list = NULL;
6806 ConvPlacementData *data;
6807
6808 ensure_default_funcs();
6809
6810 for (n = conv_placement_fncs; n; n = n->next) {
6811 data = n->data;
6812 list = g_list_append(list, data->name);
6813 list = g_list_append(list, data->id);
6814 }
6815
6816 return list;
6817 }
6818
6819
6820 void
6821 gaim_gtkconv_placement_add_fnc(const char *id, const char *name,
6822 GaimConvPlacementFunc fnc)
6823 {
6824 g_return_if_fail(id != NULL);
6825 g_return_if_fail(name != NULL);
6826 g_return_if_fail(fnc != NULL);
6827
6828 ensure_default_funcs();
6829
6830 add_conv_placement_fnc(id, name, fnc);
6831 }
6832
6833 void
6834 gaim_gtkconv_placement_remove_fnc(const char *id)
6835 {
6836 ConvPlacementData *data = get_conv_placement_data(id);
6837
6838 if (data == NULL)
6839 return;
6840
6841 conv_placement_fncs = g_list_remove(conv_placement_fncs, data);
6842
6843 g_free(data->id);
6844 g_free(data->name);
6845 g_free(data);
6846 }
6847
6848 const char *
6849 gaim_gtkconv_placement_get_name(const char *id)
6850 {
6851 ConvPlacementData *data;
6852
6853 ensure_default_funcs();
6854
6855 data = get_conv_placement_data(id);
6856
6857 if (data == NULL)
6858 return NULL;
6859
6860 return data->name;
6861 }
6862
6863 GaimConvPlacementFunc
6864 gaim_gtkconv_placement_get_fnc(const char *id)
6865 {
6866 ConvPlacementData *data;
6867
6868 ensure_default_funcs();
6869
6870 data = get_conv_placement_data(id);
6871
6872 if (data == NULL)
6873 return NULL;
6874
6875 return data->fnc;
6876 }
6877
6878 void
6879 gaim_gtkconv_placement_set_current_func(GaimConvPlacementFunc func)
6880 {
6881 g_return_if_fail(func != NULL);
6882
6883 place_conv = func;
6884 }
6885
6886 GaimConvPlacementFunc
6887 gaim_gtkconv_placement_get_current_func(void)
6888 {
6889 return place_conv;
6890 }
6891
6892 void
6893 gaim_gtkconv_placement_place(GaimGtkConversation *gtkconv)
6894 {
6895 if (place_conv)
6896 place_conv(gtkconv);
6897 }