vi_create_editor() is public
[nvi.git] / motif_l / m_vi.c
blobb636079d35622c4f7877af0f5b787d84887f5200
1 /*-
2 * Copyright (c) 1996
3 * Rob Zimmermann. All rights reserved.
4 * Copyright (c) 1996
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: m_vi.c,v 8.25 1996/12/11 13:35:01 bostic Exp $ (Berkeley) $Date: 1996/12/11 13:35:01 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
19 #include <X11/Intrinsic.h>
20 #include <X11/StringDefs.h>
21 #include <X11/cursorfont.h>
22 #include <Xm/PanedW.h>
23 #include <Xm/DrawingA.h>
24 #include <Xm/Form.h>
25 #include <Xm/Frame.h>
26 #include <Xm/ScrollBar.h>
28 #include <bitstring.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
38 #include "../common/common.h"
39 #include "../ip_vi/ip.h"
40 #include "ipc_motif.h"
41 #include "ipc_mutil.h"
42 #include "ipc_extern.h"
43 #include "ipc_mextern.h"
44 #include "pathnames.h"
46 static void f_copy();
47 static void f_paste();
48 static void f_clear();
52 * Globals and costants
55 #define BufferSize 1024
57 static XFontStruct *font;
58 static GC gc;
59 GC __vi_copy_gc;
60 static XtAppContext ctx;
62 xvi_screen *__vi_screen = NULL;
63 static Cursor std_cursor;
64 static Cursor busy_cursor;
65 static XtTranslations area_trans;
66 static int multi_click_length;
68 void (*__vi_exitp)(); /* Exit function. */
70 static char bp[ BufferSize ]; /* input buffer from pipe */
71 static size_t len, blen = sizeof(bp);
74 #if defined(__STDC__)
75 static void set_gc_colors( xvi_screen *this_screen, int val )
76 #else
77 static void set_gc_colors( this_screen, val )
78 xvi_screen *this_screen;
79 int val;
80 #endif
82 static Pixel fg, bg, hi, shade;
83 static int prev = COLOR_INVALID;
85 /* no change? */
86 if ( prev == val ) return;
88 /* init? */
89 if ( gc == NULL ) {
91 /* what colors are selected for the drawing area? */
92 XtVaGetValues( this_screen->area,
93 XtNbackground, &bg,
94 XtNforeground, &fg,
95 XmNhighlightColor, &hi,
96 XmNtopShadowColor, &shade,
100 gc = XCreateGC( XtDisplay(this_screen->area),
101 DefaultRootWindow(XtDisplay(this_screen->area)),
106 XSetFont( XtDisplay(this_screen->area), gc, font->fid );
109 /* special colors? */
110 if ( val & COLOR_CARET ) {
111 XSetForeground( XtDisplay(this_screen->area), gc, fg );
112 XSetBackground( XtDisplay(this_screen->area), gc, hi );
114 else if ( val & COLOR_SELECT ) {
115 XSetForeground( XtDisplay(this_screen->area), gc, fg );
116 XSetBackground( XtDisplay(this_screen->area), gc, shade );
118 else switch (val) {
119 case COLOR_STANDARD:
120 XSetForeground( XtDisplay(this_screen->area), gc, fg );
121 XSetBackground( XtDisplay(this_screen->area), gc, bg );
122 break;
123 case COLOR_INVERSE:
124 XSetForeground( XtDisplay(this_screen->area), gc, bg );
125 XSetBackground( XtDisplay(this_screen->area), gc, fg );
126 break;
127 default: /* implement color map later */
128 break;
134 * Memory utilities
137 #ifdef REALLOC
138 #undef REALLOC
139 #endif
141 #define REALLOC( ptr, size ) \
142 ((ptr == NULL) ? malloc(size) : realloc(ptr,size))
145 /* X windows routines.
146 * We currently create a single, top-level shell. In that is a
147 * single drawing area into which we will draw text. This allows
148 * us to put multi-color (and font, but we'll never build that) text
149 * into the drawing area. In the future, we'll add scrollbars to the
150 * drawing areas
153 void select_start();
154 void select_extend();
155 void select_paste();
156 void key_press();
157 void insert_string();
158 void beep();
159 void find();
160 void command();
162 static XtActionsRec area_actions[] = {
163 { "select_start", select_start },
164 { "select_extend", select_extend },
165 { "select_paste", select_paste },
166 { "key_press", key_press },
167 { "insert_string", insert_string },
168 { "beep", beep },
169 { "find", find },
170 { "command", command },
173 char areaTrans[] =
174 "<Btn1Down>: select_start() \n\
175 <Btn1Motion>: select_extend() \n\
176 <Btn2Down>: select_paste() \n\
177 <Btn3Down>: select_extend() \n\
178 <Btn3Motion>: select_extend() \n\
179 <Key>End: command(VI_C_BOTTOM) \n\
180 <Key>Escape: command(EINSERT) \n\
181 <Key>Find: find() \n\
182 <Key>Home: command(VI_C_TOP) \n\
183 <Key>Next: command(VI_C_PGDOWN) \n\
184 <Key>Prior: command(VI_C_PGUP) \n\
185 <Key>osfBackSpace: command(VI_C_LEFT) \n\
186 <Key>osfBeginLine: command(VI_C_BOL) \n\
187 <Key>osfCopy: beep() \n\
188 <Key>osfCut: beep() \n\
189 <Key>osfDelete: command(VI_C_DEL) \n\
190 <Key>osfDown: command(VI_C_DOWN) \n\
191 <Key>osfEndLine: command(VI_C_EOL) \n\
192 <Key>osfInsert: command(VI_C_INSERT) \n\
193 <Key>osfLeft: command(VI_C_LEFT) \n\
194 <Key>osfPageDown: command(VI_C_PGDOWN) \n\
195 <Key>osfPageUp: command(VI_C_PGUP) \n\
196 <Key>osfPaste: insert_string(p) \n\
197 <Key>osfRight: command(VI_C_RIGHT) \n\
198 <Key>osfUndo: command(VI_UNDO) \n\
199 <Key>osfUp: command(VI_C_UP) \n\
200 Ctrl<Key>C: command(VI_INTERRUPT) \n\
201 <Key>: key_press()";
204 static XutResource resource[] = {
205 { "font", XutRKfont, &font },
206 { "pointerShape", XutRKcursor, &std_cursor },
207 { "busyShape", XutRKcursor, &busy_cursor },
212 #if defined(__STDC__)
213 static Boolean process_pipe_input( XtPointer pread )
214 #else
215 static Boolean process_pipe_input( pread )
216 XtPointer pread;
217 #endif
219 /* might have read more since the last call */
220 len += (pread) ? *((int *)pread) : 0;
222 /* Parse to data end or partial message. */
223 (void)__vi_trans(bp, &len);
225 if (len > 0) {
226 #ifdef TRACE
227 trace("pipe_input_func: abort with %d in the buffer\n", len);
228 #endif
229 /* call me again later */
230 return False;
233 /* do NOT call me again later */
234 return True;
239 * vi_pipe_input_func --
240 * We've received input on the pipe from vi.
242 * PUBLIC: void vi_pipe_input_func __P((XtPointer, int *, XtInputId *));
244 void
245 vi_pipe_input_func(client_data, source, id)
246 XtPointer client_data;
247 int *source;
248 XtInputId *id;
250 int nr;
252 /* Read waiting vi messags and translate to X calls. */
253 switch (nr = read( *source, bp + len, blen - len)) {
254 case 0:
255 #ifdef TRACE
256 trace("pipe_input_func: empty input from vi\n");
257 #endif
258 return;
259 case -1:
260 perror("ip_cl: read");
261 exit (1);
262 default:
263 #ifdef TRACE
264 trace("input from vi, %d bytes read\n", nr);
265 #endif
266 break;
269 /* parse and dispatch on commands in the queue */
270 if ( ! process_pipe_input( &nr ) ) {
271 /* check the pipe for unused events when not busy */
272 XtAppAddWorkProc( ctx, process_pipe_input, NULL );
278 /* Send the window size. */
279 #if defined(__STDC__)
280 static void send_resize( xvi_screen *this_screen )
281 #else
282 static void send_resize( this_screen )
283 xvi_screen *this_screen;
284 #endif
286 IP_BUF ipb;
288 ipb.val1 = this_screen->rows;
289 ipb.val2 = this_screen->cols;
290 ipb.code = VI_RESIZE;
292 #ifdef TRACE
293 trace("resize_func ( %d x %d )\n", this_screen->rows, this_screen->cols);
294 #endif
296 /* send up the pipe */
297 __vi_send("12", &ipb);
301 #if defined(__STDC__)
302 static void resize_backing_store( xvi_screen *this_screen )
303 #else
304 static void resize_backing_store( this_screen )
305 xvi_screen *this_screen;
306 #endif
308 int total_chars = this_screen->rows * this_screen->cols;
310 this_screen->characters = REALLOC( this_screen->characters,
311 total_chars
313 memset( this_screen->characters, ' ', total_chars );
315 this_screen->flags = REALLOC( this_screen->flags,
316 total_chars
318 memset( this_screen->flags, 0, total_chars );
323 /* X will call this when we are resized */
324 #if defined(__STDC__)
325 static void resize_func( Widget wid,
326 XtPointer client_data,
327 XtPointer call_data
329 #else
330 static void resize_func( wid, client_data, call_data )
331 Widget wid;
332 XtPointer client_data;
333 XtPointer call_data;
334 #endif
336 xvi_screen *this_screen = (xvi_screen *) client_data;
337 Dimension height, width;
339 XtVaGetValues( wid, XmNheight, &height, XmNwidth, &width, 0 );
341 /* generate correct sizes when we have font metrics implemented */
342 this_screen->cols = width / this_screen->ch_width;
343 this_screen->rows = height / this_screen->ch_height;
345 resize_backing_store( this_screen );
346 send_resize( this_screen );
351 * __vi_draw_text --
352 * Draw from backing store.
354 * PUBLIC: void __vi_draw_text __P((xvi_screen *, int, int, int));
356 void
357 __vi_draw_text(this_screen, row, start_col, len)
358 xvi_screen *this_screen;
359 int row, start_col, len;
361 int col, color, xpos;
362 char *start, *end;
364 start = CharAt( __vi_screen, row, start_col );
365 color = *FlagAt( __vi_screen, row, start_col );
366 xpos = XPOS( __vi_screen, start_col );
368 /* one column at a time */
369 for ( col=start_col;
370 col<this_screen->cols && col<start_col+len;
371 col++ ) {
373 /* has the color changed? */
374 if ( *FlagAt( __vi_screen, row, col ) == color )
375 continue;
377 /* is there anything to write? */
378 end = CharAt( __vi_screen, row, col );
379 if ( end == start )
380 continue;
382 /* yes. write in the previous color */
383 set_gc_colors( __vi_screen, color );
385 /* add to display */
386 XDrawImageString( XtDisplay(__vi_screen->area),
387 XtWindow(__vi_screen->area),
389 xpos,
390 YPOS( __vi_screen, row ),
391 start,
392 end - start
395 /* this is the new context */
396 color = *FlagAt( __vi_screen, row, col );
397 xpos = XPOS( __vi_screen, col );
398 start = end;
401 /* is there anything to write? */
402 end = CharAt( __vi_screen, row, col );
403 if ( end != start ) {
404 /* yes. write in the previous color */
405 set_gc_colors( __vi_screen, color );
407 /* add to display */
408 XDrawImageString( XtDisplay(__vi_screen->area),
409 XtWindow(__vi_screen->area),
411 xpos,
412 YPOS( __vi_screen, row ),
413 start,
414 end - start
420 /* set clipping rectangles accordingly */
421 #if defined(__STDC__)
422 static void add_to_clip( xvi_screen *cur_screen, int x, int y, int width, int height )
423 #else
424 static void add_to_clip( cur_screen, x, y, width, height )
425 xvi_screen *cur_screen;
426 int x;
427 int y;
428 int width;
429 int height;
430 #endif
432 XRectangle rect;
433 rect.x = x;
434 rect.y = y;
435 rect.height = height;
436 rect.width = width;
437 if ( cur_screen->clip == NULL )
438 cur_screen->clip = XCreateRegion();
439 XUnionRectWithRegion( &rect, cur_screen->clip, cur_screen->clip );
444 * __vi_expose_func --
445 * Redraw the window's contents.
447 * NOTE: When vi wants to force a redraw, we are called with NULL widget
448 * and call_data.
450 * PUBLIC: void __vi_expose_func __P((Widget, XtPointer, XtPointer));
452 void
453 __vi_expose_func(wid, client_data, call_data)
454 Widget wid;
455 XtPointer client_data, call_data;
457 xvi_screen *this_screen;
458 XmDrawingAreaCallbackStruct *cbs;
459 XExposeEvent *xev;
460 XGraphicsExposeEvent *gev;
461 int row;
463 /* convert pointers */
464 this_screen = (xvi_screen *) client_data;
465 cbs = (XmDrawingAreaCallbackStruct *) call_data;
467 /* first exposure? tell vi we are ready... */
468 if ( this_screen->init == False ) {
470 /* what does the user want to see? */
471 __vi_set_cursor( __vi_screen, False );
473 /* vi wants a resize as the first event */
474 send_resize( __vi_screen );
476 /* fine for now. we'll be back */
477 this_screen->init = True;
478 return;
481 if ( call_data == NULL ) {
483 /* vi core calls this when it wants a full refresh */
484 #ifdef TRACE
485 trace("expose_func: full refresh\n");
486 #endif
488 XClearWindow( XtDisplay(this_screen->area),
489 XtWindow(this_screen->area)
492 else {
493 switch ( cbs->event->type ) {
495 case GraphicsExpose:
496 gev = (XGraphicsExposeEvent *) cbs->event;
498 /* set clipping rectangles accordingly */
499 add_to_clip( this_screen,
500 gev->x, gev->y,
501 gev->width, gev->height
504 /* X calls here when XCopyArea exposes new bits */
505 #ifdef TRACE
506 trace("expose_func (X): (x=%d,y=%d,w=%d,h=%d), count=%d\n",
507 gev->x, gev->y,
508 gev->width, gev->height,
509 gev->count);
510 #endif
512 /* more coming? do it then */
513 if ( gev->count > 0 ) return;
515 /* set clipping region */
516 XSetRegion( XtDisplay(wid), gc, this_screen->clip );
517 break;
519 case Expose:
520 xev = (XExposeEvent *) cbs->event;
522 /* set clipping rectangles accordingly */
523 add_to_clip( this_screen,
524 xev->x, xev->y,
525 xev->width, xev->height
528 /* Motif calls here when DrawingArea is exposed */
529 #ifdef TRACE
530 trace("expose_func (Motif): (x=%d,y=%d,w=%d,h=%d), count=%d\n",
531 xev->x, xev->y,
532 xev->width, xev->height,
533 xev->count);
534 #endif
536 /* more coming? do it then */
537 if ( xev->count > 0 ) return;
539 /* set clipping region */
540 XSetRegion( XtDisplay(wid), gc, this_screen->clip );
541 break;
543 default:
544 /* don't care? */
545 return;
549 /* one row at a time */
550 for (row=0; row<this_screen->rows; row++) {
552 /* draw from the backing store */
553 __vi_draw_text( this_screen, row, 0, this_screen->cols );
556 /* clear clipping region */
557 XSetClipMask( XtDisplay(this_screen->area), gc, None );
558 if ( this_screen->clip != NULL ) {
559 XDestroyRegion( this_screen->clip );
560 this_screen->clip = NULL;
566 #if defined(__STDC__)
567 static void xexpose ( Widget w,
568 XtPointer client_data,
569 XEvent *ev,
570 Boolean *cont
572 #else
573 static void xexpose ( w, client_data, ev, cont )
574 Widget w;
575 XtPointer client_data;
576 XEvent *ev;
577 Boolean *cont;
578 #endif
580 XmDrawingAreaCallbackStruct cbs;
582 switch ( ev->type ) {
583 case GraphicsExpose:
584 cbs.event = ev;
585 cbs.window = XtWindow(w);
586 cbs.reason = XmCR_EXPOSE;
587 __vi_expose_func( w, client_data, (XtPointer) &cbs );
588 *cont = False; /* we took care of it */
589 break;
590 default:
591 /* don't care */
592 break;
597 /* unimplemented keystroke or command */
598 #if defined(__STDC__)
599 static void beep( Widget w )
600 #else
601 static void beep( w )
602 Widget w;
603 #endif
605 XBell(XtDisplay(w),0);
609 /* give me a search dialog */
610 #if defined(__STDC__)
611 static void find( Widget w )
612 #else
613 static void find( w )
614 Widget w;
615 #endif
617 __vi_show_search_dialog( w, "Find" );
621 * command --
622 * Translate simple keyboard input into vi protocol commands.
624 void
625 command(widget, event, str, cardinal)
626 Widget widget;
627 XKeyEvent *event;
628 String *str;
629 Cardinal *cardinal;
631 static struct {
632 String name;
633 int code;
634 int count;
635 } table[] = {
636 { "VI_C_BOL", VI_C_BOL, 0 },
637 { "VI_C_BOTTOM", VI_C_BOTTOM, 0 },
638 { "VI_C_DEL", VI_C_DEL, 0 },
639 { "VI_C_DOWN", VI_C_DOWN, 1 },
640 { "VI_C_EOL", VI_C_EOL, 0 },
641 { "VI_C_INSERT", VI_C_INSERT, 0 },
642 { "VI_C_LEFT", VI_C_LEFT, 0 },
643 { "VI_C_PGDOWN", VI_C_PGDOWN, 1 },
644 { "VI_C_PGUP", VI_C_PGUP, 1 },
645 { "VI_C_RIGHT", VI_C_RIGHT, 0 },
646 { "VI_C_TOP", VI_C_TOP, 0 },
647 { "VI_C_UP", VI_C_UP, 1 },
648 { "VI_INTERRUPT", VI_INTERRUPT, 0 },
650 IP_BUF ipb;
651 int i;
654 * XXX
655 * Do fast lookup based on character #6 -- sleazy, but I don't
656 * want to do 10 strcmp's per keystroke.
658 ipb.val1 = 1;
659 for (i = 0; i < XtNumber(table); i++)
660 if (table[i].name[6] == (*str)[6] &&
661 strcmp(table[i].name, *str) == 0) {
662 ipb.code = table[i].code;
663 __vi_send(table[i].count ? "1" : NULL, &ipb);
664 return;
667 /* oops. */
668 beep(widget);
671 /* mouse or keyboard input. */
672 #if defined(__STDC__)
673 static void insert_string( Widget widget,
674 XKeyEvent *event,
675 String *str,
676 Cardinal *cardinal
678 #else
679 static void insert_string( widget, event, str, cardinal )
680 Widget widget;
681 XKeyEvent *event;
682 String *str;
683 Cardinal *cardinal;
684 #endif
686 IP_BUF ipb;
688 ipb.len = strlen( *str );
689 if ( ipb.len != 0 ) {
690 ipb.code = VI_STRING;
691 ipb.str = *str;
692 __vi_send("s", &ipb);
695 #ifdef TRACE
696 trace("insert_string {%.*s}\n", strlen( *str ), *str );
697 #endif
701 /* mouse or keyboard input. */
702 #if defined(__STDC__)
703 static void key_press( Widget widget,
704 XKeyEvent *event,
705 String str,
706 Cardinal *cardinal
708 #else
709 static void key_press( widget, event, str, cardinal )
710 Widget widget;
711 XKeyEvent *event;
712 String str;
713 Cardinal *cardinal;
714 #endif
716 IP_BUF ipb;
717 char bp[BufferSize];
719 ipb.len = XLookupString( event, bp, BufferSize, NULL, NULL );
720 if ( ipb.len != 0 ) {
721 ipb.code = VI_STRING;
722 ipb.str = bp;
723 #ifdef TRACE
724 trace("key_press {%.*s}\n", ipb.len, bp );
725 #endif
726 __vi_send("s", &ipb);
732 #if defined(__STDC__)
733 static xvi_screen *create_screen( Widget parent, int rows, int cols )
734 #else
735 static xvi_screen *create_screen( parent, rows, cols )
736 Widget parent;
737 int rows, cols;
738 #endif
740 xvi_screen *new_screen = (xvi_screen *) calloc( 1, sizeof(xvi_screen) );
741 Widget frame;
743 /* init... */
744 new_screen->color = COLOR_STANDARD;
745 new_screen->parent = parent;
747 /* figure out the sizes */
748 new_screen->rows = rows;
749 new_screen->cols = cols;
750 new_screen->ch_width = font->max_bounds.width;
751 new_screen->ch_height = font->descent + font->ascent;
752 new_screen->ch_descent = font->descent;
753 new_screen->clip = NULL;
755 /* allocate and init the backing stores */
756 resize_backing_store( new_screen );
758 /* set up a translation table for the X toolkit */
759 if ( area_trans == NULL )
760 area_trans = XtParseTranslationTable(areaTrans);
762 /* future, new screen gets inserted into the parent sash
763 * immediately after the current screen. Default Pane action is
764 * to add it to the end
767 /* use a form to hold the drawing area and the scrollbar */
768 new_screen->form = XtVaCreateManagedWidget( "form",
769 xmFormWidgetClass,
770 parent,
771 XmNpaneMinimum, 2*new_screen->ch_height,
772 XmNallowResize, True,
773 NULL
776 /* create a scroolbar.
777 * Future, connect new Protocol messages to position the scrollbar
778 * Future, connect scrollbar messages to new Protocol messages
780 new_screen->scroll = XtVaCreateManagedWidget( "scroll",
781 xmScrollBarWidgetClass,
782 new_screen->form,
783 XmNtopAttachment, XmATTACH_FORM,
784 XmNbottomAttachment, XmATTACH_FORM,
785 XmNrightAttachment, XmATTACH_FORM,
786 NULL
789 /* create a frame because they look nice */
790 frame = XtVaCreateManagedWidget( "frame",
791 xmFrameWidgetClass,
792 new_screen->form,
793 XmNshadowType, XmSHADOW_ETCHED_IN,
794 XmNtopAttachment, XmATTACH_FORM,
795 XmNbottomAttachment, XmATTACH_FORM,
796 XmNleftAttachment, XmATTACH_FORM,
797 XmNrightAttachment, XmATTACH_WIDGET,
798 XmNrightWidget, new_screen->scroll,
799 NULL
802 /* create a drawing area into which we will put text */
803 new_screen->area = XtVaCreateManagedWidget( "screen",
804 xmDrawingAreaWidgetClass,
805 frame,
806 XmNheight, new_screen->ch_height * new_screen->rows,
807 XmNwidth, new_screen->ch_width * new_screen->cols,
808 XmNtranslations, area_trans,
809 XmNuserData, new_screen,
810 XmNnavigationType, XmNONE,
811 XmNtraversalOn, False,
812 NULL
815 /* this callback is for when the drawing area is resized */
816 XtAddCallback( new_screen->area,
817 XmNresizeCallback,
818 resize_func,
819 new_screen
822 /* this callback is for when the drawing area is exposed */
823 XtAddCallback( new_screen->area,
824 XmNexposeCallback,
825 __vi_expose_func,
826 new_screen
829 /* this callback is for when we expose obscured bits
830 * (e.g. there is a window over part of our drawing area
832 XtAddEventHandler( new_screen->area,
833 0, /* no standard events */
834 True, /* we *WANT* GraphicsExpose */
835 xexpose, /* what to do */
836 new_screen
839 return new_screen;
843 static xvi_screen *split_screen()
845 Cardinal num;
846 WidgetList c;
847 int rows = __vi_screen->rows / 2;
848 xvi_screen *new_screen;
850 /* Note that (global) cur_screen needs to be correctly set so that
851 * insert_here knows which screen to put the new one after
853 new_screen = create_screen( __vi_screen->parent,
854 rows,
855 __vi_screen->cols
858 /* what are the screens? */
859 XtVaGetValues( __vi_screen->parent,
860 XmNnumChildren, &num,
861 XmNchildren, &c,
862 NULL
865 /* unmanage all children in preparation for resizing */
866 XtUnmanageChildren( c, num );
868 /* force resize of the affected screens */
869 XtVaSetValues( new_screen->form,
870 XmNheight, new_screen->ch_height * rows,
871 NULL
873 XtVaSetValues( __vi_screen->form,
874 XmNheight, __vi_screen->ch_height * rows,
875 NULL
878 /* re-manage */
879 XtManageChildren( c, num );
881 /* done */
882 return new_screen;
886 /* Tell me where to insert the next subpane */
887 #if defined(__STDC__)
888 static Cardinal insert_here( Widget wid )
889 #else
890 static Cardinal insert_here( wid )
891 Widget wid;
892 #endif
894 Cardinal i, num;
895 WidgetList c;
897 XtVaGetValues( XtParent(wid),
898 XmNnumChildren, &num,
899 XmNchildren, &c,
900 NULL
903 /* The default XmNinsertPosition procedure for PanedWindow
904 * causes sashes to be inserted at the end of the list of children
905 * and causes non-sash widgets to be inserted after other
906 * non-sash children but before any sashes.
908 if ( ! XmIsForm( wid ) )
909 return num;
911 /* We will put the widget after the one with the current screen */
912 for (i=0; i<num && XmIsForm(c[i]); i++) {
913 if ( __vi_screen == NULL || __vi_screen->form == c[i] )
914 return i+1; /* after the i-th */
917 /* could not find it? this should never happen */
918 return num;
923 * vi_create_editor --
924 * Create the necessary widgetry.
926 * PUBLIC: Widget vi_create_editor __P((String, Widget, void (*)(void)));
928 Widget
929 vi_create_editor(name, parent, exitp)
930 String name;
931 Widget parent;
932 void (*exitp) __P((void));
934 Widget pane_w;
935 Display *display = XtDisplay( parent );
937 __vi_exitp = exitp;
939 /* first time through? */
940 if ( ctx == NULL ) {
942 /* save this for later */
943 ctx = XtWidgetToApplicationContext( parent );
945 /* add our own special actions */
946 XtAppAddActions( ctx, area_actions, XtNumber(area_actions) );
948 /* how long is double-click? */
949 multi_click_length = XtGetMultiClickTime( display );
951 /* check the resource database for interesting resources */
952 XutConvertResources( parent,
953 vi_progname,
954 resource,
955 XtNumber(resource)
958 /* we need a context for moving bits around in the windows */
959 __vi_copy_gc = XCreateGC( display,
960 DefaultRootWindow(display),
965 /* routines for inter client communications conventions */
966 __vi_InitCopyPaste( f_copy, f_paste, f_clear, fprintf );
969 /* create the paned window */
970 pane_w = XtVaCreateManagedWidget( "pane",
971 xmPanedWindowWidgetClass,
972 parent,
973 XmNinsertPosition, insert_here,
974 NULL
977 /* allocate our data structure. in the future we will have several
978 * screens running around at the same time
980 __vi_screen = create_screen( pane_w, 24, 80 );
982 /* force creation of our color text context */
983 set_gc_colors( __vi_screen, COLOR_STANDARD );
985 /* done */
986 return pane_w;
990 /* These routines deal with the selection buffer */
992 static int selection_start, selection_end, selection_anchor;
993 static enum select_enum {
994 select_char, select_word, select_line
995 } select_type = select_char;
996 static int last_click;
998 static char *clipboard = NULL;
999 static int clipboard_size = 0,
1000 clipboard_length;
1003 #if defined(__STDC__)
1004 static void copy_to_clipboard( xvi_screen *cur_screen )
1005 #else
1006 static void copy_to_clipboard( cur_screen )
1007 xvi_screen *cur_screen;
1008 #endif
1010 /* for now, copy from the backing store. in the future,
1011 * vi core will tell us exactly what the selection buffer contains
1013 clipboard_length = 1 + selection_end - selection_start;
1015 if ( clipboard == NULL )
1016 clipboard = (char *) malloc( clipboard_length );
1017 else if ( clipboard_size < clipboard_length )
1018 clipboard = (char *) realloc( clipboard, clipboard_length );
1020 memcpy( clipboard,
1021 cur_screen->characters + selection_start,
1022 clipboard_length
1027 #if defined(__STDC__)
1028 static void mark_selection( xvi_screen *cur_screen, int start, int end )
1029 #else
1030 static void mark_selection( cur_screen, start, end )
1031 xvi_screen *cur_screen;
1032 int start;
1033 int end;
1034 #endif
1036 int row, col, i;
1038 for ( i=start; i<=end; i++ ) {
1039 if ( !( cur_screen->flags[i] & COLOR_SELECT ) ) {
1040 cur_screen->flags[i] |= COLOR_SELECT;
1041 ToRowCol( cur_screen, i, row, col );
1042 __vi_draw_text( cur_screen, row, col, 1 );
1048 #if defined(__STDC__)
1049 static void erase_selection( xvi_screen *cur_screen, int start, int end )
1050 #else
1051 static void erase_selection( cur_screen, start, end )
1052 xvi_screen *cur_screen;
1053 int start;
1054 int end;
1055 #endif
1057 int row, col, i;
1059 for ( i=start; i<=end; i++ ) {
1060 if ( cur_screen->flags[i] & COLOR_SELECT ) {
1061 cur_screen->flags[i] &= ~COLOR_SELECT;
1062 ToRowCol( cur_screen, i, row, col );
1063 __vi_draw_text( cur_screen, row, col, 1 );
1069 #if defined(__STDC__)
1070 static void left_expand_selection( xvi_screen *cur_screen, int *start )
1071 #else
1072 static void left_expand_selection( cur_screen, start )
1073 xvi_screen *cur_screen;
1074 int *start;
1075 #endif
1077 int row, col;
1079 switch ( select_type ) {
1080 case select_word:
1081 if ( *start == 0 || isspace( cur_screen->characters[*start] ) )
1082 return;
1083 for (;;) {
1084 if ( isspace( cur_screen->characters[*start-1] ) )
1085 return;
1086 if ( --(*start) == 0 )
1087 return;
1089 case select_line:
1090 ToRowCol( cur_screen, *start, row, col );
1091 col = 0;
1092 *start = Linear( cur_screen, row, col );
1093 break;
1098 #if defined(__STDC__)
1099 static void right_expand_selection( xvi_screen *cur_screen, int *end )
1100 #else
1101 static void right_expand_selection( cur_screen, end )
1102 xvi_screen *cur_screen;
1103 int *end;
1104 #endif
1106 int row, col, last = cur_screen->cols * cur_screen->rows - 1;
1108 switch ( select_type ) {
1109 case select_word:
1110 if ( *end == last || isspace( cur_screen->characters[*end] ) )
1111 return;
1112 for (;;) {
1113 if ( isspace( cur_screen->characters[*end+1] ) )
1114 return;
1115 if ( ++(*end) == last )
1116 return;
1118 case select_line:
1119 ToRowCol( cur_screen, *end, row, col );
1120 col = cur_screen->cols -1;
1121 *end = Linear( cur_screen, row, col );
1122 break;
1127 #if defined(__STDC__)
1128 static void select_start( Widget widget,
1129 XEvent *event,
1130 String str,
1131 Cardinal *cardinal
1133 #else
1134 static void select_start( widget, event, str, cardinal )
1135 Widget widget;
1136 XEvent *event;
1137 String str;
1138 Cardinal *cardinal;
1139 #endif
1141 char buffer[BufferSize];
1142 IP_BUF ipb;
1143 int xpos, ypos;
1144 XPointerMovedEvent *ev = (XPointerMovedEvent *) event;
1145 static int last_click;
1148 * NOTE: when multiple panes are implemented, we need to find the correct
1149 * screen. For now, there is only one.
1151 xpos = COLUMN( __vi_screen, ev->x );
1152 ypos = ROW( __vi_screen, ev->y );
1154 /* Remove the old one. */
1155 erase_selection( __vi_screen, selection_start, selection_end );
1157 /* Send the new cursor position. */
1158 ipb.code = VI_MOUSE_MOVE;
1159 ipb.val1 = ypos;
1160 ipb.val2 = xpos;
1161 (void)__vi_send("12", &ipb);
1163 /* click-click, and we go for words, lines, etc */
1164 if ( ev->time - last_click < multi_click_length )
1165 select_type = (enum select_enum) ((((int)select_type)+1)%3);
1166 else
1167 select_type = select_char;
1168 last_click = ev->time;
1170 /* put the selection here */
1171 selection_anchor = Linear( __vi_screen, ypos, xpos );
1172 selection_start = selection_anchor;
1173 selection_end = selection_anchor;
1175 /* expand to include words, line, etc */
1176 left_expand_selection( __vi_screen, &selection_start );
1177 right_expand_selection( __vi_screen, &selection_end );
1179 /* draw the new one */
1180 mark_selection( __vi_screen, selection_start, selection_end );
1182 /* and tell the window manager we own the selection */
1183 if ( select_type != select_char ) {
1184 __vi_AcquirePrimary( widget );
1185 copy_to_clipboard( __vi_screen );
1190 #if defined(__STDC__)
1191 static void select_extend( Widget widget,
1192 XEvent *event,
1193 String str,
1194 Cardinal *cardinal
1196 #else
1197 static void select_extend( widget, event, str, cardinal )
1198 Widget widget;
1199 XEvent *event;
1200 String str;
1201 Cardinal *cardinal;
1202 #endif
1204 int xpos, ypos, pos;
1205 XPointerMovedEvent *ev = (XPointerMovedEvent *) event;
1207 /* NOTE: when multiple panes are implemented, we need to find
1208 * the correct screen. For now, there is only one.
1210 xpos = COLUMN( __vi_screen, ev->x );
1211 ypos = ROW( __vi_screen, ev->y );
1213 /* deal with words, lines, etc */
1214 pos = Linear( __vi_screen, ypos, xpos );
1215 if ( pos < selection_anchor )
1216 left_expand_selection( __vi_screen, &pos );
1217 else
1218 right_expand_selection( __vi_screen, &pos );
1220 /* extend from before the start? */
1221 if ( pos < selection_start ) {
1222 mark_selection( __vi_screen, pos, selection_start-1 );
1223 selection_start = pos;
1226 /* extend past the end? */
1227 else if ( pos > selection_end ) {
1228 mark_selection( __vi_screen, selection_end+1, pos );
1229 selection_end = pos;
1232 /* between the anchor and the start? */
1233 else if ( pos < selection_anchor ) {
1234 erase_selection( __vi_screen, selection_start, pos-1 );
1235 selection_start = pos;
1238 /* between the anchor and the end? */
1239 else {
1240 erase_selection( __vi_screen, pos+1, selection_end );
1241 selection_end = pos;
1244 /* and tell the window manager we own the selection */
1245 __vi_AcquirePrimary( widget );
1246 copy_to_clipboard( __vi_screen );
1250 #if defined(__STDC__)
1251 static void select_paste( Widget widget,
1252 XEvent *event,
1253 String str,
1254 Cardinal *cardinal
1256 #else
1257 static void select_paste( widget, event, str, cardinal )
1258 Widget widget;
1259 XEvent *event;
1260 String str;
1261 Cardinal *cardinal;
1262 #endif
1264 __vi_PasteFromClipboard( widget );
1268 /* Interface to copy and paste
1269 * (a) callbacks from the window manager
1270 * f_copy - it wants our buffer
1271 * f_paste - it wants us to paste some text
1272 * f_clear - we've lost the selection, clear it
1275 #if defined(__STDC__)
1276 static void f_copy( String *buffer, int *len )
1277 #else
1278 static void f_copy( buffer, len )
1279 String *buffer;
1280 int *len;
1281 #endif
1283 #ifdef TRACE
1284 trace("f_copy() called");
1285 #endif
1286 *buffer = clipboard;
1287 *len = clipboard_length;
1292 static void f_paste( widget, buffer, length )
1293 int widget, buffer, length;
1295 /* NOTE: when multiple panes are implemented, we need to find
1296 * the correct screen. For now, there is only one.
1298 #ifdef TRACE
1299 trace("f_paste() called with '%*.*s'\n", length, length, buffer);
1300 #endif
1304 #if defined(__STDC__)
1305 static void f_clear( Widget widget )
1306 #else
1307 static void f_clear( widget )
1308 Widget widget;
1309 #endif
1311 xvi_screen *cur_screen;
1313 #ifdef TRACE
1314 trace("f_clear() called");
1315 #endif
1317 XtVaGetValues( widget, XmNuserData, &cur_screen, 0 );
1319 erase_selection( cur_screen, selection_start, selection_end );
1324 * These routines deal with the cursor.
1326 * PUBLIC: void __vi_set_cursor __P((xvi_screen *, int));
1328 void
1329 __vi_set_cursor(cur_screen, is_busy)
1330 xvi_screen *cur_screen;
1331 int is_busy;
1333 XDefineCursor( XtDisplay(cur_screen->area),
1334 XtWindow(cur_screen->area),
1335 (is_busy) ? busy_cursor : std_cursor
1342 * These routines deal with the caret.
1344 * PUBLIC: void draw_caret __P((xvi_screen *));
1346 static void
1347 draw_caret(this_screen)
1348 xvi_screen *this_screen;
1350 /* draw the caret by drawing the text in highlight color */
1351 *FlagAt( this_screen, this_screen->cury, this_screen->curx ) |= COLOR_CARET;
1352 __vi_draw_text( this_screen, this_screen->cury, this_screen->curx, 1 );
1356 * PUBLIC: void __vi_erase_caret __P((xvi_screen *));
1358 void
1359 __vi_erase_caret(this_screen)
1360 xvi_screen *this_screen;
1362 /* erase the caret by drawing the text in normal video */
1363 *FlagAt( this_screen, this_screen->cury, this_screen->curx ) &= ~COLOR_CARET;
1364 __vi_draw_text( this_screen, this_screen->cury, this_screen->curx, 1 );
1368 * PUBLIC: void __vi_move_caret __P((xvi_screen *, int, int));
1370 void
1371 __vi_move_caret(this_screen, newy, newx)
1372 xvi_screen *this_screen;
1373 int newy, newx;
1375 /* caret is now here */
1376 __vi_erase_caret( this_screen );
1377 this_screen->curx = newx;
1378 this_screen->cury = newy;
1379 draw_caret( this_screen );