1 /* $XTermId: button.c,v 1.395 2011/02/09 10:15:46 tom Exp $ */
4 * Copyright 1999-2010,2011 by Thomas E. Dickey
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the
29 * sale, use or other dealings in this Software without prior written
33 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
37 * Permission to use, copy, modify, and distribute this software and its
38 * documentation for any purpose and without fee is hereby granted,
39 * provided that the above copyright notice appear in all copies and that
40 * both that copyright notice and this permission notice appear in
41 * supporting documentation, and that the name of Digital Equipment
42 * Corporation not be used in advertising or publicity pertaining to
43 * distribution of the software without specific, written prior permission.
46 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
47 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
48 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
49 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
50 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
51 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
56 button.c Handles button events in the terminal emulator.
57 does cut/paste operations, change modes via menu,
58 passes button events through to some applications.
67 #include <X11/Xatom.h>
68 #include <X11/Xmu/Atoms.h>
69 #include <X11/Xmu/StdSel.h>
72 #include <fontutils.h>
77 #include <xcharmouse.h>
78 #include <charclass.h>
82 #ifdef HAVE_PCREPOSIX_H
83 #include <pcreposix.h>
84 #else /* POSIX regex.h */
85 #include <sys/types.h>
94 #define CharacterClass(value) \
95 charClass[value & ((sizeof(charClass)/sizeof(charClass[0]))-1)]
99 * We'll generally map rows to indices when doing selection.
100 * Simplify that with a macro.
102 * Note that ROW2INX() is safe to use with auto increment/decrement for
103 * the row expression since that is evaluated once.
105 #define GET_LINEDATA(screen, row) \
106 getLineData(screen, ROW2INX(screen, row))
109 * We reserve shift modifier for cut/paste operations. In principle we
110 * can pass through control and meta modifiers, but in practice, the
111 * popup menu uses control, and the window manager is likely to use meta,
112 * so those events are not delivered to SendMousePosition.
114 #define OurModifiers (ShiftMask | ControlMask | Mod1Mask)
115 #define AllModifiers (ShiftMask | LockMask | ControlMask | Mod1Mask | \
116 Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)
118 #define BtnModifiers(event) (event->state & OurModifiers)
119 #define KeyModifiers(event) (event->xbutton.state & OurModifiers)
121 #define IsBtnEvent(event) ((event)->type == ButtonPress || (event)->type == ButtonRelease)
123 #define KeyState(x) (((int) ((x) & (ShiftMask|ControlMask))) \
124 + (((x) & Mod1Mask) ? 2 : 0))
125 /* adds together the bits:
130 #define Coordinate(s,c) ((c)->row * MaxCols(s) + (c)->col)
132 static const CELL zeroCELL =
136 static Bool SendLocatorPosition(XtermWidget xw, XButtonEvent * event);
137 static void CheckLocatorPosition(XtermWidget xw, XButtonEvent * event);
138 #endif /* OPT_DEC_LOCATOR */
140 /* Multi-click handling */
142 static Time lastButtonDownTime = 0;
143 static int ExtendingSelection = 0;
144 static Time lastButton3UpTime = 0;
145 static Time lastButton3DoubleDownTime = 0;
146 static CELL lastButton3; /* At the release time */
147 #endif /* OPT_READLINE */
149 static Char *SaveText(TScreen * screen, int row, int scol, int ecol,
150 Char * lp, int *eol);
151 static int Length(TScreen * screen, int row, int scol, int ecol);
152 static void ComputeSelect(XtermWidget xw, CELL * startc, CELL * endc, Bool extend);
153 static void EditorButton(XtermWidget xw, XButtonEvent * event);
154 static void EndExtend(XtermWidget w, XEvent * event, String * params, Cardinal
155 num_params, Bool use_cursor_loc);
156 static void ExtendExtend(XtermWidget xw, const CELL * cell);
157 static void PointToCELL(TScreen * screen, int y, int x, CELL * cell);
158 static void ReHiliteText(XtermWidget xw, CELL * first, CELL * last);
159 static void SaltTextAway(XtermWidget xw, CELL * cellc, CELL * cell,
160 String * params, Cardinal num_params);
161 static void SelectSet(XtermWidget xw, XEvent * event, String * params, Cardinal num_params);
162 static void SelectionReceived PROTO_XT_SEL_CB_ARGS;
163 static void StartSelect(XtermWidget xw, const CELL * cell);
164 static void TrackDown(XtermWidget xw, XButtonEvent * event);
165 static void TrackText(XtermWidget xw, const CELL * first, const CELL * last);
166 static void _OwnSelection(XtermWidget xw, String * selections, Cardinal count);
167 static void do_select_end(XtermWidget xw, XEvent * event, String * params,
168 Cardinal *num_params, Bool use_cursor_loc);
170 #define MOUSE_LIMIT (255 - 32)
172 /* Send SET_EXT_SIZE_MOUSE to enable offsets up to EXT_MOUSE_LIMIT */
173 #define EXT_MOUSE_LIMIT (2047 - 32)
174 #define EXT_MOUSE_START (127 - 32)
177 EmitMousePosition(TScreen * screen, Char line[], unsigned count, int value)
179 int mouse_limit = (screen->ext_mode_mouse
184 * Add pointer position to key sequence
186 * In extended mode we encode large positions as two-byte UTF-8.
188 * NOTE: historically, it was possible to emit 256, which became
189 * zero by truncation to 8 bits. While this was arguably a bug,
190 * it's also somewhat useful as a past-end marker. We preserve
191 * this behavior for both normal and extended mouse modes.
193 if (value == mouse_limit) {
194 line[count++] = CharOf(0);
195 } else if (!screen->ext_mode_mouse || value < EXT_MOUSE_START) {
196 line[count++] = CharOf(' ' + value + 1);
199 line[count++] = CharOf(0xC0 + (value >> 6));
200 line[count++] = CharOf(0x80 + (value & 0x3F));
206 SendMousePosition(XtermWidget xw, XEvent * event)
208 TScreen *screen = TScreenOf(xw);
209 XButtonEvent *my_event = (XButtonEvent *) event;
212 switch (screen->send_mouse_pos) {
214 /* If send_mouse_pos mode isn't on, we shouldn't be here */
217 case BTN_EVENT_MOUSE:
218 case ANY_EVENT_MOUSE:
219 if (KeyModifiers(event) == 0 || KeyModifiers(event) == ControlMask) {
220 /* xterm extension for motion reporting. June 1998 */
221 /* EditorButton() will distinguish between the modes */
222 switch (event->type) {
224 my_event->button = 0;
229 EditorButton(xw, my_event);
237 /* Make sure the event is an appropriate type */
238 if (IsBtnEvent(event)) {
239 switch (screen->send_mouse_pos) {
240 case X10_MOUSE: /* X10 compatibility sequences */
242 if (BtnModifiers(my_event) == 0) {
243 if (my_event->type == ButtonPress)
244 EditorButton(xw, my_event);
249 case VT200_HIGHLIGHT_MOUSE: /* DEC vt200 hilite tracking */
250 if (my_event->type == ButtonPress &&
251 BtnModifiers(my_event) == 0 &&
252 my_event->button == Button1) {
253 TrackDown(xw, my_event);
255 } else if (BtnModifiers(my_event) == 0
256 || BtnModifiers(my_event) == ControlMask) {
257 EditorButton(xw, my_event);
262 case VT200_MOUSE: /* DEC vt200 compatible */
263 if (BtnModifiers(my_event) == 0
264 || BtnModifiers(my_event) == ControlMask) {
265 EditorButton(xw, my_event);
272 result = SendLocatorPosition(xw, my_event);
274 #endif /* OPT_DEC_LOCATOR */
283 #define LocatorCoords( row, col, x, y, oor ) \
284 if( screen->locator_pixels ) { \
285 (oor)=False; (row) = (y)+1; (col) = (x)+1; \
286 /* Limit to screen dimensions */ \
287 if ((row) < 1) (row) = 1,(oor)=True; \
288 else if ((row) > screen->border*2+Height(screen)) \
289 (row) = screen->border*2+Height(screen),(oor)=True; \
290 if ((col) < 1) (col) = 1,(oor)=True; \
291 else if ((col) > OriginX(screen)*2+Width(screen)) \
292 (col) = OriginX(screen)*2+Width(screen),(oor)=True; \
295 /* Compute character position of mouse pointer */ \
296 (row) = ((y) - screen->border) / FontHeight(screen); \
297 (col) = ((x) - OriginX(screen)) / FontWidth(screen); \
298 /* Limit to screen dimensions */ \
299 if ((row) < 0) (row) = 0,(oor)=True; \
300 else if ((row) > screen->max_row) \
301 (row) = screen->max_row,(oor)=True; \
302 if ((col) < 0) (col) = 0,(oor)=True; \
303 else if ((col) > screen->max_col) \
304 (col) = screen->max_col,(oor)=True; \
309 SendLocatorPosition(XtermWidget xw, XButtonEvent * event)
312 TScreen *screen = TScreenOf(xw);
318 /* Make sure the event is an appropriate type */
319 if ((!IsBtnEvent(event) &&
320 !screen->loc_filter) ||
321 (BtnModifiers(event) != 0 && BtnModifiers(event) != ControlMask))
324 if ((event->type == ButtonPress &&
325 !(screen->locator_events & LOC_BTNS_DN)) ||
326 (event->type == ButtonRelease &&
327 !(screen->locator_events & LOC_BTNS_UP)))
330 if (event->type == MotionNotify) {
331 CheckLocatorPosition(xw, event);
336 button = (int) event->button - 1;
338 LocatorCoords(row, col, event->x, event->y, oor);
343 * ESCAPE '[' event ; mask ; row ; column '&' 'w'
345 memset(&reply, 0, sizeof(reply));
346 reply.a_type = ANSI_CSI;
350 reply.a_param[0] = 0; /* Event - 0 = locator unavailable */
351 reply.a_inters = '&';
353 unparseseq(xw, &reply);
355 if (screen->locator_reset) {
356 MotionOff(screen, xw);
357 screen->send_mouse_pos = MOUSE_OFF;
367 * 4 middle button down
369 * 6 right button down
375 switch (event->type) {
377 reply.a_param[0] = (ParmType) (2 + (button << 1));
380 reply.a_param[0] = (ParmType) (3 + (button << 1));
387 * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
388 * M4 down left down middle down right down
390 * Notice that Button1 (left) and Button3 (right) are swapped in the mask.
391 * Also, mask should be the state after the button press/release,
392 * X provides the state not including the button press/release.
394 state = (event->state
395 & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8;
396 /* update mask to "after" state */
397 state ^= ((unsigned) (1 << button));
398 /* swap Button1 & Button3 */
399 state = ((state & (unsigned) ~(4 | 1))
400 | ((state & 1) ? 4 : 0)
401 | ((state & 4) ? 1 : 0));
403 reply.a_param[1] = (ParmType) state;
404 reply.a_param[2] = (ParmType) row;
405 reply.a_param[3] = (ParmType) col;
406 reply.a_inters = '&';
409 unparseseq(xw, &reply);
411 if (screen->locator_reset) {
412 MotionOff(screen, xw);
413 screen->send_mouse_pos = MOUSE_OFF;
417 * DECterm turns the Locator off if a button is pressed while a filter rectangle
418 * is active. This might be a bug, but I don't know, so I'll emulate it anyways.
420 if (screen->loc_filter) {
421 screen->send_mouse_pos = MOUSE_OFF;
422 screen->loc_filter = False;
423 screen->locator_events = 0;
424 MotionOff(screen, xw);
432 * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
433 * M4 down left down middle down right down
435 * Button1 (left) and Button3 (right) are swapped in the mask relative to X.
437 #define ButtonState(state, mask) \
438 { (state) = (int) (((mask) & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8); \
439 /* swap Button1 & Button3 */ \
440 (state) = ((state) & ~(4|1)) | (((state)&1)?4:0) | (((state)&4)?1:0); \
444 GetLocatorPosition(XtermWidget xw)
447 TScreen *screen = TScreenOf(xw);
451 int row = 0, col = 0;
457 * DECterm turns the Locator off if the position is requested while a filter rectangle
458 * is active. This might be a bug, but I don't know, so I'll emulate it anyways.
460 if (screen->loc_filter) {
461 screen->send_mouse_pos = MOUSE_OFF;
462 screen->loc_filter = False;
463 screen->locator_events = 0;
464 MotionOff(screen, xw);
467 memset(&reply, 0, sizeof(reply));
468 reply.a_type = ANSI_CSI;
470 if (screen->send_mouse_pos == DEC_LOCATOR) {
471 ret = XQueryPointer(screen->display, VWindow(screen), &root,
472 &child, &rx, &ry, &x, &y, &mask);
474 LocatorCoords(row, col, x, y, oor);
477 if (ret == False || oor) {
479 reply.a_param[0] = 0; /* Event - 0 = locator unavailable */
480 reply.a_inters = '&';
482 unparseseq(xw, &reply);
484 if (screen->locator_reset) {
485 MotionOff(screen, xw);
486 screen->send_mouse_pos = MOUSE_OFF;
491 ButtonState(state, mask);
494 reply.a_param[0] = 1; /* Event - 1 = response to locator request */
495 reply.a_param[1] = (ParmType) state;
496 reply.a_param[2] = (ParmType) row;
497 reply.a_param[3] = (ParmType) col;
498 reply.a_inters = '&';
500 unparseseq(xw, &reply);
502 if (screen->locator_reset) {
503 MotionOff(screen, xw);
504 screen->send_mouse_pos = MOUSE_OFF;
509 InitLocatorFilter(XtermWidget xw)
512 TScreen *screen = TScreenOf(xw);
516 int row = 0, col = 0;
521 ret = XQueryPointer(screen->display, VWindow(screen),
522 &root, &child, &rx, &ry, &x, &y, &mask);
524 LocatorCoords(row, col, x, y, oor);
526 if (ret == False || oor) {
527 /* Locator is unavailable */
529 if (screen->loc_filter_top != LOC_FILTER_POS ||
530 screen->loc_filter_left != LOC_FILTER_POS ||
531 screen->loc_filter_bottom != LOC_FILTER_POS ||
532 screen->loc_filter_right != LOC_FILTER_POS) {
534 * If any explicit coordinates were received,
535 * report immediately with no coordinates.
537 memset(&reply, 0, sizeof(reply));
538 reply.a_type = ANSI_CSI;
540 reply.a_param[0] = 0; /* Event - 0 = locator unavailable */
541 reply.a_inters = '&';
543 unparseseq(xw, &reply);
545 if (screen->locator_reset) {
546 MotionOff(screen, xw);
547 screen->send_mouse_pos = MOUSE_OFF;
551 * No explicit coordinates were received, and the pointer is
552 * unavailable. Report when the pointer re-enters the window.
554 screen->loc_filter = True;
555 MotionOn(screen, xw);
561 * Adjust rectangle coordinates:
562 * 1. Replace "LOC_FILTER_POS" with current coordinates
563 * 2. Limit coordinates to screen size
564 * 3. make sure top and left are less than bottom and right, resp.
566 if (screen->locator_pixels) {
567 rx = OriginX(screen) * 2 + Width(screen);
568 ry = screen->border * 2 + Height(screen);
570 rx = screen->max_col;
571 ry = screen->max_row;
574 #define Adjust( coord, def, max ) \
575 if( (coord) == LOC_FILTER_POS ) (coord) = (def); \
576 else if ((coord) < 1) (coord) = 1; \
577 else if ((coord) > (max)) (coord) = (max)
579 Adjust(screen->loc_filter_top, row, ry);
580 Adjust(screen->loc_filter_left, col, rx);
581 Adjust(screen->loc_filter_bottom, row, ry);
582 Adjust(screen->loc_filter_right, col, rx);
584 if (screen->loc_filter_top > screen->loc_filter_bottom) {
585 ry = screen->loc_filter_top;
586 screen->loc_filter_top = screen->loc_filter_bottom;
587 screen->loc_filter_bottom = ry;
590 if (screen->loc_filter_left > screen->loc_filter_right) {
591 rx = screen->loc_filter_left;
592 screen->loc_filter_left = screen->loc_filter_right;
593 screen->loc_filter_right = rx;
596 if ((col < screen->loc_filter_left) ||
597 (col > screen->loc_filter_right) ||
598 (row < screen->loc_filter_top) ||
599 (row > screen->loc_filter_bottom)) {
600 /* Pointer is already outside the rectangle - report immediately */
601 ButtonState(state, mask);
603 memset(&reply, 0, sizeof(reply));
604 reply.a_type = ANSI_CSI;
606 reply.a_param[0] = 10; /* Event - 10 = locator outside filter */
607 reply.a_param[1] = (ParmType) state;
608 reply.a_param[2] = (ParmType) row;
609 reply.a_param[3] = (ParmType) col;
610 reply.a_inters = '&';
612 unparseseq(xw, &reply);
614 if (screen->locator_reset) {
615 MotionOff(screen, xw);
616 screen->send_mouse_pos = MOUSE_OFF;
622 * Rectangle is set up. Allow pointer tracking
623 * to detect if the mouse leaves the rectangle.
625 screen->loc_filter = True;
626 MotionOn(screen, xw);
630 CheckLocatorPosition(XtermWidget xw, XButtonEvent * event)
633 TScreen *screen = TScreenOf(xw);
638 LocatorCoords(row, col, event->x, event->y, oor);
641 * Send report if the pointer left the filter rectangle, if
642 * the pointer left the window, or if the filter rectangle
643 * had no coordinates and the pointer re-entered the window.
645 if (oor || (screen->loc_filter_top == LOC_FILTER_POS) ||
646 (col < screen->loc_filter_left) ||
647 (col > screen->loc_filter_right) ||
648 (row < screen->loc_filter_top) ||
649 (row > screen->loc_filter_bottom)) {
650 /* Filter triggered - disable it */
651 screen->loc_filter = False;
652 MotionOff(screen, xw);
654 memset(&reply, 0, sizeof(reply));
655 reply.a_type = ANSI_CSI;
658 reply.a_param[0] = 0; /* Event - 0 = locator unavailable */
660 ButtonState(state, event->state);
663 reply.a_param[0] = 10; /* Event - 10 = locator outside filter */
664 reply.a_param[1] = (ParmType) state;
665 reply.a_param[2] = (ParmType) row;
666 reply.a_param[3] = (ParmType) col;
669 reply.a_inters = '&';
671 unparseseq(xw, &reply);
673 if (screen->locator_reset) {
674 MotionOff(screen, xw);
675 screen->send_mouse_pos = MOUSE_OFF;
679 #endif /* OPT_DEC_LOCATOR */
683 isClick1_clean(TScreen * screen, XButtonEvent * event)
687 if (!IsBtnEvent(event)
688 /* Disable on Shift-Click-1, including the application-mouse modes */
689 || (BtnModifiers(event) & ShiftMask)
690 || (screen->send_mouse_pos != MOUSE_OFF) /* Kinda duplicate... */
691 ||ExtendingSelection) /* Was moved */
694 if (event->type != ButtonRelease)
697 if (lastButtonDownTime == (Time) 0) {
698 /* first time or once in a blue moon */
699 delta = screen->multiClickTime + 1;
700 } else if (event->time > lastButtonDownTime) {
701 /* most of the time */
702 delta = (int) (event->time - lastButtonDownTime);
704 /* time has rolled over since lastButtonUpTime */
705 delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->time);
708 return delta <= screen->multiClickTime;
712 isDoubleClick3(TScreen * screen, XButtonEvent * event)
716 if (event->type != ButtonRelease
717 || (BtnModifiers(event) & ShiftMask)
718 || event->button != Button3) {
719 lastButton3UpTime = 0; /* Disable the cached info */
722 /* Process Btn3Release. */
723 if (lastButton3DoubleDownTime == (Time) 0) {
724 /* No previous click or once in a blue moon */
725 delta = screen->multiClickTime + 1;
726 } else if (event->time > lastButton3DoubleDownTime) {
727 /* most of the time */
728 delta = (int) (event->time - lastButton3DoubleDownTime);
730 /* time has rolled over since lastButton3DoubleDownTime */
731 delta = (int) ((((Time) ~ 0) - lastButton3DoubleDownTime) + event->time);
733 if (delta <= screen->multiClickTime) {
737 /* Cannot check ExtendingSelection, since mouse-3 always sets it */
738 PointToCELL(screen, event->y, event->x, &cell);
739 if (isSameCELL(&cell, &lastButton3)) {
740 lastButton3DoubleDownTime = 0; /* Disable the third click */
744 /* Not a double click, memorize for future check. */
745 lastButton3UpTime = event->time;
746 PointToCELL(screen, event->y, event->x, &lastButton3);
751 CheckSecondPress3(TScreen * screen, XEvent * event)
755 if (event->type != ButtonPress
756 || (KeyModifiers(event) & ShiftMask)
757 || event->xbutton.button != Button3) {
758 lastButton3DoubleDownTime = 0; /* Disable the cached info */
761 /* Process Btn3Press. */
762 if (lastButton3UpTime == (Time) 0) {
763 /* No previous click or once in a blue moon */
764 delta = screen->multiClickTime + 1;
765 } else if (event->xbutton.time > lastButton3UpTime) {
766 /* most of the time */
767 delta = (int) (event->xbutton.time - lastButton3UpTime);
769 /* time has rolled over since lastButton3UpTime */
770 delta = (int) ((((Time) ~ 0) - lastButton3UpTime) + event->xbutton.time);
772 if (delta <= screen->multiClickTime) {
775 PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell);
776 if (isSameCELL(&cell, &lastButton3)) {
777 /* A candidate for a double-click */
778 lastButton3DoubleDownTime = event->xbutton.time;
779 PointToCELL(screen, event->xbutton.y, event->xbutton.x, &lastButton3);
782 lastButton3UpTime = 0; /* Disable the info about the previous click */
784 /* Either too long, or moved, disable. */
785 lastButton3DoubleDownTime = 0;
790 rowOnCurrentLine(TScreen * screen,
792 int *deltap) /* must be XButtonEvent */
798 if (line != screen->cur_row) {
799 if (line < screen->cur_row)
800 l1 = line, l2 = screen->cur_row;
802 l2 = line, l1 = screen->cur_row;
805 LineData *ld = GET_LINEDATA(screen, l1);
806 if (!LineTstWrapped(ld)) {
812 /* Everything is on one "wrapped line" now */
813 *deltap = line - screen->cur_row;
820 eventRow(TScreen * screen, XEvent * event) /* must be XButtonEvent */
822 return (event->xbutton.y - screen->border) / FontHeight(screen);
826 eventColBetween(TScreen * screen, XEvent * event) /* must be XButtonEvent */
828 /* Correct by half a width - we are acting on a boundary, not on a cell. */
829 return ((event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) / 2)
830 / FontWidth(screen));
834 ReadLineMovePoint(TScreen * screen, int col, int ldelta)
839 col += ldelta * MaxCols(screen) - screen->cur_col;
842 if (screen->control_eight_bits) {
843 line[count++] = ANSI_CSI;
845 line[count++] = ANSI_ESC;
846 line[count++] = '['; /* XXX maybe sometimes O is better? */
848 line[count] = CharOf(col > 0 ? 'C' : 'D');
852 v_write(screen->respond, line, 3);
857 ReadLineDelete(TScreen * screen, CELL * cell1, CELL * cell2)
861 del = (cell2->col - cell1->col) + ((cell2->row - cell1->row) * MaxCols(screen));
862 if (del <= 0) /* Just in case... */
865 v_write(screen->respond, (const Char *) "\177", 1);
870 readlineExtend(TScreen * screen, XEvent * event)
872 int ldelta1, ldelta2;
874 if (IsBtnEvent(event)) {
875 XButtonEvent *my_event = (XButtonEvent *) event;
876 if (isClick1_clean(screen, my_event)
877 && SCREEN_FLAG(screen, click1_moves)
878 && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta1)) {
879 ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta1);
881 if (isDoubleClick3(screen, my_event)
882 && SCREEN_FLAG(screen, dclick3_deletes)
883 && rowOnCurrentLine(screen, screen->startSel.row, &ldelta1)
884 && rowOnCurrentLine(screen, screen->endSel.row, &ldelta2)) {
885 ReadLineMovePoint(screen, screen->endSel.col, ldelta2);
886 ReadLineDelete(screen, &screen->startSel, &(screen->endSel));
891 #endif /* OPT_READLINE */
893 /* ^XM-G<line+' '><col+' '> */
895 DiredButton(Widget w,
896 XEvent * event, /* must be XButtonEvent */
897 String * params GCC_UNUSED, /* selections */
898 Cardinal *num_params GCC_UNUSED)
902 if ((xw = getXtermWidget(w)) != 0) {
903 TScreen *screen = TScreenOf(xw);
907 if (IsBtnEvent(event)
908 && (event->xbutton.y >= screen->border)
909 && (event->xbutton.x >= OriginX(screen))) {
910 line = (unsigned) ((event->xbutton.y - screen->border)
911 / FontHeight(screen));
912 col = (unsigned) ((event->xbutton.x - OriginX(screen))
913 / FontWidth(screen));
914 Line[0] = CONTROL('X');
917 Line[3] = CharOf(' ' + col);
918 Line[4] = CharOf(' ' + line);
919 v_write(screen->respond, Line, 5);
926 ReadLineButton(Widget w,
927 XEvent * event, /* must be XButtonEvent */
928 String * params GCC_UNUSED, /* selections */
929 Cardinal *num_params GCC_UNUSED)
933 if ((xw = getXtermWidget(w)) != 0) {
934 TScreen *screen = TScreenOf(xw);
936 int line, col, ldelta = 0;
938 if (!IsBtnEvent(event)
939 || (screen->send_mouse_pos != MOUSE_OFF) || ExtendingSelection)
941 if (event->type == ButtonRelease) {
944 if (lastButtonDownTime == (Time) 0) {
945 /* first time and once in a blue moon */
946 delta = screen->multiClickTime + 1;
947 } else if (event->xbutton.time > lastButtonDownTime) {
948 /* most of the time */
949 delta = (int) (event->xbutton.time - lastButtonDownTime);
951 /* time has rolled over since lastButtonUpTime */
952 delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time);
954 if (delta > screen->multiClickTime)
955 goto finish; /* All this work for this... */
957 line = (event->xbutton.y - screen->border) / FontHeight(screen);
958 if (!rowOnCurrentLine(screen, line, &ldelta))
960 /* Correct by half a width - we are acting on a boundary, not on a cell. */
961 col = (event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1)
963 / FontWidth(screen) - screen->cur_col + ldelta * MaxCols(screen);
967 /* XXX: sometimes it is better to send '['? */
969 Line[2] = CharOf(col > 0 ? 'C' : 'D');
973 v_write(screen->respond, Line, 3);
975 if (event->type == ButtonRelease)
976 do_select_end(xw, event, params, num_params, False);
979 #endif /* OPT_READLINE */
981 /* repeats <ESC>n or <ESC>p */
984 XEvent * event, /* must be XButtonEvent */
985 String * params GCC_UNUSED, /* selections */
986 Cardinal *num_params GCC_UNUSED)
990 if ((xw = getXtermWidget(w)) != 0) {
991 TScreen *screen = TScreenOf(xw);
992 int pty = screen->respond;
996 if (IsBtnEvent(event)) {
998 line = screen->cur_row -
999 ((event->xbutton.y - screen->border) / FontHeight(screen));
1001 Line[0] = ANSI_ESC; /* force an exit from insert-mode */
1002 v_write(pty, Line, 1);
1006 Line[0] = CONTROL('n');
1008 Line[0] = CONTROL('p');
1011 v_write(pty, Line, 1);
1018 * This function handles button-motion events
1022 HandleSelectExtend(Widget w,
1023 XEvent * event, /* must be XMotionEvent */
1024 String * params GCC_UNUSED,
1025 Cardinal *num_params GCC_UNUSED)
1029 if ((xw = getXtermWidget(w)) != 0) {
1030 TScreen *screen = TScreenOf(xw);
1033 screen->selection_time = event->xmotion.time;
1034 switch (screen->eventMode) {
1035 /* If not in one of the DEC mouse-reporting modes */
1037 case RIGHTEXTENSION:
1038 PointToCELL(screen, event->xmotion.y, event->xmotion.x, &cell);
1039 ExtendExtend(xw, &cell);
1042 /* If in motion reporting mode, send mouse position to
1043 character process as a key sequence \E[M... */
1045 /* will get here if send_mouse_pos != MOUSE_OFF */
1046 if (screen->send_mouse_pos == BTN_EVENT_MOUSE
1047 || screen->send_mouse_pos == ANY_EVENT_MOUSE) {
1048 (void) SendMousePosition(xw, event);
1056 HandleKeyboardSelectExtend(Widget w,
1057 XEvent * event GCC_UNUSED, /* must be XButtonEvent */
1058 String * params GCC_UNUSED,
1059 Cardinal *num_params GCC_UNUSED)
1063 if ((xw = getXtermWidget(w)) != 0) {
1064 TScreen *screen = TScreenOf(xw);
1065 ExtendExtend(xw, &screen->cursorp);
1070 do_select_end(XtermWidget xw,
1071 XEvent * event, /* must be XButtonEvent */
1072 String * params, /* selections */
1073 Cardinal *num_params,
1074 Bool use_cursor_loc)
1076 TScreen *screen = TScreenOf(xw);
1078 screen->selection_time = event->xbutton.time;
1079 switch (screen->eventMode) {
1081 (void) SendMousePosition(xw, event);
1084 case RIGHTEXTENSION:
1085 EndExtend(xw, event, params, *num_params, use_cursor_loc);
1087 readlineExtend(screen, event);
1088 #endif /* OPT_READLINE */
1094 HandleSelectEnd(Widget w,
1095 XEvent * event, /* must be XButtonEvent */
1096 String * params, /* selections */
1097 Cardinal *num_params)
1101 if ((xw = getXtermWidget(w)) != 0) {
1102 do_select_end(xw, event, params, num_params, False);
1107 HandleKeyboardSelectEnd(Widget w,
1108 XEvent * event, /* must be XButtonEvent */
1109 String * params, /* selections */
1110 Cardinal *num_params)
1114 if ((xw = getXtermWidget(w)) != 0) {
1115 do_select_end(xw, event, params, num_params, True);
1120 * Copy the selection data to the given target(s).
1123 HandleCopySelection(Widget w,
1125 String * params, /* list of targets */
1126 Cardinal *num_params)
1130 if ((xw = getXtermWidget(w)) != 0) {
1131 SelectSet(xw, event, params, *num_params);
1135 struct _SelectionList {
1143 DECtoASCII(unsigned ch)
1145 if (xtermIsDecGraphic(ch)) {
1146 ch = CharOf("###########+++++##-##++++|######"[ch]);
1147 /* 01234567890123456789012345678901 */
1154 addXtermChar(Char ** buffer, Cardinal *used, Cardinal offset, unsigned value)
1156 if (offset + 1 >= *used) {
1157 *used = 1 + (2 * (offset + 1));
1158 allocXtermChars(buffer, *used);
1160 (*buffer)[offset++] = (Char) value;
1163 #define AddChar(buffer, used, offset, value) \
1164 offset = addXtermChar(buffer, used, offset, (unsigned) value)
1167 * Convert a UTF-8 string to Latin-1, replacing non Latin-1 characters by `#',
1168 * or ASCII/Latin-1 equivalents for special cases.
1171 UTF8toLatin1(TScreen * screen, Char * s, unsigned long len, unsigned long *result)
1173 static Char *buffer;
1174 static Cardinal used;
1176 Cardinal offset = 0;
1183 fakePtyData(&data, s, s + len);
1184 while (decodeUtf8(&data)) {
1187 IChar value = skipPtyData(&data);
1188 if (value == UCS_REPL) {
1190 } else if (value < 256) {
1191 AddChar(&buffer, &used, offset, CharOf(value));
1193 unsigned eqv = ucs2dec(value);
1194 if (xtermIsDecGraphic(eqv)) {
1195 AddChar(&buffer, &used, offset, DECtoASCII(eqv));
1197 eqv = AsciiEquivs(value);
1201 AddChar(&buffer, &used, offset, eqv);
1203 if (isWide((wchar_t) value))
1209 * If we're not able to plug in a single-byte result, insert the
1210 * defaultString (which normally is a single "#", but could be
1211 * whatever the user wants).
1214 for (p = (const Char *) screen->default_string; *p != '\0'; ++p) {
1215 AddChar(&buffer, &used, offset, *p);
1219 AddChar(&buffer, &used, offset, ' ');
1221 AddChar(&buffer, &used, offset, '\0');
1222 *result = (unsigned long) (offset - 1);
1230 xtermUtf8ToTextList(XtermWidget xw,
1231 XTextProperty * text_prop,
1233 int *text_list_count)
1235 TScreen *screen = TScreenOf(xw);
1236 Display *dpy = screen->display;
1239 if (text_prop->format == 8
1240 && (rc = Xutf8TextPropertyToTextList(dpy, text_prop,
1242 text_list_count)) >= 0) {
1243 if (*text_list != NULL && *text_list_count != 0) {
1246 char **new_text_list, *tmp;
1247 unsigned long size, new_size;
1249 TRACE(("xtermUtf8ToTextList size %d\n", *text_list_count));
1252 * XLib StringList actually uses only two pointers, one for the
1253 * list itself, and one for the data. Pointer to the data is the
1254 * first element of the list, the rest (if any) list elements point
1255 * to the same memory block as the first element
1258 for (i = 0; i < *text_list_count; ++i) {
1259 data = (Char *) (*text_list)[i];
1260 size = strlen((*text_list)[i]) + 1;
1261 (void) UTF8toLatin1(screen, data, size, &size);
1262 new_size += size + 1;
1264 new_text_list = TypeXtMallocN(char *, *text_list_count);
1265 new_text_list[0] = tmp = XtMalloc((Cardinal) new_size);
1266 for (i = 0; i < (*text_list_count); ++i) {
1267 data = (Char *) (*text_list)[i];
1268 size = strlen((*text_list)[i]) + 1;
1269 data = UTF8toLatin1(screen, data, size, &size);
1270 memcpy(tmp, data, size + 1);
1271 new_text_list[i] = tmp;
1274 XFreeStringList((*text_list));
1275 *text_list = new_text_list;
1282 #endif /* OPT_WIDE_CHARS */
1285 parseItem(char *value, char *nextc)
1287 char *nextp = value;
1288 while (*nextp != '\0' && *nextp != ',') {
1289 *nextp = x_toupper(*nextp);
1300 * All of the wanted strings are unique in the first character, so we can
1301 * use simple abbreviations.
1304 sameItem(const char *actual, const char *wanted)
1306 Bool result = False;
1307 size_t have = strlen(actual);
1308 size_t need = strlen(wanted);
1310 if (have != 0 && have <= need) {
1311 if (!strncmp(actual, wanted, have)) {
1312 TRACE(("...matched \"%s\"\n", wanted));
1321 * Handle the eightBitSelectTypes or utf8SelectTypes resource values.
1324 overrideTargets(Widget w, String value, Atom ** resultp)
1326 Bool override = False;
1329 if ((xw = getXtermWidget(w)) != 0) {
1330 TScreen *screen = TScreenOf(xw);
1332 if (!IsEmpty(value)) {
1333 char *copied = x_strdup(value);
1339 TRACE(("decoding SelectTypes \"%s\"\n", value));
1340 for (n = 0; copied[n] != '\0'; ++n) {
1341 if (copied[n] == ',')
1344 result = TypeXtMallocN(Atom, (2 * count) + 1);
1345 if (result == NULL) {
1346 TRACE(("Couldn't allocate selection types\n"));
1349 char *listp = (char *) copied;
1352 char *nextp = parseItem(listp, &nextc);
1353 size_t len = strlen(listp);
1359 else if (sameItem(listp, "UTF8")) {
1360 result[count++] = XA_UTF8_STRING(XtDisplay(w));
1363 else if (sameItem(listp, "I18N")) {
1364 if (screen->i18nSelections) {
1365 result[count++] = XA_TEXT(XtDisplay(w));
1366 result[count++] = XA_COMPOUND_TEXT(XtDisplay(w));
1368 } else if (sameItem(listp, "TEXT")) {
1369 result[count++] = XA_TEXT(XtDisplay(w));
1370 } else if (sameItem(listp, "COMPOUND_TEXT")) {
1371 result[count++] = XA_COMPOUND_TEXT(XtDisplay(w));
1372 } else if (sameItem(listp, "STRING")) {
1373 result[count++] = XA_STRING;
1377 } while (nextc != '\0');
1379 result[count] = None;
1383 XtFree((char *) result);
1387 TRACE(("Couldn't allocate copy of selection types\n"));
1396 allocUtf8Targets(Widget w, TScreen * screen)
1398 Atom **resultp = &(screen->selection_targets_utf8);
1400 if (*resultp == 0) {
1403 if (!overrideTargets(w, screen->utf8_select_types, &result)) {
1404 result = TypeXtMallocN(Atom, 5);
1405 if (result == NULL) {
1406 TRACE(("Couldn't allocate utf-8 selection targets\n"));
1410 result[n++] = XA_UTF8_STRING(XtDisplay(w));
1411 #ifdef X_HAVE_UTF8_STRING
1412 if (screen->i18nSelections) {
1413 result[n++] = XA_TEXT(XtDisplay(w));
1414 result[n++] = XA_COMPOUND_TEXT(XtDisplay(w));
1417 result[n++] = XA_STRING;
1430 alloc8bitTargets(Widget w, TScreen * screen)
1432 Atom **resultp = &(screen->selection_targets_8bit);
1434 if (*resultp == 0) {
1437 if (!overrideTargets(w, screen->eightbit_select_types, &result)) {
1438 result = TypeXtMallocN(Atom, 5);
1439 if (result == NULL) {
1440 TRACE(("Couldn't allocate 8bit selection targets\n"));
1444 #ifdef X_HAVE_UTF8_STRING
1445 result[n++] = XA_UTF8_STRING(XtDisplay(w));
1447 if (screen->i18nSelections) {
1448 result[n++] = XA_TEXT(XtDisplay(w));
1449 result[n++] = XA_COMPOUND_TEXT(XtDisplay(w));
1451 result[n++] = XA_STRING;
1463 _SelectionTargets(Widget w)
1469 if ((xw = getXtermWidget(w)) == 0) {
1472 screen = TScreenOf(xw);
1475 if (screen->wide_chars) {
1476 result = allocUtf8Targets(w, screen);
1480 /* not screen->wide_chars */
1481 result = alloc8bitTargets(w, screen);
1488 #define isSELECT(value) (!strcmp(value, "SELECT"))
1491 UnmapSelections(XtermWidget xw)
1493 TScreen *screen = TScreenOf(xw);
1496 if (screen->mappedSelect) {
1497 for (n = 0; screen->mappedSelect[n] != 0; ++n)
1498 free((void *) screen->mappedSelect[n]);
1499 free(screen->mappedSelect);
1500 screen->mappedSelect = 0;
1505 * xterm generally uses the primary selection. Some applications prefer
1506 * (or are limited to) the clipboard. Since the translations resource is
1507 * complicated, users seldom change the way it affects selection. But it
1508 * is simple to remap the choice between primary and clipboard before the
1509 * call to XmuInternStrings().
1512 MapSelections(XtermWidget xw, String * params, Cardinal num_params)
1514 String *result = params;
1516 if (num_params > 0) {
1518 Boolean map = False;
1520 for (j = 0; j < num_params; ++j) {
1521 TRACE(("param[%d]:%s\n", j, params[j]));
1522 if (isSELECT(params[j])) {
1528 TScreen *screen = TScreenOf(xw);
1529 const char *mapTo = (screen->selectToClipboard
1533 UnmapSelections(xw);
1534 if ((result = TypeMallocN(String, num_params + 1)) != 0) {
1535 result[num_params] = 0;
1536 for (j = 0; j < num_params; ++j) {
1537 result[j] = x_strdup((isSELECT(params[j])
1540 if (result[j] == 0) {
1541 UnmapSelections(xw);
1546 screen->mappedSelect = result;
1554 * Lookup the cut-buffer number, which will be in the range 0-7.
1555 * If it is not a cut-buffer, it is the primary selection (-1).
1558 CutBuffer(Atom code)
1561 switch ((unsigned) code) {
1562 case XA_CUT_BUFFER0:
1565 case XA_CUT_BUFFER1:
1568 case XA_CUT_BUFFER2:
1571 case XA_CUT_BUFFER3:
1574 case XA_CUT_BUFFER4:
1577 case XA_CUT_BUFFER5:
1580 case XA_CUT_BUFFER6:
1583 case XA_CUT_BUFFER7:
1595 FinishPaste64(XtermWidget xw)
1597 TScreen *screen = TScreenOf(xw);
1599 TRACE(("FinishPaste64(%d)\n", screen->base64_paste));
1600 if (screen->base64_paste) {
1601 screen->base64_paste = 0;
1602 unparseputc1(xw, screen->base64_final);
1612 xtermGetSelection(Widget w,
1614 String * params, /* selections in precedence order */
1615 Cardinal num_params,
1624 if (num_params == 0)
1626 if ((xw = getXtermWidget(w)) == 0)
1629 TRACE(("xtermGetSelection num_params %d\n", num_params));
1630 params = MapSelections(xw, params, num_params);
1632 XmuInternStrings(XtDisplay(w), params, (Cardinal) 1, &selection);
1633 cutbuffer = CutBuffer(selection);
1635 TRACE(("Cutbuffer: %d, target: %s\n", cutbuffer,
1637 ? visibleSelectionTarget(XtDisplay(w), targets[0])
1640 if (cutbuffer >= 0) {
1642 unsigned long nbytes;
1644 Atom type = XA_STRING;
1647 /* 'line' is freed in SelectionReceived */
1648 line = XFetchBuffer(XtDisplay(w), &inbytes, cutbuffer);
1649 nbytes = (unsigned long) inbytes;
1652 SelectionReceived(w, NULL, &selection, &type, (XtPointer) line,
1654 else if (num_params > 1) {
1655 xtermGetSelection(w, ev_time, params + 1, num_params - 1, NULL);
1664 struct _SelectionList *list;
1666 if (targets == NULL || targets[0] == None) {
1667 targets = _SelectionTargets(w);
1671 target = targets[0];
1673 if (targets[1] == None) { /* last target in list */
1676 targets = _SelectionTargets(w);
1678 targets = &(targets[1]);
1682 /* 'list' is freed in SelectionReceived */
1683 list = TypeXtMalloc(struct _SelectionList);
1685 list->params = params;
1686 list->count = num_params;
1687 list->targets = targets;
1688 list->time = ev_time;
1694 XtGetSelectionValue(w, selection,
1697 (XtPointer) list, ev_time);
1702 #if OPT_TRACE && OPT_WIDE_CHARS
1704 GettingSelection(Display * dpy, Atom type, Char * line, unsigned long len)
1709 name = XGetAtomName(dpy, type);
1711 TRACE(("Getting %s (%ld)\n", name, (long int) type));
1712 for (cp = line; cp < line + len; cp++) {
1713 TRACE(("[%d:%lu]", (int) (cp + 1 - line), len));
1715 TRACE(("%c\n", *cp));
1717 TRACE(("\\x%02x\n", *cp));
1722 #define GettingSelection(dpy,type,line,len) /* nothing */
1726 # define tty_vwrite(pty,lag,l) tt_write(lag,l)
1727 #else /* !( VMS ) */
1728 # define tty_vwrite(pty,lag,l) v_write(pty,lag,l)
1729 #endif /* defined VMS */
1732 /* Return base64 code character given 6-bit number */
1733 static const char base64_code[] = "\
1734 ABCDEFGHIJKLMNOPQRSTUVWXYZ\
1735 abcdefghijklmnopqrstuvwxyz\
1738 base64_flush(TScreen * screen)
1741 switch (screen->base64_count) {
1745 x = CharOf(base64_code[screen->base64_accu << 4]);
1746 tty_vwrite(screen->respond, &x, 1);
1749 x = CharOf(base64_code[screen->base64_accu << 2]);
1750 tty_vwrite(screen->respond, &x, 1);
1753 if (screen->base64_pad & 3)
1754 tty_vwrite(screen->respond,
1755 (const Char *) "===",
1756 (unsigned) (4 - (screen->base64_pad & 3)));
1757 screen->base64_count = 0;
1758 screen->base64_accu = 0;
1759 screen->base64_pad = 0;
1761 #endif /* OPT_PASTE64 */
1764 _qWriteSelectionData(TScreen * screen, Char * lag, unsigned length)
1767 if (screen->base64_paste) {
1768 /* Send data as base64 */
1773 switch (screen->base64_count) {
1775 buf[x++] = CharOf(base64_code[*p >> 2]);
1776 screen->base64_accu = (unsigned) (*p & 0x3);
1777 screen->base64_count = 2;
1781 buf[x++] = CharOf(base64_code[(screen->base64_accu << 4) +
1783 screen->base64_accu = (unsigned) (*p & 0xF);
1784 screen->base64_count = 4;
1788 buf[x++] = CharOf(base64_code[(screen->base64_accu << 2) +
1790 buf[x++] = CharOf(base64_code[*p & 0x3F]);
1791 screen->base64_accu = 0;
1792 screen->base64_count = 0;
1797 /* Write 63 or 64 characters */
1798 screen->base64_pad += x;
1799 tty_vwrite(screen->respond, buf, x);
1804 screen->base64_pad += x;
1805 tty_vwrite(screen->respond, buf, x);
1808 #endif /* OPT_PASTE64 */
1810 if (SCREEN_FLAG(screen, paste_quotes)) {
1812 tty_vwrite(screen->respond, (const Char *) "\026", 1); /* Control-V */
1813 tty_vwrite(screen->respond, lag++, 1);
1817 tty_vwrite(screen->respond, lag, length);
1821 _WriteSelectionData(TScreen * screen, Char * line, size_t length)
1823 /* Write data to pty a line at a time. */
1824 /* Doing this one line at a time may no longer be necessary
1825 because v_write has been re-written. */
1829 /* in the VMS version, if tt_pasting isn't set to True then qio
1830 reads aren't blocked and an infinite loop is entered, where the
1831 pasted text shows up as new input, goes in again, shows up
1832 again, ad nauseum. */
1837 end = &line[length];
1841 if (screen->base64_paste) {
1842 _qWriteSelectionData(screen, lag, (unsigned) (end - lag));
1843 base64_flush(screen);
1847 if (!SCREEN_FLAG(screen, paste_literal_nl)) {
1849 for (cp = line; cp != end; cp++) {
1852 _qWriteSelectionData(screen, lag, (unsigned) (cp - lag + 1));
1859 _qWriteSelectionData(screen, lag, (unsigned) (end - lag));
1864 tt_start_read(); /* reenable reads or a character may be lost */
1870 _WriteKey(TScreen * screen, const Char * in)
1874 size_t length = strlen((const char *) in);
1876 if (screen->control_eight_bits) {
1877 line[count++] = ANSI_CSI;
1879 line[count++] = ANSI_ESC;
1880 line[count++] = '[';
1883 line[count++] = *in++;
1884 line[count++] = '~';
1885 tty_vwrite(screen->respond, line, count);
1887 #endif /* OPT_READLINE */
1889 /* SelectionReceived: stuff received selection text into pty */
1893 SelectionReceived(Widget w,
1894 XtPointer client_data,
1895 Atom * selection GCC_UNUSED,
1898 unsigned long *length,
1901 char **text_list = NULL;
1902 int text_list_count;
1903 XTextProperty text_prop;
1906 #if OPT_TRACE && OPT_WIDE_CHARS
1907 Char *line = (Char *) value;
1912 if ((xw = getXtermWidget(w)) == 0)
1915 screen = TScreenOf(xw);
1918 if (*type == 0 /*XT_CONVERT_FAIL */
1923 text_prop.value = (unsigned char *) value;
1924 text_prop.encoding = *type;
1925 text_prop.format = *format;
1926 text_prop.nitems = *length;
1928 TRACE(("SelectionReceived %s format %d, nitems %ld\n",
1929 visibleSelectionTarget(dpy, text_prop.encoding),
1934 if (screen->wide_chars) {
1935 if (*type == XA_UTF8_STRING(dpy) ||
1936 *type == XA_STRING ||
1937 *type == XA_COMPOUND_TEXT(dpy)) {
1938 GettingSelection(dpy, *type, line, *length);
1939 if (Xutf8TextPropertyToTextList(dpy, &text_prop,
1941 &text_list_count) < 0) {
1942 TRACE(("Conversion failed\n"));
1947 #endif /* OPT_WIDE_CHARS */
1949 /* Convert the selection to locale's multibyte encoding. */
1951 if (*type == XA_UTF8_STRING(dpy) ||
1952 *type == XA_STRING ||
1953 *type == XA_COMPOUND_TEXT(dpy)) {
1956 GettingSelection(dpy, *type, line, *length);
1959 if (*type == XA_UTF8_STRING(dpy) &&
1960 !(screen->wide_chars || screen->c1_printable)) {
1961 rc = xtermUtf8ToTextList(xw, &text_prop,
1962 &text_list, &text_list_count);
1965 if (*type == XA_STRING && screen->brokenSelections) {
1966 rc = XTextPropertyToStringList(&text_prop,
1967 &text_list, &text_list_count);
1969 rc = XmbTextPropertyToTextList(dpy, &text_prop,
1974 TRACE(("Conversion failed\n"));
1980 if (text_list != NULL && text_list_count != 0) {
1984 if (screen->base64_paste) {
1989 if (SCREEN_FLAG(screen, paste_brackets)) {
1990 _WriteKey(screen, (const Char *) "200");
1993 for (i = 0; i < text_list_count; i++) {
1994 size_t len = strlen(text_list[i]);
1995 _WriteSelectionData(screen, (Char *) text_list[i], len);
1998 if (screen->base64_paste) {
2003 if (SCREEN_FLAG(screen, paste_brackets)) {
2004 _WriteKey(screen, (const Char *) "201");
2007 XFreeStringList(text_list);
2011 XtFree((char *) client_data);
2012 XtFree((char *) value);
2017 if (client_data != 0) {
2018 struct _SelectionList *list = (struct _SelectionList *) client_data;
2020 TRACE(("SelectionReceived ->xtermGetSelection\n"));
2021 xtermGetSelection(w, list->time,
2022 list->params, list->count, list->targets);
2023 XtFree((char *) client_data);
2033 HandleInsertSelection(Widget w,
2034 XEvent * event, /* assumed to be XButtonEvent* */
2035 String * params, /* selections in precedence order */
2036 Cardinal *num_params)
2040 if ((xw = getXtermWidget(w)) != 0) {
2041 if (!SendMousePosition(xw, event)) {
2044 TScreen *screen = TScreenOf(xw);
2045 if (IsBtnEvent(event)
2046 /* Disable on Shift-mouse, including the application-mouse modes */
2047 && !(KeyModifiers(event) & ShiftMask)
2048 && (screen->send_mouse_pos == MOUSE_OFF)
2049 && SCREEN_FLAG(screen, paste_moves)
2050 && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta))
2051 ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta);
2052 #endif /* OPT_READLINE */
2054 xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL);
2060 EvalSelectUnit(XtermWidget xw,
2061 Time buttonDownTime,
2062 SelectUnit defaultUnit,
2063 unsigned int button)
2065 TScreen *screen = TScreenOf(xw);
2069 if (button != screen->lastButton) {
2070 delta = screen->multiClickTime + 1;
2071 } else if (screen->lastButtonUpTime == (Time) 0) {
2072 /* first time and once in a blue moon */
2073 delta = screen->multiClickTime + 1;
2074 } else if (buttonDownTime > screen->lastButtonUpTime) {
2075 /* most of the time */
2076 delta = (int) (buttonDownTime - screen->lastButtonUpTime);
2078 /* time has rolled over since lastButtonUpTime */
2079 delta = (int) ((((Time) ~ 0) - screen->lastButtonUpTime) + buttonDownTime);
2082 if (delta > screen->multiClickTime) {
2083 screen->numberOfClicks = 1;
2084 result = defaultUnit;
2086 result = screen->selectMap[screen->numberOfClicks % screen->maxClicks];
2087 screen->numberOfClicks += 1;
2089 TRACE(("EvalSelectUnit(%d) = %d\n", screen->numberOfClicks, result));
2094 do_select_start(XtermWidget xw,
2095 XEvent * event, /* must be XButtonEvent* */
2098 TScreen *screen = TScreenOf(xw);
2100 if (SendMousePosition(xw, event))
2102 screen->selectUnit = EvalSelectUnit(xw,
2103 event->xbutton.time,
2105 event->xbutton.button);
2106 screen->replyToEmacs = False;
2109 lastButtonDownTime = event->xbutton.time;
2112 StartSelect(xw, cell);
2117 HandleSelectStart(Widget w,
2118 XEvent * event, /* must be XButtonEvent* */
2119 String * params GCC_UNUSED,
2120 Cardinal *num_params GCC_UNUSED)
2124 if ((xw = getXtermWidget(w)) != 0) {
2125 TScreen *screen = TScreenOf(xw);
2128 screen->firstValidRow = 0;
2129 screen->lastValidRow = screen->max_row;
2130 PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell);
2133 ExtendingSelection = 0;
2136 do_select_start(xw, event, &cell);
2142 HandleKeyboardSelectStart(Widget w,
2143 XEvent * event, /* must be XButtonEvent* */
2144 String * params GCC_UNUSED,
2145 Cardinal *num_params GCC_UNUSED)
2149 if ((xw = getXtermWidget(w)) != 0) {
2150 TScreen *screen = TScreenOf(xw);
2151 do_select_start(xw, event, &screen->cursorp);
2156 TrackDown(XtermWidget xw, XButtonEvent * event)
2158 TScreen *screen = TScreenOf(xw);
2161 screen->selectUnit = EvalSelectUnit(xw,
2165 if (screen->numberOfClicks > 1) {
2166 PointToCELL(screen, event->y, event->x, &cell);
2167 screen->replyToEmacs = True;
2168 StartSelect(xw, &cell);
2170 screen->waitingForTrackInfo = True;
2171 EditorButton(xw, event);
2175 #define boundsCheck(x) if (x < 0) \
2177 else if (x >= screen->max_row) \
2181 TrackMouse(XtermWidget xw,
2187 TScreen *screen = TScreenOf(xw);
2189 if (screen->waitingForTrackInfo) { /* if Timed, ignore */
2190 screen->waitingForTrackInfo = False;
2193 CELL first = *start;
2195 boundsCheck(first.row);
2196 boundsCheck(firstrow);
2197 boundsCheck(lastrow);
2198 screen->firstValidRow = firstrow;
2199 screen->lastValidRow = lastrow;
2200 screen->replyToEmacs = True;
2201 StartSelect(xw, &first);
2207 StartSelect(XtermWidget xw, const CELL * cell)
2209 TScreen *screen = TScreenOf(xw);
2211 TRACE(("StartSelect row=%d, col=%d\n", cell->row, cell->col));
2212 if (screen->cursor_state)
2214 if (screen->numberOfClicks == 1) {
2215 /* set start of selection */
2216 screen->rawPos = *cell;
2218 /* else use old values in rawPos */
2219 screen->saveStartR = screen->startExt = screen->rawPos;
2220 screen->saveEndR = screen->endExt = screen->rawPos;
2221 if (Coordinate(screen, cell) < Coordinate(screen, &(screen->rawPos))) {
2222 screen->eventMode = LEFTEXTENSION;
2223 screen->startExt = *cell;
2225 screen->eventMode = RIGHTEXTENSION;
2226 screen->endExt = *cell;
2228 ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False);
2232 EndExtend(XtermWidget xw,
2233 XEvent * event, /* must be XButtonEvent */
2234 String * params, /* selections */
2235 Cardinal num_params,
2236 Bool use_cursor_loc)
2240 TScreen *screen = TScreenOf(xw);
2243 if (use_cursor_loc) {
2244 cell = screen->cursorp;
2246 PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell);
2248 ExtendExtend(xw, &cell);
2249 screen->lastButtonUpTime = event->xbutton.time;
2250 screen->lastButton = event->xbutton.button;
2251 if (!isSameCELL(&(screen->startSel), &(screen->endSel))) {
2252 if (screen->replyToEmacs) {
2254 if (screen->control_eight_bits) {
2255 line[count++] = ANSI_CSI;
2257 line[count++] = ANSI_ESC;
2258 line[count++] = '[';
2260 if (isSameCELL(&(screen->rawPos), &(screen->startSel))
2261 && isSameCELL(&cell, &(screen->endSel))) {
2262 /* Use short-form emacs select */
2263 line[count++] = 't';
2264 count = EmitMousePosition(screen, line, count, screen->endSel.col);
2265 count = EmitMousePosition(screen, line, count, screen->endSel.row);
2267 /* long-form, specify everything */
2268 line[count++] = 'T';
2269 count = EmitMousePosition(screen, line, count, screen->startSel.col);
2270 count = EmitMousePosition(screen, line, count, screen->startSel.row);
2271 count = EmitMousePosition(screen, line, count, screen->endSel.col);
2272 count = EmitMousePosition(screen, line, count, screen->endSel.row);
2273 count = EmitMousePosition(screen, line, count, cell.col);
2274 count = EmitMousePosition(screen, line, count, cell.row);
2276 v_write(screen->respond, line, count);
2277 TrackText(xw, &zeroCELL, &zeroCELL);
2280 SelectSet(xw, event, params, num_params);
2281 screen->eventMode = NORMAL;
2285 HandleSelectSet(Widget w,
2288 Cardinal *num_params)
2292 if ((xw = getXtermWidget(w)) != 0) {
2293 SelectSet(xw, event, params, *num_params);
2299 SelectSet(XtermWidget xw,
2300 XEvent * event GCC_UNUSED,
2302 Cardinal num_params)
2304 TScreen *screen = TScreenOf(xw);
2306 TRACE(("SelectSet\n"));
2307 /* Only do select stuff if non-null select */
2308 if (!isSameCELL(&(screen->startSel), &(screen->endSel))) {
2309 SaltTextAway(xw, &(screen->startSel), &(screen->endSel), params, num_params);
2311 DisownSelection(xw);
2315 #define Abs(x) ((x) < 0 ? -(x) : (x))
2319 do_start_extend(XtermWidget xw,
2320 XEvent * event, /* must be XButtonEvent* */
2321 String * params GCC_UNUSED,
2322 Cardinal *num_params GCC_UNUSED,
2323 Bool use_cursor_loc)
2325 TScreen *screen = TScreenOf(xw);
2329 if (SendMousePosition(xw, event))
2332 screen->firstValidRow = 0;
2333 screen->lastValidRow = screen->max_row;
2335 if ((KeyModifiers(event) & ShiftMask)
2336 || event->xbutton.button != Button3
2337 || !(SCREEN_FLAG(screen, dclick3_deletes)))
2339 screen->selectUnit = EvalSelectUnit(xw,
2340 event->xbutton.time,
2342 event->xbutton.button);
2343 screen->replyToEmacs = False;
2346 CheckSecondPress3(screen, event);
2349 if (screen->numberOfClicks == 1
2350 || (SCREEN_FLAG(screen, dclick3_deletes) /* Dclick special */
2351 &&!(KeyModifiers(event) & ShiftMask))) {
2352 /* Save existing selection so we can reestablish it if the guy
2353 extends past the other end of the selection */
2354 screen->saveStartR = screen->startExt = screen->startRaw;
2355 screen->saveEndR = screen->endExt = screen->endRaw;
2357 /* He just needed the selection mode changed, use old values. */
2358 screen->startExt = screen->startRaw = screen->saveStartR;
2359 screen->endExt = screen->endRaw = screen->saveEndR;
2361 if (use_cursor_loc) {
2362 cell = screen->cursorp;
2364 PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell);
2366 coord = Coordinate(screen, &cell);
2368 if (Abs(coord - Coordinate(screen, &(screen->startSel)))
2369 < Abs(coord - Coordinate(screen, &(screen->endSel)))
2370 || coord < Coordinate(screen, &(screen->startSel))) {
2371 /* point is close to left side of selection */
2372 screen->eventMode = LEFTEXTENSION;
2373 screen->startExt = cell;
2375 /* point is close to left side of selection */
2376 screen->eventMode = RIGHTEXTENSION;
2377 screen->endExt = cell;
2379 ComputeSelect(xw, &(screen->startExt), &(screen->endExt), True);
2382 if (!isSameCELL(&(screen->startSel), &(screen->endSel)))
2383 ExtendingSelection = 1;
2388 ExtendExtend(XtermWidget xw, const CELL * cell)
2390 TScreen *screen = TScreenOf(xw);
2391 int coord = Coordinate(screen, cell);
2393 TRACE(("ExtendExtend row=%d, col=%d\n", cell->row, cell->col));
2394 if (screen->eventMode == LEFTEXTENSION
2395 && ((coord + (screen->selectUnit != Select_CHAR))
2396 > Coordinate(screen, &(screen->endSel)))) {
2397 /* Whoops, he's changed his mind. Do RIGHTEXTENSION */
2398 screen->eventMode = RIGHTEXTENSION;
2399 screen->startExt = screen->saveStartR;
2400 } else if (screen->eventMode == RIGHTEXTENSION
2401 && coord < Coordinate(screen, &(screen->startSel))) {
2402 /* Whoops, he's changed his mind. Do LEFTEXTENSION */
2403 screen->eventMode = LEFTEXTENSION;
2404 screen->endExt = screen->saveEndR;
2406 if (screen->eventMode == LEFTEXTENSION) {
2407 screen->startExt = *cell;
2409 screen->endExt = *cell;
2411 ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False);
2414 if (!isSameCELL(&(screen->startSel), &(screen->endSel)))
2415 ExtendingSelection = 1;
2420 HandleStartExtend(Widget w,
2421 XEvent * event, /* must be XButtonEvent* */
2422 String * params, /* unused */
2423 Cardinal *num_params) /* unused */
2427 if ((xw = getXtermWidget(w)) != 0) {
2428 do_start_extend(xw, event, params, num_params, False);
2433 HandleKeyboardStartExtend(Widget w,
2434 XEvent * event, /* must be XButtonEvent* */
2435 String * params, /* unused */
2436 Cardinal *num_params) /* unused */
2440 if ((xw = getXtermWidget(w)) != 0) {
2441 do_start_extend(xw, event, params, num_params, True);
2446 ScrollSelection(TScreen * screen, int amount, Bool always)
2448 int minrow = INX2ROW(screen, -screen->savedlines);
2449 int maxrow = INX2ROW(screen, screen->max_row);
2450 int maxcol = screen->max_col;
2452 #define scroll_update_one(cell) \
2453 (cell)->row += amount; \
2454 if ((cell)->row < minrow) { \
2455 (cell)->row = minrow; \
2458 if ((cell)->row > maxrow) { \
2459 (cell)->row = maxrow; \
2460 (cell)->col = maxcol; \
2463 scroll_update_one(&(screen->startRaw));
2464 scroll_update_one(&(screen->endRaw));
2465 scroll_update_one(&(screen->startSel));
2466 scroll_update_one(&(screen->endSel));
2468 scroll_update_one(&(screen->rawPos));
2471 * If we are told to scroll the selection but it lies outside the scrolling
2472 * margins, then that could cause the selection to move (bad). It is not
2473 * simple to fix, because this function is called both for the scrollbar
2474 * actions as well as application scrolling. The 'always' flag is set in
2475 * the former case. The rest of the logic handles the latter.
2477 if (ScrnHaveSelection(screen)) {
2480 adjust = ROW2INX(screen, screen->startH.row);
2482 || !ScrnHaveLineMargins(screen)
2483 || ScrnIsLineInMargins(screen, adjust)) {
2484 scroll_update_one(&screen->startH);
2486 adjust = ROW2INX(screen, screen->endH.row);
2488 || !ScrnHaveLineMargins(screen)
2489 || ScrnIsLineInMargins(screen, adjust)) {
2490 scroll_update_one(&screen->endH);
2494 screen->startHCoord = Coordinate(screen, &screen->startH);
2495 screen->endHCoord = Coordinate(screen, &screen->endH);
2500 ResizeSelection(TScreen * screen GCC_UNUSED, int rows, int cols)
2502 rows--; /* decr to get 0-max */
2505 if (screen->startRaw.row > rows)
2506 screen->startRaw.row = rows;
2507 if (screen->startSel.row > rows)
2508 screen->startSel.row = rows;
2509 if (screen->endRaw.row > rows)
2510 screen->endRaw.row = rows;
2511 if (screen->endSel.row > rows)
2512 screen->endSel.row = rows;
2513 if (screen->rawPos.row > rows)
2514 screen->rawPos.row = rows;
2516 if (screen->startRaw.col > cols)
2517 screen->startRaw.col = cols;
2518 if (screen->startSel.col > cols)
2519 screen->startSel.col = cols;
2520 if (screen->endRaw.col > cols)
2521 screen->endRaw.col = cols;
2522 if (screen->endSel.col > cols)
2523 screen->endSel.col = cols;
2524 if (screen->rawPos.col > cols)
2525 screen->rawPos.col = cols;
2532 return (i == HIDDEN_CHAR) || (WideCells(i) == 2);
2535 #define isWideCell(row, col) iswide((int)XTERM_CELL(row, col))
2539 PointToCELL(TScreen * screen,
2543 /* Convert pixel coordinates to character coordinates.
2544 Rows are clipped between firstValidRow and lastValidRow.
2545 Columns are clipped between to be 0 or greater, but are not clipped to some
2548 cell->row = (y - screen->border) / FontHeight(screen);
2549 if (cell->row < screen->firstValidRow)
2550 cell->row = screen->firstValidRow;
2551 else if (cell->row > screen->lastValidRow)
2552 cell->row = screen->lastValidRow;
2553 cell->col = (x - OriginX(screen)) / FontWidth(screen);
2556 else if (cell->col > MaxCols(screen)) {
2557 cell->col = MaxCols(screen);
2561 * If we got a click on the right half of a doublewidth character,
2562 * pretend it happened on the left half.
2565 && isWideCell(cell->row, cell->col - 1)
2566 && (XTERM_CELL(cell->row, cell->col) == HIDDEN_CHAR)) {
2573 * Find the last column at which text was drawn on the given row.
2576 LastTextCol(TScreen * screen, LineData * ld, int row)
2582 if (okScrnRow(screen, row)) {
2583 for (i = screen->max_col,
2584 ch = ld->attribs + i;
2585 i >= 0 && !(*ch & CHARDRAWN);
2590 if (CSET_DOUBLE(GetLineDblCS(ld))) {
2601 ** double click table for cut and paste in 8 bits
2603 ** This table is divided in four parts :
2605 ** - control characters [0,0x1f] U [0x80,0x9f]
2606 ** - separators [0x20,0x3f] U [0xa0,0xb9]
2607 ** - binding characters [0x40,0x7f] U [0xc0,0xff]
2611 static int charClass[256] =
2613 /* NUL SOH STX ETX EOT ENQ ACK BEL */
2614 32, 1, 1, 1, 1, 1, 1, 1,
2615 /* BS HT NL VT NP CR SO SI */
2616 1, 32, 1, 1, 1, 1, 1, 1,
2617 /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
2618 1, 1, 1, 1, 1, 1, 1, 1,
2619 /* CAN EM SUB ESC FS GS RS US */
2620 1, 1, 1, 1, 1, 1, 1, 1,
2621 /* SP ! " # $ % & ' */
2622 32, 33, 34, 35, 36, 37, 38, 39,
2623 /* ( ) * + , - . / */
2624 40, 41, 42, 43, 44, 45, 46, 47,
2625 /* 0 1 2 3 4 5 6 7 */
2626 48, 48, 48, 48, 48, 48, 48, 48,
2627 /* 8 9 : ; < = > ? */
2628 48, 48, 58, 59, 60, 61, 62, 63,
2629 /* @ A B C D E F G */
2630 64, 48, 48, 48, 48, 48, 48, 48,
2631 /* H I J K L M N O */
2632 48, 48, 48, 48, 48, 48, 48, 48,
2633 /* P Q R S T U V W */
2634 48, 48, 48, 48, 48, 48, 48, 48,
2635 /* X Y Z [ \ ] ^ _ */
2636 48, 48, 48, 91, 92, 93, 94, 48,
2637 /* ` a b c d e f g */
2638 96, 48, 48, 48, 48, 48, 48, 48,
2639 /* h i j k l m n o */
2640 48, 48, 48, 48, 48, 48, 48, 48,
2641 /* p q r s t u v w */
2642 48, 48, 48, 48, 48, 48, 48, 48,
2643 /* x y z { | } ~ DEL */
2644 48, 48, 48, 123, 124, 125, 126, 1,
2645 /* x80 x81 x82 x83 IND NEL SSA ESA */
2646 1, 1, 1, 1, 1, 1, 1, 1,
2647 /* HTS HTJ VTS PLD PLU RI SS2 SS3 */
2648 1, 1, 1, 1, 1, 1, 1, 1,
2649 /* DCS PU1 PU2 STS CCH MW SPA EPA */
2650 1, 1, 1, 1, 1, 1, 1, 1,
2651 /* x98 x99 x9A CSI ST OSC PM APC */
2652 1, 1, 1, 1, 1, 1, 1, 1,
2653 /* - i c/ L ox Y- | So */
2654 160, 161, 162, 163, 164, 165, 166, 167,
2655 /* .. c0 ip << _ R0 - */
2656 168, 169, 170, 171, 172, 173, 174, 175,
2657 /* o +- 2 3 ' u q| . */
2658 176, 177, 178, 179, 180, 181, 182, 183,
2659 /* , 1 2 >> 1/4 1/2 3/4 ? */
2660 184, 185, 186, 187, 188, 189, 190, 191,
2661 /* A` A' A^ A~ A: Ao AE C, */
2662 48, 48, 48, 48, 48, 48, 48, 48,
2663 /* E` E' E^ E: I` I' I^ I: */
2664 48, 48, 48, 48, 48, 48, 48, 48,
2665 /* D- N~ O` O' O^ O~ O: X */
2666 48, 48, 48, 48, 48, 48, 48, 215,
2667 /* O/ U` U' U^ U: Y' P B */
2668 48, 48, 48, 48, 48, 48, 48, 48,
2669 /* a` a' a^ a~ a: ao ae c, */
2670 48, 48, 48, 48, 48, 48, 48, 48,
2671 /* e` e' e^ e: i` i' i^ i: */
2672 48, 48, 48, 48, 48, 48, 48, 48,
2673 /* d n~ o` o' o^ o~ o: -: */
2674 48, 48, 48, 48, 48, 48, 48, 247,
2675 /* o/ u` u' u^ u: y' P y: */
2676 48, 48, 48, 48, 48, 48, 48, 48};
2680 SetCharacterClassRange(int low, /* in range of [0..255] */
2682 int value) /* arbitrary */
2685 if (low < 0 || high > 255 || high < low)
2688 for (; low <= high; low++)
2689 charClass[low] = value;
2696 class_of(LineData * ld, CELL * cell)
2701 if (CSET_DOUBLE(GetLineDblCS(ld))) {
2706 assert(temp.col < ld->lineSize);
2707 return CharacterClass((int) (ld->charData[temp.col]));
2711 #define CClassSelects(name, cclass) \
2712 (CClassOf(name) == cclass \
2713 || XTERM_CELL(screen->name.row, screen->name.col) == HIDDEN_CHAR)
2715 #define CClassSelects(name, cclass) \
2716 (class_of(ld.name, &((screen->name))) == cclass)
2719 #define CClassOf(name) class_of(ld.name, &((screen->name)))
2722 * If the given column is past the end of text on the given row, bump to the
2723 * beginning of the next line.
2726 okPosition(TScreen * screen,
2730 Boolean result = True;
2732 if (cell->row > screen->max_row) {
2734 } else if (cell->col > (LastTextCol(screen, *ld, cell->row) + 1)) {
2735 if (cell->row < screen->max_row) {
2737 *ld = GET_LINEDATA(screen, ++cell->row);
2745 trimLastLine(TScreen * screen,
2749 if (screen->cutNewline && last->row < screen->max_row) {
2751 *ld = GET_LINEDATA(screen, ++last->row);
2753 last->col = LastTextCol(screen, *ld, last->row) + 1;
2757 #if OPT_SELECT_REGEX
2759 * Returns the first row of a wrapped line.
2762 firstRowOfLine(TScreen * screen, int row, Bool visible)
2765 int limit = visible ? 0 : -screen->savedlines;
2767 while (row > limit &&
2768 (ld = GET_LINEDATA(screen, row - 1)) != 0 &&
2769 LineTstWrapped(ld)) {
2776 * Returns the last row of a wrapped line.
2779 lastRowOfLine(TScreen * screen, int row)
2783 while (row < screen->max_row &&
2784 (ld = GET_LINEDATA(screen, row)) != 0 &&
2785 LineTstWrapped(ld)) {
2792 * Returns the number of cells on the range of rows.
2795 lengthOfLines(TScreen * screen, int firstRow, int lastRow)
2797 unsigned length = 0;
2800 for (n = firstRow; n <= lastRow; ++n) {
2801 LineData *ld = GET_LINEDATA(screen, n);
2802 int value = LastTextCol(screen, ld, n);
2804 length += (unsigned) (value + 1);
2810 * Make a copy of the wrapped-line which corresponds to the given row as a
2811 * string of bytes. Construct an index for the columns from the beginning of
2815 make_indexed_text(TScreen * screen, int row, unsigned length, int *indexed)
2818 size_t need = (length + 1);
2821 * Get a quick upper bound to the number of bytes needed, if the whole
2822 * string were UTF-8.
2824 if_OPT_WIDE_CHARS(screen, {
2825 need *= ((screen->lineExtra + 1) * 6);
2828 if ((result = TypeCallocN(Char, need + 1)) != 0) {
2829 LineData *ld = GET_LINEDATA(screen, row);
2831 Char *last = result;
2835 int limit = LastTextCol(screen, ld, row);
2837 while (col <= limit) {
2839 unsigned data = ld->charData[col];
2841 assert(col < ld->lineSize);
2842 /* some internal points may not be drawn */
2846 if_WIDE_OR_NARROW(screen, {
2847 next = convertToUTF8(last, data);
2850 *next++ = CharOf(data);
2853 if_OPT_WIDE_CHARS(screen, {
2855 for_each_combData(off, ld) {
2856 data = ld->combData[off][col];
2859 next = convertToUTF8(next, data);
2863 indexed[used] = (int) (last - result);
2865 /* TRACE(("index[%d.%d] %d:%s\n", row, used, indexed[used], last)); */
2869 indexed[used] = (int) (next - result);
2871 } while (used < length &&
2872 LineTstWrapped(ld) &&
2873 (ld = GET_LINEDATA(screen, ++row)) != 0 &&
2874 row < screen->max_row);
2876 /* TRACE(("result:%s\n", result)); */
2877 return (char *) result;
2881 * Find the column given an offset into the character string by using the
2882 * index constructed in make_indexed_text().
2885 indexToCol(int *indexed, int len, int off)
2888 while (indexed[col] < len) {
2889 if (indexed[col] >= off)
2897 * Given a row number, and a column offset from that (which may be wrapped),
2898 * set the cell to the actual row/column values.
2901 columnToCell(TScreen * screen, int row, int col, CELL * cell)
2903 while (row < screen->max_row) {
2904 LineData *ld = GET_LINEDATA(screen, row);
2905 int last = LastTextCol(screen, ld, row);
2907 /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */
2912 * Stop if the current row does not wrap (does not continue the current
2915 if (!LineTstWrapped(ld)) {
2929 * Given a cell, find the corresponding column offset.
2932 cellToColumn(TScreen * screen, CELL * cell)
2935 int col = cell->col;
2936 int row = firstRowOfLine(screen, cell->row, False);
2937 while (row < cell->row) {
2938 ld = GET_LINEDATA(screen, row);
2939 col += LastTextCol(screen, ld, row++);
2943 ld = GET_LINEDATA(screen, row);
2944 if (CSET_DOUBLE(GetLineDblCS(ld)))
2951 do_select_regex(TScreen * screen, CELL * startc, CELL * endc)
2953 LineData *ld = GET_LINEDATA(screen, startc->row);
2954 int inx = ((screen->numberOfClicks - 1) % screen->maxClicks);
2955 char *expr = screen->selectExpr[inx];
2961 TRACE(("Select_REGEX:%s\n", NonNull(expr)));
2962 if (okPosition(screen, &ld, startc) && expr != 0) {
2963 if (regcomp(&preg, expr, REG_EXTENDED) == 0) {
2964 int firstRow = firstRowOfLine(screen, startc->row, True);
2965 int lastRow = lastRowOfLine(screen, firstRow);
2966 unsigned size = lengthOfLines(screen, firstRow, lastRow);
2967 int actual = cellToColumn(screen, startc);
2969 TRACE(("regcomp ok rows %d..%d bytes %d\n",
2970 firstRow, lastRow, size));
2972 if ((indexed = TypeCallocN(int, size + 1)) != 0) {
2973 if ((search = make_indexed_text(screen,
2977 int len = (int) strlen(search);
2982 for (col = 0; indexed[col] < len; ++col) {
2984 search + indexed[col],
2985 (size_t) 1, &match, 0) == 0) {
2986 int start_inx = match.rm_so + indexed[col];
2987 int finis_inx = match.rm_eo + indexed[col];
2988 int start_col = indexToCol(indexed, len, start_inx);
2989 int finis_col = indexToCol(indexed, len, finis_inx);
2991 if (start_col <= actual &&
2992 actual < finis_col) {
2993 int test = finis_col - start_col;
2994 if (best_len < test) {
2996 best_col = start_col;
2997 TRACE(("match column %d len %d\n",
3004 if (best_col >= 0) {
3005 int best_nxt = best_col + best_len;
3006 columnToCell(screen, firstRow, best_col, startc);
3007 columnToCell(screen, firstRow, best_nxt, endc);
3008 TRACE(("search::%s\n", search));
3009 TRACE(("indexed:%d..%d -> %d..%d\n",
3012 indexed[best_nxt]));
3013 TRACE(("matched:%d:%s\n",
3014 indexed[best_nxt] + 1 -
3016 visibleChars((Char *) (search + indexed[best_col]),
3017 (unsigned) (indexed[best_nxt] +
3019 indexed[best_col]))));
3025 if ((ld = GET_LINEDATA(screen, startc->row)) != 0) {
3026 if (CSET_DOUBLE(GetLineDblCS(ld)))
3029 if ((ld = GET_LINEDATA(screen, endc->row)) != 0) {
3030 if (CSET_DOUBLE(GetLineDblCS(ld)))
3039 #endif /* OPT_SELECT_REGEX */
3041 #define InitRow(name) \
3042 ld.name = GET_LINEDATA(screen, screen->name.row)
3044 #define NextRow(name) \
3045 ld.name = GET_LINEDATA(screen, ++screen->name.row)
3047 #define PrevRow(name) \
3048 ld.name = GET_LINEDATA(screen, --screen->name.row)
3050 #define MoreRows(name) \
3051 (screen->name.row < screen->max_row)
3053 #define isPrevWrapped(name) \
3054 (screen->name.row > 0 \
3055 && (ltmp = GET_LINEDATA(screen, screen->name.row - 1)) != 0 \
3056 && LineTstWrapped(ltmp))
3059 * sets startSel endSel
3060 * ensuring that they have legal values
3063 ComputeSelect(XtermWidget xw,
3068 TScreen *screen = TScreenOf(xw);
3072 CELL first = *startc;
3074 Boolean ignored = False;
3082 TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n",
3083 first.row, first.col,
3085 extend ? "" : "no"));
3089 && isWideCell(first.row, first.col - 1)
3090 && XTERM_CELL(first.row, first.col - 0) == HIDDEN_CHAR) {
3091 TRACE(("Adjusting start. Changing downwards from %i.\n", first.col));
3093 if (last.col == (first.col + 1))
3098 && isWideCell(last.row, last.col - 1)
3099 && XTERM_CELL(last.row, last.col) == HIDDEN_CHAR) {
3104 if (Coordinate(screen, &first) <= Coordinate(screen, &last)) {
3105 screen->startSel = screen->startRaw = first;
3106 screen->endSel = screen->endRaw = last;
3107 } else { /* Swap them */
3108 screen->startSel = screen->startRaw = last;
3109 screen->endSel = screen->endRaw = first;
3115 switch (screen->selectUnit) {
3117 (void) okPosition(screen, &(ld.startSel), &(screen->startSel));
3118 (void) okPosition(screen, &(ld.endSel), &(screen->endSel));
3122 TRACE(("Select_WORD\n"));
3123 if (okPosition(screen, &(ld.startSel), &(screen->startSel))) {
3124 cclass = CClassOf(startSel);
3126 --screen->startSel.col;
3127 if (screen->startSel.col < 0
3128 && isPrevWrapped(startSel)) {
3130 screen->startSel.col = LastTextCol(screen, ld.startSel, screen->startSel.row);
3132 } while (screen->startSel.col >= 0
3133 && CClassSelects(startSel, cclass));
3134 ++screen->startSel.col;
3137 if (screen->startSel.col
3138 && XTERM_CELL(screen->startSel.row,
3139 screen->startSel.col) == HIDDEN_CHAR)
3140 screen->startSel.col++;
3143 if (okPosition(screen, &(ld.endSel), &(screen->endSel))) {
3144 length = LastTextCol(screen, ld.endSel, screen->endSel.row);
3145 cclass = CClassOf(endSel);
3147 ++screen->endSel.col;
3148 if (screen->endSel.col > length
3149 && LineTstWrapped(ld.endSel)) {
3150 if (!MoreRows(endSel))
3152 screen->endSel.col = 0;
3154 length = LastTextCol(screen, ld.endSel, screen->endSel.row);
3156 } while (screen->endSel.col <= length
3157 && CClassSelects(endSel, cclass));
3158 /* Word-select selects if pointing to any char in "word",
3159 * especially note that it includes the last character in a word.
3160 * So we do no --endSel.col and do special eol handling.
3162 if (screen->endSel.col > length + 1
3163 && MoreRows(endSel)) {
3164 screen->endSel.col = 0;
3169 if (screen->endSel.col
3170 && XTERM_CELL(screen->endSel.row,
3171 screen->endSel.col) == HIDDEN_CHAR)
3172 screen->endSel.col++;
3175 screen->saveStartW = screen->startSel;
3179 TRACE(("Select_LINE\n"));
3180 while (LineTstWrapped(ld.endSel)
3181 && MoreRows(endSel)) {
3184 if (screen->cutToBeginningOfLine
3185 || screen->startSel.row < screen->saveStartW.row) {
3186 screen->startSel.col = 0;
3187 while (isPrevWrapped(startSel)) {
3190 } else if (!extend) {
3191 if ((first.row < screen->saveStartW.row)
3192 || (isSameRow(&first, &(screen->saveStartW))
3193 && first.col < screen->saveStartW.col)) {
3194 screen->startSel.col = 0;
3195 while (isPrevWrapped(startSel)) {
3199 screen->startSel = screen->saveStartW;
3202 trimLastLine(screen, &(ld.endSel), &(screen->endSel));
3205 case Select_GROUP: /* paragraph */
3206 TRACE(("Select_GROUP\n"));
3207 if (okPosition(screen, &(ld.startSel), &(screen->startSel))) {
3208 /* scan backward for beginning of group */
3209 while (screen->startSel.row > 0 &&
3210 (LastTextCol(screen, ld.startSel, screen->startSel.row -
3212 isPrevWrapped(startSel))) {
3215 screen->startSel.col = 0;
3216 /* scan forward for end of group */
3217 while (MoreRows(endSel) &&
3218 (LastTextCol(screen, ld.endSel, screen->endSel.row + 1) >
3220 LineTstWrapped(ld.endSel))) {
3223 trimLastLine(screen, &(ld.endSel), &(screen->endSel));
3227 case Select_PAGE: /* everything one can see */
3228 TRACE(("Select_PAGE\n"));
3229 screen->startSel.row = 0;
3230 screen->startSel.col = 0;
3231 screen->endSel.row = MaxRows(screen);
3232 screen->endSel.col = 0;
3235 case Select_ALL: /* counts scrollback if in normal screen */
3236 TRACE(("Select_ALL\n"));
3237 screen->startSel.row = -screen->savedlines;
3238 screen->startSel.col = 0;
3239 screen->endSel.row = MaxRows(screen);
3240 screen->endSel.col = 0;
3243 #if OPT_SELECT_REGEX
3245 do_select_regex(screen, &(screen->startSel), &(screen->endSel));
3249 case NSELECTUNITS: /* always ignore */
3255 /* check boundaries */
3256 ScrollSelection(screen, 0, False);
3257 TrackText(xw, &(screen->startSel), &(screen->endSel));
3263 /* Guaranteed (first.row, first.col) <= (last.row, last.col) */
3265 TrackText(XtermWidget xw,
3266 const CELL * firstp,
3269 TScreen *screen = TScreenOf(xw);
3271 CELL old_start, old_end;
3272 CELL first = *firstp;
3275 TRACE(("TrackText(first=%d,%d, last=%d,%d)\n",
3276 first.row, first.col, last.row, last.col));
3278 old_start = screen->startH;
3279 old_end = screen->endH;
3280 if (isSameCELL(&first, &old_start) &&
3281 isSameCELL(&last, &old_end))
3283 screen->startH = first;
3284 screen->endH = last;
3285 from = Coordinate(screen, &screen->startH);
3286 to = Coordinate(screen, &screen->endH);
3287 if (to <= screen->startHCoord || from > screen->endHCoord) {
3288 /* No overlap whatsoever between old and new hilite */
3289 ReHiliteText(xw, &old_start, &old_end);
3290 ReHiliteText(xw, &first, &last);
3292 if (from < screen->startHCoord) {
3293 /* Extend left end */
3294 ReHiliteText(xw, &first, &old_start);
3295 } else if (from > screen->startHCoord) {
3296 /* Shorten left end */
3297 ReHiliteText(xw, &old_start, &first);
3299 if (to > screen->endHCoord) {
3300 /* Extend right end */
3301 ReHiliteText(xw, &old_end, &last);
3302 } else if (to < screen->endHCoord) {
3303 /* Shorten right end */
3304 ReHiliteText(xw, &last, &old_end);
3307 screen->startHCoord = from;
3308 screen->endHCoord = to;
3311 /* Guaranteed that (first->row, first->col) <= (last->row, last->col) */
3313 ReHiliteText(XtermWidget xw,
3317 TScreen *screen = TScreenOf(xw);
3319 CELL first = *firstp;
3322 TRACE(("ReHiliteText from %d.%d to %d.%d\n",
3323 first.row, first.col, last.row, last.col));
3326 first.row = first.col = 0;
3327 else if (first.row > screen->max_row)
3328 return; /* nothing to do, since last.row >= first.row */
3331 return; /* nothing to do, since first.row <= last.row */
3332 else if (last.row > screen->max_row) {
3333 last.row = screen->max_row;
3334 last.col = MaxCols(screen);
3336 if (isSameCELL(&first, &last))
3339 if (!isSameRow(&first, &last)) { /* do multiple rows */
3340 if ((i = screen->max_col - first.col + 1) > 0) { /* first row */
3341 ScrnRefresh(xw, first.row, first.col, 1, i, True);
3343 if ((i = last.row - first.row - 1) > 0) { /* middle rows */
3344 ScrnRefresh(xw, first.row + 1, 0, i, MaxCols(screen), True);
3346 if (last.col > 0 && last.row <= screen->max_row) { /* last row */
3347 ScrnRefresh(xw, last.row, 0, 1, last.col, True);
3349 } else { /* do single row */
3350 ScrnRefresh(xw, first.row, first.col, 1, last.col - first.col, True);
3355 * Guaranteed that (cellc->row, cellc->col) <= (cell->row, cell->col), and that both points are valid
3356 * (may have cell->row = screen->max_row+1, cell->col = 0).
3359 SaltTextAway(XtermWidget xw,
3362 String * params, /* selections */
3363 Cardinal num_params)
3365 TScreen *screen = TScreenOf(xw);
3371 CELL first = *cellc;
3374 if (isSameRow(&first, &last) && first.col > last.col) {
3375 EXCHANGE(first.col, last.col, tmp);
3379 /* first we need to know how long the string is before we can save it */
3381 if (isSameRow(&last, &first)) {
3382 j = Length(screen, first.row, first.col, last.col);
3383 } else { /* two cases, cut is on same line, cut spans multiple lines */
3384 j += Length(screen, first.row, first.col, screen->max_col) + 1;
3385 for (i = first.row + 1; i < last.row; i++)
3386 j += Length(screen, i, 0, screen->max_col) + 1;
3388 j += Length(screen, last.row, 0, last.col);
3391 /* UTF-8 may require more space */
3392 if_OPT_WIDE_CHARS(screen, {
3396 /* now get some memory to save it in */
3398 if (screen->selection_size <= j) {
3399 if ((line = (Char *) malloc((size_t) j + 1)) == 0)
3400 SysError(ERROR_BMALLOC2);
3401 XtFree((char *) screen->selection_data);
3402 screen->selection_data = line;
3403 screen->selection_size = j + 1;
3405 line = screen->selection_data;
3412 line[j] = '\0'; /* make sure it is null terminated */
3413 lp = line; /* lp points to where to save the text */
3414 if (isSameRow(&last, &first)) {
3415 lp = SaveText(screen, last.row, first.col, last.col, lp, &eol);
3417 lp = SaveText(screen, first.row, first.col, screen->max_col, lp, &eol);
3419 *lp++ = '\n'; /* put in newline at end of line */
3420 for (i = first.row + 1; i < last.row; i++) {
3421 lp = SaveText(screen, i, 0, screen->max_col, lp, &eol);
3426 lp = SaveText(screen, last.row, 0, last.col, lp, &eol);
3428 *lp = '\0'; /* make sure we have end marked */
3430 TRACE(("Salted TEXT:%d:%s\n", (int) (lp - line),
3431 visibleChars(line, (unsigned) (lp - line))));
3433 screen->selection_length = (unsigned long) (lp - line);
3434 _OwnSelection(xw, params, num_params);
3439 ClearSelectionBuffer(TScreen * screen)
3441 screen->selection_length = 0;
3442 screen->base64_count = 0;
3446 AppendStrToSelectionBuffer(TScreen * screen, Char * text, size_t len)
3449 int j = (int) (screen->selection_length + len); /* New length */
3450 int k = j + (j >> 2) + 80; /* New size if we grow buffer: grow by ~50% */
3451 if (j + 1 >= screen->selection_size) {
3452 if (!screen->selection_length) {
3455 if ((line = (Char *) malloc((size_t) k)) == 0)
3456 SysError(ERROR_BMALLOC2);
3457 XtFree((char *) screen->selection_data);
3458 screen->selection_data = line;
3460 /* Realloc buffer */
3461 screen->selection_data = (Char *)
3462 realloc(screen->selection_data,
3464 if (screen->selection_data == 0)
3465 SysError(ERROR_BMALLOC2);
3467 screen->selection_size = k;
3469 if (screen->selection_data != 0) {
3470 memcpy(screen->selection_data + screen->selection_length, text, len);
3471 screen->selection_length += len;
3472 screen->selection_data[screen->selection_length] = 0;
3478 AppendToSelectionBuffer(TScreen * screen, unsigned c)
3483 /* Decode base64 character */
3484 if (c >= 'A' && c <= 'Z')
3486 else if (c >= 'a' && c <= 'z')
3488 else if (c >= '0' && c <= '9')
3497 /* Accumulate bytes */
3498 switch (screen->base64_count) {
3500 screen->base64_accu = six;
3501 screen->base64_count = 6;
3505 ch = CharOf((screen->base64_accu << 6) + six);
3506 screen->base64_count = 0;
3507 AppendStrToSelectionBuffer(screen, &ch, (size_t) 1);
3511 ch = CharOf((screen->base64_accu << 4) + (six >> 2));
3512 screen->base64_accu = (six & 0x3);
3513 screen->base64_count = 2;
3514 AppendStrToSelectionBuffer(screen, &ch, (size_t) 1);
3518 ch = CharOf((screen->base64_accu << 2) + (six >> 4));
3519 screen->base64_accu = (six & 0xF);
3520 screen->base64_count = 4;
3521 AppendStrToSelectionBuffer(screen, &ch, (size_t) 1);
3527 CompleteSelection(XtermWidget xw, String * args, Cardinal len)
3529 TScreen *screen = TScreenOf(xw);
3531 screen->base64_count = 0;
3532 screen->base64_accu = 0;
3533 _OwnSelection(xw, args, len);
3535 #endif /* OPT_PASTE64 */
3538 _ConvertSelectionHelper(Widget w,
3541 unsigned long *length,
3543 int (*conversion_function) (Display *,
3547 XICCEncodingStyle conversion_style)
3551 if ((xw = getXtermWidget(w)) != 0) {
3552 TScreen *screen = TScreenOf(xw);
3553 Display *dpy = XtDisplay(w);
3554 XTextProperty textprop;
3555 char *the_data = (char *) screen->selection_data;
3557 if (conversion_function(dpy, &the_data, 1,
3559 &textprop) >= Success) {
3560 *value = (XtPointer) textprop.value;
3561 *length = textprop.nitems;
3562 *type = textprop.encoding;
3563 *format = textprop.format;
3571 SaveConvertedLength(XtPointer *target, unsigned long source)
3573 Boolean result = False;
3575 *target = XtMalloc(4);
3578 if (sizeof(unsigned long) == 4) {
3579 *(unsigned long *) *target = source;
3580 } else if (sizeof(unsigned) == 4) {
3581 *(unsigned *) *target = (unsigned) source;
3582 } else if (sizeof(unsigned short) == 4) {
3583 *(unsigned short *) *target = (unsigned short) source;
3585 /* FIXME - does this depend on byte-order? */
3586 unsigned long temp = source;
3587 memcpy((char *) *target,
3588 ((char *) &temp) + sizeof(temp) - 4,
3596 ConvertSelection(Widget w,
3601 unsigned long *length,
3604 Display *dpy = XtDisplay(w);
3606 Bool result = False;
3610 if ((xw = getXtermWidget(w)) == 0)
3613 screen = TScreenOf(xw);
3615 if (screen->selection_data == NULL)
3616 return False; /* can this happen? */
3618 TRACE(("ConvertSelection %s\n",
3619 visibleSelectionTarget(dpy, *target)));
3621 if (*target == XA_TARGETS(dpy)) {
3625 XPointer std_return = 0;
3626 unsigned long std_length;
3628 if (XmuConvertStandardSelection(w, screen->selection_time, selection,
3629 target, type, &std_return,
3630 &std_length, format)) {
3631 Atom *my_targets = _SelectionTargets(w);
3633 TRACE(("XmuConvertStandardSelection - success\n"));
3634 std_targets = (Atom *) (void *) (std_return);
3635 *length = std_length + 6;
3637 targetP = TypeXtMallocN(Atom, *length);
3640 *value = (XtPointer) targetP;
3642 while (*my_targets != None) {
3643 *targetP++ = *my_targets++;
3645 *targetP++ = XA_LENGTH(dpy);
3646 *targetP++ = XA_LIST_LENGTH(dpy);
3648 *length = std_length + (unsigned long) (targetP - allocP);
3650 memcpy(targetP, std_targets, sizeof(Atom) * std_length);
3651 XtFree((char *) std_targets);
3656 TRACE(("XmuConvertStandardSelection - failed\n"));
3660 else if (screen->wide_chars && *target == XA_STRING) {
3662 _ConvertSelectionHelper(w,
3663 type, value, length, format,
3664 Xutf8TextListToTextProperty,
3666 TRACE(("...Xutf8TextListToTextProperty:%d\n", result));
3667 } else if (screen->wide_chars && *target == XA_UTF8_STRING(dpy)) {
3669 _ConvertSelectionHelper(w,
3670 type, value, length, format,
3671 Xutf8TextListToTextProperty,
3673 TRACE(("...Xutf8TextListToTextProperty:%d\n", result));
3674 } else if (screen->wide_chars && *target == XA_TEXT(dpy)) {
3676 _ConvertSelectionHelper(w,
3677 type, value, length, format,
3678 Xutf8TextListToTextProperty,
3680 TRACE(("...Xutf8TextListToTextProperty:%d\n", result));
3681 } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(dpy)) {
3683 _ConvertSelectionHelper(w,
3684 type, value, length, format,
3685 Xutf8TextListToTextProperty,
3686 XCompoundTextStyle);
3687 TRACE(("...Xutf8TextListToTextProperty:%d\n", result));
3691 else if (*target == XA_STRING) { /* not wide_chars */
3692 /* We can only reach this point if the selection requestor
3693 requested STRING before any of TEXT, COMPOUND_TEXT or
3694 UTF8_STRING. We therefore assume that the requestor is not
3695 properly internationalised, and dump raw eight-bit data
3696 with no conversion into the selection. Yes, this breaks
3697 the ICCCM in non-Latin-1 locales. */
3699 *value = (XtPointer) screen->selection_data;
3700 *length = screen->selection_length;
3703 TRACE(("...raw 8-bit data:%d\n", result));
3704 } else if (*target == XA_TEXT(dpy)) { /* not wide_chars */
3706 _ConvertSelectionHelper(w,
3707 type, value, length, format,
3708 XmbTextListToTextProperty,
3710 TRACE(("...XmbTextListToTextProperty(StdICC):%d\n", result));
3711 } else if (*target == XA_COMPOUND_TEXT(dpy)) { /* not wide_chars */
3713 _ConvertSelectionHelper(w,
3714 type, value, length, format,
3715 XmbTextListToTextProperty,
3716 XCompoundTextStyle);
3717 TRACE(("...XmbTextListToTextProperty(Compound):%d\n", result));
3719 #ifdef X_HAVE_UTF8_STRING
3720 else if (*target == XA_UTF8_STRING(dpy)) { /* not wide_chars */
3722 _ConvertSelectionHelper(w,
3723 type, value, length, format,
3724 XmbTextListToTextProperty,
3726 TRACE(("...XmbTextListToTextProperty(UTF8):%d\n", result));
3729 else if (*target == XA_LIST_LENGTH(dpy)) {
3730 result = SaveConvertedLength(value, (unsigned long) 1);
3734 TRACE(("...list of values:%d\n", result));
3735 } else if (*target == XA_LENGTH(dpy)) {
3736 /* This value is wrong if we have UTF-8 text */
3737 result = SaveConvertedLength(value, screen->selection_length);
3741 TRACE(("...list of values:%d\n", result));
3742 } else if (XmuConvertStandardSelection(w,
3743 screen->selection_time, selection,
3744 target, type, (XPointer *) value,
3747 TRACE(("...XmuConvertStandardSelection:%d\n", result));
3751 return (Boolean) result;
3755 LoseSelection(Widget w, Atom * selection)
3763 if ((xw = getXtermWidget(w)) == 0)
3766 screen = TScreenOf(xw);
3767 for (i = 0, atomP = screen->selection_atoms;
3768 i < screen->selection_count; i++, atomP++) {
3769 if (*selection == *atomP)
3771 if (CutBuffer(*atomP) >= 0) {
3776 for (i = screen->selection_count; i; i--) {
3777 if (screen->selection_atoms[i - 1] != 0)
3780 screen->selection_count = i;
3782 for (i = 0, atomP = screen->selection_atoms;
3783 i < screen->selection_count; i++, atomP++) {
3784 if (*atomP == (Atom) 0) {
3785 *atomP = screen->selection_atoms[--screen->selection_count];
3789 if (screen->selection_count == 0)
3790 TrackText(xw, &zeroCELL, &zeroCELL);
3795 SelectionDone(Widget w GCC_UNUSED,
3796 Atom * selection GCC_UNUSED,
3797 Atom * target GCC_UNUSED)
3799 /* empty proc so Intrinsics know we want to keep storage */
3803 _OwnSelection(XtermWidget xw,
3804 String * selections,
3807 TScreen *screen = TScreenOf(xw);
3808 Atom *atoms = screen->selection_atoms;
3810 Bool have_selection = False;
3814 if (screen->selection_length == 0)
3817 TRACE(("_OwnSelection count %d\n", count));
3818 selections = MapSelections(xw, selections, count);
3820 if (count > screen->sel_atoms_size) {
3821 XtFree((char *) atoms);
3822 atoms = TypeXtMallocN(Atom, count);
3823 screen->selection_atoms = atoms;
3824 screen->sel_atoms_size = count;
3826 XmuInternStrings(XtDisplay((Widget) xw), selections, count, atoms);
3827 for (i = 0; i < count; i++) {
3828 int cutbuffer = CutBuffer(atoms[i]);
3829 if (cutbuffer >= 0) {
3830 unsigned long limit =
3831 (unsigned long) (4 * XMaxRequestSize(XtDisplay((Widget) xw)) - 32);
3832 if (screen->selection_length > limit) {
3833 TRACE(("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n",
3834 screen->selection_length, cutbuffer));
3836 "%s: selection too big (%lu bytes), not storing in CUT_BUFFER%d\n",
3837 xterm_name, screen->selection_length, cutbuffer);
3839 /* This used to just use the UTF-8 data, which was totally
3840 * broken as not even the corresponding paste code in Xterm
3841 * understood this! So now it converts to Latin1 first.
3842 * Robert Brady, 2000-09-05
3844 unsigned long length = screen->selection_length;
3845 Char *data = screen->selection_data;
3846 if_OPT_WIDE_CHARS((screen), {
3847 data = UTF8toLatin1(screen, data, length, &length);
3849 TRACE(("XStoreBuffer(%d)\n", cutbuffer));
3850 XStoreBuffer(XtDisplay((Widget) xw),
3855 } else if (!screen->replyToEmacs) {
3857 XtOwnSelection((Widget) xw, atoms[i],
3858 screen->selection_time,
3859 ConvertSelection, LoseSelection, SelectionDone);
3862 if (!screen->replyToEmacs)
3863 screen->selection_count = count;
3864 if (!have_selection)
3865 TrackText(xw, &zeroCELL, &zeroCELL);
3869 ResetSelectionState(TScreen * screen)
3871 screen->selection_count = 0;
3872 screen->startH = zeroCELL;
3873 screen->endH = zeroCELL;
3877 DisownSelection(XtermWidget xw)
3879 TScreen *screen = TScreenOf(xw);
3880 Atom *atoms = screen->selection_atoms;
3881 Cardinal count = screen->selection_count;
3884 TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n",
3891 for (i = 0; i < count; i++) {
3892 int cutbuffer = CutBuffer(atoms[i]);
3893 if (cutbuffer < 0) {
3894 XtDisownSelection((Widget) xw, atoms[i],
3895 screen->selection_time);
3899 * If none of the callbacks via XtDisownSelection() reset highlighting
3902 if (ScrnHaveSelection(screen)) {
3903 /* save data which will be reset */
3904 CELL first = screen->startH;
3905 CELL last = screen->endH;
3907 ResetSelectionState(screen);
3908 ReHiliteText(xw, &first, &last);
3910 ResetSelectionState(screen);
3915 UnhiliteSelection(XtermWidget xw)
3917 TScreen *screen = TScreenOf(xw);
3919 if (ScrnHaveSelection(screen)) {
3920 CELL first = screen->startH;
3921 CELL last = screen->endH;
3923 screen->startH = zeroCELL;
3924 screen->endH = zeroCELL;
3925 ReHiliteText(xw, &first, &last);
3929 /* returns number of chars in line from scol to ecol out */
3932 Length(TScreen * screen,
3937 LineData *ld = GET_LINEDATA(screen, row);
3938 int lastcol = LastTextCol(screen, ld, row);
3942 return (ecol - scol + 1);
3945 /* copies text into line, preallocated */
3947 SaveText(TScreen * screen,
3951 Char * lp, /* pointer to where to put the text */
3959 unsigned previous = 0;
3962 ld = GET_LINEDATA(screen, row);
3963 i = Length(screen, row, scol, ecol);
3966 if (CSET_DOUBLE(GetLineDblCS(ld))) {
3967 scol = (scol + 0) / 2;
3968 ecol = (ecol + 1) / 2;
3971 *eol = !LineTstWrapped(ld);
3972 for (i = scol; i < ecol; i++) {
3973 assert(i < ld->lineSize);
3974 c = E2A(ld->charData[i]);
3976 /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a
3979 if (c == HIDDEN_CHAR && isWide((int) previous)) {
3981 /* Combining characters attached to double-width characters
3982 are in memory attached to the HIDDEN_CHAR */
3983 if_OPT_WIDE_CHARS(screen, {
3984 if (screen->utf8_mode != uFalse) {
3987 for_each_combData(off, ld) {
3988 ch = ld->combData[off][i];
3991 lp = convertToUTF8(lp, ch);
3998 if (screen->utf8_mode != uFalse) {
3999 lp = convertToUTF8(lp, (c != 0) ? c : ' ');
4000 if_OPT_WIDE_CHARS(screen, {
4003 for_each_combData(off, ld) {
4004 ch = ld->combData[off][i];
4007 lp = convertToUTF8(lp, ch);
4015 } else if (c < E2A(' ')) {
4017 } else if (c == 0x7f) {
4020 *lp++ = CharOf(A2E(c));
4027 * If requested, trim trailing blanks from selected lines. Do not do this
4028 * if the line is wrapped.
4030 if (!*eol || !screen->trim_selection)
4036 /* 32 + following 7-bit word:
4038 1:0 Button no: 0, 1, 2. 3=release.
4042 5 set for motion notify
4046 /* Position: 32 - 255. */
4048 BtnCode(XButtonEvent * event, int button)
4050 int result = (int) (32 + (KeyState(event->state) << 2));
4052 if (button < 0 || button > 5) {
4057 if (event->type == MotionNotify)
4065 EmitButtonCode(TScreen * screen, Char * line, unsigned count, XButtonEvent * event)
4067 int value = BtnCode(event, screen->mouse_button);
4069 if (!screen->ext_mode_mouse || value < 128) {
4070 line[count++] = CharOf(value);
4072 line[count++] = CharOf(0xC0 + (value >> 6));
4073 line[count++] = CharOf(0x80 + (value & 0x3F));
4079 EditorButton(XtermWidget xw, XButtonEvent * event)
4081 TScreen *screen = TScreenOf(xw);
4082 int pty = screen->respond;
4083 int mouse_limit = screen->ext_mode_mouse ? EXT_MOUSE_LIMIT : MOUSE_LIMIT;
4088 Boolean changed = True;
4090 /* If button event, get button # adjusted for DEC compatibility */
4091 button = (int) (event->button - 1);
4095 /* Compute character position of mouse pointer */
4096 row = (event->y - screen->border) / FontHeight(screen);
4097 col = (event->x - OriginX(screen)) / FontWidth(screen);
4099 /* Limit to screen dimensions */
4102 else if (row > screen->max_row)
4103 row = screen->max_row;
4107 else if (col > screen->max_col)
4108 col = screen->max_col;
4110 /* Limit to representable mouse dimensions */
4111 if (row > mouse_limit)
4113 if (col > mouse_limit)
4116 /* Build key sequence starting with \E[M */
4117 if (screen->control_eight_bits) {
4118 line[count++] = ANSI_CSI;
4120 line[count++] = ANSI_ESC;
4121 line[count++] = '[';
4123 #if OPT_SCO_FUNC_KEYS
4124 if (xw->keyboard.type == keyboardIsSCO) {
4126 * SCO function key F1 is \E[M, which would conflict with xterm's
4129 line[count++] = '>';
4132 line[count++] = 'M';
4134 /* Add event code to key sequence */
4135 if (screen->send_mouse_pos == X10_MOUSE) {
4136 line[count++] = CharOf(' ' + button);
4138 /* Button-Motion events */
4139 switch (event->type) {
4141 screen->mouse_button = button;
4142 count = EmitButtonCode(screen, line, count, event);
4146 * Wheel mouse interface generates release-events for buttons
4147 * 4 and 5, coded here as 3 and 4 respectively. We change the
4148 * release for buttons 1..3 to a -1.
4152 screen->mouse_button = button;
4153 count = EmitButtonCode(screen, line, count, event);
4156 /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion
4157 * events only if character cell has changed.
4159 if ((row == screen->mouse_row)
4160 && (col == screen->mouse_col)) {
4163 count = EmitButtonCode(screen, line, count, event);
4173 screen->mouse_row = row;
4174 screen->mouse_col = col;
4176 TRACE(("mouse at %d,%d button+mask = %#x\n", row, col, line[count - 1]));
4178 /* Add pointer position to key sequence */
4179 count = EmitMousePosition(screen, line, count, col);
4180 count = EmitMousePosition(screen, line, count, row);
4182 /* Transmit key sequence to process running under xterm */
4183 v_write(pty, line, count);
4190 SendFocusButton(XtermWidget xw, XFocusChangeEvent * event)
4192 TScreen *screen = TScreenOf(xw);
4194 if (screen->send_focus_pos) {
4197 memset(&reply, 0, sizeof(reply));
4198 reply.a_type = ANSI_CSI;
4200 #if OPT_SCO_FUNC_KEYS
4201 if (xw->keyboard.type == keyboardIsSCO) {
4202 reply.a_pintro = '>';
4205 reply.a_final = CharOf((event->type == FocusIn) ? 'I' : 'O');
4206 unparseseq(xw, &reply);
4210 #endif /* OPT_FOCUS_EVENT */