Remove building with NOCRYPTO option
[minix.git] / external / bsd / nvi / dist / motif_l / m_vi.c
blobb0894bee0cfb83e328291edbdff549b35a6c8733
1 /* $NetBSD: m_vi.c,v 1.3 2014/01/26 21:43:45 christos Exp $ */
2 * Copyright (c) 1996
3 * Rob Zimmermann. All rights reserved.
4 * Copyright (c) 1996
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #include <sys/cdefs.h>
13 #if 0
14 #ifndef lint
15 static const char sccsid[] = "Id: m_vi.c,v 8.41 2003/11/05 17:10:01 skimo Exp (Berkeley) Date: 2003/11/05 17:10:01 ";
16 #endif /* not lint */
17 #else
18 __RCSID("$NetBSD: m_vi.c,v 1.3 2014/01/26 21:43:45 christos Exp $");
19 #endif
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>
29 #include <Xm/Form.h>
30 #include <Xm/Frame.h>
31 #include <Xm/ScrollBar.h>
33 #include <bitstring.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
43 #undef LOCK_SUCCESS
44 #include "../common/common.h"
45 #include "../ipc/ip.h"
46 #include "m_motif.h"
47 #include "vi_mextern.h"
48 #include "pathnames.h"
50 extern int vi_ofd;
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;
64 static GC gc;
65 GC __vi_copy_gc;
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
81 * messages.
82 * To that end, we set scroll_block when we receive input from the scrollbar,
83 * and we clear it when we process the IPO_REFRESH message from core.
84 * A specific SCROLL_COMPLETED message would be better, but this seems to work.
87 static Boolean scroll_block = False;
90 * PUBLIC: void __vi_set_scroll_block __P((void));
92 void
93 __vi_set_scroll_block(void)
95 scroll_block = True;
99 * PUBLIC: void __vi_clear_scroll_block __P((void));
101 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 )
110 #else
111 static void set_gc_colors( this_screen, val )
112 xvi_screen *this_screen;
113 int val;
114 #endif
116 static Pixel fg, bg, hi, shade;
117 static int prev = COLOR_INVALID;
119 /* no change? */
120 if ( prev == val ) return;
122 /* init? */
123 if ( gc == NULL ) {
125 /* what colors are selected for the drawing area? */
126 XtVaGetValues( this_screen->area,
127 XtNbackground, &bg,
128 XtNforeground, &fg,
129 XmNhighlightColor, &hi,
130 XmNtopShadowColor, &shade,
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 );
152 else switch (val) {
153 case COLOR_STANDARD:
154 XSetForeground( XtDisplay(this_screen->area), gc, fg );
155 XSetBackground( XtDisplay(this_screen->area), gc, bg );
156 break;
157 case COLOR_INVERSE:
158 XSetForeground( XtDisplay(this_screen->area), gc, bg );
159 XSetBackground( XtDisplay(this_screen->area), gc, fg );
160 break;
161 default: /* implement color map later */
162 break;
168 * Memory utilities
171 #ifdef REALLOC
172 #undef REALLOC
173 #endif
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
184 * drawing areas
187 void select_start();
188 void select_extend();
189 void select_paste();
190 void key_press();
191 void insert_string();
192 void beep __P((Widget w));
193 void find();
194 void command();
196 static XtActionsRec area_actions[] = {
197 { "select_start", select_start },
198 { "select_extend", select_extend },
199 { "select_paste", select_paste },
200 { "key_press", key_press },
201 { "insert_string", insert_string },
202 { "beep", beep },
203 { "find", find },
204 { "command", command },
207 char areaTrans[] =
208 "<Btn1Down>: select_start() \n\
209 <Btn1Motion>: select_extend() \n\
210 <Btn2Down>: select_paste() \n\
211 <Btn3Down>: select_extend() \n\
212 <Btn3Motion>: select_extend() \n\
213 <Key>End: command(VI_C_BOTTOM) \n\
214 <Key>Escape: command(EINSERT) \n\
215 <Key>Find: find() \n\
216 <Key>Home: command(VI_C_TOP) \n\
217 <Key>Next: command(VI_C_PGDOWN) \n\
218 <Key>Prior: command(VI_C_PGUP) \n\
219 <Key>osfBackSpace: command(VI_C_LEFT) \n\
220 <Key>osfBeginLine: command(VI_C_BOL) \n\
221 <Key>osfCopy: beep() \n\
222 <Key>osfCut: beep() \n\
223 <Key>osfDelete: command(VI_C_DEL) \n\
224 <Key>osfDown: command(VI_C_DOWN) \n\
225 <Key>osfEndLine: command(VI_C_EOL) \n\
226 <Key>osfInsert: command(VI_C_INSERT) \n\
227 <Key>osfLeft: command(VI_C_LEFT) \n\
228 <Key>osfPageDown: command(VI_C_PGDOWN) \n\
229 <Key>osfPageUp: command(VI_C_PGUP) \n\
230 <Key>osfPaste: insert_string(p) \n\
231 <Key>osfRight: command(VI_C_RIGHT) \n\
232 <Key>osfUndo: command(VI_UNDO) \n\
233 <Key>osfUp: command(VI_C_UP) \n\
234 Ctrl<Key>C: command(VI_INTERRUPT) \n\
235 <Key>: key_press()";
238 static XutResource resource[] = {
239 { "font", XutRKfont, &font },
240 { "pointerShape", XutRKcursor, &std_cursor },
241 { "busyShape", XutRKcursor, &busy_cursor },
246 * vi_input_func --
247 * We've received input on the pipe from vi.
249 * PUBLIC: void vi_input_func __P((XtPointer, int *, XtInputId *));
251 void
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);
257 #ifdef notdef
258 /* Check the pipe for unused events when not busy. */
259 XtAppAddWorkProc(ctx, process_pipe_input, NULL);
260 #endif
265 /* Send the window size. */
266 #if defined(__STDC__)
267 static void send_resize( xvi_screen *this_screen )
268 #else
269 static void send_resize( this_screen )
270 xvi_screen *this_screen;
271 #endif
273 IP_BUF ipb;
275 ipb.val1 = this_screen->rows;
276 ipb.val2 = this_screen->cols;
277 ipb.code = VI_RESIZE;
279 #ifdef TRACE
280 vtrace("resize_func ( %d x %d )\n", this_screen->rows, this_screen->cols);
281 #endif
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 )
290 #else
291 static void resize_backing_store( this_screen )
292 xvi_screen *this_screen;
293 #endif
295 int total_chars = this_screen->rows * this_screen->cols;
297 this_screen->characters = REALLOC( this_screen->characters,
298 total_chars
300 memset( this_screen->characters, ' ', total_chars );
302 this_screen->flags = REALLOC( this_screen->flags,
303 total_chars
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,
314 XtPointer call_data
316 #else
317 static void resize_func( wid, client_data, call_data )
318 Widget wid;
319 XtPointer client_data;
320 XtPointer call_data;
321 #endif
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 );
338 * __vi_draw_text --
339 * Draw from backing store.
341 * PUBLIC: void __vi_draw_text __P((xvi_screen *, int, int, int));
343 void
344 __vi_draw_text(xvi_screen *this_screen, int row, int start_col, int len)
346 int col, color, xpos;
347 char *start, *end;
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 */
354 for ( col=start_col;
355 col<this_screen->cols && col<start_col+len;
356 col++ ) {
358 /* has the color changed? */
359 if ( *FlagAt( __vi_screen, row, col ) == color )
360 continue;
362 /* is there anything to write? */
363 end = CharAt( __vi_screen, row, col );
364 if ( end == start )
365 continue;
367 /* yes. write in the previous color */
368 set_gc_colors( __vi_screen, color );
370 /* add to display */
371 XDrawImageString( XtDisplay(__vi_screen->area),
372 XtWindow(__vi_screen->area),
374 xpos,
375 YPOS( __vi_screen, row ),
376 start,
377 end - start
380 /* this is the new context */
381 color = *FlagAt( __vi_screen, row, col );
382 xpos = XPOS( __vi_screen, col );
383 start = end;
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 );
392 /* add to display */
393 XDrawImageString( XtDisplay(__vi_screen->area),
394 XtWindow(__vi_screen->area),
396 xpos,
397 YPOS( __vi_screen, row ),
398 start,
399 end - start
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 )
408 #else
409 static void add_to_clip( cur_screen, x, y, width, height )
410 xvi_screen *cur_screen;
411 int x;
412 int y;
413 int width;
414 int height;
415 #endif
417 XRectangle rect;
418 rect.x = x;
419 rect.y = y;
420 rect.height = height;
421 rect.width = width;
422 if ( cur_screen->clip == NULL )
423 cur_screen->clip = XCreateRegion();
424 XUnionRectWithRegion( &rect, cur_screen->clip, cur_screen->clip );
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
433 * and call_data.
435 * PUBLIC: void __vi_expose_func __P((Widget, XtPointer, XtPointer));
437 void
438 __vi_expose_func(Widget wid, XtPointer client_data, XtPointer call_data)
440 xvi_screen *this_screen;
441 XmDrawingAreaCallbackStruct *cbs;
442 XExposeEvent *xev;
443 XGraphicsExposeEvent *gev;
444 int row;
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;
461 return;
464 if ( call_data == NULL ) {
466 /* vi core calls this when it wants a full refresh */
467 #ifdef TRACE
468 vtrace("expose_func: full refresh\n");
469 #endif
471 XClearWindow( XtDisplay(this_screen->area),
472 XtWindow(this_screen->area)
475 else {
476 switch ( cbs->event->type ) {
478 case GraphicsExpose:
479 gev = (XGraphicsExposeEvent *) cbs->event;
481 /* set clipping rectangles accordingly */
482 add_to_clip( this_screen,
483 gev->x, gev->y,
484 gev->width, gev->height
487 /* X calls here when XCopyArea exposes new bits */
488 #ifdef TRACE
489 vtrace("expose_func (X): (x=%d,y=%d,w=%d,h=%d), count=%d\n",
490 gev->x, gev->y,
491 gev->width, gev->height,
492 gev->count);
493 #endif
495 /* more coming? do it then */
496 if ( gev->count > 0 ) return;
498 /* set clipping region */
499 XSetRegion( XtDisplay(wid), gc, this_screen->clip );
500 break;
502 case Expose:
503 xev = (XExposeEvent *) cbs->event;
505 /* set clipping rectangles accordingly */
506 add_to_clip( this_screen,
507 xev->x, xev->y,
508 xev->width, xev->height
511 /* Motif calls here when DrawingArea is exposed */
512 #ifdef TRACE
513 vtrace("expose_func (Motif): (x=%d,y=%d,w=%d,h=%d), count=%d\n",
514 xev->x, xev->y,
515 xev->width, xev->height,
516 xev->count);
517 #endif
519 /* more coming? do it then */
520 if ( xev->count > 0 ) return;
522 /* set clipping region */
523 XSetRegion( XtDisplay(wid), gc, this_screen->clip );
524 break;
526 default:
527 /* don't care? */
528 return;
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,
552 XEvent *ev,
553 Boolean *cont
555 #else
556 static void xexpose ( w, client_data, ev, cont )
557 Widget w;
558 XtPointer client_data;
559 XEvent *ev;
560 Boolean *cont;
561 #endif
563 XmDrawingAreaCallbackStruct cbs;
565 switch ( ev->type ) {
566 case GraphicsExpose:
567 cbs.event = ev;
568 cbs.window = XtWindow(w);
569 cbs.reason = XmCR_EXPOSE;
570 __vi_expose_func( w, client_data, (XtPointer) &cbs );
571 *cont = False; /* we took care of it */
572 break;
573 default:
574 /* don't care */
575 break;
580 /* unimplemented keystroke or command */
581 #if defined(__STDC__)
582 static void beep( Widget w )
583 #else
584 static void beep( w )
585 Widget w;
586 #endif
588 XBell(XtDisplay(w),0);
592 /* give me a search dialog */
593 #if defined(__STDC__)
594 static void find( Widget w )
595 #else
596 static void find( w )
597 Widget w;
598 #endif
600 __vi_show_search_dialog( w, "Find" );
604 * command --
605 * Translate simple keyboard input into vi protocol commands.
607 static void
608 command(Widget widget, XKeyEvent *event, String *str, Cardinal *cardinal)
610 static struct {
611 String name;
612 int code;
613 int count;
614 } table[] = {
615 { "VI_C_BOL", VI_C_BOL, 0 },
616 { "VI_C_BOTTOM", VI_C_BOTTOM, 0 },
617 { "VI_C_DEL", VI_C_DEL, 0 },
618 { "VI_C_DOWN", VI_C_DOWN, 1 },
619 { "VI_C_EOL", VI_C_EOL, 0 },
620 { "VI_C_INSERT", VI_C_INSERT, 0 },
621 { "VI_C_LEFT", VI_C_LEFT, 0 },
622 { "VI_C_PGDOWN", VI_C_PGDOWN, 1 },
623 { "VI_C_PGUP", VI_C_PGUP, 1 },
624 { "VI_C_RIGHT", VI_C_RIGHT, 0 },
625 { "VI_C_TOP", VI_C_TOP, 0 },
626 { "VI_C_UP", VI_C_UP, 1 },
627 { "VI_INTERRUPT", VI_INTERRUPT, 0 },
629 IP_BUF ipb;
630 int i;
633 * XXX
634 * Do fast lookup based on character #6 -- sleazy, but I don't
635 * want to do 10 strcmp's per keystroke.
637 ipb.val1 = 1;
638 for (i = 0; i < XtNumber(table); i++)
639 if (table[i].name[6] == (*str)[6] &&
640 strcmp(table[i].name, *str) == 0) {
641 ipb.code = table[i].code;
642 vi_send(vi_ofd, table[i].count ? "1" : NULL, &ipb);
643 return;
646 /* oops. */
647 beep(widget);
650 /* mouse or keyboard input. */
651 #if defined(__STDC__)
652 static void insert_string( Widget widget,
653 XKeyEvent *event,
654 String *str,
655 Cardinal *cardinal
657 #else
658 static void insert_string( widget, event, str, cardinal )
659 Widget widget;
660 XKeyEvent *event;
661 String *str;
662 Cardinal *cardinal;
663 #endif
665 IP_BUF ipb;
667 ipb.len1 = strlen( *str );
668 if ( ipb.len1 != 0 ) {
669 ipb.code = VI_STRING;
670 ipb.str1 = *str;
671 vi_send(vi_ofd, "a", &ipb);
674 #ifdef TRACE
675 vtrace("insert_string {%.*s}\n", strlen( *str ), *str );
676 #endif
680 /* mouse or keyboard input. */
681 #if defined(__STDC__)
682 static void key_press( Widget widget,
683 XKeyEvent *event,
684 String str,
685 Cardinal *cardinal
687 #else
688 static void key_press( widget, event, str, cardinal )
689 Widget widget;
690 XKeyEvent *event;
691 String str;
692 Cardinal *cardinal;
693 #endif
695 IP_BUF ipb;
696 char bp[BufferSize];
698 ipb.len1 = XLookupString( event, bp, BufferSize, NULL, NULL );
699 if ( ipb.len1 != 0 ) {
700 ipb.code = VI_STRING;
701 ipb.str1 = bp;
702 #ifdef TRACE
703 vtrace("key_press {%.*s}\n", ipb.len1, bp );
704 #endif
705 vi_send(vi_ofd, "a", &ipb);
711 #if defined(__STDC__)
712 static void scrollbar_moved( Widget widget,
713 XtPointer ptr,
714 XmScrollBarCallbackStruct *cbs
716 #else
717 static void scrollbar_moved( widget, ptr, cbs )
718 Widget widget;
719 XtPointer ptr;
720 XmScrollBarCallbackStruct *cbs;
721 #endif
723 /* Future: Need to scroll the correct screen! */
724 xvi_screen *cur_screen = (xvi_screen *) ptr;
725 IP_BUF ipb;
727 /* if we are still processing messages from core, skip this event
728 * (see comments near __vi_set_scroll_block())
730 if ( scroll_block ) {
731 return;
733 __vi_set_scroll_block();
735 #ifdef TRACE
736 switch ( cbs->reason ) {
737 case XmCR_VALUE_CHANGED:
738 vtrace( "scrollbar VALUE_CHANGED %d\n", cbs->value );
739 break;
740 case XmCR_DRAG:
741 vtrace( "scrollbar DRAG %d\n", cbs->value );
742 break;
743 default:
744 vtrace( "scrollbar <default> %d\n", cbs->value );
745 break;
747 vtrace("scrollto {%d}\n", cbs->value );
748 #endif
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 )
759 #else
760 static xvi_screen *create_screen( parent, rows, cols )
761 Widget parent;
762 int rows, cols;
763 #endif
765 xvi_screen *new_screen = (xvi_screen *) calloc( 1, sizeof(xvi_screen) );
766 Widget frame;
768 /* init... */
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",
794 xmFormWidgetClass,
795 parent,
796 XmNpaneMinimum, 2*new_screen->ch_height,
797 XmNallowResize, True,
798 NULL
801 /* create a scrollbar. */
802 new_screen->scroll = XtVaCreateManagedWidget( "scroll",
803 xmScrollBarWidgetClass,
804 new_screen->form,
805 XmNtopAttachment, XmATTACH_FORM,
806 XmNbottomAttachment, XmATTACH_FORM,
807 XmNrightAttachment, XmATTACH_FORM,
808 XmNminimum, 1,
809 XmNmaximum, 2,
810 XmNsliderSize, 1,
811 NULL
813 XtAddCallback( new_screen->scroll,
814 XmNvalueChangedCallback,
815 scrollbar_moved,
816 new_screen
818 XtAddCallback( new_screen->scroll,
819 XmNdragCallback,
820 scrollbar_moved,
821 new_screen
824 /* create a frame because they look nice */
825 frame = XtVaCreateManagedWidget( "frame",
826 xmFrameWidgetClass,
827 new_screen->form,
828 XmNshadowType, XmSHADOW_ETCHED_IN,
829 XmNtopAttachment, XmATTACH_FORM,
830 XmNbottomAttachment, XmATTACH_FORM,
831 XmNleftAttachment, XmATTACH_FORM,
832 XmNrightAttachment, XmATTACH_WIDGET,
833 XmNrightWidget, new_screen->scroll,
834 NULL
837 /* create a drawing area into which we will put text */
838 new_screen->area = XtVaCreateManagedWidget( "screen",
839 xmDrawingAreaWidgetClass,
840 frame,
841 XmNheight, new_screen->ch_height * new_screen->rows,
842 XmNwidth, new_screen->ch_width * new_screen->cols,
843 XmNtranslations, area_trans,
844 XmNuserData, new_screen,
845 XmNnavigationType, XmNONE,
846 XmNtraversalOn, False,
847 NULL
850 /* this callback is for when the drawing area is resized */
851 XtAddCallback( new_screen->area,
852 XmNresizeCallback,
853 resize_func,
854 new_screen
857 /* this callback is for when the drawing area is exposed */
858 XtAddCallback( new_screen->area,
859 XmNexposeCallback,
860 __vi_expose_func,
861 new_screen
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 */
871 new_screen
874 return new_screen;
878 static xvi_screen *split_screen(void)
880 Cardinal num;
881 WidgetList c;
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,
889 rows,
890 __vi_screen->cols
893 /* what are the screens? */
894 XtVaGetValues( __vi_screen->parent,
895 XmNnumChildren, &num,
896 XmNchildren, &c,
897 NULL
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,
906 NULL
908 XtVaSetValues( __vi_screen->form,
909 XmNheight, __vi_screen->ch_height * rows,
910 NULL
913 /* re-manage */
914 XtManageChildren( c, num );
916 /* done */
917 return new_screen;
921 /* Tell me where to insert the next subpane */
922 #if defined(__STDC__)
923 static Cardinal insert_here( Widget wid )
924 #else
925 static Cardinal insert_here( wid )
926 Widget wid;
927 #endif
929 Cardinal i, num;
930 WidgetList c;
932 XtVaGetValues( XtParent(wid),
933 XmNnumChildren, &num,
934 XmNchildren, &c,
935 NULL
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 ) )
944 return num;
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 */
953 return num;
958 * vi_create_editor --
959 * Create the necessary widgetry.
961 * PUBLIC: Widget vi_create_editor __P((String, Widget, void (*)(void)));
963 Widget
964 vi_create_editor(String name, Widget parent, void (*exitp) (void))
966 Widget pane_w;
967 Display *display = XtDisplay( parent );
969 __vi_exitp = exitp;
971 /* first time through? */
972 if ( ctx == NULL ) {
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,
985 vi_progname,
986 resource,
987 XtNumber(resource)
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,
1004 parent,
1005 XmNinsertPosition, insert_here,
1006 NULL
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 );
1017 /* done */
1018 return pane_w;
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,
1032 clipboard_length;
1035 #if defined(__STDC__)
1036 static void copy_to_clipboard( xvi_screen *cur_screen )
1037 #else
1038 static void copy_to_clipboard( cur_screen )
1039 xvi_screen *cur_screen;
1040 #endif
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 );
1052 memcpy( clipboard,
1053 cur_screen->characters + selection_start,
1054 clipboard_length
1059 #if defined(__STDC__)
1060 static void mark_selection( xvi_screen *cur_screen, int start, int end )
1061 #else
1062 static void mark_selection( cur_screen, start, end )
1063 xvi_screen *cur_screen;
1064 int start;
1065 int end;
1066 #endif
1068 int row, col, i;
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 )
1082 #else
1083 static void erase_selection( cur_screen, start, end )
1084 xvi_screen *cur_screen;
1085 int start;
1086 int end;
1087 #endif
1089 int row, col, i;
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 )
1103 #else
1104 static void left_expand_selection( cur_screen, start )
1105 xvi_screen *cur_screen;
1106 int *start;
1107 #endif
1109 int row, col;
1111 switch ( select_type ) {
1112 case select_word:
1113 if ( *start == 0 || isspace( (unsigned char)cur_screen->characters[*start] ) )
1114 return;
1115 for (;;) {
1116 if ( isspace( (unsigned char)cur_screen->characters[*start-1] ) )
1117 return;
1118 if ( --(*start) == 0 )
1119 return;
1121 case select_line:
1122 ToRowCol( cur_screen, *start, row, col );
1123 col = 0;
1124 *start = Linear( cur_screen, row, col );
1125 break;
1130 #if defined(__STDC__)
1131 static void right_expand_selection( xvi_screen *cur_screen, int *end )
1132 #else
1133 static void right_expand_selection( cur_screen, end )
1134 xvi_screen *cur_screen;
1135 int *end;
1136 #endif
1138 int row, col, last = cur_screen->cols * cur_screen->rows - 1;
1140 switch ( select_type ) {
1141 case select_word:
1142 if ( *end == last || isspace( (unsigned char)cur_screen->characters[*end] ) )
1143 return;
1144 for (;;) {
1145 if ( isspace( (unsigned char)cur_screen->characters[*end+1] ) )
1146 return;
1147 if ( ++(*end) == last )
1148 return;
1150 case select_line:
1151 ToRowCol( cur_screen, *end, row, col );
1152 col = cur_screen->cols -1;
1153 *end = Linear( cur_screen, row, col );
1154 break;
1159 #if defined(__STDC__)
1160 static void select_start( Widget widget,
1161 XEvent *event,
1162 String str,
1163 Cardinal *cardinal
1165 #else
1166 static void select_start( widget, event, str, cardinal )
1167 Widget widget;
1168 XEvent *event;
1169 String str;
1170 Cardinal *cardinal;
1171 #endif
1173 IP_BUF ipb;
1174 int xpos, ypos;
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;
1190 ipb.val1 = ypos;
1191 ipb.val2 = xpos;
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);
1197 else
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,
1223 XEvent *event,
1224 String str,
1225 Cardinal *cardinal
1227 #else
1228 static void select_extend( widget, event, str, cardinal )
1229 Widget widget;
1230 XEvent *event;
1231 String str;
1232 Cardinal *cardinal;
1233 #endif
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 );
1248 else
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? */
1270 else {
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,
1283 XEvent *event,
1284 String str,
1285 Cardinal *cardinal
1287 #else
1288 static void select_paste( widget, event, str, cardinal )
1289 Widget widget;
1290 XEvent *event;
1291 String str;
1292 Cardinal *cardinal;
1293 #endif
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 )
1308 #else
1309 static void f_copy( buffer, len )
1310 String *buffer;
1311 int *len;
1312 #endif
1314 #ifdef TRACE
1315 vtrace("f_copy() called");
1316 #endif
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.
1328 #ifdef TRACE
1329 vtrace("f_paste() called with '%*.*s'\n", length, length, buffer);
1330 #endif
1334 #if defined(__STDC__)
1335 static void f_clear( Widget widget )
1336 #else
1337 static void f_clear( widget )
1338 Widget widget;
1339 #endif
1341 xvi_screen *cur_screen;
1343 #ifdef TRACE
1344 vtrace("f_clear() called");
1345 #endif
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));
1358 void
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 *));
1376 void
1377 __vi_set_word_at_caret(xvi_screen *this_screen)
1379 char *start, *end, save;
1380 int newx, newy;
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);
1388 end++, newx++
1390 save = *end;
1391 *end = '\0';
1392 if ( cur_word != NULL ) free( cur_word );
1393 cur_word = strdup( start );
1394 *end = save;
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 *));
1414 static void
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 *));
1425 void
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));
1436 void
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 );