1 /* $XConsortium: button.c /main/70 1996/01/14 16:52:34 kaleb $ */
2 /* $Id: button.c,v 6.2 1996/07/02 05:01:31 kagotani Rel $ */
3 /*
4  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
5  *
6  *                         All Rights Reserved
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose and without fee is hereby granted,
10  * provided that the above copyright notice appear in all copies and that
11  * both that copyright notice and this permission notice appear in
12  * supporting documentation, and that the name of Digital Equipment
13  * Corporation not be used in advertising or publicity pertaining to
14  * distribution of the software without specific, written prior permission.
15  *
16  *
17  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
18  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
19  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
20  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23  * SOFTWARE.
24  */
25 
26 /*
27 button.c	Handles button events in the terminal emulator.
28 		does cut/paste operations, change modes via menu,
29 		passes button events through to some applications.
30 				J. Gettys.
31 */
32 
33 #include "ptyx.h"		/* Xlib headers included here. */
34 #include <X11/Xatom.h>
35 #include <stdio.h>
36 
37 #include <X11/Xmu/Atoms.h>
38 #include <X11/Xmu/StdSel.h>
39 
40 #include "data.h"
41 #include "error.h"
42 #include "menu.h"
43 
44 extern char *malloc();
45 
46 extern void DoSecureKeyboard();
47 
48 #define KeyState(x) (((x) & (ShiftMask|ControlMask)) + (((x) & Mod1Mask) ? 2 : 0))
49     /* adds together the bits:
50         shift key -> 1
51         meta key  -> 2
52         control key -> 4 */
53 
54 #define TEXTMODES 4
55 #define NBUTS 3
56 #define DIRS 2
57 #define UP 1
58 #define DOWN 0
59 #define SHIFTS 8		/* three keys, so eight combinations */
60 #define	Coordinate(r,c)		((r) * (term->screen.max_col+1) + (c))
61 
62 extern char *xterm_name;
63 
64 static void PointToRowCol();
65 static void SelectionReceived();
66 static void TrackDown();
67 static void ComputeSelect();
68 static void EditorButton();
69 static void ExtendExtend();
70 static void ReHiliteText();
71 static void SelectSet();
72 static void StartSelect();
73 static int Length();
74 #ifdef KTERM
75 static Ichr *SaveText();
76 #else /* !KTERM */
77 static char *SaveText();
78 #endif /* !KTERM */
79 
80 extern XtermWidget term;
81 
82 /* Selection/extension variables */
83 
84 /* Raw char position where the selection started */
85 static int rawRow, rawCol;
86 
87 /* Selected area before CHAR, WORD, LINE selectUnit processing */
88 static int startRRow, startRCol, endRRow, endRCol = 0;
89 
90 /* Selected area after CHAR, WORD, LINE selectUnit processing */
91 static int startSRow, startSCol, endSRow, endSCol = 0;
92 
93 /* Valid rows for selection clipping */
94 static int firstValidRow, lastValidRow;
95 
96 /* Start, end of extension */
97 static int startERow, startECol, endERow, endECol;
98 
99 /* Saved values of raw selection for extend to restore to */
100 static int saveStartRRow, saveStartRCol, saveEndRRow, saveEndRCol;
101 
102 /* Multi-click handling */
103 static int numberOfClicks = 0;
104 #ifdef ENBUG /* kagotani */
105 static long int lastButtonUpTime = 0;
106 #else
107 static Time lastButtonUpTime = 0;
108 #endif
109 typedef int SelectUnit;
110 #define SELECTCHAR 0
111 #define SELECTWORD 1
112 #define SELECTLINE 2
113 #define NSELECTUNITS 3
114 static SelectUnit selectUnit;
115 
116 /* Send emacs escape code when done selecting or extending? */
117 static int replyToEmacs;
118 
119 #if defined(KTERM) && defined(KTERM_MBCC)
120 /*
121  * by Kiyoshi KANAZAWA, Nov. 29, 1990.
122  * Support word-select for MBCS.
123 */
124 static int mbcsCharClass ();
125 #endif	/* KTERM && KTERM_MBCC */
126 
SendMousePosition(w,event)127 Boolean SendMousePosition(w, event)
128 Widget w;
129 XEvent* event;
130 {
131     register TScreen *screen = &((XtermWidget)w)->screen;
132 
133     if (screen->send_mouse_pos == 0) return False;
134 
135     if (event->type != ButtonPress && event->type != ButtonRelease)
136 	return False;
137 
138 #define KeyModifiers \
139     (event->xbutton.state & (ShiftMask | LockMask | ControlMask | Mod1Mask | \
140 			     Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask ))
141 
142 #define ButtonModifiers \
143     (event->xbutton.state & (ShiftMask | LockMask | ControlMask | Mod1Mask | \
144 			     Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask ))
145 
146     switch (screen->send_mouse_pos) {
147       case 1: /* X10 compatibility sequences */
148 
149 	if (KeyModifiers == 0) {
150 	    if (event->type == ButtonPress)
151 		EditorButton(event);
152 	    return True;
153 	}
154 	return False;
155 
156       case 2: /* DEC vt200 compatible */
157 
158 	if (KeyModifiers == 0 || KeyModifiers == ControlMask) {
159 	    EditorButton(event);
160 	    return True;
161 	}
162 	return False;
163 
164       case 3: /* DEC vt200 hilite tracking */
165 	if (  event->type == ButtonPress &&
166 	      KeyModifiers == 0 &&
167 	      event->xbutton.button == Button1 ) {
168 	    TrackDown(event);
169 	    return True;
170 	}
171 	if (KeyModifiers == 0 || KeyModifiers == ControlMask) {
172 	    EditorButton(event);
173 	    return True;
174 	}
175 	/* fall through */
176 
177       default:
178 	return False;
179     }
180 #undef KeyModifiers
181 }
182 
183 
184 /*ARGSUSED*/
HandleSelectExtend(w,event,params,num_params)185 void HandleSelectExtend(w, event, params, num_params)
186 Widget w;
187 XEvent *event;			/* must be XMotionEvent */
188 String *params;			/* unused */
189 Cardinal *num_params;		/* unused */
190 {
191 	register TScreen *screen = &((XtermWidget)w)->screen;
192 	int row, col;
193 
194 	screen->selection_time = event->xmotion.time;
195 	switch (eventMode) {
196 		case LEFTEXTENSION :
197 		case RIGHTEXTENSION :
198 			PointToRowCol (event->xmotion.y, event->xmotion.x,
199 				       &row, &col);
200 			ExtendExtend (row, col);
201 			break;
202 		case NORMAL :
203 			/* will get here if send_mouse_pos != 0 */
204 		        break;
205 	}
206 }
207 
208 static void EndExtend();
209 
do_select_end(w,event,params,num_params,use_cursor_loc)210 static void do_select_end (w, event, params, num_params, use_cursor_loc)
211 Widget w;
212 XEvent *event;			/* must be XButtonEvent */
213 String *params;			/* selections */
214 Cardinal *num_params;
215 Bool use_cursor_loc;
216 {
217 	((XtermWidget)w)->screen.selection_time = event->xbutton.time;
218 	switch (eventMode) {
219 		case NORMAL :
220 		    (void) SendMousePosition(w, event);
221 		    break;
222 		case LEFTEXTENSION :
223 		case RIGHTEXTENSION :
224 		    EndExtend(w, event, params, *num_params, use_cursor_loc);
225 		    break;
226 	}
227 }
228 
229 
HandleSelectEnd(w,event,params,num_params)230 void HandleSelectEnd(w, event, params, num_params)
231 Widget w;
232 XEvent *event;			/* must be XButtonEvent */
233 String *params;			/* selections */
234 Cardinal *num_params;
235 {
236 	do_select_end (w, event, params, num_params, False);
237 }
238 
239 
HandleKeyboardSelectEnd(w,event,params,num_params)240 void HandleKeyboardSelectEnd(w, event, params, num_params)
241 Widget w;
242 XEvent *event;			/* must be XButtonEvent */
243 String *params;			/* selections */
244 Cardinal *num_params;
245 {
246 	do_select_end (w, event, params, num_params, True);
247 }
248 
249 
250 
251 enum {
252     TRY_COMPOUND_TEXT,
253     TRY_UTF8_STRING,
254     TRY_STRING,
255 };
256 
257 struct _SelectionList {
258     String *params;
259     Cardinal count;
260     Time time;
261 #ifdef KTERM /* from exterm */
262     Atom selection;
263     int  try;
264     char *ctext;
265     unsigned long ctext_len;
266 #endif /* KTERM */
267 };
268 
269 static void paste_compound_text();
270 static void paste_utf8_string();
271 static void paste_string();
272 static void paste_cs();
273 static void paste_text();
274 
_GetSelection(w,time,params,num_params)275 static void _GetSelection(w, time, params, num_params)
276 Widget w;
277 Time time;
278 String *params;			/* selections in precedence order */
279 Cardinal num_params;
280 {
281     Atom selection;
282     int cutbuffer;
283 
284     XmuInternStrings(XtDisplay(w), params, (Cardinal)1, &selection);
285     switch (selection) {
286       case XA_CUT_BUFFER0: cutbuffer = 0; break;
287       case XA_CUT_BUFFER1: cutbuffer = 1; break;
288       case XA_CUT_BUFFER2: cutbuffer = 2; break;
289       case XA_CUT_BUFFER3: cutbuffer = 3; break;
290       case XA_CUT_BUFFER4: cutbuffer = 4; break;
291       case XA_CUT_BUFFER5: cutbuffer = 5; break;
292       case XA_CUT_BUFFER6: cutbuffer = 6; break;
293       case XA_CUT_BUFFER7: cutbuffer = 7; break;
294       default:	       cutbuffer = -1;
295     }
296     if (cutbuffer >= 0) {
297 	register TScreen *screen = &((XtermWidget)w)->screen;
298 	int inbytes;
299 	unsigned long nbytes;
300 	int fmt8 = 8;
301 	Atom type = XA_STRING;
302 	char *line = XFetchBuffer(screen->display, &inbytes, cutbuffer);
303 	nbytes = (unsigned long) inbytes;
304 	if (nbytes > 0)
305 	    SelectionReceived(w, NULL, &selection, &type, (XtPointer)line,
306 			      &nbytes, &fmt8);
307 	else if (num_params > 1)
308 	    _GetSelection(w, time, params+1, num_params-1);
309     } else {
310 	struct _SelectionList* list;
311 	if (--num_params) {
312 	    list = XtNew(struct _SelectionList);
313 	    list->params = params + 1;
314 	    list->count = num_params; /* decremented above */
315 	    list->time = time;
316 #ifdef KTERM /* from exterm */
317 	    list->selection = selection;
318 	    list->try = TRY_COMPOUND_TEXT;
319 	    list->ctext = NULL;
320 	    list->ctext_len = 0;
321 #endif /* KTERM */
322 	} else list = NULL;
323 #ifdef KTERM
324 	XtGetSelectionValue(w, selection,
325 			    XA_COMPOUND_TEXT(XtDisplay(w)), SelectionReceived,
326 			    (XtPointer)list, time);
327 #else /* !KTERM */
328 	XtGetSelectionValue(w, selection, XA_STRING, SelectionReceived,
329 			    (XtPointer)list, time);
330 #endif /* !KTERM */
331     }
332 }
333 
334 /* SelectionReceived: stuff received selection text into pty */
335 
336 /* ARGSUSED */
SelectionReceived(w,client_data,selection,type,value,length,format)337 static void SelectionReceived(w, client_data, selection, type,
338 			      value, length, format)
339 Widget w;
340 XtPointer client_data;
341 Atom *selection, *type;
342 XtPointer value;
343 unsigned long *length;
344 int *format;
345 {
346     struct _SelectionList* list = (struct _SelectionList*)client_data;
347 
348     if (*type == 0 /*XT_CONVERT_FAIL*/ || *length == 0 || value == NULL) {
349 	/* could not get this selection, so see if there are more to try */
350 	if (list != NULL) {
351 #ifdef KTERM /* from exterm */
352             /* ask XA_STRING again.
353              * Warning: hope owner not triggered between the 3 requests
354              *          XA_COMPOUNT_TEXT, SA_UTF8_STRING and XA_STRING.
355              */
356 	    if (list->try == TRY_COMPOUND_TEXT) {
357                 list->try = TRY_UTF8_STRING;
358 		list->ctext = NULL;
359 		list->ctext_len = 0;
360                 XtGetSelectionValue(w, list->selection,
361 				    XA_UTF8_STRING(XtDisplay(w)),
362 				    SelectionReceived, (XtPointer)list,
363 				    list->time);
364 	    } else if (list->try == TRY_UTF8_STRING) {
365 		if (list->ctext && list->ctext_len > 0) {
366 		    paste_compound_text(w, list->ctext, list->ctext_len);
367 		    XtFree(list->ctext);
368 		    XtFree(client_data);
369 		    return;
370 		} else {
371 		    list->try = TRY_STRING;
372 		    XtGetSelectionValue(w, list->selection,
373 					XA_STRING, SelectionReceived,
374 					(XtPointer)list, list->time);
375 		}
376             } else {
377                 _GetSelection(w, list->time, list->params, list->count);
378 		if (list->ctext) XtFree(list->ctext);
379 		if (client_data) XtFree(client_data);
380             }
381 #else /* !KTERM */
382 	    _GetSelection(w, list->time, list->params, list->count);
383 #endif /* !KTERM */
384 	}
385 	return;
386     }
387 #ifdef KTERM
388     if (*type == XA_COMPOUND_TEXT(XtDisplay(w))) {
389 	if (check_ctext_kterm((char*)value, *length)) {
390 	    paste_compound_text(w, (Char*)value, *length);
391 	} else {
392 	    list->try = TRY_UTF8_STRING;
393 	    list->ctext = (char *)value;
394 	    list->ctext_len =  *length;
395 	    XtGetSelectionValue(w, list->selection,
396 				XA_UTF8_STRING(XtDisplay(w)),
397 				SelectionReceived, (XtPointer)list,
398 				list->time);
399 	    return;
400 	}
401     } else if (*type == XA_UTF8_STRING(XtDisplay(w))) {
402 	paste_utf8_string(w, (Char*)value, *length, list);
403     } else {
404 	paste_string(w, (Char*)value, *length);
405     }
406 #else /* !KTERM */
407     paste_text(w, (char *)value, (char*)value + *length);
408 #endif /* !KTERM */
409 
410     if (list && list->ctext) XtFree(list->ctext);
411     if (client_data) XtFree(client_data);
412     if (value) XtFree(value);
413     return;
414 }
415 
416 static void
paste_compound_text(w,ct,len)417 paste_compound_text(w, ct, len)
418 Widget w;
419 Char *ct;
420 unsigned long len;
421 {
422     Ichr *cs;
423     int n;
424     Ichr cbuf[256 + 1];
425 
426     n = convCTtoCS(ct, len, NULL);
427     if (n < 0)
428 	return;
429 
430     cs = (n > 256) ? (Ichr *)XtMalloc((n + 1) * sizeof(Ichr)) : cbuf;
431     (void)convCTtoCS(ct, len, cs);
432     paste_cs(w, cs);
433 
434     if (cs != cbuf) XtFree((char *)cs);
435 }
436 
437 static void
paste_utf8_string(w,ut,len,list)438 paste_utf8_string(w, ut, len, list)
439 Widget w;
440 Char *ut;
441 unsigned long len;
442 struct _SelectionList* list;
443 {
444     Ichr *cs;
445     int n;
446     Ichr cbuf[256 + 1];
447 
448 # ifdef KTERM_KANJIMODE
449     if (((XtermWidget)w)->flags & UTF8_KANJI) {
450 	/* if utf-8 mode, paste original */
451 	paste_text(w, ut, ut + len);
452 	return;
453     }
454 # endif /* !KTERM_KANJIMODE */
455 
456     n = convUTF8toCS(ut, len, NULL);
457     if (n <= 0)
458 	return;
459 
460     cs = (n > 256) ? (Ichr *)XtMalloc((n + 1) * sizeof(Ichr)) : cbuf;
461     (void)convUTF8toCS(ut, len, cs);
462     paste_cs(w, cs);
463 
464     if (cs != cbuf) XtFree((char *)cs);
465 }
466 
467 static void
paste_string(w,str,len)468 paste_string(w, str, len)
469 Widget w;
470 Char *str;
471 unsigned long len;
472 {
473     Ichr *cs;
474     int n;
475     Ichr cbuf[256 + 1];
476     Char *p;
477     Ichr *q;
478 
479     cs = (len > 256) ? (Ichr *)XtMalloc((n + 1) * sizeof(Ichr)) : cbuf;
480 
481     p = str;
482     q = cs;
483     while (len-- > 0) {
484 	if (!(*p & 0x80)) {
485 	    q->gset = GSET_ASCII;
486 	} else {
487 	    q->gset = GSET_LATIN1R;
488 	}
489 	q->code = *p ++;
490 	q ++;
491     }
492     q->gset = 0;
493     q->code = 0;
494 
495     paste_cs(w, cs);
496 
497     if (cs != cbuf) XtFree((char *)cs);
498 }
499 
500 static void
paste_cs(w,cs)501 paste_cs(w, cs)
502 Widget w;
503 Ichr *cs;
504 {
505     int n;
506     int convCStoJIS();
507 # ifdef KTERM_KANJIMODE
508     int convCStoEUC(), convCStoSJIS(), convCStoUTF8();
509 # endif /* KTERM_KANJIMODE */
510     int (*func)();
511     char lbuf[256 + 1];
512     char *line;
513 
514 # ifdef KTERM_KANJIMODE
515     switch (((XtermWidget)w)->flags & (EUC_KANJI|SJIS_KANJI|UTF8_KANJI)) {
516     case UTF8_KANJI:
517 	func = convCStoUTF8;
518 	break;
519     case EUC_KANJI:
520 	func = convCStoEUC;
521 	break;
522     case SJIS_KANJI:
523 	func = convCStoSJIS;
524 	break;
525     default:
526 	func = convCStoJIS;
527 	break;
528     }
529 # else /* !KTERM_KANJIMODE */
530     func = convCStoJIS;
531 # endif /* !KTERM_KANJIMODE */
532 
533     n = (*func)(cs, NULL);
534     line = (n > 256) ? XtMalloc(n + 1) : lbuf;
535     (void)(*func)(cs, line);
536     paste_text(w, line, line + n);
537     if (line != lbuf) XtFree(line);
538 }
539 
540 static void
paste_text(w,line,end)541 paste_text(w, line, end)
542 Widget w;
543 char *line;
544 char *end;
545 {
546     int pty = ((XtermWidget)w)->screen.respond;	/* file descriptor of pty */
547     register char *lag, *cp;
548 
549     lag = line;
550     for (cp = line; cp != end; cp++)
551 	{
552 	    if (*cp != '\n') continue;
553 	    *cp = '\r';
554 	    v_write(pty, lag, cp - lag + 1);
555 	    lag = cp + 1;
556 	}
557     if (lag != end)
558 	v_write(pty, lag, end - lag);
559 }
560 
561 
562 void
HandleInsertSelection(w,event,params,num_params)563 HandleInsertSelection(w, event, params, num_params)
564 Widget w;
565 XEvent *event;			/* assumed to be XButtonEvent* */
566 String *params;			/* selections in precedence order */
567 Cardinal *num_params;
568 {
569     if (SendMousePosition(w, event)) return;
570     _GetSelection(w, event->xbutton.time, params, *num_params);
571 }
572 
573 
574 static void
SetSelectUnit(buttonDownTime,defaultUnit)575 SetSelectUnit(buttonDownTime, defaultUnit)
576     Time buttonDownTime;
577     SelectUnit defaultUnit;
578 {
579 #ifdef ENBUG /* kagotani */
580 /* Do arithmetic as integers, but compare as unsigned solves clock wraparound */
581 	if ((long unsigned)((long int)buttonDownTime - lastButtonUpTime)
582 #else
583 	if (buttonDownTime - lastButtonUpTime
584 #endif
585 	 > term->screen.multiClickTime) {
586 		numberOfClicks = 1;
587 		selectUnit = defaultUnit;
588 	} else {
589 		++numberOfClicks;
590 		selectUnit = ((selectUnit + 1) % NSELECTUNITS);
591 	}
592 }
593 
do_select_start(w,event,startrow,startcol)594 static void do_select_start (w, event, startrow, startcol)
595 Widget w;
596 XEvent *event;			/* must be XButtonEvent* */
597 int startrow, startcol;
598 {
599 	if (SendMousePosition(w, event)) return;
600 	SetSelectUnit(event->xbutton.time, SELECTCHAR);
601 	replyToEmacs = FALSE;
602 	StartSelect(startrow, startcol);
603 }
604 
605 /* ARGSUSED */
606 void
HandleSelectStart(w,event,params,num_params)607 HandleSelectStart(w, event, params, num_params)
608 Widget w;
609 XEvent *event;			/* must be XButtonEvent* */
610 String *params;			/* unused */
611 Cardinal *num_params;		/* unused */
612 {
613 	register TScreen *screen = &((XtermWidget)w)->screen;
614 	int startrow, startcol;
615 
616 	firstValidRow = 0;
617 	lastValidRow  = screen->max_row;
618 	PointToRowCol(event->xbutton.y, event->xbutton.x, &startrow, &startcol);
619 	do_select_start (w, event, startrow, startcol);
620 }
621 
622 
623 /* ARGSUSED */
624 void
HandleKeyboardSelectStart(w,event,params,num_params)625 HandleKeyboardSelectStart(w, event, params, num_params)
626 Widget w;
627 XEvent *event;			/* must be XButtonEvent* */
628 String *params;			/* unused */
629 Cardinal *num_params;		/* unused */
630 {
631 	register TScreen *screen = &((XtermWidget)w)->screen;
632 
633 	do_select_start (w, event, screen->cursor_row, screen->cursor_col);
634 }
635 
636 
637 static void
TrackDown(event)638 TrackDown(event)
639     register XButtonEvent *event;
640 {
641 	int startrow, startcol;
642 
643 	SetSelectUnit(event->time, SELECTCHAR);
644 	if (numberOfClicks > 1 ) {
645 		PointToRowCol(event->y, event->x, &startrow, &startcol);
646 		replyToEmacs = TRUE;
647 		StartSelect(startrow, startcol);
648 	} else {
649 		waitingForTrackInfo = 1;
650 		EditorButton(event);
651 	}
652 }
653 
654 
655 #define boundsCheck(x)	if (x < 0) \
656 			    x = 0; \
657 			else if (x >= screen->max_row) \
658 			    x = screen->max_row;
659 
660 void
TrackMouse(func,startrow,startcol,firstrow,lastrow)661 TrackMouse(func, startrow, startcol, firstrow, lastrow)
662     int func, startrow, startcol, firstrow, lastrow;
663 {
664 	TScreen *screen = &term->screen;
665 
666 	if (!waitingForTrackInfo) {	/* Timed out, so ignore */
667 		return;
668 	}
669 	waitingForTrackInfo = 0;
670 	if (func == 0) return;
671 	boundsCheck (startrow)
672 	boundsCheck (firstrow)
673 	boundsCheck (lastrow)
674 	firstValidRow = firstrow;
675 	lastValidRow  = lastrow;
676 	replyToEmacs = TRUE;
677 	StartSelect(startrow, startcol);
678 }
679 
680 static void
StartSelect(startrow,startcol)681 StartSelect(startrow, startcol)
682     int startrow, startcol;
683 {
684 	TScreen *screen = &term->screen;
685 
686 	if (screen->cursor_state)
687 	    HideCursor ();
688 	if (numberOfClicks == 1) {
689 		/* set start of selection */
690 		rawRow = startrow;
691 		rawCol = startcol;
692 
693 	} /* else use old values in rawRow, Col */
694 
695 	saveStartRRow = startERow = rawRow;
696 	saveStartRCol = startECol = rawCol;
697 	saveEndRRow   = endERow   = rawRow;
698 	saveEndRCol   = endECol   = rawCol;
699 	if (Coordinate(startrow, startcol) < Coordinate(rawRow, rawCol)) {
700 		eventMode = LEFTEXTENSION;
701 		startERow = startrow;
702 		startECol = startcol;
703 	} else {
704 		eventMode = RIGHTEXTENSION;
705 		endERow = startrow;
706 		endECol = startcol;
707 	}
708 	ComputeSelect(startERow, startECol, endERow, endECol, False);
709 
710 }
711 
712 static void
EndExtend(w,event,params,num_params,use_cursor_loc)713 EndExtend(w, event, params, num_params, use_cursor_loc)
714     Widget w;
715     XEvent *event;			/* must be XButtonEvent */
716     String *params;			/* selections */
717     Cardinal num_params;
718     Bool use_cursor_loc;
719 {
720 	int	row, col;
721 	TScreen *screen = &term->screen;
722 	char line[9];
723 
724 	if (use_cursor_loc) {
725 	    row = screen->cursor_row;
726 	    col = screen->cursor_col;
727 	} else {
728 	    PointToRowCol(event->xbutton.y, event->xbutton.x, &row, &col);
729 	}
730 	ExtendExtend (row, col);
731 	lastButtonUpTime = event->xbutton.time;
732 	if (startSRow != endSRow || startSCol != endSCol) {
733 		if (replyToEmacs) {
734 			if (rawRow == startSRow && rawCol == startSCol
735 			    && row == endSRow && col == endSCol) {
736 			 	/* Use short-form emacs select */
737 				strcpy(line, "\033[t");
738 				line[3] = ' ' + endSCol + 1;
739 				line[4] = ' ' + endSRow + 1;
740 				v_write(screen->respond, line, 5);
741 			} else {
742 				/* long-form, specify everything */
743 				strcpy(line, "\033[T");
744 				line[3] = ' ' + startSCol + 1;
745 				line[4] = ' ' + startSRow + 1;
746 				line[5] = ' ' + endSCol + 1;
747 				line[6] = ' ' + endSRow + 1;
748 				line[7] = ' ' + col + 1;
749 				line[8] = ' ' + row + 1;
750 				v_write(screen->respond, line, 9);
751 			}
752 			TrackText(0, 0, 0, 0);
753 		}
754 	}
755 	SelectSet(w, event, params, num_params);
756 	eventMode = NORMAL;
757 }
758 
759 void
HandleSelectSet(w,event,params,num_params)760 HandleSelectSet(w, event, params, num_params)
761     Widget w;
762     XEvent *event;
763     String *params;
764     Cardinal *num_params;
765 {
766 	SelectSet (w, event, params, *num_params);
767 }
768 
769 static void SaltTextAway();
770 
771 /* ARGSUSED */
772 static void
SelectSet(w,event,params,num_params)773 SelectSet (w, event, params, num_params)
774     Widget	w;
775     XEvent	*event;
776     String	*params;
777     Cardinal    num_params;
778 {
779 	/* Only do select stuff if non-null select */
780 	if (startSRow != endSRow || startSCol != endSCol) {
781 		SaltTextAway(startSRow, startSCol, endSRow, endSCol,
782 			     params, num_params);
783 	} else
784 		DisownSelection(term);
785 }
786 
787 #define Abs(x)		((x) < 0 ? -(x) : (x))
788 
789 /* ARGSUSED */
do_start_extend(w,event,params,num_params,use_cursor_loc)790 static void do_start_extend (w, event, params, num_params, use_cursor_loc)
791 Widget w;
792 XEvent *event;			/* must be XButtonEvent* */
793 String *params;			/* unused */
794 Cardinal *num_params;		/* unused */
795 Bool use_cursor_loc;
796 {
797 	TScreen *screen = &((XtermWidget)w)->screen;
798 	int row, col, coord;
799 
800 	if (SendMousePosition(w, event)) return;
801 	firstValidRow = 0;
802 	lastValidRow  = screen->max_row;
803 	SetSelectUnit(event->xbutton.time, selectUnit);
804 	replyToEmacs = FALSE;
805 
806 	if (numberOfClicks == 1) {
807 		/* Save existing selection so we can reestablish it if the guy
808 		   extends past the other end of the selection */
809 		saveStartRRow = startERow = startRRow;
810 		saveStartRCol = startECol = startRCol;
811 		saveEndRRow   = endERow   = endRRow;
812 		saveEndRCol   = endECol   = endRCol;
813 	} else {
814 		/* He just needed the selection mode changed, use old values. */
815 		startERow = startRRow = saveStartRRow;
816 		startECol = startRCol = saveStartRCol;
817 		endERow   = endRRow   = saveEndRRow;
818 		endECol   = endRCol   = saveEndRCol;
819 
820 	}
821 	if (use_cursor_loc) {
822 	    row = screen->cursor_row;
823 	    col = screen->cursor_col;
824 	} else {
825 	    PointToRowCol(event->xbutton.y, event->xbutton.x, &row, &col);
826 	}
827 	coord = Coordinate(row, col);
828 
829 	if (Abs(coord - Coordinate(startSRow, startSCol))
830 	     < Abs(coord - Coordinate(endSRow, endSCol))
831 	    || coord < Coordinate(startSRow, startSCol)) {
832 	 	/* point is close to left side of selection */
833 		eventMode = LEFTEXTENSION;
834 		startERow = row;
835 		startECol = col;
836 	} else {
837 	 	/* point is close to left side of selection */
838 		eventMode = RIGHTEXTENSION;
839 		endERow = row;
840 		endECol = col;
841 	}
842 	ComputeSelect(startERow, startECol, endERow, endECol, True);
843 }
844 
845 static void
ExtendExtend(row,col)846 ExtendExtend (row, col)
847     int row, col;
848 {
849 	int coord = Coordinate(row, col);
850 
851 	if (eventMode == LEFTEXTENSION
852 	 && (coord + (selectUnit!=SELECTCHAR)) > Coordinate(endSRow, endSCol)) {
853 		/* Whoops, he's changed his mind.  Do RIGHTEXTENSION */
854 		eventMode = RIGHTEXTENSION;
855 		startERow = saveStartRRow;
856 		startECol = saveStartRCol;
857 	} else if (eventMode == RIGHTEXTENSION
858 	 && coord < Coordinate(startSRow, startSCol)) {
859 	 	/* Whoops, he's changed his mind.  Do LEFTEXTENSION */
860 		eventMode = LEFTEXTENSION;
861 		endERow   = saveEndRRow;
862 		endECol   = saveEndRCol;
863 	}
864 	if (eventMode == LEFTEXTENSION) {
865 		startERow = row;
866 		startECol = col;
867 	} else {
868 		endERow = row;
869 		endECol = col;
870 	}
871 	ComputeSelect(startERow, startECol, endERow, endECol, False);
872 }
873 
874 
HandleStartExtend(w,event,params,num_params)875 void HandleStartExtend(w, event, params, num_params)
876 Widget w;
877 XEvent *event;			/* must be XButtonEvent* */
878 String *params;			/* unused */
879 Cardinal *num_params;		/* unused */
880 {
881     do_start_extend (w, event, params, num_params, False);
882 }
883 
HandleKeyboardStartExtend(w,event,params,num_params)884 void HandleKeyboardStartExtend(w, event, params, num_params)
885 Widget w;
886 XEvent *event;			/* must be XButtonEvent* */
887 String *params;			/* unused */
888 Cardinal *num_params;		/* unused */
889 {
890     do_start_extend (w, event, params, num_params, True);
891 }
892 
893 
ScrollSelection(screen,amount)894 ScrollSelection(screen, amount)
895 register TScreen* screen;
896 register int amount;
897 {
898     register int minrow = -screen->savedlines - screen->topline;
899     register int maxrow = screen->max_row - screen->topline;
900     register int maxcol = screen->max_col;
901 
902 #define scroll_update_one(row, col) \
903 	row += amount; \
904 	if (row < minrow) { \
905 	    row = minrow; \
906 	    col = 0; \
907 	} \
908 	if (row > maxrow) { \
909 	    row = maxrow; \
910 	    col = maxcol; \
911 	}
912 
913     scroll_update_one(startRRow, startRCol);
914     scroll_update_one(endRRow, endRCol);
915     scroll_update_one(startSRow, startSCol);
916     scroll_update_one(endSRow, endSCol);
917 
918     scroll_update_one(rawRow, rawCol);
919 
920     scroll_update_one(screen->startHRow, screen->startHCol);
921     scroll_update_one(screen->endHRow, screen->endHCol);
922 
923     screen->startHCoord = Coordinate (screen->startHRow, screen->startHCol);
924     screen->endHCoord = Coordinate (screen->endHRow, screen->endHCol);
925 }
926 
927 
928 /*ARGSUSED*/
ResizeSelection(screen,rows,cols)929 ResizeSelection (screen, rows, cols)
930     TScreen *screen;
931     int rows, cols;
932 {
933     rows--;				/* decr to get 0-max */
934     cols--;
935 
936     if (startRRow > rows) startRRow = rows;
937     if (startSRow > rows) startSRow = rows;
938     if (endRRow > rows) endRRow = rows;
939     if (endSRow > rows) endSRow = rows;
940     if (rawRow > rows) rawRow = rows;
941 
942     if (startRCol > cols) startRCol = cols;
943     if (startSCol > cols) startSCol = cols;
944     if (endRCol > cols) endRCol = cols;
945     if (endSCol > cols) endSCol = cols;
946     if (rawCol > cols) rawCol = cols;
947 }
948 
949 static void
PointToRowCol(y,x,r,c)950 PointToRowCol(y, x, r, c)
951     register int y, x;
952     int *r, *c;
953 /* Convert pixel coordinates to character coordinates.
954    Rows are clipped between firstValidRow and lastValidRow.
955    Columns are clipped between to be 0 or greater, but are not clipped to some
956        maximum value. */
957 {
958 	register TScreen *screen = &term->screen;
959 	register row, col;
960 
961 	row = (y - screen->border) / FontHeight(screen);
962 	if(row < firstValidRow)
963 		row = firstValidRow;
964 	else if(row > lastValidRow)
965 		row = lastValidRow;
966 	col = (x - screen->border - screen->scrollbar) / FontWidth(screen);
967 	if(col < 0)
968 		col = 0;
969 	else if(col > screen->max_col+1) {
970 		col = screen->max_col+1;
971 	}
972 	*r = row;
973 	*c = col;
974 }
975 
976 static int
LastTextCol(row)977 LastTextCol(row)
978     register int row;
979 {
980 	register TScreen *screen =  &term->screen;
981 	register int i;
982 #ifdef KTERM
983 	register Bchr *ch;
984 #else /* !KTERM */
985 	register Char *ch;
986 #endif /* !KTERM */
987 
988 	for ( i = screen->max_col,
989 #ifdef KTERM
990 	        ch = screen->buf[row + screen->topline] + i ;
991 	      i >= 0 && !(ch->attr & CHARDRAWN) ;
992 	      ch--, i--)
993 #else /* !KTERM */
994 	        ch = screen->buf[2 * (row + screen->topline) + 1] + i ;
995 	      i >= 0 && !(*ch & CHARDRAWN) ;
996 	      ch--, i--)
997 #endif /* !KTERM */
998 	    ;
999 	return(i);
1000 }
1001 
1002 /*
1003 ** double click table for cut and paste in 8 bits
1004 **
1005 ** This table is divided in four parts :
1006 **
1007 **	- control characters	[0,0x1f] U [0x80,0x9f]
1008 **	- separators		[0x20,0x3f] U [0xa0,0xb9]
1009 **	- binding characters	[0x40,0x7f] U [0xc0,0xff]
1010 **  	- execeptions
1011 */
1012 static int charClass[256] = {
1013 /* NUL  SOH  STX  ETX  EOT  ENQ  ACK  BEL */
1014     32,   1,   1,   1,   1,   1,   1,   1,
1015 /*  BS   HT   NL   VT   NP   CR   SO   SI */
1016      1,  32,   1,   1,   1,   1,   1,   1,
1017 /* DLE  DC1  DC2  DC3  DC4  NAK  SYN  ETB */
1018      1,   1,   1,   1,   1,   1,   1,   1,
1019 /* CAN   EM  SUB  ESC   FS   GS   RS   US */
1020      1,   1,   1,   1,   1,   1,   1,   1,
1021 /*  SP    !    "    #    $    %    &    ' */
1022     32,  33,  34,  35,  36,  37,  38,  39,
1023 /*   (    )    *    +    ,    -    .    / */
1024     40,  41,  42,  43,  44,  45,  46,  47,
1025 /*   0    1    2    3    4    5    6    7 */
1026     48,  48,  48,  48,  48,  48,  48,  48,
1027 /*   8    9    :    ;    <    =    >    ? */
1028     48,  48,  58,  59,  60,  61,  62,  63,
1029 /*   @    A    B    C    D    E    F    G */
1030     64,  48,  48,  48,  48,  48,  48,  48,
1031 /*   H    I    J    K    L    M    N    O */
1032     48,  48,  48,  48,  48,  48,  48,  48,
1033 /*   P    Q    R    S    T    U    V    W */
1034     48,  48,  48,  48,  48,  48,  48,  48,
1035 /*   X    Y    Z    [    \    ]    ^    _ */
1036     48,  48,  48,  91,  92,  93,  94,  48,
1037 /*   `    a    b    c    d    e    f    g */
1038     96,  48,  48,  48,  48,  48,  48,  48,
1039 /*   h    i    j    k    l    m    n    o */
1040     48,  48,  48,  48,  48,  48,  48,  48,
1041 /*   p    q    r    s    t    u    v    w */
1042     48,  48,  48,  48,  48,  48,  48,  48,
1043 /*   x    y    z    {    |    }    ~  DEL */
1044     48,  48,  48, 123, 124, 125, 126,   1,
1045 /* x80  x81  x82  x83  IND  NEL  SSA  ESA */
1046      1,   1,   1,   1,   1,   1,   1,   1,
1047 /* HTS  HTJ  VTS  PLD  PLU   RI  SS2  SS3 */
1048      1,   1,   1,   1,   1,   1,   1,   1,
1049 /* DCS  PU1  PU2  STS  CCH   MW  SPA  EPA */
1050      1,   1,   1,   1,   1,   1,   1,   1,
1051 /* x98  x99  x9A  CSI   ST  OSC   PM  APC */
1052      1,   1,   1,   1,   1,   1,   1,   1,
1053 /*   -    i   c/    L   ox   Y-    |   So */
1054    160, 161, 162, 163, 164, 165, 166, 167,
1055 /*  ..   c0   ip   <<    _        R0    - */
1056    168, 169, 170, 171, 172, 173, 174, 175,
1057 /*   o   +-    2    3    '    u   q|    . */
1058    176, 177, 178, 179, 180, 181, 182, 183,
1059 /*   ,    1    2   >>  1/4  1/2  3/4    ? */
1060    184, 185, 186, 187, 188, 189, 190, 191,
1061 /*  A`   A'   A^   A~   A:   Ao   AE   C, */
1062     48,  48,  48,  48,  48,  48,  48,  48,
1063 /*  E`   E'   E^   E:   I`   I'   I^   I: */
1064     48,  48,  48,  48,  48,  48,  48,  48,
1065 /*  D-   N~   O`   O'   O^   O~   O:    X */
1066     48,  48,  48,  48,  48,  48,  48, 216,
1067 /*  O/   U`   U'   U^   U:   Y'    P    B */
1068     48,  48,  48,  48,  48,  48,  48,  48,
1069 /*  a`   a'   a^   a~   a:   ao   ae   c, */
1070     48,  48,  48,  48,  48,  48,  48,  48,
1071 /*  e`   e'   e^   e:    i`  i'   i^   i: */
1072     48,  48,  48,  48,  48,  48,  48,  48,
1073 /*   d   n~   o`   o'   o^   o~   o:   -: */
1074     48,  48,  48,  48,  48,  48,  48,  248,
1075 /*  o/   u`   u'   u^   u:   y'    P   y: */
1076     48,  48,  48,  48,  48,  48,  48,  48};
1077 
SetCharacterClassRange(low,high,value)1078 int SetCharacterClassRange (low, high, value)
1079     register int low, high;		/* in range of [0..255] */
1080     register int value;			/* arbitrary */
1081 {
1082 
1083     if (low < 0 || high > 255 || high < low) return (-1);
1084 
1085     for (; low <= high; low++) charClass[low] = value;
1086 
1087     return (0);
1088 }
1089 
1090 /*
1091  * sets startSRow startSCol endSRow endSCol
1092  * ensuring that they have legal values
1093  */
1094 
1095 static void
ComputeSelect(startRow,startCol,endRow,endCol,extend)1096 ComputeSelect(startRow, startCol, endRow, endCol, extend)
1097     int startRow, startCol, endRow, endCol;
1098     Bool extend;
1099 {
1100 	register TScreen *screen = &term->screen;
1101 #ifdef KTERM
1102 	register Bchr *ptr;
1103 	Char gset;
1104 #else /* !KTERM */
1105 	register Char *ptr;
1106 #endif /* !KTERM */
1107 	register int length;
1108 	register int class;
1109 	int osc = startSCol;
1110 
1111 	if (Coordinate(startRow, startCol) <= Coordinate(endRow, endCol)) {
1112 		startSRow = startRRow = startRow;
1113 		startSCol = startRCol = startCol;
1114 		endSRow   = endRRow   = endRow;
1115 		endSCol   = endRCol   = endCol;
1116 	} else {	/* Swap them */
1117 		startSRow = startRRow = endRow;
1118 		startSCol = startRCol = endCol;
1119 		endSRow   = endRRow   = startRow;
1120 		endSCol   = endRCol   = startCol;
1121 	}
1122 
1123 	switch (selectUnit) {
1124 		case SELECTCHAR :
1125 			if (startSCol > (LastTextCol(startSRow) + 1)) {
1126 				startSCol = 0;
1127 				startSRow++;
1128 			}
1129 			if (endSCol > (LastTextCol(endSRow) + 1)) {
1130 				endSCol = 0;
1131 				endSRow++;
1132 			}
1133 			break;
1134 		case SELECTWORD :
1135 			if (startSCol > (LastTextCol(startSRow) + 1)) {
1136 				startSCol = 0;
1137 				startSRow++;
1138 			} else {
1139 #ifdef KTERM
1140 				ptr = screen->buf[startSRow+screen->topline]
1141 				 + startSCol;
1142 #ifdef KTERM_MBCC
1143 				if (ptr->gset == MBC2)
1144 				{	/* 2nd byte of a mbcs character */
1145 					startSCol--;
1146 					ptr--;
1147 				}
1148 				if (ptr->gset != MBC2 && (ptr->gset & MBCS) != 0)
1149 				{	/* 1st byte of a mbcs character */
1150 					class = mbcsCharClass (ptr);
1151 					do
1152 					{
1153 						startSCol -= 2;
1154 						ptr -= 2;
1155 					} while (startSCol >= 0
1156 					&& ptr->gset != MBC2 && (ptr->gset & MBCS) != 0
1157 					&& class == mbcsCharClass (ptr));
1158 					startSCol++;
1159 					ptr++;
1160 				}
1161 				else if (ptr->gset == GSET_KANA)
1162 					do
1163 					{
1164 						--startSCol;
1165 						--ptr;
1166 					} while (startSCol >= 0
1167 					&& ptr->gset == GSET_KANA);
1168 				else
1169 				{
1170 					gset = ptr->gset;
1171 					class = charClass[ptr->code];
1172 					do {
1173 						--startSCol;
1174 						--ptr;
1175 					} while (startSCol >= 0
1176 					&& ptr->gset == gset
1177 				 	&& charClass[ptr->code] == class);
1178 				}
1179 #else	/* !KTERM_MBCC */
1180 				class = charClass[ptr->code];
1181 				do {
1182 					--startSCol;
1183 					--ptr;
1184 				} while (startSCol >= 0
1185 				 && charClass[ptr->code] == class);
1186 #endif	/* !KTERM_MBCC */
1187 #else /* !KTERM */
1188 				ptr = screen->buf[2*(startSRow+screen->topline)]
1189 				 + startSCol;
1190 				class = charClass[*ptr];
1191 				do {
1192 					--startSCol;
1193 					--ptr;
1194 				} while (startSCol >= 0
1195 				 && charClass[*ptr] == class);
1196 #endif /* !KTERM */
1197 				++startSCol;
1198 			}
1199 			if (endSCol > (LastTextCol(endSRow) + 1)) {
1200 				endSCol = 0;
1201 				endSRow++;
1202 			} else {
1203 				length = LastTextCol(endSRow);
1204 #ifdef KTERM
1205 				ptr = screen->buf[endSRow+screen->topline]
1206 				 + endSCol;
1207 #ifdef KTERM_MBCC
1208 				if (ptr->gset == MBC2)
1209 				{	/* 2nd byte of a mbcs character */
1210 					endSCol--;
1211 					ptr--;
1212 				}
1213 				if (ptr->gset != MBC2 && (ptr->gset & MBCS) != 0)
1214 				{	/* 1st byte of a mbcs character */
1215 					class = mbcsCharClass (ptr);
1216 					do
1217 					{
1218 						endSCol += 2;
1219 						ptr += 2;
1220 					} while (endSCol < length
1221 					&& ptr->gset != MBC2 && (ptr->gset & MBCS) != 0
1222 					&& class == mbcsCharClass (ptr));
1223 				}
1224 				else if (ptr->gset == GSET_KANA)
1225 					do
1226 					{
1227 						++endSCol;
1228 						++ptr;
1229 					} while (endSCol <= length
1230 					&& ptr->gset == GSET_KANA);
1231 				else
1232 				{
1233 					gset = ptr->gset;
1234 					class = charClass[ptr->code];
1235 					do {
1236 						++endSCol;
1237 						++ptr;
1238 					} while (endSCol <= length
1239 					&& ptr->gset == gset
1240 				 	&& charClass[ptr->code] == class);
1241 				}
1242 #else	/* !KTERM_MBCC */
1243 				class = charClass[ptr->code];
1244 				do {
1245 					++endSCol;
1246 					++ptr;
1247 				} while (endSCol <= length
1248 				 && charClass[ptr->code] == class);
1249 #endif	/* !KTERM_MBCC */
1250 #else /* !KTERM */
1251 				ptr = screen->buf[2*(endSRow+screen->topline)]
1252 				 + endSCol;
1253 				class = charClass[*ptr];
1254 				do {
1255 					++endSCol;
1256 					++ptr;
1257 				} while (endSCol <= length
1258 				 && charClass[*ptr] == class);
1259 #endif /* !KTERM */
1260 				/* Word select selects if pointing to any char
1261 				   in "word", especially in that it includes
1262 				   the last character in a word.  So no --endSCol
1263 				   and do special eol handling */
1264 				if (endSCol > length+1) {
1265 					endSCol = 0;
1266 					++endSRow;
1267 				}
1268 			}
1269 			break;
1270 		case SELECTLINE :
1271 			if (term->screen.cutToBeginningOfLine) {
1272 			    startSCol = 0;
1273 			} else if (!extend) {
1274 			    startSCol = osc;
1275 			}
1276 			if (term->screen.cutNewline) {
1277 			    endSCol = 0;
1278 			    ++endSRow;
1279 			} else {
1280 			    endSCol = LastTextCol(endSRow) + 1;
1281 			}
1282 			break;
1283 	}
1284 
1285 	TrackText(startSRow, startSCol, endSRow, endSCol);
1286 	return;
1287 }
1288 
1289 #if defined(KTERM) && defined(KTERM_MBCC)
1290 /*
1291  * by Kiyoshi KANAZAWA, Nov. 29, 1990.
1292  *
1293  * MBCS is divided to ARABIAN-number, ENGLISH, HIRAGANA, KATAKANA,
1294  * KANJI (including both dai_1_suijun and dai_2_suijun), GREEK,
1295  * RUSSIAN, KEISEN and OTHERS.
1296  *
1297  * It is assumed that
1298  *     HIRAGANA, KATAKANA and KANJI belong to the same character class.
1299  *     ARABIAN-number and ENGLISH   belong to the same character class.
1300  *     Each character in OTHERS makes one character class by itself.
1301 */
1302 
1303 #define MBCS_ARABIAN	0			/* arabia suuji		*/
1304 #define MBCS_ENGLISH	MBCS_ARABIAN		/* eigo			*/
1305 #define MBCS_HIRAGANA	(MBCS_ENGLISH + 1)	/* hiragana		*/
1306 #define MBCS_KATAKANA	MBCS_HIRAGANA		/* katakana		*/
1307 #define MBCS_KANJI	MBCS_KATAKANA		/* kanji		*/
1308 #define MBCS_GREEK	(MBCS_KANJI + 1)	/* girisha moji		*/
1309 #define MBCS_RUSSIAN	(MBCS_GREEK + 1)	/* roshia moji		*/
1310 #define MBCS_KEISEN 	(MBCS_RUSSIAN + 1)	/* keisen		*/
1311 
mbcsCharClass(ptr)1312 static int mbcsCharClass (ptr)
1313 register Bchr *ptr;
1314 {
1315 	register unsigned char	c1, c2;
1316 
1317 	c2 = (ptr + 1)->code;
1318 	switch (c1 = ptr->code)
1319 	{
1320 	case 0x21:
1321 		switch (c2)
1322 		{
1323 		case 0x38:
1324 		case 0x39:
1325 		case 0x3a:
1326 			return (MBCS_KANJI);
1327 		case 0x3c:
1328 			return (MBCS_KATAKANA);
1329 		}
1330 		break;
1331 	case 0x23:
1332 		if (0x30 <= c2 && c2 <= 0x39)
1333 			return (MBCS_ARABIAN);
1334 		if (0x41 <= c2 && c2 <= 0x5a || 0x61 <= c2 && c2 <= 0x7a)
1335 			return (MBCS_ENGLISH);
1336 		break;
1337 	case 0x24:
1338 		if (0x21 <= c2 && c2 <= 0x73)
1339 			return (MBCS_HIRAGANA);
1340 		break;
1341 	case 0x25:
1342 		if (0x21 <= c2 && c2 <= 0x76)
1343 			return (MBCS_KATAKANA);
1344 		break;
1345 	case 0x26:
1346 		if (0x21 <= c2 && c2 <= 0x38 || 0x41 <= c2 && c2 <= 0x58)
1347 			return (MBCS_GREEK);
1348 		break;
1349 	case 0x27:
1350 		if (0x21 <= c2 && c2 <= 0x41 || 0x51 <= c2 && c2 <= 0x71)
1351 			return (MBCS_RUSSIAN);
1352 		break;
1353 	case 0x28:
1354 		if (0x21 <= c2 && c2 <= 0x40)
1355 			return (MBCS_KEISEN);
1356 		break;
1357 	default:
1358 		if (0x30 <= c1 && c1 <= 0x4e && 0x21 <= c2 && c2 <= 0x7e
1359 			|| c1 == 0x4f && (0x21 <= c2 || c2 <= 0x53)) /* dai_1_suijun */
1360 			return (MBCS_KANJI);
1361 		if (0x50 <= c1 && c1 <= 0x73 && 0x21 <= c2 && c2 <= 0x7e
1362 			|| c1 == 0x74 && (0x21 <= c2 || c2 <= 0x24)) /* dai_2_suijun */
1363 			return (MBCS_KANJI);
1364 		break;
1365 	}
1366 	return ((c1 << 8) | c2);	/*	return mbcs code	*/
1367 }
1368 
1369 #endif	/* KTERM && KTERM_MBCC */
1370 
TrackText(frow,fcol,trow,tcol)1371 TrackText(frow, fcol, trow, tcol)
1372     register int frow, fcol, trow, tcol;
1373     /* Guaranteed (frow, fcol) <= (trow, tcol) */
1374 {
1375 	register int from, to;
1376 	register TScreen *screen = &term->screen;
1377 	int old_startrow, old_startcol, old_endrow, old_endcol;
1378 
1379 	old_startrow = screen->startHRow;
1380 	old_startcol = screen->startHCol;
1381 	old_endrow = screen->endHRow;
1382 	old_endcol = screen->endHCol;
1383 	if (frow == old_startrow && fcol == old_startcol &&
1384 	    trow == old_endrow   && tcol == old_endcol) return;
1385 	screen->startHRow = frow;
1386 	screen->startHCol = fcol;
1387 	screen->endHRow   = trow;
1388 	screen->endHCol   = tcol;
1389 	from = Coordinate(frow, fcol);
1390 	to = Coordinate(trow, tcol);
1391 	if (to <= screen->startHCoord || from > screen->endHCoord) {
1392 	    /* No overlap whatsoever between old and new hilite */
1393 	    ReHiliteText(old_startrow, old_startcol, old_endrow, old_endcol);
1394 	    ReHiliteText(frow, fcol, trow, tcol);
1395 	} else {
1396 	    if (from < screen->startHCoord) {
1397 		    /* Extend left end */
1398 		    ReHiliteText(frow, fcol, old_startrow, old_startcol);
1399 	    } else if (from > screen->startHCoord) {
1400 		    /* Shorten left end */
1401 		    ReHiliteText(old_startrow, old_startcol, frow, fcol);
1402 	    }
1403 	    if (to > screen->endHCoord) {
1404 		    /* Extend right end */
1405 		    ReHiliteText(old_endrow, old_endcol, trow, tcol);
1406 	    } else if (to < screen->endHCoord) {
1407 		    /* Shorten right end */
1408 		    ReHiliteText(trow, tcol, old_endrow, old_endcol);
1409 	    }
1410 	}
1411 	screen->startHCoord = from;
1412 	screen->endHCoord = to;
1413 }
1414 
1415 static void
ReHiliteText(frow,fcol,trow,tcol)1416 ReHiliteText(frow, fcol, trow, tcol)
1417     register int frow, fcol, trow, tcol;
1418     /* Guaranteed that (frow, fcol) <= (trow, tcol) */
1419 {
1420 	register TScreen *screen = &term->screen;
1421 	register int i;
1422 
1423 	if (frow < 0)
1424 	    frow = fcol = 0;
1425 	else if (frow > screen->max_row)
1426 	    return;		/* nothing to do, since trow >= frow */
1427 
1428 	if (trow < 0)
1429 	    return;		/* nothing to do, since frow <= trow */
1430 	else if (trow > screen->max_row) {
1431 	    trow = screen->max_row;
1432 	    tcol = screen->max_col+1;
1433 	}
1434 	if (frow == trow && fcol == tcol)
1435 		return;
1436 
1437 	if(frow != trow) {	/* do multiple rows */
1438 		if((i = screen->max_col - fcol + 1) > 0) {     /* first row */
1439 		    ScrnRefresh(screen, frow, fcol, 1, i, True);
1440 		}
1441 		if((i = trow - frow - 1) > 0) {		       /* middle rows*/
1442 		    ScrnRefresh(screen, frow+1, 0,i, screen->max_col+1, True);
1443 		}
1444 		if(tcol > 0 && trow <= screen->max_row) {      /* last row */
1445 		    ScrnRefresh(screen, trow, 0, 1, tcol, True);
1446 		}
1447 	} else {		/* do single row */
1448 		ScrnRefresh(screen, frow, fcol, 1, tcol - fcol, True);
1449 	}
1450 }
1451 
1452 static void _OwnSelection();
1453 
1454 static void
SaltTextAway(crow,ccol,row,col,params,num_params)1455 SaltTextAway(crow, ccol, row, col, params, num_params)
1456     /*register*/ int crow, ccol, row, col;
1457     String *params;			/* selections */
1458     Cardinal num_params;
1459     /* Guaranteed that (crow, ccol) <= (row, col), and that both points are valid
1460        (may have row = screen->max_row+1, col = 0) */
1461 {
1462 	register TScreen *screen = &term->screen;
1463 	register int i, j = 0;
1464 	int eol;
1465 #ifdef KTERM
1466 	Ichr *line, *lp;
1467 	Bchr *ch;
1468 #else /* !KTERM */
1469 	char *line, *lp;
1470 #endif /* !KTERM */
1471 
1472 	if (crow == row && ccol > col) {
1473 	    int tmp = ccol;
1474 	    ccol = col;
1475 	    col = tmp;
1476 	}
1477 
1478 	--col;
1479 	/* first we need to know how long the string is before we can save it*/
1480 
1481 #ifdef KTERM
1482 	ch = screen->buf[crow + screen->topline];
1483 	if (ch[ccol].gset == MBC2)
1484 	    ccol--;
1485 	ch = screen->buf[row + screen->topline];
1486 	if (ch[col].gset & MBCS && ch[col].gset != MBC2) /* MBC1 */
1487 	    col++;
1488 #endif /* !KTERM */
1489 	if ( row == crow ) j = Length(screen, crow, ccol, col);
1490 	else {	/* two cases, cut is on same line, cut spans multiple lines */
1491 		j += Length(screen, crow, ccol, screen->max_col) + 1;
1492 		for(i = crow + 1; i < row; i++)
1493 			j += Length(screen, i, 0, screen->max_col) + 1;
1494 		if (col >= 0)
1495 			j += Length(screen, row, 0, col);
1496 	}
1497 
1498 	/* now get some memory to save it in */
1499 
1500 	if (screen->selection_size <= j) {
1501 #ifdef KTERM
1502 	    if((line = (Ichr *)malloc((unsigned)((j + 1) * sizeof(Ichr)))) == (Ichr *)NULL)
1503 		SysError(ERROR_BMALLOC2);
1504 	    XtFree((char *)screen->selection);
1505 #else /* !KTERM */
1506 	    if((line = malloc((unsigned) j + 1)) == (char *)NULL)
1507 		SysError(ERROR_BMALLOC2);
1508 	    XtFree(screen->selection);
1509 #endif /* !KTERM */
1510 	    screen->selection = line;
1511 	    screen->selection_size = j + 1;
1512 	} else line = screen->selection;
1513 	if (!line || j < 0) return;
1514 
1515 #ifdef KTERM
1516 	line[j].code = '\0';		/* make sure it is null terminated */
1517 	line[j].gset = 0;
1518 #else /* !KTERM */
1519 	line[j] = '\0';		/* make sure it is null terminated */
1520 #endif /* !KTERM */
1521 	lp = line;		/* lp points to where to save the text */
1522 	if ( row == crow ) lp = SaveText(screen, row, ccol, col, lp, &eol);
1523 	else {
1524 		lp = SaveText(screen, crow, ccol, screen->max_col, lp, &eol);
1525 		if (eol)
1526 #ifdef KTERM
1527 		{
1528 			lp->code = '\n';
1529 			lp++->gset = GSET_ASCII;
1530 		}
1531 #else /* !KTERM */
1532 			*lp ++ = '\n';	/* put in newline at end of line */
1533 #endif /* !KTERM */
1534 		for(i = crow +1; i < row; i++) {
1535 			lp = SaveText(screen, i, 0, screen->max_col, lp, &eol);
1536 			if (eol)
1537 #ifdef KTERM
1538 			{
1539 				lp->code = '\n';
1540 				lp++->gset = GSET_ASCII;
1541 			}
1542 #else /* !KTERM */
1543 				*lp ++ = '\n';
1544 #endif /* !KTERM */
1545 			}
1546 		if (col >= 0)
1547 			lp = SaveText(screen, row, 0, col, lp, &eol);
1548 	}
1549 #ifdef KTERM
1550 	lp->code = '\0';		/* make sure we have end marked */
1551 	lp->gset = 0;
1552 #else /* !KTERM */
1553 	*lp = '\0';		/* make sure we have end marked */
1554 #endif /* !KTERM */
1555 
1556 	screen->selection_length = (lp - line);
1557 	_OwnSelection(term, params, num_params);
1558 }
1559 
ConvertSelection(w,selection,target,type,value,length,format)1560 static Boolean ConvertSelection(w, selection, target,
1561 				type, value, length, format)
1562 Widget w;
1563 Atom *selection, *target, *type;
1564 XtPointer *value;
1565 unsigned long *length;
1566 int *format;
1567 {
1568     Display* d = XtDisplay(w);
1569     XtermWidget xterm = (XtermWidget)w;
1570 
1571     if (xterm->screen.selection == NULL) return False; /* can this happen? */
1572 
1573     if (*target == XA_TARGETS(d)) {
1574 	Atom* targetP;
1575 	Atom* std_targets;
1576 	unsigned long std_length;
1577 	XmuConvertStandardSelection(
1578 		    w, xterm->screen.selection_time, selection,
1579 		    target, type, (caddr_t*)&std_targets, &std_length, format
1580 		   );
1581 	*length = std_length + 5;
1582 	*value = (XtPointer)XtMalloc(sizeof(Atom)*(*length));
1583 	targetP = *(Atom**)value;
1584 	*targetP++ = XA_STRING;
1585 	*targetP++ = XA_COMPOUND_TEXT(d);
1586 	*targetP++ = XA_UTF8_STRING(d);
1587 	*targetP++ = XA_LENGTH(d);
1588 	*targetP++ = XA_LIST_LENGTH(d);
1589 	memmove( (char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
1590 	XtFree((char*)std_targets);
1591 	*type = XA_ATOM;
1592 	*format = 32;
1593 	return True;
1594     }
1595 
1596     if (*target == XA_STRING ||
1597 	*target == XA_TEXT(d) ||
1598 	*target == XA_UTF8_STRING(d) ||
1599 	*target == XA_COMPOUND_TEXT(d)) {
1600 #ifdef KTERM
1601 	if (*target == XA_UTF8_STRING(d)) {
1602 	    *type = XA_UTF8_STRING(d);
1603 	    *length = pasteCStoUTF8(xterm->screen.selection, NULL);
1604 	    *value = (caddr_t)XtMalloc(*length + 1);
1605 	    (void)pasteCStoUTF8(xterm->screen.selection, (Char *)*value);
1606 	} else if (*target == XA_COMPOUND_TEXT(d) || *target == XA_TEXT(d)) {
1607 	    *type = XA_COMPOUND_TEXT(d);
1608 	    *length = convCStoCT(xterm->screen.selection, NULL);
1609 	    *value = (caddr_t)XtMalloc(*length + 1);
1610 	    (void)convCStoCT(xterm->screen.selection, (Char *)*value);
1611 	} else {
1612 	    *type = XA_STRING;
1613 	    *length = convCStoLatin1(xterm->screen.selection, NULL);
1614 	    *value = (caddr_t)XtMalloc(*length + 1);
1615 	    (void)convCStoLatin1(xterm->screen.selection, (Char *)*value);
1616 	}
1617 #else /* !KTERM */
1618 	if (*target == XA_COMPOUND_TEXT(d))
1619 	    *type = *target;
1620 	else
1621 	    *type = XA_STRING;
1622 	*value = xterm->screen.selection;
1623 	*length = xterm->screen.selection_length;
1624 #endif /* !KTERM */
1625 	*format = 8;
1626 	return True;
1627     }
1628     if (*target == XA_LIST_LENGTH(d)) {
1629 	*value = XtMalloc(4);
1630 	if (sizeof(long) == 4)
1631 	    *(long*)*value = 1;
1632 	else {
1633 	    long temp = 1;
1634 	    memmove( (char*)*value, ((char*)&temp)+sizeof(long)-4, 4);
1635 	}
1636 	*type = XA_INTEGER;
1637 	*length = 1;
1638 	*format = 32;
1639 	return True;
1640     }
1641     if (*target == XA_LENGTH(d)) {
1642 	*value = XtMalloc(4);
1643 	if (sizeof(long) == 4)
1644 #ifdef KTERM
1645 	    *(long*)*value = convCStoCT(xterm->screen.selection, NULL);
1646 #else /* !KTERM */
1647 	    *(long*)*value = xterm->screen.selection_length;
1648 #endif /* !KTERM */
1649 	else {
1650 #ifdef KTERM
1651 	    long temp = convCStoCT(xterm->screen.selection, NULL);
1652 #else /* !KTERM */
1653 	    long temp = xterm->screen.selection_length;
1654 #endif /* !KTERM */
1655 	    memmove( (char*)*value, ((char*)&temp)+sizeof(long)-4, 4);
1656 	}
1657 	*type = XA_INTEGER;
1658 	*length = 1;
1659 	*format = 32;
1660 	return True;
1661     }
1662     if (XmuConvertStandardSelection(w, xterm->screen.selection_time, selection,
1663 				    target, type,
1664 				    (caddr_t *)value, length, format))
1665 	return True;
1666 
1667     /* else */
1668     return False;
1669 
1670 }
1671 
1672 
LoseSelection(w,selection)1673 static void LoseSelection(w, selection)
1674   Widget w;
1675   Atom *selection;
1676 {
1677     register TScreen* screen = &((XtermWidget)w)->screen;
1678     register Atom* atomP;
1679     int i;
1680     for (i = 0, atomP = screen->selection_atoms;
1681 	 i < screen->selection_count; i++, atomP++)
1682     {
1683 	if (*selection == *atomP) *atomP = (Atom)0;
1684 	switch (*atomP) {
1685 	  case XA_CUT_BUFFER0:
1686 	  case XA_CUT_BUFFER1:
1687 	  case XA_CUT_BUFFER2:
1688 	  case XA_CUT_BUFFER3:
1689 	  case XA_CUT_BUFFER4:
1690 	  case XA_CUT_BUFFER5:
1691 	  case XA_CUT_BUFFER6:
1692 	  case XA_CUT_BUFFER7:	*atomP = (Atom)0;
1693 	}
1694     }
1695 
1696     for (i = screen->selection_count; i; i--) {
1697 	if (screen->selection_atoms[i-1] != 0) break;
1698     }
1699     screen->selection_count = i;
1700 
1701     for (i = 0, atomP = screen->selection_atoms;
1702 	 i < screen->selection_count; i++, atomP++)
1703     {
1704 	if (*atomP == (Atom)0) {
1705 	    *atomP = screen->selection_atoms[--screen->selection_count];
1706 	}
1707     }
1708 
1709     if (screen->selection_count == 0)
1710 	TrackText(0, 0, 0, 0);
1711 }
1712 
1713 
1714 #ifndef KTERM
1715 /* ARGSUSED */
SelectionDone(w,selection,target)1716 static void SelectionDone(w, selection, target)
1717 Widget w;
1718 Atom *selection, *target;
1719 {
1720     /* empty proc so Intrinsics know we want to keep storage */
1721 }
1722 #endif /* !KTERM */
1723 
1724 
_OwnSelection(termw,selections,count)1725 static void _OwnSelection(termw, selections, count)
1726     register XtermWidget termw;
1727     String *selections;
1728     Cardinal count;
1729 {
1730     Atom* atoms = termw->screen.selection_atoms;
1731     int i;
1732     Boolean have_selection = False;
1733 
1734     if (termw->screen.selection_length < 0) return;
1735 
1736     if (count > termw->screen.sel_atoms_size) {
1737 	XtFree((char*)atoms);
1738 	atoms = (Atom*)XtMalloc(count*sizeof(Atom));
1739 	termw->screen.selection_atoms = atoms;
1740 	termw->screen.sel_atoms_size = count;
1741     }
1742     XmuInternStrings( XtDisplay((Widget)termw), selections, count, atoms );
1743     for (i = 0; i < count; i++) {
1744 	int cutbuffer;
1745 	switch (atoms[i]) {
1746 	  case XA_CUT_BUFFER0: cutbuffer = 0; break;
1747 	  case XA_CUT_BUFFER1: cutbuffer = 1; break;
1748 	  case XA_CUT_BUFFER2: cutbuffer = 2; break;
1749 	  case XA_CUT_BUFFER3: cutbuffer = 3; break;
1750 	  case XA_CUT_BUFFER4: cutbuffer = 4; break;
1751 	  case XA_CUT_BUFFER5: cutbuffer = 5; break;
1752 	  case XA_CUT_BUFFER6: cutbuffer = 6; break;
1753 	  case XA_CUT_BUFFER7: cutbuffer = 7; break;
1754 	  default:	       cutbuffer = -1;
1755 	}
1756 	if (cutbuffer >= 0)
1757 	    if ( termw->screen.selection_length >
1758 		 4*XMaxRequestSize(XtDisplay((Widget)termw))-32)
1759 		fprintf(stderr,
1760 			"%s: selection too big (%d bytes), not storing in CUT_BUFFER%d\n",
1761 			xterm_name, termw->screen.selection_length, cutbuffer);
1762 	    else
1763 #ifdef KTERM
1764 	    {
1765 		/* Since type of a CUT_BUFFER is STRING, KANJI and KANA
1766 		 * characters can't be stored in a CUT_BUFFER
1767 		 */
1768 		int nw;
1769 		int nc = 0;
1770 		Ichr *p;
1771 		char *s, *q;
1772 		p = termw->screen.selection;
1773 		for (nw = termw->screen.selection_length; nw > 0; nw--, p++) {
1774 		    if (p->gset == GSET_ASCII)
1775 			nc++;
1776 		}
1777 		if (nc > 0) {
1778 		    char buf[256];
1779 		    p = termw->screen.selection;
1780 		    s = q = (nc > 256) ? XtMalloc(nc) : buf;
1781 		    for (nw = termw->screen.selection_length; nw > 0; nw--, p++) {
1782 			if (p->gset == GSET_ASCII)
1783 			    *q++ = p->code & 0x7f;
1784 		    }
1785 		    XStoreBuffer( XtDisplay((Widget)termw), s, nc, cutbuffer );
1786 		    if (s != buf) XtFree(s);
1787 		} else
1788 		    XStoreBuffer( XtDisplay((Widget)termw), NULL, nc, cutbuffer );
1789 	    }
1790 #else /* !KTERM */
1791 		XStoreBuffer( XtDisplay((Widget)termw), termw->screen.selection,
1792 			      termw->screen.selection_length, cutbuffer );
1793 #endif /* !KTERM */
1794 	else if (!replyToEmacs) {
1795 	    have_selection |=
1796 		XtOwnSelection( (Widget)termw, atoms[i],
1797 			    termw->screen.selection_time,
1798 #ifdef KTERM
1799 			    ConvertSelection, LoseSelection, NULL );
1800 #else /* !KTERM */
1801 			    ConvertSelection, LoseSelection, SelectionDone );
1802 #endif /* !KTERM */
1803 	}
1804     }
1805     if (!replyToEmacs)
1806 	termw->screen.selection_count = count;
1807     if (!have_selection)
1808 	TrackText(0, 0, 0, 0);
1809 }
1810 
1811 /* void */
DisownSelection(termw)1812 DisownSelection(termw)
1813     register XtermWidget termw;
1814 {
1815     Atom* atoms = termw->screen.selection_atoms;
1816     Cardinal count = termw->screen.selection_count;
1817     int i;
1818 
1819     for (i = 0; i < count; i++) {
1820 	int cutbuffer;
1821 	switch (atoms[i]) {
1822 	  case XA_CUT_BUFFER0: cutbuffer = 0; break;
1823 	  case XA_CUT_BUFFER1: cutbuffer = 1; break;
1824 	  case XA_CUT_BUFFER2: cutbuffer = 2; break;
1825 	  case XA_CUT_BUFFER3: cutbuffer = 3; break;
1826 	  case XA_CUT_BUFFER4: cutbuffer = 4; break;
1827 	  case XA_CUT_BUFFER5: cutbuffer = 5; break;
1828 	  case XA_CUT_BUFFER6: cutbuffer = 6; break;
1829 	  case XA_CUT_BUFFER7: cutbuffer = 7; break;
1830 	  default:	       cutbuffer = -1;
1831 	}
1832 	if (cutbuffer < 0)
1833 	    XtDisownSelection( (Widget)termw, atoms[i],
1834 			       termw->screen.selection_time );
1835     }
1836     termw->screen.selection_count = 0;
1837     termw->screen.startHRow = termw->screen.startHCol = 0;
1838     termw->screen.endHRow = termw->screen.endHCol = 0;
1839 }
1840 
1841 
1842 /* returns number of chars in line from scol to ecol out */
1843 /* ARGSUSED */
1844 static int
Length(screen,row,scol,ecol)1845 Length(screen, row, scol, ecol)
1846     register int row, scol, ecol;
1847     register TScreen *screen;
1848 {
1849         register int lastcol = LastTextCol(row);
1850 
1851 	if (ecol > lastcol)
1852 	    ecol = lastcol;
1853 	return (ecol - scol + 1);
1854 }
1855 
1856 /* copies text into line, preallocated */
1857 #ifdef KTERM
1858 static Ichr *
1859 #else /* !KTERM */
1860 static char *
1861 #endif /* !KTERM */
SaveText(screen,row,scol,ecol,lp,eol)1862 SaveText(screen, row, scol, ecol, lp, eol)
1863     int row;
1864     int scol, ecol;
1865     TScreen *screen;
1866 #ifdef KTERM
1867     register Ichr *lp;		/* pointer to where to put the text */
1868 #else /* !KTERM */
1869     register char *lp;		/* pointer to where to put the text */
1870 #endif /* !KTERM */
1871     int *eol;
1872 {
1873 	register int i = 0;
1874 #ifdef KTERM
1875 	register Bchr *ch = screen->buf[row + screen->topline];
1876 	register Char g;
1877 #else /* !KTERM */
1878 	register Char *ch = screen->buf[2 * (row + screen->topline)];
1879 #endif /* !KTERM */
1880 	Char attr;
1881 	register int c;
1882 
1883 	*eol = 0;
1884 	i = Length(screen, row, scol, ecol);
1885 	ecol = scol + i;
1886 	if (*eol == 0) {
1887 		if(ScrnGetAttributes(screen, row + screen->topline, 0, &attr, 1) == 1) {
1888 			*eol = (attr & LINEWRAPPED) ? 0 : 1;
1889 		} else {
1890 			/* If we can't get the attributes, assume no wrap */
1891 			/* CANTHAPPEN */
1892 			(void)fprintf(stderr, "%s: no attributes for %d, %d\n",
1893 				xterm_name, row, ecol - 1);
1894 			*eol = 1;
1895 		}
1896 	}
1897 	for (i = scol; i < ecol; i++) {
1898 #ifdef KTERM
1899 		c = ch[i].code & 0x7f;
1900 		g = ch[i].gset;
1901 		if (c < ' ' || c == 0x7f && !(g & CS96)) {
1902 			lp->code = ' ';
1903 			lp->gset = GSET_ASCII;
1904 		} else {
1905 			lp->code = c;
1906 			lp->gset = g;
1907 		}
1908 		lp++;
1909 #else /* !KTERM */
1910 	        c = ch[i];
1911 		if (c == 0)
1912 			c = ' ';
1913 		else if(c < ' ') {
1914 			if(c == '\036')
1915 				c = '#'; /* char on screen is pound sterling */
1916 			else
1917 				c += 0x5f; /* char is from DEC drawing set */
1918 		} else if(c == 0x7f)
1919 			c = 0x5f;
1920 		*lp++ = c;
1921 #endif /* !KTERM */
1922 	}
1923 	return(lp);
1924 }
1925 
1926 static void
EditorButton(event)1927 EditorButton(event)
1928     register XButtonEvent *event;
1929 {
1930 	register TScreen *screen = &term->screen;
1931 	int pty = screen->respond;
1932 	char line[6];
1933 	register unsigned row, col;
1934 	int button;
1935 
1936 	button = event->button - 1;
1937 
1938 	row = (event->y - screen->border)
1939 	 / FontHeight(screen);
1940 	col = (event->x - screen->border - screen->scrollbar)
1941 	 / FontWidth(screen);
1942 	(void) strcpy(line, "\033[M");
1943 	if (screen->send_mouse_pos == 1) {
1944 		line[3] = ' ' + button;
1945 	} else {
1946 		line[3] = ' ' + (KeyState(event->state) << 2) +
1947 			((event->type == ButtonPress)? button:3);
1948 	}
1949 	line[4] = ' ' + col + 1;
1950 	line[5] = ' ' + row + 1;
1951 	v_write(pty, line, 6);
1952 }
1953 
1954 
1955 #ifndef KTERM_NOTEK
1956 /*ARGSUSED*/
HandleGINInput(w,event,param_list,nparamsp)1957 void HandleGINInput (w, event, param_list, nparamsp)
1958     Widget w;
1959     XEvent *event;
1960     String *param_list;
1961     Cardinal *nparamsp;
1962 {
1963     if (term->screen.TekGIN && *nparamsp == 1) {
1964 	int c = param_list[0][0];
1965 	switch (c) {
1966 	  case 'l': case 'm': case 'r':
1967 	  case 'L': case 'M': case 'R':
1968 	    break;
1969 	  default:
1970 	    Bell (XkbBI_MinorError,0);	/* let them know they goofed */
1971 	    c = 'l';				/* provide a default */
1972 	}
1973 	TekEnqMouse (c | 0x80);
1974 	TekGINoff();
1975     } else {
1976 	Bell (XkbBI_MinorError,0);
1977     }
1978 }
1979 #endif /* !KTERM_NOTEK */
1980 
1981 
1982 /* ARGSUSED */
HandleSecure(w,event,params,param_count)1983 void HandleSecure(w, event, params, param_count)
1984     Widget w;
1985     XEvent *event;		/* unused */
1986     String *params;		/* [0] = volume */
1987     Cardinal *param_count;	/* 0 or 1 */
1988 {
1989     Time time = CurrentTime;
1990 
1991     if ((event->xany.type == KeyPress) ||
1992 	(event->xany.type == KeyRelease))
1993 	time = event->xkey.time;
1994     else if ((event->xany.type == ButtonPress) ||
1995 	     (event->xany.type == ButtonRelease))
1996       time = event->xbutton.time;
1997     DoSecureKeyboard (time);
1998 }
1999