aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/programs/xterm/button.c
diff options
context:
space:
mode:
authorReinhard Tartler <siretart@tauware.de>2011-10-10 17:43:39 +0200
committerReinhard Tartler <siretart@tauware.de>2011-10-10 17:43:39 +0200
commitf4092abdf94af6a99aff944d6264bc1284e8bdd4 (patch)
tree2ac1c9cc16ceb93edb2c4382c088dac5aeafdf0f /nx-X11/programs/xterm/button.c
parenta840692edc9c6d19cd7c057f68e39c7d95eb767d (diff)
downloadnx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.tar.gz
nx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.tar.bz2
nx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.zip
Imported nx-X11-3.1.0-1.tar.gznx-X11/3.1.0-1
Summary: Imported nx-X11-3.1.0-1.tar.gz Keywords: Imported nx-X11-3.1.0-1.tar.gz into Git repository
Diffstat (limited to 'nx-X11/programs/xterm/button.c')
-rw-r--r--nx-X11/programs/xterm/button.c3284
1 files changed, 3284 insertions, 0 deletions
diff --git a/nx-X11/programs/xterm/button.c b/nx-X11/programs/xterm/button.c
new file mode 100644
index 000000000..d8d0b32b3
--- /dev/null
+++ b/nx-X11/programs/xterm/button.c
@@ -0,0 +1,3284 @@
+/* $XTermId: button.c,v 1.197 2005/11/03 13:17:27 tom Exp $ */
+
+/* $Xorg: button.c,v 1.3 2000/08/17 19:55:08 cpqbld Exp $ */
+/*
+ * Copyright 1999-2004,2005 by Thomas E. Dickey
+ *
+ * All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name(s) of the above copyright
+ * holders shall not be used in advertising or otherwise to promote the
+ * sale, use or other dealings in this Software without prior written
+ * authorization.
+ *
+ *
+ * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Digital Equipment
+ * Corporation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ *
+ *
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+/* $XFree86: xc/programs/xterm/button.c,v 3.82 2005/11/03 13:17:27 dickey Exp $ */
+
+/*
+button.c Handles button events in the terminal emulator.
+ does cut/paste operations, change modes via menu,
+ passes button events through to some applications.
+ J. Gettys.
+*/
+
+#include <xterm.h>
+
+#include <stdio.h>
+
+#include <X11/Xatom.h>
+#include <X11/Xmu/Atoms.h>
+#include <X11/Xmu/StdSel.h>
+
+#include <xutf8.h>
+
+#include <data.h>
+#include <error.h>
+#include <menu.h>
+#include <xcharmouse.h>
+#include <charclass.h>
+
+#if OPT_WIDE_CHARS
+#include <wcwidth.h>
+#else
+#define CharacterClass(value) \
+ charClass[value & ((sizeof(charClass)/sizeof(charClass[0]))-1)]
+#endif
+
+#define XTERM_CELL(row,col) getXtermCell(screen, row + screen->topline, col)
+#define XTERM_CELL_C1(row,col) getXtermCellComb1(screen, row + screen->topline, col)
+#define XTERM_CELL_C2(row,col) getXtermCellComb2(screen, row + screen->topline, col)
+
+ /*
+ * We reserve shift modifier for cut/paste operations. In principle we
+ * can pass through control and meta modifiers, but in practice, the
+ * popup menu uses control, and the window manager is likely to use meta,
+ * so those events are not delivered to SendMousePosition.
+ */
+#define OurModifiers (ShiftMask | ControlMask | Mod1Mask)
+#define AllModifiers (ShiftMask | LockMask | ControlMask | Mod1Mask | \
+ Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)
+
+#define KeyModifiers (event->xbutton.state & OurModifiers)
+
+#define KeyState(x) (((x) & (ShiftMask|ControlMask)) + (((x) & Mod1Mask) ? 2 : 0))
+ /* adds together the bits:
+ shift key -> 1
+ meta key -> 2
+ control key -> 4 */
+
+#define Coordinate(r,c) ((r) * MaxCols(&(term->screen)) + (c))
+
+#if OPT_DEC_LOCATOR
+static ANSI reply;
+#endif
+
+/* Selection/extension variables */
+
+/* Raw char position where the selection started */
+static int rawRow, rawCol;
+
+/* Selected area before CHAR, WORD, LINE selectUnit processing */
+static int startRRow, startRCol, endRRow, endRCol = 0;
+
+/* Selected area after CHAR, WORD, LINE selectUnit processing */
+static int startSRow, startSCol, endSRow, endSCol = 0;
+
+/* Valid rows for selection clipping */
+static int firstValidRow, lastValidRow;
+
+/* Start, end of extension */
+static int startERow, startECol, endERow, endECol;
+
+/* Saved values of raw selection for extend to restore to */
+static int saveStartRRow, saveStartRCol, saveEndRRow, saveEndRCol;
+
+/* Saved value of WORD selection for LINE processing to restore to */
+static int saveStartWRow, saveStartWCol;
+
+/* Multi-click handling */
+static int numberOfClicks = 0;
+static Time lastButtonUpTime = 0;
+
+#if OPT_READLINE
+static Time lastButtonDownTime = 0;
+static int ExtendingSelection = 0;
+static Time lastButton3UpTime = 0;
+static Time lastButton3DoubleDownTime = 0;
+static int lastButton3row, lastButton3col; /* At the release time */
+#endif /* OPT_READLINE */
+
+typedef int SelectUnit;
+
+#define SELECTCHAR 0
+#define SELECTWORD 1
+#define SELECTLINE 2
+#define NSELECTUNITS 3
+static SelectUnit selectUnit;
+
+/* Send emacs escape code when done selecting or extending? */
+static int replyToEmacs;
+
+static Char *SaveText(TScreen * screen, int row, int scol, int ecol, Char *
+ lp, int *eol);
+static int Length(TScreen * screen, int row, int scol, int ecol);
+static void ComputeSelect(int startRow, int startCol, int endRow, int
+ endCol, Bool extend);
+static void EditorButton(XButtonEvent * event);
+static void EndExtend(Widget w, XEvent * event, String * params, Cardinal
+ num_params, Bool use_cursor_loc);
+static void ExtendExtend(int row, int col);
+static void PointToRowCol(int y, int x, int *r, int *c);
+static void ReHiliteText(int frow, int fcol, int trow, int tcol);
+static void SaltTextAway(int crow, int ccol, int row, int col, String *
+ params, Cardinal num_params);
+static void SelectSet(Widget w, XEvent * event, String * params, Cardinal num_params);
+static void SelectionReceived PROTO_XT_SEL_CB_ARGS;
+static void StartSelect(int startrow, int startcol);
+static void TrackDown(XButtonEvent * event);
+static void _OwnSelection(XtermWidget termw, String * selections, Cardinal count);
+static void do_select_end(Widget w, XEvent * event, String * params,
+ Cardinal *num_params, Bool use_cursor_loc);
+
+Bool
+SendMousePosition(Widget w, XEvent * event)
+{
+ TScreen *screen;
+
+ if (!IsXtermWidget(w))
+ return False;
+
+ screen = &((XtermWidget) w)->screen;
+
+ /* If send_mouse_pos mode isn't on, we shouldn't be here */
+ if (screen->send_mouse_pos == MOUSE_OFF)
+ return False;
+
+#if OPT_DEC_LOCATOR
+ if (screen->send_mouse_pos == DEC_LOCATOR) {
+ return (SendLocatorPosition(w, event));
+ }
+#endif /* OPT_DEC_LOCATOR */
+
+ /* Make sure the event is an appropriate type */
+ if ((screen->send_mouse_pos != BTN_EVENT_MOUSE)
+ && (screen->send_mouse_pos != ANY_EVENT_MOUSE)
+ && event->type != ButtonPress
+ && event->type != ButtonRelease)
+ return False;
+
+ switch (screen->send_mouse_pos) {
+ case X10_MOUSE: /* X10 compatibility sequences */
+
+ if (KeyModifiers == 0) {
+ if (event->type == ButtonPress)
+ EditorButton((XButtonEvent *) event);
+ return True;
+ }
+ return False;
+
+ case VT200_HIGHLIGHT_MOUSE: /* DEC vt200 hilite tracking */
+ if (event->type == ButtonPress &&
+ KeyModifiers == 0 &&
+ event->xbutton.button == Button1) {
+ TrackDown((XButtonEvent *) event);
+ return True;
+ }
+ if (KeyModifiers == 0 || KeyModifiers == ControlMask) {
+ EditorButton((XButtonEvent *) event);
+ return True;
+ }
+ return False;
+
+ case VT200_MOUSE: /* DEC vt200 compatible */
+
+ /* xterm extension for motion reporting. June 1998 */
+ /* EditorButton() will distinguish between the modes */
+ case BTN_EVENT_MOUSE:
+ case ANY_EVENT_MOUSE:
+ if (KeyModifiers == 0 || KeyModifiers == ControlMask) {
+ EditorButton((XButtonEvent *) event);
+ return True;
+ }
+ return False;
+
+ default:
+ return False;
+ }
+}
+
+#if OPT_DEC_LOCATOR
+
+#define LocatorCoords( row, col, x, y, oor ) \
+ if( screen->locator_pixels ) { \
+ (oor)=False; (row) = (y)+1; (col) = (x)+1; \
+ /* Limit to screen dimensions */ \
+ if ((row) < 1) (row) = 1,(oor)=True; \
+ else if ((row) > screen->border*2+Height(screen)) \
+ (row) = screen->border*2+Height(screen),(oor)=True; \
+ if ((col) < 1) (col) = 1,(oor)=True; \
+ else if ((col) > OriginX(screen)*2+Width(screen)) \
+ (col) = OriginX(screen)*2+Width(screen),(oor)=True; \
+ } else { \
+ (oor)=False; \
+ /* Compute character position of mouse pointer */ \
+ (row) = ((y) - screen->border) / FontHeight(screen); \
+ (col) = ((x) - OriginX(screen)) / FontWidth(screen); \
+ /* Limit to screen dimensions */ \
+ if ((row) < 0) (row) = 0,(oor)=True; \
+ else if ((row) > screen->max_row) \
+ (row) = screen->max_row,(oor)=True; \
+ if ((col) < 0) (col) = 0,(oor)=True; \
+ else if ((col) > screen->max_col) \
+ (col) = screen->max_col,(oor)=True; \
+ (row)++; (col)++; \
+ }
+
+Bool
+SendLocatorPosition(Widget w, XEvent * event)
+{
+ TScreen *screen = &((XtermWidget) w)->screen;
+ int row, col;
+ Bool oor;
+ int button;
+ int state;
+
+ /* Make sure the event is an appropriate type */
+ if ((event->type != ButtonPress &&
+ event->type != ButtonRelease &&
+ !screen->loc_filter) ||
+ (KeyModifiers != 0 && KeyModifiers != ControlMask))
+ return (False);
+
+ if ((event->type == ButtonPress &&
+ !(screen->locator_events & LOC_BTNS_DN)) ||
+ (event->type == ButtonRelease &&
+ !(screen->locator_events & LOC_BTNS_UP)))
+ return (True);
+
+ if (event->type == MotionNotify) {
+ CheckLocatorPosition(w, event);
+ return (True);
+ }
+
+ /* get button # */
+ button = event->xbutton.button - 1;
+
+ LocatorCoords(row, col, event->xbutton.x, event->xbutton.y, oor);
+
+ /*
+ * DECterm mouse:
+ *
+ * ESCAPE '[' event ; mask ; row ; column '&' 'w'
+ */
+ reply.a_type = CSI;
+
+ if (oor) {
+ reply.a_nparam = 1;
+ reply.a_param[0] = 0; /* Event - 0 = locator unavailable */
+ reply.a_inters = '&';
+ reply.a_final = 'w';
+ unparseseq(&reply, screen->respond);
+
+ if (screen->locator_reset) {
+ MotionOff(screen, term);
+ screen->send_mouse_pos = MOUSE_OFF;
+ }
+ return (True);
+ }
+
+ /*
+ * event:
+ * 1 no buttons
+ * 2 left button down
+ * 3 left button up
+ * 4 middle button down
+ * 5 middle button up
+ * 6 right button down
+ * 7 right button up
+ * 8 M4 down
+ * 9 M4 up
+ */
+ reply.a_nparam = 4;
+ switch (event->type) {
+ case ButtonPress:
+ reply.a_param[0] = 2 + (button << 1);
+ break;
+ case ButtonRelease:
+ reply.a_param[0] = 3 + (button << 1);
+ break;
+ default:
+ return (True);
+ }
+ /*
+ * mask:
+ * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
+ * M4 down left down middle down right down
+ *
+ * Notice that Button1 (left) and Button3 (right) are swapped in the mask.
+ * Also, mask should be the state after the button press/release,
+ * X provides the state not including the button press/release.
+ */
+ state = (event->xbutton.state
+ & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8;
+ state ^= 1 << button; /* update mask to "after" state */
+ state = (state & ~(4 | 1)) | ((state & 1) ? 4 : 0) | ((state & 4) ? 1 : 0); /* swap Button1 & Button3 */
+
+ reply.a_param[1] = state;
+ reply.a_param[2] = row;
+ reply.a_param[3] = col;
+ reply.a_inters = '&';
+ reply.a_final = 'w';
+
+ unparseseq(&reply, screen->respond);
+
+ if (screen->locator_reset) {
+ MotionOff(screen, term);
+ screen->send_mouse_pos = MOUSE_OFF;
+ }
+
+ /*
+ * DECterm turns the Locator off if a button is pressed while a filter rectangle
+ * is active. This might be a bug, but I don't know, so I'll emulate it anyways.
+ */
+ if (screen->loc_filter) {
+ screen->send_mouse_pos = MOUSE_OFF;
+ screen->loc_filter = False;
+ screen->locator_events = 0;
+ MotionOff(screen, term);
+ }
+
+ return (True);
+}
+
+/*
+ * mask:
+ * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
+ * M4 down left down middle down right down
+ *
+ * Button1 (left) and Button3 (right) are swapped in the mask relative to X.
+ */
+#define ButtonState(state, mask) \
+{ (state) = ((mask) & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8; \
+ /* swap Button1 & Button3 */ \
+ (state) = ((state) & ~(4|1)) | (((state)&1)?4:0) | (((state)&4)?1:0); \
+}
+
+void
+GetLocatorPosition(XtermWidget w)
+{
+ TScreen *screen = &w->screen;
+ Window root, child;
+ int rx, ry, x, y;
+ unsigned int mask;
+ int row = 0, col = 0;
+ Bool oor = False;
+ Bool ret = False;
+ int state;
+
+ /*
+ * DECterm turns the Locator off if the position is requested while a filter rectangle
+ * is active. This might be a bug, but I don't know, so I'll emulate it anyways.
+ */
+ if (screen->loc_filter) {
+ screen->send_mouse_pos = MOUSE_OFF;
+ screen->loc_filter = False;
+ screen->locator_events = 0;
+ MotionOff(screen, term);
+ }
+
+ reply.a_type = CSI;
+
+ if (screen->send_mouse_pos == DEC_LOCATOR) {
+ ret = XQueryPointer(screen->display, VWindow(screen), &root,
+ &child, &rx, &ry, &x, &y, &mask);
+ if (ret) {
+ LocatorCoords(row, col, x, y, oor);
+ }
+ }
+ if (ret == False || oor) {
+ reply.a_nparam = 1;
+ reply.a_param[0] = 0; /* Event - 0 = locator unavailable */
+ reply.a_inters = '&';
+ reply.a_final = 'w';
+ unparseseq(&reply, screen->respond);
+
+ if (screen->locator_reset) {
+ MotionOff(screen, term);
+ screen->send_mouse_pos = MOUSE_OFF;
+ }
+ return;
+ }
+
+ ButtonState(state, mask);
+
+ reply.a_nparam = 4;
+ reply.a_param[0] = 1; /* Event - 1 = response to locator request */
+ reply.a_param[1] = state;
+ reply.a_param[2] = row;
+ reply.a_param[3] = col;
+ reply.a_inters = '&';
+ reply.a_final = 'w';
+ unparseseq(&reply, screen->respond);
+
+ if (screen->locator_reset) {
+ MotionOff(screen, term);
+ screen->send_mouse_pos = MOUSE_OFF;
+ }
+}
+
+void
+InitLocatorFilter(XtermWidget w)
+{
+ TScreen *screen = &w->screen;
+ Window root, child;
+ int rx, ry, x, y;
+ unsigned int mask;
+ int row = 0, col = 0;
+ Bool oor = 0;
+ Bool ret;
+ int state;
+
+ ret = XQueryPointer(screen->display, VWindow(screen),
+ &root, &child, &rx, &ry, &x, &y, &mask);
+ if (ret) {
+ LocatorCoords(row, col, x, y, oor);
+ }
+ if (ret == False || oor) {
+ /* Locator is unavailable */
+
+ if (screen->loc_filter_top != LOC_FILTER_POS ||
+ screen->loc_filter_left != LOC_FILTER_POS ||
+ screen->loc_filter_bottom != LOC_FILTER_POS ||
+ screen->loc_filter_right != LOC_FILTER_POS) {
+ /*
+ * If any explicit coordinates were received,
+ * report immediately with no coordinates.
+ */
+ reply.a_type = CSI;
+ reply.a_nparam = 1;
+ reply.a_param[0] = 0; /* Event - 0 = locator unavailable */
+ reply.a_inters = '&';
+ reply.a_final = 'w';
+ unparseseq(&reply, screen->respond);
+
+ if (screen->locator_reset) {
+ MotionOff(screen, term);
+ screen->send_mouse_pos = MOUSE_OFF;
+ }
+ } else {
+ /*
+ * No explicit coordinates were received, and the pointer is
+ * unavailable. Report when the pointer re-enters the window.
+ */
+ screen->loc_filter = True;
+ MotionOn(screen, term);
+ }
+ return;
+ }
+
+ /*
+ * Adjust rectangle coordinates:
+ * 1. Replace "LOC_FILTER_POS" with current coordinates
+ * 2. Limit coordinates to screen size
+ * 3. make sure top and left are less than bottom and right, resp.
+ */
+ if (screen->locator_pixels) {
+ rx = OriginX(screen) * 2 + Width(screen);
+ ry = screen->border * 2 + Height(screen);
+ } else {
+ rx = screen->max_col;
+ ry = screen->max_row;
+ }
+
+#define Adjust( coord, def, max ) \
+ if( (coord) == LOC_FILTER_POS ) (coord) = (def); \
+ else if ((coord) < 1) (coord) = 1; \
+ else if ((coord) > (max)) (coord) = (max)
+
+ Adjust(screen->loc_filter_top, row, ry);
+ Adjust(screen->loc_filter_left, col, rx);
+ Adjust(screen->loc_filter_bottom, row, ry);
+ Adjust(screen->loc_filter_right, col, rx);
+
+ if (screen->loc_filter_top > screen->loc_filter_bottom) {
+ ry = screen->loc_filter_top;
+ screen->loc_filter_top = screen->loc_filter_bottom;
+ screen->loc_filter_bottom = ry;
+ }
+
+ if (screen->loc_filter_left > screen->loc_filter_right) {
+ rx = screen->loc_filter_left;
+ screen->loc_filter_left = screen->loc_filter_right;
+ screen->loc_filter_right = rx;
+ }
+
+ if ((col < screen->loc_filter_left) ||
+ (col > screen->loc_filter_right) ||
+ (row < screen->loc_filter_top) ||
+ (row > screen->loc_filter_bottom)) {
+ /* Pointer is already outside the rectangle - report immediately */
+ ButtonState(state, mask);
+
+ reply.a_type = CSI;
+ reply.a_nparam = 4;
+ reply.a_param[0] = 10; /* Event - 10 = locator outside filter */
+ reply.a_param[1] = state;
+ reply.a_param[2] = row;
+ reply.a_param[3] = col;
+ reply.a_inters = '&';
+ reply.a_final = 'w';
+ unparseseq(&reply, screen->respond);
+
+ if (screen->locator_reset) {
+ MotionOff(screen, term);
+ screen->send_mouse_pos = MOUSE_OFF;
+ }
+ return;
+ }
+
+ /*
+ * Rectangle is set up. Allow pointer tracking
+ * to detect if the mouse leaves the rectangle.
+ */
+ screen->loc_filter = True;
+ MotionOn(screen, term);
+}
+
+void
+CheckLocatorPosition(Widget w, XEvent * event)
+{
+ TScreen *screen = &((XtermWidget) w)->screen;
+ int row, col;
+ Bool oor;
+ int state;
+
+ LocatorCoords(row, col, event->xbutton.x, event->xbutton.y, oor);
+
+ /*
+ * Send report if the pointer left the filter rectangle, if
+ * the pointer left the window, or if the filter rectangle
+ * had no coordinates and the pointer re-entered the window.
+ */
+ if (oor || (screen->loc_filter_top == LOC_FILTER_POS) ||
+ (col < screen->loc_filter_left) ||
+ (col > screen->loc_filter_right) ||
+ (row < screen->loc_filter_top) ||
+ (row > screen->loc_filter_bottom)) {
+ /* Filter triggered - disable it */
+ screen->loc_filter = False;
+ MotionOff(screen, term);
+
+ reply.a_type = CSI;
+ if (oor) {
+ reply.a_nparam = 1;
+ reply.a_param[0] = 0; /* Event - 0 = locator unavailable */
+ } else {
+ ButtonState(state, event->xbutton.state);
+
+ reply.a_nparam = 4;
+ reply.a_param[0] = 10; /* Event - 10 = locator outside filter */
+ reply.a_param[1] = state;
+ reply.a_param[2] = row;
+ reply.a_param[3] = col;
+ }
+
+ reply.a_inters = '&';
+ reply.a_final = 'w';
+ unparseseq(&reply, screen->respond);
+
+ if (screen->locator_reset) {
+ MotionOff(screen, term);
+ screen->send_mouse_pos = MOUSE_OFF;
+ }
+ }
+}
+#endif /* OPT_DEC_LOCATOR */
+
+#if OPT_READLINE
+static int
+isClick1_clean(XEvent * event)
+{
+ TScreen *screen = &term->screen;
+ int delta;
+
+ if (!(event->type == ButtonPress || event->type == ButtonRelease)
+ /* Disable on Shift-Click-1, including the application-mouse modes */
+ || (KeyModifiers & ShiftMask)
+ || (screen->send_mouse_pos != MOUSE_OFF) /* Kinda duplicate... */
+ ||ExtendingSelection) /* Was moved */
+ return 0;
+ if (event->type != ButtonRelease)
+ return 0;
+ if (lastButtonDownTime == (Time) 0) /* first time or once in a blue moon */
+ delta = term->screen.multiClickTime + 1;
+ else if (event->xbutton.time > lastButtonDownTime) /* most of the time */
+ delta = event->xbutton.time - lastButtonDownTime;
+ else /* time has rolled over since lastButtonUpTime */
+ delta = (((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time;
+ return delta <= term->screen.multiClickTime;
+}
+
+static int
+isDoubleClick3(XEvent * event)
+{
+ int delta;
+
+ if (event->type != ButtonRelease
+ || (KeyModifiers & ShiftMask)
+ || event->xbutton.button != Button3) {
+ lastButton3UpTime = 0; /* Disable the cached info */
+ return 0;
+ }
+ /* Process Btn3Release. */
+ if (lastButton3DoubleDownTime == (Time) 0) /* No previous click
+ or once in a blue moon */
+ delta = term->screen.multiClickTime + 1;
+ else if (event->xbutton.time > lastButton3DoubleDownTime) /* most of the time */
+ delta = event->xbutton.time - lastButton3DoubleDownTime;
+ else /* time has rolled over since lastButton3DoubleDownTime */
+ delta = (((Time) ~ 0) - lastButton3DoubleDownTime) + event->xbutton.time;
+ if (delta <= term->screen.multiClickTime) {
+ /* Double click */
+ int row, col;
+
+ /* Cannot check ExtendingSelection, since mouse-3 always sets it */
+ PointToRowCol(event->xbutton.y, event->xbutton.x, &row, &col);
+ if (row == lastButton3row && col == lastButton3col) {
+ lastButton3DoubleDownTime = 0; /* Disable the third click */
+ return 1;
+ }
+ }
+ /* Not a double click, memorize for future check. */
+ lastButton3UpTime = event->xbutton.time;
+ PointToRowCol(event->xbutton.y, event->xbutton.x,
+ &lastButton3row, &lastButton3col);
+ return 0;
+}
+
+static int
+CheckSecondPress3(XEvent * event)
+{
+ int delta, row, col;
+
+ if (event->type != ButtonPress
+ || (KeyModifiers & ShiftMask)
+ || event->xbutton.button != Button3) {
+ lastButton3DoubleDownTime = 0; /* Disable the cached info */
+ return 0;
+ }
+ /* Process Btn3Press. */
+ if (lastButton3UpTime == (Time) 0) /* No previous click
+ or once in a blue moon */
+ delta = term->screen.multiClickTime + 1;
+ else if (event->xbutton.time > lastButton3UpTime) /* most of the time */
+ delta = event->xbutton.time - lastButton3UpTime;
+ else /* time has rolled over since lastButton3UpTime */
+ delta = (((Time) ~ 0) - lastButton3UpTime) + event->xbutton.time;
+ if (delta <= term->screen.multiClickTime) {
+ PointToRowCol(event->xbutton.y, event->xbutton.x, &row, &col);
+ if (row == lastButton3row && col == lastButton3col) {
+ /* A candidate for a double-click */
+ lastButton3DoubleDownTime = event->xbutton.time;
+ PointToRowCol(event->xbutton.y, event->xbutton.x,
+ &lastButton3row, &lastButton3col);
+ return 1;
+ }
+ lastButton3UpTime = 0; /* Disable the info about the previous click */
+ }
+ /* Either too long, or moved, disable. */
+ lastButton3DoubleDownTime = 0;
+ return 0;
+}
+
+static int
+rowOnCurrentLine(int line, int *deltap) /* must be XButtonEvent */
+{
+ TScreen *screen = &term->screen;
+ int l1, l2;
+
+ *deltap = 0;
+ if (line == screen->cur_row)
+ return 1;
+
+ if (line < screen->cur_row)
+ l1 = line, l2 = screen->cur_row;
+ else
+ l2 = line, l1 = screen->cur_row;
+ l1--;
+ while (++l1 < l2)
+ if (!ScrnTstWrapped(screen, l1))
+ return 0;
+ /* Everything is on one "wrapped line" now */
+ *deltap = line - screen->cur_row;
+ return 1;
+}
+
+static int
+eventRow(XEvent * event) /* must be XButtonEvent */
+{
+ TScreen *screen = &term->screen;
+
+ return (event->xbutton.y - screen->border) / FontHeight(screen);
+}
+
+static int
+eventColBetween(XEvent * event) /* must be XButtonEvent */
+{
+ TScreen *screen = &term->screen;
+
+ /* Correct by half a width - we are acting on a boundary, not on a cell. */
+ return ((event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) / 2)
+ / FontWidth(screen));
+}
+
+static int
+ReadLineMovePoint(int col, int ldelta)
+{
+ TScreen *screen = &term->screen;
+ Char line[6];
+ unsigned count = 0;
+
+ col += ldelta * MaxCols(screen) - screen->cur_col;
+ if (col == 0)
+ return 0;
+ if (screen->control_eight_bits) {
+ line[count++] = CSI;
+ } else {
+ line[count++] = ESC;
+ line[count++] = '['; /* XXX maybe sometimes O is better? */
+ }
+ line[count++] = (col > 0 ? 'C' : 'D');
+ if (col < 0)
+ col = -col;
+ while (col--)
+ v_write(screen->respond, line, 3);
+ return 1;
+}
+
+static int
+ReadLineDelete(int r1, int c1, int r2, int c2)
+{
+ TScreen *screen = &term->screen;
+ int del;
+
+ del = c2 - c1 + (r2 - r1) * MaxCols(screen);
+ if (del <= 0) /* Just in case... */
+ return 0;
+ while (del--)
+ v_write(screen->respond, (Char *) "\177", 1);
+ return 1;
+}
+#endif /* OPT_READLINE */
+
+/* ^XM-G<line+' '><col+' '> */
+void
+DiredButton(Widget w GCC_UNUSED,
+ XEvent * event, /* must be XButtonEvent */
+ String * params GCC_UNUSED, /* selections */
+ Cardinal *num_params GCC_UNUSED)
+{
+ TScreen *screen = &term->screen;
+ Char Line[6];
+ unsigned line, col;
+
+ if (event->type == ButtonPress || event->type == ButtonRelease) {
+ line = (event->xbutton.y - screen->border) / FontHeight(screen);
+ col = (event->xbutton.x - OriginX(screen)) / FontWidth(screen);
+ Line[0] = CONTROL('X');
+ Line[1] = ESC;
+ Line[2] = 'G';
+ Line[3] = ' ' + col;
+ Line[4] = ' ' + line;
+ v_write(screen->respond, Line, 5);
+ }
+}
+
+#if OPT_READLINE
+void
+ReadLineButton(Widget w GCC_UNUSED,
+ XEvent * event, /* must be XButtonEvent */
+ String * params GCC_UNUSED, /* selections */
+ Cardinal *num_params GCC_UNUSED)
+{
+ TScreen *screen = &term->screen;
+ Char Line[6];
+ int line, col, ldelta = 0;
+
+ if (!(event->type == ButtonPress || event->type == ButtonRelease)
+ || (screen->send_mouse_pos != MOUSE_OFF) || ExtendingSelection)
+ goto finish;
+ if (event->type == ButtonRelease) {
+ int delta;
+
+ if (lastButtonDownTime == (Time) 0) /* first time and once in a blue moon */
+ delta = screen->multiClickTime + 1;
+ else if (event->xbutton.time > lastButtonDownTime) /* most of the time */
+ delta = event->xbutton.time - lastButtonDownTime;
+ else /* time has rolled over since lastButtonUpTime */
+ delta = (((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time;
+ if (delta > screen->multiClickTime)
+ goto finish; /* All this work for this... */
+ }
+ line = (event->xbutton.y - screen->border) / FontHeight(screen);
+ if (line != screen->cur_row) {
+ int l1, l2;
+
+ if (line < screen->cur_row)
+ l1 = line, l2 = screen->cur_row;
+ else
+ l2 = line, l1 = screen->cur_row;
+ l1--;
+ while (++l1 < l2)
+ if (!ScrnTstWrapped(screen, l1))
+ goto finish;
+ /* Everything is on one "wrapped line" now */
+ ldelta = line - screen->cur_row;
+ }
+ /* Correct by half a width - we are acting on a boundary, not on a cell. */
+ col = (event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) / 2)
+ / FontWidth(screen) - screen->cur_col + ldelta * MaxCols(screen);
+ if (col == 0)
+ goto finish;
+ Line[0] = ESC;
+ /* XXX: sometimes it is better to send '['? */
+ Line[1] = 'O';
+ Line[2] = (col > 0 ? 'C' : 'D');
+ if (col < 0)
+ col = -col;
+ while (col--)
+ v_write(screen->respond, Line, 3);
+ finish:
+ if (event->type == ButtonRelease)
+ do_select_end(w, event, params, num_params, False);
+}
+#endif /* OPT_READLINE */
+
+/* repeats <ESC>n or <ESC>p */
+void
+ViButton(Widget w GCC_UNUSED,
+ XEvent * event, /* must be XButtonEvent */
+ String * params GCC_UNUSED, /* selections */
+ Cardinal *num_params GCC_UNUSED)
+{
+ TScreen *screen = &term->screen;
+ int pty = screen->respond;
+ Char Line[6];
+ int line;
+
+ if (event->type == ButtonPress || event->type == ButtonRelease) {
+
+ line = screen->cur_row -
+ ((event->xbutton.y - screen->border) / FontHeight(screen));
+ if (line != 0) {
+ Line[0] = ESC; /* force an exit from insert-mode */
+ v_write(pty, Line, 1);
+
+ if (line < 0) {
+ line = -line;
+ Line[0] = CONTROL('n');
+ } else {
+ Line[0] = CONTROL('p');
+ }
+ while (--line >= 0)
+ v_write(pty, Line, 1);
+ }
+ }
+}
+
+/*
+ * This function handles button-motion events
+ */
+/*ARGSUSED*/
+void
+HandleSelectExtend(Widget w,
+ XEvent * event, /* must be XMotionEvent */
+ String * params GCC_UNUSED,
+ Cardinal *num_params GCC_UNUSED)
+{
+ TScreen *screen;
+ int row, col;
+
+ if (!IsXtermWidget(w))
+ return;
+
+ screen = &((XtermWidget) w)->screen;
+ screen->selection_time = event->xmotion.time;
+ switch (eventMode) {
+ /* If not in one of the DEC mouse-reporting modes */
+ case LEFTEXTENSION:
+ case RIGHTEXTENSION:
+ PointToRowCol(event->xmotion.y, event->xmotion.x,
+ &row, &col);
+ ExtendExtend(row, col);
+ break;
+
+ /* If in motion reporting mode, send mouse position to
+ character process as a key sequence \E[M... */
+ case NORMAL:
+ /* will get here if send_mouse_pos != MOUSE_OFF */
+ if (screen->send_mouse_pos == BTN_EVENT_MOUSE
+ || screen->send_mouse_pos == ANY_EVENT_MOUSE) {
+ (void) SendMousePosition(w, event);
+ }
+ break;
+ }
+}
+
+void
+HandleKeyboardSelectExtend(Widget w,
+ XEvent * event GCC_UNUSED, /* must be XButtonEvent */
+ String * params GCC_UNUSED,
+ Cardinal *num_params GCC_UNUSED)
+{
+ TScreen *screen;
+
+ if (!IsXtermWidget(w))
+ return;
+
+ screen = &((XtermWidget) w)->screen;
+ ExtendExtend(screen->cursor_row, screen->cursor_col);
+}
+
+static void
+do_select_end(Widget w,
+ XEvent * event, /* must be XButtonEvent */
+ String * params, /* selections */
+ Cardinal *num_params,
+ Bool use_cursor_loc)
+{
+#if OPT_READLINE
+ int ldelta1, ldelta2;
+ TScreen *screen = &term->screen;
+#endif
+
+ if (!IsXtermWidget(w)) {
+ return;
+ }
+
+ ((XtermWidget) w)->screen.selection_time = event->xbutton.time;
+ switch (eventMode) {
+ case NORMAL:
+ (void) SendMousePosition(w, event);
+ break;
+ case LEFTEXTENSION:
+ case RIGHTEXTENSION:
+ EndExtend(w, event, params, *num_params, use_cursor_loc);
+#if OPT_READLINE
+ if (isClick1_clean(event)
+ && SCREEN_FLAG(screen, click1_moves)
+ && rowOnCurrentLine(eventRow(event), &ldelta1)) {
+ ReadLineMovePoint(eventColBetween(event), ldelta1);
+ }
+ if (isDoubleClick3(event)
+ && SCREEN_FLAG(screen, dclick3_deletes)
+ && rowOnCurrentLine(startSRow, &ldelta1)
+ && rowOnCurrentLine(endSRow, &ldelta2)) {
+ ReadLineMovePoint(endSCol, ldelta2);
+ ReadLineDelete(startSRow, startSCol, endSRow, endSCol);
+ }
+#endif /* OPT_READLINE */
+ break;
+ }
+}
+
+void
+HandleSelectEnd(Widget w,
+ XEvent * event, /* must be XButtonEvent */
+ String * params, /* selections */
+ Cardinal *num_params)
+{
+ do_select_end(w, event, params, num_params, False);
+}
+
+void
+HandleKeyboardSelectEnd(Widget w,
+ XEvent * event, /* must be XButtonEvent */
+ String * params, /* selections */
+ Cardinal *num_params)
+{
+ do_select_end(w, event, params, num_params, True);
+}
+
+struct _SelectionList {
+ String *params;
+ Cardinal count;
+ Atom *targets;
+ Time time;
+};
+
+/* convert a UTF-8 string to Latin-1, replacing non Latin-1 characters
+ * by `#'. */
+
+#if OPT_WIDE_CHARS
+static Char *
+UTF8toLatin1(Char * s, unsigned len, unsigned long *result)
+{
+ static Char *buffer;
+ static size_t used;
+
+ Char *p = s;
+ Char *q;
+
+ if (used == 0) {
+ buffer = (Char *) XtMalloc(used = len);
+ } else if (len > used) {
+ buffer = (Char *) XtRealloc((char *) buffer, used = len);
+ }
+ q = buffer;
+
+ /* We're assuming that the xterm widget never contains Unicode
+ control characters. */
+
+ while (p < s + len) {
+ if ((*p & 0x80) == 0) {
+ *q++ = *p++;
+ } else if ((*p & 0x7C) == 0x40 && p < s + len - 1) {
+ *q++ = ((*p & 0x03) << 6) | (p[1] & 0x3F);
+ p += 2;
+ } else if ((*p & 0x60) == 0x40) {
+ *q++ = '#';
+ p += 2;
+ } else if ((*p & 0x50) == 0x40) {
+ *q++ = '#';
+ p += 3;
+ } else { /* this cannot happen */
+ *q++ = '#';
+ p++;
+ }
+ }
+ *result = q - buffer;
+ return buffer;
+}
+#endif /* OPT_WIDE_CHARS */
+
+static Atom *
+_SelectionTargets(Widget w)
+{
+ static Atom *eightBitSelectionTargets = NULL;
+ TScreen *screen;
+ int n;
+
+ if (!IsXtermWidget(w))
+ return NULL;
+
+ screen = &((XtermWidget) w)->screen;
+
+#if OPT_WIDE_CHARS
+ if (screen->wide_chars) {
+ static Atom *utf8SelectionTargets = NULL;
+
+ if (utf8SelectionTargets == NULL) {
+ utf8SelectionTargets = (Atom *) XtMalloc(5 * sizeof(Atom));
+ if (utf8SelectionTargets == NULL) {
+ TRACE(("Couldn't allocate utf8SelectionTargets\n"));
+ return NULL;
+ }
+ n = 0;
+ utf8SelectionTargets[n++] = XA_UTF8_STRING(XtDisplay(w));
+#ifdef X_HAVE_UTF8_STRING
+ if (screen->i18nSelections) {
+ utf8SelectionTargets[n++] = XA_TEXT(XtDisplay(w));
+ utf8SelectionTargets[n++] = XA_COMPOUND_TEXT(XtDisplay(w));
+ }
+#endif
+ utf8SelectionTargets[n++] = XA_STRING;
+ utf8SelectionTargets[n] = None;
+ }
+ return utf8SelectionTargets;
+ }
+#endif
+
+ /* not screen->wide_chars */
+ if (eightBitSelectionTargets == NULL) {
+ eightBitSelectionTargets = (Atom *) XtMalloc(5 * sizeof(Atom));
+ if (eightBitSelectionTargets == NULL) {
+ TRACE(("Couldn't allocate eightBitSelectionTargets\n"));
+ return NULL;
+ }
+ n = 0;
+#ifdef X_HAVE_UTF8_STRING
+ eightBitSelectionTargets[n++] = XA_UTF8_STRING(XtDisplay(w));
+#endif
+ if (screen->i18nSelections) {
+ eightBitSelectionTargets[n++] = XA_TEXT(XtDisplay(w));
+ eightBitSelectionTargets[n++] = XA_COMPOUND_TEXT(XtDisplay(w));
+ }
+ eightBitSelectionTargets[n++] = XA_STRING;
+ eightBitSelectionTargets[n] = None;
+ }
+ return eightBitSelectionTargets;
+}
+
+/*
+ * Lookup the cut-buffer number, which will be in the range 0-7.
+ * If it is not a cut-buffer, it is the primary selection (-1).
+ */
+static int
+CutBuffer(unsigned code)
+{
+ int cutbuffer;
+ switch (code) {
+ case XA_CUT_BUFFER0:
+ cutbuffer = 0;
+ break;
+ case XA_CUT_BUFFER1:
+ cutbuffer = 1;
+ break;
+ case XA_CUT_BUFFER2:
+ cutbuffer = 2;
+ break;
+ case XA_CUT_BUFFER3:
+ cutbuffer = 3;
+ break;
+ case XA_CUT_BUFFER4:
+ cutbuffer = 4;
+ break;
+ case XA_CUT_BUFFER5:
+ cutbuffer = 5;
+ break;
+ case XA_CUT_BUFFER6:
+ cutbuffer = 6;
+ break;
+ case XA_CUT_BUFFER7:
+ cutbuffer = 7;
+ break;
+ default:
+ cutbuffer = -1;
+ break;
+ }
+ return cutbuffer;
+}
+
+#define ResetPaste64() term->screen.base64_paste = 0
+
+#if !OPT_PASTE64
+static
+#endif
+void
+xtermGetSelection(Widget w,
+ Time ev_time,
+ String * params, /* selections in precedence order */
+ Cardinal num_params,
+ Atom * targets)
+{
+ Atom selection;
+ int cutbuffer;
+ Atom target;
+
+ if (!IsXtermWidget(w))
+ return;
+
+#if OPT_TRACE
+ TRACE(("xtermGetSelection\n"));
+ if (num_params > 0) {
+ Cardinal n;
+ for (n = 0; n < num_params; ++n) {
+ TRACE(("param[%d]:%s\n", n, params[n]));
+ }
+ }
+#endif
+
+ XmuInternStrings(XtDisplay(w), params, (Cardinal) 1, &selection);
+ cutbuffer = CutBuffer(selection);
+ TRACE(("Cutbuffer: %d, target: %lu\n", cutbuffer,
+ targets ? (unsigned long) targets[0] : 0));
+ if (cutbuffer >= 0) {
+ int inbytes;
+ unsigned long nbytes;
+ int fmt8 = 8;
+ Atom type = XA_STRING;
+ char *line;
+
+ /* 'line' is freed in SelectionReceived */
+ line = XFetchBuffer(XtDisplay(w), &inbytes, cutbuffer);
+ nbytes = (unsigned long) inbytes;
+
+ if (nbytes > 0)
+ SelectionReceived(w, NULL, &selection, &type, (XtPointer) line,
+ &nbytes, &fmt8);
+ else if (num_params > 1)
+ xtermGetSelection(w, ev_time, params + 1, num_params - 1, NULL);
+#if OPT_PASTE64
+ else
+ ResetPaste64();
+#endif
+ return;
+ } else {
+ struct _SelectionList *list;
+
+ if (targets == NULL || targets[0] == None) {
+ targets = _SelectionTargets(w);
+ }
+
+ if (targets != 0) {
+ target = targets[0];
+
+ if (targets[1] == None) { /* last target in list */
+ params++;
+ num_params--;
+ targets = _SelectionTargets(w);
+ } else {
+ targets = &(targets[1]);
+ }
+
+ if (num_params) {
+ /* 'list' is freed in SelectionReceived */
+ list = XtNew(struct _SelectionList);
+ if (list != 0) {
+ list->params = params;
+ list->count = num_params;
+ list->targets = targets;
+ list->time = ev_time;
+ }
+ } else {
+ list = NULL;
+ }
+
+ XtGetSelectionValue(w, selection,
+ target,
+ SelectionReceived,
+ (XtPointer) list, ev_time);
+ }
+ }
+}
+
+#if OPT_TRACE && OPT_WIDE_CHARS
+static void
+GettingSelection(Display * dpy, Atom type, Char * line, unsigned long len)
+{
+ Char *cp;
+ char *name;
+
+ name = XGetAtomName(dpy, type);
+
+ TRACE(("Getting %s (%ld)\n", name, (long int) type));
+ for (cp = line; cp < line + len; cp++) {
+ TRACE(("[%d:%lu]", cp + 1 - line, len));
+ if (isprint(*cp)) {
+ TRACE(("%c\n", *cp));
+ } else {
+ TRACE(("\\x%02x\n", *cp));
+ }
+ }
+}
+#else
+#define GettingSelection(dpy,type,line,len) /* nothing */
+#endif
+
+#ifdef VMS
+# define tty_vwrite(pty,lag,l) tt_write(lag,l)
+#else /* !( VMS ) */
+# define tty_vwrite(pty,lag,l) v_write(pty,lag,l)
+#endif /* defined VMS */
+
+#if OPT_PASTE64
+/* Return base64 code character given 6-bit number */
+static const char base64_code[] = "\
+ABCDEFGHIJKLMNOPQRSTUVWXYZ\
+abcdefghijklmnopqrstuvwxyz\
+0123456789+/";
+static void
+base64_flush(TScreen * screen)
+{
+ Char x;
+ switch (screen->base64_count) {
+ case 0:
+ break;
+ case 2:
+ x = base64_code[screen->base64_accu << 4];
+ tty_vwrite(screen->respond, &x, 1);
+ break;
+ case 4:
+ x = base64_code[screen->base64_accu << 2];
+ tty_vwrite(screen->respond, &x, 1);
+ break;
+ }
+ if (screen->base64_pad & 3)
+ tty_vwrite(screen->respond,
+ (Char *) "===",
+ 4 - (screen->base64_pad & 3));
+ screen->base64_count = 0;
+ screen->base64_accu = 0;
+ screen->base64_pad = 0;
+}
+#endif /* OPT_PASTE64 */
+
+static void
+_qWriteSelectionData(TScreen * screen, Char * lag, unsigned length)
+{
+#if OPT_PASTE64
+ if (screen->base64_paste) {
+ /* Send data as base64 */
+ Char *p = lag;
+ Char buf[64];
+ unsigned x = 0;
+ while (length--) {
+ switch (screen->base64_count) {
+ case 0:
+ buf[x++] = base64_code[*p >> 2];
+ screen->base64_accu = (*p & 0x3);
+ screen->base64_count = 2;
+ ++p;
+ break;
+ case 2:
+ buf[x++] = base64_code[(screen->base64_accu << 4) + (*p >> 4)];
+ screen->base64_accu = (*p & 0xF);
+ screen->base64_count = 4;
+ ++p;
+ break;
+ case 4:
+ buf[x++] = base64_code[(screen->base64_accu << 2) + (*p >> 6)];
+ buf[x++] = base64_code[*p & 0x3F];
+ screen->base64_accu = 0;
+ screen->base64_count = 0;
+ ++p;
+ break;
+ }
+ if (x >= 63) {
+ /* Write 63 or 64 characters */
+ screen->base64_pad += x;
+ tty_vwrite(screen->respond, buf, x);
+ x = 0;
+ }
+ }
+ if (x != 0) {
+ screen->base64_pad += x;
+ tty_vwrite(screen->respond, buf, x);
+ }
+ } else
+#endif /* OPT_PASTE64 */
+#if OPT_READLINE
+ if (SCREEN_FLAG(screen, paste_quotes)) {
+ while (length--) {
+ tty_vwrite(screen->respond, (Char *) "\026", 1); /* Control-V */
+ tty_vwrite(screen->respond, lag++, 1);
+ }
+ } else
+#endif
+ tty_vwrite(screen->respond, lag, length);
+}
+
+static void
+_WriteSelectionData(TScreen * screen, Char * line, int length)
+{
+ /* Write data to pty a line at a time. */
+ /* Doing this one line at a time may no longer be necessary
+ because v_write has been re-written. */
+
+ Char *lag, *end;
+
+ /* in the VMS version, if tt_pasting isn't set to True then qio
+ reads aren't blocked and an infinite loop is entered, where the
+ pasted text shows up as new input, goes in again, shows up
+ again, ad nauseum. */
+#ifdef VMS
+ tt_pasting = True;
+#endif
+
+ end = &line[length];
+ lag = line;
+
+#if OPT_PASTE64
+ if (screen->base64_paste) {
+ _qWriteSelectionData(screen, lag, (unsigned) (end - lag));
+ base64_flush(screen);
+ } else
+#endif
+ {
+ if (!SCREEN_FLAG(screen, paste_literal_nl)) {
+ Char *cp;
+ for (cp = line; cp != end; cp++) {
+ if (*cp == '\n') {
+ *cp = '\r';
+ _qWriteSelectionData(screen, lag, (unsigned) (cp - lag + 1));
+ lag = cp + 1;
+ }
+ }
+ }
+
+ if (lag != end) {
+ _qWriteSelectionData(screen, lag, (unsigned) (end - lag));
+ }
+ }
+#ifdef VMS
+ tt_pasting = False;
+ tt_start_read(); /* reenable reads or a character may be lost */
+#endif
+}
+
+#if OPT_READLINE
+static void
+_WriteKey(TScreen * screen, Char * in)
+{
+ Char line[16];
+ unsigned count = 0;
+ unsigned length = strlen((char *) in);
+
+ if (screen->control_eight_bits) {
+ line[count++] = CSI;
+ } else {
+ line[count++] = ESC;
+ line[count++] = '[';
+ }
+ while (length--)
+ line[count++] = *in++;
+ line[count++] = '~';
+ tty_vwrite(screen->respond, line, count);
+}
+#endif /* OPT_READLINE */
+
+/* SelectionReceived: stuff received selection text into pty */
+
+/* ARGSUSED */
+static void
+SelectionReceived(Widget w,
+ XtPointer client_data,
+ Atom * selection GCC_UNUSED,
+ Atom * type,
+ XtPointer value,
+ unsigned long *length,
+ int *format GCC_UNUSED)
+{
+ char **text_list = NULL;
+ int text_list_count;
+ XTextProperty text_prop;
+ TScreen *screen;
+ Display *dpy;
+#if OPT_TRACE && OPT_WIDE_CHARS
+ Char *line = (Char *) value;
+#endif
+
+ if (!IsXtermWidget(w))
+ return;
+ screen = &((XtermWidget) w)->screen;
+ dpy = XtDisplay(w);
+
+ if (*type == 0 /*XT_CONVERT_FAIL */
+ || *length == 0
+ || value == NULL)
+ goto fail;
+
+ text_prop.value = (unsigned char *) value;
+ text_prop.encoding = *type;
+ text_prop.format = *format;
+ text_prop.nitems = *length;
+
+#if OPT_WIDE_CHARS
+ if (screen->wide_chars) {
+ if (*type == XA_UTF8_STRING(XtDisplay(w)) ||
+ *type == XA_STRING ||
+ *type == XA_COMPOUND_TEXT(XtDisplay(w))) {
+ GettingSelection(dpy, *type, line, *length);
+ if (Xutf8TextPropertyToTextList(dpy, &text_prop,
+ &text_list,
+ &text_list_count) < 0) {
+ TRACE(("Conversion failed\n"));
+ text_list = NULL;
+ }
+ }
+ } else
+#endif /* OPT_WIDE_CHARS */
+ {
+ /* Convert the selection to locale's multibyte encoding. */
+
+ /* There's no need to special-case UTF8_STRING. If Xlib
+ doesn't know about it, we didn't request it. If a broken
+ selection holder sends it anyhow, the conversion function
+ will fail. */
+
+ if (*type == XA_UTF8_STRING(XtDisplay(w)) ||
+ *type == XA_STRING ||
+ *type == XA_COMPOUND_TEXT(XtDisplay(w))) {
+ Status rc;
+ GettingSelection(dpy, *type, line, *length);
+ if (*type == XA_STRING && screen->brokenSelections) {
+ rc = XTextPropertyToStringList(&text_prop,
+ &text_list, &text_list_count);
+ } else {
+ rc = XmbTextPropertyToTextList(dpy, &text_prop,
+ &text_list,
+ &text_list_count);
+ }
+ if (rc < 0) {
+ TRACE(("Conversion failed\n"));
+ text_list = NULL;
+ }
+ }
+ }
+
+ if (text_list != NULL && text_list_count != 0) {
+ int i;
+
+#if OPT_PASTE64
+ if (screen->base64_paste) {
+ ;
+ } else
+#endif
+#if OPT_READLINE
+ if (SCREEN_FLAG(screen, paste_brackets)) {
+ _WriteKey(screen, (Char *) "200");
+ }
+#endif
+ for (i = 0; i < text_list_count; i++) {
+ int len = strlen(text_list[i]);
+ _WriteSelectionData(screen, (Char *) text_list[i], len);
+ }
+#if OPT_PASTE64
+ if (screen->base64_paste) {
+ ResetPaste64();
+ } else
+#endif
+#if OPT_READLINE
+ if (SCREEN_FLAG(screen, paste_brackets)) {
+ _WriteKey(screen, (Char *) "201");
+ }
+#endif
+ XFreeStringList(text_list);
+ } else
+ goto fail;
+
+ XtFree((char *) client_data);
+ XtFree((char *) value);
+
+ return;
+
+ fail:
+ if (client_data != 0) {
+ struct _SelectionList *list = (struct _SelectionList *) client_data;
+ xtermGetSelection(w, list->time,
+ list->params, list->count, list->targets);
+ XtFree((char *) client_data);
+#if OPT_PASTE64
+ } else {
+ ResetPaste64();
+#endif
+ }
+ return;
+}
+
+void
+HandleInsertSelection(Widget w,
+ XEvent * event, /* assumed to be XButtonEvent* */
+ String * params, /* selections in precedence order */
+ Cardinal *num_params)
+{
+#if OPT_READLINE
+ int ldelta;
+ TScreen *screen = &((XtermWidget) w)->screen;
+#endif
+
+ if (SendMousePosition(w, event))
+ return;
+
+#if OPT_READLINE
+ if ((event->type == ButtonPress || event->type == ButtonRelease)
+ /* Disable on Shift-mouse, including the application-mouse modes */
+ && !(KeyModifiers & ShiftMask)
+ && (screen->send_mouse_pos == MOUSE_OFF)
+ && SCREEN_FLAG(screen, paste_moves)
+ && rowOnCurrentLine(eventRow(event), &ldelta))
+ ReadLineMovePoint(eventColBetween(event), ldelta);
+#endif /* OPT_READLINE */
+
+ xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL);
+}
+
+static SelectUnit
+EvalSelectUnit(Time buttonDownTime, SelectUnit defaultUnit)
+{
+ int delta;
+
+ if (lastButtonUpTime == (Time) 0) /* first time and once in a blue moon */
+ delta = term->screen.multiClickTime + 1;
+ else if (buttonDownTime > lastButtonUpTime) /* most of the time */
+ delta = buttonDownTime - lastButtonUpTime;
+ else /* time has rolled over since lastButtonUpTime */
+ delta = (((Time) ~ 0) - lastButtonUpTime) + buttonDownTime;
+
+ if (delta > term->screen.multiClickTime) {
+ numberOfClicks = 1;
+ return defaultUnit;
+ } else {
+ ++numberOfClicks;
+ return ((selectUnit + 1) % NSELECTUNITS);
+ }
+}
+
+static void
+do_select_start(Widget w,
+ XEvent * event, /* must be XButtonEvent* */
+ int startrow,
+ int startcol)
+{
+ if (SendMousePosition(w, event))
+ return;
+ selectUnit = EvalSelectUnit(event->xbutton.time, SELECTCHAR);
+ replyToEmacs = False;
+
+#if OPT_READLINE
+ lastButtonDownTime = event->xbutton.time;
+#endif
+
+ StartSelect(startrow, startcol);
+}
+
+/* ARGSUSED */
+void
+HandleSelectStart(Widget w,
+ XEvent * event, /* must be XButtonEvent* */
+ String * params GCC_UNUSED,
+ Cardinal *num_params GCC_UNUSED)
+{
+ TScreen *screen;
+ int startrow, startcol;
+
+ if (!IsXtermWidget(w))
+ return;
+
+ screen = &((XtermWidget) w)->screen;
+ firstValidRow = 0;
+ lastValidRow = screen->max_row;
+ PointToRowCol(event->xbutton.y, event->xbutton.x, &startrow, &startcol);
+
+#if OPT_READLINE
+ ExtendingSelection = 0;
+#endif
+
+ do_select_start(w, event, startrow, startcol);
+}
+
+/* ARGSUSED */
+void
+HandleKeyboardSelectStart(Widget w,
+ XEvent * event, /* must be XButtonEvent* */
+ String * params GCC_UNUSED,
+ Cardinal *num_params GCC_UNUSED)
+{
+ TScreen *screen;
+
+ if (!IsXtermWidget(w))
+ return;
+
+ screen = &((XtermWidget) w)->screen;
+ do_select_start(w, event, screen->cursor_row, screen->cursor_col);
+}
+
+static void
+TrackDown(XButtonEvent * event)
+{
+ int startrow, startcol;
+
+ selectUnit = EvalSelectUnit(event->time, SELECTCHAR);
+ if (numberOfClicks > 1) {
+ PointToRowCol(event->y, event->x, &startrow, &startcol);
+ replyToEmacs = True;
+ StartSelect(startrow, startcol);
+ } else {
+ waitingForTrackInfo = True;
+ EditorButton((XButtonEvent *) event);
+ }
+}
+
+#define boundsCheck(x) if (x < 0) \
+ x = 0; \
+ else if (x >= screen->max_row) \
+ x = screen->max_row
+
+void
+TrackMouse(int func, int startrow, int startcol, int firstrow, int lastrow)
+{
+ TScreen *screen = &term->screen;
+
+ if (!waitingForTrackInfo) { /* Timed out, so ignore */
+ return;
+ }
+ waitingForTrackInfo = False;
+ if (func == 0)
+ return;
+ boundsCheck(startrow);
+ boundsCheck(firstrow);
+ boundsCheck(lastrow);
+ firstValidRow = firstrow;
+ lastValidRow = lastrow;
+ replyToEmacs = True;
+ StartSelect(startrow, startcol);
+}
+
+static void
+StartSelect(int startrow, int startcol)
+{
+ TScreen *screen = &term->screen;
+
+ TRACE(("StartSelect row=%d, col=%d\n", startrow, startcol));
+ if (screen->cursor_state)
+ HideCursor();
+ if (numberOfClicks == 1) {
+ /* set start of selection */
+ rawRow = startrow;
+ rawCol = startcol;
+
+ }
+ /* else use old values in rawRow, Col */
+ saveStartRRow = startERow = rawRow;
+ saveStartRCol = startECol = rawCol;
+ saveEndRRow = endERow = rawRow;
+ saveEndRCol = endECol = rawCol;
+ if (Coordinate(startrow, startcol) < Coordinate(rawRow, rawCol)) {
+ eventMode = LEFTEXTENSION;
+ startERow = startrow;
+ startECol = startcol;
+ } else {
+ eventMode = RIGHTEXTENSION;
+ endERow = startrow;
+ endECol = startcol;
+ }
+ ComputeSelect(startERow, startECol, endERow, endECol, False);
+}
+
+static void
+EndExtend(Widget w,
+ XEvent * event, /* must be XButtonEvent */
+ String * params, /* selections */
+ Cardinal num_params,
+ Bool use_cursor_loc)
+{
+ int row, col;
+ unsigned count;
+ TScreen *screen = &term->screen;
+ Char line[9];
+
+ if (use_cursor_loc) {
+ row = screen->cursor_row;
+ col = screen->cursor_col;
+ } else {
+ PointToRowCol(event->xbutton.y, event->xbutton.x, &row, &col);
+ }
+ ExtendExtend(row, col);
+ lastButtonUpTime = event->xbutton.time;
+ if (startSRow != endSRow || startSCol != endSCol) {
+ if (replyToEmacs) {
+ count = 0;
+ if (screen->control_eight_bits) {
+ line[count++] = CSI;
+ } else {
+ line[count++] = ESC;
+ line[count++] = '[';
+ }
+ if (rawRow == startSRow && rawCol == startSCol
+ && row == endSRow && col == endSCol) {
+ /* Use short-form emacs select */
+ line[count++] = 't';
+ line[count++] = ' ' + endSCol + 1;
+ line[count++] = ' ' + endSRow + 1;
+ } else {
+ /* long-form, specify everything */
+ line[count++] = 'T';
+ line[count++] = ' ' + startSCol + 1;
+ line[count++] = ' ' + startSRow + 1;
+ line[count++] = ' ' + endSCol + 1;
+ line[count++] = ' ' + endSRow + 1;
+ line[count++] = ' ' + col + 1;
+ line[count++] = ' ' + row + 1;
+ }
+ v_write(screen->respond, line, count);
+ TrackText(0, 0, 0, 0);
+ }
+ }
+ SelectSet(w, event, params, num_params);
+ eventMode = NORMAL;
+}
+
+void
+HandleSelectSet(Widget w,
+ XEvent * event,
+ String * params,
+ Cardinal *num_params)
+{
+ SelectSet(w, event, params, *num_params);
+}
+
+/* ARGSUSED */
+static void
+SelectSet(Widget w GCC_UNUSED,
+ XEvent * event GCC_UNUSED,
+ String * params,
+ Cardinal num_params)
+{
+ TRACE(("SelectSet\n"));
+ /* Only do select stuff if non-null select */
+ if (startSRow != endSRow || startSCol != endSCol) {
+ SaltTextAway(startSRow, startSCol, endSRow, endSCol,
+ params, num_params);
+ } else {
+ DisownSelection(term);
+ }
+}
+
+#define Abs(x) ((x) < 0 ? -(x) : (x))
+
+/* ARGSUSED */
+static void
+do_start_extend(Widget w,
+ XEvent * event, /* must be XButtonEvent* */
+ String * params GCC_UNUSED,
+ Cardinal *num_params GCC_UNUSED,
+ Bool use_cursor_loc)
+{
+ TScreen *screen;
+ int row, col, coord;
+
+ if (!IsXtermWidget(w))
+ return;
+
+ screen = &((XtermWidget) w)->screen;
+ if (SendMousePosition(w, event))
+ return;
+ firstValidRow = 0;
+ lastValidRow = screen->max_row;
+#if OPT_READLINE
+ if ((KeyModifiers & ShiftMask)
+ || event->xbutton.button != Button3
+ || !(SCREEN_FLAG(screen, dclick3_deletes)))
+#endif
+ selectUnit = EvalSelectUnit(event->xbutton.time, selectUnit);
+ replyToEmacs = False;
+
+#if OPT_READLINE
+ CheckSecondPress3(event);
+#endif
+
+ if (numberOfClicks == 1
+ || (SCREEN_FLAG(screen, dclick3_deletes) /* Dclick special */
+ &&!(KeyModifiers & ShiftMask))) {
+ /* Save existing selection so we can reestablish it if the guy
+ extends past the other end of the selection */
+ saveStartRRow = startERow = startRRow;
+ saveStartRCol = startECol = startRCol;
+ saveEndRRow = endERow = endRRow;
+ saveEndRCol = endECol = endRCol;
+ } else {
+ /* He just needed the selection mode changed, use old values. */
+ startERow = startRRow = saveStartRRow;
+ startECol = startRCol = saveStartRCol;
+ endERow = endRRow = saveEndRRow;
+ endECol = endRCol = saveEndRCol;
+
+ }
+ if (use_cursor_loc) {
+ row = screen->cursor_row;
+ col = screen->cursor_col;
+ } else {
+ PointToRowCol(event->xbutton.y, event->xbutton.x, &row, &col);
+ }
+ coord = Coordinate(row, col);
+
+ if (Abs(coord - Coordinate(startSRow, startSCol))
+ < Abs(coord - Coordinate(endSRow, endSCol))
+ || coord < Coordinate(startSRow, startSCol)) {
+ /* point is close to left side of selection */
+ eventMode = LEFTEXTENSION;
+ startERow = row;
+ startECol = col;
+ } else {
+ /* point is close to left side of selection */
+ eventMode = RIGHTEXTENSION;
+ endERow = row;
+ endECol = col;
+ }
+ ComputeSelect(startERow, startECol, endERow, endECol, True);
+
+#if OPT_READLINE
+ if (startSRow != endSRow || startSCol != endSCol)
+ ExtendingSelection = 1;
+#endif
+}
+
+static void
+ExtendExtend(int row, int col)
+{
+ int coord = Coordinate(row, col);
+
+ TRACE(("ExtendExtend row=%d, col=%d\n", row, col));
+ if (eventMode == LEFTEXTENSION
+ && (coord + (selectUnit != SELECTCHAR)) > Coordinate(endSRow, endSCol)) {
+ /* Whoops, he's changed his mind. Do RIGHTEXTENSION */
+ eventMode = RIGHTEXTENSION;
+ startERow = saveStartRRow;
+ startECol = saveStartRCol;
+ } else if (eventMode == RIGHTEXTENSION
+ && coord < Coordinate(startSRow, startSCol)) {
+ /* Whoops, he's changed his mind. Do LEFTEXTENSION */
+ eventMode = LEFTEXTENSION;
+ endERow = saveEndRRow;
+ endECol = saveEndRCol;
+ }
+ if (eventMode == LEFTEXTENSION) {
+ startERow = row;
+ startECol = col;
+ } else {
+ endERow = row;
+ endECol = col;
+ }
+ ComputeSelect(startERow, startECol, endERow, endECol, False);
+
+#if OPT_READLINE
+ if (startSRow != endSRow || startSCol != endSCol)
+ ExtendingSelection = 1;
+#endif
+}
+
+void
+HandleStartExtend(Widget w,
+ XEvent * event, /* must be XButtonEvent* */
+ String * params, /* unused */
+ Cardinal *num_params) /* unused */
+{
+ do_start_extend(w, event, params, num_params, False);
+}
+
+void
+HandleKeyboardStartExtend(Widget w,
+ XEvent * event, /* must be XButtonEvent* */
+ String * params, /* unused */
+ Cardinal *num_params) /* unused */
+{
+ do_start_extend(w, event, params, num_params, True);
+}
+
+void
+ScrollSelection(TScreen * screen, int amount, Bool always)
+{
+ int minrow = -screen->savedlines - screen->topline;
+ int maxrow = screen->max_row - screen->topline;
+ int maxcol = screen->max_col;
+
+#define scroll_update_one(row, col) \
+ row += amount; \
+ if (row < minrow) { \
+ row = minrow; \
+ col = 0; \
+ } \
+ if (row > maxrow) { \
+ row = maxrow; \
+ col = maxcol; \
+ }
+
+ scroll_update_one(startRRow, startRCol);
+ scroll_update_one(endRRow, endRCol);
+ scroll_update_one(startSRow, startSCol);
+ scroll_update_one(endSRow, endSCol);
+
+ scroll_update_one(rawRow, rawCol);
+
+ /*
+ * If we are told to scroll the selection but it lies outside the scrolling
+ * margins, then that could cause the selection to move (bad). It is not
+ * simple to fix, because this function is called both for the scrollbar
+ * actions as well as application scrolling. The 'always' flag is set in
+ * the former case. The rest of the logic handles the latter.
+ */
+ if (ScrnHaveSelection(screen)) {
+ int adjust;
+
+ adjust = screen->startHRow + screen->topline;
+ if (always
+ || !ScrnHaveLineMargins(screen)
+ || ScrnIsLineInMargins(screen, adjust)) {
+ scroll_update_one(screen->startHRow, screen->startHCol);
+ }
+ adjust = screen->endHRow + screen->topline;
+ if (always
+ || !ScrnHaveLineMargins(screen)
+ || ScrnIsLineInMargins(screen, adjust)) {
+ scroll_update_one(screen->endHRow, screen->endHCol);
+ }
+ }
+
+ screen->startHCoord = Coordinate(screen->startHRow, screen->startHCol);
+ screen->endHCoord = Coordinate(screen->endHRow, screen->endHCol);
+}
+
+/*ARGSUSED*/
+void
+ResizeSelection(TScreen * screen GCC_UNUSED, int rows, int cols)
+{
+ rows--; /* decr to get 0-max */
+ cols--;
+
+ if (startRRow > rows)
+ startRRow = rows;
+ if (startSRow > rows)
+ startSRow = rows;
+ if (endRRow > rows)
+ endRRow = rows;
+ if (endSRow > rows)
+ endSRow = rows;
+ if (rawRow > rows)
+ rawRow = rows;
+
+ if (startRCol > cols)
+ startRCol = cols;
+ if (startSCol > cols)
+ startSCol = cols;
+ if (endRCol > cols)
+ endRCol = cols;
+ if (endSCol > cols)
+ endSCol = cols;
+ if (rawCol > cols)
+ rawCol = cols;
+}
+
+#if OPT_WIDE_CHARS
+Bool
+iswide(int i)
+{
+ return (i == HIDDEN_CHAR) || (my_wcwidth(i) == 2);
+}
+
+#define isWideCell(row, col) iswide((int)XTERM_CELL(row, col))
+#endif
+
+static void
+PointToRowCol(int y,
+ int x,
+ int *r,
+ int *c)
+/* Convert pixel coordinates to character coordinates.
+ Rows are clipped between firstValidRow and lastValidRow.
+ Columns are clipped between to be 0 or greater, but are not clipped to some
+ maximum value. */
+{
+ TScreen *screen = &term->screen;
+ int row, col;
+
+ row = (y - screen->border) / FontHeight(screen);
+ if (row < firstValidRow)
+ row = firstValidRow;
+ else if (row > lastValidRow)
+ row = lastValidRow;
+ col = (x - OriginX(screen)) / FontWidth(screen);
+ if (col < 0)
+ col = 0;
+ else if (col > MaxCols(screen)) {
+ col = MaxCols(screen);
+ }
+#if OPT_WIDE_CHARS
+ /*
+ * If we got a click on the right half of a doublewidth character,
+ * pretend it happened on the left half.
+ */
+ if (col > 0
+ && isWideCell(row, col - 1)
+ && (XTERM_CELL(row, col) == HIDDEN_CHAR)) {
+ col -= 1;
+ }
+#endif
+ *r = row;
+ *c = col;
+}
+
+static int
+LastTextCol(int row)
+{
+ TScreen *screen = &term->screen;
+ int i;
+ Char *ch;
+
+ if ((row += screen->topline) + screen->savedlines >= 0) {
+ for (i = screen->max_col,
+ ch = SCRN_BUF_ATTRS(screen, row) + i;
+ i >= 0 && !(*ch & CHARDRAWN);
+ ch--, i--) ;
+#if OPT_DEC_CHRSET
+ if (CSET_DOUBLE(SCRN_BUF_CSETS(screen, row)[0])) {
+ i *= 2;
+ }
+#endif
+ } else {
+ i = -1;
+ }
+ return (i);
+}
+
+#if !OPT_WIDE_CHARS
+/*
+** double click table for cut and paste in 8 bits
+**
+** This table is divided in four parts :
+**
+** - control characters [0,0x1f] U [0x80,0x9f]
+** - separators [0x20,0x3f] U [0xa0,0xb9]
+** - binding characters [0x40,0x7f] U [0xc0,0xff]
+** - exceptions
+*/
+/* *INDENT-OFF* */
+static int charClass[256] =
+{
+/* NUL SOH STX ETX EOT ENQ ACK BEL */
+ 32, 1, 1, 1, 1, 1, 1, 1,
+/* BS HT NL VT NP CR SO SI */
+ 1, 32, 1, 1, 1, 1, 1, 1,
+/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
+ 1, 1, 1, 1, 1, 1, 1, 1,
+/* CAN EM SUB ESC FS GS RS US */
+ 1, 1, 1, 1, 1, 1, 1, 1,
+/* SP ! " # $ % & ' */
+ 32, 33, 34, 35, 36, 37, 38, 39,
+/* ( ) * + , - . / */
+ 40, 41, 42, 43, 44, 45, 46, 47,
+/* 0 1 2 3 4 5 6 7 */
+ 48, 48, 48, 48, 48, 48, 48, 48,
+/* 8 9 : ; < = > ? */
+ 48, 48, 58, 59, 60, 61, 62, 63,
+/* @ A B C D E F G */
+ 64, 48, 48, 48, 48, 48, 48, 48,
+/* H I J K L M N O */
+ 48, 48, 48, 48, 48, 48, 48, 48,
+/* P Q R S T U V W */
+ 48, 48, 48, 48, 48, 48, 48, 48,
+/* X Y Z [ \ ] ^ _ */
+ 48, 48, 48, 91, 92, 93, 94, 48,
+/* ` a b c d e f g */
+ 96, 48, 48, 48, 48, 48, 48, 48,
+/* h i j k l m n o */
+ 48, 48, 48, 48, 48, 48, 48, 48,
+/* p q r s t u v w */
+ 48, 48, 48, 48, 48, 48, 48, 48,
+/* x y z { | } ~ DEL */
+ 48, 48, 48, 123, 124, 125, 126, 1,
+/* x80 x81 x82 x83 IND NEL SSA ESA */
+ 1, 1, 1, 1, 1, 1, 1, 1,
+/* HTS HTJ VTS PLD PLU RI SS2 SS3 */
+ 1, 1, 1, 1, 1, 1, 1, 1,
+/* DCS PU1 PU2 STS CCH MW SPA EPA */
+ 1, 1, 1, 1, 1, 1, 1, 1,
+/* x98 x99 x9A CSI ST OSC PM APC */
+ 1, 1, 1, 1, 1, 1, 1, 1,
+/* - i c/ L ox Y- | So */
+ 160, 161, 162, 163, 164, 165, 166, 167,
+/* .. c0 ip << _ R0 - */
+ 168, 169, 170, 171, 172, 173, 174, 175,
+/* o +- 2 3 ' u q| . */
+ 176, 177, 178, 179, 180, 181, 182, 183,
+/* , 1 2 >> 1/4 1/2 3/4 ? */
+ 184, 185, 186, 187, 188, 189, 190, 191,
+/* A` A' A^ A~ A: Ao AE C, */
+ 48, 48, 48, 48, 48, 48, 48, 48,
+/* E` E' E^ E: I` I' I^ I: */
+ 48, 48, 48, 48, 48, 48, 48, 48,
+/* D- N~ O` O' O^ O~ O: X */
+ 48, 48, 48, 48, 48, 48, 48, 215,
+/* O/ U` U' U^ U: Y' P B */
+ 48, 48, 48, 48, 48, 48, 48, 48,
+/* a` a' a^ a~ a: ao ae c, */
+ 48, 48, 48, 48, 48, 48, 48, 48,
+/* e` e' e^ e: i` i' i^ i: */
+ 48, 48, 48, 48, 48, 48, 48, 48,
+/* d n~ o` o' o^ o~ o: -: */
+ 48, 48, 48, 48, 48, 48, 48, 247,
+/* o/ u` u' u^ u: y' P y: */
+ 48, 48, 48, 48, 48, 48, 48, 48};
+/* *INDENT-ON* */
+
+int
+SetCharacterClassRange(int low, /* in range of [0..255] */
+ int high,
+ int value) /* arbitrary */
+{
+
+ if (low < 0 || high > 255 || high < low)
+ return (-1);
+
+ for (; low <= high; low++)
+ charClass[low] = value;
+
+ return (0);
+}
+#endif
+
+#if OPT_WIDE_CHARS
+static int
+class_of(TScreen * screen, int row, int col)
+{
+ int value;
+#if OPT_DEC_CHRSET
+ if (CSET_DOUBLE(SCRN_BUF_CSETS(screen, row + screen->topline)[0])) {
+ col /= 2;
+ }
+#endif
+ value = XTERM_CELL(row, col);
+ if_OPT_WIDE_CHARS(screen, {
+ return CharacterClass(value);
+ });
+ return CharacterClass(value);
+}
+#define ClassSelects(screen, row, col, cclass) \
+ (class_of(screen, row, col) == cclass \
+ || XTERM_CELL(row, col) == HIDDEN_CHAR)
+#else
+#define class_of(screen,row,col) charClass[XTERM_CELL(row, col)]
+#define ClassSelects(screen, row, col, cclass) \
+ (class_of(screen,row, col) == cclass)
+#endif
+
+/*
+ * sets startSRow startSCol endSRow endSCol
+ * ensuring that they have legal values
+ */
+static void
+ComputeSelect(int startRow,
+ int startCol,
+ int endRow,
+ int endCol,
+ Bool extend)
+{
+ TScreen *screen = &term->screen;
+ int length;
+ int cclass;
+
+ TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n",
+ startRow, startCol, endRow, endCol, extend ? "" : "no"));
+
+#if OPT_WIDE_CHARS
+ if (startCol > 1
+ && isWideCell(startRow, startCol - 1)
+ && XTERM_CELL(startRow, startCol - 0) == HIDDEN_CHAR) {
+ fprintf(stderr, "Adjusting start. Changing downwards from %i.\n", startCol);
+ startCol -= 1;
+ if (endCol == (startCol + 1))
+ endCol--;
+ }
+
+ if (endCol > 1
+ && isWideCell(endRow, endCol - 1)
+ && XTERM_CELL(endRow, endCol) == HIDDEN_CHAR) {
+ endCol += 1;
+ }
+#endif
+
+ if (Coordinate(startRow, startCol) <= Coordinate(endRow, endCol)) {
+ startSRow = startRRow = startRow;
+ startSCol = startRCol = startCol;
+ endSRow = endRRow = endRow;
+ endSCol = endRCol = endCol;
+ } else { /* Swap them */
+ startSRow = startRRow = endRow;
+ startSCol = startRCol = endCol;
+ endSRow = endRRow = startRow;
+ endSCol = endRCol = startCol;
+ }
+
+ switch (selectUnit) {
+ case SELECTCHAR:
+ if (startSCol > (LastTextCol(startSRow) + 1)) {
+ startSCol = 0;
+ startSRow++;
+ }
+ if (endSCol > (LastTextCol(endSRow) + 1)) {
+ endSCol = 0;
+ endSRow++;
+ }
+ break;
+ case SELECTWORD:
+ if (startSCol > (LastTextCol(startSRow) + 1)) {
+ startSCol = 0;
+ startSRow++;
+ } else {
+ cclass = class_of(screen, startSRow, startSCol);
+ do {
+ --startSCol;
+ if (startSCol < 0
+ && ScrnTstWrapped(screen, startSRow - 1)) {
+ --startSRow;
+ startSCol = LastTextCol(startSRow);
+ }
+ } while (startSCol >= 0
+ && ClassSelects(screen, startSRow, startSCol, cclass));
+ ++startSCol;
+ }
+
+#if OPT_WIDE_CHARS
+ if (startSCol && XTERM_CELL(startSRow, startSCol) == HIDDEN_CHAR)
+ startSCol++;
+#endif
+
+ if (endSCol > (LastTextCol(endSRow) + 1)) {
+ endSCol = 0;
+ endSRow++;
+ } else {
+ length = LastTextCol(endSRow);
+ cclass = class_of(screen, endSRow, endSCol);
+ do {
+ ++endSCol;
+ if (endSCol > length
+ && ScrnTstWrapped(screen, endSRow)) {
+ endSCol = 0;
+ ++endSRow;
+ length = LastTextCol(endSRow);
+ }
+ } while (endSCol <= length
+ && ClassSelects(screen, endSRow, endSCol, cclass));
+ /* Word select selects if pointing to any char
+ in "word", especially in that it includes
+ the last character in a word. So no --endSCol
+ and do special eol handling */
+ if (endSCol > length + 1) {
+ endSCol = 0;
+ ++endSRow;
+ }
+ }
+
+#if OPT_WIDE_CHARS
+ if (endSCol && XTERM_CELL(endSRow, endSCol) == HIDDEN_CHAR)
+ endSCol++;
+#endif
+
+ saveStartWRow = startSRow;
+ saveStartWCol = startSCol;
+ break;
+ case SELECTLINE:
+ while (ScrnTstWrapped(screen, endSRow)) {
+ ++endSRow;
+ }
+ if (term->screen.cutToBeginningOfLine
+ || startSRow < saveStartWRow) {
+ startSCol = 0;
+ while (ScrnTstWrapped(screen, startSRow - 1)) {
+ --startSRow;
+ }
+ } else if (!extend) {
+ if ((startRow < saveStartWRow)
+ || (startRow == saveStartWRow
+ && startCol < saveStartWCol)) {
+ startSCol = 0;
+ while (ScrnTstWrapped(screen, startSRow - 1)) {
+ --startSRow;
+ }
+ } else {
+ startSRow = saveStartWRow;
+ startSCol = saveStartWCol;
+ }
+ }
+ if (term->screen.cutNewline) {
+ endSCol = 0;
+ ++endSRow;
+ } else {
+ endSCol = LastTextCol(endSRow) + 1;
+ }
+ break;
+ }
+
+ /* check boundaries */
+ ScrollSelection(screen, 0, False);
+
+ TrackText(startSRow, startSCol, endSRow, endSCol);
+ return;
+}
+
+void
+TrackText(int frow,
+ int fcol,
+ int trow,
+ int tcol)
+ /* Guaranteed (frow, fcol) <= (trow, tcol) */
+{
+ int from, to;
+ TScreen *screen = &term->screen;
+ int old_startrow, old_startcol, old_endrow, old_endcol;
+
+ TRACE(("TrackText(frow=%d, fcol=%d, trow=%d, tcol=%d)\n",
+ frow, fcol, trow, tcol));
+
+ old_startrow = screen->startHRow;
+ old_startcol = screen->startHCol;
+ old_endrow = screen->endHRow;
+ old_endcol = screen->endHCol;
+ if (frow == old_startrow && fcol == old_startcol &&
+ trow == old_endrow && tcol == old_endcol)
+ return;
+ screen->startHRow = frow;
+ screen->startHCol = fcol;
+ screen->endHRow = trow;
+ screen->endHCol = tcol;
+ from = Coordinate(frow, fcol);
+ to = Coordinate(trow, tcol);
+ if (to <= screen->startHCoord || from > screen->endHCoord) {
+ /* No overlap whatsoever between old and new hilite */
+ ReHiliteText(old_startrow, old_startcol, old_endrow, old_endcol);
+ ReHiliteText(frow, fcol, trow, tcol);
+ } else {
+ if (from < screen->startHCoord) {
+ /* Extend left end */
+ ReHiliteText(frow, fcol, old_startrow, old_startcol);
+ } else if (from > screen->startHCoord) {
+ /* Shorten left end */
+ ReHiliteText(old_startrow, old_startcol, frow, fcol);
+ }
+ if (to > screen->endHCoord) {
+ /* Extend right end */
+ ReHiliteText(old_endrow, old_endcol, trow, tcol);
+ } else if (to < screen->endHCoord) {
+ /* Shorten right end */
+ ReHiliteText(trow, tcol, old_endrow, old_endcol);
+ }
+ }
+ screen->startHCoord = from;
+ screen->endHCoord = to;
+}
+
+static void
+ReHiliteText(int frow,
+ int fcol,
+ int trow,
+ int tcol)
+ /* Guaranteed that (frow, fcol) <= (trow, tcol) */
+{
+ TScreen *screen = &term->screen;
+ int i;
+
+ TRACE(("ReHiliteText from %d.%d to %d.%d\n", frow, fcol, trow, tcol));
+
+ if (frow < 0)
+ frow = fcol = 0;
+ else if (frow > screen->max_row)
+ return; /* nothing to do, since trow >= frow */
+
+ if (trow < 0)
+ return; /* nothing to do, since frow <= trow */
+ else if (trow > screen->max_row) {
+ trow = screen->max_row;
+ tcol = MaxCols(screen);
+ }
+ if (frow == trow && fcol == tcol)
+ return;
+
+ if (frow != trow) { /* do multiple rows */
+ if ((i = screen->max_col - fcol + 1) > 0) { /* first row */
+ ScrnRefresh(screen, frow, fcol, 1, i, True);
+ }
+ if ((i = trow - frow - 1) > 0) { /* middle rows */
+ ScrnRefresh(screen, frow + 1, 0, i, MaxCols(screen), True);
+ }
+ if (tcol > 0 && trow <= screen->max_row) { /* last row */
+ ScrnRefresh(screen, trow, 0, 1, tcol, True);
+ }
+ } else { /* do single row */
+ ScrnRefresh(screen, frow, fcol, 1, tcol - fcol, True);
+ }
+}
+
+static void
+SaltTextAway(int crow, int ccol, int row, int col,
+ String * params, /* selections */
+ Cardinal num_params)
+ /* Guaranteed that (crow, ccol) <= (row, col), and that both points are valid
+ (may have row = screen->max_row+1, col = 0) */
+{
+ TScreen *screen = &term->screen;
+ int i, j = 0;
+ int eol;
+ Char *line;
+ Char *lp;
+
+ if (crow == row && ccol > col) {
+ int tmp = ccol;
+ ccol = col;
+ col = tmp;
+ }
+
+ --col;
+ /* first we need to know how long the string is before we can save it */
+
+ if (row == crow) {
+ j = Length(screen, crow, ccol, col);
+ } else { /* two cases, cut is on same line, cut spans multiple lines */
+ j += Length(screen, crow, ccol, screen->max_col) + 1;
+ for (i = crow + 1; i < row; i++)
+ j += Length(screen, i, 0, screen->max_col) + 1;
+ if (col >= 0)
+ j += Length(screen, row, 0, col);
+ }
+
+ /* UTF-8 may require more space */
+ if_OPT_WIDE_CHARS(screen, {
+ j *= 4;
+ });
+
+ /* now get some memory to save it in */
+
+ if (screen->selection_size <= j) {
+ if ((line = (Char *) malloc((unsigned) j + 1)) == 0)
+ SysError(ERROR_BMALLOC2);
+ XtFree((char *) screen->selection_data);
+ screen->selection_data = line;
+ screen->selection_size = j + 1;
+ } else {
+ line = screen->selection_data;
+ }
+
+ if ((line == 0)
+ || (j < 0))
+ return;
+
+ line[j] = '\0'; /* make sure it is null terminated */
+ lp = line; /* lp points to where to save the text */
+ if (row == crow) {
+ lp = SaveText(screen, row, ccol, col, lp, &eol);
+ } else {
+ lp = SaveText(screen, crow, ccol, screen->max_col, lp, &eol);
+ if (eol)
+ *lp++ = '\n'; /* put in newline at end of line */
+ for (i = crow + 1; i < row; i++) {
+ lp = SaveText(screen, i, 0, screen->max_col, lp, &eol);
+ if (eol)
+ *lp++ = '\n';
+ }
+ if (col >= 0)
+ lp = SaveText(screen, row, 0, col, lp, &eol);
+ }
+ *lp = '\0'; /* make sure we have end marked */
+
+ TRACE(("Salted TEXT:%d:%.*s\n", lp - line, lp - line, line));
+ screen->selection_length = (lp - line);
+ _OwnSelection(term, params, num_params);
+}
+
+#if OPT_PASTE64
+void
+ClearSelectionBuffer()
+{
+ TScreen *screen = &term->screen;
+ screen->selection_length = 0;
+ screen->base64_count = 0;
+}
+
+static void
+AppendStrToSelectionBuffer(Char * text, int len)
+{
+ TScreen *screen = &term->screen;
+ if (len != 0) {
+ int j = screen->selection_length + len; /* New length */
+ int k = j + (j >> 2) + 80; /* New size if we grow buffer: grow by ~50% */
+ if (j + 1 >= screen->selection_size) {
+ if (!screen->selection_length) {
+ /* New buffer */
+ Char *line;
+ if ((line = (Char *) malloc((unsigned) k)) == 0)
+ SysError(ERROR_BMALLOC2);
+ XtFree((char *) screen->selection_data);
+ screen->selection_data = line;
+ } else {
+ /* Realloc buffer */
+ screen->selection_data = (Char *)
+ realloc(screen->selection_data,
+ (unsigned) k);
+ if (screen->selection_data == 0)
+ SysError(ERROR_BMALLOC2);
+ }
+ screen->selection_size = k;
+ }
+ memcpy(screen->selection_data + screen->selection_length, text, len);
+ screen->selection_length += len;
+ screen->selection_data[screen->selection_length] = 0;
+ }
+}
+
+void
+AppendToSelectionBuffer(TScreen * screen, unsigned c)
+{
+ int six;
+ Char ch;
+
+ /* Decode base64 character */
+ if (c >= 'A' && c <= 'Z')
+ six = c - 'A';
+ else if (c >= 'a' && c <= 'z')
+ six = c - 'a' + 26;
+ else if (c >= '0' && c <= '9')
+ six = c - '0' + 52;
+ else if (c == '+')
+ six = 62;
+ else if (c == '/')
+ six = 63;
+ else
+ return;
+
+ /* Accumulate bytes */
+ switch (screen->base64_count) {
+ case 0:
+ screen->base64_accu = six;
+ screen->base64_count = 6;
+ break;
+
+ case 2:
+ ch = (screen->base64_accu << 6) + six;
+ screen->base64_count = 0;
+ AppendStrToSelectionBuffer(&ch, 1);
+ break;
+
+ case 4:
+ ch = (screen->base64_accu << 4) + (six >> 2);
+ screen->base64_accu = (six & 0x3);
+ screen->base64_count = 2;
+ AppendStrToSelectionBuffer(&ch, 1);
+ break;
+
+ case 6:
+ ch = (screen->base64_accu << 2) + (six >> 4);
+ screen->base64_accu = (six & 0xF);
+ screen->base64_count = 4;
+ AppendStrToSelectionBuffer(&ch, 1);
+ break;
+ }
+}
+
+void
+CompleteSelection(char **args, Cardinal len)
+{
+ term->screen.base64_count = 0;
+ term->screen.base64_accu = 0;
+ _OwnSelection(term, args, len);
+}
+#endif /* OPT_PASTE64 */
+
+static Bool
+_ConvertSelectionHelper(Widget w,
+ Atom * type, XtPointer *value,
+ unsigned long *length, int *format,
+ int (*conversion_function) (Display *,
+ char **, int,
+ XICCEncodingStyle,
+ XTextProperty *),
+ XICCEncodingStyle conversion_style)
+{
+ Display *d = XtDisplay(w);
+ TScreen *screen;
+ XTextProperty textprop;
+
+ if (!IsXtermWidget(w))
+ return False;
+
+ screen = &((XtermWidget) w)->screen;
+
+ if (conversion_function(d, (char **) &screen->selection_data, 1,
+ conversion_style,
+ &textprop) < Success)
+ return False;
+ *value = (XtPointer) textprop.value;
+ *length = textprop.nitems;
+ *type = textprop.encoding;
+ *format = textprop.format;
+ return True;
+}
+
+static Boolean
+ConvertSelection(Widget w,
+ Atom * selection,
+ Atom * target,
+ Atom * type,
+ XtPointer *value,
+ unsigned long *length,
+ int *format)
+{
+ Display *d = XtDisplay(w);
+ TScreen *screen;
+ Bool result = False;
+
+ if (!IsXtermWidget(w))
+ return False;
+
+ screen = &((XtermWidget) w)->screen;
+
+ if (screen->selection_data == NULL)
+ return False; /* can this happen? */
+
+ if (*target == XA_TARGETS(d)) {
+ Atom *targetP;
+ Atom *std_targets;
+ XPointer std_return = 0;
+ unsigned long std_length;
+ if (XmuConvertStandardSelection(w, screen->selection_time, selection,
+ target, type, &std_return,
+ &std_length, format)) {
+ std_targets = (Atom *) (std_return);
+ *length = std_length + 6;
+ targetP = (Atom *) XtMalloc(sizeof(Atom) * (*length));
+ *value = (XtPointer) targetP;
+ *targetP++ = XA_STRING;
+ *targetP++ = XA_TEXT(d);
+#ifdef X_HAVE_UTF8_STRING
+ *targetP++ = XA_COMPOUND_TEXT(d);
+ *targetP++ = XA_UTF8_STRING(d);
+#else
+ *targetP = XA_COMPOUND_TEXT(d);
+ if_OPT_WIDE_CHARS(screen, {
+ *targetP = XA_UTF8_STRING(d);
+ });
+ targetP++;
+#endif
+ *targetP++ = XA_LENGTH(d);
+ *targetP++ = XA_LIST_LENGTH(d);
+ memcpy(targetP, std_targets, sizeof(Atom) * std_length);
+ XtFree((char *) std_targets);
+ *type = XA_ATOM;
+ *format = 32;
+ result = True;
+ }
+ }
+#if OPT_WIDE_CHARS
+ else if (screen->wide_chars && *target == XA_STRING) {
+ result =
+ _ConvertSelectionHelper(w,
+ type, value, length, format,
+ Xutf8TextListToTextProperty,
+ XStringStyle);
+ } else if (screen->wide_chars && *target == XA_UTF8_STRING(d)) {
+ result =
+ _ConvertSelectionHelper(w,
+ type, value, length, format,
+ Xutf8TextListToTextProperty,
+ XUTF8StringStyle);
+ } else if (screen->wide_chars && *target == XA_TEXT(d)) {
+ result =
+ _ConvertSelectionHelper(w,
+ type, value, length, format,
+ Xutf8TextListToTextProperty,
+ XStdICCTextStyle);
+ } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(d)) {
+ result =
+ _ConvertSelectionHelper(w,
+ type, value, length, format,
+ Xutf8TextListToTextProperty,
+ XCompoundTextStyle);
+ }
+#endif
+
+ else if (*target == XA_STRING) { /* not wide_chars */
+ /* We can only reach this point if the selection requestor
+ requested STRING before any of TEXT, COMPOUND_TEXT or
+ UTF8_STRING. We therefore assume that the requestor is not
+ properly internationalised, and dump raw eight-bit data
+ with no conversion into the selection. Yes, this breaks
+ the ICCCM in non-Latin-1 locales. */
+ *type = XA_STRING;
+ *value = (XtPointer) screen->selection_data;
+ *length = screen->selection_length;
+ *format = 8;
+ result = True;
+ } else if (*target == XA_TEXT(d)) { /* not wide_chars */
+ result =
+ _ConvertSelectionHelper(w,
+ type, value, length, format,
+ XmbTextListToTextProperty,
+ XStdICCTextStyle);
+ } else if (*target == XA_COMPOUND_TEXT(d)) { /* not wide_chars */
+ result =
+ _ConvertSelectionHelper(w,
+ type, value, length, format,
+ XmbTextListToTextProperty,
+ XCompoundTextStyle);
+ }
+#ifdef X_HAVE_UTF8_STRING
+ else if (*target == XA_UTF8_STRING(d)) { /* not wide_chars */
+ result =
+ _ConvertSelectionHelper(w,
+ type, value, length, format,
+ XmbTextListToTextProperty,
+ XUTF8StringStyle);
+ }
+#endif
+ else if (*target == XA_LIST_LENGTH(d)) {
+ *value = XtMalloc(4);
+ if (sizeof(long) == 4)
+ *(long *) *value = 1;
+ else {
+ long temp = 1;
+ memcpy((char *) *value, ((char *) &temp) + sizeof(long) - 4, 4);
+ }
+ *type = XA_INTEGER;
+ *length = 1;
+ *format = 32;
+ result = True;
+ } else if (*target == XA_LENGTH(d)) {
+ /* This value is wrong if we have UTF-8 text */
+ *value = XtMalloc(4);
+ if (sizeof(long) == 4) {
+ *(long *) *value = screen->selection_length;
+ } else {
+ long temp = screen->selection_length;
+ memcpy((char *) *value, ((char *) &temp) + sizeof(long) - 4, 4);
+ }
+ *type = XA_INTEGER;
+ *length = 1;
+ *format = 32;
+ result = True;
+ } else if (XmuConvertStandardSelection(w,
+ screen->selection_time, selection,
+ target, type, (XPointer *) value,
+ length, format)) {
+ result = True;
+ }
+
+ /* else */
+ return result;
+}
+
+static void
+LoseSelection(Widget w, Atom * selection)
+{
+ TScreen *screen;
+ Atom *atomP;
+ Cardinal i;
+
+ if (!IsXtermWidget(w))
+ return;
+
+ screen = &((XtermWidget) w)->screen;
+ for (i = 0, atomP = screen->selection_atoms;
+ i < screen->selection_count; i++, atomP++) {
+ if (*selection == *atomP)
+ *atomP = (Atom) 0;
+ if (CutBuffer(*atomP) >= 0) {
+ *atomP = (Atom) 0;
+ }
+ }
+
+ for (i = screen->selection_count; i; i--) {
+ if (screen->selection_atoms[i - 1] != 0)
+ break;
+ }
+ screen->selection_count = i;
+
+ for (i = 0, atomP = screen->selection_atoms;
+ i < screen->selection_count; i++, atomP++) {
+ if (*atomP == (Atom) 0) {
+ *atomP = screen->selection_atoms[--screen->selection_count];
+ }
+ }
+
+ if (screen->selection_count == 0)
+ TrackText(0, 0, 0, 0);
+}
+
+/* ARGSUSED */
+static void
+SelectionDone(Widget w GCC_UNUSED,
+ Atom * selection GCC_UNUSED,
+ Atom * target GCC_UNUSED)
+{
+ /* empty proc so Intrinsics know we want to keep storage */
+}
+
+static void
+_OwnSelection(XtermWidget termw,
+ String * selections,
+ Cardinal count)
+{
+ Atom *atoms = termw->screen.selection_atoms;
+ Cardinal i;
+ Bool have_selection = False;
+
+ if (termw->screen.selection_length < 0)
+ return;
+
+ if (count > termw->screen.sel_atoms_size) {
+ XtFree((char *) atoms);
+ atoms = (Atom *) XtMalloc(count * sizeof(Atom));
+ termw->screen.selection_atoms = atoms;
+ termw->screen.sel_atoms_size = count;
+ }
+ XmuInternStrings(XtDisplay((Widget) termw), selections, count, atoms);
+ for (i = 0; i < count; i++) {
+ int cutbuffer = CutBuffer(atoms[i]);
+ if (cutbuffer >= 0) {
+ if (termw->screen.selection_length >
+ 4 * XMaxRequestSize(XtDisplay((Widget) termw)) - 32) {
+ fprintf(stderr,
+ "%s: selection too big (%d bytes), not storing in CUT_BUFFER%d\n",
+ xterm_name, termw->screen.selection_length, cutbuffer);
+ } else {
+ /* This used to just use the UTF-8 data, which was totally
+ * broken as not even the corresponding paste code in Xterm
+ * understood this! So now it converts to Latin1 first.
+ * Robert Brady, 2000-09-05
+ */
+ unsigned long length = termw->screen.selection_length;
+ Char *data = termw->screen.selection_data;
+ if_OPT_WIDE_CHARS((&(termw->screen)), {
+ data = UTF8toLatin1(data, length, &length);
+ });
+ TRACE(("XStoreBuffer(%d)\n", cutbuffer));
+ XStoreBuffer(XtDisplay((Widget) termw),
+ (char *) data,
+ (int) length,
+ cutbuffer);
+ }
+ } else if (!replyToEmacs) {
+ have_selection |=
+ XtOwnSelection((Widget) termw, atoms[i],
+ termw->screen.selection_time,
+ ConvertSelection, LoseSelection, SelectionDone);
+ }
+ }
+ if (!replyToEmacs)
+ termw->screen.selection_count = count;
+ if (!have_selection)
+ TrackText(0, 0, 0, 0);
+}
+
+static void
+ResetSelectionState(TScreen * screen)
+{
+ screen->selection_count = 0;
+ screen->startHRow = screen->startHCol = 0;
+ screen->endHRow = screen->endHCol = 0;
+}
+
+void
+DisownSelection(XtermWidget termw)
+{
+ TScreen *screen = &(termw->screen);
+ Atom *atoms = screen->selection_atoms;
+ Cardinal count = screen->selection_count;
+ Cardinal i;
+
+ TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n",
+ count,
+ screen->startHRow,
+ screen->startHCol,
+ screen->endHRow,
+ screen->endHCol));
+
+ for (i = 0; i < count; i++) {
+ int cutbuffer = CutBuffer(atoms[i]);
+ if (cutbuffer < 0) {
+ XtDisownSelection((Widget) termw, atoms[i],
+ screen->selection_time);
+ }
+ }
+ /*
+ * If none of the callbacks via XtDisownSelection() reset highlighting
+ * do it now.
+ */
+ if (ScrnHaveSelection(screen)) {
+ /* save data which will be reset */
+ int start_row = screen->startHRow;
+ int start_col = screen->startHCol;
+ int end_row = screen->endHRow;
+ int end_col = screen->endHCol;
+
+ ResetSelectionState(screen);
+ ReHiliteText(start_row, start_col, end_row, end_col);
+ } else {
+ ResetSelectionState(screen);
+ }
+}
+
+/* returns number of chars in line from scol to ecol out */
+/* ARGSUSED */
+static int
+Length(TScreen * screen GCC_UNUSED,
+ int row,
+ int scol,
+ int ecol)
+{
+ int lastcol = LastTextCol(row);
+
+ if (ecol > lastcol)
+ ecol = lastcol;
+ return (ecol - scol + 1);
+}
+
+/* copies text into line, preallocated */
+static Char *
+SaveText(TScreen * screen,
+ int row,
+ int scol,
+ int ecol,
+ Char * lp, /* pointer to where to put the text */
+ int *eol)
+{
+ int i = 0;
+ unsigned c;
+ Char *result = lp;
+#if OPT_WIDE_CHARS
+ int previous = 0;
+ unsigned c_1 = 0, c_2 = 0;
+#endif
+
+ i = Length(screen, row, scol, ecol);
+ ecol = scol + i;
+#if OPT_DEC_CHRSET
+ if (CSET_DOUBLE(SCRN_BUF_CSETS(screen, row + screen->topline)[0])) {
+ scol = (scol + 0) / 2;
+ ecol = (ecol + 1) / 2;
+ }
+#endif
+ *eol = !ScrnTstWrapped(screen, row);
+ for (i = scol; i < ecol; i++) {
+ c = E2A(XTERM_CELL(row, i));
+#if OPT_WIDE_CHARS
+ if (screen->utf8_mode != uFalse) {
+ c_1 = E2A(XTERM_CELL_C1(row, i));
+ c_2 = E2A(XTERM_CELL_C2(row, i));
+ }
+
+ /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a
+ * wide character.
+ */
+ if (c == HIDDEN_CHAR && iswide(previous)) {
+ previous = c;
+ /* Combining characters attached to double-width characters
+ are in memory attached to the HIDDEN_CHAR */
+ if (c_1) {
+ lp = convertToUTF8(lp, c_1);
+ if (c_2)
+ lp = convertToUTF8(lp, c_2);
+ }
+ continue;
+ }
+ previous = c;
+ if (screen->utf8_mode != uFalse) {
+ lp = convertToUTF8(lp, (c != 0) ? c : ' ');
+ if (c_1) {
+ lp = convertToUTF8(lp, c_1);
+ if (c_2)
+ lp = convertToUTF8(lp, c_2);
+ }
+ } else
+#endif
+ {
+ if (c == 0) {
+ c = E2A(' ');
+ } else if (c < E2A(' ')) {
+ if (c == XPOUND)
+ c = 0x23; /* char on screen is pound sterling */
+ else
+ c += 0x5f; /* char is from DEC drawing set */
+ } else if (c == 0x7f) {
+ c = 0x5f;
+ }
+ *lp++ = A2E(c);
+ }
+ if (c != E2A(' '))
+ result = lp;
+ }
+
+ /*
+ * If requested, trim trailing blanks from selected lines. Do not do this
+ * if the line is wrapped.
+ */
+ if (!*eol || !screen->trim_selection)
+ result = lp;
+
+ return (result);
+}
+
+/* 32 + following 7-bit word:
+
+ 1:0 Button no: 0, 1, 2. 3=release.
+ 2 shift
+ 3 meta
+ 4 ctrl
+ 5 set for motion notify
+ 6 set for wheel
+*/
+
+/* Position: 32 - 255. */
+
+static int
+BtnCode(XButtonEvent * event, int button)
+{
+ int result = 32 + (KeyState(event->state) << 2);
+
+ if (button < 0 || button > 5) {
+ result += 3;
+ } else {
+ if (button > 3)
+ result += (64 - 4);
+ if (event->type == MotionNotify)
+ result += 32;
+ result += button;
+ }
+ return result;
+}
+
+#define MOUSE_LIMIT (255 - 32)
+
+static void
+EditorButton(XButtonEvent * event)
+{
+ TScreen *screen = &term->screen;
+ int pty = screen->respond;
+ Char line[6];
+ int row, col;
+ int button;
+ unsigned count = 0;
+
+ /* If button event, get button # adjusted for DEC compatibility */
+ button = event->button - 1;
+ if (button >= 3)
+ button++;
+
+ /* Compute character position of mouse pointer */
+ row = (event->y - screen->border) / FontHeight(screen);
+ col = (event->x - OriginX(screen)) / FontWidth(screen);
+
+ /* Limit to screen dimensions */
+ if (row < 0)
+ row = 0;
+ else if (row > screen->max_row)
+ row = screen->max_row;
+ else if (row > MOUSE_LIMIT)
+ row = MOUSE_LIMIT;
+
+ if (col < 0)
+ col = 0;
+ else if (col > screen->max_col)
+ col = screen->max_col;
+ else if (col > MOUSE_LIMIT)
+ col = MOUSE_LIMIT;
+
+ /* Build key sequence starting with \E[M */
+ if (screen->control_eight_bits) {
+ line[count++] = CSI;
+ } else {
+ line[count++] = ESC;
+ line[count++] = '[';
+ }
+ line[count++] = 'M';
+
+ /* Add event code to key sequence */
+ if (screen->send_mouse_pos == X10_MOUSE) {
+ line[count++] = ' ' + button;
+ } else {
+ /* Button-Motion events */
+ switch (event->type) {
+ case ButtonPress:
+ line[count++] = BtnCode(event, screen->mouse_button = button);
+ break;
+ case ButtonRelease:
+ /*
+ * Wheel mouse interface generates release-events for buttons
+ * 4 and 5, coded here as 3 and 4 respectively. We change the
+ * release for buttons 1..3 to a -1.
+ */
+ if (button < 3)
+ button = -1;
+ line[count++] = BtnCode(event, screen->mouse_button = button);
+ break;
+ case MotionNotify:
+ /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion
+ * events only if character cell has changed.
+ */
+ if ((row == screen->mouse_row)
+ && (col == screen->mouse_col))
+ return;
+ line[count++] = BtnCode(event, screen->mouse_button);
+ break;
+ default:
+ return;
+ }
+ }
+
+ screen->mouse_row = row;
+ screen->mouse_col = col;
+
+ /* Add pointer position to key sequence */
+ line[count++] = ' ' + col + 1;
+ line[count++] = ' ' + row + 1;
+
+ TRACE(("mouse at %d,%d button+mask = %#x\n", row, col,
+ (screen->control_eight_bits) ? line[2] : line[3]));
+
+ /* Transmit key sequence to process running under xterm */
+ v_write(pty, line, count);
+}
+
+/*ARGSUSED*/
+#if OPT_TEK4014
+void
+HandleGINInput(Widget w GCC_UNUSED,
+ XEvent * event GCC_UNUSED,
+ String * param_list,
+ Cardinal *nparamsp)
+{
+ if (term->screen.TekGIN && *nparamsp == 1) {
+ int c = param_list[0][0];
+ switch (c) {
+ case 'l':
+ case 'm':
+ case 'r':
+ case 'L':
+ case 'M':
+ case 'R':
+ break;
+ default:
+ Bell(XkbBI_MinorError, 0); /* let them know they goofed */
+ c = 'l'; /* provide a default */
+ }
+ TekEnqMouse(c | 0x80);
+ TekGINoff();
+ } else {
+ Bell(XkbBI_MinorError, 0);
+ }
+}
+#endif /* OPT_TEK4014 */
+
+/* ARGSUSED */
+void
+HandleSecure(Widget w GCC_UNUSED,
+ XEvent * event, /* unused */
+ String * params GCC_UNUSED, /* [0] = volume */
+ Cardinal *param_count GCC_UNUSED) /* 0 or 1 */
+{
+ Time ev_time = CurrentTime;
+
+ if ((event->xany.type == KeyPress) ||
+ (event->xany.type == KeyRelease))
+ ev_time = event->xkey.time;
+ else if ((event->xany.type == ButtonPress) ||
+ (event->xany.type == ButtonRelease))
+ ev_time = event->xbutton.time;
+ DoSecureKeyboard(ev_time);
+}