/* * Copyright (C) 1998 Nathan Neulinger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include "gtkyahoo.h" #include #include #include GtkWidget *create_combo_identities(char *defaulttext, int editable) { GtkWidget *combo; GList *identlist; int i; /* optionmenu for choosing what identity to chat with */ identlist = NULL; if (context->identities) { i = 0; while (context->identities[i]) { identlist = g_list_append(identlist, context->identities[i]); i++; } } else { identlist = g_list_append(identlist, current_user); } combo = gtk_combo_new(); gtk_combo_set_popdown_strings(GTK_COMBO(combo), identlist); gtk_combo_set_use_arrows_always(GTK_COMBO(combo), TRUE); if (defaulttext) { gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), defaulttext); } gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo)->entry), editable); return combo; } GtkWidget *create_combo_groups(char *defaulttext, int editable) { GtkWidget *combo; GList *grouplist; char *lastgroup; int i; /* Build the list of group names for the combo box */ i = 0; grouplist = NULL; lastgroup = ""; while (context->buddies && context->buddies[i]) { if (strcmp(context->buddies[i]->group, lastgroup)) { grouplist = g_list_append(grouplist, context->buddies[i]->group); } lastgroup = context->buddies[i]->group; i++; } if (!grouplist) { grouplist = g_list_append(grouplist, "Friends"); } combo = gtk_combo_new(); gtk_combo_set_popdown_strings(GTK_COMBO(combo), grouplist); gtk_combo_set_use_arrows_always(GTK_COMBO(combo), TRUE); gtk_combo_set_case_sensitive(GTK_COMBO(combo), TRUE); if (defaulttext) { gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), defaulttext); } gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo)->entry), editable); return combo; } char *make_timestamp(void) { static char timestamp[22]; time_t timep; struct tm *timeptr; time(&timep); timeptr = localtime(&timep); strftime(timestamp, 22, "[%m/%d/%Y %H:%M:%S] ", timeptr); return timestamp; } char *make_short_timestamp(time_t *timep) { if (!timep) return NULL; else { struct tm *timeptr = localtime(timep); static char timestamp[13]; strftime(timestamp, sizeof(timestamp), "%a %l:%M %P", timeptr); /* don't want the double space before the time */ { char *c = timestamp; while (*(++c)) if (c[0] == ' ' && c[1] == ' ') break; if (*c) { while (*c) { c[0] = c[1]; c++; } } } return timestamp; } } /* Routines for hash table and chat windows */ guint gtkyahoo_hash(gpointer rawkey) { int i; char *key = (char *) rawkey; unsigned int res = 0; for (i = 0; i < strlen(key); i++) { res += key[i]; } return res; } gint gtkyahoo_hash_compare(gpointer a, gpointer b) { return strcasecmp(a, b) == 0; } /* Create the chat log file and flag cw->singlelog to indicate whether we're * using single or multiple logfiles * FORMAT: * gtkyahoo specific starts with '@': * @F chat_from * @T chat_to * date format starts with '%': * %a The abbreviated weekday name * %D Date (mm/dd/yy) * %T Time in hh:mm:ss * ... see the man page for 'date' for other formats * %n (newline) and %t (tab) are omitted */ char *create_chat_logfilename(char *chat_log_fileformat, struct gtkyahoo_chat_window *cw) { char *ptr = chat_log_fileformat; char *dest = NULL; char *ptr2dest = dest; char *tocopy; int destlen = 0; int len; static char timestamp[30]; /* hopefully 30 is enough for all strftime() time format */ time_t timep; struct tm *timeptr; char timefmt[3]; timefmt[0] = '%'; timefmt[2] = '\0'; cw->singlelog = 1; while (*ptr) { switch (*ptr) { case '@': ptr++; if ( *ptr == 'F' ) { tocopy = cw->chat_from; len = strlen(tocopy); ptr++; } else if ( *ptr == 'T') { tocopy = cw->chat_to; len = strlen(tocopy); ptr++; /* Set for multiple logfile if the filename contains 'chat_to'. Not sure if this is enough * justification for deciding single or multiple chat logfile */ cw->singlelog = 0; } else { tocopy = ptr-1; len = 1; } break; case '%': ptr++; /* 'man date' for detail, %n (newline) and %t (tab) are omitted */ if (strchr("%aAbBcdDehHIjklmMprsSTUVwWxXyYzZ", *ptr)) { timefmt[1] = *ptr; time(&timep); timeptr = localtime(&timep); len = strftime(timestamp, 30, timefmt, timeptr); tocopy = timestamp; ptr++; } else { tocopy = ptr-1; len = 1; } break; default: ptr++; tocopy = ptr-1; len = 1; } dest = realloc(dest, destlen + len + 1); ptr2dest = dest + destlen; strncpy(ptr2dest, tocopy, len); destlen += len; *(ptr2dest+len) = '\0'; } DBG_Print("rcfile", "chat log file format = '%s'\n", chat_log_fileformat); DBG_Print("rcfile", "chat log file name = '%s'\n", dest); return dest; } /* Strip out unsafe chars from username, offically yahoo won't allow them anyway s */ int shellsafecpy(char *dest, char *src, int length) { int count = 0; while ((*src) && (count++ < length)) { switch (*src) { case ';': case '&': case '>': case '<': case '%': case '$': case '|': case '!': case '`': continue; default: *(dest++) = *(src++); continue; } } *dest = '\0'; return count; } /* Lookup colors based on rgb values */ GdkColor *gtkyahoo_window_alloc_color(GtkWidget * window, short red, short green, short blue, GdkColor * color) { /* the color we want to use */ if (!color) color = (GdkColor *) malloc(sizeof(GdkColor)); /* red, green, and blue are passed values, indicating the RGB triple * of the color we want to draw. Note that the values of the RGB components * within the GdkColor are taken from 0 to 65535, not 0 to 255. */ color->red = red * (65535 / 255); color->green = green * (65535 / 255); color->blue = blue * (65535 / 255); /* color->pixel is filled in by gtk_colormap_alloc_color(), request a best match color that we will not adjust, multiple requests for the same color will not eat additional entries */ gdk_colormap_alloc_color(gtk_widget_get_colormap(window), color, TRUE, TRUE); return color; } typedef enum { Medium, Bold } FontWeight; typedef enum { Italic, Roman } FontSlant; static GdkFont *get_font(const char *family, const short size, const FontWeight weight, const FontSlant slant) { GdkFont *font = NULL; char XLFD[1000]; XFontStruct *fontOK = (XFontStruct *) NULL; strcpy(XLFD, "-*"); /* foundry */ if (family && *family) { char *p = NULL, *lowerFace = NULL; strcat(XLFD, "-"); p = lowerFace = strdup(family); while (p && *p) { int c = tolower(*p); *p = c; ++p; } strcat(XLFD, lowerFace); free(lowerFace); } else { strcat(XLFD, "-times"); /* default family, I should really get this from the current theme */ } switch (weight) { case Bold: strcat(XLFD, "-bold"); /* weight */ break; case Medium: default: strcat(XLFD, "-medium"); /* weight */ break; } switch (slant) { case Italic: strcat(XLFD, "-i"); /* slant : italic */ break; case Roman: default: strcat(XLFD, "-r"); /* slant : roman */ break; } strcat(XLFD, "-normal"); /* set width */ strcat(XLFD, "-*"); /* additional style (nil) */ strcat(XLFD, "-*"); /* pixel size (don't care) */ if (size > -1) { char sizeS[10]; sprintf(sizeS, "-%d", 10 * size); strcat(XLFD, sizeS); } else { strcat(XLFD, "-*"); } strcat(XLFD, "-*"); /* resolution X */ strcat(XLFD, "-*"); /* resolution Y */ strcat(XLFD, "-p"); /* proportional spacing */ strcat(XLFD, "-*"); /* Average width */ strcat(XLFD, "-*"); /* Charset registry */ strcat(XLFD, "-*"); /* Charset encoding */ /* Test load the font. If it fails, fontOK is null, and get on with * life after giving the user an error. * If it is successful, immediately unload the font, since we're using * GTK+ here, mmmk? */ fontOK = XLoadQueryFont(GDK_DISPLAY(), XLFD); if (fontOK == (XFontStruct *) NULL || (!fontOK)) { /* Font was no good - you can't load this font. */ DBG_Print("font", "Not worth calling gdk_font_load (\"%s\")!\n", XLFD); font = NULL; } else { /* Remember to free this since XLoadQueryFont returns allocated memory */ XFreeFont(GDK_DISPLAY(), fontOK); DBG_Print("font", "Calling gdk_font_load (\"%s\")", XLFD); font = gdk_font_load(XLFD); DBG_Print("font", " %s\n", (font == NULL ? "FAILED!" : "worked.")); } return font; } static GdkFont *getFont(int bold, int italic, int underline, const char *family, const char *sizeS) { static GdkFont *font = NULL; FontWeight weight; FontSlant slant; short size = -1; if (sizeS && *sizeS) { size = atoi(sizeS); } weight = bold ? Bold : Medium; slant = italic ? Italic : Roman; if (NULL != font) { gdk_font_unref(font); font = NULL; } if (NULL == (font = get_font(family, size, weight, slant))) { /* If the getting the actual font fails, first try a few sizes smaller and then try a blank family */ short trySize = size - 1, endTrySize = (size - 4); if (family && *family) { while ((trySize > 0) && (NULL == (font = get_font(family, trySize, weight, slant))) && (trySize > endTrySize)) { --trySize; } } if (NULL == font) { trySize = size; while ((trySize > 0) && (NULL == (font = get_font(NULL, trySize, weight, slant))) && (trySize > endTrySize)) { --trySize; } } } if (NULL == font) { gdk_font_ref(font); } return (font); } #define YAHOO_FONT_TAG_START "' == text[i]) { ++i; closeFound = TRUE; continue; } if (!strncmp(&text[i], YAHOO_FONT_SIZE_START, strlen(YAHOO_FONT_SIZE_START))) { int k = 0; i += strlen(YAHOO_FONT_SIZE_START); while (text && i < strlen(text) && text[i] != '"') { size[k] = text[i]; ++i; ++k; size[k] = '\0'; } while (text && i < strlen(text) && NULL != strchr("\" \t", text[i])) { ++i; } } } if (!myfontsonly) { font = getFont(bold, italic, underline, face, size); } } else if (!strncmp(&text[i], YAHOO_COLOR_BLACK, strlen(YAHOO_COLOR_BLACK))) { memcpy(oldColor, color, sizeof(GdkColor)); color = gtkyahoo_window_alloc_color(window, 0x00, 0x00, 0x00, color); i += strlen(YAHOO_COLOR_BLACK); continue; } else if (!strncmp(&text[i], YAHOO_COLOR_BLUE, strlen(YAHOO_COLOR_BLUE))) { memcpy(oldColor, color, sizeof(GdkColor)); color = gtkyahoo_window_alloc_color(window, 0x00, 0x00, 0xff, color); i += strlen(YAHOO_COLOR_BLUE); continue; } else if (!strncmp(&text[i], YAHOO_COLOR_RED, strlen(YAHOO_COLOR_RED))) { memcpy(oldColor, color, sizeof(GdkColor)); color = gtkyahoo_window_alloc_color(window, 0xff, 0x00, 0x00, color); i += strlen(YAHOO_COLOR_RED); continue; } else if (!strncmp(&text[i], YAHOO_COLOR_GREEN, strlen(YAHOO_COLOR_GREEN))) { memcpy(oldColor, color, sizeof(GdkColor)); color = gtkyahoo_window_alloc_color(window, 0x09, 0x7a, 0x1e, color); i += strlen(YAHOO_COLOR_GREEN); continue; } else if (!strncmp(&text[i], YAHOO_COLOR_GRAY, strlen(YAHOO_COLOR_GRAY))) { memcpy(oldColor, color, sizeof(GdkColor)); color = gtkyahoo_window_alloc_color(window, 0xc8, 0xc8, 0xc8, color); i += strlen(YAHOO_COLOR_GRAY); continue; } else if (!strncmp(&text[i], YAHOO_COLOR_LIGHTBLUE, strlen(YAHOO_COLOR_LIGHTBLUE))) { memcpy(oldColor, color, sizeof(GdkColor)); color = gtkyahoo_window_alloc_color(window, 0x99, 0xa6, 0xef, color); i += strlen(YAHOO_COLOR_LIGHTBLUE); continue; } else if (!strncmp(&text[i], YAHOO_COLOR_PINK, strlen(YAHOO_COLOR_PINK))) { memcpy(oldColor, color, sizeof(GdkColor)); color = gtkyahoo_window_alloc_color(window, 0xef, 0x99, 0xe9, color); i += strlen(YAHOO_COLOR_PINK); continue; } else if (!strncmp(&text[i], YAHOO_COLOR_OLIVE, strlen(YAHOO_COLOR_OLIVE))) { memcpy(oldColor, color, sizeof(GdkColor)); color = gtkyahoo_window_alloc_color(window, 0x54, 0x6b, 0x50, color); i += strlen(YAHOO_COLOR_OLIVE); continue; } else if (!strncmp(&text[i], YAHOO_COLOR_PURPLE, strlen(YAHOO_COLOR_PURPLE))) { memcpy(oldColor, color, sizeof(GdkColor)); color = gtkyahoo_window_alloc_color(window, 0x8a, 0x1b, 0xa3, color); i += strlen(YAHOO_COLOR_PURPLE); continue; } else if (!strncmp(&text[i], YAHOO_COLOR_ORANGE, strlen(YAHOO_COLOR_ORANGE))) { memcpy(oldColor, color, sizeof(GdkColor)); color = gtkyahoo_window_alloc_color(window, 0xfc, 0xc1, 0x0f, color); i += strlen(YAHOO_COLOR_ORANGE); continue; } else if (!strncmp(&text[i], YAHOO_STYLE_BOLDON, strlen(YAHOO_STYLE_BOLDON))) { bold = TRUE; font = getFont(bold, italic, underline, face, size); i += strlen(YAHOO_STYLE_BOLDON); continue; } else if (!strncmp(&text[i], YAHOO_STYLE_BOLDOFF, strlen(YAHOO_STYLE_BOLDOFF))) { bold = FALSE; font = getFont(bold, italic, underline, face, size); i += strlen(YAHOO_STYLE_BOLDOFF); continue; } else if (!strncmp(&text[i], YAHOO_STYLE_ITALICON, strlen(YAHOO_STYLE_ITALICON))) { italic = TRUE; font = getFont(bold, italic, underline, face, size); i += strlen(YAHOO_STYLE_ITALICON); continue; } else if (!strncmp(&text[i], YAHOO_STYLE_ITALICOFF, strlen(YAHOO_STYLE_ITALICOFF))) { italic = FALSE; font = getFont(bold, italic, underline, face, size); i += strlen(YAHOO_STYLE_ITALICOFF); continue; } else if (!strncmp(&text[i], YAHOO_STYLE_UNDERLINEON, strlen(YAHOO_STYLE_UNDERLINEON))) { underline = TRUE; font = getFont(bold, italic, underline, face, size); i += strlen(YAHOO_STYLE_UNDERLINEON); continue; } else if (!strncmp(&text[i], YAHOO_STYLE_UNDERLINEOFF, strlen(YAHOO_STYLE_UNDERLINEOFF))) { underline = FALSE; font = getFont(bold, italic, underline, face, size); i += strlen(YAHOO_STYLE_UNDERLINEOFF); continue; } else if (!strncmp(&text[i], YAHOO_STYLE_URLON, strlen(YAHOO_STYLE_URLON))) { url = TRUE; memcpy(oldColor, color, sizeof(GdkColor)); color = gtkyahoo_window_alloc_color(window, 0x00, 0x00, 0xff, color); i += strlen(YAHOO_STYLE_URLON); continue; } else if (!strncmp(&text[i], YAHOO_STYLE_URLOFF, strlen(YAHOO_STYLE_URLOFF))) { url = FALSE; color = oldColor; i += strlen(YAHOO_STYLE_URLOFF); continue; } if (i >= strlen(text)) { break; } gtk_text_insert(GTK_TEXT(textbox), font, color, NULL, (gchar *) & text[i], 1); i++; } } GtkWidget *xpm_label_box(GtkWidget * parent, gchar ** xpm_data, gchar * label_text) { GtkWidget *box1; GtkWidget *label; GtkWidget *pixmapwid; GdkPixmap *pixmap; GdkBitmap *mask; GtkStyle *style; /* Warn to use something else */ if (parent->window == NULL) { DBG_Print("gtk", "xpm_label_box() called with null parent.\n"); return NULL; } /* create box for xpm and label */ box1 = gtk_hbox_new(FALSE, 0); gtk_container_border_width(GTK_CONTAINER(box1), 2); style = gtk_widget_get_style(parent); pixmap = gdk_pixmap_create_from_xpm_d(parent->window, &mask, &style->bg[GTK_STATE_NORMAL], xpm_data); pixmapwid = gtk_pixmap_new(pixmap, mask); /* create label for button */ label = gtk_label_new(label_text); /* pack the pixmap and label into the box */ gtk_box_pack_start(GTK_BOX(box1), pixmapwid, FALSE, FALSE, 3); gtk_box_pack_start(GTK_BOX(box1), label, FALSE, FALSE, 3); gtk_widget_show(pixmapwid); gtk_widget_show(label); gtk_widget_show(box1); return (box1); } /* Launch browser using url-handler or netscape -remote w/ fallback */ void launch_browser(char *url) { int pid; DBG_Print("external", "Launch Browser (%s)\n", url); if (url_handler) { pid = fork(); if (pid == 0) { execlp(url_handler, url_handler, url, NULL); execl("/bin/false", "/bin/false", NULL); /* gets rid of X error on failure */ exit(1); } else if (pid == -1) { printf("Error: Failed to fork for URL handler.\n"); } } else { #if defined(PATH_PROG_NETSCAPE) pid = fork(); if (pid == 0) { char *tmp; tmp = (char *) g_malloc(strlen(url) + 20); sprintf(tmp, "openURL(%s)", url); execl(PATH_PROG_NETSCAPE, PATH_PROG_NETSCAPE, "-raise", "-remote", tmp, NULL); DBG_Print("external", "Launch Cmd: %s -raise -remote %s\n", PATH_PROG_NETSCAPE, tmp); _exit(1); } else if (pid == -1) { printf("Error: Failed to fork for URL handler.\n"); } #else printf("Error: No URL handler available.\n"); #endif } } /* Play a sound using the sound-handler defined in rc file, or default to the sound handler script $prefix/lib/gtkyahoo/gtkyahoo-sound-handler */ void play_sound(char *file) { int pid; struct stat st_buf; char *filename = NULL; DBG_Print("external", "Play Sound (%s)\n", file); if (!file) { printf("Error: Sound filename is null!\n"); return; } if (0 == lstat (file, &st_buf)) { filename = strdup (file); } else { #define SOUNDSUBDIR "/sounds/" filename = malloc (strlen (PKGDATADIR) + strlen (file) + 1 + strlen (SOUNDSUBDIR)); strcpy (filename, PKGDATADIR); strcat (filename, SOUNDSUBDIR); strcat (filename, file); if (-1 == lstat (filename, &st_buf)) { printf("Error: Sound filename doesn't exist!\n"); return; } } if (sound_handler) { pid = fork(); if (pid == 0) { execl(sound_handler, sound_handler, filename, NULL); _exit(1); } else if (pid == -1) { printf("Error: Failed to fork for sound handler.\n"); } else { free (filename); filename = NULL; } } else { printf("Error: No sound handler defined.\n"); } } /* Take a string and return the same string with all letters converted to lowercase */ char *strlower(char *in) { char *tmp; int len, i; if (!in) { return NULL; } len = strlen(in); tmp = (char *) malloc(len + 1); for (i = 0; i < len; i++) { tmp[i] = tolower(in[i]); } tmp[i] = 0; return tmp; } void make_friends_ctree(GtkCTree * tree, gboolean show_offline) { int i; char *lastgroup = ""; GtkCTreeNode *me = NULL; GtkCTreeNode *parent = NULL; GtkCTreeNode *child = NULL; GdkPixmap *pixmap; GdkBitmap *mask; char len; char *labelstatus, *label; int in_pager, in_chat, in_game, status, away; char *labels[4]; /* Clear the list */ gtk_clist_freeze(GTK_CLIST(tree)); gtk_clist_clear(GTK_CLIST(tree)); /* clear this cause otherwise it gets corrupted */ user_selected = NULL; if (last_user_status == YAHOO_STATUS_AVAILABLE) { labels[0] = current_user; } else { int lab_len = 0; char *status = NULL; char *lab = NULL; if (last_user_status != YAHOO_STATUS_CUSTOM) { status = yahoo_get_status_string (last_user_status); } else { status = last_custom_msg; } lab_len = strlen (current_user) + 2 /* " (" */ + strlen (status) + 2 /* ")\0" */; lab = malloc (lab_len); snprintf (lab, lab_len, "%s (%s)", current_user, status); labels[0] = lab; } /* * To save realestate, don't show yourself when you're simply * "available". Maybe this should be an option........ */ if (last_user_status != YAHOO_STATUS_AVAILABLE) { me = gtk_ctree_insert_node(tree, NULL, NULL, labels, 5, mw->pm_here, mw->mask_here, mw->pm_here, mw->mask_here, FALSE, TRUE); } i = 0; online_count = 0; while (context->buddies && context->buddies[i]) { struct yahoo_buddy *tmpbuddy; char *group; char *id; char *msg; char *real_name = NULL; char *label_name = NULL; char *timestamp; tmpbuddy = context->buddies[i]; group = tmpbuddy->group; id = tmpbuddy->id; real_name = tmpbuddy->real_name; if (FALSE == display_real_names) { label_name = id; } else { if (NULL != real_name) { label_name = real_name; } else { label_name = id; } } /* Get status info for user */ in_pager = status_get_in_pager(id); in_chat = status_get_in_chat(id); in_game = status_get_in_game(id); status = status_get_status(id); if (show_status_time) timestamp = make_short_timestamp(status_get_changetime(id)); else timestamp = NULL; msg = status_get_msg(id); away = (status != YAHOO_STATUS_AVAILABLE); /* Choose pixmap according to logged on status */ if (in_pager || in_chat || in_game) { if (away) { if (status == YAHOO_STATUS_IDLE) { pixmap = mw->pm_idle; mask = mw->mask_idle; } else { pixmap = mw->pm_away; mask = mw->mask_away; } } else { pixmap = mw->pm_here; mask = mw->mask_here; } if (status == YAHOO_STATUS_CUSTOM && msg) { labelstatus = msg; } else if (status != 0) { labelstatus = yahoo_get_status_string(status); } else { if (timestamp) labelstatus = "available"; else labelstatus = NULL; } online_count++; } else /* offline */ { /* return if only viewing online users */ if (!show_offline) { /* skip this user */ i++; continue; } pixmap = mw->pm_offline; mask = mw->mask_offline; if (timestamp) labelstatus = "away"; else labelstatus = NULL; } /* Determine length of label, and allocate temporary space for it */ /* labeluser is used so that case gets the case from your buddylist, and it stays that way, instead of the case changing to all lowercase */ if (labelstatus) { len = strlen(label_name) + strlen(labelstatus) + 40; if (timestamp) len += strlen(timestamp) + strlen(" since "); label = (char *) malloc(len); if (timestamp) snprintf(label, len, "%s (%s since %s)", label_name, labelstatus, timestamp); else snprintf(label, len, "%s (%s)", label_name, labelstatus); } else { len = strlen(label_name) + 40; label = (char *) malloc(len); snprintf(label, len, "%s", label_name); } /* if next group, then create new parent node */ if (strcmp(group, lastgroup)) { labels[0] = group; parent = gtk_ctree_insert_node(tree, me, parent, labels, 5, NULL, NULL, NULL, NULL, FALSE, TRUE); lastgroup = group; gtk_ctree_node_set_selectable(tree, parent, FALSE); gtk_ctree_node_set_row_data(tree, parent, NULL); child = NULL; } /* add the new user node */ labels[0] = label; child = gtk_ctree_insert_node(tree, parent, child, labels, 5, pixmap, mask, pixmap, mask, TRUE, FALSE); /* set the row data for the child */ /* slighly unsafe - must make sure that if I ever rebuild the buddy list that I immediately refresh the userlist */ gtk_ctree_node_set_row_data(tree, child, (gpointer) tmpbuddy); /* free temporaries */ free(label); /* move to next buddy */ i++; } gtk_clist_thaw(GTK_CLIST(tree)); } void ensure_window_raised(GdkWindow *window) { #if 0 /* gdk 2.x has gdk_window_deiconify -- I suppose this will work then */ gdk_window_deiconify(window); #endif gdk_window_raise(window); }