4 #include <gtk/gtkmain.h>
5 #include <gtk/gtksignal.h>
6 #include "gtkviscreen.h"
7 #include "../common/conv.h"
9 #define DEFAULT_VI_SCREEN_WIDTH_CHARS 80
10 #define DEFAULT_VI_SCREEN_HEIGHT_LINES 25
11 #define VI_SCREEN_BORDER_ROOM 1
23 static void gtk_vi_screen_class_init (GtkViScreenClass
*klass
);
24 static void gtk_vi_screen_set_arg (GtkObject
*object
,
27 static void gtk_vi_screen_get_arg (GtkObject
*object
,
30 static void gtk_vi_screen_init (GtkViScreen
*vi
);
31 static void gtk_vi_screen_destroy (GtkObject
*object
);
32 static void gtk_vi_screen_realize (GtkWidget
*widget
);
34 static void gtk_vi_screen_map (GtkWidget *widget);
35 static void gtk_vi_screen_unmap (GtkWidget *widget);
37 static void gtk_vi_screen_size_request (GtkWidget
*widget
,
38 GtkRequisition
*requisition
);
39 static void gtk_vi_screen_size_allocate (GtkWidget
*widget
,
40 GtkAllocation
*allocation
);
42 static void gtk_vi_screen_adjustment (GtkAdjustment *adjustment,
46 static void gtk_vi_screen_draw (GtkWidget
*widget
,
48 static gint
gtk_vi_screen_expose (GtkWidget
*widget
,
49 GdkEventExpose
*event
);
51 static void recompute_geometry (GtkViScreen
* vi
);
52 static void expose_text (GtkViScreen
* vi
, GdkRectangle
*area
, gboolean cursor
);
53 static void draw_lines(GtkViScreen
*vi
, gint y
, gint x
, gint ymax
, gint xmax
);
54 static void mark_lines(GtkViScreen
*vi
, gint ymin
, gint xmin
, gint ymax
, gint xmax
);
56 static GtkWidgetClass
*parent_class
= NULL
;
57 static guint vi_screen_signals
[LAST_SIGNAL
] = { 0 };
59 static GdkFont
*gb_font
;
61 #define CharAt(scr,y,x) scr->chars + (y) * scr->cols + x
62 #define FlagAt(scr,y,x) (scr->reverse + (y) * scr->cols + x)
64 #define COLOR_STANDARD 0x00
65 #define COLOR_STANDOUT 0x01
68 enum { SA_ALTERNATE
, SA_INVERSE
};
71 gtk_vi_screen_attribute(GtkViScreen
*vi
, gint attribute
, gint on
)
75 vi
->color
= on
? COLOR_STANDOUT
: COLOR_STANDARD
;
81 gtk_vi_screen_move(GtkViScreen
*vi
, gint row
, gint col
)
86 mark_lines(vi
, vi
->cury
, vi
->curx
, vi
->cury
+1, vi
->curx
+1);
87 line
= vi
->chars
+ row
*vi
->cols
;
88 for (x
= 0, xpos
= 0; xpos
<= col
; ++x
)
89 xpos
+= INTIS9494(*(line
+x
)) ? 2 : 1;
90 xpos
-= INTIS9494(*(line
+--x
)) ? 2 : 1;
93 mark_lines(vi
, vi
->cury
, vi
->curx
, vi
->cury
+1, vi
->curx
+1);
97 cleartoel (GtkViScreen
*vi
, guint row
, guint col
)
101 p
= CharAt(vi
,row
,col
);
102 end
= p
+ vi
->cols
- col
;
103 while (p
< end
) *p
++ = ' ';
107 gtk_vi_screen_clrtoel (GtkViScreen
*vi
)
109 cleartoel(vi
, vi
->cury
, vi
->curx
);
110 memset(FlagAt(vi
,vi
->cury
,vi
->curx
), COLOR_STANDARD
, vi
->cols
- vi
->curx
);
111 mark_lines(vi
, vi
->cury
, vi
->curx
, vi
->cury
+1, vi
->cols
);
115 gtk_vi_screen_addstr(GtkViScreen
*vi
, const char *str
, int len
)
119 for (p
= CharAt(vi
,vi
->cury
,vi
->curx
), end
= p
+ len
; p
< end
; )
121 memset(FlagAt(vi
,vi
->cury
,vi
->curx
), vi
->color
, len
);
122 mark_lines(vi
, vi
->cury
, vi
->curx
, vi
->cury
+1, vi
->curx
+ len
);
123 if ((vi
->curx
+= len
) >= vi
->cols
) {
124 if (++vi
->cury
>= vi
->rows
) {
125 vi
->cury
= vi
->rows
-1;
126 vi
->curx
= vi
->cols
-1;
134 gtk_vi_screen_waddstr(GtkViScreen
*vi
, const CHAR_T
*str
, int len
)
138 MEMMOVE(CharAt(vi
,vi
->cury
,vi
->curx
),str
,len
);
139 memset(FlagAt(vi
,vi
->cury
,vi
->curx
), vi
->color
, len
);
140 mark_lines(vi
, vi
->cury
, vi
->curx
, vi
->cury
+1, vi
->curx
+ len
);
141 if ((vi
->curx
+= len
) >= vi
->cols
) {
142 if (++vi
->cury
>= vi
->rows
) {
143 vi
->cury
= vi
->rows
-1;
144 vi
->curx
= vi
->cols
-1;
152 gtk_vi_screen_deleteln(GtkViScreen
*vi
)
155 gint rows
= vi
->rows
- (y
+1);
157 MEMMOVE(CharAt(vi
,y
,0), CharAt(vi
,y
+1,0), rows
* vi
->cols
);
158 cleartoel(vi
,vi
->rows
-1,0);
159 memmove(FlagAt(vi
,y
,0), FlagAt(vi
,y
+1,0), rows
* vi
->cols
);
160 memset(FlagAt(vi
,vi
->rows
-1,0), COLOR_STANDARD
, vi
->cols
);
161 mark_lines(vi
, y
, 0, vi
->rows
, vi
->cols
);
165 gtk_vi_screen_insertln(GtkViScreen
*vi
)
168 gint rows
= vi
->rows
- (y
+1);
170 MEMMOVE(CharAt(vi
,y
+1,0), CharAt(vi
,y
,0), rows
* vi
->cols
);
172 memmove(FlagAt(vi
,y
+1,0), FlagAt(vi
,y
,0), rows
* vi
->cols
);
173 memset(FlagAt(vi
,y
,0), COLOR_STANDARD
, vi
->cols
);
174 mark_lines(vi
, y
, 0, vi
->rows
, vi
->cols
);
178 gtk_vi_screen_refresh(GtkViScreen
*vi
)
180 if (vi
->marked_maxy
== 0)
182 draw_lines(vi
, vi
->marked_y
, vi
->marked_x
, vi
->marked_maxy
, vi
->marked_maxx
);
183 vi
->marked_x
= vi
->cols
;
184 vi
->marked_y
= vi
->rows
;
190 gtk_vi_screen_rewrite(GtkViScreen
*vi
, gint row
)
192 memset(FlagAt(vi
,row
,0), COLOR_STANDARD
, vi
->cols
);
193 mark_lines(vi
, row
, 0, row
+1, vi
->cols
);
197 gtk_vi_screen_get_type (void)
199 static GtkType vi_screen_type
= 0;
203 static const GtkTypeInfo vi_screen_info
=
206 sizeof (GtkViScreen
),
207 sizeof (GtkViScreenClass
),
208 (GtkClassInitFunc
) gtk_vi_screen_class_init
,
209 (GtkObjectInitFunc
) gtk_vi_screen_init
,
210 /* reserved_1 */ NULL
,
211 /* reserved_2 */ NULL
,
212 (GtkClassInitFunc
) NULL
,
215 vi_screen_type
= gtk_type_unique (GTK_TYPE_WIDGET
, &vi_screen_info
);
218 return vi_screen_type
;
222 gtk_vi_screen_class_init (GtkViScreenClass
*class)
224 GtkObjectClass
*object_class
;
225 GtkWidgetClass
*widget_class
;
227 object_class
= (GtkObjectClass
*) class;
228 widget_class
= (GtkWidgetClass
*) class;
229 parent_class
= gtk_type_class (GTK_TYPE_WIDGET
);
231 vi_screen_signals
[RESIZED
] =
232 gtk_signal_new ("resized",
235 GTK_SIGNAL_OFFSET (GtkViScreenClass
, resized
),
236 gtk_marshal_NONE__INT_INT
,
237 GTK_TYPE_NONE
, 2, GTK_TYPE_INT
, GTK_TYPE_INT
, 0);
239 gtk_object_class_add_signals(object_class
, vi_screen_signals
, LAST_SIGNAL
);
241 gtk_object_add_arg_type ("GtkViScreen::vadjustment",
243 GTK_ARG_READWRITE
| GTK_ARG_CONSTRUCT
,
246 object_class
->set_arg
= gtk_vi_screen_set_arg
;
247 object_class
->get_arg
= gtk_vi_screen_get_arg
;
248 object_class
->destroy
= gtk_vi_screen_destroy
;
250 widget_class
->realize
= gtk_vi_screen_realize
;
252 widget_class->map = gtk_vi_screen_map;
253 widget_class->unmap = gtk_vi_screen_unmap;
255 widget_class
->size_request
= gtk_vi_screen_size_request
;
256 widget_class
->size_allocate
= gtk_vi_screen_size_allocate
;
257 widget_class
->draw
= gtk_vi_screen_draw
;
258 widget_class
->expose_event
= gtk_vi_screen_expose
;
260 class->rename
= NULL
;
261 class->resized
= NULL
;
263 gb_font
= gdk_font_load ("-*-*-*-*-*-*-16-*-*-*-*-*-gb2312.1980-*");
267 gtk_vi_screen_set_arg (GtkObject
*object
,
271 GtkViScreen
*vi_screen
;
273 vi_screen
= GTK_VI_SCREEN (object
);
277 case ARG_VADJUSTMENT
:
278 gtk_vi_screen_set_adjustment (vi_screen
, GTK_VALUE_POINTER (*arg
));
286 gtk_vi_screen_get_arg (GtkObject
*object
,
290 GtkViScreen
*vi_screen
;
292 vi_screen
= GTK_VI_SCREEN (object
);
296 case ARG_VADJUSTMENT
:
297 GTK_VALUE_POINTER (*arg
) = vi_screen
->vadj
;
300 arg
->type
= GTK_TYPE_INVALID
;
306 gtk_vi_screen_init (GtkViScreen
*vi
)
310 GTK_WIDGET_SET_FLAGS (vi
, GTK_CAN_FOCUS
);
312 vi
->text_area
= NULL
;
315 vi
->color
= COLOR_STANDARD
;
319 style
= gtk_style_copy(GTK_WIDGET(vi
)->style
);
320 gdk_font_unref(style
->font
);
321 style
->font
= gdk_font_load("-*-fixed-*-*-*-*-16-*-*-*-*-*-iso8859-*");
322 GTK_WIDGET(vi
)->style
= style
;
326 gtk_vi_screen_destroy (GtkObject
*object
)
328 GtkViScreen
*vi_screen
;
330 g_return_if_fail (object
!= NULL
);
331 g_return_if_fail (GTK_IS_VI_SCREEN (object
));
333 vi_screen
= (GtkViScreen
*) object
;
336 gtk_signal_disconnect_by_data (GTK_OBJECT (vi_screen->vadj), vi_screen);
339 GTK_OBJECT_CLASS(parent_class
)->destroy (object
);
343 gtk_vi_screen_new (GtkAdjustment
*vadj
)
347 vi
= gtk_widget_new (GTK_TYPE_VI_SCREEN
,
356 gtk_vi_screen_set_adjustment (GtkViScreen
*vi_screen
,
359 g_return_if_fail (vi_screen
!= NULL
);
360 g_return_if_fail (GTK_IS_VI_SCREEN (vi_screen
));
362 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj
));
364 vadj
= GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 1.0, 0.0, 1.0, 0.0, 0.0));
366 if (vi_screen
->vadj
&& (vi_screen
->vadj
!= vadj
))
368 gtk_signal_disconnect_by_data (GTK_OBJECT (vi_screen
->vadj
), vi_screen
);
369 gtk_object_unref (GTK_OBJECT (vi_screen
->vadj
));
372 if (vi_screen
->vadj
!= vadj
)
374 vi_screen
->vadj
= vadj
;
375 gtk_object_ref (GTK_OBJECT (vi_screen
->vadj
));
376 gtk_object_sink (GTK_OBJECT (vi_screen
->vadj
));
379 gtk_signal_connect (GTK_OBJECT (vi_screen->vadj), "changed",
380 (GtkSignalFunc) gtk_vi_screen_adjustment,
382 gtk_signal_connect (GTK_OBJECT (vi_screen->vadj), "value_changed",
383 (GtkSignalFunc) gtk_vi_screen_adjustment,
385 gtk_signal_connect (GTK_OBJECT (vi_screen->vadj), "disconnect",
386 (GtkSignalFunc) gtk_vi_screen_disconnect,
388 gtk_vi_screen_adjustment (vadj, vi_screen);
394 gtk_vi_screen_realize (GtkWidget
*widget
)
397 GdkWindowAttr attributes
;
398 gint attributes_mask
;
400 g_return_if_fail (widget
!= NULL
);
401 g_return_if_fail (GTK_IS_VI_SCREEN (widget
));
403 vi
= GTK_VI_SCREEN (widget
);
404 GTK_WIDGET_SET_FLAGS (vi
, GTK_REALIZED
);
406 attributes
.window_type
= GDK_WINDOW_CHILD
;
407 attributes
.x
= widget
->allocation
.x
;
408 attributes
.y
= widget
->allocation
.y
;
409 attributes
.width
= widget
->allocation
.width
;
410 attributes
.height
= widget
->allocation
.height
;
411 attributes
.wclass
= GDK_INPUT_OUTPUT
;
412 attributes
.visual
= gtk_widget_get_visual (widget
);
413 attributes
.colormap
= gtk_widget_get_colormap (widget
);
414 attributes
.event_mask
= gtk_widget_get_events (widget
);
415 attributes
.event_mask
|= (GDK_EXPOSURE_MASK
|
416 GDK_BUTTON_PRESS_MASK
|
417 GDK_BUTTON_RELEASE_MASK
|
418 GDK_BUTTON_MOTION_MASK
|
419 GDK_ENTER_NOTIFY_MASK
|
420 GDK_LEAVE_NOTIFY_MASK
|
422 attributes_mask
= GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
;
424 widget
->window
= gdk_window_new (gtk_widget_get_parent_window (widget
), &attributes
, attributes_mask
);
425 gdk_window_set_user_data (widget
->window
, vi
);
427 attributes
.x
= (widget
->style
->klass
->xthickness
+ VI_SCREEN_BORDER_ROOM
);
428 attributes
.y
= (widget
->style
->klass
->ythickness
+ VI_SCREEN_BORDER_ROOM
);
429 attributes
.width
= MAX (1, (gint
)widget
->allocation
.width
- (gint
)attributes
.x
* 2);
430 attributes
.height
= MAX (1, (gint
)widget
->allocation
.height
- (gint
)attributes
.y
* 2);
432 vi
->text_area
= gdk_window_new (widget
->window
, &attributes
, attributes_mask
);
433 gdk_window_set_user_data (vi
->text_area
, vi
);
435 widget
->style
= gtk_style_attach (widget
->style
, widget
->window
);
437 /* Can't call gtk_style_set_background here because it's handled specially */
438 gdk_window_set_background (widget
->window
, &widget
->style
->base
[GTK_STATE_NORMAL
]);
439 gdk_window_set_background (vi
->text_area
, &widget
->style
->base
[GTK_STATE_NORMAL
]);
441 vi
->gc
= gdk_gc_new (vi
->text_area
);
443 gdk_gc_set_exposures (vi
->gc
, TRUE
);
444 gdk_gc_set_foreground (vi
->gc
, &widget
->style
->text
[GTK_STATE_NORMAL
]);
446 vi
->reverse_gc
= gdk_gc_new (vi
->text_area
);
447 gdk_gc_set_foreground (vi
->reverse_gc
, &widget
->style
->base
[GTK_STATE_NORMAL
]);
449 gdk_window_show (vi
->text_area
);
451 recompute_geometry (vi
);
455 gtk_vi_screen_size_request (GtkWidget
*widget
,
456 GtkRequisition
*requisition
)
464 g_return_if_fail (widget
!= NULL
);
465 g_return_if_fail (GTK_IS_VI_SCREEN (widget
));
466 g_return_if_fail (requisition
!= NULL
);
468 vi
= GTK_VI_SCREEN (widget
);
470 xthickness
= widget
->style
->klass
->xthickness
+ VI_SCREEN_BORDER_ROOM
;
471 ythickness
= widget
->style
->klass
->ythickness
+ VI_SCREEN_BORDER_ROOM
;
473 vi
->ch_ascent
= widget
->style
->font
->ascent
;
474 vi
->ch_height
= (widget
->style
->font
->ascent
+ widget
->style
->font
->descent
) + 1;
475 vi
->ch_width
= gdk_text_width (widget
->style
->font
, "A", 1);
476 char_height
= DEFAULT_VI_SCREEN_HEIGHT_LINES
* vi
->ch_height
;
477 char_width
= DEFAULT_VI_SCREEN_WIDTH_CHARS
* vi
->ch_width
;
479 requisition
->width
= char_width
+ xthickness
* 2;
480 requisition
->height
= char_height
+ ythickness
* 2;
484 gtk_vi_screen_size_allocate (GtkWidget
*widget
,
485 GtkAllocation
*allocation
)
489 g_return_if_fail (widget
!= NULL
);
490 g_return_if_fail (GTK_IS_VI_SCREEN (widget
));
491 g_return_if_fail (allocation
!= NULL
);
493 vi
= GTK_VI_SCREEN (widget
);
495 widget
->allocation
= *allocation
;
496 if (GTK_WIDGET_REALIZED (widget
))
498 gdk_window_move_resize (widget
->window
,
499 allocation
->x
, allocation
->y
,
500 allocation
->width
, allocation
->height
);
502 gdk_window_move_resize (vi
->text_area
,
503 widget
->style
->klass
->xthickness
+ VI_SCREEN_BORDER_ROOM
,
504 widget
->style
->klass
->ythickness
+ VI_SCREEN_BORDER_ROOM
,
505 MAX (1, (gint
)widget
->allocation
.width
- (gint
)(widget
->style
->klass
->xthickness
+
506 (gint
)VI_SCREEN_BORDER_ROOM
) * 2),
507 MAX (1, (gint
)widget
->allocation
.height
- (gint
)(widget
->style
->klass
->ythickness
+
508 (gint
)VI_SCREEN_BORDER_ROOM
) * 2));
510 recompute_geometry (vi
);
516 gtk_vi_screen_adjustment (GtkAdjustment *adjustment,
517 GtkViScreen *vi_screen)
519 g_return_if_fail (adjustment != NULL);
520 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
521 g_return_if_fail (vi_screen != NULL);
522 g_return_if_fail (GTK_IS_VI_SCREEN (vi_screen));
528 gtk_vi_screen_draw (GtkWidget
*widget
,
531 g_return_if_fail (widget
!= NULL
);
532 g_return_if_fail (GTK_IS_VI_SCREEN (widget
));
533 g_return_if_fail (area
!= NULL
);
535 if (GTK_WIDGET_DRAWABLE (widget
))
537 expose_text (GTK_VI_SCREEN (widget
), area
, TRUE
);
538 gtk_widget_draw_focus (widget
);
543 gtk_vi_screen_expose (GtkWidget
*widget
,
544 GdkEventExpose
*event
)
546 g_return_val_if_fail (widget
!= NULL
, FALSE
);
547 g_return_val_if_fail (GTK_IS_VI_SCREEN (widget
), FALSE
);
548 g_return_val_if_fail (event
!= NULL
, FALSE
);
550 if (event
->window
== GTK_VI_SCREEN (widget
)->text_area
)
552 expose_text (GTK_VI_SCREEN (widget
), &event
->area
, TRUE
);
554 else if (event
->count
== 0)
556 gtk_widget_draw_focus (widget
);
563 recompute_geometry (GtkViScreen
* vi
)
572 //xthickness = widget->style->klass->xthickness + VI_SCREEN_BORDER_ROOM;
573 //ythickness = widget->style->klass->ythickness + VI_SCREEN_BORDER_ROOM;
575 gdk_window_get_size (vi
->text_area
, &width
, &height
);
577 rows
= height
/ vi
->ch_height
;
578 cols
= width
/ vi
->ch_width
;
580 if (rows
== vi
->rows
&& cols
== vi
->cols
)
583 vi
->marked_x
= vi
->cols
= cols
;
584 vi
->marked_y
= vi
->rows
= rows
;
589 vi
->chars
= (CHAR_T
*)g_new(gchar
, vi
->rows
*vi
->cols
* sizeof(CHAR_T
));
590 for (i
= 0; i
< vi
->rows
*vi
->cols
; ++i
)
593 vi
->reverse
= g_new(gchar
, vi
->rows
*vi
->cols
);
594 memset(vi
->reverse
, 0, vi
->rows
*vi
->cols
);
596 gtk_signal_emit(GTK_OBJECT(vi
), vi_screen_signals
[RESIZED
], vi
->rows
, vi
->cols
);
600 expose_text (GtkViScreen
* vi
, GdkRectangle
*area
, gboolean cursor
)
605 gdk_window_clear_area (vi
->text_area
, area
->x
, area
->y
,
606 area
->width
, area
->height
);
607 ymax
= MIN((area
->y
+ area
->height
+ vi
->ch_height
- 1) / vi
->ch_height
,
609 xmin
= area
->x
/ vi
->ch_width
;
610 xmax
= MIN((area
->x
+ area
->width
+ vi
->ch_width
- 1) / vi
->ch_width
,
612 draw_lines(vi
, area
->y
/ vi
->ch_height
, xmin
, ymax
, xmax
);
615 #define Inverse(screen,y,x) \
616 ((*FlagAt(screen,y,x) == COLOR_STANDOUT) ^ \
617 (screen->cury == y && screen->curx == x))
620 draw_lines(GtkViScreen
*vi
, gint ymin
, gint xmin
, gint ymax
, gint xmax
)
622 gint y
, x
, len
, blen
, xpos
;
629 for (y
= ymin
, line
= vi
->chars
+ y
*vi
->cols
;
630 y
< ymax
; ++y
, line
+= vi
->cols
) {
631 for (x
= 0, xpos
= 0; xpos
<= xmin
; ++x
)
632 xpos
+= INTIS9494(*(line
+x
)) ? 2 : 1;
633 xpos
-= INTIS9494(*(line
+--x
)) ? 2 : 1;
634 for (; xpos
< xmax
; x
+=len
, xpos
+= blen
) {
636 inverse
= Inverse(vi
,y
,x
);
638 if (sizeof(CHAR_T
) == sizeof(gchar
))
639 for (; x
+len
< xmax
&&
640 Inverse(vi
,y
,x
+len
) == inverse
; ++len
);
648 if (INTIS9494(*(line
+x
))) {
650 buf
[0] = INT9494R(*(line
+x
));
651 buf
[1] = INT9494C(*(line
+x
));
655 font
= GTK_WIDGET(vi
)->style
->font
;
656 if (sizeof(CHAR_T
) == sizeof(gchar
))
664 gdk_draw_rectangle(vi
->text_area
, bg
, 1, xpos
* vi
->ch_width
,
665 y
* vi
->ch_height
, blen
* vi
->ch_width
,
667 gdk_draw_text (vi
->text_area
, font
, fg
,
669 y
* vi
->ch_height
+ vi
->ch_ascent
,
676 mark_lines(GtkViScreen
*vi
, gint ymin
, gint xmin
, gint ymax
, gint xmax
)
678 if (ymin
< vi
->marked_y
) vi
->marked_y
= ymin
;
679 if (xmin
< vi
->marked_x
) vi
->marked_x
= xmin
;
680 if (ymax
> vi
->marked_maxy
) vi
->marked_maxy
= ymax
;
681 if (xmax
> vi
->marked_maxx
) vi
->marked_maxx
= xmax
;