Home | History | Annotate | Line # | Download | only in gtk
      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