Crossfire Client, Branch
R11627
|
00001 const char * const rcsid_gtk2_info_c = 00002 "$Id: info.c 11116 2008-12-30 06:57:53Z mwedel $"; 00003 /* 00004 Crossfire client, a client program for the crossfire program. 00005 00006 Copyright (C) 2005-2008 Mark Wedel & Crossfire Development Team 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00021 00022 The author can be reached via e-mail to crossfire@metalforge.org 00023 */ 00024 00030 #ifdef HAVE_CONFIG_H 00031 # include <config.h> 00032 #endif 00033 00034 #include <gtk/gtk.h> 00035 #include <glade/glade.h> 00036 00037 #include "client.h" 00038 00039 #include "image.h" 00040 #include "gtk2proto.h" 00041 00042 #include "main.h" 00043 00051 #define FONT_NORMAL 0 00052 #define FONT_ARCANE 1 00053 #define FONT_STRANGE 2 00054 #define FONT_FIXED 3 00055 #define FONT_HAND 4 00056 #define NUM_FONTS 5 00057 00061 static char *font_style_names[NUM_FONTS] = { 00062 "info_font_normal", 00063 "info_font_arcane", 00064 "info_font_strange", 00065 "info_font_fixed", 00066 "info_font_hand" 00067 }; 00079 #define NUM_TEXT_VIEWS 2 00080 00081 extern const char * const usercolorname[NUM_COLORS]; 00082 00083 struct Info_Pane 00084 { 00085 GtkWidget *textview; 00086 GtkWidget *scrolled_window; 00087 GtkTextBuffer *textbuffer; 00088 GtkTextMark *textmark; 00089 GtkAdjustment *adjustment; 00090 GtkTextTag *color_tags[NUM_COLORS]; 00091 GtkTextTag *font_tags[NUM_FONTS]; 00092 GtkTextTag *bold_tag, *italic_tag, *underline_tag, *default_tag; 00093 GtkTextTag **msg_type_tags[MSG_TYPE_LAST]; 00094 } info_pane[NUM_TEXT_VIEWS]; 00095 00096 static void message_callback(int flag, int type, int subtype, char *message); 00097 00098 extern const char * const colorname[NUM_COLORS]; 00099 00100 /* 00101 * The idea behind the msg_type_names is to provide meaningful names that the 00102 * client can use to load/save these values, in particular, the gtk2 client 00103 * uses these to find styles on how to draw the different msg types. We could 00104 * set this up as a two dimension array instead - that probably isn't as 00105 * efficient as the number of subtypes varies wildly. The 0 subtypes are used 00106 * for general cases (describe the entire class of those message types). Note 00107 * also that the names here are verbose - the actual code that uses these will 00108 * expand it further. In practice, there should never be entries with both the 00109 * same type/subtype (each subtype should be unique) - if so, the results are 00110 * probably unpredictable on which one the code would use. 00111 */ 00112 #include "msgtypes.h" 00113 00114 static int max_subtype=0, has_style=0; 00115 00133 void set_text_tag_from_style(GtkTextTag *tag, GtkStyle *style, GtkStyle *base_style) 00134 { 00135 g_object_set(tag, "foreground-set", FALSE, NULL); 00136 g_object_set(tag, "background-set", FALSE, NULL); 00137 g_object_set(tag, "font-desc", NULL, NULL); 00138 00139 if (memcmp( 00140 &style->fg[GTK_STATE_NORMAL], 00141 &base_style->fg[GTK_STATE_NORMAL], 00142 sizeof(GdkColor))) 00143 00144 g_object_set(tag, "foreground-gdk", &style->fg[GTK_STATE_NORMAL], NULL); 00145 00146 if (memcmp( 00147 &style->bg[GTK_STATE_NORMAL], 00148 &base_style->bg[GTK_STATE_NORMAL], 00149 sizeof(GdkColor))) 00150 00151 g_object_set(tag, "background-gdk", &style->bg[GTK_STATE_NORMAL], NULL); 00152 00153 if (style->font_desc != base_style->font_desc) 00154 g_object_set(tag, "font-desc", style->font_desc, NULL); 00155 } 00156 00165 void info_get_styles(void) 00166 { 00167 int i, j; 00168 static int has_init=0; 00169 GtkStyle *tmp_style, *base_style[2]; 00170 char style_name[MAX_BUF]; 00171 00172 if (!has_init) { 00173 /* 00174 * We want to set up a 2 dimensional array of msg_type_tags to 00175 * correspond to all the types/subtypes, so looking up any value is 00176 * really easy. We know the size of the types, but don't know the 00177 * number of subtypes - no single declared value. So we just parse the 00178 * msg_type_names to find that, then know how big to make the other 00179 * dimension. We could allocate different number of entries for each 00180 * type, but that makes processing a bit harder (no single value on the 00181 * number of subtypes), and this extra memory usage shouldn't really be 00182 * at all significant. 00183 */ 00184 for (i = 0; i < sizeof(msg_type_names) / sizeof(Msg_Type_Names); i++) { 00185 if (msg_type_names[i].subtype > max_subtype) 00186 max_subtype = msg_type_names[i].subtype; 00187 } 00188 for (j = 0; j < NUM_TEXT_VIEWS; j++) { 00189 for (i = 0; i < MSG_TYPE_LAST; i++) 00190 info_pane[j].msg_type_tags[i] = 00191 calloc(max_subtype + 1, sizeof(GtkTextTag*)); 00192 00193 for (i = 0; i < NUM_FONTS; i++) 00194 info_pane[j].font_tags[i] = NULL; 00195 00196 for (i = 0; i < NUM_COLORS; i++) 00197 info_pane[j].color_tags[i] = NULL; 00198 /* 00199 * These tag definitions never change - we don't get them from the 00200 * settings file (maybe we should), so we only need to allocate 00201 * them once. 00202 */ 00203 info_pane[j].bold_tag = 00204 gtk_text_buffer_create_tag(info_pane[j].textbuffer, 00205 "bold", "weight", PANGO_WEIGHT_BOLD, NULL); 00206 00207 info_pane[j].italic_tag = 00208 gtk_text_buffer_create_tag(info_pane[j].textbuffer, 00209 "italic", "style", PANGO_STYLE_ITALIC, NULL); 00210 00211 info_pane[j].underline_tag = 00212 gtk_text_buffer_create_tag(info_pane[j].textbuffer, 00213 "underline", "underline", PANGO_UNDERLINE_SINGLE, NULL); 00214 /* 00215 * This is really a convenience - we can pass multiple tags in when 00216 * drawing text, but once we pass in a NULL tag, that signifies no 00217 * more tags. Rather than having to set up an array we pass in, 00218 * instead, we have this empty tag that we can pass is so that we 00219 * always have the same calling semantics, just differ what tags we 00220 * pass in. 00221 */ 00222 if (!info_pane[j].default_tag) 00223 info_pane[j].default_tag = 00224 gtk_text_buffer_create_tag(info_pane[j].textbuffer, 00225 "default", NULL); 00226 } 00227 has_init = 1; 00228 } 00229 for (i = 0; i < NUM_TEXT_VIEWS; i++) { 00230 base_style[i] = 00231 gtk_rc_get_style_by_paths( 00232 gtk_settings_get_default(), 00233 NULL, "info_default", G_TYPE_NONE); 00234 } 00235 if (!base_style[0]) { 00236 LOG(LOG_INFO, "info.c::info_get_styles", 00237 "Unable to find base style info_default" 00238 " - will not process most info tag styles!"); 00239 } 00240 00241 has_style = 0; 00242 00243 /* 00244 * If we don't have a base style tag, we can't process these other tags, as 00245 * we need to be able to do a difference, and doing a difference from 00246 * nothing (meaning, taking everything in style) still doesn't work really 00247 * well. 00248 */ 00249 if (base_style[0]) { 00250 /* 00251 * This processes the type/subtype styles. We look up the names in the 00252 * array to find what name goes to what number. 00253 */ 00254 for (i = 0; i < sizeof(msg_type_names) / sizeof(Msg_Type_Names); i++) { 00255 int type, subtype; 00256 00257 snprintf(style_name, sizeof(style_name), "msg_%s", msg_type_names[i].style_name); 00258 type = msg_type_names[i].type; 00259 subtype = msg_type_names[i].subtype; 00260 00261 tmp_style = 00262 gtk_rc_get_style_by_paths( 00263 gtk_settings_get_default(), NULL, style_name, G_TYPE_NONE); 00264 00265 for (j = 0; j < NUM_TEXT_VIEWS; j++) { 00266 /* 00267 * If we have a style for this, update the tag that goes along 00268 * with this. If we don't have a tag for this style, create 00269 * it. 00270 */ 00271 if (tmp_style) { 00272 if (!info_pane[j].msg_type_tags[type][subtype]) { 00273 info_pane[j].msg_type_tags[type][subtype] = 00274 gtk_text_buffer_create_tag( 00275 info_pane[j].textbuffer, NULL, NULL); 00276 } 00277 set_text_tag_from_style( 00278 info_pane[j].msg_type_tags[type][subtype], 00279 tmp_style, base_style[j]); 00280 has_style = 1; 00281 } else { 00282 /* 00283 * No setting for this type/subtype, so remove tag if there 00284 * is one. 00285 */ 00286 if (info_pane[j].msg_type_tags[type][subtype]) { 00287 gtk_text_tag_table_remove( 00288 gtk_text_buffer_get_tag_table( 00289 info_pane[j].textbuffer), 00290 info_pane[j].msg_type_tags[type][subtype]); 00291 info_pane[j].msg_type_tags[type][subtype] = NULL; 00292 } 00293 } 00294 } 00295 } 00296 00297 /* 00298 * Old message/color support. 00299 */ 00300 for (i = 0; i < NUM_COLORS; i++) { 00301 snprintf(style_name, MAX_BUF, "info_%s", usercolorname[i]); 00302 00303 tmp_style = 00304 gtk_rc_get_style_by_paths( 00305 gtk_settings_get_default(), NULL, style_name, G_TYPE_NONE); 00306 00307 for (j = 0; j < NUM_TEXT_VIEWS; j++) { 00308 if (tmp_style) { 00309 if (!info_pane[j].color_tags[i]) { 00310 info_pane[j].color_tags[i] = 00311 gtk_text_buffer_create_tag( 00312 info_pane[j].textbuffer, NULL, NULL); 00313 } 00314 set_text_tag_from_style( 00315 info_pane[j].color_tags[i], 00316 tmp_style, base_style[j]); 00317 } else { 00318 if (info_pane[j].color_tags[i]) { 00319 gtk_text_tag_table_remove( 00320 gtk_text_buffer_get_tag_table( 00321 info_pane[j].textbuffer), 00322 info_pane[j].color_tags[i]); 00323 info_pane[j].color_tags[i] = NULL; 00324 } 00325 } 00326 } 00327 } 00328 00329 /* Font type support */ 00330 for (i = 0; i < NUM_FONTS; i++) { 00331 tmp_style = 00332 gtk_rc_get_style_by_paths( 00333 gtk_settings_get_default(), 00334 NULL, font_style_names[i], G_TYPE_NONE); 00335 00336 for (j = 0; j < NUM_TEXT_VIEWS; j++) { 00337 if (tmp_style) { 00338 if (!info_pane[j].font_tags[i]) { 00339 info_pane[j].font_tags[i] = 00340 gtk_text_buffer_create_tag( 00341 info_pane[j].textbuffer, NULL, NULL); 00342 } 00343 set_text_tag_from_style( 00344 info_pane[j].font_tags[i], tmp_style, base_style[j]); 00345 } else { 00346 if (info_pane[j].font_tags[i]) { 00347 gtk_text_tag_table_remove( 00348 gtk_text_buffer_get_tag_table( 00349 info_pane[j].textbuffer), 00350 info_pane[j].font_tags[i]); 00351 info_pane[j].font_tags[i] = NULL; 00352 } 00353 } 00354 } 00355 } 00356 } else { 00357 /* 00358 * There is no base style - this should not normally be the case 00359 * with any real setting files, but certainly can be the case if the 00360 * user selected the 'None' setting. So in this case, we just free all 00361 * the text tags. 00362 */ 00363 has_style = 0; 00364 for (i = 0; i < sizeof(msg_type_names) / sizeof(Msg_Type_Names); i++) { 00365 int type, subtype; 00366 00367 type = msg_type_names[i].type; 00368 subtype = msg_type_names[i].subtype; 00369 00370 for (j = 0; j < NUM_TEXT_VIEWS; j++) { 00371 if (info_pane[j].msg_type_tags[type][subtype]) { 00372 gtk_text_tag_table_remove( 00373 gtk_text_buffer_get_tag_table( 00374 info_pane[j].textbuffer), 00375 info_pane[j].msg_type_tags[type][subtype]); 00376 info_pane[j].msg_type_tags[type][subtype] = NULL; 00377 } 00378 } 00379 } 00380 for (i = 0; i < NUM_COLORS; i++) { 00381 for (j = 0; j < NUM_TEXT_VIEWS; j++) { 00382 if (info_pane[j].color_tags[i]) { 00383 gtk_text_tag_table_remove( 00384 gtk_text_buffer_get_tag_table( 00385 info_pane[j].textbuffer), 00386 info_pane[j].color_tags[i]); 00387 info_pane[j].color_tags[i] = NULL; 00388 } 00389 } 00390 } 00391 /* Font type support */ 00392 for (i = 0; i < NUM_FONTS; i++) { 00393 for (j = 0; j < NUM_TEXT_VIEWS; j++) { 00394 if (info_pane[j].font_tags[i]) { 00395 gtk_text_tag_table_remove( 00396 gtk_text_buffer_get_tag_table( 00397 info_pane[j].textbuffer), 00398 info_pane[j].font_tags[i]); 00399 info_pane[j].font_tags[i] = NULL; 00400 } 00401 } 00402 } 00403 } 00404 } 00405 00413 void info_init(GtkWidget *window_root) 00414 { 00415 int i; 00416 GtkTextIter end; 00417 char widget_name[MAX_BUF]; 00418 GladeXML *xml_tree; 00419 00420 xml_tree = glade_get_widget_tree(GTK_WIDGET(window_root)); 00421 for (i = 0; i < NUM_TEXT_VIEWS; i++) { 00422 snprintf(widget_name, MAX_BUF, "textview_info%d", i+1); 00423 info_pane[i].textview = glade_xml_get_widget(xml_tree, widget_name); 00424 00425 snprintf(widget_name, MAX_BUF, "scrolledwindow_textview%d", i+1); 00426 00427 info_pane[i].scrolled_window = 00428 glade_xml_get_widget(xml_tree, widget_name); 00429 00430 gtk_text_view_set_wrap_mode( 00431 GTK_TEXT_VIEW(info_pane[i].textview), GTK_WRAP_WORD); 00432 00433 info_pane[i].textbuffer = 00434 gtk_text_view_get_buffer(GTK_TEXT_VIEW(info_pane[i].textview)); 00435 00436 info_pane[i].adjustment = 00437 gtk_scrolled_window_get_vadjustment( 00438 GTK_SCROLLED_WINDOW(info_pane[i].scrolled_window)); 00439 00440 gtk_text_buffer_get_end_iter(info_pane[i].textbuffer, &end); 00441 00442 info_pane[i].textmark = 00443 gtk_text_buffer_create_mark( 00444 info_pane[i].textbuffer, NULL, &end, FALSE); 00445 00446 gtk_widget_realize(info_pane[i].textview); 00447 } 00448 00449 info_get_styles(); 00450 00451 /* Register callbacks for all message types */ 00452 for (i = 0; i < MSG_TYPE_LAST; i++) 00453 setTextManager(i, message_callback); 00454 } 00455 00481 static void add_to_textbuf(int pane, char *message, 00482 int type, int subtype, 00483 int bold, int italic, 00484 int font, char *color, int underline) 00485 { 00486 GtkTextIter end; 00487 GdkRectangle rect; 00488 int scroll_to_end=0, color_num; 00489 GtkTextTag *color_tag=NULL, *type_tag=NULL; 00490 00491 /* 00492 * Lets see if the defined color matches any of our defined colors. If we 00493 * get a match, set color_tag. If color_tag is null, we either don't have 00494 * a match, we don't have a defined tag for the color, or we don't have a 00495 * color, use the default tag. It would be nice to know if color is a sub 00496 * value set with [color] tag, or is part of the message itself - if we're 00497 * just being passed NDI_RED in the draw_ext_info from the server, we 00498 * really don't care about that - the type/subtype styles should really be 00499 * what determines what color to use. 00500 */ 00501 if (color) { 00502 for (color_num = 0; color_num < NUM_COLORS; color_num++) 00503 if (!strcasecmp(usercolorname[color_num], color)) 00504 break; 00505 if (color_num < NUM_COLORS) 00506 color_tag = info_pane[pane].color_tags[color_num]; 00507 } 00508 if (!color_tag) 00509 color_tag = info_pane[pane].default_tag; 00510 00511 /* 00512 * Following block of code deals with the type/subtype. First, we check 00513 * and make sure the passed in values are legal. If so, first see if there 00514 * is a particular style for the type/subtype combo, if not, fall back to 00515 * one just for the type. 00516 */ 00517 type_tag = info_pane[pane].default_tag; 00518 00519 if (type >= MSG_TYPE_LAST 00520 || subtype >= max_subtype 00521 || type < 0 || subtype < 0 ) { 00522 LOG(LOG_ERROR, "info.c::add_to_textbuf", 00523 "type (%d) >= MSG_TYPE_LAST (%d) or " 00524 "subtype (%d) >= max_subtype (%d)\n", 00525 type, MSG_TYPE_LAST, subtype, max_subtype); 00526 } else { 00527 if (info_pane[pane].msg_type_tags[type][subtype]) 00528 type_tag = info_pane[pane].msg_type_tags[type][subtype]; 00529 else if (info_pane[pane].msg_type_tags[type][0]) 00530 type_tag = info_pane[pane].msg_type_tags[type][0]; 00531 } 00532 00533 gtk_text_view_get_visible_rect( 00534 GTK_TEXT_VIEW(info_pane[pane].textview), &rect); 00535 00536 if ((info_pane[pane].adjustment->value + rect.height) 00537 >= info_pane[pane].adjustment->upper) 00538 scroll_to_end = 1; 00539 00540 gtk_text_buffer_get_end_iter(info_pane[pane].textbuffer, &end); 00541 00542 gtk_text_buffer_insert_with_tags( 00543 info_pane[pane].textbuffer, &end, message, strlen(message), 00544 bold ? info_pane[pane].bold_tag : info_pane[pane].default_tag, 00545 italic ? info_pane[pane].italic_tag : info_pane[pane].default_tag, 00546 underline ? info_pane[pane].underline_tag : info_pane[pane].default_tag, 00547 info_pane[pane].font_tags[font] ? 00548 info_pane[pane].font_tags[font] : info_pane[pane].default_tag, 00549 color_tag, type_tag, NULL); 00550 00551 if (scroll_to_end) 00552 gtk_text_view_scroll_mark_onscreen( 00553 GTK_TEXT_VIEW(info_pane[pane].textview), info_pane[pane].textmark); 00554 } 00555 00573 static void message_callback(int orig_color, int type, int subtype, char *message) { 00574 char *marker, *current, *original; 00575 int bold=0, italic=0, font=0, underline=0; 00576 int pane=0; 00578 char *color=NULL; 00583 current = strdup(message); 00584 original = current; /* Just so we know what to free */ 00585 00586 if (!has_style) { 00587 if (orig_color <0 || orig_color>NUM_COLORS) { 00588 LOG(LOG_ERROR, "info.c::message_callback", 00589 "Passed invalid color from server: %d, max allowed is %d\n", 00590 orig_color, NUM_COLORS); 00591 orig_color = 0; 00592 } else { 00593 /* 00594 * Not efficient - we have a number, but convert it to a string, at 00595 * which point add_to_textbuf() converts it back to a number :( 00596 */ 00597 color = (char*)usercolorname[orig_color]; 00598 } 00599 } 00600 00601 while ((marker = strchr(current, '[')) != NULL) { 00602 *marker = 0; 00603 00604 if (strlen(current) > 0) 00605 add_to_textbuf(pane, 00606 current, type, subtype, bold, italic, font, color, underline); 00607 00608 current = marker + 1; 00609 00610 if ((marker = strchr(current, ']')) == NULL) { 00611 free(original); 00612 return; 00613 } 00614 00615 *marker = 0; 00616 if (!strcmp(current, "b")) bold = TRUE; 00617 else if (!strcmp(current, "/b")) bold = FALSE; 00618 else if (!strcmp(current, "i")) italic = TRUE; 00619 else if (!strcmp(current, "/i")) italic = FALSE; 00620 else if (!strcmp(current, "ul")) underline = TRUE; 00621 else if (!strcmp(current, "/ul")) underline = FALSE; 00622 else if (!strcmp(current, "fixed")) font = FONT_FIXED; 00623 else if (!strcmp(current, "arcane")) font = FONT_ARCANE; 00624 else if (!strcmp(current, "hand")) font = FONT_HAND; 00625 else if (!strcmp(current, "strange")) font = FONT_STRANGE; 00626 else if (!strcmp(current, "print")) font = FONT_NORMAL; 00627 else if (!strcmp(current, "/color")) color = NULL; 00628 else if (!strncmp(current, "color=", 6)) color = current + 6; 00629 else 00630 LOG(LOG_INFO, "info.c::message_callback", 00631 "unrecognized tag: [%s]\n", current); 00632 00633 current = marker + 1; 00634 } 00635 00636 add_to_textbuf( 00637 pane, current, type, subtype, bold, italic, font, color, underline); 00638 00639 add_to_textbuf( 00640 pane, "\n", type, subtype, bold, italic, font, color, underline); 00641 00642 free(original); 00643 } 00644 00662 void draw_info(const char *str, int color) { 00663 int ncolor = color; 00664 GtkTextIter end; 00665 GdkRectangle rect; 00666 int scroll_to_end=0; 00667 00668 if (ncolor == NDI_WHITE) { 00669 ncolor = NDI_BLACK; 00670 } 00671 00672 /* 00673 * This seems more complicated than it should be, but we need to see if the 00674 * window is scrolled at the end. If it is, we want to keep scrolling it 00675 * down with new info. If not, we don't want to change position - 00676 * otherwise, it makes it very difficult to look back at the old info (like 00677 * old messages missed during combat, looking at the shop listing while 00678 * people are chatting, etc) We need to find out the position before 00679 * putting in new text - otherwise, that operation will mess up our 00680 * position, and not give us right info. 00681 */ 00682 gtk_text_view_get_visible_rect( 00683 GTK_TEXT_VIEW(info_pane[0].textview), &rect); 00684 00685 if ((info_pane[0].adjustment->value + rect.height) 00686 >= info_pane[0].adjustment->upper) 00687 scroll_to_end = 1; 00688 00689 gtk_text_buffer_get_end_iter(info_pane[0].textbuffer, &end); 00690 00691 gtk_text_buffer_insert_with_tags( 00692 info_pane[0].textbuffer, &end, str, strlen(str), 00693 info_pane[0].color_tags[ncolor], NULL); 00694 00695 gtk_text_buffer_insert(info_pane[0].textbuffer, &end, "\n" , 1); 00696 00697 if (scroll_to_end) 00698 gtk_text_view_scroll_mark_onscreen( 00699 GTK_TEXT_VIEW(info_pane[0].textview), info_pane[0].textmark); 00700 00701 /* 00702 * Non-black text is also copied to the critical message panel. Why 00703 * does/should color alone determine the message is critical? 00704 */ 00705 if (color != NDI_BLACK) { 00706 00707 gtk_text_view_get_visible_rect( 00708 GTK_TEXT_VIEW(info_pane[1].textview), &rect); 00709 00710 if ((info_pane[1].adjustment->value + rect.height) 00711 >= info_pane[1].adjustment->upper) 00712 scroll_to_end = 1; 00713 else 00714 scroll_to_end = 0; 00715 00716 gtk_text_buffer_get_end_iter(info_pane[1].textbuffer, &end); 00717 00718 gtk_text_buffer_insert_with_tags( 00719 info_pane[1].textbuffer, &end, str, strlen(str), 00720 info_pane[1].color_tags[ncolor], NULL); 00721 00722 gtk_text_buffer_insert(info_pane[1].textbuffer, &end, "\n" , 1); 00723 00724 if (scroll_to_end) 00725 gtk_text_view_scroll_mark_onscreen( 00726 GTK_TEXT_VIEW(info_pane[1].textview), info_pane[1].textmark); 00727 } 00728 } 00729 00742 void draw_color_info(int colr, const char *buf) { 00743 draw_info(buf,colr); 00744 } 00745 00750 void menu_clear(void) { 00751 int i; 00752 00753 for (i=0; i < NUM_TEXT_VIEWS; i++) { 00754 gtk_text_buffer_set_text(info_pane[i].textbuffer, "", 0); 00755 } 00756 } 00757 00767 void set_scroll(const char *s) 00768 { 00769 } 00770 00780 void set_autorepeat(const char *s) 00781 { 00782 } 00783 00795 int get_info_width(void) 00796 { 00797 return 40; 00798 }