1 /* $NetBSD: m_vi.c,v 1.3 2014/01/26 21:43:45 christos Exp $ */
3 * Rob Zimmermann
. All rights reserved
.
5 * Keith Bostic
. All rights reserved
.
7 * See the LICENSE file
for redistribution information
.
12 #include <sys/cdefs.h>
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 ";
18 __RCSID("$NetBSD: m_vi.c,v 1.3 2014/01/26 21:43:45 christos Exp $");
21 #include <sys/types.h>
22 #include <sys/queue.h>
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>
31 #include <Xm/ScrollBar.h>
33 #include <bitstring.h>
44 #include "../common/common.h"
45 #include "../ipc/ip.h"
47 #include "vi_mextern.h"
48 #include "pathnames.h"
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
);
58 * Globals and costants
61 #define BufferSize 1024
63 static XFontStruct
*font
;
66 static XtAppContext ctx
;
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
;
74 void (*__vi_exitp
)(); /* Exit function. */
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
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.
87 static Boolean scroll_block
= False
;
90 * PUBLIC: void __vi_set_scroll_block __P((void));
93 __vi_set_scroll_block(void)
99 * PUBLIC: void __vi_clear_scroll_block __P((void));
102 __vi_clear_scroll_block(void)
104 scroll_block
= False
;
108 #if defined(__STDC__)
109 static void set_gc_colors( xvi_screen
*this_screen
, int val
)
111 static void set_gc_colors( this_screen
, val
)
112 xvi_screen
*this_screen
;
116 static Pixel fg
, bg
, hi
, shade
;
117 static int prev
= COLOR_INVALID
;
120 if ( prev
== val
) return;
125 /* what colors are selected for the drawing area? */
126 XtVaGetValues( this_screen
->area
,
129 XmNhighlightColor
, &hi
,
130 XmNtopShadowColor
, &shade
,
134 gc
= XCreateGC( XtDisplay(this_screen
->area
),
135 DefaultRootWindow(XtDisplay(this_screen
->area
)),
140 XSetFont( XtDisplay(this_screen
->area
), gc
, font
->fid
);
143 /* special colors? */
144 if ( val
& COLOR_CARET
) {
145 XSetForeground( XtDisplay(this_screen
->area
), gc
, fg
);
146 XSetBackground( XtDisplay(this_screen
->area
), gc
, hi
);
148 else if ( val
& COLOR_SELECT
) {
149 XSetForeground( XtDisplay(this_screen
->area
), gc
, fg
);
150 XSetBackground( XtDisplay(this_screen
->area
), gc
, shade
);
154 XSetForeground( XtDisplay(this_screen
->area
), gc
, fg
);
155 XSetBackground( XtDisplay(this_screen
->area
), gc
, bg
);
158 XSetForeground( XtDisplay(this_screen
->area
), gc
, bg
);
159 XSetBackground( XtDisplay(this_screen
->area
), gc
, fg
);
161 default: /* implement color map later */
175 #define REALLOC( ptr, size ) \
176 ((ptr == NULL) ? malloc(size) : realloc(ptr,size))
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
188 void select_extend();
191 void insert_string();
192 void beep
__P((Widget w
));
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
},
204 { "command", command
},
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\
238 static XutResource resource
[] = {
239 { "font", XutRKfont
, &font
},
240 { "pointerShape", XutRKcursor
, &std_cursor
},
241 { "busyShape", XutRKcursor
, &busy_cursor
},
247 * We've received input on the pipe from vi.
249 * PUBLIC: void vi_input_func __P((XtPointer, int *, XtInputId *));
252 vi_input_func(XtPointer client_data
, int *source
, XtInputId
*id
)
254 /* Parse and dispatch on commands in the queue. */
255 (void)ipvi_motif
->input(ipvi_motif
, *source
);
258 /* Check the pipe for unused events when not busy. */
259 XtAppAddWorkProc(ctx
, process_pipe_input
, NULL
);
265 /* Send the window size. */
266 #if defined(__STDC__)
267 static void send_resize( xvi_screen
*this_screen
)
269 static void send_resize( this_screen
)
270 xvi_screen
*this_screen
;
275 ipb
.val1
= this_screen
->rows
;
276 ipb
.val2
= this_screen
->cols
;
277 ipb
.code
= VI_RESIZE
;
280 vtrace("resize_func ( %d x %d )\n", this_screen
->rows
, this_screen
->cols
);
283 /* send up the pipe */
284 vi_send(vi_ofd
, "12", &ipb
);
288 #if defined(__STDC__)
289 static void resize_backing_store( xvi_screen
*this_screen
)
291 static void resize_backing_store( this_screen
)
292 xvi_screen
*this_screen
;
295 int total_chars
= this_screen
->rows
* this_screen
->cols
;
297 this_screen
->characters
= REALLOC( this_screen
->characters
,
300 memset( this_screen
->characters
, ' ', total_chars
);
302 this_screen
->flags
= REALLOC( this_screen
->flags
,
305 memset( this_screen
->flags
, 0, total_chars
);
310 /* X will call this when we are resized */
311 #if defined(__STDC__)
312 static void resize_func( Widget wid
,
313 XtPointer client_data
,
317 static void resize_func( wid
, client_data
, call_data
)
319 XtPointer client_data
;
323 xvi_screen
*this_screen
= (xvi_screen
*) client_data
;
324 Dimension height
, width
;
326 XtVaGetValues( wid
, XmNheight
, &height
, XmNwidth
, &width
, 0 );
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
;
332 resize_backing_store( this_screen
);
333 send_resize( this_screen
);
339 * Draw from backing store.
341 * PUBLIC: void __vi_draw_text __P((xvi_screen *, int, int, int));
344 __vi_draw_text(xvi_screen
*this_screen
, int row
, int start_col
, int len
)
346 int col
, color
, xpos
;
349 start
= CharAt( __vi_screen
, row
, start_col
);
350 color
= *FlagAt( __vi_screen
, row
, start_col
);
351 xpos
= XPOS( __vi_screen
, start_col
);
353 /* one column at a time */
355 col
<this_screen
->cols
&& col
<start_col
+len
;
358 /* has the color changed? */
359 if ( *FlagAt( __vi_screen
, row
, col
) == color
)
362 /* is there anything to write? */
363 end
= CharAt( __vi_screen
, row
, col
);
367 /* yes. write in the previous color */
368 set_gc_colors( __vi_screen
, color
);
371 XDrawImageString( XtDisplay(__vi_screen
->area
),
372 XtWindow(__vi_screen
->area
),
375 YPOS( __vi_screen
, row
),
380 /* this is the new context */
381 color
= *FlagAt( __vi_screen
, row
, col
);
382 xpos
= XPOS( __vi_screen
, col
);
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
);
393 XDrawImageString( XtDisplay(__vi_screen
->area
),
394 XtWindow(__vi_screen
->area
),
397 YPOS( __vi_screen
, row
),
405 /* set clipping rectangles accordingly */
406 #if defined(__STDC__)
407 static void add_to_clip( xvi_screen
*cur_screen
, int x
, int y
, int width
, int height
)
409 static void add_to_clip( cur_screen
, x
, y
, width
, height
)
410 xvi_screen
*cur_screen
;
420 rect
.height
= height
;
422 if ( cur_screen
->clip
== NULL
)
423 cur_screen
->clip
= XCreateRegion();
424 XUnionRectWithRegion( &rect
, cur_screen
->clip
, cur_screen
->clip
);
429 * __vi_expose_func --
430 * Redraw the window's contents.
432 * NOTE: When vi wants to force a redraw, we are called with NULL widget
435 * PUBLIC: void __vi_expose_func __P((Widget, XtPointer, XtPointer));
438 __vi_expose_func(Widget wid
, XtPointer client_data
, XtPointer call_data
)
440 xvi_screen
*this_screen
;
441 XmDrawingAreaCallbackStruct
*cbs
;
443 XGraphicsExposeEvent
*gev
;
446 /* convert pointers */
447 this_screen
= (xvi_screen
*) client_data
;
448 cbs
= (XmDrawingAreaCallbackStruct
*) call_data
;
450 /* first exposure? tell vi we are ready... */
451 if ( this_screen
->init
== False
) {
453 /* what does the user want to see? */
454 __vi_set_cursor( __vi_screen
, False
);
456 /* vi wants a resize as the first event */
457 send_resize( __vi_screen
);
459 /* fine for now. we'll be back */
460 this_screen
->init
= True
;
464 if ( call_data
== NULL
) {
466 /* vi core calls this when it wants a full refresh */
468 vtrace("expose_func: full refresh\n");
471 XClearWindow( XtDisplay(this_screen
->area
),
472 XtWindow(this_screen
->area
)
476 switch ( cbs
->event
->type
) {
479 gev
= (XGraphicsExposeEvent
*) cbs
->event
;
481 /* set clipping rectangles accordingly */
482 add_to_clip( this_screen
,
484 gev
->width
, gev
->height
487 /* X calls here when XCopyArea exposes new bits */
489 vtrace("expose_func (X): (x=%d,y=%d,w=%d,h=%d), count=%d\n",
491 gev
->width
, gev
->height
,
495 /* more coming? do it then */
496 if ( gev
->count
> 0 ) return;
498 /* set clipping region */
499 XSetRegion( XtDisplay(wid
), gc
, this_screen
->clip
);
503 xev
= (XExposeEvent
*) cbs
->event
;
505 /* set clipping rectangles accordingly */
506 add_to_clip( this_screen
,
508 xev
->width
, xev
->height
511 /* Motif calls here when DrawingArea is exposed */
513 vtrace("expose_func (Motif): (x=%d,y=%d,w=%d,h=%d), count=%d\n",
515 xev
->width
, xev
->height
,
519 /* more coming? do it then */
520 if ( xev
->count
> 0 ) return;
522 /* set clipping region */
523 XSetRegion( XtDisplay(wid
), gc
, this_screen
->clip
);
532 /* one row at a time */
533 for (row
=0; row
<this_screen
->rows
; row
++) {
535 /* draw from the backing store */
536 __vi_draw_text( this_screen
, row
, 0, this_screen
->cols
);
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
;
549 #if defined(__STDC__)
550 static void xexpose ( Widget w
,
551 XtPointer client_data
,
556 static void xexpose ( w
, client_data
, ev
, cont
)
558 XtPointer client_data
;
563 XmDrawingAreaCallbackStruct cbs
;
565 switch ( ev
->type
) {
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 */
580 /* unimplemented keystroke or command */
581 #if defined(__STDC__)
582 static void beep( Widget w
)
584 static void beep( w
)
588 XBell(XtDisplay(w
),0);
592 /* give me a search dialog */
593 #if defined(__STDC__)
594 static void find( Widget w
)
596 static void find( w
)
600 __vi_show_search_dialog( w
, "Find" );
605 * Translate simple keyboard input into vi protocol commands.
608 command(Widget widget
, XKeyEvent
*event
, String
*str
, Cardinal
*cardinal
)
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 },
634 * Do fast lookup based on character #6 -- sleazy, but I don't
635 * want to do 10 strcmp's per keystroke.
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
);
650 /* mouse or keyboard input. */
651 #if defined(__STDC__)
652 static void insert_string( Widget widget
,
658 static void insert_string( widget
, event
, str
, cardinal
)
667 ipb
.len1
= strlen( *str
);
668 if ( ipb
.len1
!= 0 ) {
669 ipb
.code
= VI_STRING
;
671 vi_send(vi_ofd
, "a", &ipb
);
675 vtrace("insert_string {%.*s}\n", strlen( *str
), *str
);
680 /* mouse or keyboard input. */
681 #if defined(__STDC__)
682 static void key_press( Widget widget
,
688 static void key_press( widget
, event
, str
, cardinal
)
698 ipb
.len1
= XLookupString( event
, bp
, BufferSize
, NULL
, NULL
);
699 if ( ipb
.len1
!= 0 ) {
700 ipb
.code
= VI_STRING
;
703 vtrace("key_press {%.*s}\n", ipb
.len1
, bp
);
705 vi_send(vi_ofd
, "a", &ipb
);
711 #if defined(__STDC__)
712 static void scrollbar_moved( Widget widget
,
714 XmScrollBarCallbackStruct
*cbs
717 static void scrollbar_moved( widget
, ptr
, cbs
)
720 XmScrollBarCallbackStruct
*cbs
;
723 /* Future: Need to scroll the correct screen! */
724 xvi_screen
*cur_screen
= (xvi_screen
*) ptr
;
727 /* if we are still processing messages from core, skip this event
728 * (see comments near __vi_set_scroll_block())
730 if ( scroll_block
) {
733 __vi_set_scroll_block();
736 switch ( cbs
->reason
) {
737 case XmCR_VALUE_CHANGED
:
738 vtrace( "scrollbar VALUE_CHANGED %d\n", cbs
->value
);
741 vtrace( "scrollbar DRAG %d\n", cbs
->value
);
744 vtrace( "scrollbar <default> %d\n", cbs
->value
);
747 vtrace("scrollto {%d}\n", cbs
->value
);
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
);
757 #if defined(__STDC__)
758 static xvi_screen
*create_screen( Widget parent
, int rows
, int cols
)
760 static xvi_screen
*create_screen( parent
, rows
, cols
)
765 xvi_screen
*new_screen
= (xvi_screen
*) calloc( 1, sizeof(xvi_screen
) );
769 new_screen
->color
= COLOR_STANDARD
;
770 new_screen
->parent
= parent
;
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
;
780 /* allocate and init the backing stores */
781 resize_backing_store( new_screen
);
783 /* set up a translation table for the X toolkit */
784 if ( area_trans
== NULL
)
785 area_trans
= XtParseTranslationTable(areaTrans
);
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
792 /* use a form to hold the drawing area and the scrollbar */
793 new_screen
->form
= XtVaCreateManagedWidget( "form",
796 XmNpaneMinimum
, 2*new_screen
->ch_height
,
797 XmNallowResize
, True
,
801 /* create a scrollbar. */
802 new_screen
->scroll
= XtVaCreateManagedWidget( "scroll",
803 xmScrollBarWidgetClass
,
805 XmNtopAttachment
, XmATTACH_FORM
,
806 XmNbottomAttachment
, XmATTACH_FORM
,
807 XmNrightAttachment
, XmATTACH_FORM
,
813 XtAddCallback( new_screen
->scroll
,
814 XmNvalueChangedCallback
,
818 XtAddCallback( new_screen
->scroll
,
824 /* create a frame because they look nice */
825 frame
= XtVaCreateManagedWidget( "frame",
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
,
837 /* create a drawing area into which we will put text */
838 new_screen
->area
= XtVaCreateManagedWidget( "screen",
839 xmDrawingAreaWidgetClass
,
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
,
850 /* this callback is for when the drawing area is resized */
851 XtAddCallback( new_screen
->area
,
857 /* this callback is for when the drawing area is exposed */
858 XtAddCallback( new_screen
->area
,
864 /* this callback is for when we expose obscured bits
865 * (e.g. there is a window over part of our drawing area
867 XtAddEventHandler( new_screen
->area
,
868 0, /* no standard events */
869 True
, /* we *WANT* GraphicsExpose */
870 xexpose
, /* what to do */
878 static xvi_screen
*split_screen(void)
882 int rows
= __vi_screen
->rows
/ 2;
883 xvi_screen
*new_screen
;
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
888 new_screen
= create_screen( __vi_screen
->parent
,
893 /* what are the screens? */
894 XtVaGetValues( __vi_screen
->parent
,
895 XmNnumChildren
, &num
,
900 /* unmanage all children in preparation for resizing */
901 XtUnmanageChildren( c
, num
);
903 /* force resize of the affected screens */
904 XtVaSetValues( new_screen
->form
,
905 XmNheight
, new_screen
->ch_height
* rows
,
908 XtVaSetValues( __vi_screen
->form
,
909 XmNheight
, __vi_screen
->ch_height
* rows
,
914 XtManageChildren( c
, num
);
921 /* Tell me where to insert the next subpane */
922 #if defined(__STDC__)
923 static Cardinal
insert_here( Widget wid
)
925 static Cardinal
insert_here( wid
)
932 XtVaGetValues( XtParent(wid
),
933 XmNnumChildren
, &num
,
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.
943 if ( ! XmIsForm( wid
) )
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 */
952 /* could not find it? this should never happen */
958 * vi_create_editor --
959 * Create the necessary widgetry.
961 * PUBLIC: Widget vi_create_editor __P((String, Widget, void (*)(void)));
964 vi_create_editor(String name
, Widget parent
, void (*exitp
) (void))
967 Display
*display
= XtDisplay( parent
);
971 /* first time through? */
974 /* save this for later */
975 ctx
= XtWidgetToApplicationContext( parent
);
977 /* add our own special actions */
978 XtAppAddActions( ctx
, area_actions
, XtNumber(area_actions
) );
980 /* how long is double-click? */
981 multi_click_length
= XtGetMultiClickTime( display
);
983 /* check the resource database for interesting resources */
984 __XutConvertResources( parent
,
990 /* we need a context for moving bits around in the windows */
991 __vi_copy_gc
= XCreateGC( display
,
992 DefaultRootWindow(display
),
997 /* routines for inter client communications conventions */
998 __vi_InitCopyPaste( f_copy
, f_paste
, f_clear
, fprintf
);
1001 /* create the paned window */
1002 pane_w
= XtVaCreateManagedWidget( "pane",
1003 xmPanedWindowWidgetClass
,
1005 XmNinsertPosition
, insert_here
,
1009 /* allocate our data structure. in the future we will have several
1010 * screens running around at the same time
1012 __vi_screen
= create_screen( pane_w
, 24, 80 );
1014 /* force creation of our color text context */
1015 set_gc_colors( __vi_screen
, COLOR_STANDARD
);
1022 /* These routines deal with the selection buffer */
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
;
1030 static char *clipboard
= NULL
;
1031 static int clipboard_size
= 0,
1035 #if defined(__STDC__)
1036 static void copy_to_clipboard( xvi_screen
*cur_screen
)
1038 static void copy_to_clipboard( cur_screen
)
1039 xvi_screen
*cur_screen
;
1042 /* for now, copy from the backing store. in the future,
1043 * vi core will tell us exactly what the selection buffer contains
1045 clipboard_length
= 1 + selection_end
- selection_start
;
1047 if ( clipboard
== NULL
)
1048 clipboard
= (char *) malloc( clipboard_length
);
1049 else if ( clipboard_size
< clipboard_length
)
1050 clipboard
= (char *) realloc( clipboard
, clipboard_length
);
1053 cur_screen
->characters
+ selection_start
,
1059 #if defined(__STDC__)
1060 static void mark_selection( xvi_screen
*cur_screen
, int start
, int end
)
1062 static void mark_selection( cur_screen
, start
, end
)
1063 xvi_screen
*cur_screen
;
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 );
1080 #if defined(__STDC__)
1081 static void erase_selection( xvi_screen
*cur_screen
, int start
, int end
)
1083 static void erase_selection( cur_screen
, start
, end
)
1084 xvi_screen
*cur_screen
;
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 );
1101 #if defined(__STDC__)
1102 static void left_expand_selection( xvi_screen
*cur_screen
, int *start
)
1104 static void left_expand_selection( cur_screen
, start
)
1105 xvi_screen
*cur_screen
;
1111 switch ( select_type
) {
1113 if ( *start
== 0 || isspace( (unsigned char)cur_screen
->characters
[*start
] ) )
1116 if ( isspace( (unsigned char)cur_screen
->characters
[*start
-1] ) )
1118 if ( --(*start
) == 0 )
1122 ToRowCol( cur_screen
, *start
, row
, col
);
1124 *start
= Linear( cur_screen
, row
, col
);
1130 #if defined(__STDC__)
1131 static void right_expand_selection( xvi_screen
*cur_screen
, int *end
)
1133 static void right_expand_selection( cur_screen
, end
)
1134 xvi_screen
*cur_screen
;
1138 int row
, col
, last
= cur_screen
->cols
* cur_screen
->rows
- 1;
1140 switch ( select_type
) {
1142 if ( *end
== last
|| isspace( (unsigned char)cur_screen
->characters
[*end
] ) )
1145 if ( isspace( (unsigned char)cur_screen
->characters
[*end
+1] ) )
1147 if ( ++(*end
) == last
)
1151 ToRowCol( cur_screen
, *end
, row
, col
);
1152 col
= cur_screen
->cols
-1;
1153 *end
= Linear( cur_screen
, row
, col
);
1159 #if defined(__STDC__)
1160 static void select_start( Widget widget
,
1166 static void select_start( widget
, event
, str
, cardinal
)
1175 XPointerMovedEvent
*ev
= (XPointerMovedEvent
*) event
;
1176 static int last_click
;
1179 * NOTE: when multiple panes are implemented, we need to find the correct
1180 * screen. For now, there is only one.
1182 xpos
= COLUMN( __vi_screen
, ev
->x
);
1183 ypos
= ROW( __vi_screen
, ev
->y
);
1185 /* Remove the old one. */
1186 erase_selection( __vi_screen
, selection_start
, selection_end
);
1188 /* Send the new cursor position. */
1189 ipb
.code
= VI_MOUSE_MOVE
;
1192 (void)vi_send(vi_ofd
, "12", &ipb
);
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);
1198 select_type
= select_char
;
1199 last_click
= ev
->time
;
1201 /* put the selection here */
1202 selection_anchor
= Linear( __vi_screen
, ypos
, xpos
);
1203 selection_start
= selection_anchor
;
1204 selection_end
= selection_anchor
;
1206 /* expand to include words, line, etc */
1207 left_expand_selection( __vi_screen
, &selection_start
);
1208 right_expand_selection( __vi_screen
, &selection_end
);
1210 /* draw the new one */
1211 mark_selection( __vi_screen
, selection_start
, selection_end
);
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
);
1221 #if defined(__STDC__)
1222 static void select_extend( Widget widget
,
1228 static void select_extend( widget
, event
, str
, cardinal
)
1235 int xpos
, ypos
, pos
;
1236 XPointerMovedEvent
*ev
= (XPointerMovedEvent
*) event
;
1238 /* NOTE: when multiple panes are implemented, we need to find
1239 * the correct screen. For now, there is only one.
1241 xpos
= COLUMN( __vi_screen
, ev
->x
);
1242 ypos
= ROW( __vi_screen
, ev
->y
);
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
);
1249 right_expand_selection( __vi_screen
, &pos
);
1251 /* extend from before the start? */
1252 if ( pos
< selection_start
) {
1253 mark_selection( __vi_screen
, pos
, selection_start
-1 );
1254 selection_start
= pos
;
1257 /* extend past the end? */
1258 else if ( pos
> selection_end
) {
1259 mark_selection( __vi_screen
, selection_end
+1, pos
);
1260 selection_end
= pos
;
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
;
1269 /* between the anchor and the end? */
1271 erase_selection( __vi_screen
, pos
+1, selection_end
);
1272 selection_end
= pos
;
1275 /* and tell the window manager we own the selection */
1276 __vi_AcquirePrimary( widget
);
1277 copy_to_clipboard( __vi_screen
);
1281 #if defined(__STDC__)
1282 static void select_paste( Widget widget
,
1288 static void select_paste( widget
, event
, str
, cardinal
)
1295 __vi_PasteFromClipboard( widget
);
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
1306 #if defined(__STDC__)
1307 static void f_copy( String
*buffer
, int *len
)
1309 static void f_copy( buffer
, len
)
1315 vtrace("f_copy() called");
1317 *buffer
= clipboard
;
1318 *len
= clipboard_length
;
1323 static void f_paste(int widget
, int buffer
, int length
)
1325 /* NOTE: when multiple panes are implemented, we need to find
1326 * the correct screen. For now, there is only one.
1329 vtrace("f_paste() called with '%*.*s'\n", length
, length
, buffer
);
1334 #if defined(__STDC__)
1335 static void f_clear( Widget widget
)
1337 static void f_clear( widget
)
1341 xvi_screen
*cur_screen
;
1344 vtrace("f_clear() called");
1347 XtVaGetValues( widget
, XmNuserData
, &cur_screen
, 0 );
1349 erase_selection( cur_screen
, selection_start
, selection_end
);
1354 * These routines deal with the cursor.
1356 * PUBLIC: void __vi_set_cursor __P((xvi_screen *, int));
1359 __vi_set_cursor(xvi_screen
*cur_screen
, int is_busy
)
1361 XDefineCursor( XtDisplay(cur_screen
->area
),
1362 XtWindow(cur_screen
->area
),
1363 (is_busy
) ? busy_cursor
: std_cursor
1369 /* hooks for the tags widget */
1371 static String cur_word
= NULL
;
1374 * PUBLIC: void __vi_set_word_at_caret __P((xvi_screen *));
1377 __vi_set_word_at_caret(xvi_screen
*this_screen
)
1379 char *start
, *end
, save
;
1382 newx
= this_screen
->curx
;
1383 newy
= this_screen
->cury
;
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
);
1392 if ( cur_word
!= NULL
) free( cur_word
);
1393 cur_word
= strdup( start
);
1396 /* if the tag stack widget is active, set the text field there
1397 * to agree with the current caret position.
1399 __vi_set_tag_text( cur_word
);
1403 String
__vi_get_word_at_caret(xvi_screen
*this_screen
)
1405 return (cur_word
) ? cur_word
: "";
1410 * These routines deal with the caret.
1412 * PUBLIC: void draw_caret __P((xvi_screen *));
1415 draw_caret(xvi_screen
*this_screen
)
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 );
1423 * PUBLIC: void __vi_erase_caret __P((xvi_screen *));
1426 __vi_erase_caret(xvi_screen
*this_screen
)
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 );
1434 * PUBLIC: void __vi_move_caret __P((xvi_screen *, int, int));
1437 __vi_move_caret(xvi_screen
*this_screen
, int newy
, int newx
)
1439 /* remove the old caret */
1440 __vi_erase_caret( this_screen
);
1442 /* caret is now here */
1443 this_screen
->curx
= newx
;
1444 this_screen
->cury
= newy
;
1445 draw_caret( this_screen
);