xref: /minix/external/bsd/nvi/dist/gtk/gtkviscreen.c (revision 84d9c625)
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
gtk_vi_screen_attribute(GtkViScreen * vi,gint attribute,gint on)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
gtk_vi_screen_move(GtkViScreen * vi,gint row,gint col)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
cleartoel(GtkViScreen * vi,guint row,guint col)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
gtk_vi_screen_clrtoel(GtkViScreen * vi)118 gtk_vi_screen_clrtoel (GtkViScreen *vi)
119 {
120     cleartoel(vi, vi->cury, vi->curx);
121 }
122 
123 void
gtk_vi_screen_addstr(GtkViScreen * vi,const char * str,int len)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
gtk_vi_screen_waddstr(GtkViScreen * vi,const CHAR_T * str,int len)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
gtk_vi_screen_deleteln(GtkViScreen * vi)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
gtk_vi_screen_insertln(GtkViScreen * vi)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
gtk_vi_screen_refresh(GtkViScreen * vi)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
gtk_vi_screen_rewrite(GtkViScreen * vi,gint row)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
gtk_vi_screen_get_type(void)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
gtk_vi_screen_class_init(GtkViScreenClass * class)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
gtk_vi_screen_set_arg(GtkObject * object,GtkArg * arg,guint arg_id)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
gtk_vi_screen_get_arg(GtkObject * object,GtkArg * arg,guint arg_id)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
gtk_vi_screen_init(GtkViScreen * vi)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
gtk_vi_screen_destroy(GtkObject * object)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*
gtk_vi_screen_new(GtkAdjustment * vadj)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
gtk_vi_screen_set_adjustment(GtkViScreen * vi_screen,GtkAdjustment * vadj)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
gtk_vi_screen_realize(GtkWidget * widget)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
gtk_vi_screen_size_request(GtkWidget * widget,GtkRequisition * requisition)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
gtk_vi_screen_size_allocate(GtkWidget * widget,GtkAllocation * allocation)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
gtk_vi_screen_expose(GtkWidget * widget,GdkEventExpose * event)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
recompute_geometry(GtkViScreen * vi)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
expose_text(GtkViScreen * vi,GdkRectangle * area,gboolean cursor)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
draw_lines(GtkViScreen * vi,gint ymin,gint xmin,gint ymax,gint xmax)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
mark_lines(GtkViScreen * vi,gint ymin,gint xmin,gint ymax,gint xmax)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