|
|
1.1 root 1: /*
2: * $Source: /orpheus/u1/X11/clients/xterm/RCS/button.c,v $
3: * $Header: button.c,v 1.19 87/09/10 17:20:59 swick Exp $
4: */
5:
6:
7: #include <X11/copyright.h>
8:
9: /*
10: * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
11: *
12: * All Rights Reserved
13: *
14: * Permission to use, copy, modify, and distribute this software and its
15: * documentation for any purpose and without fee is hereby granted,
16: * provided that the above copyright notice appear in all copies and that
17: * both that copyright notice and this permission notice appear in
18: * supporting documentation, and that the name of Digital Equipment
19: * Corporation not be used in advertising or publicity pertaining to
20: * distribution of the software without specific, written prior permission.
21: *
22: *
23: * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24: * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25: * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26: * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27: * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28: * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29: * SOFTWARE.
30: */
31:
32: /*
33: button.c Handles button events in the terminal emulator.
34: does cut/paste operations, change modes via menu,
35: passes button events through to some applications.
36: J. Gettys.
37: */
38: #ifndef lint
39: static char rcs_id[] = "$Header: button.c,v 1.19 87/09/10 17:20:59 swick Exp $";
40: #endif lint
41: #include <stdio.h>
42: #include <signal.h>
43: #include <setjmp.h>
44: #include <ctype.h>
45: #include <strings.h>
46: #include <X11/Xlib.h>
47: #include <X11/Intrinsic.h>
48: #include "ptyx.h"
49: #include "data.h"
50: #include "error.h"
51: #ifdef MODEMENU
52: #include "menu.h"
53: #endif MODEMENU
54:
55: extern char *malloc();
56:
57: #define KeyState(x) ((x) & (ShiftMask|ControlMask|Mod1Mask))
58: #define X10Map(state) ((state&ShiftMask?4:0) + (state&ControlMask?16:0) \
59: + (state&Mod1Mask?8:0))
60:
61: #define TEXTMODES 4
62: #define NBUTS 3
63: #define DIRS 2
64: #define UP 1
65: #define DOWN 0
66: #define SHIFTS 8 /* three keys, so eight combinations */
67: #define Coordinate(r,c) ((r) * (term.screen.max_col+1) + (c))
68:
69: char *SaveText();
70: extern UnSaltText();
71: extern StartCut();
72: extern StartExtend();
73: extern EditorButton();
74: extern TrackDown();
75:
76: extern ModeMenu();
77: extern char *xterm_name;
78: extern Bogus(), Silence();
79: extern GINbutton();
80:
81: /* due to LK201 limitations, not all of the below are actually possible */
82: static int (*textfunc[TEXTMODES][SHIFTS][DIRS][NBUTS])() = {
83: /* left middle right */
84: StartCut, Silence, StartExtend, /* down | */
85: Silence, UnSaltText, Silence, /* up |no shift */
86:
87: StartCut, Silence, StartExtend, /* down | */
88: Silence, UnSaltText, Silence, /* up |shift */
89:
90: Bogus, Bogus, Bogus, /* down | */
91: Silence, Silence, Silence, /* up |meta */
92:
93: Bogus, Bogus, Bogus, /* down | */
94: Silence, Silence, Silence, /* up |meta shift */
95:
96: ModeMenu, ModeMenu, ModeMenu, /* down | */
97: Silence, Silence, Silence, /* up |control */
98:
99: ModeMenu, ModeMenu, ModeMenu, /* down | */
100: Silence, Silence, Silence, /* up |ctl shift */
101:
102: Bogus, Bogus, Bogus, /* down | */
103: Silence, Silence, Silence, /* up |ctl meta */
104:
105: Bogus, Bogus, Bogus, /* down | control */
106: Silence, Silence, Silence, /* up |meta shift*/
107:
108: /* MIT mouse bogus sequence */
109: /* button, shift keys, and direction */
110: /* left middle right */
111: EditorButton, EditorButton, EditorButton, /* down | */
112: Silence, Silence, Silence, /* up |no shift */
113:
114: StartCut, Silence, StartExtend, /* down | */
115: Silence, UnSaltText, Silence, /* up |shift */
116:
117: Bogus, Bogus, Bogus, /* down | */
118: Silence, Silence, Silence, /* up |meta */
119:
120: Bogus, Bogus, Bogus, /* down | */
121: Silence, Silence, Silence, /* up |meta shift */
122:
123: ModeMenu, ModeMenu, ModeMenu, /* down | */
124: Silence, Silence, Silence, /* up |control */
125:
126: ModeMenu, ModeMenu, ModeMenu, /* down | */
127: Silence, Silence, Silence, /* up |ctl shift */
128:
129: Bogus, Bogus, Bogus, /* down | */
130: Silence, Silence, Silence, /* up |ctl meta */
131:
132: Bogus, Bogus, Bogus, /* down | control */
133: Silence, Silence, Silence, /* up |meta shift*/
134:
135: /* DEC mouse bogus sequence */
136: /* button, shift keys, and direction */
137: /* left middle right */
138: EditorButton, EditorButton, EditorButton, /* down | */
139: EditorButton, EditorButton, EditorButton, /* up |no shift */
140:
141: StartCut, Silence, StartExtend, /* down | */
142: Silence, UnSaltText, Silence, /* up |shift */
143:
144: Bogus, Bogus, Bogus, /* down | */
145: Silence, Silence, Silence, /* up |meta */
146:
147: Bogus, Bogus, Bogus, /* down | */
148: Silence, Silence, Silence, /* up |meta shift */
149:
150: EditorButton, EditorButton, EditorButton, /* down | */
151: EditorButton, EditorButton, EditorButton, /* up |control */
152:
153: ModeMenu, ModeMenu, ModeMenu, /* down | */
154: Silence, Silence, Silence, /* up |ctl shift */
155:
156: Bogus, Bogus, Bogus, /* down | */
157: Silence, Silence, Silence, /* up |ctl meta */
158:
159: Bogus, Bogus, Bogus, /* down | control */
160: Silence, Silence, Silence, /* up |meta shift*/
161:
162: /* Hilite tracking DEC mouse bogus sequence */
163: /* button, shift keys, and direction */
164: /* left middle right */
165: TrackDown, EditorButton, EditorButton, /* down | */
166: EditorButton, EditorButton, EditorButton, /* up |no shift */
167:
168: StartCut, Silence, StartExtend, /* down | */
169: Silence, UnSaltText, Silence, /* up |shift */
170:
171: Bogus, Bogus, Bogus, /* down | */
172: Silence, Silence, Silence, /* up |meta */
173:
174: Bogus, Bogus, Bogus, /* down | */
175: Silence, Silence, Silence, /* up |meta shift */
176:
177: EditorButton, EditorButton, EditorButton, /* down | */
178: EditorButton, EditorButton, EditorButton, /* up |control */
179:
180: ModeMenu, ModeMenu, ModeMenu, /* down | */
181: Silence, Silence, Silence, /* up |ctl shift */
182:
183: Bogus, Bogus, Bogus, /* down | */
184: Silence, Silence, Silence, /* up |ctl meta */
185:
186: Bogus, Bogus, Bogus, /* down | control */
187: Silence, Silence, Silence /* up |meta shift */
188:
189: };
190:
191: /* button and shift keys for Tek mode */
192: static int (*Tbfunc[SHIFTS][NBUTS])() = {
193: /* left middle right */
194: GINbutton, GINbutton, GINbutton, /* down |no shift */
195:
196: GINbutton, GINbutton, GINbutton, /* down |shift */
197:
198: Bogus, Bogus, Bogus, /* down |meta */
199:
200: Bogus, Bogus, Bogus, /* down |meta shift */
201:
202: ModeMenu, ModeMenu, ModeMenu, /* down |control */
203:
204: ModeMenu, ModeMenu, ModeMenu, /* down |ctl shift */
205:
206: Bogus, Bogus, Bogus, /* down |ctl meta */
207:
208: Bogus, Bogus, Bogus, /* down | all */
209:
210: }; /* button and shift keys */
211:
212: extern Terminal term;
213:
214: /* Selection/extension variables */
215:
216: /* Raw char position where the selection started */
217: static int rawRow, rawCol;
218:
219: /* Hilited area */
220: static int startHRow, startHCol, endHRow, endHCol, startHCoord, endHCoord = 0;
221:
222: /* Selected area before CHAR, WORD, LINE selectUnit processing */
223: static int startRRow, startRCol, endRRow, endRCol = 0;
224:
225: /* Selected area after CHAR, WORD, LINE selectUnit processing */
226: static int startSRow, startSCol, endSRow, endSCol = 0;
227:
228: /* Valid rows for selection clipping */
229: static int firstValidRow, lastValidRow;
230:
231: /* Start, end of extension */
232: static int startERow, startECol, endERow, endECol;
233:
234: /* Saved values of raw selection for extend to restore to */
235: static int saveStartRRow, saveStartRCol, saveEndRRow, saveEndRCol;
236:
237: /* Multi-click handling */
238: static int numberOfClicks = 0;
239: static long int lastButtonUpTime = 0;
240: typedef enum {SELECTCHAR, SELECTWORD, SELECTLINE} SelectUnit;
241: static SelectUnit selectUnit;
242:
243: /* Send emacs escape code when done selecting or extending? */
244: static int replyToEmacs;
245:
246:
247: /*ARGSUSED*/
248: XtEventReturnCode VTButtonPressed(event, eventdata)
249: register XButtonEvent *event;
250: caddr_t eventdata;
251: {
252: register TScreen *screen = &term.screen;
253: /* so table above will be nice, we index from 0 */
254: int button = event->button - 1;
255: int shift = KeyState(event->state);
256:
257: if (eventMode != NORMAL)
258: return (XteventHandled);
259: if (screen->incopy)
260: CopyWait (screen);
261: textfunc[screen->send_mouse_pos][shift][0][button](event);
262: return (XteventHandled);
263: }
264:
265: /*ARGSUSED*/
266: XtEventReturnCode VTMouseMoved(event, eventdata)
267: register XMotionEvent *event;
268: caddr_t eventdata;
269: {
270: switch (eventMode) {
271: case LEFTEXTENSION :
272: case RIGHTEXTENSION :
273: ExtendExtend(event->x, event->y);
274: break;
275: default :
276: /* Should get here rarely when everything
277: fixed with windows and the event mgr */
278: /* fprintf(stderr, "Race mouse motion\n");
279: */ break;
280: }
281: return (XteventHandled);
282: }
283:
284:
285: /*ARGSUSED*/
286: XtEventReturnCode VTButtonReleased(event, eventdata)
287: register XButtonEvent *event;
288: caddr_t eventdata;
289: {
290: register TScreen *screen = &term.screen;
291: /* so table above will be nice, we index from 0 */
292: int button = event->button - 1;
293: int shift = KeyState(event->state);
294:
295: switch (eventMode) {
296: case NORMAL :
297: textfunc[screen->send_mouse_pos][shift][1][button]
298: (event);
299: break;
300: case LEFTEXTENSION :
301: case RIGHTEXTENSION :
302: if AllButtonsUp(event->state, event->button)
303: EndExtend(event);
304: break;
305: }
306: return (XteventHandled);
307: }
308:
309: /*ARGSUSED*/
310: XtEventReturnCode TekButtonPressed(event, eventdata)
311: register XButtonEvent *event;
312: caddr_t eventdata;
313: {
314: register TScreen *screen = &term.screen;
315: /* so table above will be nice, we index from 0 */
316: int button = event->button - 1;
317: int shift = KeyState(event->state);
318:
319: if (screen->incopy)
320: CopyWait (screen);
321: Tbfunc[shift][button](event);
322: return (XteventHandled);
323: }
324:
325:
326: /*ARGSUSED*/
327: UnSaltText(event)
328: XEvent *event;
329: {
330: int pty = term.screen.respond; /* file descriptor of pty */
331: char *line;
332: int nbytes;
333: register char *lag, *cp, *end;
334: register TScreen *screen = &term.screen;
335:
336: line = XFetchBytes(screen->display,&nbytes);
337: if (!nbytes) return;
338: end = &line[nbytes];
339: lag = line;
340: for (cp = line; cp != end; cp++)
341: {
342: if (*cp != '\n') continue;
343: *cp = '\r';
344: v_write(pty, lag, cp - lag + 1);
345: lag = cp + 1;
346: }
347: if (lag != end)
348: v_write(pty, lag, end - lag);
349: free (line); /* free text from fetch */
350: }
351:
352:
353: #define MULTICLICKTIME 250
354:
355: SetSelectUnit(buttonDownTime, defaultUnit)
356: unsigned long buttonDownTime;
357: SelectUnit defaultUnit;
358: {
359: /* Do arithmetic as integers, but compare as unsigned solves clock wraparound */
360: if ((long unsigned)((long int)buttonDownTime - lastButtonUpTime)
361: > MULTICLICKTIME) {
362: numberOfClicks = 1;
363: selectUnit = defaultUnit;
364: } else {
365: ++numberOfClicks;
366: /* Don't bitch. This is only temporary. */
367: selectUnit = (SelectUnit) (((int) selectUnit + 1) % 3);
368: }
369: }
370:
371: StartCut(event)
372: register XButtonEvent *event;
373: {
374: register TScreen *screen = &term.screen;
375: int startrow, startcol;
376:
377: firstValidRow = 0;
378: lastValidRow = screen->max_row;
379: SetSelectUnit(event->time, SELECTCHAR);
380: PointToRowCol(event->y, event->x, &startrow, &startcol);
381: replyToEmacs = FALSE;
382: StartSelect(startrow, startcol);
383: }
384:
385:
386: TrackDown(event)
387: register XButtonEvent *event;
388: {
389: int startrow, startcol;
390:
391: SetSelectUnit(event->time, SELECTCHAR);
392: if (numberOfClicks > 1 ) {
393: PointToRowCol(event->y, event->x, &startrow, &startcol);
394: replyToEmacs = TRUE;
395: StartSelect(startrow, startcol);
396: } else {
397: waitingForTrackInfo = 1;
398: EditorButton(event);
399: }
400: }
401:
402:
403: TrackMouse(func, startrow, startcol, firstrow, lastrow)
404: int func, startrow, startcol, firstrow, lastrow;
405: {
406: if (!waitingForTrackInfo) { /* Timed out, so ignore */
407: return;
408: }
409: waitingForTrackInfo = 0;
410: if (func == 0) return;
411:
412: firstValidRow = firstrow;
413: lastValidRow = lastrow;
414: replyToEmacs = TRUE;
415: StartSelect(startrow, startcol);
416: }
417:
418: StartSelect(startrow, startcol)
419: int startrow, startcol;
420: {
421: TScreen *screen = &term.screen;
422:
423: if (screen->cursor_state)
424: HideCursor ();
425: if (numberOfClicks == 1) {
426: /* set start of selection */
427: rawRow = startrow;
428: rawCol = startcol;
429:
430: } /* else use old values in rawRow, Col */
431:
432: saveStartRRow = startERow = rawRow;
433: saveStartRCol = startECol = rawCol;
434: saveEndRRow = endERow = rawRow;
435: saveEndRCol = endECol = rawCol;
436: if (Coordinate(startrow, startcol) < Coordinate(rawRow, rawCol)) {
437: eventMode = LEFTEXTENSION;
438: startERow = startrow;
439: startECol = startcol;
440: } else {
441: eventMode = RIGHTEXTENSION;
442: endERow = startrow;
443: endECol = startcol;
444: }
445: ComputeSelect(startERow, startECol, endERow, endECol);
446:
447: }
448:
449: EndExtend(event)
450: XButtonEvent *event;
451: {
452: int row, col;
453: TScreen *screen = &term.screen;
454: char line[9];
455:
456: ExtendExtend(event->x, event->y);
457:
458: lastButtonUpTime = event->time;
459: PointToRowCol(event->y, event->x, &row, &col);
460: /* Only do select stuff if non-null select */
461: if (startSRow != endSRow || startSCol != endSCol) {
462: if (replyToEmacs) {
463: if (rawRow == startSRow && rawCol == startSCol
464: && row == endSRow && col == endSCol) {
465: /* Use short-form emacs select */
466: strcpy(line, "\033[t");
467: line[3] = ' ' + endSCol + 1;
468: line[4] = ' ' + endSRow + 1;
469: v_write(screen->respond, line, 5);
470: } else {
471: /* long-form, specify everything */
472: strcpy(line, "\033[T");
473: line[3] = ' ' + startSCol + 1;
474: line[4] = ' ' + startSRow + 1;
475: line[5] = ' ' + endSCol + 1;
476: line[6] = ' ' + endSRow + 1;
477: line[7] = ' ' + col + 1;
478: line[8] = ' ' + row + 1;
479: v_write(screen->respond, line, 9);
480: }
481: }
482: SaltTextAway(startSRow, startSCol, endSRow, endSCol);
483: }
484: TrackText(0, 0, 0, 0);
485: eventMode = NORMAL;
486: }
487:
488: #define Abs(x) ((x) < 0 ? -(x) : (x))
489:
490: StartExtend(event)
491: XButtonEvent *event;
492: {
493: TScreen *screen = &term.screen;
494: int row, col, coord;
495:
496: firstValidRow = 0;
497: lastValidRow = screen->max_row;
498: SetSelectUnit(event->time, selectUnit);
499: replyToEmacs = FALSE;
500:
501: if (numberOfClicks == 1) {
502: /* Save existing selection so we can reestablish it if the guy
503: extends past the other end of the selection */
504: saveStartRRow = startERow = startRRow;
505: saveStartRCol = startECol = startRCol;
506: saveEndRRow = endERow = endRRow;
507: saveEndRCol = endECol = endRCol;
508: } else {
509: /* He just needed the selection mode changed, use old values. */
510: startERow = startRRow = saveStartRRow;
511: startECol = startRCol = saveStartRCol;
512: endERow = endRRow = saveEndRRow;
513: endECol = endRCol = saveEndRCol;
514:
515: }
516: PointToRowCol(event->y, event->x, &row, &col);
517: coord = Coordinate(row, col);
518:
519: if (Abs(coord - Coordinate(startSRow, startSCol))
520: < Abs(coord - Coordinate(endSRow, endSCol))
521: || coord < Coordinate(startSRow, startSCol)) {
522: /* point is close to left side of selection */
523: eventMode = LEFTEXTENSION;
524: startERow = row;
525: startECol = col;
526: } else {
527: /* point is close to left side of selection */
528: eventMode = RIGHTEXTENSION;
529: endERow = row;
530: endECol = col;
531: }
532: ComputeSelect(startERow, startECol, endERow, endECol);
533: }
534:
535: ExtendExtend(x, y)
536: int x, y;
537: {
538: int row, col, coord;
539:
540: PointToRowCol(y, x, &row, &col);
541: coord = Coordinate(row, col);
542:
543: if (eventMode == LEFTEXTENSION
544: && (coord + (selectUnit!=SELECTCHAR)) > Coordinate(endSRow, endSCol)) {
545: /* Whoops, he's changed his mind. Do RIGHTEXTENSION */
546: eventMode = RIGHTEXTENSION;
547: startERow = saveStartRRow;
548: startECol = saveStartRCol;
549: } else if (eventMode == RIGHTEXTENSION
550: && coord < Coordinate(startSRow, startSCol)) {
551: /* Whoops, he's changed his mind. Do LEFTEXTENSION */
552: eventMode = LEFTEXTENSION;
553: endERow = saveEndRRow;
554: endECol = saveEndRCol;
555: }
556: if (eventMode == LEFTEXTENSION) {
557: startERow = row;
558: startECol = col;
559: } else {
560: endERow = row;
561: endECol = col;
562: }
563: ComputeSelect(startERow, startECol, endERow, endECol);
564: }
565:
566:
567: ScrollSelection(amount)
568: int amount;
569: {
570: /* Sent by scrollbar stuff, so amount never takes selection out of
571: saved text */
572: startRRow += amount; endRRow += amount; startSRow += amount; endSRow += amount;
573: rawRow += amount;
574: }
575:
576:
577: PointToRowCol(y, x, r, c)
578: register int y, x;
579: int *r, *c;
580: /* Convert pixel coordinates to character coordinates.
581: Rows are clipped between firstValidRow and lastValidRow.
582: Columns are clipped between to be 0 or greater, but are not clipped to some
583: maximum value. */
584: {
585: register TScreen *screen = &term.screen;
586: register row, col;
587:
588: row = (y - screen->border) / FontHeight(screen);
589: if(row < firstValidRow)
590: row = firstValidRow;
591: else if(row > lastValidRow)
592: row = lastValidRow;
593: col = (x - screen->border - screen->scrollbar) / FontWidth(screen);
594: if(col < 0)
595: col = 0;
596: else if(col > screen->max_col+1) {
597: col = screen->max_col+1;
598: }
599: *r = row;
600: *c = col;
601: }
602:
603: int LastTextCol(row)
604: register int row;
605: {
606: register TScreen *screen = &term.screen;
607: register int i;
608: register char *ch;
609:
610: for(i = screen->max_col,
611: ch = screen->buf[2 * (row + screen->topline)] + i ;
612: i > 0 && *ch == 0 ; ch--, i--);
613: return(i);
614: }
615:
616: static int charClass[128] = {
617: /* NUL SOH STX ETX EOT ENQ ACK BEL */
618: 32, 1, 1, 1, 1, 1, 1, 1,
619: /* BS HT NL VT NP CR SO SI */
620: 1, 32, 1, 1, 1, 1, 1, 1,
621: /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
622: 1, 1, 1, 1, 1, 1, 1, 1,
623: /* CAN EM SUB ESC FS GS RS US */
624: 1, 1, 1, 1, 1, 1, 1, 1,
625: /* SP ! " # $ % & ' */
626: 32, 33, 34, 35, 36, 37, 38, 39,
627: /* ( ) * + , - . / */
628: 40, 41, 42, 43, 44, 45, 46, 47,
629: /* 0 1 2 3 4 5 6 7 */
630: 48, 48, 48, 48, 48, 48, 48, 48,
631: /* 8 9 : ; < = > ? */
632: 48, 48, 58, 59, 60, 61, 62, 63,
633: /* @ A B C D E F G */
634: 64, 48, 48, 48, 48, 48, 48, 48,
635: /* H I J K L M N O */
636: 48, 48, 48, 48, 48, 48, 48, 48,
637: /* P Q R S T U V W */
638: 48, 48, 48, 48, 48, 48, 48, 48,
639: /* X Y Z [ \ ] ^ _ */
640: 48, 48, 48, 91, 92, 93, 94, 48,
641: /* ` a b c d e f g */
642: 96, 48, 48, 48, 48, 48, 48, 48,
643: /* h i j k l m n o */
644: 48, 48, 48, 48, 48, 48, 48, 48,
645: /* p q r s t u v w */
646: 48, 48, 48, 48, 48, 48, 48, 48,
647: /* x y z { | } ~ DEL */
648: 48, 48, 48, 123, 124, 125, 126, 1};
649:
650:
651: ComputeSelect(startRow, startCol, endRow, endCol)
652: int startRow, startCol, endRow, endCol;
653: {
654: register TScreen *screen = &term.screen;
655: register char *ptr;
656: register int length;
657: register int class;
658:
659: if (Coordinate(startRow, startCol) <= Coordinate(endRow, endCol)) {
660: startSRow = startRRow = startRow;
661: startSCol = startRCol = startCol;
662: endSRow = endRRow = endRow;
663: endSCol = endRCol = endCol;
664: } else { /* Swap them */
665: startSRow = startRRow = endRow;
666: startSCol = startRCol = endCol;
667: endSRow = endRRow = startRow;
668: endSCol = endRCol = startCol;
669: }
670:
671: switch (selectUnit) {
672: case SELECTCHAR :
673: if (startSCol > (LastTextCol(startSRow) + 1)) {
674: startSCol = 0;
675: startSRow++;
676: }
677: if (endSCol > (LastTextCol(endSRow) + 1)) {
678: endSCol = 0;
679: endSRow++;
680: }
681: break;
682: case SELECTWORD :
683: if (startSCol > (LastTextCol(startSRow) + 1)) {
684: startSCol = 0;
685: startSRow++;
686: } else {
687: ptr = screen->buf[2*(startSRow+screen->topline)]
688: + startSCol;
689: class = charClass[*ptr];
690: do {
691: --startSCol;
692: --ptr;
693: } while (startSCol >= 0
694: && charClass[*ptr] == class);
695: ++startSCol;
696: }
697: if (endSCol > (LastTextCol(endSRow) + 1)) {
698: endSCol = 0;
699: endSRow++;
700: } else {
701: length = LastTextCol(endSRow);
702: ptr = screen->buf[2*(endSRow+screen->topline)]
703: + endSCol;
704: class = charClass[*ptr];
705: do {
706: ++endSCol;
707: ++ptr;
708: } while (endSCol <= length
709: && charClass[*ptr] == class);
710: /* Word select selects if pointing to any char
711: in "word", especially in that it includes
712: the last character in a word. So no --endSCol
713: and do special eol handling */
714: if (endSCol > length+1) {
715: endSCol = 0;
716: ++endSRow;
717: }
718: }
719: break;
720: case SELECTLINE :
721: startSCol = 0;
722: endSCol = 0;
723: ++endSRow;
724: break;
725: }
726: TrackText(startSRow, startSCol, endSRow, endSCol);
727: return;
728: }
729:
730:
731: TrackText(frow, fcol, trow, tcol)
732: register int frow, fcol, trow, tcol;
733: /* Guaranteed (frow, fcol) <= (trow, tcol) */
734: {
735: register int from, to;
736: register TScreen *screen = &term.screen;
737:
738: /* (frow, fcol) may have been scrolled off top of display */
739: if (frow < 0)
740: frow = fcol = 0;
741: /* (trow, tcol) may have been scrolled off bottom of display */
742: if (trow > screen->max_row+1) {
743: trow = screen->max_row+1;
744: tcol = 0;
745: }
746: from = Coordinate(frow, fcol);
747: to = Coordinate(trow, tcol);
748: if (to <= startHCoord || from > endHCoord) {
749: /* No overlap whatsoever between old and new hilite */
750: HiliteText(startHRow, startHCol, endHRow, endHCol, FALSE);
751: HiliteText(frow, fcol, trow, tcol, TRUE);
752: } else {
753: if (from < startHCoord) {
754: /* Extend left end */
755: HiliteText(frow, fcol, startHRow, startHCol, TRUE);
756: } else if (from > startHCoord) {
757: /* Shorten left end */
758: HiliteText(startHRow, startHCol, frow, fcol, FALSE);
759: }
760: if (to > endHCoord) {
761: /* Extend right end */
762: HiliteText(endHRow, endHCol, trow, tcol, TRUE);
763: } else if (to < endHCoord) {
764: /* Shorten right end */
765: HiliteText(trow, tcol, endHRow, endHCol, FALSE);
766: }
767: }
768: startHRow = frow;
769: startHCol = fcol;
770: endHRow = trow;
771: endHCol = tcol;
772: startHCoord = from;
773: endHCoord = to;
774: }
775:
776: HiliteText(frow, fcol, trow, tcol, hilite)
777: register int frow, fcol, trow, tcol;
778: int hilite;
779: /* Guaranteed that (frow, fcol) <= (trow, tcol) */
780: {
781: register TScreen *screen = &term.screen;
782: register int i, j;
783: GC tempgc;
784:
785: if (frow == trow && fcol == tcol)
786: return;
787: if(hilite) {
788: tempgc = screen->normalGC;
789: screen->normalGC = screen->reverseGC;
790: screen->reverseGC = tempgc;
791: tempgc = screen->normalboldGC;
792: screen->normalboldGC = screen->reverseboldGC;
793: screen->reverseboldGC = tempgc;
794:
795:
796: i = screen->foreground;
797: screen->foreground = screen->background;
798: screen->background = i;
799: XSetWindowBackground(screen->display,VWindow(screen),screen->background);
800:
801: }
802: if(frow != trow) { /* do multiple rows */
803: if((i = screen->max_col - fcol + 1) > 0) { /* first row */
804: XClearArea(
805: screen->display,
806: VWindow(screen),
807: (int) CursorX(screen, fcol),
808: (int) frow * FontHeight(screen) + screen->border,
809: (unsigned) i*FontWidth(screen),
810: (unsigned) FontHeight(screen),
811: FALSE);
812: ScrnRefresh(screen, frow, fcol, 1, i);
813: }
814: if((i = trow - frow - 1) > 0) { /* middle rows*/
815: j = screen->max_col + 1;
816: XClearArea(
817: screen->display,
818: VWindow(screen),
819: (int) screen->border + screen->scrollbar,
820: (int) (frow+1)*FontHeight(screen) + screen->border,
821: (unsigned) j * FontWidth(screen),
822: (unsigned) i * FontHeight(screen),
823: FALSE);
824: ScrnRefresh(screen, frow + 1, 0, i, j);
825: }
826: if(tcol > 0 && trow <= screen->max_row) { /* last row */
827: XClearArea(
828: screen->display,
829: VWindow(screen),
830: (int) screen->border + screen->scrollbar,
831: (int) trow * FontHeight(screen) + screen->border,
832: (unsigned) tcol * FontWidth(screen),
833: (unsigned) FontHeight(screen),
834: FALSE);
835: ScrnRefresh(screen, trow, 0, 1, tcol);
836: }
837: } else { /* do single row */
838: i = tcol - fcol;
839: XClearArea(
840: screen->display,
841: VWindow(screen),
842: (int) CursorX(screen, fcol),
843: (int) frow * FontHeight(screen) + screen->border,
844: (unsigned) i * FontWidth(screen),
845: (unsigned) FontHeight(screen),
846: FALSE);
847: ScrnRefresh(screen, frow, fcol, 1, tcol - fcol);
848: }
849: if(hilite) {
850: tempgc = screen->normalGC;
851: screen->normalGC = screen->reverseGC;
852: screen->reverseGC = tempgc;
853: tempgc = screen->normalboldGC;
854: screen->normalboldGC = screen->reverseboldGC;
855: screen->reverseboldGC = tempgc;
856:
857: i = screen->foreground;
858: screen->foreground = screen->background;
859: screen->background = i;
860: XSetWindowBackground(screen->display,VWindow(screen),screen->background);
861:
862: }
863: }
864:
865: SaltTextAway(crow, ccol, row, col)
866: register crow, ccol, row, col;
867: /* Guaranteed that (crow, ccol) <= (row, col), and that both points are valid
868: (may have row = screen->max_row+1, col = 0) */
869: {
870: register TScreen *screen = &term.screen;
871: register int i, j = 0;
872: char *line, *lp;
873:
874: --col;
875: /* first we need to know how long the string is before we can save it*/
876:
877: if ( row == crow ) j = Length(screen, crow, ccol, col);
878: else { /* two cases, cut is on same line, cut spans multiple lines */
879: j += Length(screen, crow, ccol, screen->max_col) + 1;
880: for(i = crow + 1; i < row; i++)
881: j += Length(screen, i, 0, screen->max_col) + 1;
882: if (col >= 0)
883: j += Length(screen, row, 0, col);
884: }
885:
886: /* now get some memory to save it in */
887:
888: if((line = malloc((unsigned) j + 1)) == (char *)NULL)
889: SysError(ERROR_BMALLOC2);
890: line[j] = '\0'; /* make sure it is null terminated */
891: lp = line; /* lp points to where to save the text */
892: if ( row == crow ) lp = SaveText(screen, row, ccol, col, lp);
893: else {
894: lp = SaveText(screen, crow, ccol, screen->max_col, lp);
895: *lp ++ = '\n'; /* put in newline at end of line */
896: for(i = crow +1; i < row; i++) {
897: lp = SaveText(screen, i, 0, screen->max_col, lp);
898: *lp ++ = '\n';
899: }
900: if (col >= 0)
901: lp = SaveText(screen, row, 0, col, lp);
902: }
903: *lp = '\0'; /* make sure we have end marked */
904:
905: XStoreBytes(screen->display,line, j);
906: free(line);
907: }
908:
909: /* returns number of chars in line from scol to ecol out */
910: int Length(screen, row, scol, ecol)
911: register int row, scol, ecol;
912: register TScreen *screen;
913: {
914: register char *ch;
915:
916: ch = screen->buf[2 * (row + screen->topline)];
917: while (ecol >= scol && ch[ecol] == 0)
918: ecol--;
919: return (ecol - scol + 1);
920: }
921:
922: /* copies text into line, preallocated */
923: char *SaveText(screen, row, scol, ecol, lp)
924: int row;
925: int scol, ecol;
926: TScreen *screen;
927: register char *lp; /* pointer to where to put the text */
928: {
929: register int i = 0;
930: register char *ch = screen->buf[2 * (row + screen->topline)];
931: register int c;
932:
933: if ((i = Length(screen, row, scol, ecol)) == 0) return(lp);
934: ecol = scol + i;
935: for (i = scol; i < ecol; i++) {
936: if ((c = ch[i]) == 0)
937: c = ' ';
938: else if(c < ' ') {
939: if(c == '\036')
940: c = '#';
941: else
942: c += 0x5f;
943: } else if(c == 0x7f)
944: c = 0x5f;
945: *lp++ = c;
946: }
947: return(lp);
948: }
949:
950: EditorButton(event)
951: register XButtonEvent *event;
952: {
953: register TScreen *screen = &term.screen;
954: int pty = screen->respond;
955: char line[6];
956: register unsigned row, col;
957: int button;
958:
959: button = event->button - 1;
960:
961: row = (event->y - screen->border)
962: / FontHeight(screen);
963: col = (event->x - screen->border - screen->scrollbar)
964: / FontWidth(screen);
965: (void) strcpy(line, "\033[M");
966: if (screen->send_mouse_pos == 1) {
967: line[3] = ' ' + button;
968: } else {
969: line[3] = ' ' + X10Map(event->state) +
970: ((event->type == ButtonPress)? button:3);
971: }
972: line[4] = ' ' + col + 1;
973: line[5] = ' ' + row + 1;
974: v_write(pty, line, 6);
975: }
976:
977: #ifdef MODEMENU
978: #define XTERMMENU 0
979: #define VTMENU 1
980: #define TEKMENU 2
981: #define NMENUS 3
982:
983: static Menu *menus[NMENUS];
984: static int type;
985: extern TekLink *TekRefresh;
986:
987: ModeMenu(event)
988: register XButtonEvent *event;
989: {
990: register TScreen *screen = &term.screen;
991: register Menu *menu;
992: register int item;
993: static int inited;
994: extern Menu *setupmenu(), *Tsetupmenu(), *xsetupmenu();
995:
996:
997: if(!inited) {
998: extern Pixmap Gray_Tile;
999: extern Cursor Menu_DefaultCursor;
1000: extern char *Menu_DefaultFont;
1001: extern XFontStruct *Menu_DefaultFontInfo;
1002:
1003: inited++;
1004: Gray_Tile = make_gray(BlackPixel(screen->display,
1005: DefaultScreen(screen->display)),
1006: WhitePixel(screen->display, DefaultScreen(screen->display)), 1);
1007: InitMenu(xterm_name);
1008: Menu_DefaultCursor = screen->arrow;
1009: /* if(XStrCmp(Menu_DefaultFont, f_t) == 0)
1010: Menu_DefaultFontInfo = screen->fnt_norm;
1011: */
1012: }
1013: if((event->button) == Button1)
1014: type = XTERMMENU;
1015: else if((event->button) == Button3)
1016: {
1017: Bell();
1018: return;
1019: }
1020: else if(event->window == VWindow(screen))
1021: type = VTMENU;
1022: else if(event->window == TWindow(screen))
1023: type = TEKMENU;
1024: else
1025: SysError(ERROR_BADMENU);
1026: switch(type) {
1027: case XTERMMENU:
1028: if((menu = xsetupmenu(&menus[XTERMMENU])) == NULL)
1029: return;
1030: break;
1031: case VTMENU:
1032: if((menu = setupmenu(&menus[VTMENU])) == NULL)
1033: return;
1034: break;
1035: case TEKMENU:
1036: if((menu = Tsetupmenu(&menus[TEKMENU])) == NULL)
1037: return;
1038: screen->waitrefresh = TRUE;
1039: break;
1040: }
1041: /*
1042: * Set the select mode manually.
1043: */
1044: TrackMenu(menu, event); /* MenuButtonReleased calls FinishModeMenu */
1045: }
1046:
1047: FinishModeMenu(item)
1048: register int item;
1049: {
1050: TScreen *screen = &term.screen;
1051:
1052: menusync();
1053: screen->waitrefresh = FALSE;
1054: reselectwindow(screen);
1055:
1056: if (item < 0) {
1057: if(type == TEKMENU && TekRefresh)
1058: dorefresh();
1059: return;
1060: }
1061: switch(type) {
1062: case XTERMMENU:
1063: xdomenufunc(item);
1064: break;
1065: case VTMENU:
1066: domenufunc(item);
1067: break;
1068: case TEKMENU:
1069: Tdomenufunc(item);
1070: break;
1071: }
1072: }
1073:
1074: menusync()
1075: {
1076: TScreen *screen = &term.screen;
1077: XSync(screen->display, 0);
1078: if (QLength(screen->display) > 0)
1079: xevents();
1080: }
1081:
1082: #define XMENU_VISUALBELL 0
1083: #define XMENU_LOG (XMENU_VISUALBELL+1)
1084: #define XMENU_LINE (XMENU_LOG+1)
1085: #define XMENU_REDRAW (XMENU_LINE+1)
1086: #define XMENU_RESUME (XMENU_REDRAW+1)
1087: #define XMENU_SUSPEND (XMENU_RESUME+1)
1088: #define XMENU_INTR (XMENU_SUSPEND+1)
1089: #define XMENU_HANGUP (XMENU_INTR+1)
1090: #define XMENU_TERM (XMENU_HANGUP+1)
1091: #define XMENU_KILL (XMENU_TERM+1)
1092:
1093: static char *xtext[] = {
1094: "Visual Bell",
1095: "Logging",
1096: "-",
1097: "Redraw",
1098: "Continue",
1099: "Suspend",
1100: "Interrupt",
1101: "Hangup",
1102: "Terminate",
1103: "Kill",
1104: 0,
1105: };
1106:
1107: static int xbell;
1108: static int xlog;
1109:
1110: Menu *xsetupmenu(menu)
1111: register Menu **menu;
1112: {
1113: register TScreen *screen = &term.screen;
1114: register char **cp;
1115: register int i;
1116:
1117: if (*menu == NULL) {
1118: if ((*menu = NewMenu("xterm X11", re_verse)) == NULL)
1119: return(NULL);
1120: for(cp = xtext ; *cp ; cp++)
1121: AddMenuItem(*menu, *cp);
1122: if(xbell = screen->visualbell)
1123: CheckItem(*menu, XMENU_VISUALBELL);
1124: if(xlog = screen->logging)
1125: CheckItem(*menu, XMENU_LOG);
1126: DisableItem(*menu, XMENU_LINE);
1127: if((screen->inhibit & I_LOG) ||
1128: /* if login window, check for completed login */
1129: (L_flag && !checklogin()))
1130: DisableItem(*menu, XMENU_LOG);
1131: if(screen->inhibit & I_SIGNAL)
1132: for(i = XMENU_SUSPEND ; i <= XMENU_KILL ; i++)
1133: DisableItem(*menu, i);
1134: return(*menu);
1135: }
1136: /* if login window, check for completed login */
1137: if (!(L_flag && !checklogin()) && !(screen->inhibit & I_LOG))
1138: EnableItem(*menu, XMENU_LOG);
1139: if (xbell != screen->visualbell)
1140: SetItemCheck(*menu, XMENU_VISUALBELL, (xbell =
1141: screen->visualbell));
1142: if (xlog != screen->logging)
1143: SetItemCheck(*menu, XMENU_LOG, (xlog = screen->logging));
1144: return(*menu);
1145: }
1146:
1147: xdomenufunc(item)
1148: int item;
1149: {
1150: register TScreen *screen = &term.screen;
1151:
1152: switch (item) {
1153: case XMENU_VISUALBELL:
1154: screen->visualbell = !screen->visualbell;
1155: break;
1156:
1157: case XMENU_LOG:
1158: if(screen->logging)
1159: CloseLog(screen);
1160: else
1161: StartLog(screen);
1162: break;
1163:
1164: case XMENU_REDRAW:
1165: Redraw();
1166: break;
1167:
1168: case XMENU_RESUME:
1169: if(screen->pid > 1)
1170: killpg(getpgrp(screen->pid), SIGCONT);
1171: break;
1172:
1173: case XMENU_SUSPEND:
1174: if(screen->pid > 1)
1175: killpg(getpgrp(screen->pid), SIGTSTP);
1176: break;
1177:
1178: case XMENU_INTR:
1179: if(screen->pid > 1)
1180: killpg(getpgrp(screen->pid), SIGINT);
1181: break;
1182:
1183: case XMENU_HANGUP:
1184: if(screen->pid > 1)
1185: killpg(getpgrp(screen->pid), SIGHUP);
1186: break;
1187:
1188: case XMENU_TERM:
1189: if(screen->pid > 1)
1190: killpg(getpgrp(screen->pid), SIGTERM);
1191: break;
1192:
1193: case XMENU_KILL:
1194: if(screen->pid > 1)
1195: killpg(getpgrp(screen->pid), SIGKILL);
1196: break;
1197: }
1198: }
1199:
1200:
1201: MenuNewCursor(cur)
1202: register Cursor cur;
1203: {
1204: register Menu **menu;
1205: register int i;
1206: register TScreen *screen = &term.screen;
1207: extern Cursor Menu_DefaultCursor;
1208:
1209: Menu_DefaultCursor = cur;
1210: for(i = XTERMMENU, menu = menus ; i <= TEKMENU ; menu++, i++) {
1211: if(!*menu)
1212: continue;
1213: (*menu)->menuCursor = cur;
1214: if((*menu)->menuWindow)
1215: XDefineCursor(screen->display, (*menu)->menuWindow,
1216: cur);
1217: }
1218: }
1219: #else MODEMENU
1220:
1221: /*ARGSUSED*/
1222: ModeMenu(event) register XButtonEvent *event; { Bell(); }
1223: #endif MODEMENU
1224:
1225: GINbutton(event)
1226: XButtonEvent *event;
1227: {
1228: register TScreen *screen = &term.screen;
1229: register int i;
1230:
1231: if(screen->TekGIN) {
1232: i = "rml"[event->button - 1];
1233: if(event->state & ShiftMask)
1234: i = toupper(i);
1235: TekEnqMouse(i | 0x80); /* set high bit */
1236: TekGINoff();
1237: } else
1238: Bell();
1239: }
1240:
1241: /*ARGSUSED*/
1242: Bogus(event)
1243: XButtonEvent *event;
1244: {
1245: Bell();
1246: }
1247:
1248: /*ARGSUSED*/
1249: Silence(event)
1250: XButtonEvent *event;
1251: {
1252: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.