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