3 * Rob Zimmermann. All rights reserved.
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
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 $";
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>
26 #include <Xm/ScrollBar.h>
28 #include <bitstring.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"
47 static void f_paste();
48 static void f_clear();
52 * Globals and costants
55 #define BufferSize 1024
57 static XFontStruct
*font
;
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
);
75 static void set_gc_colors( xvi_screen
*this_screen
, int val
)
77 static void set_gc_colors( this_screen
, val
)
78 xvi_screen
*this_screen
;
82 static Pixel fg
, bg
, hi
, shade
;
83 static int prev
= COLOR_INVALID
;
86 if ( prev
== val
) return;
91 /* what colors are selected for the drawing area? */
92 XtVaGetValues( this_screen
->area
,
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
);
120 XSetForeground( XtDisplay(this_screen
->area
), gc
, fg
);
121 XSetBackground( XtDisplay(this_screen
->area
), gc
, bg
);
124 XSetForeground( XtDisplay(this_screen
->area
), gc
, bg
);
125 XSetBackground( XtDisplay(this_screen
->area
), gc
, fg
);
127 default: /* implement color map later */
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
154 void select_extend();
157 void insert_string();
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
},
170 { "command", command
},
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\
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
)
215 static Boolean
process_pipe_input( pread
)
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
);
227 trace("pipe_input_func: abort with %d in the buffer\n", len
);
229 /* call me again later */
233 /* do NOT call me again later */
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 *));
245 vi_pipe_input_func(client_data
, source
, id
)
246 XtPointer client_data
;
252 /* Read waiting vi messags and translate to X calls. */
253 switch (nr
= read( *source
, bp
+ len
, blen
- len
)) {
256 trace("pipe_input_func: empty input from vi\n");
260 perror("ip_cl: read");
264 trace("input from vi, %d bytes read\n", nr
);
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
)
282 static void send_resize( this_screen
)
283 xvi_screen
*this_screen
;
288 ipb
.val1
= this_screen
->rows
;
289 ipb
.val2
= this_screen
->cols
;
290 ipb
.code
= VI_RESIZE
;
293 trace("resize_func ( %d x %d )\n", this_screen
->rows
, this_screen
->cols
);
296 /* send up the pipe */
297 __vi_send("12", &ipb
);
301 #if defined(__STDC__)
302 static void resize_backing_store( xvi_screen
*this_screen
)
304 static void resize_backing_store( this_screen
)
305 xvi_screen
*this_screen
;
308 int total_chars
= this_screen
->rows
* this_screen
->cols
;
310 this_screen
->characters
= REALLOC( this_screen
->characters
,
313 memset( this_screen
->characters
, ' ', total_chars
);
315 this_screen
->flags
= REALLOC( this_screen
->flags
,
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
,
330 static void resize_func( wid
, client_data
, call_data
)
332 XtPointer client_data
;
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
);
352 * Draw from backing store.
354 * PUBLIC: void __vi_draw_text __P((xvi_screen *, int, int, int));
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
;
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 */
370 col
<this_screen
->cols
&& col
<start_col
+len
;
373 /* has the color changed? */
374 if ( *FlagAt( __vi_screen
, row
, col
) == color
)
377 /* is there anything to write? */
378 end
= CharAt( __vi_screen
, row
, col
);
382 /* yes. write in the previous color */
383 set_gc_colors( __vi_screen
, color
);
386 XDrawImageString( XtDisplay(__vi_screen
->area
),
387 XtWindow(__vi_screen
->area
),
390 YPOS( __vi_screen
, row
),
395 /* this is the new context */
396 color
= *FlagAt( __vi_screen
, row
, col
);
397 xpos
= XPOS( __vi_screen
, col
);
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
);
408 XDrawImageString( XtDisplay(__vi_screen
->area
),
409 XtWindow(__vi_screen
->area
),
412 YPOS( __vi_screen
, row
),
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
)
424 static void add_to_clip( cur_screen
, x
, y
, width
, height
)
425 xvi_screen
*cur_screen
;
435 rect
.height
= height
;
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
450 * PUBLIC: void __vi_expose_func __P((Widget, XtPointer, XtPointer));
453 __vi_expose_func(wid
, client_data
, call_data
)
455 XtPointer client_data
, call_data
;
457 xvi_screen
*this_screen
;
458 XmDrawingAreaCallbackStruct
*cbs
;
460 XGraphicsExposeEvent
*gev
;
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
;
481 if ( call_data
== NULL
) {
483 /* vi core calls this when it wants a full refresh */
485 trace("expose_func: full refresh\n");
488 XClearWindow( XtDisplay(this_screen
->area
),
489 XtWindow(this_screen
->area
)
493 switch ( cbs
->event
->type
) {
496 gev
= (XGraphicsExposeEvent
*) cbs
->event
;
498 /* set clipping rectangles accordingly */
499 add_to_clip( this_screen
,
501 gev
->width
, gev
->height
504 /* X calls here when XCopyArea exposes new bits */
506 trace("expose_func (X): (x=%d,y=%d,w=%d,h=%d), count=%d\n",
508 gev
->width
, gev
->height
,
512 /* more coming? do it then */
513 if ( gev
->count
> 0 ) return;
515 /* set clipping region */
516 XSetRegion( XtDisplay(wid
), gc
, this_screen
->clip
);
520 xev
= (XExposeEvent
*) cbs
->event
;
522 /* set clipping rectangles accordingly */
523 add_to_clip( this_screen
,
525 xev
->width
, xev
->height
528 /* Motif calls here when DrawingArea is exposed */
530 trace("expose_func (Motif): (x=%d,y=%d,w=%d,h=%d), count=%d\n",
532 xev
->width
, xev
->height
,
536 /* more coming? do it then */
537 if ( xev
->count
> 0 ) return;
539 /* set clipping region */
540 XSetRegion( XtDisplay(wid
), gc
, this_screen
->clip
);
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
,
573 static void xexpose ( w
, client_data
, ev
, cont
)
575 XtPointer client_data
;
580 XmDrawingAreaCallbackStruct cbs
;
582 switch ( ev
->type
) {
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 */
597 /* unimplemented keystroke or command */
598 #if defined(__STDC__)
599 static void beep( Widget w
)
601 static void beep( w
)
605 XBell(XtDisplay(w
),0);
609 /* give me a search dialog */
610 #if defined(__STDC__)
611 static void find( Widget w
)
613 static void find( w
)
617 __vi_show_search_dialog( w
, "Find" );
622 * Translate simple keyboard input into vi protocol commands.
625 command(widget
, event
, str
, cardinal
)
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 },
655 * Do fast lookup based on character #6 -- sleazy, but I don't
656 * want to do 10 strcmp's per keystroke.
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
);
671 /* mouse or keyboard input. */
672 #if defined(__STDC__)
673 static void insert_string( Widget widget
,
679 static void insert_string( widget
, event
, str
, cardinal
)
688 ipb
.len
= strlen( *str
);
689 if ( ipb
.len
!= 0 ) {
690 ipb
.code
= VI_STRING
;
692 __vi_send("s", &ipb
);
696 trace("insert_string {%.*s}\n", strlen( *str
), *str
);
701 /* mouse or keyboard input. */
702 #if defined(__STDC__)
703 static void key_press( Widget widget
,
709 static void key_press( widget
, event
, str
, cardinal
)
719 ipb
.len
= XLookupString( event
, bp
, BufferSize
, NULL
, NULL
);
720 if ( ipb
.len
!= 0 ) {
721 ipb
.code
= VI_STRING
;
724 trace("key_press {%.*s}\n", ipb
.len
, bp
);
726 __vi_send("s", &ipb
);
732 #if defined(__STDC__)
733 static xvi_screen
*create_screen( Widget parent
, int rows
, int cols
)
735 static xvi_screen
*create_screen( parent
, rows
, cols
)
740 xvi_screen
*new_screen
= (xvi_screen
*) calloc( 1, sizeof(xvi_screen
) );
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",
771 XmNpaneMinimum
, 2*new_screen
->ch_height
,
772 XmNallowResize
, True
,
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
,
783 XmNtopAttachment
, XmATTACH_FORM
,
784 XmNbottomAttachment
, XmATTACH_FORM
,
785 XmNrightAttachment
, XmATTACH_FORM
,
789 /* create a frame because they look nice */
790 frame
= XtVaCreateManagedWidget( "frame",
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
,
802 /* create a drawing area into which we will put text */
803 new_screen
->area
= XtVaCreateManagedWidget( "screen",
804 xmDrawingAreaWidgetClass
,
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
,
815 /* this callback is for when the drawing area is resized */
816 XtAddCallback( new_screen
->area
,
822 /* this callback is for when the drawing area is exposed */
823 XtAddCallback( new_screen
->area
,
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 */
843 static xvi_screen
*split_screen()
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
,
858 /* what are the screens? */
859 XtVaGetValues( __vi_screen
->parent
,
860 XmNnumChildren
, &num
,
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
,
873 XtVaSetValues( __vi_screen
->form
,
874 XmNheight
, __vi_screen
->ch_height
* rows
,
879 XtManageChildren( c
, num
);
886 /* Tell me where to insert the next subpane */
887 #if defined(__STDC__)
888 static Cardinal
insert_here( Widget wid
)
890 static Cardinal
insert_here( wid
)
897 XtVaGetValues( XtParent(wid
),
898 XmNnumChildren
, &num
,
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
) )
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 */
923 * vi_create_editor --
924 * Create the necessary widgetry.
926 * PUBLIC: Widget vi_create_editor __P((String, Widget, void (*)(void)));
929 vi_create_editor(name
, parent
, exitp
)
932 void (*exitp
) __P((void));
935 Display
*display
= XtDisplay( parent
);
939 /* first time through? */
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
,
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
,
973 XmNinsertPosition
, insert_here
,
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
);
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,
1003 #if defined(__STDC__)
1004 static void copy_to_clipboard( xvi_screen
*cur_screen
)
1006 static void copy_to_clipboard( cur_screen
)
1007 xvi_screen
*cur_screen
;
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
);
1021 cur_screen
->characters
+ selection_start
,
1027 #if defined(__STDC__)
1028 static void mark_selection( xvi_screen
*cur_screen
, int start
, int end
)
1030 static void mark_selection( cur_screen
, start
, end
)
1031 xvi_screen
*cur_screen
;
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
)
1051 static void erase_selection( cur_screen
, start
, end
)
1052 xvi_screen
*cur_screen
;
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
)
1072 static void left_expand_selection( cur_screen
, start
)
1073 xvi_screen
*cur_screen
;
1079 switch ( select_type
) {
1081 if ( *start
== 0 || isspace( cur_screen
->characters
[*start
] ) )
1084 if ( isspace( cur_screen
->characters
[*start
-1] ) )
1086 if ( --(*start
) == 0 )
1090 ToRowCol( cur_screen
, *start
, row
, col
);
1092 *start
= Linear( cur_screen
, row
, col
);
1098 #if defined(__STDC__)
1099 static void right_expand_selection( xvi_screen
*cur_screen
, int *end
)
1101 static void right_expand_selection( cur_screen
, end
)
1102 xvi_screen
*cur_screen
;
1106 int row
, col
, last
= cur_screen
->cols
* cur_screen
->rows
- 1;
1108 switch ( select_type
) {
1110 if ( *end
== last
|| isspace( cur_screen
->characters
[*end
] ) )
1113 if ( isspace( cur_screen
->characters
[*end
+1] ) )
1115 if ( ++(*end
) == last
)
1119 ToRowCol( cur_screen
, *end
, row
, col
);
1120 col
= cur_screen
->cols
-1;
1121 *end
= Linear( cur_screen
, row
, col
);
1127 #if defined(__STDC__)
1128 static void select_start( Widget widget
,
1134 static void select_start( widget
, event
, str
, cardinal
)
1141 char buffer
[BufferSize
];
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
;
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);
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
,
1197 static void select_extend( widget
, event
, str
, cardinal
)
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
);
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? */
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
,
1257 static void select_paste( widget
, event
, str
, cardinal
)
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
)
1278 static void f_copy( buffer
, len
)
1284 trace("f_copy() called");
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.
1299 trace("f_paste() called with '%*.*s'\n", length
, length
, buffer
);
1304 #if defined(__STDC__)
1305 static void f_clear( Widget widget
)
1307 static void f_clear( widget
)
1311 xvi_screen
*cur_screen
;
1314 trace("f_clear() called");
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));
1329 __vi_set_cursor(cur_screen
, is_busy
)
1330 xvi_screen
*cur_screen
;
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 *));
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 *));
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));
1371 __vi_move_caret(this_screen
, newy
, newx
)
1372 xvi_screen
*this_screen
;
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
);