Home | History | Annotate | Line # | Download | only in motif_l
      1 /*	$NetBSD: m_vi.c,v 1.3 2014/01/26 21:43:45 christos Exp $ */
      2  * Copyright (c) 1996
      3  *	Rob Zimmermann.  All rights reserved.
      4  * Copyright (c) 1996
      5  *	Keith Bostic.  All rights reserved.
      6  *
      7  * See the LICENSE file for redistribution information.
      8  */
      9 
     10 #include "config.h"
     11 
     12 #include <sys/cdefs.h>
     13 #if 0
     14 #ifndef lint
     15 static const char sccsid[] = "Id: m_vi.c,v 8.41 2003/11/05 17:10:01 skimo Exp  (Berkeley) Date: 2003/11/05 17:10:01 ";
     16 #endif /* not lint */
     17 #else
     18 __RCSID("$NetBSD: m_vi.c,v 1.3 2014/01/26 21:43:45 christos Exp $");
     19 #endif
     20 
     21 #include <sys/types.h>
     22 #include <sys/queue.h>
     23 
     24 #include <X11/Intrinsic.h>
     25 #include <X11/StringDefs.h>
     26 #include <X11/cursorfont.h>
     27 #include <Xm/PanedW.h>
     28 #include <Xm/DrawingA.h>
     29 #include <Xm/Form.h>
     30 #include <Xm/Frame.h>
     31 #include <Xm/ScrollBar.h>
     32 
     33 #include <bitstring.h>
     34 #include <ctype.h>
     35 #include <errno.h>
     36 #include <fcntl.h>
     37 #include <signal.h>
     38 #include <stdio.h>
     39 #include <stdlib.h>
     40 #include <string.h>
     41 #include <unistd.h>
     42 
     43 #undef LOCK_SUCCESS
     44 #include "../common/common.h"
     45 #include "../ipc/ip.h"
     46 #include "m_motif.h"
     47 #include "vi_mextern.h"
     48 #include "pathnames.h"
     49 
     50 extern int vi_ofd;
     51 
     52 static	void	f_copy(String *buffer, int *len);
     53 static	void	f_paste(int widget, int buffer, int length);
     54 static	void	f_clear(Widget widget);
     55 
     56 
     57 /*
     59  * Globals and costants
     60  */
     61 
     62 #define	BufferSize	1024
     63 
     64 static	XFontStruct	*font;
     65 static	GC		gc;
     66 	GC		__vi_copy_gc;
     67 static	XtAppContext	ctx;
     68 
     69 	xvi_screen	*__vi_screen = NULL;
     70 static	Cursor		std_cursor;
     71 static	Cursor		busy_cursor;
     72 static	XtTranslations	area_trans;
     73 static	int		multi_click_length;
     74 
     75 void (*__vi_exitp)();				/* Exit function. */
     76 
     77 
     78 /* hack for drag scrolling...
     80  * I'm not sure why, but the current protocol gets out of sync when
     81  * a lot of drag messages get passed around.  Likely, we need to wait
     82  * for core to finish repainting the screen before sending more drag
     83  * messages.
     84  * To that end, we set scroll_block when we receive input from the scrollbar,
     85  * and we clear it when we process the IPO_REFRESH message from core.
     86  * A specific SCROLL_COMPLETED message would be better, but this seems to work.
     87  */
     88 
     89 static Boolean scroll_block = False;
     90 
     91 /*
     92  * PUBLIC: void __vi_set_scroll_block __P((void));
     93  */
     94 void
     95 __vi_set_scroll_block(void)
     96 {
     97 	scroll_block = True;
     98 }
     99 
    100 /*
    101  * PUBLIC: void __vi_clear_scroll_block __P((void));
    102  */
    103 void
    104 __vi_clear_scroll_block(void)
    105 {
    106 	scroll_block = False;
    107 }
    108 
    109 
    110 #if defined(__STDC__)
    112 static	void	set_gc_colors( xvi_screen *this_screen, int val )
    113 #else
    114 static	void	set_gc_colors( this_screen, val )
    115 xvi_screen	*this_screen;
    116 int		val;
    117 #endif
    118 {
    119     static Pixel	fg, bg, hi, shade;
    120     static int		prev = COLOR_INVALID;
    121 
    122     /* no change? */
    123     if ( prev == val ) return;
    124 
    125     /* init? */
    126     if ( gc == NULL ) {
    127 
    128 	/* what colors are selected for the drawing area? */
    129 	XtVaGetValues( this_screen->area,
    130 		       XtNbackground,		&bg,
    131 		       XtNforeground,		&fg,
    132 		       XmNhighlightColor,	&hi,
    133 		       XmNtopShadowColor,	&shade,
    134 		       0
    135 		       );
    136 
    137 	gc = XCreateGC( XtDisplay(this_screen->area),
    138 		        DefaultRootWindow(XtDisplay(this_screen->area)),
    139 			0,
    140 			0
    141 			);
    142 
    143 	XSetFont( XtDisplay(this_screen->area), gc, font->fid );
    144     }
    145 
    146     /* special colors? */
    147     if ( val & COLOR_CARET ) {
    148 	XSetForeground( XtDisplay(this_screen->area), gc, fg );
    149 	XSetBackground( XtDisplay(this_screen->area), gc, hi );
    150     }
    151     else if ( val & COLOR_SELECT ) {
    152 	XSetForeground( XtDisplay(this_screen->area), gc, fg );
    153 	XSetBackground( XtDisplay(this_screen->area), gc, shade );
    154     }
    155     else switch (val) {
    156 	case COLOR_STANDARD:
    157 	    XSetForeground( XtDisplay(this_screen->area), gc, fg );
    158 	    XSetBackground( XtDisplay(this_screen->area), gc, bg );
    159 	    break;
    160 	case COLOR_INVERSE:
    161 	    XSetForeground( XtDisplay(this_screen->area), gc, bg );
    162 	    XSetBackground( XtDisplay(this_screen->area), gc, fg );
    163 	    break;
    164 	default:	/* implement color map later */
    165 	    break;
    166     }
    167 }
    168 
    169 
    170 /*
    172  * Memory utilities
    173  */
    174 
    175 #ifdef REALLOC
    176 #undef REALLOC
    177 #endif
    178 
    179 #define REALLOC( ptr, size )	\
    180 	((ptr == NULL) ? malloc(size) : realloc(ptr,size))
    181 
    182 
    183 /* X windows routines.
    185  * We currently create a single, top-level shell.  In that is a
    186  * single drawing area into which we will draw text.  This allows
    187  * us to put multi-color (and font, but we'll never build that) text
    188  * into the drawing area.  In the future, we'll add scrollbars to the
    189  * drawing areas
    190  */
    191 
    192 void	select_start();
    193 void	select_extend();
    194 void	select_paste();
    195 void	key_press();
    196 void	insert_string();
    197 void	beep __P((Widget w));
    198 void	find();
    199 void	command();
    200 
    201 static XtActionsRec	area_actions[] = {
    202     { "select_start",	select_start	},
    203     { "select_extend",	select_extend	},
    204     { "select_paste",	select_paste	},
    205     { "key_press",	key_press	},
    206     { "insert_string",	insert_string	},
    207     { "beep",		beep		},
    208     { "find",		find		},
    209     { "command",	command		},
    210 };
    211 
    212 char	areaTrans[] =
    213     "<Btn1Down>:	select_start()		\n\
    214      <Btn1Motion>:	select_extend()		\n\
    215      <Btn2Down>:	select_paste()		\n\
    216      <Btn3Down>:	select_extend()		\n\
    217      <Btn3Motion>:	select_extend()		\n\
    218      <Key>End:		command(VI_C_BOTTOM)	\n\
    219      <Key>Escape:	command(EINSERT)	\n\
    220      <Key>Find:		find()			\n\
    221      <Key>Home:		command(VI_C_TOP)	\n\
    222      <Key>Next:		command(VI_C_PGDOWN)	\n\
    223      <Key>Prior:	command(VI_C_PGUP)	\n\
    224      <Key>osfBackSpace:	command(VI_C_LEFT)	\n\
    225      <Key>osfBeginLine:	command(VI_C_BOL)	\n\
    226      <Key>osfCopy:	beep()			\n\
    227      <Key>osfCut:	beep()			\n\
    228      <Key>osfDelete:	command(VI_C_DEL)	\n\
    229      <Key>osfDown:	command(VI_C_DOWN)	\n\
    230      <Key>osfEndLine:	command(VI_C_EOL)	\n\
    231      <Key>osfInsert:	command(VI_C_INSERT)	\n\
    232      <Key>osfLeft:	command(VI_C_LEFT)	\n\
    233      <Key>osfPageDown:	command(VI_C_PGDOWN)	\n\
    234      <Key>osfPageUp:	command(VI_C_PGUP)	\n\
    235      <Key>osfPaste:	insert_string(p)	\n\
    236      <Key>osfRight:	command(VI_C_RIGHT)	\n\
    237      <Key>osfUndo:	command(VI_UNDO)	\n\
    238      <Key>osfUp:	command(VI_C_UP)	\n\
    239      Ctrl<Key>C:	command(VI_INTERRUPT)	\n\
    240      <Key>:		key_press()";
    241 
    242 
    243 static  XutResource resource[] = {
    244     { "font",		XutRKfont,	&font		},
    245     { "pointerShape",	XutRKcursor,	&std_cursor	},
    246     { "busyShape",	XutRKcursor,	&busy_cursor	},
    247 };
    248 
    249 
    250 /*
    251  * vi_input_func --
    252  *	We've received input on the pipe from vi.
    253  *
    254  * PUBLIC: void vi_input_func __P((XtPointer, int *, XtInputId *));
    255  */
    256 void
    257 vi_input_func(XtPointer client_data, int *source, XtInputId *id)
    258 {
    259 	/* Parse and dispatch on commands in the queue. */
    260 	(void)ipvi_motif->input(ipvi_motif, *source);
    261 
    262 #ifdef notdef
    263 	/* Check the pipe for unused events when not busy. */
    264 	XtAppAddWorkProc(ctx, process_pipe_input, NULL);
    265 #endif
    266 }
    267 
    268 
    269 
    270 /* Send the window size. */
    272 #if defined(__STDC__)
    273 static	void	send_resize( xvi_screen *this_screen )
    274 #else
    275 static	void	send_resize( this_screen )
    276 xvi_screen	*this_screen;
    277 #endif
    278 {
    279     IP_BUF	ipb;
    280 
    281     ipb.val1 = this_screen->rows;
    282     ipb.val2 = this_screen->cols;
    283     ipb.code = VI_RESIZE;
    284 
    285 #ifdef TRACE
    286     vtrace("resize_func ( %d x %d )\n", this_screen->rows, this_screen->cols);
    287 #endif
    288 
    289     /* send up the pipe */
    290     vi_send(vi_ofd, "12", &ipb);
    291 }
    292 
    293 
    294 #if defined(__STDC__)
    296 static	void	resize_backing_store( xvi_screen *this_screen )
    297 #else
    298 static	void	resize_backing_store( this_screen )
    299 xvi_screen	*this_screen;
    300 #endif
    301 {
    302     int	total_chars = this_screen->rows * this_screen->cols;
    303 
    304     this_screen->characters	= REALLOC( this_screen->characters,
    305 					   total_chars
    306 					   );
    307     memset( this_screen->characters, ' ', total_chars );
    308 
    309     this_screen->flags		= REALLOC( this_screen->flags,
    310 					   total_chars
    311 					   );
    312     memset( this_screen->flags, 0, total_chars );
    313 }
    314 
    315 
    316 
    317 /* X will call this when we are resized */
    319 #if defined(__STDC__)
    320 static	void	resize_func( Widget wid,
    321 			     XtPointer client_data,
    322 			     XtPointer call_data
    323 			     )
    324 #else
    325 static	void	resize_func( wid, client_data, call_data )
    326 Widget		wid;
    327 XtPointer	client_data;
    328 XtPointer	call_data;
    329 #endif
    330 {
    331     xvi_screen			*this_screen = (xvi_screen *) client_data;
    332     Dimension			height, width;
    333 
    334     XtVaGetValues( wid, XmNheight, &height, XmNwidth, &width, 0 );
    335 
    336     /* generate correct sizes when we have font metrics implemented */
    337     this_screen->cols = width / this_screen->ch_width;
    338     this_screen->rows = height / this_screen->ch_height;
    339 
    340     resize_backing_store( this_screen );
    341     send_resize( this_screen );
    342 }
    343 
    344 
    345 /*
    346  * __vi_draw_text --
    347  *	Draw from backing store.
    348  *
    349  * PUBLIC: void	__vi_draw_text __P((xvi_screen *, int, int, int));
    350  */
    351 void
    352 __vi_draw_text(xvi_screen *this_screen, int row, int start_col, int len)
    353 {
    354     int		col, color, xpos;
    355     char	*start, *end;
    356 
    357     start = CharAt( __vi_screen, row, start_col );
    358     color = *FlagAt( __vi_screen, row, start_col );
    359     xpos  = XPOS( __vi_screen, start_col );
    360 
    361     /* one column at a time */
    362     for ( col=start_col;
    363 	  col<this_screen->cols && col<start_col+len;
    364 	  col++ ) {
    365 
    366 	/* has the color changed? */
    367 	if ( *FlagAt( __vi_screen, row, col ) == color )
    368 	    continue;
    369 
    370 	/* is there anything to write? */
    371 	end  = CharAt( __vi_screen, row, col );
    372 	if ( end == start )
    373 	    continue;
    374 
    375 	/* yes. write in the previous color */
    376 	set_gc_colors( __vi_screen, color );
    377 
    378 	/* add to display */
    379 	XDrawImageString( XtDisplay(__vi_screen->area),
    380 			  XtWindow(__vi_screen->area),
    381 			  gc,
    382 			  xpos,
    383 			  YPOS( __vi_screen, row ),
    384 			  start,
    385 			  end - start
    386 			  );
    387 
    388 	/* this is the new context */
    389 	color = *FlagAt( __vi_screen, row, col );
    390 	xpos  = XPOS( __vi_screen, col );
    391 	start = end;
    392     }
    393 
    394     /* is there anything to write? */
    395     end = CharAt( __vi_screen, row, col );
    396     if ( end != start ) {
    397 	/* yes. write in the previous color */
    398 	set_gc_colors( __vi_screen, color );
    399 
    400 	/* add to display */
    401 	XDrawImageString( XtDisplay(__vi_screen->area),
    402 			  XtWindow(__vi_screen->area),
    403 			  gc,
    404 			  xpos,
    405 			  YPOS( __vi_screen, row ),
    406 			  start,
    407 			  end - start
    408 			  );
    409     }
    410 }
    411 
    412 
    413 /* set clipping rectangles accordingly */
    415 #if defined(__STDC__)
    416 static	void	add_to_clip( xvi_screen *cur_screen, int x, int y, int width, int height )
    417 #else
    418 static	void	add_to_clip( cur_screen, x, y, width, height )
    419 	xvi_screen *cur_screen;
    420 	int	x;
    421 	int	y;
    422 	int	width;
    423 	int	height;
    424 #endif
    425 {
    426     XRectangle	rect;
    427     rect.x	= x;
    428     rect.y	= y;
    429     rect.height	= height;
    430     rect.width	= width;
    431     if ( cur_screen->clip == NULL )
    432 	cur_screen->clip = XCreateRegion();
    433     XUnionRectWithRegion( &rect, cur_screen->clip, cur_screen->clip );
    434 }
    435 
    436 
    437 /*
    439  * __vi_expose_func --
    440  *	Redraw the window's contents.
    441  *
    442  * NOTE: When vi wants to force a redraw, we are called with NULL widget
    443  *	 and call_data.
    444  *
    445  * PUBLIC: void	__vi_expose_func __P((Widget, XtPointer, XtPointer));
    446  */
    447 void
    448 __vi_expose_func(Widget wid, XtPointer client_data, XtPointer call_data)
    449 {
    450     xvi_screen			*this_screen;
    451     XmDrawingAreaCallbackStruct	*cbs;
    452     XExposeEvent		*xev;
    453     XGraphicsExposeEvent	*gev;
    454     int				row;
    455 
    456     /* convert pointers */
    457     this_screen = (xvi_screen *) client_data;
    458     cbs		= (XmDrawingAreaCallbackStruct *) call_data;
    459 
    460     /* first exposure? tell vi we are ready... */
    461     if ( this_screen->init == False ) {
    462 
    463 	/* what does the user want to see? */
    464 	__vi_set_cursor( __vi_screen, False );
    465 
    466 	/* vi wants a resize as the first event */
    467 	send_resize( __vi_screen );
    468 
    469 	/* fine for now.  we'll be back */
    470 	this_screen->init = True;
    471 	return;
    472     }
    473 
    474     if ( call_data == NULL ) {
    475 
    476 	/* vi core calls this when it wants a full refresh */
    477 #ifdef TRACE
    478 	vtrace("expose_func:  full refresh\n");
    479 #endif
    480 
    481 	XClearWindow( XtDisplay(this_screen->area),
    482 		      XtWindow(this_screen->area)
    483 		      );
    484     }
    485     else {
    486 	switch ( cbs->event->type ) {
    487 
    488 	    case GraphicsExpose:
    489 		gev = (XGraphicsExposeEvent *) cbs->event;
    490 
    491 		/* set clipping rectangles accordingly */
    492 		add_to_clip( this_screen,
    493 			     gev->x, gev->y,
    494 			     gev->width, gev->height
    495 			     );
    496 
    497 		/* X calls here when XCopyArea exposes new bits */
    498 #ifdef TRACE
    499 		vtrace("expose_func (X):  (x=%d,y=%d,w=%d,h=%d), count=%d\n",
    500 			     gev->x, gev->y,
    501 			     gev->width, gev->height,
    502 			     gev->count);
    503 #endif
    504 
    505 		/* more coming?  do it then */
    506 		if ( gev->count > 0 ) return;
    507 
    508 		/* set clipping region */
    509 		XSetRegion( XtDisplay(wid), gc, this_screen->clip );
    510 		break;
    511 
    512 	    case Expose:
    513 		xev = (XExposeEvent *) cbs->event;
    514 
    515 		/* set clipping rectangles accordingly */
    516 		add_to_clip( this_screen,
    517 			     xev->x, xev->y,
    518 			     xev->width, xev->height
    519 			     );
    520 
    521 		/* Motif calls here when DrawingArea is exposed */
    522 #ifdef TRACE
    523 		vtrace("expose_func (Motif): (x=%d,y=%d,w=%d,h=%d), count=%d\n",
    524 			     xev->x, xev->y,
    525 			     xev->width, xev->height,
    526 			     xev->count);
    527 #endif
    528 
    529 		/* more coming?  do it then */
    530 		if ( xev->count > 0 ) return;
    531 
    532 		/* set clipping region */
    533 		XSetRegion( XtDisplay(wid), gc, this_screen->clip );
    534 		break;
    535 
    536 	    default:
    537 		/* don't care? */
    538 		return;
    539 	}
    540     }
    541 
    542     /* one row at a time */
    543     for (row=0; row<this_screen->rows; row++) {
    544 
    545 	/* draw from the backing store */
    546 	__vi_draw_text( this_screen, row, 0, this_screen->cols );
    547     }
    548 
    549     /* clear clipping region */
    550     XSetClipMask( XtDisplay(this_screen->area), gc, None );
    551     if ( this_screen->clip != NULL ) {
    552 	XDestroyRegion( this_screen->clip );
    553 	this_screen->clip = NULL;
    554     }
    555 
    556 }
    557 
    558 
    559 #if defined(__STDC__)
    561 static void	xexpose	( Widget w,
    562 			  XtPointer client_data,
    563 			  XEvent *ev,
    564 			  Boolean *cont
    565 			  )
    566 #else
    567 static void	xexpose	( w, client_data, ev, cont )
    568 Widget		w;
    569 XtPointer	client_data;
    570 XEvent		*ev;
    571 Boolean		*cont;
    572 #endif
    573 {
    574     XmDrawingAreaCallbackStruct	cbs;
    575 
    576     switch ( ev->type ) {
    577 	case GraphicsExpose:
    578 	    cbs.event	= ev;
    579 	    cbs.window	= XtWindow(w);
    580 	    cbs.reason	= XmCR_EXPOSE;
    581 	    __vi_expose_func( w, client_data, (XtPointer) &cbs );
    582 	    *cont	= False;	/* we took care of it */
    583 	    break;
    584 	default:
    585 	    /* don't care */
    586 	    break;
    587     }
    588 }
    589 
    590 
    591 /* unimplemented keystroke or command */
    592 #if defined(__STDC__)
    593 static void	beep( Widget w )
    594 #else
    595 static void	beep( w )
    596 Widget	w;
    597 #endif
    598 {
    599     XBell(XtDisplay(w),0);
    600 }
    601 
    602 
    603 /* give me a search dialog */
    604 #if defined(__STDC__)
    605 static void	find( Widget w )
    606 #else
    607 static void	find( w )
    608 Widget	w;
    609 #endif
    610 {
    611     __vi_show_search_dialog( w, "Find" );
    612 }
    613 
    614 /*
    615  * command --
    616  *	Translate simple keyboard input into vi protocol commands.
    617  */
    618 static	void
    619 command(Widget widget, XKeyEvent *event, String *str, Cardinal *cardinal)
    620 {
    621 	static struct {
    622 		String	name;
    623 		int	code;
    624 		int	count;
    625 	} table[] = {
    626 		{ "VI_C_BOL",		VI_C_BOL,	0 },
    627 		{ "VI_C_BOTTOM",	VI_C_BOTTOM,	0 },
    628 		{ "VI_C_DEL",		VI_C_DEL,	0 },
    629 		{ "VI_C_DOWN",		VI_C_DOWN,	1 },
    630 		{ "VI_C_EOL",		VI_C_EOL,	0 },
    631 		{ "VI_C_INSERT",	VI_C_INSERT,	0 },
    632 		{ "VI_C_LEFT",		VI_C_LEFT,	0 },
    633 		{ "VI_C_PGDOWN",	VI_C_PGDOWN,	1 },
    634 		{ "VI_C_PGUP",		VI_C_PGUP,	1 },
    635 		{ "VI_C_RIGHT",		VI_C_RIGHT,	0 },
    636 		{ "VI_C_TOP",		VI_C_TOP,	0 },
    637 		{ "VI_C_UP",		VI_C_UP,	1 },
    638 		{ "VI_INTERRUPT",	VI_INTERRUPT,	0 },
    639 	};
    640 	IP_BUF ipb;
    641 	int i;
    642 
    643 	/*
    644 	 * XXX
    645 	 * Do fast lookup based on character #6 -- sleazy, but I don't
    646 	 * want to do 10 strcmp's per keystroke.
    647 	 */
    648 	ipb.val1 = 1;
    649 	for (i = 0; i < XtNumber(table); i++)
    650 		if (table[i].name[6] == (*str)[6] &&
    651 		    strcmp(table[i].name, *str) == 0) {
    652 			ipb.code = table[i].code;
    653 			vi_send(vi_ofd, table[i].count ? "1" : NULL, &ipb);
    654 			return;
    655 		}
    656 
    657 	/* oops. */
    658 	beep(widget);
    659 }
    660 
    661 /* mouse or keyboard input. */
    662 #if defined(__STDC__)
    663 static	void	insert_string( Widget widget,
    664 			       XKeyEvent *event,
    665 			       String *str,
    666 			       Cardinal *cardinal
    667 			       )
    668 #else
    669 static	void	insert_string( widget, event, str, cardinal )
    670 Widget          widget;
    671 XKeyEvent       *event;
    672 String          *str;
    673 Cardinal        *cardinal;
    674 #endif
    675 {
    676     IP_BUF	ipb;
    677 
    678     ipb.len1 = strlen( *str );
    679     if ( ipb.len1 != 0 ) {
    680 	ipb.code = VI_STRING;
    681 	ipb.str1 = *str;
    682 	vi_send(vi_ofd, "a", &ipb);
    683     }
    684 
    685 #ifdef TRACE
    686     vtrace("insert_string {%.*s}\n", strlen( *str ), *str );
    687 #endif
    688 }
    689 
    690 
    691 /* mouse or keyboard input. */
    692 #if defined(__STDC__)
    693 static	void	key_press( Widget widget,
    694 			   XKeyEvent *event,
    695 			   String str,
    696 			   Cardinal *cardinal
    697 			   )
    698 #else
    699 static	void	key_press( widget, event, str, cardinal )
    700 Widget          widget;
    701 XKeyEvent       *event;
    702 String          str;
    703 Cardinal        *cardinal;
    704 #endif
    705 {
    706     IP_BUF	ipb;
    707     char	bp[BufferSize];
    708 
    709     ipb.len1 = XLookupString( event, bp, BufferSize, NULL, NULL );
    710     if ( ipb.len1 != 0 ) {
    711 	ipb.code = VI_STRING;
    712 	ipb.str1 = bp;
    713 #ifdef TRACE
    714 	vtrace("key_press {%.*s}\n", ipb.len1, bp );
    715 #endif
    716 	vi_send(vi_ofd, "a", &ipb);
    717     }
    718 
    719 }
    720 
    721 
    722 #if defined(__STDC__)
    723 static	void	scrollbar_moved( Widget widget,
    724 				 XtPointer ptr,
    725 				 XmScrollBarCallbackStruct *cbs
    726 				 )
    727 #else
    728 static	void				scrollbar_moved( widget, ptr, cbs )
    729 	Widget				widget;
    730 	XtPointer			ptr;
    731 	XmScrollBarCallbackStruct	*cbs;
    732 #endif
    733 {
    734     /* Future:  Need to scroll the correct screen! */
    735     xvi_screen	*cur_screen = (xvi_screen *) ptr;
    736     IP_BUF	ipb;
    737 
    738     /* if we are still processing messages from core, skip this event
    739      * (see comments near __vi_set_scroll_block())
    740      */
    741     if ( scroll_block ) {
    742 	return;
    743     }
    744     __vi_set_scroll_block();
    745 
    746 #ifdef TRACE
    747     switch ( cbs->reason ) {
    748 	case XmCR_VALUE_CHANGED:
    749 	    vtrace( "scrollbar VALUE_CHANGED %d\n", cbs->value );
    750 	    break;
    751 	case XmCR_DRAG:
    752 	    vtrace( "scrollbar DRAG %d\n", cbs->value );
    753 	    break;
    754 	default:
    755 	    vtrace( "scrollbar <default> %d\n", cbs->value );
    756 	    break;
    757     }
    758     vtrace("scrollto {%d}\n", cbs->value );
    759 #endif
    760 
    761     /* Send the new cursor position. */
    762     ipb.code = VI_C_SETTOP;
    763     ipb.val1 = cbs->value;
    764     (void)vi_send(vi_ofd, "1", &ipb);
    765 }
    766 
    767 
    768 #if defined(__STDC__)
    769 static	xvi_screen	*create_screen( Widget parent, int rows, int cols )
    770 #else
    771 static	xvi_screen	*create_screen( parent, rows, cols )
    772 	Widget		parent;
    773 	int		rows, cols;
    774 #endif
    775 {
    776     xvi_screen	*new_screen = (xvi_screen *) calloc( 1, sizeof(xvi_screen) );
    777     Widget	frame;
    778 
    779     /* init... */
    780     new_screen->color		= COLOR_STANDARD;
    781     new_screen->parent		= parent;
    782 
    783     /* figure out the sizes */
    784     new_screen->rows		= rows;
    785     new_screen->cols		= cols;
    786     new_screen->ch_width	= font->max_bounds.width;
    787     new_screen->ch_height	= font->descent + font->ascent;
    788     new_screen->ch_descent	= font->descent;
    789     new_screen->clip		= NULL;
    790 
    791     /* allocate and init the backing stores */
    792     resize_backing_store( new_screen );
    793 
    794     /* set up a translation table for the X toolkit */
    795     if ( area_trans == NULL )
    796 	area_trans = XtParseTranslationTable(areaTrans);
    797 
    798     /* future, new screen gets inserted into the parent sash
    799      * immediately after the current screen.  Default Pane action is
    800      * to add it to the end
    801      */
    802 
    803     /* use a form to hold the drawing area and the scrollbar */
    804     new_screen->form = XtVaCreateManagedWidget( "form",
    805 	    xmFormWidgetClass,
    806 	    parent,
    807 	    XmNpaneMinimum,		2*new_screen->ch_height,
    808 	    XmNallowResize,		True,
    809 	    NULL
    810 	    );
    811 
    812     /* create a scrollbar. */
    813     new_screen->scroll = XtVaCreateManagedWidget( "scroll",
    814 	    xmScrollBarWidgetClass,
    815 	    new_screen->form,
    816 	    XmNtopAttachment,		XmATTACH_FORM,
    817 	    XmNbottomAttachment,	XmATTACH_FORM,
    818 	    XmNrightAttachment,		XmATTACH_FORM,
    819 	    XmNminimum,			1,
    820 	    XmNmaximum,			2,
    821 	    XmNsliderSize,		1,
    822 	    NULL
    823 	    );
    824     XtAddCallback( new_screen->scroll,
    825 		   XmNvalueChangedCallback,
    826 		   scrollbar_moved,
    827 		   new_screen
    828 		   );
    829     XtAddCallback( new_screen->scroll,
    830 		   XmNdragCallback,
    831 		   scrollbar_moved,
    832 		   new_screen
    833 		   );
    834 
    835     /* create a frame because they look nice */
    836     frame = XtVaCreateManagedWidget( "frame",
    837 	    xmFrameWidgetClass,
    838 	    new_screen->form,
    839 	    XmNshadowType,		XmSHADOW_ETCHED_IN,
    840 	    XmNtopAttachment,		XmATTACH_FORM,
    841 	    XmNbottomAttachment,	XmATTACH_FORM,
    842 	    XmNleftAttachment,		XmATTACH_FORM,
    843 	    XmNrightAttachment,		XmATTACH_WIDGET,
    844 	    XmNrightWidget,		new_screen->scroll,
    845 	    NULL
    846 	    );
    847 
    848     /* create a drawing area into which we will put text */
    849     new_screen->area = XtVaCreateManagedWidget( "screen",
    850 	    xmDrawingAreaWidgetClass,
    851 	    frame,
    852 	    XmNheight,		new_screen->ch_height * new_screen->rows,
    853 	    XmNwidth,		new_screen->ch_width * new_screen->cols,
    854 	    XmNtranslations,	area_trans,
    855 	    XmNuserData,	new_screen,
    856 	    XmNnavigationType,	XmNONE,
    857 	    XmNtraversalOn,	False,
    858 	    NULL
    859 	    );
    860 
    861     /* this callback is for when the drawing area is resized */
    862     XtAddCallback( new_screen->area,
    863 		   XmNresizeCallback,
    864 		   resize_func,
    865 		   new_screen
    866 		   );
    867 
    868     /* this callback is for when the drawing area is exposed */
    869     XtAddCallback( new_screen->area,
    870 		   XmNexposeCallback,
    871 		   __vi_expose_func,
    872 		   new_screen
    873 		   );
    874 
    875     /* this callback is for when we expose obscured bits
    876      * (e.g. there is a window over part of our drawing area
    877      */
    878     XtAddEventHandler( new_screen->area,
    879 		       0,	/* no standard events */
    880 		       True,	/* we *WANT* GraphicsExpose */
    881 		       xexpose,	/* what to do */
    882 		       new_screen
    883 		       );
    884 
    885     return new_screen;
    886 }
    887 
    888 
    889 static	xvi_screen	*split_screen(void)
    890 {
    891     Cardinal	num;
    892     WidgetList	c;
    893     int		rows = __vi_screen->rows / 2;
    894     xvi_screen	*new_screen;
    895 
    896     /* Note that (global) cur_screen needs to be correctly set so that
    897      * insert_here knows which screen to put the new one after
    898      */
    899     new_screen = create_screen( __vi_screen->parent,
    900 				rows,
    901 				__vi_screen->cols
    902 				);
    903 
    904     /* what are the screens? */
    905     XtVaGetValues( __vi_screen->parent,
    906 		   XmNnumChildren,	&num,
    907 		   XmNchildren,		&c,
    908 		   NULL
    909 		   );
    910 
    911     /* unmanage all children in preparation for resizing */
    912     XtUnmanageChildren( c, num );
    913 
    914     /* force resize of the affected screens */
    915     XtVaSetValues( new_screen->form,
    916 		   XmNheight,	new_screen->ch_height * rows,
    917 		   NULL
    918 		   );
    919     XtVaSetValues( __vi_screen->form,
    920 		   XmNheight,	__vi_screen->ch_height * rows,
    921 		   NULL
    922 		   );
    923 
    924     /* re-manage */
    925     XtManageChildren( c, num );
    926 
    927     /* done */
    928     return new_screen;
    929 }
    930 
    931 
    932 /* Tell me where to insert the next subpane */
    934 #if defined(__STDC__)
    935 static	Cardinal	insert_here( Widget wid )
    936 #else
    937 static	Cardinal	insert_here( wid )
    938 	Widget		wid;
    939 #endif
    940 {
    941     Cardinal	i, num;
    942     WidgetList	c;
    943 
    944     XtVaGetValues( XtParent(wid),
    945 		   XmNnumChildren,	&num,
    946 		   XmNchildren,		&c,
    947 		   NULL
    948 		   );
    949 
    950     /* The  default  XmNinsertPosition  procedure  for  PanedWindow
    951      * causes sashes to be inserted at the end of the list of children
    952      * and causes non-sash widgets to be inserted after  other
    953      * non-sash children but before any sashes.
    954      */
    955     if ( ! XmIsForm( wid ) )
    956 	return num;
    957 
    958     /* We will put the widget after the one with the current screen */
    959     for (i=0; i<num && XmIsForm(c[i]); i++) {
    960 	if ( __vi_screen == NULL || __vi_screen->form == c[i] )
    961 	    return i+1;	/* after the i-th */
    962     }
    963 
    964     /* could not find it?  this should never happen */
    965     return num;
    966 }
    967 
    968 
    969 /*
    970  * vi_create_editor --
    971  *	Create the necessary widgetry.
    972  *
    973  * PUBLIC: Widget vi_create_editor __P((String, Widget, void (*)(void)));
    974  */
    975 Widget
    976 vi_create_editor(String name, Widget parent, void (*exitp) (void))
    977 {
    978     Widget	pane_w;
    979     Display	*display = XtDisplay( parent );
    980 
    981     __vi_exitp = exitp;
    982 
    983     /* first time through? */
    984     if ( ctx == NULL ) {
    985 
    986 	/* save this for later */
    987 	ctx = XtWidgetToApplicationContext( parent );
    988 
    989 	/* add our own special actions */
    990 	XtAppAddActions( ctx, area_actions, XtNumber(area_actions) );
    991 
    992 	/* how long is double-click? */
    993 	multi_click_length = XtGetMultiClickTime( display );
    994 
    995 	/* check the resource database for interesting resources */
    996 	__XutConvertResources( parent,
    997 			     vi_progname,
    998 			     resource,
    999 			     XtNumber(resource)
   1000 			     );
   1001 
   1002 	/* we need a context for moving bits around in the windows */
   1003 	__vi_copy_gc = XCreateGC( display,
   1004 				 DefaultRootWindow(display),
   1005 				 0,
   1006 				 0
   1007 				 );
   1008 
   1009 	/* routines for inter client communications conventions */
   1010 	__vi_InitCopyPaste( f_copy, f_paste, f_clear, fprintf );
   1011     }
   1012 
   1013     /* create the paned window */
   1014     pane_w = XtVaCreateManagedWidget( "pane",
   1015 				      xmPanedWindowWidgetClass,
   1016 				      parent,
   1017 				      XmNinsertPosition,	insert_here,
   1018 				      NULL
   1019 				      );
   1020 
   1021     /* allocate our data structure.  in the future we will have several
   1022      * screens running around at the same time
   1023      */
   1024     __vi_screen = create_screen( pane_w, 24, 80 );
   1025 
   1026     /* force creation of our color text context */
   1027     set_gc_colors( __vi_screen, COLOR_STANDARD );
   1028 
   1029     /* done */
   1030     return pane_w;
   1031 }
   1032 
   1033 
   1034 /* These routines deal with the selection buffer */
   1036 
   1037 static	int	selection_start, selection_end, selection_anchor;
   1038 static	enum	select_enum {
   1039 	    select_char, select_word, select_line
   1040 	}	select_type = select_char;
   1041 static	int	last_click;
   1042 
   1043 static	char	*clipboard = NULL;
   1044 static	int	clipboard_size = 0,
   1045 		clipboard_length;
   1046 
   1047 
   1048 #if defined(__STDC__)
   1049 static	void	copy_to_clipboard( xvi_screen *cur_screen )
   1050 #else
   1051 static	void	copy_to_clipboard( cur_screen )
   1052 xvi_screen	*cur_screen;
   1053 #endif
   1054 {
   1055     /* for now, copy from the backing store.  in the future,
   1056      * vi core will tell us exactly what the selection buffer contains
   1057      */
   1058     clipboard_length = 1 + selection_end - selection_start;
   1059 
   1060     if ( clipboard == NULL )
   1061 	clipboard = (char *) malloc( clipboard_length );
   1062     else if ( clipboard_size < clipboard_length )
   1063 	clipboard = (char *) realloc( clipboard, clipboard_length );
   1064 
   1065     memcpy( clipboard,
   1066 	    cur_screen->characters + selection_start,
   1067 	    clipboard_length
   1068 	    );
   1069 }
   1070 
   1071 
   1072 #if defined(__STDC__)
   1073 static	void	mark_selection( xvi_screen *cur_screen, int start, int end )
   1074 #else
   1075 static	void	mark_selection( cur_screen, start, end )
   1076 xvi_screen	*cur_screen;
   1077 int		start;
   1078 int		end;
   1079 #endif
   1080 {
   1081     int	row, col, i;
   1082 
   1083     for ( i=start; i<=end; i++ ) {
   1084 	if ( !( cur_screen->flags[i] & COLOR_SELECT ) ) {
   1085 	    cur_screen->flags[i] |= COLOR_SELECT;
   1086 	    ToRowCol( cur_screen, i, row, col );
   1087 	    __vi_draw_text( cur_screen, row, col, 1 );
   1088 	}
   1089     }
   1090 }
   1091 
   1092 
   1093 #if defined(__STDC__)
   1094 static	void	erase_selection( xvi_screen *cur_screen, int start, int end )
   1095 #else
   1096 static	void	erase_selection( cur_screen, start, end )
   1097 xvi_screen	*cur_screen;
   1098 int		start;
   1099 int		end;
   1100 #endif
   1101 {
   1102     int	row, col, i;
   1103 
   1104     for ( i=start; i<=end; i++ ) {
   1105 	if ( cur_screen->flags[i] & COLOR_SELECT ) {
   1106 	    cur_screen->flags[i] &= ~COLOR_SELECT;
   1107 	    ToRowCol( cur_screen, i, row, col );
   1108 	    __vi_draw_text( cur_screen, row, col, 1 );
   1109 	}
   1110     }
   1111 }
   1112 
   1113 
   1114 #if defined(__STDC__)
   1115 static	void	left_expand_selection( xvi_screen *cur_screen, int *start )
   1116 #else
   1117 static	void	left_expand_selection( cur_screen, start )
   1118 xvi_screen	*cur_screen;
   1119 int		*start;
   1120 #endif
   1121 {
   1122     int row, col;
   1123 
   1124     switch ( select_type ) {
   1125 	case select_word:
   1126 	    if ( *start == 0 || isspace( (unsigned char)cur_screen->characters[*start] ) )
   1127 		return;
   1128 	    for (;;) {
   1129 		if ( isspace( (unsigned char)cur_screen->characters[*start-1] ) )
   1130 		    return;
   1131 		if ( --(*start) == 0 )
   1132 		   return;
   1133 	    }
   1134 	case select_line:
   1135 	    ToRowCol( cur_screen, *start, row, col );
   1136 	    col = 0;
   1137 	    *start = Linear( cur_screen, row, col );
   1138 	    break;
   1139     }
   1140 }
   1141 
   1142 
   1143 #if defined(__STDC__)
   1144 static	void	right_expand_selection( xvi_screen *cur_screen, int *end )
   1145 #else
   1146 static	void	right_expand_selection( cur_screen, end )
   1147 xvi_screen	*cur_screen;
   1148 int		*end;
   1149 #endif
   1150 {
   1151     int row, col, last = cur_screen->cols * cur_screen->rows - 1;
   1152 
   1153     switch ( select_type ) {
   1154 	case select_word:
   1155 	    if ( *end == last || isspace( (unsigned char)cur_screen->characters[*end] ) )
   1156 		return;
   1157 	    for (;;) {
   1158 		if ( isspace( (unsigned char)cur_screen->characters[*end+1] ) )
   1159 		    return;
   1160 		if ( ++(*end) == last )
   1161 		   return;
   1162 	    }
   1163 	case select_line:
   1164 	    ToRowCol( cur_screen, *end, row, col );
   1165 	    col = cur_screen->cols -1;
   1166 	    *end = Linear( cur_screen, row, col );
   1167 	    break;
   1168     }
   1169 }
   1170 
   1171 
   1172 #if defined(__STDC__)
   1173 static	void	select_start( Widget widget,
   1174 			      XEvent *event,
   1175 			      String str,
   1176 			      Cardinal *cardinal
   1177 			      )
   1178 #else
   1179 static	void	select_start( widget, event, str, cardinal )
   1180 Widget		widget;
   1181 XEvent		*event;
   1182 String		str;
   1183 Cardinal        *cardinal;
   1184 #endif
   1185 {
   1186     IP_BUF		ipb;
   1187     int			xpos, ypos;
   1188     XPointerMovedEvent	*ev = (XPointerMovedEvent *) event;
   1189     static int		last_click;
   1190 
   1191     /*
   1192      * NOTE: when multiple panes are implemented, we need to find the correct
   1193      * screen.  For now, there is only one.
   1194      */
   1195     xpos = COLUMN( __vi_screen, ev->x );
   1196     ypos = ROW( __vi_screen, ev->y );
   1197 
   1198     /* Remove the old one. */
   1199     erase_selection( __vi_screen, selection_start, selection_end );
   1200 
   1201     /* Send the new cursor position. */
   1202     ipb.code = VI_MOUSE_MOVE;
   1203     ipb.val1 = ypos;
   1204     ipb.val2 = xpos;
   1205     (void)vi_send(vi_ofd, "12", &ipb);
   1206 
   1207     /* click-click, and we go for words, lines, etc */
   1208     if ( ev->time - last_click < multi_click_length )
   1209 	select_type = (enum select_enum) ((((int)select_type)+1)%3);
   1210     else
   1211 	select_type = select_char;
   1212     last_click = ev->time;
   1213 
   1214     /* put the selection here */
   1215     selection_anchor	= Linear( __vi_screen, ypos, xpos );
   1216     selection_start	= selection_anchor;
   1217     selection_end	= selection_anchor;
   1218 
   1219     /* expand to include words, line, etc */
   1220     left_expand_selection( __vi_screen, &selection_start );
   1221     right_expand_selection( __vi_screen, &selection_end );
   1222 
   1223     /* draw the new one */
   1224     mark_selection( __vi_screen, selection_start, selection_end );
   1225 
   1226     /* and tell the window manager we own the selection */
   1227     if ( select_type != select_char ) {
   1228 	__vi_AcquirePrimary( widget );
   1229 	copy_to_clipboard( __vi_screen );
   1230     }
   1231 }
   1232 
   1233 
   1234 #if defined(__STDC__)
   1235 static	void	select_extend( Widget widget,
   1236 			       XEvent *event,
   1237 			       String str,
   1238 			       Cardinal *cardinal
   1239 			       )
   1240 #else
   1241 static	void	select_extend( widget, event, str, cardinal )
   1242 Widget		widget;
   1243 XEvent		*event;
   1244 String		str;
   1245 Cardinal        *cardinal;
   1246 #endif
   1247 {
   1248     int			xpos, ypos, pos;
   1249     XPointerMovedEvent	*ev = (XPointerMovedEvent *) event;
   1250 
   1251     /* NOTE:  when multiple panes are implemented, we need to find
   1252      * the correct screen.  For now, there is only one.
   1253      */
   1254     xpos = COLUMN( __vi_screen, ev->x );
   1255     ypos = ROW( __vi_screen, ev->y );
   1256 
   1257     /* deal with words, lines, etc */
   1258     pos = Linear( __vi_screen, ypos, xpos );
   1259     if ( pos < selection_anchor )
   1260 	left_expand_selection( __vi_screen, &pos );
   1261     else
   1262 	right_expand_selection( __vi_screen, &pos );
   1263 
   1264     /* extend from before the start? */
   1265     if ( pos < selection_start ) {
   1266 	mark_selection( __vi_screen, pos, selection_start-1 );
   1267 	selection_start = pos;
   1268     }
   1269 
   1270     /* extend past the end? */
   1271     else if ( pos > selection_end ) {
   1272 	mark_selection( __vi_screen, selection_end+1, pos );
   1273 	selection_end = pos;
   1274     }
   1275 
   1276     /* between the anchor and the start? */
   1277     else if ( pos < selection_anchor ) {
   1278 	erase_selection( __vi_screen, selection_start, pos-1 );
   1279 	selection_start = pos;
   1280     }
   1281 
   1282     /* between the anchor and the end? */
   1283     else {
   1284 	erase_selection( __vi_screen, pos+1, selection_end );
   1285 	selection_end = pos;
   1286     }
   1287 
   1288     /* and tell the window manager we own the selection */
   1289     __vi_AcquirePrimary( widget );
   1290     copy_to_clipboard( __vi_screen );
   1291 }
   1292 
   1293 
   1294 #if defined(__STDC__)
   1295 static	void	select_paste( Widget widget,
   1296 			      XEvent *event,
   1297 			      String str,
   1298 			      Cardinal *cardinal
   1299 			      )
   1300 #else
   1301 static	void	select_paste( widget, event, str, cardinal )
   1302 Widget		widget;
   1303 XEvent		*event;
   1304 String		str;
   1305 Cardinal        *cardinal;
   1306 #endif
   1307 {
   1308     __vi_PasteFromClipboard( widget );
   1309 }
   1310 
   1311 
   1312 /* Interface to copy and paste
   1314  * (a) callbacks from the window manager
   1315  *	f_copy	-	it wants our buffer
   1316  *	f_paste	-	it wants us to paste some text
   1317  *	f_clear	-	we've lost the selection, clear it
   1318  */
   1319 
   1320 #if defined(__STDC__)
   1321 static	void	f_copy( String *buffer, int *len )
   1322 #else
   1323 static	void	f_copy( buffer, len )
   1324 	String	*buffer;
   1325 	int	*len;
   1326 #endif
   1327 {
   1328 #ifdef TRACE
   1329     vtrace("f_copy() called");
   1330 #endif
   1331     *buffer	= clipboard;
   1332     *len	= clipboard_length;
   1333 }
   1334 
   1335 
   1336 
   1337 static	void	f_paste(int widget, int buffer, int length)
   1338 {
   1339     /* NOTE:  when multiple panes are implemented, we need to find
   1340      * the correct screen.  For now, there is only one.
   1341      */
   1342 #ifdef TRACE
   1343     vtrace("f_paste() called with '%*.*s'\n", length, length, buffer);
   1344 #endif
   1345 }
   1346 
   1347 
   1348 #if defined(__STDC__)
   1349 static	void	f_clear( Widget widget )
   1350 #else
   1351 static	void	f_clear( widget )
   1352 Widget	widget;
   1353 #endif
   1354 {
   1355     xvi_screen	*cur_screen;
   1356 
   1357 #ifdef TRACE
   1358     vtrace("f_clear() called");
   1359 #endif
   1360 
   1361     XtVaGetValues( widget, XmNuserData, &cur_screen, 0 );
   1362 
   1363     erase_selection( cur_screen, selection_start, selection_end );
   1364 }
   1365 
   1366 
   1367 /*
   1369  * These routines deal with the cursor.
   1370  *
   1371  * PUBLIC: void __vi_set_cursor __P((xvi_screen *, int));
   1372  */
   1373 void
   1374 __vi_set_cursor(xvi_screen *cur_screen, int is_busy)
   1375 {
   1376     XDefineCursor( XtDisplay(cur_screen->area),
   1377 		   XtWindow(cur_screen->area),
   1378 		   (is_busy) ? busy_cursor : std_cursor
   1379 		   );
   1380 }
   1381 
   1382 
   1383 
   1384 /* hooks for the tags widget */
   1386 
   1387 static	String	cur_word = NULL;
   1388 
   1389 /*
   1390  * PUBLIC: void __vi_set_word_at_caret __P((xvi_screen *));
   1391  */
   1392 void
   1393 __vi_set_word_at_caret(xvi_screen *this_screen)
   1394 {
   1395     char	*start, *end, save;
   1396     int		newx, newy;
   1397 
   1398     newx = this_screen->curx;
   1399     newy = this_screen->cury;
   1400 
   1401     /* Note that this really ought to be done by core due to wrapping issues */
   1402     for ( end = start = CharAt( this_screen, newy, newx );
   1403 	  (isalnum( (unsigned char)*end ) || *end == '_') && (newx < this_screen->cols);
   1404 	  end++, newx++
   1405 	  );
   1406     save = *end;
   1407     *end = '\0';
   1408     if ( cur_word != NULL ) free( cur_word );
   1409     cur_word = strdup( start );
   1410     *end = save;
   1411 
   1412     /* if the tag stack widget is active, set the text field there
   1413      * to agree with the current caret position.
   1414      */
   1415     __vi_set_tag_text( cur_word );
   1416 }
   1417 
   1418 
   1419 String	__vi_get_word_at_caret(xvi_screen *this_screen)
   1420 {
   1421     return (cur_word) ? cur_word : "";
   1422 }
   1423 
   1424 
   1425 /*
   1427  * These routines deal with the caret.
   1428  *
   1429  * PUBLIC: void draw_caret __P((xvi_screen *));
   1430  */
   1431 static void
   1432 draw_caret(xvi_screen *this_screen)
   1433 {
   1434     /* draw the caret by drawing the text in highlight color */
   1435     *FlagAt( this_screen, this_screen->cury, this_screen->curx ) |= COLOR_CARET;
   1436     __vi_draw_text( this_screen, this_screen->cury, this_screen->curx, 1 );
   1437 }
   1438 
   1439 /*
   1440  * PUBLIC: void __vi_erase_caret __P((xvi_screen *));
   1441  */
   1442 void
   1443 __vi_erase_caret(xvi_screen *this_screen)
   1444 {
   1445     /* erase the caret by drawing the text in normal video */
   1446     *FlagAt( this_screen, this_screen->cury, this_screen->curx ) &= ~COLOR_CARET;
   1447     __vi_draw_text( this_screen, this_screen->cury, this_screen->curx, 1 );
   1448 }
   1449 
   1450 /*
   1451  * PUBLIC: void	__vi_move_caret __P((xvi_screen *, int, int));
   1452  */
   1453 void
   1454 __vi_move_caret(xvi_screen *this_screen, int newy, int newx)
   1455 {
   1456     /* remove the old caret */
   1457     __vi_erase_caret( this_screen );
   1458 
   1459     /* caret is now here */
   1460     this_screen->curx = newx;
   1461     this_screen->cury = newy;
   1462     draw_caret( this_screen );
   1463 }
   1464