1 
2 /*
3 	edx/emx (EDitor for X) (C) 2002, Terry Loveall
4 	released into the public domain.
5 	Based upon the original work ee.c of Yijun Ding, copyright 1991 which is
6 	in the public domain.
7 	This program comes with no warranties or binaries. Use at your own risk.
8 */
9 
10 #include <stdio.h>
11 #include <string.h>
12 #include <sys/stat.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15 #include <signal.h>
16 #include <pwd.h>
17 #include <X11/Xlib.h>
18 #include <X11/Xatom.h>
19 #include <X11/Xutil.h>
20 #include <X11/Xos.h>
21 #define  XK_MISCELLANY
22 #include <X11/keysymdef.h>
23 #include <sys/time.h>
24 
25 #ifdef MINIMAL
26 #define DEFAULT_HEIGHT 25
27 #else
28 #define DEFAULT_HEIGHT 32
29 #endif
30 
31 #define DEFAULT_WIDTH 80
32 
33 /* turns on display of keypressed event values in upper right corner */
34 /* #define DEBUG */
35 
36 /*
37 #define FONTNAME  "-b&h-lucidatypewriter-medium-r-normal-sans-12-*-*-*-m-70-iso8859-1"
38 #define FONTNAME	"-b&h-lucidatypewriter-bold-r-normal-sans-12-*-*-*-m-70-iso8859-1"
39 #define FONTNAME "9x15bold"
40 */
41 #ifdef TLL
42 #define FONTNAME	"-b&h-lucidatypewriter-bold-r-normal-sans-12-*-*-*-m-70-iso8859-1"
43 #else
44 #define FONTNAME "8x13"
45 #endif
46 
47 #define X11
48 
49 /* #define cprintf(s,v) { char str[350]; sprintf(str,s,v); cputs(str); } */
50 
51 #/************************************************************/
52 
53 /* use MS style COORD to track cursor pos */
54 typedef struct {
55 	int X;		/* x coordinate */
56 	int Y;		/* y coordinate */
57 } COORD;		/* x-y structure */
58 
59 COORD outxy;	/* cursor coordinates for screen positioning */
60 
61 #/************************************************************/
62 
63 /* X related globals */
64 Display *dpy;
65 Window win;
66 GC gc;
67 XFontStruct *font;
68 /*
69 int Ascent, Descent;
70 */	/* font max y excursions */
71 XEvent event;
72 XKeyEvent *keve;
73 Time eve_time;
74 char *selection_text;	/* selected text for X clipboard */
75 char *comment;
76 int selection_length;
77 int expose;
78 int vtot, vcur, pos, ftheight; /* global variables for scrollbar */
79 
80 int Width, Height;
81 int fwidth, fheight, ycur = 0;	/* font character width, height */
82 
83 /* Foreground, Background normal and highlight colores */
84 XColor FgXColor, BgXColor, CrXColor,
85        HiFgXColor, HiBgXColor;
86 
87 int HiLo;						/* hightlight status, 0=off */
88 Atom DeleteWindow;				/* Atom of delete window message */
89 
90 /* char *FgColor="Black", *BgColor="Linen", *HiFgColor="Black", *HiBgColor="Grey75"; */
91 #ifdef DARK
92 char	*FgColor="Yellow",
93 	*BgColor="Black",
94 	*CrColor="White",
95 #else
96 char	*FgColor="Black",
97 	*BgColor="White",
98 	*CrColor="Red",
99 #endif
100 	*HiFgColor="Black",
101 	*HiBgColor="Grey84";
102 char *FontName=NULL;
103 char *DisplayName=NULL;
104 char *AppName;
105 char *RcFile = NULL;
106 
107 char *Geometry=NULL;
108 /* maximum viewable 6x8 chars on a 2000x1600 screen */
109 #define MAXVLINE 450
110 char eolbuf[MAXVLINE];	/* holds spaces for clreol(), 450 is 2000x1600 */
111 
112 /* func prototypes */
113 
114 void gotoxy(int horz,int vert);
115 void cursor_draw(unsigned long color);
116 void draw_cursor();
117 void undraw_cursor();
118 void drawstring(char *str, int len);
119 void cputs(char *prntstr);
120 int putch(char chr);
121 void clreol();
122 void highvideo();
123 void lowvideo();
124 void clrscr();
125 void bell();
126 void show_vbar();
127 void update();
128 void scroll_text();
129 void sig_handler(int);
130 void font_height(void);
131 int paste_primary(int win, int property, int Delete);
132 int request_selection(int time);
133 char *mrealloc(char *s, int len);
134 void set_selection();
135 void send_selection(XSelectionRequestEvent * rq);
136 void init(int argc,char *argv[]);
137 void handle_key(char *astr, int skey, int state);
138 void moveto();
139 void do_paste();
140 void do_select(int delete);
141 void iconify();
142 void set_title(char *str);
143 
144 /* for monolithic whole include engine here */
145 
146 #include "version.h"
147 #include "messages.def"
148 #include "edit.h"
149 
150 #ifdef EMACS
151 #include "x11_bind_em.c"
152 #endif
153 #ifdef WORDSTAR
154 #include "x11_bind_ws.c"
155 #endif
156 
157 /******************** Start of cursor I/O ********************/
158 
159 /* Goto the specified location. */
160 
gotoxy(int horz,int vert)161 void gotoxy(int horz,int vert)
162 {
163 		outxy.X = horz;
164 		outxy.Y = vert;
165 }
166 
cursor_draw(unsigned long color)167 void cursor_draw(unsigned long color)
168 {
169 	XSetForeground(dpy, gc, color);
170 #ifdef VERTCURS
171 	XDrawRectangle(dpy, win, gc,
172 		(outxy.X * fwidth) + 2, (outxy.Y * fheight) + 2,
173 		0, fheight - 0);
174 #else
175 #ifdef BOXCURS
176 	XDrawRectangle(dpy, win, gc,
177 		(outxy.X * fwidth) + 1, (outxy.Y * fheight) + 2,
178 		fwidth, fheight);
179 #else
180 	XFillRectangle(dpy, win, gc,
181 		(outxy.X * fwidth) + 2, ((outxy.Y+1)* fheight) + 2,
182 		fwidth-1, 2);
183 #endif
184 #endif
185 	XSetForeground(dpy, gc, HiLo ? HiFgXColor.pixel : FgXColor.pixel);
186 }
187 
draw_cursor()188 void draw_cursor()
189 {
190   /*
191         cursor_draw( HiLo ? HiFgXColor.pixel : FgXColor.pixel);
192   */
193 	cursor_draw( CrXColor.pixel);
194 }
195 
undraw_cursor()196 void undraw_cursor()
197 {
198 	cursor_draw( HiLo ? HiBgXColor.pixel : BgXColor.pixel);
199 }
200 
drawstring(char * str,int len)201 void drawstring(char *str, int len)
202 {
203 	if (outxy.X+len>screen_width+1) len = screen_width+1-outxy.X;
204 	XDrawImageString(dpy, win, gc, (outxy.X * fwidth) + 2,
205             (outxy.Y+1) * fheight, str, len > 0 ? len : 0);
206 }
207 
putch(char chr)208 int putch(char chr)
209 {
210 	static char str[]="\0\0";
211 
212 	if(chr >= ' '){
213 		str[0] = chr;
214 		drawstring(str, 1);
215 		outxy.X += 1;
216 	}
217 
218 	if(!(chr) || ((chr & 0xff) == LF)){
219 		clreol();
220 		outxy.X = 0;
221 		outxy.Y += 1;
222 	}
223 	return 0;
224 }
225 
cputs(char * prntstr)226 void cputs(char *prntstr)
227 {
228 	int strl = strlen(prntstr);
229 
230 	drawstring(prntstr, strl);
231 	outxy.X += strl;
232 }
233 
234 /* Erase from cursor to end of line. */
235 
clreol()236 void clreol()
237 {
238 		int tmpx = outxy.X;
239 		int eollen = abs(screen_width+1 - tmpx);
240 		outxy.X = outxy.X <= screen_width ? outxy.X : screen_width+1;
241 		drawstring(eolbuf, eollen);
242 		outxy.X = tmpx;
243 }
244 
245 /* display string if visible, bump X */
246 
highvideo()247 void highvideo()
248 {
249 		XSetBackground(dpy,gc,HiBgXColor.pixel);
250 		XSetForeground(dpy,gc,HiFgXColor.pixel);
251 		HiLo = -1;
252 }
253 
lowvideo()254 void lowvideo()
255 {
256 		XSetBackground(dpy,gc,BgXColor.pixel);
257 		XSetForeground(dpy,gc,FgXColor.pixel);
258 		HiLo = 0;
259 }
260 
clrscr()261 void clrscr()
262 {
263 		XClearWindow(dpy,win);
264 }
265 
bell()266 void bell()
267 {
268 		XBell(dpy,100);
269 }
270 
show_vbar()271 void show_vbar()
272 {
273 	int j;
274 
275 	/* display buffer screen height in pixels */
276 	vtot = (screen_height-2)*fheight - font->descent;
277 
278 	/* font true height as a constant */
279 	ftheight = fheight+font->descent+1;
280 
281 	/* thumb height is display buffer percentage of total lines */
282 	vcur = (vtot*(screen_height-1))/((ytot)?ytot:1);
283 
284 	/* min thumb size is 1 char */
285 	if (vcur<fheight) vcur = fheight;
286 
287 	/* max thumb size is 2/3 vtot */
288 	j = 2*vtot/3;
289 	if (vcur>j) vcur = j;
290 
291 	/* current line number to vertical thumb pos */
292 	pos = (ytru * (vtot-(vcur-fheight)))/((ytot)? ytot:1);
293 
294 	/* draw scrollbar through */
295 	XSetForeground(dpy,gc,HiBgXColor.pixel);
296 #ifdef THREED	// provide background for line scroll triangles
297 	XFillRectangle(dpy, win, gc, Width-10, 0, 10, Height);
298 #else	/* indicate line scroll rectangles */
299 	XFillRectangle(dpy, win, gc, Width-10, ftheight, 10, Height+2-2*(ftheight));
300 #endif /* THREED */
301 
302 	/* draw thumb */
303 	XSetForeground(dpy,gc,~HiBgXColor.pixel);
304 	XDrawRectangle(dpy, win, gc, Width-9, ftheight+pos, 8, vcur);
305 
306 #ifdef THREED
307 	{
308 		XPoint opoints[] ={{Width-10,ftheight-1},{10,0},
309 						   {-5,-9},{-5,9},
310 						   {0,Height+2-(2*(ftheight))},{5,9},
311 						   {5,-9},{-10,0}
312 						  };
313 		XSegment lpoints[] ={{Width-1, ftheight+pos, Width-9, ftheight+pos},
314 							 {Width-9, ftheight+pos, Width-9, ftheight+pos+vcur},
315 							 {Width-9, ftheight-2, Width-6, ftheight-9},
316 							 {Width-9, Height+2-ftheight, Width-6, Height+3-ftheight+6}
317 							};
318 
319 		/* outline trough and end triangles */
320 		XDrawLines(dpy, win, gc, opoints, 8, CoordModePrevious);
321 
322 		/* draw in light color for 3D shading */
323 		XSetForeground(dpy, gc, -1);
324 		XDrawSegments(dpy, win, gc, lpoints, 4);
325 	}
326 #endif /* THREED */
327 	lowvideo();
328 }
329 
scroll_text()330 void scroll_text()
331 {
332 	int m, rep;
333 
334         if (ycur<0) { y=0 ; scroll_down(); ycur = 0; }
335         if (ycur>ytot) ycur = ytot;
336 
337         m = (ycur * vtot) / (ytot? ytot : 1);
338 	rep = abs(ytru-ycur)/screen_height;
339 
340 	if(m<0) scroll_down();					/* if cursor at top of screen */
341 	else if(m>vtot+ftheight) scroll_up();	/* if cursor at bottom of screen */
342 	else if(m<pos) {
343 	     for (m=0; m<rep; m++)
344 	         cursor_pageup();		/* if cursor above thumb */
345 	}
346 	else if(m>pos+vcur) {
347 	     for (m=0; m<rep; m++)
348 	         cursor_pagedown();	/* if cursor below thumb */
349 	}
350 
351 	goto_y(ycur);  /* cursor on thumb so track it */
352 
353 	scr_update(); /* does show_vbar */
354 }
355 
356 
update()357 void update()
358 {
359 		flag[SHW] = 1;
360 		show_top();
361 		scr_update();
362 		show_vbar();
363 		if (executive == DIALOG) {
364 			undraw_cursor();
365 			show_gets(comment, diabuf, dblen, dialogCB);
366 			gotoxy(diastart+col,yl1);
367 			draw_cursor();
368 		}
369 }
370 
sig_handler(int nothing)371 void sig_handler(int nothing)
372 {
373 		update();
374 		XFlush(dpy);
375 }
376 
377 /*
378 void font_height(void)
379 {
380 		int foo,bar,baz;
381 		XCharStruct extents;
382 
383 		XTextExtents(font,"OOO|jW6789",10,&foo,&bar,&baz,&extents);
384 		Ascent=extents.ascent;
385 		Descent=extents.descent;
386 }
387 */
388 
389 
paste_primary(int win,int property,int Delete)390 int paste_primary(int win, int property, int Delete)
391 {
392 	Atom actual_type;
393 	int actual_format, i;
394 	long nitem, bytes_after, nread;
395 	unsigned char *data;
396 	char indent = flag[IND];	/* stash autoindent state */
397 
398 	if (property == None)	/* don't paste anything */
399 		return(0);
400 
401 	flag[IND] = 0;	/* off autoindent */
402 	nread = 0;
403 	/* X-selection paste loop */
404 	do {
405 		if (XGetWindowProperty		/* get remaining selection max 1024 chars */
406 			(dpy, win, property, nread / 4, 1024, Delete,
407 			 AnyPropertyType, &actual_type, &actual_format, &nitem,
408 			 &bytes_after, (unsigned char **) &data)
409 			!= Success)
410 			return(0);
411 		update_scr = 0;				/* dont update scr...yet */
412 		/* paste last batch one char at a time */
413 		for(i = 0; i < nitem; handle_key(NULL, data[i++],0));
414 		nread += nitem;
415 		XFree(data);
416 	} while (bytes_after > 0);
417 	update_scr = 1;					/* _now_ update display */
418 	flag[SHW] = 1;
419 	scr_update();
420 	flag[IND] = indent;	/* restore autoindent state */
421 	return(nread);
422 }
423 
request_selection(int time)424 int request_selection(int time)
425 {
426 	Window w;
427 	Atom property;
428 
429 	if ((w = XGetSelectionOwner(dpy, XA_PRIMARY)) == None) {
430 		int tmp = paste_primary(DefaultRootWindow(dpy), XA_CUT_BUFFER0,
431 				  False);
432 		return(tmp);
433 	}
434 	property = XInternAtom(dpy, "VT_SELECTION", False);
435 	XConvertSelection(dpy, XA_PRIMARY, XA_STRING, property, win,
436 			  time);
437 	return(0);
438 }
439 
mrealloc(char * s,int len)440 char *mrealloc(char *s, int len)
441 {
442 		char *ttt;
443 		if(!s) ttt = (char *) malloc(len);
444 		else ttt = (char *) realloc(s, len);
445 		return ttt;
446 }
447 
set_selection()448 void set_selection()
449 {
450 	int i;
451 
452 	if(!flag[BLK] || mk == cur_pos) return;
453 
454 		if(cur_pos < mk)
455 			{ bstart = cur_pos; bend = mk; }
456 		else
457 			{ bstart = mk; bend = cur_pos; }
458 
459 	selection_length = bend - bstart;
460 	if ((selection_text = (char *) mrealloc(selection_text, selection_length)) == NULL) {
461 		printf(SELECT_REALLOC"\n");
462 se_exit:
463 		bell();
464 		return;
465 	}
466 	for (i = 0; i < selection_length; i++) {
467 		selection_text[i] = bstart[i] == EOL ? '\n' : bstart[i];
468 	}
469 	XSetSelectionOwner(dpy, XA_PRIMARY, win, (Time) eve_time);
470 	if (XGetSelectionOwner(dpy, XA_PRIMARY) != win) {
471 		printf(CANT_SELECT"\n");
472 		goto se_exit;
473 	}
474 	XChangeProperty(dpy, DefaultRootWindow(dpy), XA_CUT_BUFFER0,
475 			XA_STRING, 8, PropModeReplace, selection_text,
476 			selection_length);
477 }
478 
send_selection(XSelectionRequestEvent * rq)479 void send_selection(XSelectionRequestEvent * rq)
480 {
481 	XSelectionEvent notify;
482 
483 	notify.type = SelectionNotify;
484 	notify.display = rq->display;
485 	notify.requestor = rq->requestor;
486 	notify.selection = rq->selection;
487 	notify.target = rq->target;
488 	notify.time = rq->time;
489 	XChangeProperty(dpy, rq->requestor, rq->property, XA_STRING, 8,
490 			PropModeReplace, selection_text, selection_length);
491 	notify.property = rq->property;
492 	XSendEvent(dpy, rq->requestor, False, 0, (XEvent *) & notify);
493 }
494 
parse_arg(char * arg1,char * arg2)495 void parse_arg(char *arg1, char *arg2)
496 {
497 	if(*arg1=='-') {
498 		if (!strcasecmp(arg1, "-f"))
499 			strcpy(ewin.name, arg2);
500 		else
501 		if (!strcasecmp(arg1, "-t"))
502 			tabsize = atoi(arg2);
503 		else
504 		if (!strcasecmp(arg1, "-j"))
505 			ewin.jump = atoi(arg2);
506 		else
507 		if (!strcasecmp(arg1, "-w")) {
508 			screen_width = atoi(arg2);
509 			if (screen_width<20) screen_width = 20;
510 			if (screen_width>180) screen_width = 180;
511 		}
512 		else
513 		if (!strcasecmp(arg1, "-h")) {
514 			screen_height = atoi(arg2);
515 			if (screen_height<5) screen_height = 5;
516 			if (screen_height>80) screen_height = 80;
517 		}
518 		else
519 		if (!strcasecmp(arg1, "-fn"))
520 			FontName = strdup(arg2);
521 		else
522 		if (!strcasecmp(arg1, "-rc"))
523 			RcFile = strdup(arg2);
524 		else
525 		if (!strcasecmp(arg1, "-fg"))
526 	        	FgColor = strdup(arg2);
527 		else
528 		if (!strcasecmp(arg1, "-bg"))
529 			BgColor = strdup(arg2);
530 		else
531 		if (!strcasecmp(arg1, "-hifg"))
532 			HiFgColor = strdup(arg2);
533 		else
534 		if (!strcasecmp(arg1, "-hibg"))
535 			HiBgColor = strdup(arg2);
536 		else
537 		if (!strcasecmp(arg1, "-cr"))
538 			CrColor = strdup(arg2);
539 		else
540 		if (!strcasecmp(arg1, "-edit"))
541 		        flag[EDT] = atoi(arg2);
542 	}
543 #ifndef MINIMAL
544 	if(*arg1=='@') {
545 		char *ptr;
546 		int i;
547 		i = tolower(arg1[1])-'a';
548 		if (i>=0 && i<26) {
549 			ptr = arg2;
550 			while(isspace(*ptr)) ++ptr;
551 			if (binding[i]) free(binding[i]);
552 			binding[i] = strdup(ptr);
553 		}
554 	}
555 #endif /* MINIMAL */
556 }
557 
558 #ifndef MINIMAL
parse_rc(FILE * f)559 void parse_rc(FILE *f)
560 {
561 	char buf[512], *ptr;
562 	int i, l;
563 	while ((ptr=fgets(buf, 510, f))) {
564 		while (isspace(*ptr)) ++ptr;
565 	        if (strlen(ptr)<2 || *ptr == '#') continue;
566 		i = 0;
567 		while(ptr[i] && !isspace(ptr[i])) ++i;
568 		if (!ptr[i]) continue;
569 		ptr[i++] = '\0';
570 		if (ptr[i]) {
571 			l = strlen(ptr+i)+i-1;
572 			if (l>=i && ptr[l]=='\n') ptr[l] = '\0';
573 			parse_arg(ptr, ptr+i);
574 		}
575 	}
576 }
577 
read_rc()578 void read_rc()
579 {
580 	FILE *fr = NULL;
581 	char name[NLEN], *ptr;
582 
583 	if ((ptr=getenv("HOME"))) {
584 		if (RcFile) {
585 			if (ptr && *RcFile == '~' && RcFile[1] == '/')
586 				sprintf(name, "%s/%s", ptr, RcFile+2);
587 			else
588 				strcpy(name, RcFile);
589 		}
590 		else
591 			sprintf(name, "%s/.%s", ptr, DEFAULT_RC);
592 		fr = fopen(name, "r");
593 	}
594 
595 	if (!fr) {
596 		sprintf(name, "%s/%s", SHAREDIR, DEFAULT_RC);
597 		fr = fopen(name, "r");
598 	}
599 
600 	if (fr) {
601 		parse_rc(fr);
602 		fclose(fr);
603 	}
604 }
605 #endif /* MINIMAL */
606 
init(int argc,char * argv[])607 void init(int argc,char *argv[])
608 {
609 		int screen;
610 		XWMHints *wmh;
611 		XSizeHints *xsh;
612 		XClassHint *classh;
613 		XColor tmp;
614 		int i, x, y;
615 
616 		/* Default settings */
617 		*ewin.name = '\0';
618 		amax = AMAX;
619 		bmax = BMAX;
620 		umax = UMAX;
621 
622 		/* engine screen width, height, font */
623 		screen_height = DEFAULT_HEIGHT - 1;
624 		screen_width = DEFAULT_WIDTH;
625 
626 #ifndef MINIMAL
627 		memset((void *)binding, 0, 26*sizeof(char *));
628 
629 		for (i=1; i<argc; i++) {
630 			if (i<argc-1 && !strcasecmp(argv[i], "-rc"))
631 			RcFile = strdup(argv[++i]);
632 		}
633 		read_rc();
634 #endif /* MINIMAL */
635 
636 		/* get command line options */
637 		for (i=1; i<argc; i++) {
638 			if ((i<argc-1) &&
639 				(argv[i][0]=='-'
640 #ifndef MINIMAL
641 || argv[i][0]=='@'
642 #endif
643 				)) {
644 					parse_arg(argv[i], argv[i+1]);
645 					++i;
646 			} else {
647 				if (*ewin.name) break;
648 				/* case of syntax  'filename:linenumber' */
649 				{
650                                     char* p=strchr(argv[i],':');
651                                     if (p) {
652                                          *p++ = '\0';
653                                          ewin.jump = atoi(p);
654                                     }
655 				}
656 				strcpy(ewin.name, argv[i]);
657 			}
658 		}
659 
660                 /* alloc memory for the main buffer and block buffer */
661 		edbuf = (char *) malloc((size_t)(amax+tabsize+1));
662                 bb = (char *) malloc((size_t)(bmax+tabsize+1));
663 		unbuf = (void *) malloc((size_t)(umax+tabsize+1));
664 
665 		if (!edbuf || !bb || !unbuf) {
666 			fprintf(stderr,"Memory allocation failed, aborting !!\n");
667 			exit(1);
668                 }
669 
670 		/* open the display */
671 		dpy=XOpenDisplay(DisplayName);
672 		if(dpy==NULL)  {
673 				fprintf(stderr,"Can't open display: %s\n",DisplayName);
674 				sys_exit(1);
675 		}
676 
677 		/* setup to gracefully respond to exit requests from X */
678 		screen=DefaultScreen(dpy);
679 		DeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
680 
681 		/* establish window manager hints data structure */
682 		xsh=XAllocSizeHints();
683 		wmh=XAllocWMHints();
684 		classh=XAllocClassHint();
685 
686 		x = 1; y=0;
687 
688 		/* setup font(s) */
689 		if(FontName == NULL) { FontName = FONTNAME; }
690 
691 		font=XLoadQueryFont(dpy, FontName);
692 		if(font==NULL) {
693 				fprintf(stderr, FONTS_NOT_FOUND"\n");
694 				sys_exit(1);
695 		}
696 
697 		fheight = font->ascent + font->descent;
698 		Height = fheight * screen_height + font->descent + 2;
699 
700 		/* engine screen width */
701 		fwidth = XTextWidth(font,"8",1);
702 
703 		Width = (fwidth * screen_width)+13;
704 		xsh->flags = PSize; xsh->width = Width; xsh->height = Height;
705 
706 		/* initialize clreol string to all blanks */
707 		memset(eolbuf, ' ', sizeof(eolbuf));
708 
709 		/* create the only window */
710 		win=XCreateSimpleWindow(dpy,RootWindow(dpy,screen), x, y,
711                                 Width, Height, 0,
712 				BlackPixel(dpy,screen),WhitePixel(dpy,screen));
713 
714 		/* setup window hints */
715 		wmh->initial_state=NormalState;
716 		wmh->input=True;
717 		wmh->window_group = win;
718 		wmh->flags = StateHint | InputHint | WindowGroupHint;
719 
720 		/* setup window class resource names */
721 		classh->res_name = (AppName==NULL)?EDIT:AppName;
722 		classh->res_class = "Xedit";
723 
724 		/* name that window */
725 		XmbSetWMProperties(dpy, win, EDIT, EDIT, argv, argc,
726 										   xsh, wmh, classh);
727 		/* notify X on how to force emx to exit */
728 		XSetWMProtocols(dpy, win, &DeleteWindow, 1);
729 
730 		/* specify accepted XEvent loop events */
731 		XSelectInput(dpy, win,
732 						KeyPressMask|\
733 						FocusChangeMask|\
734 						StructureNotifyMask|\
735 						ButtonPressMask|\
736 						ButtonReleaseMask|\
737 						ExposureMask|\
738 						PropertyChangeMask|\
739 						Button1MotionMask|\
740 						Button2MotionMask|\
741 						Button3MotionMask|\
742 						VisibilityChangeMask
743 		);
744 		keve = (XKeyEvent *)&event;
745 
746 		/* create the Graphic Context for drawing purposes */
747 		gc=XCreateGC(dpy,win,0,NULL);
748 
749 		/* allocate required colors */
750 		XAllocNamedColor(dpy,DefaultColormap(dpy,screen),FgColor,&FgXColor,&tmp);
751 		XAllocNamedColor(dpy,DefaultColormap(dpy,screen),BgColor,&BgXColor,&tmp);
752 		XAllocNamedColor(dpy,DefaultColormap(dpy,screen),CrColor,&CrXColor,&tmp);
753 		XAllocNamedColor(dpy,DefaultColormap(dpy,screen),HiFgColor,&HiFgXColor,&tmp);
754 		XAllocNamedColor(dpy,DefaultColormap(dpy,screen),HiBgColor,&HiBgXColor,&tmp);
755 
756 		/* apply colors to window */
757 		XSetForeground(dpy,gc,FgXColor.pixel);
758 		XSetWindowBackground(dpy,win,BgXColor.pixel);
759 
760 		/* set the font */
761 		XSetFont(dpy,gc,font->fid);
762 
763 		/* map the window real */
764 		XMapWindow(dpy, win);
765 }
766 
handle_key(char * astr,int skey,int state)767 void handle_key(char *astr, int skey, int state)
768 {
769 		char chstr[256];
770 		int x=outxy.X, y=outxy.Y, n=0;
771 
772 		/* display keyboard shift/control/alt status */
773 		highvideo();
774 		gotoxy(0,yl1);
775 		for(n=5;n;chstr[n--]=' ');
776 		if(state & ShiftMask) chstr[n++] = 'S';
777 		if(state & Mod1Mask) chstr[n++] = 'A';
778 		if(skey & 0xff00) chstr[n++] = 'F';
779 		if(state & ControlMask) chstr[n++] = '^';
780 		chstr[n] = skey & 0xff;
781 		chstr[5] = '\0';
782 		cputs(chstr);
783 		chstr[0] = '\0';
784 
785 #ifdef DEBUG
786 		/* display raw key event data */
787 		sprintf(chstr,"k=%4x,s=%2x.",skey,state);
788 #endif /* DEBUG */
789 		gotoxy(screen_width - 12,0);
790 		clreol();
791 		cputs(chstr);
792 		gotoxy(x,y);
793 		lowvideo();
794 
795 		if((skey >= 0xffe1) && (skey <= 0xffee)) return;
796 		if(skey == NoSymbol) return;
797 
798 		switch(executive) {
799 		case MAIN:
800 				main_exec(skey);
801 				break;
802 		case DIALOG:
803 				dialog(skey);
804 				break;
805 		case OPTIONS:
806 				options(skey);
807 				break;
808 		}
809 }
810 
moveto()811 void moveto()
812 {
813 	move_to(((event.xbutton.x < 0 ? 0 : event.xbutton.x)/fwidth) + 1 + xlo,
814 			((event.xbutton.y-3)/fheight) - 1);
815 }
816 
do_select(int delete)817 void do_select(int delete)
818 {
819 	if(flag[BLK] && mk != cur_pos) {
820 		set_selection();
821 		block_copy(delete);
822 	}
823 	mark_off();
824 }
825 
do_paste()826 void do_paste()
827 {
828 	if(flag[BLK] && executive == MAIN) block_remove_update();
829 	request_selection(event.xbutton.time);
830 }
831 
iconify()832 void iconify()
833 {
834 	XIconifyWindow(dpy, win, DefaultScreen(dpy));
835 }
836 
set_title(char * str)837 void set_title(char *str)
838 {
839 	char b[NLEN];
840 
841 	sprintf(b, EDIT" : %s", str);
842 	XStoreName(dpy, win, b);
843 }
844 
main(int argc,char * argv[])845 int main(int argc,char *argv[])
846 {
847 	Atom WM_PROTOCOLS = 0;
848 	struct sigaction sig;
849 	int yp0 = 0, yp1 = 0, yf, yt;
850 
851 	init(argc,argv);
852 
853 	/* disconnect from the console */
854 	/* JPD commented this out. Use instead emx/edx & from shell */
855 	/*
856 	switch (fork()) { case 0: case -1: break; default: exit(0); }
857 	*/
858 
859 	/* set path */
860 	if (cfdpath == NULL) {
861 		cfdpath = (char *) malloc(BUFSIZ);
862 		getcwd(cfdpath, BUFSIZ);
863 		if (strcmp(cfdpath, "/") != 0)
864 			strcat(cfdpath, "/");
865 	}
866 
867 	usleep(10000);
868 	XFlush(dpy);
869 	do_open();
870 
871 /* end of edit engine init */
872 
873 	/* request/create WM_PROTOCOLS atom */
874 	WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
875 
876 	/* set up the signal handler response */
877 	sig.sa_handler=sig_handler;
878 	sigemptyset(&sig.sa_mask);
879 	sig.sa_flags=SA_RESTART;
880 	sigaction(SIGALRM,&sig,NULL);
881 
882 	/* display the initial cursor */
883 	clrscr();
884 
885 #define DBLCLICK 300
886 
887 	/* main event loop, dispatch function calls in response to events */
888 	for(;;)  {
889 			static Time button_release_time;
890 			static int buttonpressed = 0;
891 			XNextEvent(dpy,&event);
892 
893 			switch(event.type)	{
894 			case Expose:
895 				while(XCheckTypedEvent(dpy,Expose,&event));
896 				expose = 1;
897 				update();
898 				expose = 0;
899 				break;
900 			case MotionNotify:
901 				if (buttonpressed==-1) {
902 				        if (executive == MAIN) {
903 					   ycur =
904 				     ((event.xbutton.y - ftheight)*ytot)/vtot;
905 					   scroll_text();
906 					}
907 					break;
908 				}
909 #ifndef TWOBUTN
910 			motion:
911 				yf = (buttonpressed == Button3)? fheight : 0;
912 #endif
913 				if(buttonpressed) {
914 #ifdef TWOBUTN
915 					if(!flag[BLK]) block_mark();
916 				  	undraw_cursor();
917 					if (event.xbutton.y < fheight + 2) {
918 #else
919 					if(!flag[BLK] && ! yf) block_mark();
920 				  	undraw_cursor();
921 					if (event.xbutton.y < fheight + yf + 2) {
922 #endif
923 						moveto();
924 						cur_pos = get_cur();
925 						scroll_down();
926 						scr_update();
927 					}
928 					else
929 #ifdef TWOBUTN
930 					if (event.xbutton.y >= Height-6-font->descent) {
931 #else
932 					if (event.xbutton.y >= Height-yf-6-font->descent) {
933 #endif
934 						moveto();
935 						cur_pos = get_cur();
936 						scroll_up();
937 						scr_update();
938 					}
939 					else {
940 #ifndef TWOBUTN
941 						if (yf) goto finish;
942 #endif
943 						moveto();
944 						yf = yp0;
945 						if (y<yf) yf = y;
946 						if (yp1<yf) yf = yp1;
947 						yt = yp0;
948 						if (y>yt) yt = y;
949 						if (yp1>yt) yt = yp1;
950 						show_scr(yf, yt);
951 #ifndef TWOBUTN
952 					finish:
953 #endif
954 						moveto();
955 						cur_pos = get_cur();
956 						gotoxy(x-1,y+1);
957 						draw_cursor();
958 						yp1 = y;
959 					}
960 				}
961 				break;
962 			case ButtonPress:
963 				if (event.xbutton.button>Button3 &&
964 				    executive==MAIN) {
965 				   if (event.xbutton.button==Button4) {
966 				      ycur -= 3;
967 				      scroll_text();
968 				   }
969 				   if (event.xbutton.button==Button5) {
970 				      ycur += 3;
971 				      scroll_text();
972 				   }
973 				   break;
974 				}
975 				help_done = 0;
976 				undraw_cursor();
977 			        if (event.xbutton.x>=Width-10) {
978 					buttonpressed = -1;
979 				        if (executive == MAIN)
980 						scroll_text(event.xbutton.y);
981 					break;
982 				}
983 				buttonpressed = event.xbutton.button;
984 #ifndef TWOBUTN
985 				if (buttonpressed == Button3) {
986 					mark_off();
987 					scr_update();
988 					goto motion;
989 				}
990 #endif
991 				if (event.xbutton.time - eve_time < DBLCLICK) break;
992 				eve_time = event.xbutton.time;
993 				moveto();
994 				yp0 = y;
995 				flag[SHW] = 1;
996 				cur_pos = get_cur();
997 				if (flag[BLK]) {
998 					mark_off(); 	/* unmark */
999 					scr_update();
1000 				} else {
1001 					block_mark();	/* start new mark */
1002 					draw_cursor();
1003 				}
1004 				break;
1005 			case ButtonRelease:
1006 				if (buttonpressed==-1) {
1007 					buttonpressed = 0;
1008 					break;
1009 				}
1010 				buttonpressed = 0;
1011 #ifndef TWOBUTN
1012 				if (event.xbutton.button == Button3) goto motion;
1013 #endif
1014 				switch (event.xbutton.button) {
1015 				case Button1:
1016 					if (event.xbutton.time - button_release_time < DBLCLICK) {
1017 						mark_off(); cursor_right(); word_left(); block_mark();	/* set mark to left end of word */
1018 						word_right(); scr_update();	/* set mark to right end of word */
1019 						break;
1020 					}
1021 					else
1022 					{
1023 
1024 						button_release_time = event.xbutton.time;
1025 						if (mk == cur_pos)
1026 							mark_off();
1027 						else
1028 							set_selection();
1029 						goto setcursor;
1030 					}
1031 					break;
1032 #ifdef TWOBUTN
1033 				case Button2:
1034 				case Button3:
1035 #else
1036 				case Button2:
1037 #endif
1038 					if ((event.xbutton.time - eve_time < DBLCLICK) &&
1039 						(event.xbutton.time - eve_time)) {
1040 							do_paste();
1041 					}
1042 					goto setcursor;
1043 				}
1044 				break;
1045 			setcursor:
1046 				moveto();
1047 				flag[SHW] = 1;
1048 				cur_pos = get_cur();
1049 				if (flag[BLK])
1050 					scr_update();
1051 				else
1052 					draw_cursor();
1053 				break;
1054 
1055 			case KeyPress:{
1056 				int count;
1057 				char astr[10];
1058 				KeySym skey;
1059 				eve_time = keve->time;
1060 				astr[0] = 0;
1061 				count = XLookupString(keve, astr,
1062 						  sizeof (astr), &skey, NULL);
1063 				astr[count] = 0;
1064 				handle_key(astr, skey, keve->state);
1065 			}
1066 			break;
1067 		case SelectionClear:
1068 			break;
1069 		case SelectionRequest:
1070 			send_selection((XSelectionRequestEvent *) &
1071 					   event);
1072 			break;
1073 		case SelectionNotify:
1074 			paste_primary(event.xselection.requestor,
1075 					  event.xselection.property, True);
1076 			break;
1077 		case ConfigureNotify:
1078 			Width = event.xconfigure.width;
1079 			screen_width = (Width-16)/fwidth;
1080 			Height = event.xconfigure.height;
1081 			screen_height = (Height/fheight) -1 ;
1082 			update();
1083 			break;
1084 		case ClientMessage:
1085 			if(event.xclient.message_type == WM_PROTOCOLS)	{
1086 			if(event.xclient.data.l[0] == DeleteWindow) {
1087 				XCloseDisplay(dpy);
1088 				flag[CHG] = 0;
1089 				sys_exit(0);
1090 			}
1091 		}
1092 		break;
1093 
1094 		case DestroyNotify:
1095 			XCloseDisplay(dpy);
1096 			exit(0);
1097 
1098 		}
1099 
1100 	}
1101 }
1102