comparison console/gntblist.c @ 14935:ef80d4c30a90

[gaim-migrate @ 17707] Change the way tooltips are displayed. This fixes crashes when the tooltip for a contact grows too large. committer: Tailor Script <tailor@pidgin.im>
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Thu, 09 Nov 2006 00:20:18 +0000
parents 056c8a27668c
children e601bc7880a6
comparison
equal deleted inserted replaced
14934:4504a21b1d8f 14935:ef80d4c30a90
41 #include "gntline.h" 41 #include "gntline.h"
42 #include "gntmenu.h" 42 #include "gntmenu.h"
43 #include "gntmenuitem.h" 43 #include "gntmenuitem.h"
44 #include "gntmenuitemcheck.h" 44 #include "gntmenuitemcheck.h"
45 #include "gnttree.h" 45 #include "gnttree.h"
46 #include "gntutils.h"
46 #include "gntwindow.h" 47 #include "gntwindow.h"
47 48
48 #include "gntblist.h" 49 #include "gntblist.h"
49 #include "gntconv.h" 50 #include "gntconv.h"
50 #include "gntstatus.h" 51 #include "gntstatus.h"
161 gnt_widget_destroy(ggblist->tooltip); 162 gnt_widget_destroy(ggblist->tooltip);
162 ggblist->tooltip = NULL; 163 ggblist->tooltip = NULL;
163 ggblist->tnode = NULL; 164 ggblist->tnode = NULL;
164 } 165 }
165 166
166 static gboolean
167 _draw_tooltip(gpointer data)
168 {
169 draw_tooltip(data);
170 return FALSE;
171 }
172
173 static void 167 static void
174 node_remove(GaimBuddyList *list, GaimBlistNode *node) 168 node_remove(GaimBuddyList *list, GaimBlistNode *node)
175 { 169 {
176 GGBlist *ggblist = list->ui_data; 170 GGBlist *ggblist = list->ui_data;
177 171
191 if ((!gaim_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group)) || 185 if ((!gaim_prefs_get_bool(PREF_ROOT "/showoffline") && !is_group_online(group)) ||
192 group->currentsize < 1) 186 group->currentsize < 1)
193 node_remove(list, node->parent); 187 node_remove(list, node->parent);
194 } 188 }
195 189
196 /* When an account has signed off, it removes one buddy at a time. 190 draw_tooltip(ggblist);
197 * Drawing the tooltip after removing each buddy is expensive. On
198 * top of that, if the selected buddy belongs to the disconnected
199 * account, then retreiving the tooltip for that causes crash. So
200 * let's make sure we wait for all the buddies to be removed first.*/
201 g_timeout_add(0, _draw_tooltip, ggblist);
202 } 191 }
203 192
204 static void 193 static void
205 node_update(GaimBuddyList *list, GaimBlistNode *node) 194 node_update(GaimBuddyList *list, GaimBlistNode *node)
206 { 195 {
1147 } 1136 }
1148 } 1137 }
1149 } 1138 }
1150 } 1139 }
1151 1140
1152 static void 1141 static GString*
1153 draw_tooltip(GGBlist *ggblist) 1142 make_sure_text_fits(GString *string)
1143 {
1144 int maxw = getmaxx(stdscr) - 3;
1145 char *str = gnt_util_onscreen_fit_string(string->str, maxw);
1146 string = g_string_assign(string, str);
1147 g_free(str);
1148 return string;
1149 }
1150
1151 static gboolean
1152 draw_tooltip_real(GGBlist *ggblist)
1154 { 1153 {
1155 GaimBlistNode *node; 1154 GaimBlistNode *node;
1156 int x, y, top, width; 1155 int x, y, top, width, w, h;
1157 GString *str; 1156 GString *str;
1158 GntTree *tree; 1157 GntTree *tree;
1159 GntWidget *widget, *box; 1158 GntWidget *widget, *box, *tv;
1160 char *title = NULL; 1159 char *title = NULL;
1161 int lastseen = 0; 1160 int lastseen = 0;
1162 1161
1163 widget = ggblist->tree; 1162 widget = ggblist->tree;
1164 tree = GNT_TREE(widget); 1163 tree = GNT_TREE(widget);
1165 1164
1166 if (!gnt_widget_has_focus(ggblist->tree) || 1165 if (!gnt_widget_has_focus(ggblist->tree) ||
1167 (ggblist->context && !GNT_WIDGET_IS_FLAG_SET(ggblist->context, GNT_WIDGET_INVISIBLE))) 1166 (ggblist->context && !GNT_WIDGET_IS_FLAG_SET(ggblist->context, GNT_WIDGET_INVISIBLE)))
1168 return; 1167 return FALSE;
1169 1168
1170 if (ggblist->tooltip) 1169 if (ggblist->tooltip)
1171 { 1170 {
1172 /* XXX: Once we can properly redraw on expose events, this can be removed at the end 1171 /* XXX: Once we can properly redraw on expose events, this can be removed at the end
1173 * to avoid the blinking*/ 1172 * to avoid the blinking*/
1174 remove_tooltip(ggblist); 1173 remove_tooltip(ggblist);
1175 } 1174 }
1176 1175
1177 node = gnt_tree_get_selection_data(tree); 1176 node = gnt_tree_get_selection_data(tree);
1178 if (!node) 1177 if (!node)
1179 return; 1178 return FALSE;
1180 1179
1181 str = g_string_new(""); 1180 str = g_string_new("");
1182 1181
1183 if (GAIM_BLIST_NODE_IS_CONTACT(node)) { 1182 if (GAIM_BLIST_NODE_IS_CONTACT(node)) {
1184 GaimBuddy *pr = gaim_contact_get_priority_buddy((GaimContact*)node); 1183 GaimBuddy *pr = gaim_contact_get_priority_buddy((GaimContact*)node);
1190 title = g_strdup(alias); 1189 title = g_strdup(alias);
1191 if (g_utf8_collate(alias, name)) 1190 if (g_utf8_collate(alias, name))
1192 g_string_append_printf(str, _("Nickname: %s\n"), gaim_buddy_get_name(pr)); 1191 g_string_append_printf(str, _("Nickname: %s\n"), gaim_buddy_get_name(pr));
1193 tooltip_for_buddy(pr, str); 1192 tooltip_for_buddy(pr, str);
1194 for (node = node->child; node; node = node->next) { 1193 for (node = node->child; node; node = node->next) {
1194 GaimBuddy *buddy = (GaimBuddy*)node;
1195 if (offline) { 1195 if (offline) {
1196 int value = gaim_blist_node_get_int(node, "last_seen"); 1196 int value = gaim_blist_node_get_int(node, "last_seen");
1197 if (value > lastseen) 1197 if (value > lastseen)
1198 lastseen = value; 1198 lastseen = value;
1199 } 1199 }
1200 if (node == (GaimBlistNode*)pr) 1200 if (node == (GaimBlistNode*)pr)
1201 continue; 1201 continue;
1202 if (!showoffline && !GAIM_BUDDY_IS_ONLINE((GaimBuddy*)node)) 1202 if (!gaim_account_is_connected(buddy->account))
1203 continue;
1204 if (!showoffline && !GAIM_BUDDY_IS_ONLINE(buddy))
1203 continue; 1205 continue;
1204 str = g_string_append(str, "\n----------\n"); 1206 str = g_string_append(str, "\n----------\n");
1205 g_string_append_printf(str, _("Nickname: %s\n"), gaim_buddy_get_name((GaimBuddy*)node)); 1207 g_string_append_printf(str, _("Nickname: %s\n"), gaim_buddy_get_name(buddy));
1206 tooltip_for_buddy((GaimBuddy*)node, str); 1208 tooltip_for_buddy(buddy, str);
1207 } 1209 }
1208 } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) { 1210 } else if (GAIM_BLIST_NODE_IS_BUDDY(node)) {
1209 GaimBuddy *buddy = (GaimBuddy *)node; 1211 GaimBuddy *buddy = (GaimBuddy *)node;
1210 tooltip_for_buddy(buddy, str); 1212 tooltip_for_buddy(buddy, str);
1211 title = g_strdup(gaim_buddy_get_name(buddy)); 1213 title = g_strdup(gaim_buddy_get_name(buddy));
1228 gaim_account_get_protocol_name(account)); 1230 gaim_account_get_protocol_name(account));
1229 1231
1230 title = g_strdup(gaim_chat_get_name(chat)); 1232 title = g_strdup(gaim_chat_get_name(chat));
1231 } else { 1233 } else {
1232 g_string_free(str, TRUE); 1234 g_string_free(str, TRUE);
1233 return; 1235 return FALSE;
1234 } 1236 }
1235 1237
1236 if (lastseen > 0) { 1238 if (lastseen > 0) {
1237 char *tmp = gaim_str_seconds_to_string(time(NULL) - lastseen); 1239 char *tmp = gaim_str_seconds_to_string(time(NULL) - lastseen);
1238 g_string_append_printf(str, _("\nLast Seen: %s ago"), tmp); 1240 g_string_append_printf(str, _("\nLast Seen: %s ago"), tmp);
1249 box = gnt_box_new(FALSE, FALSE); 1251 box = gnt_box_new(FALSE, FALSE);
1250 gnt_box_set_toplevel(GNT_BOX(box), TRUE); 1252 gnt_box_set_toplevel(GNT_BOX(box), TRUE);
1251 GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_NO_SHADOW); 1253 GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_NO_SHADOW);
1252 gnt_box_set_title(GNT_BOX(box), title); 1254 gnt_box_set_title(GNT_BOX(box), title);
1253 1255
1254 gnt_box_add_widget(GNT_BOX(box), gnt_label_new(str->str)); 1256 str = make_sure_text_fits(str);
1257 gnt_util_get_text_bound(str->str, &w, &h);
1258 h = MAX(2, h);
1259 tv = gnt_text_view_new();
1260 gnt_widget_set_size(tv, w + 1, h);
1261 gnt_box_add_widget(GNT_BOX(box), tv);
1255 1262
1256 gnt_widget_set_position(box, x, y); 1263 gnt_widget_set_position(box, x, y);
1257 GNT_WIDGET_UNSET_FLAGS(box, GNT_WIDGET_CAN_TAKE_FOCUS); 1264 GNT_WIDGET_UNSET_FLAGS(box, GNT_WIDGET_CAN_TAKE_FOCUS);
1258 GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT); 1265 GNT_WIDGET_SET_FLAGS(box, GNT_WIDGET_TRANSIENT);
1259 gnt_widget_draw(box); 1266 gnt_widget_draw(box);
1260 1267
1268 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), str->str, GNT_TEXT_FLAG_NORMAL);
1269 gnt_text_view_scroll(GNT_TEXT_VIEW(tv), 0);
1270
1261 g_free(title); 1271 g_free(title);
1262 g_string_free(str, TRUE); 1272 g_string_free(str, TRUE);
1263 ggblist->tooltip = box; 1273 ggblist->tooltip = box;
1264 ggblist->tnode = node; 1274 ggblist->tnode = node;
1265 1275
1266 gnt_widget_set_name(ggblist->tooltip, "tooltip"); 1276 gnt_widget_set_name(ggblist->tooltip, "tooltip");
1277 return FALSE;
1278 }
1279
1280 static void
1281 draw_tooltip(GGBlist *ggblist)
1282 {
1283 /* When an account has signed off, it removes one buddy at a time.
1284 * Drawing the tooltip after removing each buddy is expensive. On
1285 * top of that, if the selected buddy belongs to the disconnected
1286 * account, then retreiving the tooltip for that causes crash. So
1287 * let's make sure we wait for all the buddies to be removed first.*/
1288 int id = g_timeout_add(0, draw_tooltip_real, ggblist);
1289 g_object_set_data_full(G_OBJECT(ggblist->window), "draw_tooltip_calback",
1290 GINT_TO_POINTER(id), (GDestroyNotify)g_source_remove);
1267 } 1291 }
1268 1292
1269 static void 1293 static void
1270 selection_changed(GntWidget *widget, gpointer old, gpointer current, GGBlist *ggblist) 1294 selection_changed(GntWidget *widget, gpointer old, gpointer current, GGBlist *ggblist)
1271 { 1295 {