1 #include <stdio.h> 2 #include <string.h> 3 4 #include <gtk/gtkmain.h> 5 #include <gtk/gtksignal.h> 6 #include "gtkviscreen.h" 7 #include <gdk/gdkx.h> 8 9 #define INTISUCS(c) ((c & ~0x7F) && !(((c) >> 16) & 0x7F)) 10 #define INTUCS(c) (c) 11 #ifdef USE_WIDECHAR 12 #define CHAR_WIDTH(sp, ch) wcwidth(ch) 13 #else 14 #define CHAR_WIDTH(sp, ch) 1 15 #endif 16 17 void * v_strset __P((CHAR_T *s, CHAR_T c, size_t n)); 18 19 #define DEFAULT_VI_SCREEN_WIDTH_CHARS 80 20 #define DEFAULT_VI_SCREEN_HEIGHT_LINES 25 21 #define VI_SCREEN_BORDER_ROOM 1 22 23 enum { 24 ARG_0, 25 ARG_VADJUSTMENT, 26 }; 27 28 enum { 29 RESIZED, 30 LAST_SIGNAL 31 }; 32 33 static void gtk_vi_screen_class_init (GtkViScreenClass *klass); 34 static void gtk_vi_screen_set_arg (GtkObject *object, 35 GtkArg *arg, 36 guint arg_id); 37 static void gtk_vi_screen_get_arg (GtkObject *object, 38 GtkArg *arg, 39 guint arg_id); 40 static void gtk_vi_screen_init (GtkViScreen *vi); 41 static void gtk_vi_screen_destroy (GtkObject *object); 42 static void gtk_vi_screen_realize (GtkWidget *widget); 43 /* 44 static void gtk_vi_screen_map (GtkWidget *widget); 45 static void gtk_vi_screen_unmap (GtkWidget *widget); 46 */ 47 static void gtk_vi_screen_size_request (GtkWidget *widget, 48 GtkRequisition *requisition); 49 static void gtk_vi_screen_size_allocate (GtkWidget *widget, 50 GtkAllocation *allocation); 51 /* 52 static void gtk_vi_screen_adjustment (GtkAdjustment *adjustment, 53 GtkViScreen *text); 54 */ 55 56 static gint gtk_vi_screen_expose (GtkWidget *widget, 57 GdkEventExpose *event); 58 59 static void recompute_geometry (GtkViScreen* vi); 60 static void expose_text (GtkViScreen* vi, GdkRectangle *area, gboolean cursor); 61 static void draw_lines(GtkViScreen *vi, gint y, gint x, gint ymax, gint xmax); 62 static void mark_lines(GtkViScreen *vi, gint ymin, gint xmin, gint ymax, gint xmax); 63 64 static GtkWidgetClass *parent_class = NULL; 65 static guint vi_screen_signals[LAST_SIGNAL] = { 0 }; 66 67 static GdkFont *gb_font; 68 static GdkFont *tfn; 69 static GdkFont *tfw; 70 71 #define CharAt(scr,y,x) scr->chars + (y) * scr->cols + x 72 #define FlagAt(scr,y,x) (scr->reverse + (y) * scr->cols + x) 73 #define ColAt(scr,y,x) (scr->endcol + (y) * scr->cols + x) 74 75 #define COLOR_STANDARD 0x00 76 #define COLOR_STANDOUT 0x01 77 78 /* XXX */ 79 enum { SA_ALTERNATE, SA_INVERSE }; 80 81 void 82 gtk_vi_screen_attribute(GtkViScreen *vi, gint attribute, gint on) 83 { 84 switch (attribute) { 85 case SA_INVERSE: 86 vi->color = on ? COLOR_STANDOUT : COLOR_STANDARD; 87 break; 88 } 89 } 90 91 /* col is screen column */ 92 void 93 gtk_vi_screen_move(GtkViScreen *vi, gint row, gint col) 94 { 95 gint x; 96 guchar *endcol; 97 98 endcol = vi->endcol + row*vi->cols; 99 for (x = 0; col > endcol[x]; ++x); 100 vi->curx = x; 101 vi->cury = row; 102 } 103 104 static void 105 cleartoel (GtkViScreen *vi, guint row, guint col) 106 { 107 CHAR_T *p, *e; 108 109 if (MEMCMP(p = CharAt(vi,row,col), e = CharAt(vi,vi->rows,0), 110 vi->cols - col)) { 111 MEMMOVE(p, e, vi->cols - col); 112 memset(FlagAt(vi,row,col), COLOR_STANDARD, vi->cols - col); 113 mark_lines(vi, row, col, row+1, vi->cols); 114 } 115 } 116 117 void 118 gtk_vi_screen_clrtoel (GtkViScreen *vi) 119 { 120 cleartoel(vi, vi->cury, vi->curx); 121 } 122 123 void 124 gtk_vi_screen_addstr(GtkViScreen *vi, const char *str, int len) 125 { 126 CHAR_T *p, *end; 127 CHAR_T *line; 128 guchar *endcol; 129 gint col, startcol; 130 gint x; 131 132 line = vi->chars + vi->cury*vi->cols; 133 endcol = vi->endcol + vi->cury*vi->cols; 134 x = vi->curx; 135 startcol = x ? endcol[x-1] : -1; 136 for (p = CharAt(vi,vi->cury,vi->curx), end = p + len, col = startcol; 137 p < end; ++x) { 138 *p++ = *str++; 139 endcol[x] = ++col; 140 } 141 memset(FlagAt(vi,vi->cury,vi->curx), vi->color, len); 142 143 mark_lines(vi, vi->cury, startcol+1, vi->cury+1, endcol[x-1]+1); 144 145 if (endcol[x-1] >= vi->cols) { 146 if (++vi->cury >= vi->rows) { 147 vi->cury = vi->rows-1; 148 vi->curx = x-1; 149 } else { 150 vi->curx = 0; 151 } 152 } else vi->curx += len; 153 if (x < vi->cols) endcol[x] = vi->cols; 154 } 155 156 void 157 gtk_vi_screen_waddstr(GtkViScreen *vi, const CHAR_T *str, int len) 158 { 159 CHAR_T *p, *end; 160 CHAR_T *line; 161 guchar *endcol; 162 gint col, startcol; 163 gint x; 164 165 MEMMOVE(CharAt(vi,vi->cury,vi->curx),str,len); 166 memset(FlagAt(vi,vi->cury,vi->curx), vi->color, len); 167 168 line = vi->chars + vi->cury*vi->cols; 169 endcol = vi->endcol + vi->cury*vi->cols; 170 x = vi->curx; 171 startcol = x ? endcol[x-1] : -1; 172 for (col = startcol; x < vi->curx + len; ++x) 173 endcol[x] = col += CHAR_WIDTH(NULL, *(line+x)); 174 175 mark_lines(vi, vi->cury, startcol+1, vi->cury+1, endcol[x-1]+1); 176 177 if (endcol[x-1] >= vi->cols) { 178 if (++vi->cury >= vi->rows) { 179 vi->cury = vi->rows-1; 180 vi->curx = x-1; 181 } else { 182 vi->curx = 0; 183 } 184 } else vi->curx += len; 185 if (x < vi->cols) endcol[x] = vi->cols; 186 } 187 188 void 189 gtk_vi_screen_deleteln(GtkViScreen *vi) 190 { 191 gint y = vi->cury; 192 gint rows = vi->rows - (y+1); 193 194 MEMMOVE(CharAt(vi,y,0), CharAt(vi,y+1,0), rows * vi->cols); 195 cleartoel(vi,vi->rows-1,0); 196 memmove(FlagAt(vi,y,0), FlagAt(vi,y+1,0), rows * vi->cols); 197 memmove(ColAt(vi,y,0), ColAt(vi,y+1,0), rows * vi->cols); 198 mark_lines(vi, y, 0, vi->rows-1, vi->cols); 199 } 200 201 void 202 gtk_vi_screen_insertln(GtkViScreen *vi) 203 { 204 gint y = vi->cury; 205 gint rows = vi->rows - (y+1); 206 207 MEMMOVE(CharAt(vi,y+1,0), CharAt(vi,y,0), rows * vi->cols); 208 cleartoel(vi,y,0); 209 memmove(FlagAt(vi,y+1,0), FlagAt(vi,y,0), rows * vi->cols); 210 memmove(ColAt(vi,y+1,0), ColAt(vi,y,0), rows * vi->cols); 211 mark_lines(vi, y+1, 0, vi->rows, vi->cols); 212 } 213 214 void 215 gtk_vi_screen_refresh(GtkViScreen *vi) 216 { 217 if (vi->lastx != vi->curx || vi->lasty != vi-> cury) { 218 mark_lines(vi, vi->lasty, 219 vi->lastx ? *ColAt(vi,vi->lasty,vi->lastx-1) + 1 : 0, 220 vi->lasty+1, *ColAt(vi,vi->lasty,vi->lastx)+1); 221 mark_lines(vi, vi->cury, 222 vi->curx ? *ColAt(vi,vi->cury,vi->curx-1) + 1 : 0, 223 vi->cury+1, *ColAt(vi,vi->cury,vi->curx)+1); 224 } 225 if (vi->marked_maxy == 0) 226 return; 227 draw_lines(vi, vi->marked_y, vi->marked_x, vi->marked_maxy, vi->marked_maxx); 228 vi->marked_x = vi->cols; 229 vi->marked_y = vi->rows; 230 vi->marked_maxx = 0; 231 vi->marked_maxy = 0; 232 vi->lastx = vi->curx; 233 vi->lasty = vi->cury; 234 } 235 236 void 237 gtk_vi_screen_rewrite(GtkViScreen *vi, gint row) 238 { 239 memset(FlagAt(vi,row,0), COLOR_STANDARD, vi->cols); 240 mark_lines(vi, row, 0, row+1, vi->cols); 241 } 242 243 GtkType 244 gtk_vi_screen_get_type (void) 245 { 246 static GtkType vi_screen_type = 0; 247 248 if (!vi_screen_type) 249 { 250 static const GtkTypeInfo vi_screen_info = 251 { 252 "GtkViScreen", 253 sizeof (GtkViScreen), 254 sizeof (GtkViScreenClass), 255 (GtkClassInitFunc) gtk_vi_screen_class_init, 256 (GtkObjectInitFunc) gtk_vi_screen_init, 257 /* reserved_1 */ NULL, 258 /* reserved_2 */ NULL, 259 (GtkClassInitFunc) NULL, 260 }; 261 262 vi_screen_type = gtk_type_unique (GTK_TYPE_WIDGET, &vi_screen_info); 263 } 264 265 return vi_screen_type; 266 } 267 268 static void 269 gtk_vi_screen_class_init (GtkViScreenClass *class) 270 { 271 GtkObjectClass *object_class; 272 GtkWidgetClass *widget_class; 273 274 object_class = (GtkObjectClass*) class; 275 widget_class = (GtkWidgetClass*) class; 276 parent_class = gtk_type_class (GTK_TYPE_WIDGET); 277 278 vi_screen_signals[RESIZED] = 279 gtk_signal_new ("resized", 280 GTK_RUN_FIRST, 281 GTK_CLASS_TYPE(object_class), 282 GTK_SIGNAL_OFFSET (GtkViScreenClass, resized), 283 gtk_marshal_NONE__INT_INT, 284 GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT, 0); 285 286 #ifndef HAVE_PANGO 287 gtk_object_class_add_signals(object_class, vi_screen_signals, LAST_SIGNAL); 288 #endif 289 290 gtk_object_add_arg_type ("GtkViScreen::vadjustment", 291 GTK_TYPE_ADJUSTMENT, 292 GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT, 293 ARG_VADJUSTMENT); 294 295 object_class->set_arg = gtk_vi_screen_set_arg; 296 object_class->get_arg = gtk_vi_screen_get_arg; 297 object_class->destroy = gtk_vi_screen_destroy; 298 299 widget_class->realize = gtk_vi_screen_realize; 300 /* 301 widget_class->map = gtk_vi_screen_map; 302 widget_class->unmap = gtk_vi_screen_unmap; 303 */ 304 widget_class->size_request = gtk_vi_screen_size_request; 305 widget_class->size_allocate = gtk_vi_screen_size_allocate; 306 widget_class->expose_event = gtk_vi_screen_expose; 307 308 class->rename = NULL; 309 class->resized = NULL; 310 311 gb_font = gdk_font_load ("-*-*-*-*-*-*-16-*-*-*-*-*-gb2312.1980-*"); 312 /* 313 tf = gdk_font_load ("-misc-fixed-*-*-*-*-16-*-*-*-*-*-iso10646-*"); 314 */ 315 tfn = gdk_font_load ("-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646"); 316 tfw = gdk_font_load ("-Misc-Fixed-Medium-R-*-*-13-120-75-75-C-120-ISO10646-1"); 317 } 318 319 static void 320 gtk_vi_screen_set_arg (GtkObject *object, 321 GtkArg *arg, 322 guint arg_id) 323 { 324 GtkViScreen *vi_screen; 325 326 vi_screen = GTK_VI_SCREEN (object); 327 328 switch (arg_id) 329 { 330 case ARG_VADJUSTMENT: 331 gtk_vi_screen_set_adjustment (vi_screen, GTK_VALUE_POINTER (*arg)); 332 break; 333 default: 334 break; 335 } 336 } 337 338 static void 339 gtk_vi_screen_get_arg (GtkObject *object, 340 GtkArg *arg, 341 guint arg_id) 342 { 343 GtkViScreen *vi_screen; 344 345 vi_screen = GTK_VI_SCREEN (object); 346 347 switch (arg_id) 348 { 349 case ARG_VADJUSTMENT: 350 GTK_VALUE_POINTER (*arg) = vi_screen->vadj; 351 break; 352 default: 353 arg->type = GTK_TYPE_INVALID; 354 break; 355 } 356 } 357 358 static void 359 gtk_vi_screen_init (GtkViScreen *vi) 360 { 361 GtkStyle *style; 362 363 GTK_WIDGET_SET_FLAGS (vi, GTK_CAN_FOCUS); 364 365 vi->text_area = NULL; 366 vi->chars = 0; 367 vi->reverse = 0; 368 vi->cols = 0; 369 vi->color = COLOR_STANDARD; 370 vi->cols = 0; 371 vi->rows = 0; 372 373 #ifdef HAVE_PANGO 374 vi->conx = NULL; 375 #endif 376 377 style = gtk_style_copy(GTK_WIDGET(vi)->style); 378 gdk_font_unref(style->font); 379 style->font = gdk_font_load("-*-fixed-*-*-*-*-16-*-*-*-*-*-iso8859-*"); 380 GTK_WIDGET(vi)->style = style; 381 } 382 383 static void 384 gtk_vi_screen_destroy (GtkObject *object) 385 { 386 GtkViScreen *vi_screen; 387 388 g_return_if_fail (object != NULL); 389 g_return_if_fail (GTK_IS_VI_SCREEN (object)); 390 391 vi_screen = (GtkViScreen*) object; 392 393 /* 394 gtk_signal_disconnect_by_data (GTK_OBJECT (vi_screen->vadj), vi_screen); 395 */ 396 397 GTK_OBJECT_CLASS(parent_class)->destroy (object); 398 } 399 400 GtkWidget* 401 gtk_vi_screen_new (GtkAdjustment *vadj) 402 { 403 GtkWidget *vi; 404 405 vi = gtk_widget_new (GTK_TYPE_VI_SCREEN, 406 "vadjustment", vadj, 407 NULL); 408 409 410 return vi; 411 } 412 413 void 414 gtk_vi_screen_set_adjustment (GtkViScreen *vi_screen, 415 GtkAdjustment *vadj) 416 { 417 g_return_if_fail (vi_screen != NULL); 418 g_return_if_fail (GTK_IS_VI_SCREEN (vi_screen)); 419 if (vadj) 420 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj)); 421 else 422 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 1.0, 0.0, 1.0, 0.0, 0.0)); 423 424 if (vi_screen->vadj && (vi_screen->vadj != vadj)) 425 { 426 gtk_signal_disconnect_by_data (GTK_OBJECT (vi_screen->vadj), vi_screen); 427 gtk_object_unref (GTK_OBJECT (vi_screen->vadj)); 428 } 429 430 if (vi_screen->vadj != vadj) 431 { 432 vi_screen->vadj = vadj; 433 gtk_object_ref (GTK_OBJECT (vi_screen->vadj)); 434 gtk_object_sink (GTK_OBJECT (vi_screen->vadj)); 435 436 /* 437 gtk_signal_connect (GTK_OBJECT (vi_screen->vadj), "changed", 438 (GtkSignalFunc) gtk_vi_screen_adjustment, 439 vi_screen); 440 gtk_signal_connect (GTK_OBJECT (vi_screen->vadj), "value_changed", 441 (GtkSignalFunc) gtk_vi_screen_adjustment, 442 vi_screen); 443 gtk_signal_connect (GTK_OBJECT (vi_screen->vadj), "disconnect", 444 (GtkSignalFunc) gtk_vi_screen_disconnect, 445 vi_screen); 446 gtk_vi_screen_adjustment (vadj, vi_screen); 447 */ 448 } 449 } 450 451 static void 452 gtk_vi_screen_realize (GtkWidget *widget) 453 { 454 GtkViScreen *vi; 455 GdkWindowAttr attributes; 456 gint attributes_mask; 457 458 g_return_if_fail (widget != NULL); 459 g_return_if_fail (GTK_IS_VI_SCREEN (widget)); 460 461 vi = GTK_VI_SCREEN (widget); 462 GTK_WIDGET_SET_FLAGS (vi, GTK_REALIZED); 463 464 attributes.window_type = GDK_WINDOW_CHILD; 465 attributes.x = widget->allocation.x; 466 attributes.y = widget->allocation.y; 467 attributes.width = widget->allocation.width; 468 attributes.height = widget->allocation.height; 469 attributes.wclass = GDK_INPUT_OUTPUT; 470 attributes.visual = gtk_widget_get_visual (widget); 471 attributes.colormap = gtk_widget_get_colormap (widget); 472 attributes.event_mask = gtk_widget_get_events (widget); 473 attributes.event_mask |= (GDK_EXPOSURE_MASK | 474 GDK_BUTTON_PRESS_MASK | 475 GDK_BUTTON_RELEASE_MASK | 476 GDK_BUTTON_MOTION_MASK | 477 GDK_ENTER_NOTIFY_MASK | 478 GDK_LEAVE_NOTIFY_MASK | 479 GDK_KEY_PRESS_MASK); 480 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; 481 482 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); 483 gdk_window_set_user_data (widget->window, vi); 484 485 attributes.x = (widget->style->xthickness + VI_SCREEN_BORDER_ROOM); 486 attributes.y = (widget->style->ythickness + VI_SCREEN_BORDER_ROOM); 487 attributes.width = MAX (1, (gint)widget->allocation.width - (gint)attributes.x * 2); 488 attributes.height = MAX (1, (gint)widget->allocation.height - (gint)attributes.y * 2); 489 490 vi->text_area = gdk_window_new (widget->window, &attributes, attributes_mask); 491 gdk_window_set_user_data (vi->text_area, vi); 492 493 widget->style = gtk_style_attach (widget->style, widget->window); 494 495 /* Can't call gtk_style_set_background here because it's handled specially */ 496 gdk_window_set_background (widget->window, &widget->style->base[GTK_STATE_NORMAL]); 497 gdk_window_set_background (vi->text_area, &widget->style->base[GTK_STATE_NORMAL]); 498 499 vi->gc = gdk_gc_new (vi->text_area); 500 /* What's this ? */ 501 gdk_gc_set_exposures (vi->gc, TRUE); 502 gdk_gc_set_foreground (vi->gc, &widget->style->text[GTK_STATE_NORMAL]); 503 504 vi->reverse_gc = gdk_gc_new (vi->text_area); 505 gdk_gc_set_foreground (vi->reverse_gc, &widget->style->base[GTK_STATE_NORMAL]); 506 507 gdk_window_show (vi->text_area); 508 509 recompute_geometry (vi); 510 } 511 512 static void 513 gtk_vi_screen_size_request (GtkWidget *widget, 514 GtkRequisition *requisition) 515 { 516 gint xthick; 517 gint ythick; 518 gint char_height; 519 gint char_width; 520 GtkViScreen *vi; 521 522 g_return_if_fail (widget != NULL); 523 g_return_if_fail (GTK_IS_VI_SCREEN (widget)); 524 g_return_if_fail (requisition != NULL); 525 526 vi = GTK_VI_SCREEN (widget); 527 528 xthick = widget->style->xthickness + VI_SCREEN_BORDER_ROOM; 529 ythick = widget->style->ythickness + VI_SCREEN_BORDER_ROOM; 530 531 vi->ch_ascent = widget->style->font->ascent; 532 vi->ch_height = (widget->style->font->ascent + widget->style->font->descent) + 1; 533 vi->ch_width = gdk_text_width (widget->style->font, "A", 1); 534 char_height = DEFAULT_VI_SCREEN_HEIGHT_LINES * vi->ch_height; 535 char_width = DEFAULT_VI_SCREEN_WIDTH_CHARS * vi->ch_width; 536 537 requisition->width = char_width + xthick * 2; 538 requisition->height = char_height + ythick * 2; 539 } 540 541 static void 542 gtk_vi_screen_size_allocate (GtkWidget *widget, 543 GtkAllocation *allocation) 544 { 545 GtkViScreen *vi; 546 547 g_return_if_fail (widget != NULL); 548 g_return_if_fail (GTK_IS_VI_SCREEN (widget)); 549 g_return_if_fail (allocation != NULL); 550 551 vi = GTK_VI_SCREEN (widget); 552 553 widget->allocation = *allocation; 554 if (GTK_WIDGET_REALIZED (widget)) 555 { 556 gdk_window_move_resize (widget->window, 557 allocation->x, allocation->y, 558 allocation->width, allocation->height); 559 560 gdk_window_move_resize (vi->text_area, 561 widget->style->xthickness + VI_SCREEN_BORDER_ROOM, 562 widget->style->ythickness + VI_SCREEN_BORDER_ROOM, 563 MAX (1, (gint)widget->allocation.width - (gint)(widget->style->xthickness + 564 (gint)VI_SCREEN_BORDER_ROOM) * 2), 565 MAX (1, (gint)widget->allocation.height - (gint)(widget->style->ythickness + 566 (gint)VI_SCREEN_BORDER_ROOM) * 2)); 567 568 recompute_geometry (vi); 569 } 570 } 571 572 /* 573 static void 574 gtk_vi_screen_adjustment (GtkAdjustment *adjustment, 575 GtkViScreen *vi_screen) 576 { 577 g_return_if_fail (adjustment != NULL); 578 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); 579 g_return_if_fail (vi_screen != NULL); 580 g_return_if_fail (GTK_IS_VI_SCREEN (vi_screen)); 581 582 } 583 */ 584 585 static gint 586 gtk_vi_screen_expose (GtkWidget *widget, 587 GdkEventExpose *event) 588 { 589 g_return_val_if_fail (widget != NULL, FALSE); 590 g_return_val_if_fail (GTK_IS_VI_SCREEN (widget), FALSE); 591 g_return_val_if_fail (event != NULL, FALSE); 592 593 if (event->window == GTK_VI_SCREEN (widget)->text_area) 594 { 595 expose_text (GTK_VI_SCREEN (widget), &event->area, TRUE); 596 } 597 598 return FALSE; 599 } 600 601 static void 602 recompute_geometry (GtkViScreen* vi) 603 { 604 //gint xthickness; 605 //gint ythickness; 606 gint height; 607 gint width; 608 gint rows, cols; 609 gint i; 610 611 //xthickness = widget->style->xthickness + VI_SCREEN_BORDER_ROOM; 612 //ythickness = widget->style->ythickness + VI_SCREEN_BORDER_ROOM; 613 614 gdk_window_get_size (vi->text_area, &width, &height); 615 616 rows = height / vi->ch_height; 617 cols = width / vi->ch_width; 618 619 if (rows == vi->rows && cols == vi->cols) 620 return; 621 622 vi->marked_x = vi->cols = cols; 623 vi->marked_y = vi->rows = rows; 624 vi->marked_maxx = 0; 625 vi->marked_maxy = 0; 626 627 g_free(vi->chars); 628 vi->chars = (CHAR_T*)g_new(gchar, (vi->rows+1)*vi->cols * sizeof(CHAR_T)); 629 STRSET(vi->chars, L(' '), (vi->rows+1)*vi->cols); 630 g_free(vi->endcol); 631 vi->endcol = g_new(guchar, vi->rows*vi->cols); 632 g_free(vi->reverse); 633 vi->reverse = g_new(guchar, vi->rows*vi->cols); 634 memset(vi->reverse, 0, vi->rows*vi->cols); 635 636 gtk_signal_emit(GTK_OBJECT(vi), vi_screen_signals[RESIZED], vi->rows, vi->cols); 637 } 638 639 static void 640 expose_text (GtkViScreen* vi, GdkRectangle *area, gboolean cursor) 641 { 642 gint ymax; 643 gint xmax, xmin; 644 645 gdk_window_clear_area (vi->text_area, area->x, area->y, 646 area->width, area->height); 647 ymax = MIN((area->y + area->height + vi->ch_height - 1) / vi->ch_height, 648 vi->rows); 649 xmin = area->x / vi->ch_width; 650 xmax = MIN((area->x + area->width + vi->ch_width - 1) / vi->ch_width, 651 vi->cols); 652 draw_lines(vi, area->y / vi->ch_height, xmin, ymax, xmax); 653 } 654 655 #define Inverse(screen,y,x) \ 656 ((*FlagAt(screen,y,x) == COLOR_STANDOUT) ^ \ 657 (screen->cury == y && screen->curx == x)) 658 659 static void 660 draw_lines(GtkViScreen *vi, gint ymin, gint xmin, gint ymax, gint xmax) 661 { 662 gint y, x, len, blen, xpos; 663 CHAR_T *line; 664 GdkGC *fg, *bg; 665 GdkFont *font; 666 gchar buf[2]; 667 gchar *p; 668 gboolean pango; 669 670 for (y = ymin, line = vi->chars + y*vi->cols; 671 y < ymax; ++y, line += vi->cols) { 672 for (x = 0, xpos = 0; xpos <= xmin; ++x) 673 xpos += CHAR_WIDTH(NULL, *(line+x)); 674 --x; 675 xpos -= CHAR_WIDTH(NULL, *(line+x)); 676 for (; xpos < xmax; x+=len, xpos+= blen) { 677 gchar inverse; 678 inverse = Inverse(vi,y,x); 679 len = 1; 680 if (sizeof(CHAR_T) == sizeof(gchar)) 681 for (; x+len < xmax && 682 Inverse(vi,y,x+len) == inverse; ++len); 683 if (inverse) { 684 fg = vi->reverse_gc; 685 bg = vi->gc; 686 } else { 687 bg = vi->reverse_gc; 688 fg = vi->gc; 689 } 690 pango = 0; 691 #ifdef HAVE_PANGO 692 if (INTISUCS(*(line+x))) { 693 if (!vi->conx) { 694 PangoFontDescription font_description; 695 696 font_description.family_name = g_strdup ("monospace"); 697 font_description.style = PANGO_STYLE_NORMAL; 698 font_description.variant = PANGO_VARIANT_NORMAL; 699 font_description.weight = 500; 700 font_description.stretch = PANGO_STRETCH_NORMAL; 701 font_description.size = 15000; 702 703 vi->conx = gdk_pango_context_get(); 704 pango_context_set_font_description (vi->conx, 705 &font_description); 706 pango_context_set_lang(vi->conx, "en_US"); 707 vi->alist = pango_attr_list_new(); 708 } 709 blen = CHAR_WIDTH(NULL, *(line+x)); 710 pango = 1; 711 } else 712 #endif 713 { 714 font = GTK_WIDGET(vi)->style->font; 715 if (sizeof(CHAR_T) == sizeof(gchar)) 716 p = (gchar*)line+x; 717 else { 718 buf[0] = *(line+x); 719 p = buf; 720 } 721 blen = len; 722 } 723 gdk_draw_rectangle(vi->text_area, bg, 1, xpos * vi->ch_width, 724 y * vi->ch_height, blen * vi->ch_width, 725 vi->ch_height); 726 /* hack to not display half a wide character that wasn't 727 * removed. 728 */ 729 if (!pango) 730 gdk_draw_text (vi->text_area, font, fg, 731 xpos * vi->ch_width, 732 y * vi->ch_height + vi->ch_ascent, 733 p, blen); 734 #ifdef HAVE_PANGO 735 else { 736 PangoGlyphString *gs; 737 GList *list; 738 PangoItem *item; 739 char buf[3]; 740 int len; 741 742 len = ucs2utf8(line+x, 1, buf); 743 list = pango_itemize(vi->conx, buf, 0, len, vi->alist, NULL); 744 item = list->data; 745 gs = pango_glyph_string_new (); 746 pango_shape(buf, len, &item->analysis, gs); 747 748 gdk_draw_glyphs (vi->text_area, fg, item->analysis.font, 749 xpos * vi->ch_width, 750 y * vi->ch_height + vi->ch_ascent, gs); 751 } 752 #endif 753 } 754 } 755 } 756 757 static void 758 mark_lines(GtkViScreen *vi, gint ymin, gint xmin, gint ymax, gint xmax) 759 { 760 if (ymin < vi->marked_y) vi->marked_y = ymin; 761 if (xmin < vi->marked_x) vi->marked_x = xmin; 762 if (ymax > vi->marked_maxy) vi->marked_maxy = ymax; 763 if (xmax > vi->marked_maxx) vi->marked_maxx = xmax; 764 } 765