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