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.29 1996/12/13 12:23:05 bostic Exp $ (Berkeley) $Date: 1996/12/13 12:23:05 $";
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"
43 #include "vi_mextern.h"
44 #include "ipc_extern.h"
45 #include "pathnames.h"
48 static void f_paste();
49 static void f_clear();
53 * Globals and costants
56 #define BufferSize 1024
58 static XFontStruct
*font
;
61 static XtAppContext ctx
;
63 xvi_screen
*__vi_screen
= NULL
;
64 static Cursor std_cursor
;
65 static Cursor busy_cursor
;
66 static XtTranslations area_trans
;
67 static int multi_click_length
;
69 void (*__vi_exitp
)(); /* Exit function. */
71 static char bp
[ BufferSize
]; /* input buffer from pipe */
72 static size_t len
, blen
= sizeof(bp
);
75 /* hack for drag scrolling...
76 * I'm not sure why, but the current protocol gets out of sync when
77 * a lot of drag messages get passed around. Likely, we need to wait
78 * for core to finish repainting the screen before sending more drag
80 * To that end, we set scroll_block when we receive input from the scrollbar,
81 * and we clear it when we process the IPO_REFRESH message from core.
82 * A specific SCROLL_COMPLETED message would be better, but this seems to work.
85 static Boolean scroll_block
= False
;
88 __vi_set_scroll_block()
94 __vi_clear_scroll_block()
100 #if defined(__STDC__)
101 static void set_gc_colors( xvi_screen
*this_screen
, int val
)
103 static void set_gc_colors( this_screen
, val
)
104 xvi_screen
*this_screen
;
108 static Pixel fg
, bg
, hi
, shade
;
109 static int prev
= COLOR_INVALID
;
112 if ( prev
== val
) return;
117 /* what colors are selected for the drawing area? */
118 XtVaGetValues( this_screen
->area
,
121 XmNhighlightColor
, &hi
,
122 XmNtopShadowColor
, &shade
,
126 gc
= XCreateGC( XtDisplay(this_screen
->area
),
127 DefaultRootWindow(XtDisplay(this_screen
->area
)),
132 XSetFont( XtDisplay(this_screen
->area
), gc
, font
->fid
);
135 /* special colors? */
136 if ( val
& COLOR_CARET
) {
137 XSetForeground( XtDisplay(this_screen
->area
), gc
, fg
);
138 XSetBackground( XtDisplay(this_screen
->area
), gc
, hi
);
140 else if ( val
& COLOR_SELECT
) {
141 XSetForeground( XtDisplay(this_screen
->area
), gc
, fg
);
142 XSetBackground( XtDisplay(this_screen
->area
), gc
, shade
);
146 XSetForeground( XtDisplay(this_screen
->area
), gc
, fg
);
147 XSetBackground( XtDisplay(this_screen
->area
), gc
, bg
);
150 XSetForeground( XtDisplay(this_screen
->area
), gc
, bg
);
151 XSetBackground( XtDisplay(this_screen
->area
), gc
, fg
);
153 default: /* implement color map later */
167 #define REALLOC( ptr, size ) \
168 ((ptr == NULL) ? malloc(size) : realloc(ptr,size))
171 /* X windows routines.
172 * We currently create a single, top-level shell. In that is a
173 * single drawing area into which we will draw text. This allows
174 * us to put multi-color (and font, but we'll never build that) text
175 * into the drawing area. In the future, we'll add scrollbars to the
180 void select_extend();
183 void insert_string();
188 static XtActionsRec area_actions
[] = {
189 { "select_start", select_start
},
190 { "select_extend", select_extend
},
191 { "select_paste", select_paste
},
192 { "key_press", key_press
},
193 { "insert_string", insert_string
},
196 { "command", command
},
200 "<Btn1Down>: select_start() \n\
201 <Btn1Motion>: select_extend() \n\
202 <Btn2Down>: select_paste() \n\
203 <Btn3Down>: select_extend() \n\
204 <Btn3Motion>: select_extend() \n\
205 <Key>End: command(VI_C_BOTTOM) \n\
206 <Key>Escape: command(EINSERT) \n\
207 <Key>Find: find() \n\
208 <Key>Home: command(VI_C_TOP) \n\
209 <Key>Next: command(VI_C_PGDOWN) \n\
210 <Key>Prior: command(VI_C_PGUP) \n\
211 <Key>osfBackSpace: command(VI_C_LEFT) \n\
212 <Key>osfBeginLine: command(VI_C_BOL) \n\
213 <Key>osfCopy: beep() \n\
214 <Key>osfCut: beep() \n\
215 <Key>osfDelete: command(VI_C_DEL) \n\
216 <Key>osfDown: command(VI_C_DOWN) \n\
217 <Key>osfEndLine: command(VI_C_EOL) \n\
218 <Key>osfInsert: command(VI_C_INSERT) \n\
219 <Key>osfLeft: command(VI_C_LEFT) \n\
220 <Key>osfPageDown: command(VI_C_PGDOWN) \n\
221 <Key>osfPageUp: command(VI_C_PGUP) \n\
222 <Key>osfPaste: insert_string(p) \n\
223 <Key>osfRight: command(VI_C_RIGHT) \n\
224 <Key>osfUndo: command(VI_UNDO) \n\
225 <Key>osfUp: command(VI_C_UP) \n\
226 Ctrl<Key>C: command(VI_INTERRUPT) \n\
230 static XutResource resource
[] = {
231 { "font", XutRKfont
, &font
},
232 { "pointerShape", XutRKcursor
, &std_cursor
},
233 { "busyShape", XutRKcursor
, &busy_cursor
},
238 #if defined(__STDC__)
239 static Boolean
process_pipe_input( XtPointer pread
)
241 static Boolean
process_pipe_input( pread
)
245 /* might have read more since the last call */
246 len
+= (pread
) ? *((int *)pread
) : 0;
248 /* Parse to data end or partial message. */
249 (void)__vi_trans(bp
, &len
);
253 trace("pipe_input_func: abort with %d in the buffer\n", len
);
255 /* call me again later */
259 /* do NOT call me again later */
266 * We've received input on the pipe from vi.
268 * PUBLIC: void vi_input_func __P((XtPointer, int *, XtInputId *));
271 vi_input_func(client_data
, source
, id
)
272 XtPointer client_data
;
278 /* Read waiting vi messags and translate to X calls. */
279 switch (nr
= read( *source
, bp
+ len
, blen
- len
)) {
282 trace("pipe_input_func: empty input from vi\n");
286 perror("ip_cl: read");
290 trace("input from vi, %d bytes read\n", nr
);
295 /* parse and dispatch on commands in the queue */
296 if ( ! process_pipe_input( &nr
) ) {
297 /* check the pipe for unused events when not busy */
298 XtAppAddWorkProc( ctx
, process_pipe_input
, NULL
);
304 /* Send the window size. */
305 #if defined(__STDC__)
306 static void send_resize( xvi_screen
*this_screen
)
308 static void send_resize( this_screen
)
309 xvi_screen
*this_screen
;
314 ipb
.val1
= this_screen
->rows
;
315 ipb
.val2
= this_screen
->cols
;
316 ipb
.code
= VI_RESIZE
;
319 trace("resize_func ( %d x %d )\n", this_screen
->rows
, this_screen
->cols
);
322 /* send up the pipe */
323 __vi_send("12", &ipb
);
327 #if defined(__STDC__)
328 static void resize_backing_store( xvi_screen
*this_screen
)
330 static void resize_backing_store( this_screen
)
331 xvi_screen
*this_screen
;
334 int total_chars
= this_screen
->rows
* this_screen
->cols
;
336 this_screen
->characters
= REALLOC( this_screen
->characters
,
339 memset( this_screen
->characters
, ' ', total_chars
);
341 this_screen
->flags
= REALLOC( this_screen
->flags
,
344 memset( this_screen
->flags
, 0, total_chars
);
349 /* X will call this when we are resized */
350 #if defined(__STDC__)
351 static void resize_func( Widget wid
,
352 XtPointer client_data
,
356 static void resize_func( wid
, client_data
, call_data
)
358 XtPointer client_data
;
362 xvi_screen
*this_screen
= (xvi_screen
*) client_data
;
363 Dimension height
, width
;
365 XtVaGetValues( wid
, XmNheight
, &height
, XmNwidth
, &width
, 0 );
367 /* generate correct sizes when we have font metrics implemented */
368 this_screen
->cols
= width
/ this_screen
->ch_width
;
369 this_screen
->rows
= height
/ this_screen
->ch_height
;
371 resize_backing_store( this_screen
);
372 send_resize( this_screen
);
378 * Draw from backing store.
380 * PUBLIC: void __vi_draw_text __P((xvi_screen *, int, int, int));
383 __vi_draw_text(this_screen
, row
, start_col
, len
)
384 xvi_screen
*this_screen
;
385 int row
, start_col
, len
;
387 int col
, color
, xpos
;
390 start
= CharAt( __vi_screen
, row
, start_col
);
391 color
= *FlagAt( __vi_screen
, row
, start_col
);
392 xpos
= XPOS( __vi_screen
, start_col
);
394 /* one column at a time */
396 col
<this_screen
->cols
&& col
<start_col
+len
;
399 /* has the color changed? */
400 if ( *FlagAt( __vi_screen
, row
, col
) == color
)
403 /* is there anything to write? */
404 end
= CharAt( __vi_screen
, row
, col
);
408 /* yes. write in the previous color */
409 set_gc_colors( __vi_screen
, color
);
412 XDrawImageString( XtDisplay(__vi_screen
->area
),
413 XtWindow(__vi_screen
->area
),
416 YPOS( __vi_screen
, row
),
421 /* this is the new context */
422 color
= *FlagAt( __vi_screen
, row
, col
);
423 xpos
= XPOS( __vi_screen
, col
);
427 /* is there anything to write? */
428 end
= CharAt( __vi_screen
, row
, col
);
429 if ( end
!= start
) {
430 /* yes. write in the previous color */
431 set_gc_colors( __vi_screen
, color
);
434 XDrawImageString( XtDisplay(__vi_screen
->area
),
435 XtWindow(__vi_screen
->area
),
438 YPOS( __vi_screen
, row
),
446 /* set clipping rectangles accordingly */
447 #if defined(__STDC__)
448 static void add_to_clip( xvi_screen
*cur_screen
, int x
, int y
, int width
, int height
)
450 static void add_to_clip( cur_screen
, x
, y
, width
, height
)
451 xvi_screen
*cur_screen
;
461 rect
.height
= height
;
463 if ( cur_screen
->clip
== NULL
)
464 cur_screen
->clip
= XCreateRegion();
465 XUnionRectWithRegion( &rect
, cur_screen
->clip
, cur_screen
->clip
);
470 * __vi_expose_func --
471 * Redraw the window's contents.
473 * NOTE: When vi wants to force a redraw, we are called with NULL widget
476 * PUBLIC: void __vi_expose_func __P((Widget, XtPointer, XtPointer));
479 __vi_expose_func(wid
, client_data
, call_data
)
481 XtPointer client_data
, call_data
;
483 xvi_screen
*this_screen
;
484 XmDrawingAreaCallbackStruct
*cbs
;
486 XGraphicsExposeEvent
*gev
;
489 /* convert pointers */
490 this_screen
= (xvi_screen
*) client_data
;
491 cbs
= (XmDrawingAreaCallbackStruct
*) call_data
;
493 /* first exposure? tell vi we are ready... */
494 if ( this_screen
->init
== False
) {
496 /* what does the user want to see? */
497 __vi_set_cursor( __vi_screen
, False
);
499 /* vi wants a resize as the first event */
500 send_resize( __vi_screen
);
502 /* fine for now. we'll be back */
503 this_screen
->init
= True
;
507 if ( call_data
== NULL
) {
509 /* vi core calls this when it wants a full refresh */
511 trace("expose_func: full refresh\n");
514 XClearWindow( XtDisplay(this_screen
->area
),
515 XtWindow(this_screen
->area
)
519 switch ( cbs
->event
->type
) {
522 gev
= (XGraphicsExposeEvent
*) cbs
->event
;
524 /* set clipping rectangles accordingly */
525 add_to_clip( this_screen
,
527 gev
->width
, gev
->height
530 /* X calls here when XCopyArea exposes new bits */
532 trace("expose_func (X): (x=%d,y=%d,w=%d,h=%d), count=%d\n",
534 gev
->width
, gev
->height
,
538 /* more coming? do it then */
539 if ( gev
->count
> 0 ) return;
541 /* set clipping region */
542 XSetRegion( XtDisplay(wid
), gc
, this_screen
->clip
);
546 xev
= (XExposeEvent
*) cbs
->event
;
548 /* set clipping rectangles accordingly */
549 add_to_clip( this_screen
,
551 xev
->width
, xev
->height
554 /* Motif calls here when DrawingArea is exposed */
556 trace("expose_func (Motif): (x=%d,y=%d,w=%d,h=%d), count=%d\n",
558 xev
->width
, xev
->height
,
562 /* more coming? do it then */
563 if ( xev
->count
> 0 ) return;
565 /* set clipping region */
566 XSetRegion( XtDisplay(wid
), gc
, this_screen
->clip
);
575 /* one row at a time */
576 for (row
=0; row
<this_screen
->rows
; row
++) {
578 /* draw from the backing store */
579 __vi_draw_text( this_screen
, row
, 0, this_screen
->cols
);
582 /* clear clipping region */
583 XSetClipMask( XtDisplay(this_screen
->area
), gc
, None
);
584 if ( this_screen
->clip
!= NULL
) {
585 XDestroyRegion( this_screen
->clip
);
586 this_screen
->clip
= NULL
;
592 #if defined(__STDC__)
593 static void xexpose ( Widget w
,
594 XtPointer client_data
,
599 static void xexpose ( w
, client_data
, ev
, cont
)
601 XtPointer client_data
;
606 XmDrawingAreaCallbackStruct cbs
;
608 switch ( ev
->type
) {
611 cbs
.window
= XtWindow(w
);
612 cbs
.reason
= XmCR_EXPOSE
;
613 __vi_expose_func( w
, client_data
, (XtPointer
) &cbs
);
614 *cont
= False
; /* we took care of it */
623 /* unimplemented keystroke or command */
624 #if defined(__STDC__)
625 static void beep( Widget w
)
627 static void beep( w
)
631 XBell(XtDisplay(w
),0);
635 /* give me a search dialog */
636 #if defined(__STDC__)
637 static void find( Widget w
)
639 static void find( w
)
643 __vi_show_search_dialog( w
, "Find" );
648 * Translate simple keyboard input into vi protocol commands.
651 command(widget
, event
, str
, cardinal
)
662 { "VI_C_BOL", VI_C_BOL
, 0 },
663 { "VI_C_BOTTOM", VI_C_BOTTOM
, 0 },
664 { "VI_C_DEL", VI_C_DEL
, 0 },
665 { "VI_C_DOWN", VI_C_DOWN
, 1 },
666 { "VI_C_EOL", VI_C_EOL
, 0 },
667 { "VI_C_INSERT", VI_C_INSERT
, 0 },
668 { "VI_C_LEFT", VI_C_LEFT
, 0 },
669 { "VI_C_PGDOWN", VI_C_PGDOWN
, 1 },
670 { "VI_C_PGUP", VI_C_PGUP
, 1 },
671 { "VI_C_RIGHT", VI_C_RIGHT
, 0 },
672 { "VI_C_TOP", VI_C_TOP
, 0 },
673 { "VI_C_UP", VI_C_UP
, 1 },
674 { "VI_INTERRUPT", VI_INTERRUPT
, 0 },
681 * Do fast lookup based on character #6 -- sleazy, but I don't
682 * want to do 10 strcmp's per keystroke.
685 for (i
= 0; i
< XtNumber(table
); i
++)
686 if (table
[i
].name
[6] == (*str
)[6] &&
687 strcmp(table
[i
].name
, *str
) == 0) {
688 ipb
.code
= table
[i
].code
;
689 __vi_send(table
[i
].count
? "1" : NULL
, &ipb
);
697 /* mouse or keyboard input. */
698 #if defined(__STDC__)
699 static void insert_string( Widget widget
,
705 static void insert_string( widget
, event
, str
, cardinal
)
714 ipb
.len
= strlen( *str
);
715 if ( ipb
.len
!= 0 ) {
716 ipb
.code
= VI_STRING
;
718 __vi_send("s", &ipb
);
722 trace("insert_string {%.*s}\n", strlen( *str
), *str
);
727 /* mouse or keyboard input. */
728 #if defined(__STDC__)
729 static void key_press( Widget widget
,
735 static void key_press( widget
, event
, str
, cardinal
)
745 ipb
.len
= XLookupString( event
, bp
, BufferSize
, NULL
, NULL
);
746 if ( ipb
.len
!= 0 ) {
747 ipb
.code
= VI_STRING
;
750 trace("key_press {%.*s}\n", ipb
.len
, bp
);
752 __vi_send("s", &ipb
);
758 #if defined(__STDC__)
759 static void scrollbar_moved( Widget widget
,
761 XmScrollBarCallbackStruct
*cbs
764 static void scrollbar_moved( widget
, ptr
, cbs
)
767 XmScrollBarCallbackStruct
*cbs
;
770 /* Future: Need to scroll the correct screen! */
771 xvi_screen
*cur_screen
= (xvi_screen
*) ptr
;
774 /* if we are still processing messages from core, skip this event
775 * (see comments near __vi_set_scroll_block())
777 if ( scroll_block
) {
779 trace( "punting scroll request with %d in buffer\n", len
);
783 __vi_set_scroll_block();
786 switch ( cbs
->reason
) {
787 case XmCR_VALUE_CHANGED
:
788 trace( "scrollbar VALUE_CHANGED %d\n", cbs
->value
);
791 trace( "scrollbar DRAG %d\n", cbs
->value
);
794 trace( "scrollbar <default> %d\n", cbs
->value
);
797 trace("scrollto {%d}\n", cbs
->value
);
800 /* Send the new cursor position. */
801 ipb
.code
= VI_C_SETTOP
;
802 ipb
.val1
= cbs
->value
;
803 (void)__vi_send("1", &ipb
);
807 #if defined(__STDC__)
808 static xvi_screen
*create_screen( Widget parent
, int rows
, int cols
)
810 static xvi_screen
*create_screen( parent
, rows
, cols
)
815 xvi_screen
*new_screen
= (xvi_screen
*) calloc( 1, sizeof(xvi_screen
) );
819 new_screen
->color
= COLOR_STANDARD
;
820 new_screen
->parent
= parent
;
822 /* figure out the sizes */
823 new_screen
->rows
= rows
;
824 new_screen
->cols
= cols
;
825 new_screen
->ch_width
= font
->max_bounds
.width
;
826 new_screen
->ch_height
= font
->descent
+ font
->ascent
;
827 new_screen
->ch_descent
= font
->descent
;
828 new_screen
->clip
= NULL
;
830 /* allocate and init the backing stores */
831 resize_backing_store( new_screen
);
833 /* set up a translation table for the X toolkit */
834 if ( area_trans
== NULL
)
835 area_trans
= XtParseTranslationTable(areaTrans
);
837 /* future, new screen gets inserted into the parent sash
838 * immediately after the current screen. Default Pane action is
839 * to add it to the end
842 /* use a form to hold the drawing area and the scrollbar */
843 new_screen
->form
= XtVaCreateManagedWidget( "form",
846 XmNpaneMinimum
, 2*new_screen
->ch_height
,
847 XmNallowResize
, True
,
851 /* create a scrollbar. */
852 new_screen
->scroll
= XtVaCreateManagedWidget( "scroll",
853 xmScrollBarWidgetClass
,
855 XmNtopAttachment
, XmATTACH_FORM
,
856 XmNbottomAttachment
, XmATTACH_FORM
,
857 XmNrightAttachment
, XmATTACH_FORM
,
863 XtAddCallback( new_screen
->scroll
,
864 XmNvalueChangedCallback
,
868 XtAddCallback( new_screen
->scroll
,
874 /* create a frame because they look nice */
875 frame
= XtVaCreateManagedWidget( "frame",
878 XmNshadowType
, XmSHADOW_ETCHED_IN
,
879 XmNtopAttachment
, XmATTACH_FORM
,
880 XmNbottomAttachment
, XmATTACH_FORM
,
881 XmNleftAttachment
, XmATTACH_FORM
,
882 XmNrightAttachment
, XmATTACH_WIDGET
,
883 XmNrightWidget
, new_screen
->scroll
,
887 /* create a drawing area into which we will put text */
888 new_screen
->area
= XtVaCreateManagedWidget( "screen",
889 xmDrawingAreaWidgetClass
,
891 XmNheight
, new_screen
->ch_height
* new_screen
->rows
,
892 XmNwidth
, new_screen
->ch_width
* new_screen
->cols
,
893 XmNtranslations
, area_trans
,
894 XmNuserData
, new_screen
,
895 XmNnavigationType
, XmNONE
,
896 XmNtraversalOn
, False
,
900 /* this callback is for when the drawing area is resized */
901 XtAddCallback( new_screen
->area
,
907 /* this callback is for when the drawing area is exposed */
908 XtAddCallback( new_screen
->area
,
914 /* this callback is for when we expose obscured bits
915 * (e.g. there is a window over part of our drawing area
917 XtAddEventHandler( new_screen
->area
,
918 0, /* no standard events */
919 True
, /* we *WANT* GraphicsExpose */
920 xexpose
, /* what to do */
928 static xvi_screen
*split_screen()
932 int rows
= __vi_screen
->rows
/ 2;
933 xvi_screen
*new_screen
;
935 /* Note that (global) cur_screen needs to be correctly set so that
936 * insert_here knows which screen to put the new one after
938 new_screen
= create_screen( __vi_screen
->parent
,
943 /* what are the screens? */
944 XtVaGetValues( __vi_screen
->parent
,
945 XmNnumChildren
, &num
,
950 /* unmanage all children in preparation for resizing */
951 XtUnmanageChildren( c
, num
);
953 /* force resize of the affected screens */
954 XtVaSetValues( new_screen
->form
,
955 XmNheight
, new_screen
->ch_height
* rows
,
958 XtVaSetValues( __vi_screen
->form
,
959 XmNheight
, __vi_screen
->ch_height
* rows
,
964 XtManageChildren( c
, num
);
971 /* Tell me where to insert the next subpane */
972 #if defined(__STDC__)
973 static Cardinal
insert_here( Widget wid
)
975 static Cardinal
insert_here( wid
)
982 XtVaGetValues( XtParent(wid
),
983 XmNnumChildren
, &num
,
988 /* The default XmNinsertPosition procedure for PanedWindow
989 * causes sashes to be inserted at the end of the list of children
990 * and causes non-sash widgets to be inserted after other
991 * non-sash children but before any sashes.
993 if ( ! XmIsForm( wid
) )
996 /* We will put the widget after the one with the current screen */
997 for (i
=0; i
<num
&& XmIsForm(c
[i
]); i
++) {
998 if ( __vi_screen
== NULL
|| __vi_screen
->form
== c
[i
] )
999 return i
+1; /* after the i-th */
1002 /* could not find it? this should never happen */
1008 * vi_create_editor --
1009 * Create the necessary widgetry.
1011 * PUBLIC: Widget vi_create_editor __P((String, Widget, void (*)(void)));
1014 vi_create_editor(name
, parent
, exitp
)
1017 void (*exitp
) __P((void));
1020 Display
*display
= XtDisplay( parent
);
1024 /* first time through? */
1025 if ( ctx
== NULL
) {
1027 /* save this for later */
1028 ctx
= XtWidgetToApplicationContext( parent
);
1030 /* add our own special actions */
1031 XtAppAddActions( ctx
, area_actions
, XtNumber(area_actions
) );
1033 /* how long is double-click? */
1034 multi_click_length
= XtGetMultiClickTime( display
);
1036 /* check the resource database for interesting resources */
1037 XutConvertResources( parent
,
1043 /* we need a context for moving bits around in the windows */
1044 __vi_copy_gc
= XCreateGC( display
,
1045 DefaultRootWindow(display
),
1050 /* routines for inter client communications conventions */
1051 __vi_InitCopyPaste( f_copy
, f_paste
, f_clear
, fprintf
);
1054 /* create the paned window */
1055 pane_w
= XtVaCreateManagedWidget( "pane",
1056 xmPanedWindowWidgetClass
,
1058 XmNinsertPosition
, insert_here
,
1062 /* allocate our data structure. in the future we will have several
1063 * screens running around at the same time
1065 __vi_screen
= create_screen( pane_w
, 24, 80 );
1067 /* force creation of our color text context */
1068 set_gc_colors( __vi_screen
, COLOR_STANDARD
);
1075 /* These routines deal with the selection buffer */
1077 static int selection_start
, selection_end
, selection_anchor
;
1078 static enum select_enum
{
1079 select_char
, select_word
, select_line
1080 } select_type
= select_char
;
1081 static int last_click
;
1083 static char *clipboard
= NULL
;
1084 static int clipboard_size
= 0,
1088 #if defined(__STDC__)
1089 static void copy_to_clipboard( xvi_screen
*cur_screen
)
1091 static void copy_to_clipboard( cur_screen
)
1092 xvi_screen
*cur_screen
;
1095 /* for now, copy from the backing store. in the future,
1096 * vi core will tell us exactly what the selection buffer contains
1098 clipboard_length
= 1 + selection_end
- selection_start
;
1100 if ( clipboard
== NULL
)
1101 clipboard
= (char *) malloc( clipboard_length
);
1102 else if ( clipboard_size
< clipboard_length
)
1103 clipboard
= (char *) realloc( clipboard
, clipboard_length
);
1106 cur_screen
->characters
+ selection_start
,
1112 #if defined(__STDC__)
1113 static void mark_selection( xvi_screen
*cur_screen
, int start
, int end
)
1115 static void mark_selection( cur_screen
, start
, end
)
1116 xvi_screen
*cur_screen
;
1123 for ( i
=start
; i
<=end
; i
++ ) {
1124 if ( !( cur_screen
->flags
[i
] & COLOR_SELECT
) ) {
1125 cur_screen
->flags
[i
] |= COLOR_SELECT
;
1126 ToRowCol( cur_screen
, i
, row
, col
);
1127 __vi_draw_text( cur_screen
, row
, col
, 1 );
1133 #if defined(__STDC__)
1134 static void erase_selection( xvi_screen
*cur_screen
, int start
, int end
)
1136 static void erase_selection( cur_screen
, start
, end
)
1137 xvi_screen
*cur_screen
;
1144 for ( i
=start
; i
<=end
; i
++ ) {
1145 if ( cur_screen
->flags
[i
] & COLOR_SELECT
) {
1146 cur_screen
->flags
[i
] &= ~COLOR_SELECT
;
1147 ToRowCol( cur_screen
, i
, row
, col
);
1148 __vi_draw_text( cur_screen
, row
, col
, 1 );
1154 #if defined(__STDC__)
1155 static void left_expand_selection( xvi_screen
*cur_screen
, int *start
)
1157 static void left_expand_selection( cur_screen
, start
)
1158 xvi_screen
*cur_screen
;
1164 switch ( select_type
) {
1166 if ( *start
== 0 || isspace( cur_screen
->characters
[*start
] ) )
1169 if ( isspace( cur_screen
->characters
[*start
-1] ) )
1171 if ( --(*start
) == 0 )
1175 ToRowCol( cur_screen
, *start
, row
, col
);
1177 *start
= Linear( cur_screen
, row
, col
);
1183 #if defined(__STDC__)
1184 static void right_expand_selection( xvi_screen
*cur_screen
, int *end
)
1186 static void right_expand_selection( cur_screen
, end
)
1187 xvi_screen
*cur_screen
;
1191 int row
, col
, last
= cur_screen
->cols
* cur_screen
->rows
- 1;
1193 switch ( select_type
) {
1195 if ( *end
== last
|| isspace( cur_screen
->characters
[*end
] ) )
1198 if ( isspace( cur_screen
->characters
[*end
+1] ) )
1200 if ( ++(*end
) == last
)
1204 ToRowCol( cur_screen
, *end
, row
, col
);
1205 col
= cur_screen
->cols
-1;
1206 *end
= Linear( cur_screen
, row
, col
);
1212 #if defined(__STDC__)
1213 static void select_start( Widget widget
,
1219 static void select_start( widget
, event
, str
, cardinal
)
1226 char buffer
[BufferSize
];
1229 XPointerMovedEvent
*ev
= (XPointerMovedEvent
*) event
;
1230 static int last_click
;
1233 * NOTE: when multiple panes are implemented, we need to find the correct
1234 * screen. For now, there is only one.
1236 xpos
= COLUMN( __vi_screen
, ev
->x
);
1237 ypos
= ROW( __vi_screen
, ev
->y
);
1239 /* Remove the old one. */
1240 erase_selection( __vi_screen
, selection_start
, selection_end
);
1242 /* Send the new cursor position. */
1243 ipb
.code
= VI_MOUSE_MOVE
;
1246 (void)__vi_send("12", &ipb
);
1248 /* click-click, and we go for words, lines, etc */
1249 if ( ev
->time
- last_click
< multi_click_length
)
1250 select_type
= (enum select_enum
) ((((int)select_type
)+1)%3);
1252 select_type
= select_char
;
1253 last_click
= ev
->time
;
1255 /* put the selection here */
1256 selection_anchor
= Linear( __vi_screen
, ypos
, xpos
);
1257 selection_start
= selection_anchor
;
1258 selection_end
= selection_anchor
;
1260 /* expand to include words, line, etc */
1261 left_expand_selection( __vi_screen
, &selection_start
);
1262 right_expand_selection( __vi_screen
, &selection_end
);
1264 /* draw the new one */
1265 mark_selection( __vi_screen
, selection_start
, selection_end
);
1267 /* and tell the window manager we own the selection */
1268 if ( select_type
!= select_char
) {
1269 __vi_AcquirePrimary( widget
);
1270 copy_to_clipboard( __vi_screen
);
1275 #if defined(__STDC__)
1276 static void select_extend( Widget widget
,
1282 static void select_extend( widget
, event
, str
, cardinal
)
1289 int xpos
, ypos
, pos
;
1290 XPointerMovedEvent
*ev
= (XPointerMovedEvent
*) event
;
1292 /* NOTE: when multiple panes are implemented, we need to find
1293 * the correct screen. For now, there is only one.
1295 xpos
= COLUMN( __vi_screen
, ev
->x
);
1296 ypos
= ROW( __vi_screen
, ev
->y
);
1298 /* deal with words, lines, etc */
1299 pos
= Linear( __vi_screen
, ypos
, xpos
);
1300 if ( pos
< selection_anchor
)
1301 left_expand_selection( __vi_screen
, &pos
);
1303 right_expand_selection( __vi_screen
, &pos
);
1305 /* extend from before the start? */
1306 if ( pos
< selection_start
) {
1307 mark_selection( __vi_screen
, pos
, selection_start
-1 );
1308 selection_start
= pos
;
1311 /* extend past the end? */
1312 else if ( pos
> selection_end
) {
1313 mark_selection( __vi_screen
, selection_end
+1, pos
);
1314 selection_end
= pos
;
1317 /* between the anchor and the start? */
1318 else if ( pos
< selection_anchor
) {
1319 erase_selection( __vi_screen
, selection_start
, pos
-1 );
1320 selection_start
= pos
;
1323 /* between the anchor and the end? */
1325 erase_selection( __vi_screen
, pos
+1, selection_end
);
1326 selection_end
= pos
;
1329 /* and tell the window manager we own the selection */
1330 __vi_AcquirePrimary( widget
);
1331 copy_to_clipboard( __vi_screen
);
1335 #if defined(__STDC__)
1336 static void select_paste( Widget widget
,
1342 static void select_paste( widget
, event
, str
, cardinal
)
1349 __vi_PasteFromClipboard( widget
);
1353 /* Interface to copy and paste
1354 * (a) callbacks from the window manager
1355 * f_copy - it wants our buffer
1356 * f_paste - it wants us to paste some text
1357 * f_clear - we've lost the selection, clear it
1360 #if defined(__STDC__)
1361 static void f_copy( String
*buffer
, int *len
)
1363 static void f_copy( buffer
, len
)
1369 trace("f_copy() called");
1371 *buffer
= clipboard
;
1372 *len
= clipboard_length
;
1377 static void f_paste( widget
, buffer
, length
)
1378 int widget
, buffer
, length
;
1380 /* NOTE: when multiple panes are implemented, we need to find
1381 * the correct screen. For now, there is only one.
1384 trace("f_paste() called with '%*.*s'\n", length
, length
, buffer
);
1389 #if defined(__STDC__)
1390 static void f_clear( Widget widget
)
1392 static void f_clear( widget
)
1396 xvi_screen
*cur_screen
;
1399 trace("f_clear() called");
1402 XtVaGetValues( widget
, XmNuserData
, &cur_screen
, 0 );
1404 erase_selection( cur_screen
, selection_start
, selection_end
);
1409 * These routines deal with the cursor.
1411 * PUBLIC: void __vi_set_cursor __P((xvi_screen *, int));
1414 __vi_set_cursor(cur_screen
, is_busy
)
1415 xvi_screen
*cur_screen
;
1418 XDefineCursor( XtDisplay(cur_screen
->area
),
1419 XtWindow(cur_screen
->area
),
1420 (is_busy
) ? busy_cursor
: std_cursor
1426 /* hooks for the tags widget */
1428 static String cur_word
= NULL
;
1431 __vi_set_word_at_caret( this_screen
)
1432 xvi_screen
*this_screen
;
1434 char *start
, *end
, save
;
1437 newx
= this_screen
->curx
;
1438 newy
= this_screen
->cury
;
1440 /* Note that this really ought to be done by core due to wrapping issues */
1441 for ( end
= start
= CharAt( this_screen
, newy
, newx
);
1442 (isalnum( *end
) || *end
== '_') && (newx
< this_screen
->cols
);
1447 if ( cur_word
!= NULL
) free( cur_word
);
1448 cur_word
= strdup( start
);
1451 /* if the tag stack widget is active, set the text field there
1452 * to agree with the current caret position.
1454 __vi_set_tag_text( cur_word
);
1458 String
__vi_get_word_at_caret( this_screen
)
1459 xvi_screen
*this_screen
;
1461 return (cur_word
) ? cur_word
: "";
1466 * These routines deal with the caret.
1468 * PUBLIC: void draw_caret __P((xvi_screen *));
1471 draw_caret(this_screen
)
1472 xvi_screen
*this_screen
;
1474 /* draw the caret by drawing the text in highlight color */
1475 *FlagAt( this_screen
, this_screen
->cury
, this_screen
->curx
) |= COLOR_CARET
;
1476 __vi_draw_text( this_screen
, this_screen
->cury
, this_screen
->curx
, 1 );
1480 * PUBLIC: void __vi_erase_caret __P((xvi_screen *));
1483 __vi_erase_caret(this_screen
)
1484 xvi_screen
*this_screen
;
1486 /* erase the caret by drawing the text in normal video */
1487 *FlagAt( this_screen
, this_screen
->cury
, this_screen
->curx
) &= ~COLOR_CARET
;
1488 __vi_draw_text( this_screen
, this_screen
->cury
, this_screen
->curx
, 1 );
1492 * PUBLIC: void __vi_move_caret __P((xvi_screen *, int, int));
1495 __vi_move_caret(this_screen
, newy
, newx
)
1496 xvi_screen
*this_screen
;
1499 /* remove the old caret */
1500 __vi_erase_caret( this_screen
);
1502 /* caret is now here */
1503 this_screen
->curx
= newx
;
1504 this_screen
->cury
= newy
;
1505 draw_caret( this_screen
);