button.c revision f2e35a3a
1f2e35a3aSmrg/* $XTermId: button.c,v 1.636 2021/02/10 01:14:51 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4f2e35a3aSmrg * Copyright 1999-2020,2021 by Thomas E. Dickey 5d522f475Smrg * 6d522f475Smrg * All Rights Reserved 7d522f475Smrg * 8d522f475Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9d522f475Smrg * copy of this software and associated documentation files (the 10d522f475Smrg * "Software"), to deal in the Software without restriction, including 11d522f475Smrg * without limitation the rights to use, copy, modify, merge, publish, 12d522f475Smrg * distribute, sublicense, and/or sell copies of the Software, and to 13d522f475Smrg * permit persons to whom the Software is furnished to do so, subject to 14d522f475Smrg * the following conditions: 15d522f475Smrg * 16d522f475Smrg * The above copyright notice and this permission notice shall be included 17d522f475Smrg * in all copies or substantial portions of the Software. 18d522f475Smrg * 19d522f475Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20d522f475Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21d522f475Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22d522f475Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23d522f475Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24d522f475Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25d522f475Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26d522f475Smrg * 27d522f475Smrg * Except as contained in this notice, the name(s) of the above copyright 28d522f475Smrg * holders shall not be used in advertising or otherwise to promote the 29d522f475Smrg * sale, use or other dealings in this Software without prior written 30d522f475Smrg * authorization. 31d522f475Smrg * 32d522f475Smrg * 33d522f475Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 34d522f475Smrg * 35d522f475Smrg * All Rights Reserved 36d522f475Smrg * 37d522f475Smrg * Permission to use, copy, modify, and distribute this software and its 38d522f475Smrg * documentation for any purpose and without fee is hereby granted, 39d522f475Smrg * provided that the above copyright notice appear in all copies and that 40d522f475Smrg * both that copyright notice and this permission notice appear in 41d522f475Smrg * supporting documentation, and that the name of Digital Equipment 42d522f475Smrg * Corporation not be used in advertising or publicity pertaining to 43d522f475Smrg * distribution of the software without specific, written prior permission. 44d522f475Smrg * 45d522f475Smrg * 46d522f475Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 47d522f475Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 48d522f475Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 49d522f475Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 50d522f475Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 51d522f475Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 52d522f475Smrg * SOFTWARE. 53d522f475Smrg */ 54d522f475Smrg 55d522f475Smrg/* 56d522f475Smrgbutton.c Handles button events in the terminal emulator. 57d522f475Smrg does cut/paste operations, change modes via menu, 58d522f475Smrg passes button events through to some applications. 59d522f475Smrg J. Gettys. 60d522f475Smrg*/ 61d522f475Smrg 62d522f475Smrg#include <xterm.h> 63d522f475Smrg 64d522f475Smrg#include <stdio.h> 650bd37d32Smrg#include <ctype.h> 6620d2c4d2Smrg#include <assert.h> 67d522f475Smrg 68d522f475Smrg#include <X11/Xatom.h> 69d522f475Smrg#include <X11/Xmu/Atoms.h> 70d522f475Smrg#include <X11/Xmu/StdSel.h> 71d522f475Smrg 72d522f475Smrg#include <xutf8.h> 73d522f475Smrg#include <fontutils.h> 74d522f475Smrg 75d522f475Smrg#include <data.h> 76d522f475Smrg#include <error.h> 77d522f475Smrg#include <menu.h> 78d522f475Smrg#include <charclass.h> 79d522f475Smrg#include <xstrings.h> 80d522f475Smrg 81d522f475Smrg#if OPT_SELECT_REGEX 82f2e35a3aSmrg#ifdef HAVE_PCRE2POSIX_H 83f2e35a3aSmrg#include <pcre2posix.h> 84f2e35a3aSmrg#else 85d522f475Smrg#ifdef HAVE_PCREPOSIX_H 86d522f475Smrg#include <pcreposix.h> 87d522f475Smrg#else /* POSIX regex.h */ 88d522f475Smrg#include <sys/types.h> 89d522f475Smrg#include <regex.h> 90d522f475Smrg#endif 91d522f475Smrg#endif 92f2e35a3aSmrg#endif 93f2e35a3aSmrg 94f2e35a3aSmrg#ifdef HAVE_X11_TRANSLATEI_H 95f2e35a3aSmrg#include <X11/ConvertI.h> 96f2e35a3aSmrg#include <X11/TranslateI.h> 97f2e35a3aSmrg#else 98f2e35a3aSmrgextern String _XtPrintXlations(Widget w, 99f2e35a3aSmrg XtTranslations xlations, 100f2e35a3aSmrg Widget accelWidget, 101f2e35a3aSmrg _XtBoolean includeRHS); 102f2e35a3aSmrg#endif 103f2e35a3aSmrg 104f2e35a3aSmrg#define PRIMARY_NAME "PRIMARY" 105f2e35a3aSmrg#define CLIPBOARD_NAME "CLIPBOARD" 106f2e35a3aSmrg#define SECONDARY_NAME "SECONDARY" 107f2e35a3aSmrg 108f2e35a3aSmrg#define AtomToSelection(d,n) \ 109f2e35a3aSmrg (((n) == XA_CLIPBOARD(d)) \ 110f2e35a3aSmrg ? CLIPBOARD_CODE \ 111f2e35a3aSmrg : (((n) == XA_SECONDARY) \ 112f2e35a3aSmrg ? SECONDARY_CODE \ 113f2e35a3aSmrg : PRIMARY_CODE)) 114f2e35a3aSmrg 115f2e35a3aSmrg#define isSelectionCode(n) ((n) >= PRIMARY_CODE) 116f2e35a3aSmrg#define CutBufferToCode(n) ((n) + MAX_SELECTION_CODES) 117f2e35a3aSmrg#define okSelectionCode(n) (isSelectionCode(n) ? (n) : PRIMARY_CODE) 118d522f475Smrg 119d522f475Smrg#if OPT_WIDE_CHARS 120d522f475Smrg#include <ctype.h> 121d522f475Smrg#include <wcwidth.h> 122d522f475Smrg#else 123d522f475Smrg#define CharacterClass(value) \ 124f2e35a3aSmrg charClass[(value) & (int)((sizeof(charClass)/sizeof(charClass[0]))-1)] 125d522f475Smrg#endif 126d522f475Smrg 127956cc18dSsnj /* 128956cc18dSsnj * We'll generally map rows to indices when doing selection. 129956cc18dSsnj * Simplify that with a macro. 130956cc18dSsnj * 131956cc18dSsnj * Note that ROW2INX() is safe to use with auto increment/decrement for 132956cc18dSsnj * the row expression since that is evaluated once. 133956cc18dSsnj */ 134956cc18dSsnj#define GET_LINEDATA(screen, row) \ 135956cc18dSsnj getLineData(screen, ROW2INX(screen, row)) 136956cc18dSsnj 137f2e35a3aSmrg#define MaxMouseBtn 5 138492d43a5Smrg 139492d43a5Smrg#define IsBtnEvent(event) ((event)->type == ButtonPress || (event)->type == ButtonRelease) 1400bd37d32Smrg#define IsKeyEvent(event) ((event)->type == KeyPress || (event)->type == KeyRelease) 141d522f475Smrg 142d522f475Smrg#define Coordinate(s,c) ((c)->row * MaxCols(s) + (c)->col) 143d522f475Smrg 144d522f475Smrgstatic const CELL zeroCELL = 145d522f475Smrg{0, 0}; 146d522f475Smrg 147d522f475Smrg#if OPT_DEC_LOCATOR 148894e0ac8Smrgstatic Bool SendLocatorPosition(XtermWidget xw, XButtonEvent *event); 149894e0ac8Smrgstatic void CheckLocatorPosition(XtermWidget xw, XButtonEvent *event); 150d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 151d522f475Smrg 152d522f475Smrg/* Multi-click handling */ 153d522f475Smrg#if OPT_READLINE 154d522f475Smrgstatic Time lastButtonDownTime = 0; 155d522f475Smrgstatic int ExtendingSelection = 0; 156d522f475Smrgstatic Time lastButton3UpTime = 0; 157d522f475Smrgstatic Time lastButton3DoubleDownTime = 0; 158d522f475Smrgstatic CELL lastButton3; /* At the release time */ 159d522f475Smrg#endif /* OPT_READLINE */ 160d522f475Smrg 161e0a2b6dfSmrgstatic Char *SaveText(TScreen *screen, int row, int scol, int ecol, 162e0a2b6dfSmrg Char *lp, int *eol); 163e0a2b6dfSmrgstatic int Length(TScreen *screen, int row, int scol, int ecol); 164f2e35a3aSmrgstatic void ComputeSelect(XtermWidget xw, CELL *startc, CELL *endc, Bool 165f2e35a3aSmrg extend, Bool normal); 166894e0ac8Smrgstatic void EditorButton(XtermWidget xw, XButtonEvent *event); 167894e0ac8Smrgstatic void EndExtend(XtermWidget w, XEvent *event, String *params, Cardinal 168d522f475Smrg num_params, Bool use_cursor_loc); 169e0a2b6dfSmrgstatic void ExtendExtend(XtermWidget xw, const CELL *cell); 170e0a2b6dfSmrgstatic void PointToCELL(TScreen *screen, int y, int x, CELL *cell); 171e0a2b6dfSmrgstatic void ReHiliteText(XtermWidget xw, CELL *first, CELL *last); 172f2e35a3aSmrgstatic void SaltTextAway(XtermWidget xw, int which, CELL *cellc, CELL *cell); 173894e0ac8Smrgstatic void SelectSet(XtermWidget xw, XEvent *event, String *params, Cardinal num_params); 174d522f475Smrgstatic void SelectionReceived PROTO_XT_SEL_CB_ARGS; 175e0a2b6dfSmrgstatic void StartSelect(XtermWidget xw, const CELL *cell); 176894e0ac8Smrgstatic void TrackDown(XtermWidget xw, XButtonEvent *event); 177e0a2b6dfSmrgstatic void TrackText(XtermWidget xw, const CELL *first, const CELL *last); 178f2e35a3aSmrgstatic void UnHiliteText(XtermWidget xw); 179e0a2b6dfSmrgstatic void _OwnSelection(XtermWidget xw, String *selections, Cardinal count); 180894e0ac8Smrgstatic void do_select_end(XtermWidget xw, XEvent *event, String *params, 181d522f475Smrg Cardinal *num_params, Bool use_cursor_loc); 182d522f475Smrg 183492d43a5Smrg#define MOUSE_LIMIT (255 - 32) 184d522f475Smrg 185492d43a5Smrg/* Send SET_EXT_SIZE_MOUSE to enable offsets up to EXT_MOUSE_LIMIT */ 186492d43a5Smrg#define EXT_MOUSE_LIMIT (2047 - 32) 187492d43a5Smrg#define EXT_MOUSE_START (127 - 32) 188d522f475Smrg 1890bd37d32Smrgstatic int 190e0a2b6dfSmrgMouseLimit(TScreen *screen) 1910bd37d32Smrg{ 1920bd37d32Smrg int mouse_limit; 1930bd37d32Smrg 1940bd37d32Smrg switch (screen->extend_coords) { 1950bd37d32Smrg default: 1960bd37d32Smrg mouse_limit = MOUSE_LIMIT; 1970bd37d32Smrg break; 1980bd37d32Smrg case SET_EXT_MODE_MOUSE: 1990bd37d32Smrg mouse_limit = EXT_MOUSE_LIMIT; 2000bd37d32Smrg break; 2010bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 2020bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 203f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 2040bd37d32Smrg mouse_limit = -1; 2050bd37d32Smrg break; 2060bd37d32Smrg } 2070bd37d32Smrg return mouse_limit; 2080bd37d32Smrg} 2090bd37d32Smrg 210492d43a5Smrgstatic unsigned 211e0a2b6dfSmrgEmitMousePosition(TScreen *screen, Char line[], unsigned count, int value) 212492d43a5Smrg{ 2130bd37d32Smrg int mouse_limit = MouseLimit(screen); 214492d43a5Smrg 215492d43a5Smrg /* 216492d43a5Smrg * Add pointer position to key sequence 217492d43a5Smrg * 218492d43a5Smrg * In extended mode we encode large positions as two-byte UTF-8. 219492d43a5Smrg * 220492d43a5Smrg * NOTE: historically, it was possible to emit 256, which became 221492d43a5Smrg * zero by truncation to 8 bits. While this was arguably a bug, 222492d43a5Smrg * it's also somewhat useful as a past-end marker. We preserve 223492d43a5Smrg * this behavior for both normal and extended mouse modes. 224492d43a5Smrg */ 2250bd37d32Smrg switch (screen->extend_coords) { 2260bd37d32Smrg default: 2270bd37d32Smrg if (value == mouse_limit) { 2280bd37d32Smrg line[count++] = CharOf(0); 2290bd37d32Smrg } else { 2300bd37d32Smrg line[count++] = CharOf(' ' + value + 1); 2310bd37d32Smrg } 2320bd37d32Smrg break; 2330bd37d32Smrg case SET_EXT_MODE_MOUSE: 2340bd37d32Smrg if (value == mouse_limit) { 2350bd37d32Smrg line[count++] = CharOf(0); 2360bd37d32Smrg } else if (value < EXT_MOUSE_START) { 2370bd37d32Smrg line[count++] = CharOf(' ' + value + 1); 2380bd37d32Smrg } else { 2390bd37d32Smrg value += ' ' + 1; 2400bd37d32Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 2410bd37d32Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 2420bd37d32Smrg } 2430bd37d32Smrg break; 2440bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 2450bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 246f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 2470bd37d32Smrg count += (unsigned) sprintf((char *) line + count, "%d", value + 1); 2480bd37d32Smrg break; 2490bd37d32Smrg } 2500bd37d32Smrg return count; 2510bd37d32Smrg} 2520bd37d32Smrg 2530bd37d32Smrgstatic unsigned 254e0a2b6dfSmrgEmitMousePositionSeparator(TScreen *screen, Char line[], unsigned count) 2550bd37d32Smrg{ 2560bd37d32Smrg switch (screen->extend_coords) { 2570bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 2580bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 259f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 2600bd37d32Smrg line[count++] = ';'; 2610bd37d32Smrg break; 262d522f475Smrg } 263492d43a5Smrg return count; 264492d43a5Smrg} 265d522f475Smrg 266f2e35a3aSmrgenum { 267f2e35a3aSmrg scanMods, 268f2e35a3aSmrg scanKey, 269f2e35a3aSmrg scanColon, 270f2e35a3aSmrg scanFunc, 271f2e35a3aSmrg scanArgs 272f2e35a3aSmrg}; 273f2e35a3aSmrg 274f2e35a3aSmrg#if OPT_TRACE > 1 275f2e35a3aSmrgstatic const char * 276f2e35a3aSmrgvisibleScan(int mode) 277f2e35a3aSmrg{ 278f2e35a3aSmrg const char *result = "?"; 279f2e35a3aSmrg#define DATA(name) case name: result = #name; break 280f2e35a3aSmrg switch (mode) { 281f2e35a3aSmrg DATA(scanMods); 282f2e35a3aSmrg DATA(scanKey); 283f2e35a3aSmrg DATA(scanColon); 284f2e35a3aSmrg DATA(scanFunc); 285f2e35a3aSmrg DATA(scanArgs); 286f2e35a3aSmrg } 287f2e35a3aSmrg#undef DATA 288f2e35a3aSmrg return result; 289f2e35a3aSmrg} 290f2e35a3aSmrg#endif 291f2e35a3aSmrg 292f2e35a3aSmrg#define L_BRACK '<' 293f2e35a3aSmrg#define R_BRACK '>' 294f2e35a3aSmrg#define L_PAREN '(' 295f2e35a3aSmrg#define R_PAREN ')' 296f2e35a3aSmrg 297f2e35a3aSmrgstatic char * 298f2e35a3aSmrgscanTrans(char *source, int *this_is, int *next_is, unsigned *first, unsigned *last) 299f2e35a3aSmrg{ 300f2e35a3aSmrg char ch; 301f2e35a3aSmrg char *target = source; 302f2e35a3aSmrg 303f2e35a3aSmrg *first = *last = 0; 304f2e35a3aSmrg if (IsEmpty(target)) { 305f2e35a3aSmrg target = 0; 306f2e35a3aSmrg } else { 307f2e35a3aSmrg do { 308f2e35a3aSmrg while (IsSpace(*target)) 309f2e35a3aSmrg target++; 310f2e35a3aSmrg *first = (unsigned) (target - source); 311f2e35a3aSmrg switch (*this_is = *next_is) { 312f2e35a3aSmrg case scanMods: 313f2e35a3aSmrg while ((ch = *target)) { 314f2e35a3aSmrg if (IsSpace(ch)) { 315f2e35a3aSmrg break; 316f2e35a3aSmrg } else if (ch == L_BRACK) { 317f2e35a3aSmrg *next_is = scanKey; 318f2e35a3aSmrg break; 319f2e35a3aSmrg } else if (ch == ':') { 320f2e35a3aSmrg *next_is = scanColon; 321f2e35a3aSmrg break; 322f2e35a3aSmrg } else if (ch == '~' && target != source) { 323f2e35a3aSmrg break; 324f2e35a3aSmrg } 325f2e35a3aSmrg target++; 326f2e35a3aSmrg } 327f2e35a3aSmrg break; 328f2e35a3aSmrg case scanKey: 329f2e35a3aSmrg while ((ch = *target)) { 330f2e35a3aSmrg if (IsSpace(ch)) { 331f2e35a3aSmrg break; 332f2e35a3aSmrg } else if (ch == ':') { 333f2e35a3aSmrg *next_is = scanColon; 334f2e35a3aSmrg break; 335f2e35a3aSmrg } 336f2e35a3aSmrg target++; 337f2e35a3aSmrg if (ch == R_BRACK) 338f2e35a3aSmrg break; 339f2e35a3aSmrg } 340f2e35a3aSmrg break; 341f2e35a3aSmrg case scanColon: 342f2e35a3aSmrg *next_is = scanFunc; 343f2e35a3aSmrg target++; 344f2e35a3aSmrg break; 345f2e35a3aSmrg case scanFunc: 346f2e35a3aSmrg while ((ch = *target)) { 347f2e35a3aSmrg if (IsSpace(ch)) { 348f2e35a3aSmrg break; 349f2e35a3aSmrg } else if (ch == L_PAREN) { 350f2e35a3aSmrg *next_is = scanArgs; 351f2e35a3aSmrg break; 352f2e35a3aSmrg } 353f2e35a3aSmrg target++; 354f2e35a3aSmrg } 355f2e35a3aSmrg break; 356f2e35a3aSmrg case scanArgs: 357f2e35a3aSmrg while ((ch = *target)) { 358f2e35a3aSmrg if (ch == R_PAREN) { 359f2e35a3aSmrg target++; 360f2e35a3aSmrg *next_is = scanFunc; 361f2e35a3aSmrg break; 362f2e35a3aSmrg } 363f2e35a3aSmrg target++; 364f2e35a3aSmrg } 365f2e35a3aSmrg break; 366f2e35a3aSmrg } 367f2e35a3aSmrg *last = (unsigned) (target - source); 368f2e35a3aSmrg if (*target == '\n') { 369f2e35a3aSmrg *next_is = scanMods; 370f2e35a3aSmrg target++; 371f2e35a3aSmrg } 372f2e35a3aSmrg } while (*first == *last); 373f2e35a3aSmrg } 374f2e35a3aSmrg return target; 375f2e35a3aSmrg} 376f2e35a3aSmrg 377f2e35a3aSmrgvoid 378f2e35a3aSmrgxtermButtonInit(XtermWidget xw) 379f2e35a3aSmrg{ 380f2e35a3aSmrg Widget w = (Widget) xw; 381f2e35a3aSmrg XErrorHandler save = XSetErrorHandler(ignore_x11_error); 382f2e35a3aSmrg XtTranslations xlations; 383f2e35a3aSmrg Widget xcelerat; 384f2e35a3aSmrg String result; 385f2e35a3aSmrg 386f2e35a3aSmrg XtVaGetValues(w, 387f2e35a3aSmrg XtNtranslations, &xlations, 388f2e35a3aSmrg XtNaccelerators, &xcelerat, 389f2e35a3aSmrg (XtPointer) 0); 390f2e35a3aSmrg result = _XtPrintXlations(w, xlations, xcelerat, True); 391f2e35a3aSmrg if (result) { 392f2e35a3aSmrg static const char *table[] = 393f2e35a3aSmrg { 394f2e35a3aSmrg "insert-selection", 395f2e35a3aSmrg "select-end", 396f2e35a3aSmrg "select-extend", 397f2e35a3aSmrg "select-start", 398f2e35a3aSmrg "start-extend", 399f2e35a3aSmrg }; 400f2e35a3aSmrg char *data = x_strdup(result); 401f2e35a3aSmrg char *next; 402f2e35a3aSmrg int state = scanMods; 403f2e35a3aSmrg int state2 = scanMods; 404f2e35a3aSmrg unsigned first; 405f2e35a3aSmrg unsigned last; 406f2e35a3aSmrg int have_button = -1; 407f2e35a3aSmrg Bool want_button = False; 408f2e35a3aSmrg Bool have_shift = False; 409f2e35a3aSmrg unsigned allowed = 0; 410f2e35a3aSmrg unsigned disallow = 0; 411f2e35a3aSmrg 412f2e35a3aSmrg TRACE(("xtermButtonInit length %ld\n", (long) strlen(result))); 413f2e35a3aSmrg xw->keyboard.print_translations = data; 414f2e35a3aSmrg while ((next = scanTrans(data, &state, &state2, &first, &last)) != 0) { 415f2e35a3aSmrg unsigned len = (last - first); 416f2e35a3aSmrg TRACE2(("parse %s:%d..%d '%.*s'\n", 417f2e35a3aSmrg visibleScan(state), first, last, 418f2e35a3aSmrg len, data + first)); 419f2e35a3aSmrg if (state == scanMods) { 420f2e35a3aSmrg if (len > 1 && data[first] == '~') { 421f2e35a3aSmrg len--; 422f2e35a3aSmrg first++; 423f2e35a3aSmrg } 424f2e35a3aSmrg if (len == 7 && !x_strncasecmp(data + first, "button", len - 1)) { 425f2e35a3aSmrg have_button = data[first + 6] - '0'; 426f2e35a3aSmrg } else if (len == 5 && !x_strncasecmp(data + first, "shift", len)) { 427f2e35a3aSmrg have_shift = True; 428f2e35a3aSmrg } 429f2e35a3aSmrg } else if (state == scanKey) { 430f2e35a3aSmrg if (!x_strncasecmp(data + first, "<buttonpress>", len) || 431f2e35a3aSmrg !x_strncasecmp(data + first, "<buttonrelease>", len)) { 432f2e35a3aSmrg want_button = True; 433f2e35a3aSmrg } else if (want_button) { 434f2e35a3aSmrg have_button = data[first] - '0'; 435f2e35a3aSmrg want_button = False; 436f2e35a3aSmrg } 437f2e35a3aSmrg } else if (state == scanFunc && have_button > 0) { 438f2e35a3aSmrg Cardinal n; 439f2e35a3aSmrg unsigned bmask = 1U << (have_button - 1); 440f2e35a3aSmrg for (n = 0; n < XtNumber(table); ++n) { 441f2e35a3aSmrg if (!x_strncasecmp(table[n], data + first, len)) { 442f2e35a3aSmrg TRACE(("...button %d: %s%s\n", 443f2e35a3aSmrg have_button, table[n], 444f2e35a3aSmrg have_shift ? " (disallow)" : "")); 445f2e35a3aSmrg if (have_shift) 446f2e35a3aSmrg disallow |= bmask; 447f2e35a3aSmrg else 448f2e35a3aSmrg allowed |= bmask; 449f2e35a3aSmrg break; 450f2e35a3aSmrg } 451f2e35a3aSmrg } 452f2e35a3aSmrg } 453f2e35a3aSmrg if (state2 == scanMods && state >= scanColon) { 454f2e35a3aSmrg have_button = -1; 455f2e35a3aSmrg want_button = False; 456f2e35a3aSmrg have_shift = False; 457f2e35a3aSmrg } 458f2e35a3aSmrg state = state2; 459f2e35a3aSmrg data = next; 460f2e35a3aSmrg } 461f2e35a3aSmrg XFree((char *) result); 462f2e35a3aSmrg xw->keyboard.shift_buttons = allowed & ~disallow; 463f2e35a3aSmrg#if OPT_TRACE 464f2e35a3aSmrg if (xw->keyboard.shift_buttons) { 465f2e35a3aSmrg int button = 0; 466f2e35a3aSmrg unsigned mask = xw->keyboard.shift_buttons; 467f2e35a3aSmrg TRACE(("...Buttons used for selection that can be overridden:")); 468f2e35a3aSmrg while (mask != 0) { 469f2e35a3aSmrg ++button; 470f2e35a3aSmrg if ((mask & 1) != 0) 471f2e35a3aSmrg TRACE((" %d", button)); 472f2e35a3aSmrg mask >>= 1; 473f2e35a3aSmrg } 474f2e35a3aSmrg TRACE(("\n")); 475f2e35a3aSmrg } else { 476f2e35a3aSmrg TRACE(("...No buttons used with selection can be overridden\n")); 477f2e35a3aSmrg } 478f2e35a3aSmrg#endif 479f2e35a3aSmrg } 480f2e35a3aSmrg XSetErrorHandler(save); 481f2e35a3aSmrg} 482f2e35a3aSmrg 483f2e35a3aSmrg/* 484f2e35a3aSmrg * Shift and control are regular X11 modifiers, but meta is not: 485f2e35a3aSmrg * + X10 (which had no xmodmap utility) had a meta mask, but X11 did not. 486f2e35a3aSmrg * + X11R1 introduced xmodmap, along with the current set of modifier masks. 487f2e35a3aSmrg * The meta key has been assumed to be mod1 since X11R1. 488f2e35a3aSmrg * The initial xterm logic in X11 was different, but gave the same result. 489f2e35a3aSmrg * + X11R2 modified xterm was to eliminate the X10 table which provided part of 490f2e35a3aSmrg * the meta logic. 491f2e35a3aSmrg * + X11R3 modified Xt, making Meta_L and Meta_R assignable via xmodmap, and 492f2e35a3aSmrg * equating Alt with Meta. Neither Alt/Meta are modifiers, but Alt is more 493f2e35a3aSmrg * likely to be on the keyboard. This release also added keymap tables for 494f2e35a3aSmrg * the server; Meta was used frequently in HP keymaps, which were the most 495f2e35a3aSmrg * extensive set of keymaps. 496f2e35a3aSmrg * + X11R4 mentions Meta in the ICCCM, stating that if Meta_L or Meta_R are 497f2e35a3aSmrg * found in the keysyms for a given modifier, that the client should use 498f2e35a3aSmrg * that modifier. 499f2e35a3aSmrg * 500f2e35a3aSmrg * This function follows the ICCCM, picking the modifier which contains the 501f2e35a3aSmrg * Meta_L/Meta_R keysyms (if available), falling back to the Alt_L/Alt_R 502f2e35a3aSmrg * (as per X11R3), and ultimately to mod1 (per X11R1). 503f2e35a3aSmrg */ 504f2e35a3aSmrgstatic unsigned 505f2e35a3aSmrgMetaMask(XtermWidget xw) 506f2e35a3aSmrg{ 507f2e35a3aSmrg#if OPT_NUM_LOCK 508f2e35a3aSmrg unsigned meta = xw->work.meta_mods; 509f2e35a3aSmrg if (meta == 0) 510f2e35a3aSmrg meta = xw->work.alt_mods; 511f2e35a3aSmrg if (meta == 0) 512f2e35a3aSmrg meta = Mod1Mask; 513f2e35a3aSmrg#else 514f2e35a3aSmrg unsigned meta = Mod1Mask; 515f2e35a3aSmrg (void) xw; 516f2e35a3aSmrg#endif 517f2e35a3aSmrg return meta; 518f2e35a3aSmrg} 519f2e35a3aSmrg 520f2e35a3aSmrg/* 521f2e35a3aSmrg * Returns a mask of the modifiers we may use for modifying the mouse protocol 522f2e35a3aSmrg * response strings. 523f2e35a3aSmrg */ 524f2e35a3aSmrgstatic unsigned 525f2e35a3aSmrgOurModifiers(XtermWidget xw) 526f2e35a3aSmrg{ 527f2e35a3aSmrg return (ShiftMask 528f2e35a3aSmrg | ControlMask 529f2e35a3aSmrg | MetaMask(xw)); 530f2e35a3aSmrg} 531f2e35a3aSmrg 532f2e35a3aSmrg/* 533f2e35a3aSmrg * The actual check for the shift-mask, to see if it should tell xterm to 534f2e35a3aSmrg * override mouse-protocol in favor of select/paste actions depends upon 535f2e35a3aSmrg * whether the shiftEscape resource is set to true/always vs false/never. 536f2e35a3aSmrg */ 537f2e35a3aSmrgstatic Boolean 538f2e35a3aSmrgShiftOverride(XtermWidget xw, unsigned state, int button) 539f2e35a3aSmrg{ 540f2e35a3aSmrg unsigned check = (state & OurModifiers(xw)); 541f2e35a3aSmrg Boolean result = False; 542f2e35a3aSmrg 543f2e35a3aSmrg if (check & ShiftMask) { 544f2e35a3aSmrg if (xw->keyboard.shift_escape == ssFalse || 545f2e35a3aSmrg xw->keyboard.shift_escape == ssNever) { 546f2e35a3aSmrg result = True; 547f2e35a3aSmrg } else if (xw->keyboard.shift_escape == ssTrue) { 548f2e35a3aSmrg /* 549f2e35a3aSmrg * Check if the button is one that we found does not directly use 550f2e35a3aSmrg * the shift-modifier in its bindings to select/copy actions. 551f2e35a3aSmrg */ 552f2e35a3aSmrg if (button > 0 && button <= MaxMouseBtn) { 553f2e35a3aSmrg if (xw->keyboard.shift_buttons & (1U << (button - 1))) { 554f2e35a3aSmrg result = True; 555f2e35a3aSmrg } 556f2e35a3aSmrg } else { 557f2e35a3aSmrg result = True; /* unlikely, and we don't care */ 558f2e35a3aSmrg } 559f2e35a3aSmrg } 560f2e35a3aSmrg } 561f2e35a3aSmrg TRACE2(("ShiftOverride ( %#x -> %#x ) %d\n", state, check, result)); 562f2e35a3aSmrg return result; 563f2e35a3aSmrg} 564f2e35a3aSmrg 565f2e35a3aSmrg/* 566f2e35a3aSmrg * Normally xterm treats the shift-modifier specially when the mouse protocol 567f2e35a3aSmrg * is active. The translations resource binds otherwise unmodified button 568f2e35a3aSmrg * for these mouse-related events: 569f2e35a3aSmrg * 570f2e35a3aSmrg * ~Meta <Btn1Down>:select-start() \n\ 571f2e35a3aSmrg * ~Meta <Btn1Motion>:select-extend() \n\ 572f2e35a3aSmrg * ~Ctrl ~Meta <Btn2Up>:insert-selection(SELECT, CUT_BUFFER0) \n\ 573f2e35a3aSmrg * ~Ctrl ~Meta <Btn3Down>:start-extend() \n\ 574f2e35a3aSmrg * ~Meta <Btn3Motion>:select-extend() \n\ 575f2e35a3aSmrg * <BtnUp>:select-end(SELECT, CUT_BUFFER0) \n\ 576f2e35a3aSmrg * 577f2e35a3aSmrg * There is no API in the X libraries which would tell us if a given mouse 578f2e35a3aSmrg * button is bound to one of these actions. These functions make the choice 579f2e35a3aSmrg * configurable. 580f2e35a3aSmrg */ 581f2e35a3aSmrgstatic Bool 582f2e35a3aSmrgInterpretButton(XtermWidget xw, XButtonEvent *event) 583f2e35a3aSmrg{ 584f2e35a3aSmrg Bool result = False; 585f2e35a3aSmrg 586f2e35a3aSmrg if (ShiftOverride(xw, event->state, (int) event->button)) { 587f2e35a3aSmrg TRACE(("...shift-button #%d overrides mouse-protocol\n", event->button)); 588f2e35a3aSmrg result = True; 589f2e35a3aSmrg } 590f2e35a3aSmrg return result; 591f2e35a3aSmrg} 592f2e35a3aSmrg 593f2e35a3aSmrg#define Button1Index 8 /* X.h should have done this */ 594f2e35a3aSmrg 595f2e35a3aSmrgstatic int 596f2e35a3aSmrgMotionButton(unsigned state) 597f2e35a3aSmrg{ 598f2e35a3aSmrg unsigned bmask = state >> Button1Index; 599f2e35a3aSmrg int result = 1; 600f2e35a3aSmrg 601f2e35a3aSmrg if (bmask != 0) { 602f2e35a3aSmrg while (!(bmask & 1)) { 603f2e35a3aSmrg ++result; 604f2e35a3aSmrg bmask >>= 1; 605f2e35a3aSmrg } 606f2e35a3aSmrg } 607f2e35a3aSmrg return result; 608f2e35a3aSmrg} 609f2e35a3aSmrg 610f2e35a3aSmrgstatic Bool 611f2e35a3aSmrgInterpretEvent(XtermWidget xw, XEvent *event) 612f2e35a3aSmrg{ 613f2e35a3aSmrg Bool result = False; /* if not a button, is motion */ 614f2e35a3aSmrg 615f2e35a3aSmrg if (IsBtnEvent(event)) { 616f2e35a3aSmrg result = InterpretButton(xw, (XButtonEvent *) event); 617f2e35a3aSmrg } else if (event->type == MotionNotify) { 618f2e35a3aSmrg unsigned state = event->xmotion.state; 619f2e35a3aSmrg int button = MotionButton(state); 620f2e35a3aSmrg 621f2e35a3aSmrg if (ShiftOverride(xw, state, button)) { 622f2e35a3aSmrg TRACE(("...shift-motion #%d (%d,%d) overrides mouse-protocol\n", 623f2e35a3aSmrg button, 624f2e35a3aSmrg event->xmotion.y, 625f2e35a3aSmrg event->xmotion.x)); 626f2e35a3aSmrg result = True; 627f2e35a3aSmrg } 628f2e35a3aSmrg } 629f2e35a3aSmrg return result; 630f2e35a3aSmrg} 631f2e35a3aSmrg 632f2e35a3aSmrg#define OverrideEvent(event) InterpretEvent(xw, event) 633f2e35a3aSmrg#define OverrideButton(event) InterpretButton(xw, event) 634f2e35a3aSmrg 635f2e35a3aSmrg/* 636f2e35a3aSmrg * Returns true if we handled the event here, and nothing more is needed. 637f2e35a3aSmrg */ 638492d43a5SmrgBool 639894e0ac8SmrgSendMousePosition(XtermWidget xw, XEvent *event) 640492d43a5Smrg{ 641492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 642492d43a5Smrg Bool result = False; 643d522f475Smrg 644913cc679Smrg switch (okSendMousePos(xw)) { 645492d43a5Smrg case MOUSE_OFF: 646492d43a5Smrg /* If send_mouse_pos mode isn't on, we shouldn't be here */ 647492d43a5Smrg break; 648d522f475Smrg 649d522f475Smrg case BTN_EVENT_MOUSE: 650d522f475Smrg case ANY_EVENT_MOUSE: 651f2e35a3aSmrg if (!OverrideEvent(event)) { 652492d43a5Smrg /* xterm extension for motion reporting. June 1998 */ 653492d43a5Smrg /* EditorButton() will distinguish between the modes */ 654492d43a5Smrg switch (event->type) { 655492d43a5Smrg case MotionNotify: 656492d43a5Smrg my_event->button = 0; 657492d43a5Smrg /* FALLTHRU */ 658492d43a5Smrg case ButtonPress: 659492d43a5Smrg /* FALLTHRU */ 660492d43a5Smrg case ButtonRelease: 661492d43a5Smrg EditorButton(xw, my_event); 662492d43a5Smrg result = True; 663492d43a5Smrg break; 6642eaa94a1Schristos } 665d522f475Smrg } 666492d43a5Smrg break; 667d522f475Smrg 668913cc679Smrg case X10_MOUSE: /* X10 compatibility sequences */ 669492d43a5Smrg if (IsBtnEvent(event)) { 670f2e35a3aSmrg if (!OverrideButton(my_event)) { 671913cc679Smrg if (my_event->type == ButtonPress) 672492d43a5Smrg EditorButton(xw, my_event); 673913cc679Smrg result = True; 674913cc679Smrg } 675913cc679Smrg } 676913cc679Smrg break; 677492d43a5Smrg 678913cc679Smrg case VT200_HIGHLIGHT_MOUSE: /* DEC vt200 hilite tracking */ 679913cc679Smrg if (IsBtnEvent(event)) { 680f2e35a3aSmrg if (!OverrideButton(my_event)) { 681f2e35a3aSmrg if (my_event->type == ButtonPress && 682f2e35a3aSmrg my_event->button == Button1) { 683f2e35a3aSmrg TrackDown(xw, my_event); 684f2e35a3aSmrg } else { 685f2e35a3aSmrg EditorButton(xw, my_event); 686f2e35a3aSmrg } 687913cc679Smrg result = True; 688913cc679Smrg } 689913cc679Smrg } 690913cc679Smrg break; 691492d43a5Smrg 692913cc679Smrg case VT200_MOUSE: /* DEC vt200 compatible */ 693913cc679Smrg if (IsBtnEvent(event)) { 694f2e35a3aSmrg if (!OverrideButton(my_event)) { 695913cc679Smrg EditorButton(xw, my_event); 696913cc679Smrg result = True; 697913cc679Smrg } 698913cc679Smrg } 699913cc679Smrg break; 700913cc679Smrg 701913cc679Smrg case DEC_LOCATOR: 702492d43a5Smrg#if OPT_DEC_LOCATOR 703f2e35a3aSmrg if (IsBtnEvent(event) || event->type == MotionNotify) { 704913cc679Smrg result = SendLocatorPosition(xw, my_event); 705492d43a5Smrg } 706f2e35a3aSmrg#endif /* OPT_DEC_LOCATOR */ 707913cc679Smrg break; 708d522f475Smrg } 709492d43a5Smrg return result; 710d522f475Smrg} 711d522f475Smrg 712d522f475Smrg#if OPT_DEC_LOCATOR 713d522f475Smrg 714d522f475Smrg#define LocatorCoords( row, col, x, y, oor ) \ 715d522f475Smrg if( screen->locator_pixels ) { \ 716d522f475Smrg (oor)=False; (row) = (y)+1; (col) = (x)+1; \ 717d522f475Smrg /* Limit to screen dimensions */ \ 718d522f475Smrg if ((row) < 1) (row) = 1,(oor)=True; \ 719d522f475Smrg else if ((row) > screen->border*2+Height(screen)) \ 720d522f475Smrg (row) = screen->border*2+Height(screen),(oor)=True; \ 721d522f475Smrg if ((col) < 1) (col) = 1,(oor)=True; \ 722d522f475Smrg else if ((col) > OriginX(screen)*2+Width(screen)) \ 723d522f475Smrg (col) = OriginX(screen)*2+Width(screen),(oor)=True; \ 724d522f475Smrg } else { \ 725d522f475Smrg (oor)=False; \ 726d522f475Smrg /* Compute character position of mouse pointer */ \ 727d522f475Smrg (row) = ((y) - screen->border) / FontHeight(screen); \ 728d522f475Smrg (col) = ((x) - OriginX(screen)) / FontWidth(screen); \ 729d522f475Smrg /* Limit to screen dimensions */ \ 730d522f475Smrg if ((row) < 0) (row) = 0,(oor)=True; \ 731d522f475Smrg else if ((row) > screen->max_row) \ 732d522f475Smrg (row) = screen->max_row,(oor)=True; \ 733d522f475Smrg if ((col) < 0) (col) = 0,(oor)=True; \ 734d522f475Smrg else if ((col) > screen->max_col) \ 735d522f475Smrg (col) = screen->max_col,(oor)=True; \ 736d522f475Smrg (row)++; (col)++; \ 737d522f475Smrg } 738d522f475Smrg 739d522f475Smrgstatic Bool 740894e0ac8SmrgSendLocatorPosition(XtermWidget xw, XButtonEvent *event) 741d522f475Smrg{ 742d522f475Smrg ANSI reply; 743956cc18dSsnj TScreen *screen = TScreenOf(xw); 744d522f475Smrg int row, col; 745d522f475Smrg Bool oor; 746d522f475Smrg int button; 7472eaa94a1Schristos unsigned state; 748d522f475Smrg 749d522f475Smrg /* Make sure the event is an appropriate type */ 750f2e35a3aSmrg if (IsBtnEvent(event)) { 751f2e35a3aSmrg if (OverrideButton(event)) 752f2e35a3aSmrg return (False); 753f2e35a3aSmrg } else { 754f2e35a3aSmrg if (!screen->loc_filter) 755f2e35a3aSmrg return (False); 756f2e35a3aSmrg } 757d522f475Smrg 758d522f475Smrg if ((event->type == ButtonPress && 759d522f475Smrg !(screen->locator_events & LOC_BTNS_DN)) || 760d522f475Smrg (event->type == ButtonRelease && 761d522f475Smrg !(screen->locator_events & LOC_BTNS_UP))) 762d522f475Smrg return (True); 763d522f475Smrg 764d522f475Smrg if (event->type == MotionNotify) { 765d522f475Smrg CheckLocatorPosition(xw, event); 766d522f475Smrg return (True); 767d522f475Smrg } 768d522f475Smrg 769d522f475Smrg /* get button # */ 770492d43a5Smrg button = (int) event->button - 1; 771d522f475Smrg 772492d43a5Smrg LocatorCoords(row, col, event->x, event->y, oor); 773d522f475Smrg 774d522f475Smrg /* 775d522f475Smrg * DECterm mouse: 776d522f475Smrg * 777d522f475Smrg * ESCAPE '[' event ; mask ; row ; column '&' 'w' 778d522f475Smrg */ 779d522f475Smrg memset(&reply, 0, sizeof(reply)); 780d522f475Smrg reply.a_type = ANSI_CSI; 781d522f475Smrg 782d522f475Smrg if (oor) { 783d522f475Smrg reply.a_nparam = 1; 784d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 785d522f475Smrg reply.a_inters = '&'; 786d522f475Smrg reply.a_final = 'w'; 787d522f475Smrg unparseseq(xw, &reply); 788d522f475Smrg 789d522f475Smrg if (screen->locator_reset) { 790d522f475Smrg MotionOff(screen, xw); 791d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 792d522f475Smrg } 793d522f475Smrg return (True); 794d522f475Smrg } 795d522f475Smrg 796d522f475Smrg /* 797d522f475Smrg * event: 798d522f475Smrg * 1 no buttons 799d522f475Smrg * 2 left button down 800d522f475Smrg * 3 left button up 801d522f475Smrg * 4 middle button down 802d522f475Smrg * 5 middle button up 803d522f475Smrg * 6 right button down 804d522f475Smrg * 7 right button up 805d522f475Smrg * 8 M4 down 806d522f475Smrg * 9 M4 up 807d522f475Smrg */ 808d522f475Smrg reply.a_nparam = 4; 809d522f475Smrg switch (event->type) { 810d522f475Smrg case ButtonPress: 8112eaa94a1Schristos reply.a_param[0] = (ParmType) (2 + (button << 1)); 812d522f475Smrg break; 813d522f475Smrg case ButtonRelease: 8142eaa94a1Schristos reply.a_param[0] = (ParmType) (3 + (button << 1)); 815d522f475Smrg break; 816d522f475Smrg default: 817d522f475Smrg return (True); 818d522f475Smrg } 819d522f475Smrg /* 820d522f475Smrg * mask: 821913cc679Smrg * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 822913cc679Smrg * M4 down left down middle down right down 823d522f475Smrg * 824d522f475Smrg * Notice that Button1 (left) and Button3 (right) are swapped in the mask. 825d522f475Smrg * Also, mask should be the state after the button press/release, 826d522f475Smrg * X provides the state not including the button press/release. 827d522f475Smrg */ 828492d43a5Smrg state = (event->state 829d522f475Smrg & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8; 8304e40088cSchristos /* update mask to "after" state */ 83120d2c4d2Smrg state ^= ((unsigned) (1 << button)); 8324e40088cSchristos /* swap Button1 & Button3 */ 833956cc18dSsnj state = ((state & (unsigned) ~(4 | 1)) 834956cc18dSsnj | ((state & 1) ? 4 : 0) 835956cc18dSsnj | ((state & 4) ? 1 : 0)); 836d522f475Smrg 8372eaa94a1Schristos reply.a_param[1] = (ParmType) state; 8382eaa94a1Schristos reply.a_param[2] = (ParmType) row; 8392eaa94a1Schristos reply.a_param[3] = (ParmType) col; 840d522f475Smrg reply.a_inters = '&'; 841d522f475Smrg reply.a_final = 'w'; 842d522f475Smrg 843d522f475Smrg unparseseq(xw, &reply); 844d522f475Smrg 845d522f475Smrg if (screen->locator_reset) { 846d522f475Smrg MotionOff(screen, xw); 847d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 848d522f475Smrg } 849d522f475Smrg 850d522f475Smrg /* 851913cc679Smrg * DECterm turns the Locator off if a button is pressed while a filter 852913cc679Smrg * rectangle is active. This might be a bug, but I don't know, so I'll 853913cc679Smrg * emulate it anyway. 854d522f475Smrg */ 855d522f475Smrg if (screen->loc_filter) { 856d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 857d522f475Smrg screen->loc_filter = False; 858d522f475Smrg screen->locator_events = 0; 859d522f475Smrg MotionOff(screen, xw); 860d522f475Smrg } 861d522f475Smrg 862d522f475Smrg return (True); 863d522f475Smrg} 864d522f475Smrg 865d522f475Smrg/* 866d522f475Smrg * mask: 867d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 868d522f475Smrg * M4 down left down middle down right down 869d522f475Smrg * 870d522f475Smrg * Button1 (left) and Button3 (right) are swapped in the mask relative to X. 871d522f475Smrg */ 872d522f475Smrg#define ButtonState(state, mask) \ 873913cc679Smrg{ int stemp = (int) (((mask) & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8); \ 874d522f475Smrg /* swap Button1 & Button3 */ \ 875913cc679Smrg (state) = (stemp & ~(4|1)) | ((stemp & 1) ? 4 : 0) | ((stemp & 4) ? 1 : 0); \ 876d522f475Smrg} 877d522f475Smrg 878d522f475Smrgvoid 879d522f475SmrgGetLocatorPosition(XtermWidget xw) 880d522f475Smrg{ 881d522f475Smrg ANSI reply; 882956cc18dSsnj TScreen *screen = TScreenOf(xw); 883d522f475Smrg Window root, child; 884d522f475Smrg int rx, ry, x, y; 885f2e35a3aSmrg unsigned int mask = 0; 886d522f475Smrg int row = 0, col = 0; 887d522f475Smrg Bool oor = False; 888d522f475Smrg Bool ret = False; 889d522f475Smrg int state; 890d522f475Smrg 891d522f475Smrg /* 892913cc679Smrg * DECterm turns the Locator off if the position is requested while a 893913cc679Smrg * filter rectangle is active. This might be a bug, but I don't know, so 894913cc679Smrg * I'll emulate it anyways. 895d522f475Smrg */ 896d522f475Smrg if (screen->loc_filter) { 897d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 898d522f475Smrg screen->loc_filter = False; 899d522f475Smrg screen->locator_events = 0; 900d522f475Smrg MotionOff(screen, xw); 901d522f475Smrg } 902d522f475Smrg 903d522f475Smrg memset(&reply, 0, sizeof(reply)); 904d522f475Smrg reply.a_type = ANSI_CSI; 905d522f475Smrg 906913cc679Smrg if (okSendMousePos(xw) == DEC_LOCATOR) { 907d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), &root, 908d522f475Smrg &child, &rx, &ry, &x, &y, &mask); 909d522f475Smrg if (ret) { 910d522f475Smrg LocatorCoords(row, col, x, y, oor); 911d522f475Smrg } 912d522f475Smrg } 913d522f475Smrg if (ret == False || oor) { 914d522f475Smrg reply.a_nparam = 1; 915d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 916d522f475Smrg reply.a_inters = '&'; 917d522f475Smrg reply.a_final = 'w'; 918d522f475Smrg unparseseq(xw, &reply); 919d522f475Smrg 920d522f475Smrg if (screen->locator_reset) { 921d522f475Smrg MotionOff(screen, xw); 922d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 923d522f475Smrg } 924d522f475Smrg return; 925d522f475Smrg } 926d522f475Smrg 927d522f475Smrg ButtonState(state, mask); 928d522f475Smrg 929d522f475Smrg reply.a_nparam = 4; 930d522f475Smrg reply.a_param[0] = 1; /* Event - 1 = response to locator request */ 9312eaa94a1Schristos reply.a_param[1] = (ParmType) state; 9322eaa94a1Schristos reply.a_param[2] = (ParmType) row; 9332eaa94a1Schristos reply.a_param[3] = (ParmType) col; 934d522f475Smrg reply.a_inters = '&'; 935d522f475Smrg reply.a_final = 'w'; 936d522f475Smrg unparseseq(xw, &reply); 937d522f475Smrg 938d522f475Smrg if (screen->locator_reset) { 939d522f475Smrg MotionOff(screen, xw); 940d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 941d522f475Smrg } 942d522f475Smrg} 943d522f475Smrg 944d522f475Smrgvoid 945d522f475SmrgInitLocatorFilter(XtermWidget xw) 946d522f475Smrg{ 947d522f475Smrg ANSI reply; 948956cc18dSsnj TScreen *screen = TScreenOf(xw); 949d522f475Smrg Window root, child; 950d522f475Smrg int rx, ry, x, y; 951d522f475Smrg unsigned int mask; 952d522f475Smrg int row = 0, col = 0; 953d522f475Smrg Bool oor = 0; 954d522f475Smrg Bool ret; 955d522f475Smrg 956d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), 957d522f475Smrg &root, &child, &rx, &ry, &x, &y, &mask); 958d522f475Smrg if (ret) { 959d522f475Smrg LocatorCoords(row, col, x, y, oor); 960d522f475Smrg } 961d522f475Smrg if (ret == False || oor) { 962d522f475Smrg /* Locator is unavailable */ 963d522f475Smrg 964d522f475Smrg if (screen->loc_filter_top != LOC_FILTER_POS || 965d522f475Smrg screen->loc_filter_left != LOC_FILTER_POS || 966d522f475Smrg screen->loc_filter_bottom != LOC_FILTER_POS || 967d522f475Smrg screen->loc_filter_right != LOC_FILTER_POS) { 968d522f475Smrg /* 969d522f475Smrg * If any explicit coordinates were received, 970d522f475Smrg * report immediately with no coordinates. 971d522f475Smrg */ 972d522f475Smrg memset(&reply, 0, sizeof(reply)); 973d522f475Smrg reply.a_type = ANSI_CSI; 974d522f475Smrg reply.a_nparam = 1; 975d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 976d522f475Smrg reply.a_inters = '&'; 977d522f475Smrg reply.a_final = 'w'; 978d522f475Smrg unparseseq(xw, &reply); 979d522f475Smrg 980d522f475Smrg if (screen->locator_reset) { 981d522f475Smrg MotionOff(screen, xw); 982d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 983d522f475Smrg } 984d522f475Smrg } else { 985d522f475Smrg /* 986d522f475Smrg * No explicit coordinates were received, and the pointer is 987d522f475Smrg * unavailable. Report when the pointer re-enters the window. 988d522f475Smrg */ 989d522f475Smrg screen->loc_filter = True; 990d522f475Smrg MotionOn(screen, xw); 991d522f475Smrg } 992d522f475Smrg return; 993d522f475Smrg } 994d522f475Smrg 995d522f475Smrg /* 996d522f475Smrg * Adjust rectangle coordinates: 997d522f475Smrg * 1. Replace "LOC_FILTER_POS" with current coordinates 998d522f475Smrg * 2. Limit coordinates to screen size 999d522f475Smrg * 3. make sure top and left are less than bottom and right, resp. 1000d522f475Smrg */ 1001d522f475Smrg if (screen->locator_pixels) { 1002d522f475Smrg rx = OriginX(screen) * 2 + Width(screen); 1003d522f475Smrg ry = screen->border * 2 + Height(screen); 1004d522f475Smrg } else { 1005d522f475Smrg rx = screen->max_col; 1006d522f475Smrg ry = screen->max_row; 1007d522f475Smrg } 1008d522f475Smrg 1009d522f475Smrg#define Adjust( coord, def, max ) \ 1010d522f475Smrg if( (coord) == LOC_FILTER_POS ) (coord) = (def); \ 1011d522f475Smrg else if ((coord) < 1) (coord) = 1; \ 1012d522f475Smrg else if ((coord) > (max)) (coord) = (max) 1013d522f475Smrg 1014d522f475Smrg Adjust(screen->loc_filter_top, row, ry); 1015d522f475Smrg Adjust(screen->loc_filter_left, col, rx); 1016d522f475Smrg Adjust(screen->loc_filter_bottom, row, ry); 1017d522f475Smrg Adjust(screen->loc_filter_right, col, rx); 1018d522f475Smrg 1019d522f475Smrg if (screen->loc_filter_top > screen->loc_filter_bottom) { 1020d522f475Smrg ry = screen->loc_filter_top; 1021d522f475Smrg screen->loc_filter_top = screen->loc_filter_bottom; 1022d522f475Smrg screen->loc_filter_bottom = ry; 1023d522f475Smrg } 1024d522f475Smrg 1025d522f475Smrg if (screen->loc_filter_left > screen->loc_filter_right) { 1026d522f475Smrg rx = screen->loc_filter_left; 1027d522f475Smrg screen->loc_filter_left = screen->loc_filter_right; 1028d522f475Smrg screen->loc_filter_right = rx; 1029d522f475Smrg } 1030d522f475Smrg 1031d522f475Smrg if ((col < screen->loc_filter_left) || 1032d522f475Smrg (col > screen->loc_filter_right) || 1033d522f475Smrg (row < screen->loc_filter_top) || 1034d522f475Smrg (row > screen->loc_filter_bottom)) { 10352e4f8982Smrg int state; 10362e4f8982Smrg 1037d522f475Smrg /* Pointer is already outside the rectangle - report immediately */ 1038d522f475Smrg ButtonState(state, mask); 1039d522f475Smrg 1040d522f475Smrg memset(&reply, 0, sizeof(reply)); 1041d522f475Smrg reply.a_type = ANSI_CSI; 1042d522f475Smrg reply.a_nparam = 4; 1043d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 10442eaa94a1Schristos reply.a_param[1] = (ParmType) state; 10452eaa94a1Schristos reply.a_param[2] = (ParmType) row; 10462eaa94a1Schristos reply.a_param[3] = (ParmType) col; 1047d522f475Smrg reply.a_inters = '&'; 1048d522f475Smrg reply.a_final = 'w'; 1049d522f475Smrg unparseseq(xw, &reply); 1050d522f475Smrg 1051d522f475Smrg if (screen->locator_reset) { 1052d522f475Smrg MotionOff(screen, xw); 1053d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 1054d522f475Smrg } 1055d522f475Smrg return; 1056d522f475Smrg } 1057d522f475Smrg 1058d522f475Smrg /* 1059d522f475Smrg * Rectangle is set up. Allow pointer tracking 1060d522f475Smrg * to detect if the mouse leaves the rectangle. 1061d522f475Smrg */ 1062d522f475Smrg screen->loc_filter = True; 1063d522f475Smrg MotionOn(screen, xw); 1064d522f475Smrg} 1065d522f475Smrg 1066d522f475Smrgstatic void 1067894e0ac8SmrgCheckLocatorPosition(XtermWidget xw, XButtonEvent *event) 1068d522f475Smrg{ 1069d522f475Smrg ANSI reply; 1070956cc18dSsnj TScreen *screen = TScreenOf(xw); 1071d522f475Smrg int row, col; 1072d522f475Smrg Bool oor; 1073d522f475Smrg 1074492d43a5Smrg LocatorCoords(row, col, event->x, event->y, oor); 1075d522f475Smrg 1076d522f475Smrg /* 1077d522f475Smrg * Send report if the pointer left the filter rectangle, if 1078d522f475Smrg * the pointer left the window, or if the filter rectangle 1079d522f475Smrg * had no coordinates and the pointer re-entered the window. 1080d522f475Smrg */ 1081d522f475Smrg if (oor || (screen->loc_filter_top == LOC_FILTER_POS) || 1082d522f475Smrg (col < screen->loc_filter_left) || 1083d522f475Smrg (col > screen->loc_filter_right) || 1084d522f475Smrg (row < screen->loc_filter_top) || 1085d522f475Smrg (row > screen->loc_filter_bottom)) { 1086d522f475Smrg /* Filter triggered - disable it */ 1087d522f475Smrg screen->loc_filter = False; 1088d522f475Smrg MotionOff(screen, xw); 1089d522f475Smrg 1090d522f475Smrg memset(&reply, 0, sizeof(reply)); 1091d522f475Smrg reply.a_type = ANSI_CSI; 1092d522f475Smrg if (oor) { 1093d522f475Smrg reply.a_nparam = 1; 1094d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 1095d522f475Smrg } else { 10962e4f8982Smrg int state; 10972e4f8982Smrg 1098492d43a5Smrg ButtonState(state, event->state); 1099d522f475Smrg 1100d522f475Smrg reply.a_nparam = 4; 1101d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 11022eaa94a1Schristos reply.a_param[1] = (ParmType) state; 11032eaa94a1Schristos reply.a_param[2] = (ParmType) row; 11042eaa94a1Schristos reply.a_param[3] = (ParmType) col; 1105d522f475Smrg } 1106d522f475Smrg 1107d522f475Smrg reply.a_inters = '&'; 1108d522f475Smrg reply.a_final = 'w'; 1109d522f475Smrg unparseseq(xw, &reply); 1110d522f475Smrg 1111d522f475Smrg if (screen->locator_reset) { 1112d522f475Smrg MotionOff(screen, xw); 1113d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 1114d522f475Smrg } 1115d522f475Smrg } 1116d522f475Smrg} 1117d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 1118d522f475Smrg 1119d522f475Smrg#if OPT_READLINE 1120d522f475Smrgstatic int 1121913cc679SmrgisClick1_clean(XtermWidget xw, XButtonEvent *event) 1122d522f475Smrg{ 1123913cc679Smrg TScreen *screen = TScreenOf(xw); 1124d522f475Smrg int delta; 1125d522f475Smrg 1126d522f475Smrg /* Disable on Shift-Click-1, including the application-mouse modes */ 1127f2e35a3aSmrg if (OverrideButton(event) 1128f2e35a3aSmrg || (okSendMousePos(xw) != MOUSE_OFF) 1129f2e35a3aSmrg || ExtendingSelection) /* Was moved */ 1130d522f475Smrg return 0; 1131d522f475Smrg 1132d522f475Smrg if (event->type != ButtonRelease) 1133d522f475Smrg return 0; 1134d522f475Smrg 1135d522f475Smrg if (lastButtonDownTime == (Time) 0) { 1136d522f475Smrg /* first time or once in a blue moon */ 1137d522f475Smrg delta = screen->multiClickTime + 1; 1138492d43a5Smrg } else if (event->time > lastButtonDownTime) { 1139d522f475Smrg /* most of the time */ 1140492d43a5Smrg delta = (int) (event->time - lastButtonDownTime); 1141d522f475Smrg } else { 1142d522f475Smrg /* time has rolled over since lastButtonUpTime */ 1143492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->time); 1144d522f475Smrg } 1145d522f475Smrg 1146d522f475Smrg return delta <= screen->multiClickTime; 1147d522f475Smrg} 1148d522f475Smrg 1149d522f475Smrgstatic int 1150f2e35a3aSmrgisDoubleClick3(XtermWidget xw, TScreen *screen, XButtonEvent *event) 1151d522f475Smrg{ 1152d522f475Smrg int delta; 1153d522f475Smrg 1154d522f475Smrg if (event->type != ButtonRelease 1155f2e35a3aSmrg || OverrideButton(event) 1156492d43a5Smrg || event->button != Button3) { 1157d522f475Smrg lastButton3UpTime = 0; /* Disable the cached info */ 1158d522f475Smrg return 0; 1159d522f475Smrg } 1160d522f475Smrg /* Process Btn3Release. */ 1161d522f475Smrg if (lastButton3DoubleDownTime == (Time) 0) { 1162d522f475Smrg /* No previous click or once in a blue moon */ 1163d522f475Smrg delta = screen->multiClickTime + 1; 1164492d43a5Smrg } else if (event->time > lastButton3DoubleDownTime) { 1165d522f475Smrg /* most of the time */ 1166492d43a5Smrg delta = (int) (event->time - lastButton3DoubleDownTime); 1167d522f475Smrg } else { 1168d522f475Smrg /* time has rolled over since lastButton3DoubleDownTime */ 1169492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButton3DoubleDownTime) + event->time); 1170d522f475Smrg } 1171d522f475Smrg if (delta <= screen->multiClickTime) { 1172d522f475Smrg /* Double click */ 1173d522f475Smrg CELL cell; 1174d522f475Smrg 1175d522f475Smrg /* Cannot check ExtendingSelection, since mouse-3 always sets it */ 1176492d43a5Smrg PointToCELL(screen, event->y, event->x, &cell); 1177d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 1178d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the third click */ 1179d522f475Smrg return 1; 1180d522f475Smrg } 1181d522f475Smrg } 1182d522f475Smrg /* Not a double click, memorize for future check. */ 1183492d43a5Smrg lastButton3UpTime = event->time; 1184492d43a5Smrg PointToCELL(screen, event->y, event->x, &lastButton3); 1185d522f475Smrg return 0; 1186d522f475Smrg} 1187d522f475Smrg 1188d522f475Smrgstatic int 1189f2e35a3aSmrgCheckSecondPress3(XtermWidget xw, TScreen *screen, XEvent *event) 1190d522f475Smrg{ 1191d522f475Smrg int delta; 1192d522f475Smrg 1193d522f475Smrg if (event->type != ButtonPress 1194f2e35a3aSmrg || OverrideEvent(event) 1195d522f475Smrg || event->xbutton.button != Button3) { 1196d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the cached info */ 1197d522f475Smrg return 0; 1198d522f475Smrg } 1199d522f475Smrg /* Process Btn3Press. */ 1200d522f475Smrg if (lastButton3UpTime == (Time) 0) { 1201d522f475Smrg /* No previous click or once in a blue moon */ 1202d522f475Smrg delta = screen->multiClickTime + 1; 1203d522f475Smrg } else if (event->xbutton.time > lastButton3UpTime) { 1204d522f475Smrg /* most of the time */ 12052eaa94a1Schristos delta = (int) (event->xbutton.time - lastButton3UpTime); 1206d522f475Smrg } else { 1207d522f475Smrg /* time has rolled over since lastButton3UpTime */ 12082eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButton3UpTime) + event->xbutton.time); 1209d522f475Smrg } 1210d522f475Smrg if (delta <= screen->multiClickTime) { 1211d522f475Smrg CELL cell; 1212d522f475Smrg 1213d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 1214d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 1215d522f475Smrg /* A candidate for a double-click */ 1216d522f475Smrg lastButton3DoubleDownTime = event->xbutton.time; 1217d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &lastButton3); 1218d522f475Smrg return 1; 1219d522f475Smrg } 1220d522f475Smrg lastButton3UpTime = 0; /* Disable the info about the previous click */ 1221d522f475Smrg } 1222d522f475Smrg /* Either too long, or moved, disable. */ 1223d522f475Smrg lastButton3DoubleDownTime = 0; 1224d522f475Smrg return 0; 1225d522f475Smrg} 1226d522f475Smrg 1227d522f475Smrgstatic int 1228e0a2b6dfSmrgrowOnCurrentLine(TScreen *screen, 1229d522f475Smrg int line, 1230d522f475Smrg int *deltap) /* must be XButtonEvent */ 1231d522f475Smrg{ 1232956cc18dSsnj int result = 1; 1233d522f475Smrg 1234d522f475Smrg *deltap = 0; 12352e4f8982Smrg 1236956cc18dSsnj if (line != screen->cur_row) { 12372e4f8982Smrg int l1, l2; 12382e4f8982Smrg 1239f2e35a3aSmrg if (line < screen->cur_row) { 1240f2e35a3aSmrg l1 = line; 1241f2e35a3aSmrg l2 = screen->cur_row; 1242f2e35a3aSmrg } else { 1243f2e35a3aSmrg l2 = line; 1244f2e35a3aSmrg l1 = screen->cur_row; 1245f2e35a3aSmrg } 1246956cc18dSsnj l1--; 1247956cc18dSsnj while (++l1 < l2) { 1248956cc18dSsnj LineData *ld = GET_LINEDATA(screen, l1); 1249956cc18dSsnj if (!LineTstWrapped(ld)) { 1250956cc18dSsnj result = 0; 1251956cc18dSsnj break; 1252956cc18dSsnj } 1253956cc18dSsnj } 1254956cc18dSsnj if (result) { 1255956cc18dSsnj /* Everything is on one "wrapped line" now */ 1256956cc18dSsnj *deltap = line - screen->cur_row; 1257956cc18dSsnj } 1258956cc18dSsnj } 1259956cc18dSsnj return result; 1260d522f475Smrg} 1261d522f475Smrg 1262d522f475Smrgstatic int 1263894e0ac8SmrgeventRow(TScreen *screen, XEvent *event) /* must be XButtonEvent */ 1264d522f475Smrg{ 1265d522f475Smrg return (event->xbutton.y - screen->border) / FontHeight(screen); 1266d522f475Smrg} 1267d522f475Smrg 1268d522f475Smrgstatic int 1269894e0ac8SmrgeventColBetween(TScreen *screen, XEvent *event) /* must be XButtonEvent */ 1270d522f475Smrg{ 1271d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 1272d522f475Smrg return ((event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) / 2) 1273d522f475Smrg / FontWidth(screen)); 1274d522f475Smrg} 1275d522f475Smrg 1276d522f475Smrgstatic int 1277e0a2b6dfSmrgReadLineMovePoint(TScreen *screen, int col, int ldelta) 1278d522f475Smrg{ 1279d522f475Smrg Char line[6]; 1280d522f475Smrg unsigned count = 0; 1281d522f475Smrg 1282d522f475Smrg col += ldelta * MaxCols(screen) - screen->cur_col; 1283d522f475Smrg if (col == 0) 1284d522f475Smrg return 0; 1285d522f475Smrg if (screen->control_eight_bits) { 1286d522f475Smrg line[count++] = ANSI_CSI; 1287d522f475Smrg } else { 1288d522f475Smrg line[count++] = ANSI_ESC; 1289d522f475Smrg line[count++] = '['; /* XXX maybe sometimes O is better? */ 1290d522f475Smrg } 129120d2c4d2Smrg line[count] = CharOf(col > 0 ? 'C' : 'D'); 1292d522f475Smrg if (col < 0) 1293d522f475Smrg col = -col; 1294d522f475Smrg while (col--) 1295d522f475Smrg v_write(screen->respond, line, 3); 1296d522f475Smrg return 1; 1297d522f475Smrg} 1298d522f475Smrg 1299d522f475Smrgstatic int 1300e0a2b6dfSmrgReadLineDelete(TScreen *screen, CELL *cell1, CELL *cell2) 1301d522f475Smrg{ 1302d522f475Smrg int del; 1303d522f475Smrg 1304d522f475Smrg del = (cell2->col - cell1->col) + ((cell2->row - cell1->row) * MaxCols(screen)); 1305d522f475Smrg if (del <= 0) /* Just in case... */ 1306d522f475Smrg return 0; 1307d522f475Smrg while (del--) 1308492d43a5Smrg v_write(screen->respond, (const Char *) "\177", 1); 1309d522f475Smrg return 1; 1310d522f475Smrg} 1311492d43a5Smrg 1312492d43a5Smrgstatic void 1313913cc679SmrgreadlineExtend(XtermWidget xw, XEvent *event) 1314492d43a5Smrg{ 1315913cc679Smrg TScreen *screen = TScreenOf(xw); 1316492d43a5Smrg int ldelta1, ldelta2; 1317492d43a5Smrg 1318492d43a5Smrg if (IsBtnEvent(event)) { 1319492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 1320913cc679Smrg if (isClick1_clean(xw, my_event) 1321492d43a5Smrg && SCREEN_FLAG(screen, click1_moves) 1322492d43a5Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta1)) { 1323492d43a5Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta1); 1324492d43a5Smrg } 1325f2e35a3aSmrg if (isDoubleClick3(xw, screen, my_event) 1326492d43a5Smrg && SCREEN_FLAG(screen, dclick3_deletes) 1327492d43a5Smrg && rowOnCurrentLine(screen, screen->startSel.row, &ldelta1) 1328492d43a5Smrg && rowOnCurrentLine(screen, screen->endSel.row, &ldelta2)) { 1329492d43a5Smrg ReadLineMovePoint(screen, screen->endSel.col, ldelta2); 1330492d43a5Smrg ReadLineDelete(screen, &screen->startSel, &(screen->endSel)); 1331492d43a5Smrg } 1332492d43a5Smrg } 1333492d43a5Smrg} 1334d522f475Smrg#endif /* OPT_READLINE */ 1335d522f475Smrg 1336d522f475Smrg/* ^XM-G<line+' '><col+' '> */ 1337d522f475Smrgvoid 1338d522f475SmrgDiredButton(Widget w, 1339894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1340e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 1341d522f475Smrg Cardinal *num_params GCC_UNUSED) 1342d522f475Smrg{ 1343956cc18dSsnj XtermWidget xw; 1344956cc18dSsnj 1345956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1346956cc18dSsnj TScreen *screen = TScreenOf(xw); 1347d522f475Smrg 1348492d43a5Smrg if (IsBtnEvent(event) 13492eaa94a1Schristos && (event->xbutton.y >= screen->border) 13502eaa94a1Schristos && (event->xbutton.x >= OriginX(screen))) { 13512e4f8982Smrg Char Line[6]; 13522e4f8982Smrg unsigned line, col; 13532e4f8982Smrg 135420d2c4d2Smrg line = (unsigned) ((event->xbutton.y - screen->border) 135520d2c4d2Smrg / FontHeight(screen)); 135620d2c4d2Smrg col = (unsigned) ((event->xbutton.x - OriginX(screen)) 135720d2c4d2Smrg / FontWidth(screen)); 1358d522f475Smrg Line[0] = CONTROL('X'); 1359d522f475Smrg Line[1] = ANSI_ESC; 1360d522f475Smrg Line[2] = 'G'; 13612eaa94a1Schristos Line[3] = CharOf(' ' + col); 13622eaa94a1Schristos Line[4] = CharOf(' ' + line); 1363d522f475Smrg v_write(screen->respond, Line, 5); 1364d522f475Smrg } 1365d522f475Smrg } 1366d522f475Smrg} 1367d522f475Smrg 1368d522f475Smrg#if OPT_READLINE 1369d522f475Smrgvoid 1370d522f475SmrgReadLineButton(Widget w, 1371894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1372f2e35a3aSmrg String *params, /* selections */ 1373f2e35a3aSmrg Cardinal *num_params) 1374d522f475Smrg{ 1375956cc18dSsnj XtermWidget xw; 1376956cc18dSsnj 1377956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1378956cc18dSsnj TScreen *screen = TScreenOf(xw); 1379d522f475Smrg Char Line[6]; 1380d522f475Smrg int line, col, ldelta = 0; 1381d522f475Smrg 1382492d43a5Smrg if (!IsBtnEvent(event) 1383913cc679Smrg || (okSendMousePos(xw) != MOUSE_OFF) || ExtendingSelection) 1384d522f475Smrg goto finish; 1385d522f475Smrg if (event->type == ButtonRelease) { 1386d522f475Smrg int delta; 1387d522f475Smrg 1388d522f475Smrg if (lastButtonDownTime == (Time) 0) { 1389d522f475Smrg /* first time and once in a blue moon */ 1390d522f475Smrg delta = screen->multiClickTime + 1; 1391d522f475Smrg } else if (event->xbutton.time > lastButtonDownTime) { 1392d522f475Smrg /* most of the time */ 13932eaa94a1Schristos delta = (int) (event->xbutton.time - lastButtonDownTime); 1394d522f475Smrg } else { 1395d522f475Smrg /* time has rolled over since lastButtonUpTime */ 13962eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time); 1397d522f475Smrg } 1398d522f475Smrg if (delta > screen->multiClickTime) 1399d522f475Smrg goto finish; /* All this work for this... */ 1400d522f475Smrg } 1401d522f475Smrg line = (event->xbutton.y - screen->border) / FontHeight(screen); 1402956cc18dSsnj if (!rowOnCurrentLine(screen, line, &ldelta)) 1403956cc18dSsnj goto finish; 1404d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 1405d522f475Smrg col = (event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) 1406d522f475Smrg / 2) 1407d522f475Smrg / FontWidth(screen) - screen->cur_col + ldelta * MaxCols(screen); 1408d522f475Smrg if (col == 0) 1409d522f475Smrg goto finish; 1410d522f475Smrg Line[0] = ANSI_ESC; 1411d522f475Smrg /* XXX: sometimes it is better to send '['? */ 1412d522f475Smrg Line[1] = 'O'; 14132eaa94a1Schristos Line[2] = CharOf(col > 0 ? 'C' : 'D'); 1414d522f475Smrg if (col < 0) 1415d522f475Smrg col = -col; 1416d522f475Smrg while (col--) 1417d522f475Smrg v_write(screen->respond, Line, 3); 1418d522f475Smrg finish: 1419d522f475Smrg if (event->type == ButtonRelease) 1420d522f475Smrg do_select_end(xw, event, params, num_params, False); 1421d522f475Smrg } 1422d522f475Smrg} 1423d522f475Smrg#endif /* OPT_READLINE */ 1424d522f475Smrg 1425d522f475Smrg/* repeats <ESC>n or <ESC>p */ 1426d522f475Smrgvoid 1427d522f475SmrgViButton(Widget w, 1428894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1429e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 1430d522f475Smrg Cardinal *num_params GCC_UNUSED) 1431d522f475Smrg{ 1432956cc18dSsnj XtermWidget xw; 1433956cc18dSsnj 1434956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1435956cc18dSsnj TScreen *screen = TScreenOf(xw); 1436d522f475Smrg int pty = screen->respond; 1437d522f475Smrg 1438492d43a5Smrg if (IsBtnEvent(event)) { 14392e4f8982Smrg int line; 1440d522f475Smrg 1441d522f475Smrg line = screen->cur_row - 1442d522f475Smrg ((event->xbutton.y - screen->border) / FontHeight(screen)); 14432e4f8982Smrg 1444d522f475Smrg if (line != 0) { 14452e4f8982Smrg Char Line[6]; 14462e4f8982Smrg 1447d522f475Smrg Line[0] = ANSI_ESC; /* force an exit from insert-mode */ 1448d522f475Smrg v_write(pty, Line, 1); 1449d522f475Smrg 1450d522f475Smrg if (line < 0) { 1451d522f475Smrg line = -line; 1452d522f475Smrg Line[0] = CONTROL('n'); 1453d522f475Smrg } else { 1454d522f475Smrg Line[0] = CONTROL('p'); 1455d522f475Smrg } 1456d522f475Smrg while (--line >= 0) 1457d522f475Smrg v_write(pty, Line, 1); 1458d522f475Smrg } 1459d522f475Smrg } 1460d522f475Smrg } 1461d522f475Smrg} 1462d522f475Smrg 1463d522f475Smrg/* 1464d522f475Smrg * This function handles button-motion events 1465d522f475Smrg */ 1466d522f475Smrg/*ARGSUSED*/ 1467d522f475Smrgvoid 1468d522f475SmrgHandleSelectExtend(Widget w, 1469894e0ac8Smrg XEvent *event, /* must be XMotionEvent */ 1470e0a2b6dfSmrg String *params GCC_UNUSED, 1471d522f475Smrg Cardinal *num_params GCC_UNUSED) 1472d522f475Smrg{ 1473956cc18dSsnj XtermWidget xw; 1474956cc18dSsnj 1475956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1476956cc18dSsnj TScreen *screen = TScreenOf(xw); 1477d522f475Smrg CELL cell; 1478d522f475Smrg 1479f2e35a3aSmrg TRACE_EVENT("HandleSelectExtend", event, params, num_params); 14800bd37d32Smrg 1481d522f475Smrg screen->selection_time = event->xmotion.time; 1482d522f475Smrg switch (screen->eventMode) { 1483d522f475Smrg /* If not in one of the DEC mouse-reporting modes */ 1484d522f475Smrg case LEFTEXTENSION: 1485d522f475Smrg case RIGHTEXTENSION: 1486d522f475Smrg PointToCELL(screen, event->xmotion.y, event->xmotion.x, &cell); 1487d522f475Smrg ExtendExtend(xw, &cell); 1488d522f475Smrg break; 1489d522f475Smrg 1490d522f475Smrg /* If in motion reporting mode, send mouse position to 1491d522f475Smrg character process as a key sequence \E[M... */ 1492d522f475Smrg case NORMAL: 1493d522f475Smrg /* will get here if send_mouse_pos != MOUSE_OFF */ 1494913cc679Smrg if (okSendMousePos(xw) == BTN_EVENT_MOUSE 1495913cc679Smrg || okSendMousePos(xw) == ANY_EVENT_MOUSE) { 1496d522f475Smrg (void) SendMousePosition(xw, event); 1497d522f475Smrg } 1498d522f475Smrg break; 1499d522f475Smrg } 1500d522f475Smrg } 1501d522f475Smrg} 1502d522f475Smrg 1503d522f475Smrgvoid 1504d522f475SmrgHandleKeyboardSelectExtend(Widget w, 1505894e0ac8Smrg XEvent *event GCC_UNUSED, /* must be XButtonEvent */ 1506e0a2b6dfSmrg String *params GCC_UNUSED, 1507d522f475Smrg Cardinal *num_params GCC_UNUSED) 1508d522f475Smrg{ 1509956cc18dSsnj XtermWidget xw; 1510956cc18dSsnj 1511956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1512956cc18dSsnj TScreen *screen = TScreenOf(xw); 15130bd37d32Smrg 1514f2e35a3aSmrg TRACE_EVENT("HandleKeyboardSelectExtend", event, params, num_params); 1515d522f475Smrg ExtendExtend(xw, &screen->cursorp); 1516d522f475Smrg } 1517d522f475Smrg} 1518d522f475Smrg 1519d522f475Smrgstatic void 1520d522f475Smrgdo_select_end(XtermWidget xw, 1521894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1522e0a2b6dfSmrg String *params, /* selections */ 1523d522f475Smrg Cardinal *num_params, 1524d522f475Smrg Bool use_cursor_loc) 1525d522f475Smrg{ 1526956cc18dSsnj TScreen *screen = TScreenOf(xw); 1527d522f475Smrg 1528d522f475Smrg screen->selection_time = event->xbutton.time; 1529f2e35a3aSmrg 1530f2e35a3aSmrg TRACE(("do_select_end %s @%ld\n", 1531f2e35a3aSmrg visibleEventMode(screen->eventMode), 1532f2e35a3aSmrg screen->selection_time)); 1533f2e35a3aSmrg 1534d522f475Smrg switch (screen->eventMode) { 1535d522f475Smrg case NORMAL: 1536d522f475Smrg (void) SendMousePosition(xw, event); 1537d522f475Smrg break; 1538d522f475Smrg case LEFTEXTENSION: 1539d522f475Smrg case RIGHTEXTENSION: 1540d522f475Smrg EndExtend(xw, event, params, *num_params, use_cursor_loc); 1541d522f475Smrg#if OPT_READLINE 1542913cc679Smrg readlineExtend(xw, event); 1543d522f475Smrg#endif /* OPT_READLINE */ 1544d522f475Smrg break; 1545d522f475Smrg } 1546d522f475Smrg} 1547d522f475Smrg 1548d522f475Smrgvoid 1549d522f475SmrgHandleSelectEnd(Widget w, 1550894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1551e0a2b6dfSmrg String *params, /* selections */ 1552d522f475Smrg Cardinal *num_params) 1553d522f475Smrg{ 1554956cc18dSsnj XtermWidget xw; 1555956cc18dSsnj 1556956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 15570bd37d32Smrg TRACE(("HandleSelectEnd\n")); 1558956cc18dSsnj do_select_end(xw, event, params, num_params, False); 1559956cc18dSsnj } 1560d522f475Smrg} 1561d522f475Smrg 1562d522f475Smrgvoid 1563d522f475SmrgHandleKeyboardSelectEnd(Widget w, 1564894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1565e0a2b6dfSmrg String *params, /* selections */ 1566d522f475Smrg Cardinal *num_params) 1567d522f475Smrg{ 1568956cc18dSsnj XtermWidget xw; 1569956cc18dSsnj 1570956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 15710bd37d32Smrg TRACE(("HandleKeyboardSelectEnd\n")); 1572956cc18dSsnj do_select_end(xw, event, params, num_params, True); 1573956cc18dSsnj } 1574d522f475Smrg} 1575d522f475Smrg 1576f2e35a3aSmrgvoid 1577f2e35a3aSmrgHandlePointerMotion(Widget w, 1578f2e35a3aSmrg XEvent *event, 1579f2e35a3aSmrg String *params, /* selections */ 1580f2e35a3aSmrg Cardinal *num_params) 1581f2e35a3aSmrg{ 1582f2e35a3aSmrg XtermWidget xw; 1583f2e35a3aSmrg 1584f2e35a3aSmrg (void) params; 1585f2e35a3aSmrg (void) num_params; 1586f2e35a3aSmrg if ((xw = getXtermWidget(w)) != 0) { 1587f2e35a3aSmrg TRACE(("HandlePointerMotion\n")); 1588f2e35a3aSmrg if (event->type == MotionNotify) 1589f2e35a3aSmrg (void) SendMousePosition(xw, event); 1590f2e35a3aSmrg } 1591f2e35a3aSmrg} 1592f2e35a3aSmrg 1593f2e35a3aSmrgvoid 1594f2e35a3aSmrgHandlePointerButton(Widget w, 1595f2e35a3aSmrg XEvent *event, 1596f2e35a3aSmrg String *params, /* selections */ 1597f2e35a3aSmrg Cardinal *num_params) 1598f2e35a3aSmrg{ 1599f2e35a3aSmrg XtermWidget xw; 1600f2e35a3aSmrg 1601f2e35a3aSmrg (void) params; 1602f2e35a3aSmrg (void) num_params; 1603f2e35a3aSmrg if ((xw = getXtermWidget(w)) != 0) { 1604f2e35a3aSmrg TRACE(("HandlePointerButton\n")); 1605f2e35a3aSmrg if (IsBtnEvent(event)) 1606f2e35a3aSmrg (void) SendMousePosition(xw, event); 1607f2e35a3aSmrg } 1608f2e35a3aSmrg} 1609f2e35a3aSmrg 1610492d43a5Smrg/* 16116879286fSmrg * Copy the selection data to the given target(s). 1612492d43a5Smrg */ 1613492d43a5Smrgvoid 16146879286fSmrgHandleCopySelection(Widget w, 1615894e0ac8Smrg XEvent *event, 1616e0a2b6dfSmrg String *params, /* list of targets */ 16176879286fSmrg Cardinal *num_params) 1618492d43a5Smrg{ 1619492d43a5Smrg XtermWidget xw; 1620492d43a5Smrg 1621492d43a5Smrg if ((xw = getXtermWidget(w)) != 0) { 1622f2e35a3aSmrg TRACE_EVENT("HandleCopySelection", event, params, num_params); 16236879286fSmrg SelectSet(xw, event, params, *num_params); 1624492d43a5Smrg } 1625492d43a5Smrg} 1626492d43a5Smrg 1627d522f475Smrgstruct _SelectionList { 1628d522f475Smrg String *params; 1629d522f475Smrg Cardinal count; 1630d522f475Smrg Atom *targets; 1631d522f475Smrg Time time; 1632d522f475Smrg}; 1633d522f475Smrg 1634d522f475Smrgstatic unsigned 1635d522f475SmrgDECtoASCII(unsigned ch) 1636d522f475Smrg{ 1637d522f475Smrg if (xtermIsDecGraphic(ch)) { 16382eaa94a1Schristos ch = CharOf("###########+++++##-##++++|######"[ch]); 16392eaa94a1Schristos /* 01234567890123456789012345678901 */ 1640d522f475Smrg } 1641d522f475Smrg return ch; 1642d522f475Smrg} 164320d2c4d2Smrg 164420d2c4d2Smrg#if OPT_WIDE_CHARS 164520d2c4d2Smrgstatic Cardinal 1646e0a2b6dfSmrgaddXtermChar(Char **buffer, Cardinal *used, Cardinal offset, unsigned value) 164720d2c4d2Smrg{ 164820d2c4d2Smrg if (offset + 1 >= *used) { 164920d2c4d2Smrg *used = 1 + (2 * (offset + 1)); 165020d2c4d2Smrg allocXtermChars(buffer, *used); 165120d2c4d2Smrg } 165220d2c4d2Smrg (*buffer)[offset++] = (Char) value; 165320d2c4d2Smrg return offset; 165420d2c4d2Smrg} 165520d2c4d2Smrg#define AddChar(buffer, used, offset, value) \ 165620d2c4d2Smrg offset = addXtermChar(buffer, used, offset, (unsigned) value) 165720d2c4d2Smrg 1658d522f475Smrg/* 1659d522f475Smrg * Convert a UTF-8 string to Latin-1, replacing non Latin-1 characters by `#', 1660d522f475Smrg * or ASCII/Latin-1 equivalents for special cases. 1661d522f475Smrg */ 1662d522f475Smrgstatic Char * 1663e0a2b6dfSmrgUTF8toLatin1(TScreen *screen, Char *s, unsigned long len, unsigned long *result) 1664d522f475Smrg{ 1665d522f475Smrg static Char *buffer; 1666956cc18dSsnj static Cardinal used; 1667d522f475Smrg 166820d2c4d2Smrg Cardinal offset = 0; 1669d522f475Smrg 167020d2c4d2Smrg if (len != 0) { 1671d522f475Smrg PtyData data; 1672d522f475Smrg 1673d522f475Smrg fakePtyData(&data, s, s + len); 1674894e0ac8Smrg while (decodeUtf8(screen, &data)) { 1675956cc18dSsnj Bool fails = False; 1676956cc18dSsnj Bool extra = False; 1677f2e35a3aSmrg IChar value; 1678f2e35a3aSmrg skipPtyData(&data, value); 1679d522f475Smrg if (value == UCS_REPL) { 1680956cc18dSsnj fails = True; 1681d522f475Smrg } else if (value < 256) { 168220d2c4d2Smrg AddChar(&buffer, &used, offset, CharOf(value)); 1683d522f475Smrg } else { 1684f2e35a3aSmrg unsigned eqv = ucs2dec(screen, value); 1685d522f475Smrg if (xtermIsDecGraphic(eqv)) { 168620d2c4d2Smrg AddChar(&buffer, &used, offset, DECtoASCII(eqv)); 1687d522f475Smrg } else { 1688d522f475Smrg eqv = AsciiEquivs(value); 1689956cc18dSsnj if (eqv == value) { 1690956cc18dSsnj fails = True; 1691956cc18dSsnj } else { 169220d2c4d2Smrg AddChar(&buffer, &used, offset, eqv); 1693956cc18dSsnj } 1694956cc18dSsnj if (isWide((wchar_t) value)) 1695956cc18dSsnj extra = True; 1696956cc18dSsnj } 1697956cc18dSsnj } 1698956cc18dSsnj 1699956cc18dSsnj /* 1700956cc18dSsnj * If we're not able to plug in a single-byte result, insert the 1701956cc18dSsnj * defaultString (which normally is a single "#", but could be 1702956cc18dSsnj * whatever the user wants). 1703956cc18dSsnj */ 1704956cc18dSsnj if (fails) { 17052e4f8982Smrg const Char *p; 17062e4f8982Smrg 1707492d43a5Smrg for (p = (const Char *) screen->default_string; *p != '\0'; ++p) { 170820d2c4d2Smrg AddChar(&buffer, &used, offset, *p); 1709d522f475Smrg } 1710d522f475Smrg } 1711956cc18dSsnj if (extra) 171220d2c4d2Smrg AddChar(&buffer, &used, offset, ' '); 1713d522f475Smrg } 171420d2c4d2Smrg AddChar(&buffer, &used, offset, '\0'); 171520d2c4d2Smrg *result = (unsigned long) (offset - 1); 1716d522f475Smrg } else { 1717d522f475Smrg *result = 0; 1718d522f475Smrg } 1719d522f475Smrg return buffer; 1720d522f475Smrg} 172120d2c4d2Smrg 172220d2c4d2Smrgint 172320d2c4d2SmrgxtermUtf8ToTextList(XtermWidget xw, 172420d2c4d2Smrg XTextProperty * text_prop, 172520d2c4d2Smrg char ***text_list, 172620d2c4d2Smrg int *text_list_count) 172720d2c4d2Smrg{ 172820d2c4d2Smrg TScreen *screen = TScreenOf(xw); 172920d2c4d2Smrg Display *dpy = screen->display; 173020d2c4d2Smrg int rc = -1; 173120d2c4d2Smrg 173220d2c4d2Smrg if (text_prop->format == 8 173320d2c4d2Smrg && (rc = Xutf8TextPropertyToTextList(dpy, text_prop, 173420d2c4d2Smrg text_list, 173520d2c4d2Smrg text_list_count)) >= 0) { 173620d2c4d2Smrg if (*text_list != NULL && *text_list_count != 0) { 173720d2c4d2Smrg int i; 173820d2c4d2Smrg Char *data; 173920d2c4d2Smrg char **new_text_list, *tmp; 174020d2c4d2Smrg unsigned long size, new_size; 174120d2c4d2Smrg 174220d2c4d2Smrg TRACE(("xtermUtf8ToTextList size %d\n", *text_list_count)); 174320d2c4d2Smrg 174420d2c4d2Smrg /* 174520d2c4d2Smrg * XLib StringList actually uses only two pointers, one for the 174620d2c4d2Smrg * list itself, and one for the data. Pointer to the data is the 174720d2c4d2Smrg * first element of the list, the rest (if any) list elements point 174820d2c4d2Smrg * to the same memory block as the first element 174920d2c4d2Smrg */ 175020d2c4d2Smrg new_size = 0; 175120d2c4d2Smrg for (i = 0; i < *text_list_count; ++i) { 175220d2c4d2Smrg data = (Char *) (*text_list)[i]; 175320d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 175420d2c4d2Smrg (void) UTF8toLatin1(screen, data, size, &size); 175520d2c4d2Smrg new_size += size + 1; 175620d2c4d2Smrg } 1757a1f3da82Smrg new_text_list = TypeXtMallocN(char *, *text_list_count); 175820d2c4d2Smrg new_text_list[0] = tmp = XtMalloc((Cardinal) new_size); 175920d2c4d2Smrg for (i = 0; i < (*text_list_count); ++i) { 176020d2c4d2Smrg data = (Char *) (*text_list)[i]; 176120d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 17620bd37d32Smrg if ((data = UTF8toLatin1(screen, data, size, &size)) != 0) { 17630bd37d32Smrg memcpy(tmp, data, size + 1); 17640bd37d32Smrg new_text_list[i] = tmp; 17650bd37d32Smrg tmp += size + 1; 17660bd37d32Smrg } 176720d2c4d2Smrg } 176820d2c4d2Smrg XFreeStringList((*text_list)); 176920d2c4d2Smrg *text_list = new_text_list; 177020d2c4d2Smrg } else { 177120d2c4d2Smrg rc = -1; 177220d2c4d2Smrg } 177320d2c4d2Smrg } 177420d2c4d2Smrg return rc; 177520d2c4d2Smrg} 1776d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1777d522f475Smrg 1778956cc18dSsnjstatic char * 1779956cc18dSsnjparseItem(char *value, char *nextc) 1780d522f475Smrg{ 1781956cc18dSsnj char *nextp = value; 1782956cc18dSsnj while (*nextp != '\0' && *nextp != ',') { 1783956cc18dSsnj *nextp = x_toupper(*nextp); 1784956cc18dSsnj ++nextp; 1785956cc18dSsnj } 1786956cc18dSsnj *nextc = *nextp; 1787956cc18dSsnj *nextp = '\0'; 1788d522f475Smrg 1789956cc18dSsnj return nextp; 1790956cc18dSsnj} 1791d522f475Smrg 1792956cc18dSsnj/* 1793956cc18dSsnj * All of the wanted strings are unique in the first character, so we can 1794956cc18dSsnj * use simple abbreviations. 1795956cc18dSsnj */ 1796956cc18dSsnjstatic Bool 1797956cc18dSsnjsameItem(const char *actual, const char *wanted) 1798956cc18dSsnj{ 1799956cc18dSsnj Bool result = False; 1800956cc18dSsnj size_t have = strlen(actual); 1801956cc18dSsnj size_t need = strlen(wanted); 1802d522f475Smrg 1803956cc18dSsnj if (have != 0 && have <= need) { 1804956cc18dSsnj if (!strncmp(actual, wanted, have)) { 1805956cc18dSsnj TRACE(("...matched \"%s\"\n", wanted)); 1806956cc18dSsnj result = True; 1807956cc18dSsnj } 1808956cc18dSsnj } 1809956cc18dSsnj 1810956cc18dSsnj return result; 1811956cc18dSsnj} 1812956cc18dSsnj 1813956cc18dSsnj/* 1814956cc18dSsnj * Handle the eightBitSelectTypes or utf8SelectTypes resource values. 1815956cc18dSsnj */ 1816956cc18dSsnjstatic Bool 1817894e0ac8SmrgoverrideTargets(Widget w, String value, Atom **resultp) 1818956cc18dSsnj{ 1819956cc18dSsnj Bool override = False; 1820956cc18dSsnj XtermWidget xw; 1821956cc18dSsnj 1822956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1823956cc18dSsnj TScreen *screen = TScreenOf(xw); 1824956cc18dSsnj 182520d2c4d2Smrg if (!IsEmpty(value)) { 1826492d43a5Smrg char *copied = x_strdup(value); 1827956cc18dSsnj if (copied != 0) { 1828956cc18dSsnj Atom *result = 0; 1829956cc18dSsnj Cardinal count = 1; 1830956cc18dSsnj int n; 1831d522f475Smrg 1832956cc18dSsnj TRACE(("decoding SelectTypes \"%s\"\n", value)); 1833956cc18dSsnj for (n = 0; copied[n] != '\0'; ++n) { 1834956cc18dSsnj if (copied[n] == ',') 1835956cc18dSsnj ++count; 1836956cc18dSsnj } 1837a1f3da82Smrg result = TypeXtMallocN(Atom, (2 * count) + 1); 1838956cc18dSsnj if (result == NULL) { 1839956cc18dSsnj TRACE(("Couldn't allocate selection types\n")); 1840956cc18dSsnj } else { 1841956cc18dSsnj char nextc = '?'; 184220d2c4d2Smrg char *listp = (char *) copied; 1843956cc18dSsnj count = 0; 1844956cc18dSsnj do { 1845956cc18dSsnj char *nextp = parseItem(listp, &nextc); 18460bd37d32Smrg char *item = x_strtrim(listp); 18470bd37d32Smrg size_t len = (item ? strlen(item) : 0); 1848956cc18dSsnj 1849956cc18dSsnj if (len == 0) { 1850a1f3da82Smrg /* EMPTY */ ; 1851956cc18dSsnj } 1852956cc18dSsnj#if OPT_WIDE_CHARS 18530bd37d32Smrg else if (sameItem(item, "UTF8")) { 1854956cc18dSsnj result[count++] = XA_UTF8_STRING(XtDisplay(w)); 1855956cc18dSsnj } 1856956cc18dSsnj#endif 18570bd37d32Smrg else if (sameItem(item, "I18N")) { 1858956cc18dSsnj if (screen->i18nSelections) { 1859956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 1860956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1861956cc18dSsnj } 18620bd37d32Smrg } else if (sameItem(item, "TEXT")) { 1863956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 18640bd37d32Smrg } else if (sameItem(item, "COMPOUND_TEXT")) { 1865956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 18660bd37d32Smrg } else if (sameItem(item, "STRING")) { 1867956cc18dSsnj result[count++] = XA_STRING; 1868956cc18dSsnj } 1869956cc18dSsnj *nextp++ = nextc; 1870956cc18dSsnj listp = nextp; 18710bd37d32Smrg free(item); 1872956cc18dSsnj } while (nextc != '\0'); 1873956cc18dSsnj if (count) { 1874956cc18dSsnj result[count] = None; 1875956cc18dSsnj override = True; 1876956cc18dSsnj *resultp = result; 1877956cc18dSsnj } else { 1878956cc18dSsnj XtFree((char *) result); 1879956cc18dSsnj } 1880956cc18dSsnj } 18810bd37d32Smrg free(copied); 1882956cc18dSsnj } else { 1883956cc18dSsnj TRACE(("Couldn't allocate copy of selection types\n")); 1884d522f475Smrg } 1885956cc18dSsnj } 1886956cc18dSsnj } 1887956cc18dSsnj return override; 1888956cc18dSsnj} 1889956cc18dSsnj 1890956cc18dSsnj#if OPT_WIDE_CHARS 1891956cc18dSsnjstatic Atom * 1892e0a2b6dfSmrgallocUtf8Targets(Widget w, TScreen *screen) 1893956cc18dSsnj{ 1894956cc18dSsnj Atom **resultp = &(screen->selection_targets_utf8); 1895956cc18dSsnj 1896956cc18dSsnj if (*resultp == 0) { 1897956cc18dSsnj Atom *result; 1898956cc18dSsnj 1899956cc18dSsnj if (!overrideTargets(w, screen->utf8_select_types, &result)) { 1900a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1901956cc18dSsnj if (result == NULL) { 1902956cc18dSsnj TRACE(("Couldn't allocate utf-8 selection targets\n")); 1903956cc18dSsnj } else { 1904956cc18dSsnj int n = 0; 1905956cc18dSsnj 1906e39b573cSmrg if (XSupportsLocale()) { 1907e39b573cSmrg result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1908d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1909e39b573cSmrg if (screen->i18nSelections) { 1910e39b573cSmrg result[n++] = XA_TEXT(XtDisplay(w)); 1911e39b573cSmrg result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1912e39b573cSmrg } 1913d522f475Smrg#endif 1914e39b573cSmrg } 1915956cc18dSsnj result[n++] = XA_STRING; 1916956cc18dSsnj result[n] = None; 1917956cc18dSsnj } 1918d522f475Smrg } 1919956cc18dSsnj 1920956cc18dSsnj *resultp = result; 1921d522f475Smrg } 1922956cc18dSsnj 1923956cc18dSsnj return *resultp; 1924956cc18dSsnj} 1925d522f475Smrg#endif 1926d522f475Smrg 1927956cc18dSsnjstatic Atom * 1928e0a2b6dfSmrgalloc8bitTargets(Widget w, TScreen *screen) 1929956cc18dSsnj{ 1930956cc18dSsnj Atom **resultp = &(screen->selection_targets_8bit); 1931956cc18dSsnj 1932956cc18dSsnj if (*resultp == 0) { 1933956cc18dSsnj Atom *result = 0; 1934956cc18dSsnj 1935956cc18dSsnj if (!overrideTargets(w, screen->eightbit_select_types, &result)) { 1936a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1937956cc18dSsnj if (result == NULL) { 1938956cc18dSsnj TRACE(("Couldn't allocate 8bit selection targets\n")); 1939956cc18dSsnj } else { 1940956cc18dSsnj int n = 0; 1941956cc18dSsnj 1942e39b573cSmrg if (XSupportsLocale()) { 1943d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1944e39b573cSmrg result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1945956cc18dSsnj#endif 1946e39b573cSmrg if (screen->i18nSelections) { 1947e39b573cSmrg result[n++] = XA_TEXT(XtDisplay(w)); 1948e39b573cSmrg result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1949e39b573cSmrg } 1950956cc18dSsnj } 1951956cc18dSsnj result[n++] = XA_STRING; 1952956cc18dSsnj result[n] = None; 1953956cc18dSsnj } 1954956cc18dSsnj } 1955956cc18dSsnj 1956956cc18dSsnj *resultp = result; 1957956cc18dSsnj } 1958956cc18dSsnj 1959956cc18dSsnj return *resultp; 1960956cc18dSsnj} 1961956cc18dSsnj 1962956cc18dSsnjstatic Atom * 1963956cc18dSsnj_SelectionTargets(Widget w) 1964956cc18dSsnj{ 1965956cc18dSsnj Atom *result; 1966956cc18dSsnj XtermWidget xw; 1967956cc18dSsnj 1968956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) { 1969956cc18dSsnj result = NULL; 1970956cc18dSsnj } else { 19712e4f8982Smrg TScreen *screen = TScreenOf(xw); 1972956cc18dSsnj 1973956cc18dSsnj#if OPT_WIDE_CHARS 1974956cc18dSsnj if (screen->wide_chars) { 1975956cc18dSsnj result = allocUtf8Targets(w, screen); 1976956cc18dSsnj } else 1977d522f475Smrg#endif 1978956cc18dSsnj { 1979956cc18dSsnj /* not screen->wide_chars */ 1980956cc18dSsnj result = alloc8bitTargets(w, screen); 1981d522f475Smrg } 1982d522f475Smrg } 1983956cc18dSsnj 1984956cc18dSsnj return result; 1985d522f475Smrg} 1986d522f475Smrg 1987d522f475Smrg#define isSELECT(value) (!strcmp(value, "SELECT")) 1988d522f475Smrg 1989f2e35a3aSmrgstatic int 1990f2e35a3aSmrgDefaultSelection(TScreen *screen) 1991f2e35a3aSmrg{ 1992f2e35a3aSmrg return (screen->selectToClipboard ? 1 : 0); 1993f2e35a3aSmrg} 1994f2e35a3aSmrg 1995f2e35a3aSmrgstatic int 1996f2e35a3aSmrgTargetToSelection(TScreen *screen, String name) 1997f2e35a3aSmrg{ 1998f2e35a3aSmrg int result = -1; 1999f2e35a3aSmrg int cutb; 2000f2e35a3aSmrg 2001f2e35a3aSmrg if (isSELECT(name)) { 2002f2e35a3aSmrg result = DefaultSelection(screen); 2003f2e35a3aSmrg } else if (!strcmp(name, PRIMARY_NAME)) { 2004f2e35a3aSmrg result = PRIMARY_CODE; 2005f2e35a3aSmrg } else if (!strcmp(name, CLIPBOARD_NAME)) { 2006f2e35a3aSmrg result = CLIPBOARD_CODE; 2007f2e35a3aSmrg } else if (!strcmp(name, SECONDARY_NAME)) { 2008f2e35a3aSmrg result = SECONDARY_CODE; 2009f2e35a3aSmrg } else if (sscanf(name, "CUT_BUFFER%d", &cutb) == 1) { 2010f2e35a3aSmrg if (cutb >= 0 && cutb < MAX_CUT_BUFFER) { 2011f2e35a3aSmrg result = CutBufferToCode(cutb); 2012f2e35a3aSmrg } else { 2013f2e35a3aSmrg xtermWarning("unexpected cut-buffer code: %d\n", cutb); 2014f2e35a3aSmrg } 2015f2e35a3aSmrg } else { 2016f2e35a3aSmrg xtermWarning("unexpected selection target: %s\n", name); 2017f2e35a3aSmrg } 2018f2e35a3aSmrg TRACE2(("TargetToSelection(%s) ->%d\n", name, result)); 2019f2e35a3aSmrg return result; 2020f2e35a3aSmrg} 2021f2e35a3aSmrg 2022f2e35a3aSmrgvoid 2023d522f475SmrgUnmapSelections(XtermWidget xw) 2024d522f475Smrg{ 2025956cc18dSsnj TScreen *screen = TScreenOf(xw); 2026d522f475Smrg Cardinal n; 2027d522f475Smrg 2028d522f475Smrg if (screen->mappedSelect) { 2029d522f475Smrg for (n = 0; screen->mappedSelect[n] != 0; ++n) 203020d2c4d2Smrg free((void *) screen->mappedSelect[n]); 2031f2e35a3aSmrg FreeAndNull(screen->mappedSelect); 2032d522f475Smrg } 2033d522f475Smrg} 2034d522f475Smrg 2035d522f475Smrg/* 2036d522f475Smrg * xterm generally uses the primary selection. Some applications prefer 2037d522f475Smrg * (or are limited to) the clipboard. Since the translations resource is 2038d522f475Smrg * complicated, users seldom change the way it affects selection. But it 2039d522f475Smrg * is simple to remap the choice between primary and clipboard before the 2040d522f475Smrg * call to XmuInternStrings(). 2041d522f475Smrg */ 2042d522f475Smrgstatic String * 2043e0a2b6dfSmrgMapSelections(XtermWidget xw, String *params, Cardinal num_params) 2044d522f475Smrg{ 2045d522f475Smrg String *result = params; 2046d522f475Smrg 2047913cc679Smrg if (params != 0 && num_params > 0) { 2048d522f475Smrg Cardinal j; 2049d522f475Smrg Boolean map = False; 2050d522f475Smrg 2051d522f475Smrg for (j = 0; j < num_params; ++j) { 2052d522f475Smrg TRACE(("param[%d]:%s\n", j, params[j])); 2053d522f475Smrg if (isSELECT(params[j])) { 2054d522f475Smrg map = True; 2055d522f475Smrg break; 2056d522f475Smrg } 2057d522f475Smrg } 2058d522f475Smrg if (map) { 2059956cc18dSsnj TScreen *screen = TScreenOf(xw); 2060956cc18dSsnj const char *mapTo = (screen->selectToClipboard 2061f2e35a3aSmrg ? CLIPBOARD_NAME 2062f2e35a3aSmrg : PRIMARY_NAME); 2063d522f475Smrg 2064d522f475Smrg UnmapSelections(xw); 2065d522f475Smrg if ((result = TypeMallocN(String, num_params + 1)) != 0) { 2066d522f475Smrg result[num_params] = 0; 2067d522f475Smrg for (j = 0; j < num_params; ++j) { 2068d522f475Smrg result[j] = x_strdup((isSELECT(params[j]) 2069d522f475Smrg ? mapTo 2070d522f475Smrg : params[j])); 2071d522f475Smrg if (result[j] == 0) { 2072d522f475Smrg UnmapSelections(xw); 20730bd37d32Smrg while (j != 0) { 20740bd37d32Smrg free((void *) result[--j]); 20750bd37d32Smrg } 2076f2e35a3aSmrg FreeAndNull(result); 2077d522f475Smrg break; 2078d522f475Smrg } 2079d522f475Smrg } 2080956cc18dSsnj screen->mappedSelect = result; 2081d522f475Smrg } 2082d522f475Smrg } 2083d522f475Smrg } 2084d522f475Smrg return result; 2085d522f475Smrg} 2086d522f475Smrg 2087d522f475Smrg/* 2088d522f475Smrg * Lookup the cut-buffer number, which will be in the range 0-7. 2089f2e35a3aSmrg * If it is not a cut-buffer, it is a type of selection, e.g., primary. 2090d522f475Smrg */ 2091d522f475Smrgstatic int 209220d2c4d2SmrgCutBuffer(Atom code) 2093d522f475Smrg{ 2094d522f475Smrg int cutbuffer; 209520d2c4d2Smrg switch ((unsigned) code) { 2096d522f475Smrg case XA_CUT_BUFFER0: 2097d522f475Smrg cutbuffer = 0; 2098d522f475Smrg break; 2099d522f475Smrg case XA_CUT_BUFFER1: 2100d522f475Smrg cutbuffer = 1; 2101d522f475Smrg break; 2102d522f475Smrg case XA_CUT_BUFFER2: 2103d522f475Smrg cutbuffer = 2; 2104d522f475Smrg break; 2105d522f475Smrg case XA_CUT_BUFFER3: 2106d522f475Smrg cutbuffer = 3; 2107d522f475Smrg break; 2108d522f475Smrg case XA_CUT_BUFFER4: 2109d522f475Smrg cutbuffer = 4; 2110d522f475Smrg break; 2111d522f475Smrg case XA_CUT_BUFFER5: 2112d522f475Smrg cutbuffer = 5; 2113d522f475Smrg break; 2114d522f475Smrg case XA_CUT_BUFFER6: 2115d522f475Smrg cutbuffer = 6; 2116d522f475Smrg break; 2117d522f475Smrg case XA_CUT_BUFFER7: 2118d522f475Smrg cutbuffer = 7; 2119d522f475Smrg break; 2120d522f475Smrg default: 2121d522f475Smrg cutbuffer = -1; 2122d522f475Smrg break; 2123d522f475Smrg } 2124f2e35a3aSmrg TRACE2(("CutBuffer(%d) = %d\n", (int) code, cutbuffer)); 2125d522f475Smrg return cutbuffer; 2126d522f475Smrg} 2127d522f475Smrg 2128d522f475Smrg#if OPT_PASTE64 2129d522f475Smrgstatic void 2130d522f475SmrgFinishPaste64(XtermWidget xw) 2131d522f475Smrg{ 2132956cc18dSsnj TScreen *screen = TScreenOf(xw); 2133956cc18dSsnj 2134956cc18dSsnj TRACE(("FinishPaste64(%d)\n", screen->base64_paste)); 2135956cc18dSsnj if (screen->base64_paste) { 2136956cc18dSsnj screen->base64_paste = 0; 2137956cc18dSsnj unparseputc1(xw, screen->base64_final); 2138d522f475Smrg unparse_end(xw); 2139d522f475Smrg } 2140d522f475Smrg} 2141d522f475Smrg#endif 2142d522f475Smrg 2143d522f475Smrg#if !OPT_PASTE64 2144d522f475Smrgstatic 2145d522f475Smrg#endif 2146d522f475Smrgvoid 2147d522f475SmrgxtermGetSelection(Widget w, 2148d522f475Smrg Time ev_time, 2149e0a2b6dfSmrg String *params, /* selections in precedence order */ 2150d522f475Smrg Cardinal num_params, 2151894e0ac8Smrg Atom *targets) 2152d522f475Smrg{ 2153d522f475Smrg Atom selection; 2154d522f475Smrg int cutbuffer; 2155d522f475Smrg Atom target; 2156d522f475Smrg 2157956cc18dSsnj XtermWidget xw; 2158956cc18dSsnj 215920d2c4d2Smrg if (num_params == 0) 216020d2c4d2Smrg return; 2161956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 2162d522f475Smrg return; 2163d522f475Smrg 2164e0a2b6dfSmrg TRACE(("xtermGetSelection num_params %d @%ld\n", num_params, ev_time)); 2165956cc18dSsnj params = MapSelections(xw, params, num_params); 2166d522f475Smrg 2167d522f475Smrg XmuInternStrings(XtDisplay(w), params, (Cardinal) 1, &selection); 2168d522f475Smrg cutbuffer = CutBuffer(selection); 2169d522f475Smrg 2170956cc18dSsnj TRACE(("Cutbuffer: %d, target: %s\n", cutbuffer, 2171956cc18dSsnj (targets 2172956cc18dSsnj ? visibleSelectionTarget(XtDisplay(w), targets[0]) 2173956cc18dSsnj : "None"))); 2174d522f475Smrg 2175d522f475Smrg if (cutbuffer >= 0) { 2176d522f475Smrg int inbytes; 2177d522f475Smrg unsigned long nbytes; 2178d522f475Smrg int fmt8 = 8; 2179d522f475Smrg Atom type = XA_STRING; 2180d522f475Smrg char *line; 2181d522f475Smrg 2182d522f475Smrg /* 'line' is freed in SelectionReceived */ 2183d522f475Smrg line = XFetchBuffer(XtDisplay(w), &inbytes, cutbuffer); 2184d522f475Smrg nbytes = (unsigned long) inbytes; 2185d522f475Smrg 21860bd37d32Smrg if (nbytes > 0) { 2187d522f475Smrg SelectionReceived(w, NULL, &selection, &type, (XtPointer) line, 2188d522f475Smrg &nbytes, &fmt8); 21890bd37d32Smrg } else if (num_params > 1) { 2190d522f475Smrg xtermGetSelection(w, ev_time, params + 1, num_params - 1, NULL); 2191d522f475Smrg } 2192d522f475Smrg#if OPT_PASTE64 2193d522f475Smrg else { 2194956cc18dSsnj FinishPaste64(xw); 2195d522f475Smrg } 2196d522f475Smrg#endif 2197d522f475Smrg } else { 2198d522f475Smrg 2199d522f475Smrg if (targets == NULL || targets[0] == None) { 2200d522f475Smrg targets = _SelectionTargets(w); 2201d522f475Smrg } 2202d522f475Smrg 2203d522f475Smrg if (targets != 0) { 22042e4f8982Smrg struct _SelectionList *list; 22052e4f8982Smrg 2206d522f475Smrg target = targets[0]; 2207d522f475Smrg 2208d522f475Smrg if (targets[1] == None) { /* last target in list */ 2209d522f475Smrg params++; 2210d522f475Smrg num_params--; 2211d522f475Smrg targets = _SelectionTargets(w); 2212d522f475Smrg } else { 2213d522f475Smrg targets = &(targets[1]); 2214d522f475Smrg } 2215d522f475Smrg 2216d522f475Smrg if (num_params) { 2217d522f475Smrg /* 'list' is freed in SelectionReceived */ 2218a1f3da82Smrg list = TypeXtMalloc(struct _SelectionList); 2219d522f475Smrg if (list != 0) { 2220d522f475Smrg list->params = params; 2221d522f475Smrg list->count = num_params; 2222d522f475Smrg list->targets = targets; 2223d522f475Smrg list->time = ev_time; 2224d522f475Smrg } 2225d522f475Smrg } else { 2226d522f475Smrg list = NULL; 2227d522f475Smrg } 2228d522f475Smrg 2229d522f475Smrg XtGetSelectionValue(w, selection, 2230d522f475Smrg target, 2231d522f475Smrg SelectionReceived, 2232d522f475Smrg (XtPointer) list, ev_time); 2233d522f475Smrg } 2234d522f475Smrg } 2235d522f475Smrg} 2236d522f475Smrg 2237d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 2238d522f475Smrgstatic void 2239e0a2b6dfSmrgGettingSelection(Display *dpy, Atom type, Char *line, unsigned long len) 2240d522f475Smrg{ 2241d522f475Smrg Char *cp; 2242913cc679Smrg const char *name = TraceAtomName(dpy, type); 2243d522f475Smrg 224401037d57Smrg TRACE(("Getting %s (type=%ld, length=%ld)\n", name, (long int) type, len)); 2245d522f475Smrg for (cp = line; cp < line + len; cp++) { 2246956cc18dSsnj TRACE(("[%d:%lu]", (int) (cp + 1 - line), len)); 2247d522f475Smrg if (isprint(*cp)) { 2248d522f475Smrg TRACE(("%c\n", *cp)); 2249d522f475Smrg } else { 2250d522f475Smrg TRACE(("\\x%02x\n", *cp)); 2251d522f475Smrg } 2252d522f475Smrg } 2253d522f475Smrg} 2254d522f475Smrg#else 2255d522f475Smrg#define GettingSelection(dpy,type,line,len) /* nothing */ 2256d522f475Smrg#endif 2257d522f475Smrg 2258d522f475Smrg#ifdef VMS 2259d522f475Smrg# define tty_vwrite(pty,lag,l) tt_write(lag,l) 2260d522f475Smrg#else /* !( VMS ) */ 2261d522f475Smrg# define tty_vwrite(pty,lag,l) v_write(pty,lag,l) 2262d522f475Smrg#endif /* defined VMS */ 2263d522f475Smrg 2264d522f475Smrg#if OPT_PASTE64 2265d522f475Smrg/* Return base64 code character given 6-bit number */ 2266d522f475Smrgstatic const char base64_code[] = "\ 2267d522f475SmrgABCDEFGHIJKLMNOPQRSTUVWXYZ\ 2268d522f475Smrgabcdefghijklmnopqrstuvwxyz\ 2269d522f475Smrg0123456789+/"; 2270d522f475Smrgstatic void 2271e0a2b6dfSmrgbase64_flush(TScreen *screen) 2272d522f475Smrg{ 2273d522f475Smrg Char x; 227401037d57Smrg 227501037d57Smrg TRACE(("base64_flush count %d, pad %d (%d)\n", 227601037d57Smrg screen->base64_count, 227701037d57Smrg screen->base64_pad, 227801037d57Smrg screen->base64_pad & 3)); 227901037d57Smrg 2280d522f475Smrg switch (screen->base64_count) { 2281d522f475Smrg case 0: 2282d522f475Smrg break; 2283d522f475Smrg case 2: 22842eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 4]); 2285d522f475Smrg tty_vwrite(screen->respond, &x, 1); 2286d522f475Smrg break; 2287d522f475Smrg case 4: 22882eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 2]); 2289d522f475Smrg tty_vwrite(screen->respond, &x, 1); 2290d522f475Smrg break; 2291d522f475Smrg } 229201037d57Smrg if (screen->base64_pad & 3) { 2293d522f475Smrg tty_vwrite(screen->respond, 2294492d43a5Smrg (const Char *) "===", 229501037d57Smrg (unsigned) (3 - (screen->base64_pad & 3))); 229601037d57Smrg } 2297d522f475Smrg screen->base64_count = 0; 2298d522f475Smrg screen->base64_accu = 0; 2299d522f475Smrg screen->base64_pad = 0; 2300d522f475Smrg} 2301d522f475Smrg#endif /* OPT_PASTE64 */ 2302d522f475Smrg 2303e0a2b6dfSmrg/* 2304e0a2b6dfSmrg * Translate ISO-8859-1 or UTF-8 data to NRCS. 2305e0a2b6dfSmrg */ 2306d522f475Smrgstatic void 2307f2e35a3aSmrgToNational(XtermWidget xw, Char *buffer, unsigned *length) 2308e0a2b6dfSmrg{ 2309f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2310f2e35a3aSmrg DECNRCM_codes gsetL = screen->gsets[screen->curgl]; 2311f2e35a3aSmrg DECNRCM_codes gsetR = screen->gsets[screen->curgr]; 2312e0a2b6dfSmrg 2313e0a2b6dfSmrg#if OPT_WIDE_CHARS 2314e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 23152e4f8982Smrg Char *p; 2316e0a2b6dfSmrg PtyData *data = TypeXtMallocX(PtyData, *length); 2317e0a2b6dfSmrg 2318e0a2b6dfSmrg memset(data, 0, sizeof(*data)); 2319e0a2b6dfSmrg data->next = data->buffer; 2320e0a2b6dfSmrg data->last = data->buffer + *length; 2321e0a2b6dfSmrg memcpy(data->buffer, buffer, (size_t) *length); 2322e0a2b6dfSmrg p = buffer; 2323e0a2b6dfSmrg while (data->next < data->last) { 23242e4f8982Smrg unsigned chr, out, gl, gr; 23252e4f8982Smrg 2326894e0ac8Smrg if (!decodeUtf8(screen, data)) { 2327e0a2b6dfSmrg data->utf_size = 1; 2328e0a2b6dfSmrg data->utf_data = data->next[0]; 2329e0a2b6dfSmrg } 2330e0a2b6dfSmrg data->next += data->utf_size; 2331e0a2b6dfSmrg chr = data->utf_data; 2332e0a2b6dfSmrg out = chr; 2333f2e35a3aSmrg if ((gl = xtermCharSetIn(xw, chr, gsetL)) != chr) { 2334e0a2b6dfSmrg out = gl; 2335f2e35a3aSmrg } else if ((gr = xtermCharSetIn(xw, chr, gsetR)) != chr) { 2336e0a2b6dfSmrg out = gr; 2337e0a2b6dfSmrg } 2338e0a2b6dfSmrg *p++ = (Char) ((out < 256) ? out : ' '); 2339e0a2b6dfSmrg } 2340e0a2b6dfSmrg *length = (unsigned) (p - buffer); 2341e0a2b6dfSmrg free(data); 2342e0a2b6dfSmrg } else 2343e0a2b6dfSmrg#endif 2344e0a2b6dfSmrg { 23452e4f8982Smrg Char *p; 23462e4f8982Smrg 2347e0a2b6dfSmrg for (p = buffer; (int) (p - buffer) < (int) *length; ++p) { 23482e4f8982Smrg unsigned gl, gr; 23492e4f8982Smrg unsigned chr = *p; 23502e4f8982Smrg unsigned out = chr; 2351f2e35a3aSmrg if ((gl = xtermCharSetIn(xw, chr, gsetL)) != chr) { 2352e0a2b6dfSmrg out = gl; 2353f2e35a3aSmrg } else if ((gr = xtermCharSetIn(xw, chr, gsetR)) != chr) { 2354e0a2b6dfSmrg out = gr; 2355e0a2b6dfSmrg } 2356e0a2b6dfSmrg *p = (Char) out; 2357e0a2b6dfSmrg } 2358e0a2b6dfSmrg } 2359e0a2b6dfSmrg} 2360e0a2b6dfSmrg 2361e0a2b6dfSmrgstatic void 2362e0a2b6dfSmrg_qWriteSelectionData(XtermWidget xw, Char *lag, unsigned length) 2363d522f475Smrg{ 23640bd37d32Smrg TScreen *screen = TScreenOf(xw); 23650bd37d32Smrg 2366e0a2b6dfSmrg /* 2367e0a2b6dfSmrg * If we are pasting into a window which is using NRCS, we want to map 2368e0a2b6dfSmrg * the text from the normal encoding (ISO-8859-1 or UTF-8) into the coding 2369e0a2b6dfSmrg * that an application would use to write characters with NRCS. 2370e0a2b6dfSmrg * 2371e0a2b6dfSmrg * TODO: handle conversion from UTF-8, and adjust length. This can be done 2372e0a2b6dfSmrg * in the same buffer because the target is always 8-bit. 2373e0a2b6dfSmrg */ 2374e0a2b6dfSmrg if ((xw->flags & NATIONAL) && (length != 0)) { 2375f2e35a3aSmrg ToNational(xw, lag, &length); 2376e0a2b6dfSmrg } 2377d522f475Smrg#if OPT_PASTE64 2378d522f475Smrg if (screen->base64_paste) { 2379d522f475Smrg /* Send data as base64 */ 2380d522f475Smrg Char *p = lag; 2381d522f475Smrg Char buf[64]; 2382d522f475Smrg unsigned x = 0; 23830bd37d32Smrg 238401037d57Smrg TRACE(("convert to base64 %d:%s\n", length, visibleChars(p, length))); 238501037d57Smrg 23860bd37d32Smrg /* 23870bd37d32Smrg * Handle the case where the selection is from _this_ xterm, which 23880bd37d32Smrg * puts part of the reply in the buffer before the selection callback 23890bd37d32Smrg * happens. 23900bd37d32Smrg */ 23910bd37d32Smrg if (screen->base64_paste && screen->unparse_len) { 23920bd37d32Smrg unparse_end(xw); 23930bd37d32Smrg } 2394d522f475Smrg while (length--) { 2395d522f475Smrg switch (screen->base64_count) { 2396d522f475Smrg case 0: 23972eaa94a1Schristos buf[x++] = CharOf(base64_code[*p >> 2]); 23982eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0x3); 2399d522f475Smrg screen->base64_count = 2; 2400d522f475Smrg ++p; 2401d522f475Smrg break; 2402d522f475Smrg case 2: 24032eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 4) + 24042eaa94a1Schristos (*p >> 4)]); 24052eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0xF); 2406d522f475Smrg screen->base64_count = 4; 2407d522f475Smrg ++p; 2408d522f475Smrg break; 2409d522f475Smrg case 4: 24102eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 2) + 24112eaa94a1Schristos (*p >> 6)]); 24122eaa94a1Schristos buf[x++] = CharOf(base64_code[*p & 0x3F]); 2413d522f475Smrg screen->base64_accu = 0; 2414d522f475Smrg screen->base64_count = 0; 2415d522f475Smrg ++p; 2416d522f475Smrg break; 2417d522f475Smrg } 2418d522f475Smrg if (x >= 63) { 2419d522f475Smrg /* Write 63 or 64 characters */ 2420d522f475Smrg screen->base64_pad += x; 242101037d57Smrg TRACE(("writing base64 interim %s\n", visibleChars(buf, x))); 2422d522f475Smrg tty_vwrite(screen->respond, buf, x); 2423d522f475Smrg x = 0; 2424d522f475Smrg } 2425d522f475Smrg } 2426d522f475Smrg if (x != 0) { 2427d522f475Smrg screen->base64_pad += x; 242801037d57Smrg TRACE(("writing base64 finish %s\n", visibleChars(buf, x))); 2429d522f475Smrg tty_vwrite(screen->respond, buf, x); 2430d522f475Smrg } 2431d522f475Smrg } else 2432d522f475Smrg#endif /* OPT_PASTE64 */ 2433d522f475Smrg#if OPT_READLINE 2434d522f475Smrg if (SCREEN_FLAG(screen, paste_quotes)) { 2435d522f475Smrg while (length--) { 2436492d43a5Smrg tty_vwrite(screen->respond, (const Char *) "\026", 1); /* Control-V */ 2437d522f475Smrg tty_vwrite(screen->respond, lag++, 1); 2438d522f475Smrg } 2439d522f475Smrg } else 2440d522f475Smrg#endif 244101037d57Smrg { 244201037d57Smrg TRACE(("writing base64 padding %s\n", visibleChars(lag, length))); 2443d522f475Smrg tty_vwrite(screen->respond, lag, length); 244401037d57Smrg } 2445d522f475Smrg} 2446d522f475Smrg 2447d522f475Smrgstatic void 2448e0a2b6dfSmrg_WriteSelectionData(XtermWidget xw, Char *line, size_t length) 2449d522f475Smrg{ 2450d522f475Smrg /* Write data to pty a line at a time. */ 2451d522f475Smrg /* Doing this one line at a time may no longer be necessary 2452d522f475Smrg because v_write has been re-written. */ 2453d522f475Smrg 24542e4f8982Smrg#if OPT_PASTE64 24550bd37d32Smrg TScreen *screen = TScreenOf(xw); 24562e4f8982Smrg#endif 2457d522f475Smrg Char *lag, *end; 2458d522f475Smrg 2459d522f475Smrg /* in the VMS version, if tt_pasting isn't set to True then qio 2460d522f475Smrg reads aren't blocked and an infinite loop is entered, where the 2461d522f475Smrg pasted text shows up as new input, goes in again, shows up 2462d522f475Smrg again, ad nauseum. */ 2463d522f475Smrg#ifdef VMS 2464d522f475Smrg tt_pasting = True; 2465d522f475Smrg#endif 2466d522f475Smrg 2467d522f475Smrg end = &line[length]; 2468d522f475Smrg lag = line; 2469d522f475Smrg 2470d522f475Smrg#if OPT_PASTE64 2471d522f475Smrg if (screen->base64_paste) { 24720bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (end - lag)); 2473d522f475Smrg base64_flush(screen); 2474d522f475Smrg } else 2475d522f475Smrg#endif 2476d522f475Smrg { 2477d522f475Smrg if (!SCREEN_FLAG(screen, paste_literal_nl)) { 2478d522f475Smrg Char *cp; 2479d522f475Smrg for (cp = line; cp != end; cp++) { 2480d522f475Smrg if (*cp == '\n') { 2481d522f475Smrg *cp = '\r'; 24820bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (cp - lag + 1)); 2483d522f475Smrg lag = cp + 1; 2484d522f475Smrg } 2485d522f475Smrg } 2486d522f475Smrg } 2487d522f475Smrg 2488d522f475Smrg if (lag != end) { 24890bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (end - lag)); 2490d522f475Smrg } 2491d522f475Smrg } 2492d522f475Smrg#ifdef VMS 2493d522f475Smrg tt_pasting = False; 2494d522f475Smrg tt_start_read(); /* reenable reads or a character may be lost */ 2495d522f475Smrg#endif 2496d522f475Smrg} 2497d522f475Smrg 2498f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2499d522f475Smrgstatic void 2500e0a2b6dfSmrg_WriteKey(TScreen *screen, const Char *in) 2501d522f475Smrg{ 2502d522f475Smrg Char line[16]; 2503d522f475Smrg unsigned count = 0; 2504492d43a5Smrg size_t length = strlen((const char *) in); 2505d522f475Smrg 2506d522f475Smrg if (screen->control_eight_bits) { 2507d522f475Smrg line[count++] = ANSI_CSI; 2508d522f475Smrg } else { 2509d522f475Smrg line[count++] = ANSI_ESC; 2510d522f475Smrg line[count++] = '['; 2511d522f475Smrg } 2512d522f475Smrg while (length--) 2513d522f475Smrg line[count++] = *in++; 2514d522f475Smrg line[count++] = '~'; 2515d522f475Smrg tty_vwrite(screen->respond, line, count); 2516d522f475Smrg} 2517d522f475Smrg#endif /* OPT_READLINE */ 2518d522f475Smrg 25190bd37d32Smrg/* 25200bd37d32Smrg * Unless enabled by the user, strip control characters other than formatting. 25210bd37d32Smrg */ 25220bd37d32Smrgstatic size_t 25230bd37d32SmrgremoveControls(XtermWidget xw, char *value) 25240bd37d32Smrg{ 25250bd37d32Smrg TScreen *screen = TScreenOf(xw); 25260bd37d32Smrg size_t dst = 0; 25270bd37d32Smrg 25280bd37d32Smrg if (screen->allowPasteControls) { 25290bd37d32Smrg dst = strlen(value); 25300bd37d32Smrg } else { 25312e4f8982Smrg size_t src = 0; 25320bd37d32Smrg while ((value[dst] = value[src]) != '\0') { 25330bd37d32Smrg int ch = CharOf(value[src++]); 2534f2e35a3aSmrg 2535f2e35a3aSmrg#define ReplacePaste(n) \ 2536f2e35a3aSmrg if (screen->disallow_paste_controls[n]) \ 2537f2e35a3aSmrg value[dst] = ' ' 2538f2e35a3aSmrg 25390bd37d32Smrg if (ch < 32) { 2540f2e35a3aSmrg ReplacePaste(epC0); 2541f2e35a3aSmrg ReplacePaste(ch); 2542f2e35a3aSmrg ++dst; 2543f2e35a3aSmrg } else if (ch == ANSI_DEL) { 2544f2e35a3aSmrg ReplacePaste(epDEL); 2545f2e35a3aSmrg ++dst; 25460bd37d32Smrg } 25470bd37d32Smrg#if OPT_WIDE_CHARS 2548e0a2b6dfSmrg else if (screen->utf8_inparse || screen->utf8_nrc_mode) 25490bd37d32Smrg ++dst; 25500bd37d32Smrg#endif 25510bd37d32Smrg#if OPT_C1_PRINT || OPT_WIDE_CHARS 25520bd37d32Smrg else if (screen->c1_printable) 25530bd37d32Smrg ++dst; 25540bd37d32Smrg#endif 25550bd37d32Smrg else if (ch >= 128 && ch < 160) 25560bd37d32Smrg continue; 25570bd37d32Smrg else 25580bd37d32Smrg ++dst; 25590bd37d32Smrg } 25600bd37d32Smrg } 25610bd37d32Smrg return dst; 25620bd37d32Smrg} 25630bd37d32Smrg 2564f2e35a3aSmrg#if OPT_SELECTION_OPS 2565f2e35a3aSmrgstatic void 2566f2e35a3aSmrgbeginInternalSelect(XtermWidget xw) 2567f2e35a3aSmrg{ 2568f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2569f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2570f2e35a3aSmrg 2571f2e35a3aSmrg (void) mydata; 2572f2e35a3aSmrg /* override flags so that SelectionReceived only updates a buffer */ 2573f2e35a3aSmrg#if OPT_PASTE64 2574f2e35a3aSmrg mydata->base64_paste = screen->base64_paste; 2575f2e35a3aSmrg screen->base64_paste = 0; 2576f2e35a3aSmrg#endif 2577f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2578f2e35a3aSmrg mydata->paste_brackets = screen->paste_brackets; 2579f2e35a3aSmrg SCREEN_FLAG_unset(screen, paste_brackets); 2580f2e35a3aSmrg#endif 2581f2e35a3aSmrg} 2582f2e35a3aSmrg 2583f2e35a3aSmrgstatic void 2584f2e35a3aSmrgfinishInternalSelect(XtermWidget xw) 2585f2e35a3aSmrg{ 2586f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2587f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2588f2e35a3aSmrg 2589f2e35a3aSmrg (void) mydata; 2590f2e35a3aSmrg#if OPT_PASTE64 2591f2e35a3aSmrg screen->base64_paste = mydata->base64_paste; 2592f2e35a3aSmrg#endif 2593f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2594f2e35a3aSmrg screen->paste_brackets = mydata->paste_brackets; 2595f2e35a3aSmrg#endif 2596f2e35a3aSmrg} 2597f2e35a3aSmrg 2598f2e35a3aSmrg#else 2599f2e35a3aSmrg#define finishInternalSelect(xw) /* nothing */ 2600f2e35a3aSmrg#endif /* OPT_SELECTION_OPS */ 2601f2e35a3aSmrg 2602d522f475Smrg/* SelectionReceived: stuff received selection text into pty */ 2603d522f475Smrg 2604d522f475Smrg/* ARGSUSED */ 2605d522f475Smrgstatic void 2606d522f475SmrgSelectionReceived(Widget w, 2607d522f475Smrg XtPointer client_data, 2608894e0ac8Smrg Atom *selection GCC_UNUSED, 2609894e0ac8Smrg Atom *type, 2610d522f475Smrg XtPointer value, 2611d522f475Smrg unsigned long *length, 2612d522f475Smrg int *format) 2613d522f475Smrg{ 2614d522f475Smrg char **text_list = NULL; 26152e4f8982Smrg int text_list_count = 0; 2616d522f475Smrg XTextProperty text_prop; 2617d522f475Smrg TScreen *screen; 2618d522f475Smrg Display *dpy; 2619d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 2620d522f475Smrg Char *line = (Char *) value; 2621d522f475Smrg#endif 2622d522f475Smrg 2623956cc18dSsnj XtermWidget xw; 2624956cc18dSsnj 2625956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 2626d522f475Smrg return; 2627956cc18dSsnj 2628956cc18dSsnj screen = TScreenOf(xw); 2629d522f475Smrg dpy = XtDisplay(w); 2630d522f475Smrg 2631d522f475Smrg if (*type == 0 /*XT_CONVERT_FAIL */ 2632d522f475Smrg || *length == 0 263301037d57Smrg || value == NULL) { 263401037d57Smrg TRACE(("...no data to convert\n")); 2635d522f475Smrg goto fail; 263601037d57Smrg } 2637d522f475Smrg 2638d522f475Smrg text_prop.value = (unsigned char *) value; 2639d522f475Smrg text_prop.encoding = *type; 2640d522f475Smrg text_prop.format = *format; 2641d522f475Smrg text_prop.nitems = *length; 2642d522f475Smrg 264301037d57Smrg TRACE(("SelectionReceived %s %s format %d, nitems %ld\n", 2644913cc679Smrg TraceAtomName(screen->display, *selection), 2645956cc18dSsnj visibleSelectionTarget(dpy, text_prop.encoding), 2646956cc18dSsnj text_prop.format, 2647956cc18dSsnj text_prop.nitems)); 2648956cc18dSsnj 2649d522f475Smrg#if OPT_WIDE_CHARS 2650e39b573cSmrg if (XSupportsLocale() && screen->wide_chars) { 2651d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2652d522f475Smrg *type == XA_STRING || 2653d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2654d522f475Smrg GettingSelection(dpy, *type, line, *length); 2655d522f475Smrg if (Xutf8TextPropertyToTextList(dpy, &text_prop, 2656d522f475Smrg &text_list, 2657d522f475Smrg &text_list_count) < 0) { 2658e39b573cSmrg TRACE(("default Xutf8 Conversion failed\n")); 2659d522f475Smrg text_list = NULL; 2660d522f475Smrg } 2661d522f475Smrg } 2662d522f475Smrg } else 2663d522f475Smrg#endif /* OPT_WIDE_CHARS */ 2664d522f475Smrg { 2665d522f475Smrg /* Convert the selection to locale's multibyte encoding. */ 2666d522f475Smrg 2667d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2668d522f475Smrg *type == XA_STRING || 2669d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2670d522f475Smrg Status rc; 2671d522f475Smrg 2672d522f475Smrg GettingSelection(dpy, *type, line, *length); 2673d522f475Smrg 2674d522f475Smrg#if OPT_WIDE_CHARS 2675d522f475Smrg if (*type == XA_UTF8_STRING(dpy) && 2676d522f475Smrg !(screen->wide_chars || screen->c1_printable)) { 267720d2c4d2Smrg rc = xtermUtf8ToTextList(xw, &text_prop, 267820d2c4d2Smrg &text_list, &text_list_count); 2679d522f475Smrg } else 2680d522f475Smrg#endif 2681e39b573cSmrg if (*type == XA_STRING && (!XSupportsLocale() || screen->brokenSelections)) { 2682d522f475Smrg rc = XTextPropertyToStringList(&text_prop, 2683d522f475Smrg &text_list, &text_list_count); 2684d522f475Smrg } else { 2685d522f475Smrg rc = XmbTextPropertyToTextList(dpy, &text_prop, 2686d522f475Smrg &text_list, 2687d522f475Smrg &text_list_count); 2688d522f475Smrg } 2689d522f475Smrg if (rc < 0) { 2690d522f475Smrg TRACE(("Conversion failed\n")); 2691d522f475Smrg text_list = NULL; 2692d522f475Smrg } 2693d522f475Smrg } 2694d522f475Smrg } 2695d522f475Smrg 2696d522f475Smrg if (text_list != NULL && text_list_count != 0) { 2697d522f475Smrg int i; 2698d522f475Smrg 2699d522f475Smrg#if OPT_PASTE64 2700d522f475Smrg if (screen->base64_paste) { 2701a1f3da82Smrg /* EMPTY */ ; 2702d522f475Smrg } else 2703d522f475Smrg#endif 2704f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2705f2e35a3aSmrg if (SCREEN_FLAG(screen, paste_brackets) && !screen->selectToBuffer) { 2706492d43a5Smrg _WriteKey(screen, (const Char *) "200"); 2707d522f475Smrg } 2708d522f475Smrg#endif 2709d522f475Smrg for (i = 0; i < text_list_count; i++) { 27100bd37d32Smrg size_t len = removeControls(xw, text_list[i]); 271101037d57Smrg 27120bd37d32Smrg if (screen->selectToBuffer) { 271301037d57Smrg InternalSelect *mydata = &(screen->internal_select); 2714f2e35a3aSmrg if (!mydata->done) { 2715f2e35a3aSmrg size_t have = (mydata->buffer 2716f2e35a3aSmrg ? strlen(mydata->buffer) 2717f2e35a3aSmrg : 0); 2718f2e35a3aSmrg size_t need = have + len + 1; 2719f2e35a3aSmrg char *buffer = realloc(mydata->buffer, need); 2720f2e35a3aSmrg 2721f2e35a3aSmrg if (buffer != 0) { 2722f2e35a3aSmrg strcpy(buffer + have, text_list[i]); 2723f2e35a3aSmrg mydata->buffer = buffer; 2724f2e35a3aSmrg } 2725f2e35a3aSmrg TRACE(("FormatSelect %d.%d .. %d.%d %s\n", 2726f2e35a3aSmrg screen->startSel.row, 2727f2e35a3aSmrg screen->startSel.col, 2728f2e35a3aSmrg screen->endSel.row, 2729f2e35a3aSmrg screen->endSel.col, 2730f2e35a3aSmrg mydata->buffer)); 2731f2e35a3aSmrg mydata->format_select(w, mydata->format, mydata->buffer, 2732f2e35a3aSmrg &(screen->startSel), 2733f2e35a3aSmrg &(screen->endSel)); 2734f2e35a3aSmrg mydata->done = True; 27350bd37d32Smrg } 273601037d57Smrg 27370bd37d32Smrg } else { 27380bd37d32Smrg _WriteSelectionData(xw, (Char *) text_list[i], len); 27390bd37d32Smrg } 2740d522f475Smrg } 2741d522f475Smrg#if OPT_PASTE64 2742d522f475Smrg if (screen->base64_paste) { 2743956cc18dSsnj FinishPaste64(xw); 2744d522f475Smrg } else 2745d522f475Smrg#endif 2746f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2747f2e35a3aSmrg if (SCREEN_FLAG(screen, paste_brackets) && !screen->selectToBuffer) { 2748492d43a5Smrg _WriteKey(screen, (const Char *) "201"); 2749d522f475Smrg } 2750d522f475Smrg#endif 2751f2e35a3aSmrg if (screen->selectToBuffer) { 2752f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2753f2e35a3aSmrg finishInternalSelect(xw); 2754f2e35a3aSmrg if (mydata->done) { 2755f2e35a3aSmrg free(mydata->format); 2756f2e35a3aSmrg free(mydata->buffer); 2757f2e35a3aSmrg memset(mydata, 0, sizeof(*mydata)); 2758f2e35a3aSmrg } 2759f2e35a3aSmrg screen->selectToBuffer = False; 2760f2e35a3aSmrg } 2761d522f475Smrg XFreeStringList(text_list); 276201037d57Smrg } else { 276301037d57Smrg TRACE(("...empty text-list\n")); 2764d522f475Smrg goto fail; 276501037d57Smrg } 2766d522f475Smrg 2767d522f475Smrg XtFree((char *) client_data); 2768d522f475Smrg XtFree((char *) value); 2769d522f475Smrg 2770d522f475Smrg return; 2771d522f475Smrg 2772d522f475Smrg fail: 2773d522f475Smrg if (client_data != 0) { 2774d522f475Smrg struct _SelectionList *list = (struct _SelectionList *) client_data; 2775956cc18dSsnj 2776956cc18dSsnj TRACE(("SelectionReceived ->xtermGetSelection\n")); 2777d522f475Smrg xtermGetSelection(w, list->time, 2778d522f475Smrg list->params, list->count, list->targets); 2779d522f475Smrg XtFree((char *) client_data); 2780d522f475Smrg#if OPT_PASTE64 2781d522f475Smrg } else { 2782956cc18dSsnj FinishPaste64(xw); 2783d522f475Smrg#endif 2784d522f475Smrg } 2785d522f475Smrg return; 2786d522f475Smrg} 2787d522f475Smrg 2788d522f475Smrgvoid 2789d522f475SmrgHandleInsertSelection(Widget w, 2790894e0ac8Smrg XEvent *event, /* assumed to be XButtonEvent* */ 2791e0a2b6dfSmrg String *params, /* selections in precedence order */ 2792d522f475Smrg Cardinal *num_params) 2793d522f475Smrg{ 2794956cc18dSsnj XtermWidget xw; 2795d522f475Smrg 2796956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2797f2e35a3aSmrg TRACE_EVENT("HandleInsertSelection", event, params, num_params); 2798d522f475Smrg if (!SendMousePosition(xw, event)) { 2799d522f475Smrg#if OPT_READLINE 2800d522f475Smrg int ldelta; 2801956cc18dSsnj TScreen *screen = TScreenOf(xw); 2802492d43a5Smrg if (IsBtnEvent(event) 2803f2e35a3aSmrg && !OverrideEvent(event) 2804913cc679Smrg && (okSendMousePos(xw) == MOUSE_OFF) 2805d522f475Smrg && SCREEN_FLAG(screen, paste_moves) 2806d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta)) 2807d522f475Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta); 2808d522f475Smrg#endif /* OPT_READLINE */ 2809d522f475Smrg 2810d522f475Smrg xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL); 2811d522f475Smrg } 2812d522f475Smrg } 2813d522f475Smrg} 2814d522f475Smrg 2815d522f475Smrgstatic SelectUnit 2816956cc18dSsnjEvalSelectUnit(XtermWidget xw, 2817d522f475Smrg Time buttonDownTime, 2818d522f475Smrg SelectUnit defaultUnit, 2819d522f475Smrg unsigned int button) 2820d522f475Smrg{ 2821956cc18dSsnj TScreen *screen = TScreenOf(xw); 2822d522f475Smrg SelectUnit result; 2823d522f475Smrg int delta; 2824d522f475Smrg 2825d522f475Smrg if (button != screen->lastButton) { 282620d2c4d2Smrg delta = screen->multiClickTime + 1; 2827d522f475Smrg } else if (screen->lastButtonUpTime == (Time) 0) { 2828d522f475Smrg /* first time and once in a blue moon */ 2829d522f475Smrg delta = screen->multiClickTime + 1; 2830d522f475Smrg } else if (buttonDownTime > screen->lastButtonUpTime) { 2831d522f475Smrg /* most of the time */ 28322eaa94a1Schristos delta = (int) (buttonDownTime - screen->lastButtonUpTime); 2833d522f475Smrg } else { 2834d522f475Smrg /* time has rolled over since lastButtonUpTime */ 28352eaa94a1Schristos delta = (int) ((((Time) ~ 0) - screen->lastButtonUpTime) + buttonDownTime); 2836d522f475Smrg } 2837d522f475Smrg 2838d522f475Smrg if (delta > screen->multiClickTime) { 2839d522f475Smrg screen->numberOfClicks = 1; 2840d522f475Smrg result = defaultUnit; 2841d522f475Smrg } else { 2842d522f475Smrg result = screen->selectMap[screen->numberOfClicks % screen->maxClicks]; 2843d522f475Smrg screen->numberOfClicks += 1; 2844d522f475Smrg } 2845d522f475Smrg TRACE(("EvalSelectUnit(%d) = %d\n", screen->numberOfClicks, result)); 2846d522f475Smrg return result; 2847d522f475Smrg} 2848d522f475Smrg 2849d522f475Smrgstatic void 2850d522f475Smrgdo_select_start(XtermWidget xw, 2851894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2852e0a2b6dfSmrg CELL *cell) 2853d522f475Smrg{ 2854956cc18dSsnj TScreen *screen = TScreenOf(xw); 2855d522f475Smrg 2856d522f475Smrg if (SendMousePosition(xw, event)) 2857d522f475Smrg return; 2858956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2859d522f475Smrg event->xbutton.time, 2860d522f475Smrg Select_CHAR, 2861d522f475Smrg event->xbutton.button); 2862d522f475Smrg screen->replyToEmacs = False; 2863d522f475Smrg 2864d522f475Smrg#if OPT_READLINE 2865d522f475Smrg lastButtonDownTime = event->xbutton.time; 2866d522f475Smrg#endif 2867d522f475Smrg 2868d522f475Smrg StartSelect(xw, cell); 2869d522f475Smrg} 2870d522f475Smrg 2871d522f475Smrg/* ARGSUSED */ 2872d522f475Smrgvoid 2873d522f475SmrgHandleSelectStart(Widget w, 2874894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2875e0a2b6dfSmrg String *params GCC_UNUSED, 2876d522f475Smrg Cardinal *num_params GCC_UNUSED) 2877d522f475Smrg{ 2878956cc18dSsnj XtermWidget xw; 2879956cc18dSsnj 2880956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2881956cc18dSsnj TScreen *screen = TScreenOf(xw); 2882d522f475Smrg CELL cell; 2883d522f475Smrg 2884f2e35a3aSmrg TRACE_EVENT("HandleSelectStart", event, params, num_params); 2885d522f475Smrg screen->firstValidRow = 0; 2886d522f475Smrg screen->lastValidRow = screen->max_row; 2887d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2888d522f475Smrg 2889d522f475Smrg#if OPT_READLINE 2890d522f475Smrg ExtendingSelection = 0; 2891d522f475Smrg#endif 2892d522f475Smrg 2893d522f475Smrg do_select_start(xw, event, &cell); 2894d522f475Smrg } 2895d522f475Smrg} 2896d522f475Smrg 2897d522f475Smrg/* ARGSUSED */ 2898d522f475Smrgvoid 2899d522f475SmrgHandleKeyboardSelectStart(Widget w, 2900894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2901e0a2b6dfSmrg String *params GCC_UNUSED, 2902d522f475Smrg Cardinal *num_params GCC_UNUSED) 2903d522f475Smrg{ 2904956cc18dSsnj XtermWidget xw; 2905956cc18dSsnj 2906956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2907956cc18dSsnj TScreen *screen = TScreenOf(xw); 29080bd37d32Smrg 2909f2e35a3aSmrg TRACE_EVENT("HandleKeyboardSelectStart", event, params, num_params); 2910d522f475Smrg do_select_start(xw, event, &screen->cursorp); 2911d522f475Smrg } 2912d522f475Smrg} 2913d522f475Smrg 2914d522f475Smrgstatic void 2915894e0ac8SmrgTrackDown(XtermWidget xw, XButtonEvent *event) 2916d522f475Smrg{ 2917956cc18dSsnj TScreen *screen = TScreenOf(xw); 2918d522f475Smrg CELL cell; 2919d522f475Smrg 2920956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2921d522f475Smrg event->time, 2922d522f475Smrg Select_CHAR, 2923d522f475Smrg event->button); 2924d522f475Smrg if (screen->numberOfClicks > 1) { 2925d522f475Smrg PointToCELL(screen, event->y, event->x, &cell); 2926d522f475Smrg screen->replyToEmacs = True; 2927d522f475Smrg StartSelect(xw, &cell); 2928d522f475Smrg } else { 2929d522f475Smrg screen->waitingForTrackInfo = True; 2930492d43a5Smrg EditorButton(xw, event); 2931d522f475Smrg } 2932d522f475Smrg} 2933d522f475Smrg 2934d522f475Smrg#define boundsCheck(x) if (x < 0) \ 2935d522f475Smrg x = 0; \ 2936d522f475Smrg else if (x >= screen->max_row) \ 2937d522f475Smrg x = screen->max_row 2938d522f475Smrg 2939d522f475Smrgvoid 2940d522f475SmrgTrackMouse(XtermWidget xw, 2941d522f475Smrg int func, 2942e0a2b6dfSmrg CELL *start, 2943d522f475Smrg int firstrow, 2944d522f475Smrg int lastrow) 2945d522f475Smrg{ 2946956cc18dSsnj TScreen *screen = TScreenOf(xw); 2947d522f475Smrg 2948d522f475Smrg if (screen->waitingForTrackInfo) { /* if Timed, ignore */ 2949d522f475Smrg screen->waitingForTrackInfo = False; 2950d522f475Smrg 2951d522f475Smrg if (func != 0) { 2952d522f475Smrg CELL first = *start; 2953d522f475Smrg 2954d522f475Smrg boundsCheck(first.row); 2955d522f475Smrg boundsCheck(firstrow); 2956d522f475Smrg boundsCheck(lastrow); 2957d522f475Smrg screen->firstValidRow = firstrow; 2958d522f475Smrg screen->lastValidRow = lastrow; 2959d522f475Smrg screen->replyToEmacs = True; 2960d522f475Smrg StartSelect(xw, &first); 2961d522f475Smrg } 2962d522f475Smrg } 2963d522f475Smrg} 2964d522f475Smrg 2965d522f475Smrgstatic void 2966e0a2b6dfSmrgStartSelect(XtermWidget xw, const CELL *cell) 2967d522f475Smrg{ 2968956cc18dSsnj TScreen *screen = TScreenOf(xw); 2969d522f475Smrg 2970d522f475Smrg TRACE(("StartSelect row=%d, col=%d\n", cell->row, cell->col)); 2971d522f475Smrg if (screen->cursor_state) 2972f2e35a3aSmrg HideCursor(xw); 2973d522f475Smrg if (screen->numberOfClicks == 1) { 2974d522f475Smrg /* set start of selection */ 2975d522f475Smrg screen->rawPos = *cell; 2976d522f475Smrg } 2977d522f475Smrg /* else use old values in rawPos */ 2978d522f475Smrg screen->saveStartR = screen->startExt = screen->rawPos; 2979d522f475Smrg screen->saveEndR = screen->endExt = screen->rawPos; 2980d522f475Smrg if (Coordinate(screen, cell) < Coordinate(screen, &(screen->rawPos))) { 2981d522f475Smrg screen->eventMode = LEFTEXTENSION; 2982d522f475Smrg screen->startExt = *cell; 2983d522f475Smrg } else { 2984d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2985d522f475Smrg screen->endExt = *cell; 2986d522f475Smrg } 2987f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False, True); 2988d522f475Smrg} 2989d522f475Smrg 2990d522f475Smrgstatic void 2991d522f475SmrgEndExtend(XtermWidget xw, 2992894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 2993e0a2b6dfSmrg String *params, /* selections */ 2994d522f475Smrg Cardinal num_params, 2995d522f475Smrg Bool use_cursor_loc) 2996d522f475Smrg{ 2997d522f475Smrg CELL cell; 2998956cc18dSsnj TScreen *screen = TScreenOf(xw); 2999d522f475Smrg 3000f2e35a3aSmrg TRACE_EVENT("EndExtend", event, params, &num_params); 3001d522f475Smrg if (use_cursor_loc) { 3002d522f475Smrg cell = screen->cursorp; 3003d522f475Smrg } else { 3004d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 3005d522f475Smrg } 3006d522f475Smrg ExtendExtend(xw, &cell); 30072e4f8982Smrg 3008d522f475Smrg screen->lastButtonUpTime = event->xbutton.time; 3009d522f475Smrg screen->lastButton = event->xbutton.button; 30102e4f8982Smrg 3011d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 3012d522f475Smrg if (screen->replyToEmacs) { 30132e4f8982Smrg Char line[64]; 30142e4f8982Smrg unsigned count = 0; 30152e4f8982Smrg 3016d522f475Smrg if (screen->control_eight_bits) { 3017d522f475Smrg line[count++] = ANSI_CSI; 3018d522f475Smrg } else { 3019d522f475Smrg line[count++] = ANSI_ESC; 3020d522f475Smrg line[count++] = '['; 3021d522f475Smrg } 3022d522f475Smrg if (isSameCELL(&(screen->rawPos), &(screen->startSel)) 3023d522f475Smrg && isSameCELL(&cell, &(screen->endSel))) { 3024d522f475Smrg /* Use short-form emacs select */ 30250bd37d32Smrg 30260bd37d32Smrg switch (screen->extend_coords) { 30270bd37d32Smrg case 0: 30280bd37d32Smrg case SET_EXT_MODE_MOUSE: 30290bd37d32Smrg line[count++] = 't'; 30300bd37d32Smrg break; 30310bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 3032f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 30330bd37d32Smrg line[count++] = '<'; 30340bd37d32Smrg break; 30350bd37d32Smrg } 30360bd37d32Smrg 3037492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 30380bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3039492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 30400bd37d32Smrg 30410bd37d32Smrg switch (screen->extend_coords) { 30420bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 30430bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 3044f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 30450bd37d32Smrg line[count++] = 't'; 30460bd37d32Smrg break; 30470bd37d32Smrg } 3048d522f475Smrg } else { 3049d522f475Smrg /* long-form, specify everything */ 30500bd37d32Smrg 30510bd37d32Smrg switch (screen->extend_coords) { 30520bd37d32Smrg case 0: 30530bd37d32Smrg case SET_EXT_MODE_MOUSE: 30540bd37d32Smrg line[count++] = 'T'; 30550bd37d32Smrg break; 30560bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 3057f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 30580bd37d32Smrg line[count++] = '<'; 30590bd37d32Smrg break; 30600bd37d32Smrg } 30610bd37d32Smrg 3062492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.col); 30630bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3064492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.row); 30650bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3066492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 30670bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3068492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 30690bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3070492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.col); 30710bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3072492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.row); 30730bd37d32Smrg 30740bd37d32Smrg switch (screen->extend_coords) { 30750bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 30760bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 3077f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 30780bd37d32Smrg line[count++] = 'T'; 30790bd37d32Smrg break; 30800bd37d32Smrg } 3081d522f475Smrg } 3082d522f475Smrg v_write(screen->respond, line, count); 3083f2e35a3aSmrg UnHiliteText(xw); 3084d522f475Smrg } 3085d522f475Smrg } 3086d522f475Smrg SelectSet(xw, event, params, num_params); 3087d522f475Smrg screen->eventMode = NORMAL; 3088d522f475Smrg} 3089d522f475Smrg 3090d522f475Smrgvoid 3091d522f475SmrgHandleSelectSet(Widget w, 3092894e0ac8Smrg XEvent *event, 3093e0a2b6dfSmrg String *params, 3094d522f475Smrg Cardinal *num_params) 3095d522f475Smrg{ 3096956cc18dSsnj XtermWidget xw; 3097956cc18dSsnj 3098956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3099f2e35a3aSmrg TRACE_EVENT("HandleSelectSet", event, params, num_params); 3100956cc18dSsnj SelectSet(xw, event, params, *num_params); 3101d522f475Smrg } 3102d522f475Smrg} 3103d522f475Smrg 3104d522f475Smrg/* ARGSUSED */ 3105d522f475Smrgstatic void 3106d522f475SmrgSelectSet(XtermWidget xw, 3107894e0ac8Smrg XEvent *event GCC_UNUSED, 3108e0a2b6dfSmrg String *params, 3109d522f475Smrg Cardinal num_params) 3110d522f475Smrg{ 3111956cc18dSsnj TScreen *screen = TScreenOf(xw); 3112d522f475Smrg 3113d522f475Smrg TRACE(("SelectSet\n")); 3114d522f475Smrg /* Only do select stuff if non-null select */ 3115d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 3116f2e35a3aSmrg Cardinal n; 3117f2e35a3aSmrg for (n = 0; n < num_params; ++n) { 3118f2e35a3aSmrg SaltTextAway(xw, 3119f2e35a3aSmrg TargetToSelection(screen, params[n]), 3120f2e35a3aSmrg &(screen->startSel), &(screen->endSel)); 3121f2e35a3aSmrg } 31220bd37d32Smrg _OwnSelection(xw, params, num_params); 3123d522f475Smrg } else { 31240bd37d32Smrg ScrnDisownSelection(xw); 3125d522f475Smrg } 3126d522f475Smrg} 3127d522f475Smrg 3128d522f475Smrg#define Abs(x) ((x) < 0 ? -(x) : (x)) 3129d522f475Smrg 3130d522f475Smrg/* ARGSUSED */ 3131d522f475Smrgstatic void 3132d522f475Smrgdo_start_extend(XtermWidget xw, 3133894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3134e0a2b6dfSmrg String *params GCC_UNUSED, 3135d522f475Smrg Cardinal *num_params GCC_UNUSED, 3136d522f475Smrg Bool use_cursor_loc) 3137d522f475Smrg{ 3138956cc18dSsnj TScreen *screen = TScreenOf(xw); 3139d522f475Smrg int coord; 3140d522f475Smrg CELL cell; 3141d522f475Smrg 3142d522f475Smrg if (SendMousePosition(xw, event)) 3143d522f475Smrg return; 3144d522f475Smrg 3145d522f475Smrg screen->firstValidRow = 0; 3146d522f475Smrg screen->lastValidRow = screen->max_row; 3147d522f475Smrg#if OPT_READLINE 3148f2e35a3aSmrg if (OverrideEvent(event) 3149d522f475Smrg || event->xbutton.button != Button3 3150d522f475Smrg || !(SCREEN_FLAG(screen, dclick3_deletes))) 3151d522f475Smrg#endif 3152956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 3153d522f475Smrg event->xbutton.time, 3154d522f475Smrg screen->selectUnit, 3155d522f475Smrg event->xbutton.button); 3156d522f475Smrg screen->replyToEmacs = False; 3157d522f475Smrg 3158d522f475Smrg#if OPT_READLINE 3159f2e35a3aSmrg CheckSecondPress3(xw, screen, event); 3160d522f475Smrg#endif 3161d522f475Smrg 3162d522f475Smrg if (screen->numberOfClicks == 1 3163f2e35a3aSmrg || (SCREEN_FLAG(screen, dclick3_deletes) 3164f2e35a3aSmrg && !OverrideEvent(event))) { 3165d522f475Smrg /* Save existing selection so we can reestablish it if the guy 3166d522f475Smrg extends past the other end of the selection */ 3167d522f475Smrg screen->saveStartR = screen->startExt = screen->startRaw; 3168d522f475Smrg screen->saveEndR = screen->endExt = screen->endRaw; 3169d522f475Smrg } else { 3170d522f475Smrg /* He just needed the selection mode changed, use old values. */ 3171d522f475Smrg screen->startExt = screen->startRaw = screen->saveStartR; 3172d522f475Smrg screen->endExt = screen->endRaw = screen->saveEndR; 3173d522f475Smrg } 3174d522f475Smrg if (use_cursor_loc) { 3175d522f475Smrg cell = screen->cursorp; 3176d522f475Smrg } else { 3177d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 3178d522f475Smrg } 3179d522f475Smrg coord = Coordinate(screen, &cell); 3180d522f475Smrg 3181d522f475Smrg if (Abs(coord - Coordinate(screen, &(screen->startSel))) 3182d522f475Smrg < Abs(coord - Coordinate(screen, &(screen->endSel))) 3183d522f475Smrg || coord < Coordinate(screen, &(screen->startSel))) { 3184d522f475Smrg /* point is close to left side of selection */ 3185d522f475Smrg screen->eventMode = LEFTEXTENSION; 3186d522f475Smrg screen->startExt = cell; 3187d522f475Smrg } else { 3188d522f475Smrg /* point is close to left side of selection */ 3189d522f475Smrg screen->eventMode = RIGHTEXTENSION; 3190d522f475Smrg screen->endExt = cell; 3191d522f475Smrg } 3192f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), True, True); 3193d522f475Smrg 3194d522f475Smrg#if OPT_READLINE 3195d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 3196d522f475Smrg ExtendingSelection = 1; 3197d522f475Smrg#endif 3198d522f475Smrg} 3199d522f475Smrg 3200d522f475Smrgstatic void 3201e0a2b6dfSmrgExtendExtend(XtermWidget xw, const CELL *cell) 3202d522f475Smrg{ 3203956cc18dSsnj TScreen *screen = TScreenOf(xw); 3204d522f475Smrg int coord = Coordinate(screen, cell); 3205d522f475Smrg 3206d522f475Smrg TRACE(("ExtendExtend row=%d, col=%d\n", cell->row, cell->col)); 3207d522f475Smrg if (screen->eventMode == LEFTEXTENSION 3208d522f475Smrg && ((coord + (screen->selectUnit != Select_CHAR)) 3209d522f475Smrg > Coordinate(screen, &(screen->endSel)))) { 3210d522f475Smrg /* Whoops, he's changed his mind. Do RIGHTEXTENSION */ 3211d522f475Smrg screen->eventMode = RIGHTEXTENSION; 3212d522f475Smrg screen->startExt = screen->saveStartR; 3213d522f475Smrg } else if (screen->eventMode == RIGHTEXTENSION 3214d522f475Smrg && coord < Coordinate(screen, &(screen->startSel))) { 3215d522f475Smrg /* Whoops, he's changed his mind. Do LEFTEXTENSION */ 3216d522f475Smrg screen->eventMode = LEFTEXTENSION; 3217d522f475Smrg screen->endExt = screen->saveEndR; 3218d522f475Smrg } 3219d522f475Smrg if (screen->eventMode == LEFTEXTENSION) { 3220d522f475Smrg screen->startExt = *cell; 3221d522f475Smrg } else { 3222d522f475Smrg screen->endExt = *cell; 3223d522f475Smrg } 3224f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False, True); 3225d522f475Smrg 3226d522f475Smrg#if OPT_READLINE 3227d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 3228d522f475Smrg ExtendingSelection = 1; 3229d522f475Smrg#endif 3230d522f475Smrg} 3231d522f475Smrg 3232d522f475Smrgvoid 3233d522f475SmrgHandleStartExtend(Widget w, 3234894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3235e0a2b6dfSmrg String *params, /* unused */ 3236d522f475Smrg Cardinal *num_params) /* unused */ 3237d522f475Smrg{ 3238956cc18dSsnj XtermWidget xw; 3239956cc18dSsnj 3240956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3241f2e35a3aSmrg TRACE_EVENT("HandleStartExtend", event, params, num_params); 3242956cc18dSsnj do_start_extend(xw, event, params, num_params, False); 3243956cc18dSsnj } 3244d522f475Smrg} 3245d522f475Smrg 3246d522f475Smrgvoid 3247d522f475SmrgHandleKeyboardStartExtend(Widget w, 3248894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3249e0a2b6dfSmrg String *params, /* unused */ 3250d522f475Smrg Cardinal *num_params) /* unused */ 3251d522f475Smrg{ 3252956cc18dSsnj XtermWidget xw; 3253956cc18dSsnj 3254956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3255f2e35a3aSmrg TRACE_EVENT("HandleKeyboardStartExtend", event, params, num_params); 3256956cc18dSsnj do_start_extend(xw, event, params, num_params, True); 3257956cc18dSsnj } 3258d522f475Smrg} 3259d522f475Smrg 3260d522f475Smrgvoid 3261e0a2b6dfSmrgScrollSelection(TScreen *screen, int amount, Bool always) 3262d522f475Smrg{ 3263d522f475Smrg int minrow = INX2ROW(screen, -screen->savedlines); 3264d522f475Smrg int maxrow = INX2ROW(screen, screen->max_row); 3265d522f475Smrg int maxcol = screen->max_col; 3266d522f475Smrg 3267d522f475Smrg#define scroll_update_one(cell) \ 3268d522f475Smrg (cell)->row += amount; \ 3269d522f475Smrg if ((cell)->row < minrow) { \ 3270d522f475Smrg (cell)->row = minrow; \ 3271d522f475Smrg (cell)->col = 0; \ 3272d522f475Smrg } \ 3273d522f475Smrg if ((cell)->row > maxrow) { \ 3274d522f475Smrg (cell)->row = maxrow; \ 3275d522f475Smrg (cell)->col = maxcol; \ 3276d522f475Smrg } 3277d522f475Smrg 3278d522f475Smrg scroll_update_one(&(screen->startRaw)); 3279d522f475Smrg scroll_update_one(&(screen->endRaw)); 3280d522f475Smrg scroll_update_one(&(screen->startSel)); 3281d522f475Smrg scroll_update_one(&(screen->endSel)); 3282d522f475Smrg 3283d522f475Smrg scroll_update_one(&(screen->rawPos)); 3284d522f475Smrg 3285d522f475Smrg /* 3286d522f475Smrg * If we are told to scroll the selection but it lies outside the scrolling 3287d522f475Smrg * margins, then that could cause the selection to move (bad). It is not 3288d522f475Smrg * simple to fix, because this function is called both for the scrollbar 3289d522f475Smrg * actions as well as application scrolling. The 'always' flag is set in 3290d522f475Smrg * the former case. The rest of the logic handles the latter. 3291d522f475Smrg */ 3292d522f475Smrg if (ScrnHaveSelection(screen)) { 3293d522f475Smrg int adjust; 3294d522f475Smrg 3295d522f475Smrg adjust = ROW2INX(screen, screen->startH.row); 3296d522f475Smrg if (always 32970bd37d32Smrg || !ScrnHaveRowMargins(screen) 32980bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 3299d522f475Smrg scroll_update_one(&screen->startH); 3300d522f475Smrg } 3301d522f475Smrg adjust = ROW2INX(screen, screen->endH.row); 3302d522f475Smrg if (always 33030bd37d32Smrg || !ScrnHaveRowMargins(screen) 33040bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 3305d522f475Smrg scroll_update_one(&screen->endH); 3306d522f475Smrg } 3307d522f475Smrg } 3308d522f475Smrg 3309d522f475Smrg screen->startHCoord = Coordinate(screen, &screen->startH); 3310d522f475Smrg screen->endHCoord = Coordinate(screen, &screen->endH); 3311d522f475Smrg} 3312d522f475Smrg 3313d522f475Smrg/*ARGSUSED*/ 3314d522f475Smrgvoid 3315f2e35a3aSmrgResizeSelection(TScreen *screen, int rows, int cols) 3316d522f475Smrg{ 3317d522f475Smrg rows--; /* decr to get 0-max */ 3318d522f475Smrg cols--; 3319d522f475Smrg 3320d522f475Smrg if (screen->startRaw.row > rows) 3321d522f475Smrg screen->startRaw.row = rows; 3322d522f475Smrg if (screen->startSel.row > rows) 3323d522f475Smrg screen->startSel.row = rows; 3324d522f475Smrg if (screen->endRaw.row > rows) 3325d522f475Smrg screen->endRaw.row = rows; 3326d522f475Smrg if (screen->endSel.row > rows) 3327d522f475Smrg screen->endSel.row = rows; 3328d522f475Smrg if (screen->rawPos.row > rows) 3329d522f475Smrg screen->rawPos.row = rows; 3330d522f475Smrg 3331d522f475Smrg if (screen->startRaw.col > cols) 3332d522f475Smrg screen->startRaw.col = cols; 3333d522f475Smrg if (screen->startSel.col > cols) 3334d522f475Smrg screen->startSel.col = cols; 3335d522f475Smrg if (screen->endRaw.col > cols) 3336d522f475Smrg screen->endRaw.col = cols; 3337d522f475Smrg if (screen->endSel.col > cols) 3338d522f475Smrg screen->endSel.col = cols; 3339d522f475Smrg if (screen->rawPos.col > cols) 3340d522f475Smrg screen->rawPos.col = cols; 3341d522f475Smrg} 3342d522f475Smrg 3343d522f475Smrg#if OPT_WIDE_CHARS 3344f2e35a3aSmrg#define isWideCell(row, col) isWideFrg((int)XTERM_CELL(row, col)) 3345d522f475Smrg#endif 3346d522f475Smrg 3347d522f475Smrgstatic void 3348e0a2b6dfSmrgPointToCELL(TScreen *screen, 3349d522f475Smrg int y, 3350d522f475Smrg int x, 3351e0a2b6dfSmrg CELL *cell) 3352d522f475Smrg/* Convert pixel coordinates to character coordinates. 3353d522f475Smrg Rows are clipped between firstValidRow and lastValidRow. 3354d522f475Smrg Columns are clipped between to be 0 or greater, but are not clipped to some 3355d522f475Smrg maximum value. */ 3356d522f475Smrg{ 3357d522f475Smrg cell->row = (y - screen->border) / FontHeight(screen); 3358d522f475Smrg if (cell->row < screen->firstValidRow) 3359d522f475Smrg cell->row = screen->firstValidRow; 3360d522f475Smrg else if (cell->row > screen->lastValidRow) 3361d522f475Smrg cell->row = screen->lastValidRow; 3362d522f475Smrg cell->col = (x - OriginX(screen)) / FontWidth(screen); 3363d522f475Smrg if (cell->col < 0) 3364d522f475Smrg cell->col = 0; 3365d522f475Smrg else if (cell->col > MaxCols(screen)) { 3366d522f475Smrg cell->col = MaxCols(screen); 3367d522f475Smrg } 3368d522f475Smrg#if OPT_WIDE_CHARS 3369d522f475Smrg /* 3370d522f475Smrg * If we got a click on the right half of a doublewidth character, 3371d522f475Smrg * pretend it happened on the left half. 3372d522f475Smrg */ 3373d522f475Smrg if (cell->col > 0 3374d522f475Smrg && isWideCell(cell->row, cell->col - 1) 3375d522f475Smrg && (XTERM_CELL(cell->row, cell->col) == HIDDEN_CHAR)) { 3376d522f475Smrg cell->col -= 1; 3377d522f475Smrg } 3378d522f475Smrg#endif 3379d522f475Smrg} 3380d522f475Smrg 3381d522f475Smrg/* 3382d522f475Smrg * Find the last column at which text was drawn on the given row. 3383d522f475Smrg */ 3384d522f475Smrgstatic int 338501037d57SmrgLastTextCol(TScreen *screen, CLineData *ld, int row) 3386d522f475Smrg{ 338720d2c4d2Smrg int i = -1; 3388d522f475Smrg 338920d2c4d2Smrg if (ld != 0) { 339020d2c4d2Smrg if (okScrnRow(screen, row)) { 33912e4f8982Smrg const IAttr *ch; 339220d2c4d2Smrg for (i = screen->max_col, 339320d2c4d2Smrg ch = ld->attribs + i; 339420d2c4d2Smrg i >= 0 && !(*ch & CHARDRAWN); 339520d2c4d2Smrg ch--, i--) { 339620d2c4d2Smrg ; 339720d2c4d2Smrg } 3398d522f475Smrg#if OPT_DEC_CHRSET 339920d2c4d2Smrg if (CSET_DOUBLE(GetLineDblCS(ld))) { 340020d2c4d2Smrg i *= 2; 340120d2c4d2Smrg } 3402d522f475Smrg#endif 340320d2c4d2Smrg } 3404d522f475Smrg } 3405d522f475Smrg return (i); 3406d522f475Smrg} 3407d522f475Smrg 3408d522f475Smrg#if !OPT_WIDE_CHARS 3409d522f475Smrg/* 3410d522f475Smrg** double click table for cut and paste in 8 bits 3411d522f475Smrg** 3412d522f475Smrg** This table is divided in four parts : 3413d522f475Smrg** 3414d522f475Smrg** - control characters [0,0x1f] U [0x80,0x9f] 3415d522f475Smrg** - separators [0x20,0x3f] U [0xa0,0xb9] 3416d522f475Smrg** - binding characters [0x40,0x7f] U [0xc0,0xff] 3417d522f475Smrg** - exceptions 3418d522f475Smrg*/ 3419d522f475Smrg/* *INDENT-OFF* */ 3420d522f475Smrgstatic int charClass[256] = 3421d522f475Smrg{ 3422d522f475Smrg/* NUL SOH STX ETX EOT ENQ ACK BEL */ 3423d522f475Smrg 32, 1, 1, 1, 1, 1, 1, 1, 34240bd37d32Smrg/* BS HT NL VT FF CR SO SI */ 3425d522f475Smrg 1, 32, 1, 1, 1, 1, 1, 1, 3426d522f475Smrg/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 3427d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3428d522f475Smrg/* CAN EM SUB ESC FS GS RS US */ 3429d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3430d522f475Smrg/* SP ! " # $ % & ' */ 3431d522f475Smrg 32, 33, 34, 35, 36, 37, 38, 39, 3432d522f475Smrg/* ( ) * + , - . / */ 3433d522f475Smrg 40, 41, 42, 43, 44, 45, 46, 47, 3434d522f475Smrg/* 0 1 2 3 4 5 6 7 */ 3435d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3436d522f475Smrg/* 8 9 : ; < = > ? */ 3437d522f475Smrg 48, 48, 58, 59, 60, 61, 62, 63, 3438d522f475Smrg/* @ A B C D E F G */ 3439d522f475Smrg 64, 48, 48, 48, 48, 48, 48, 48, 3440d522f475Smrg/* H I J K L M N O */ 3441d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3442d522f475Smrg/* P Q R S T U V W */ 3443d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3444d522f475Smrg/* X Y Z [ \ ] ^ _ */ 3445d522f475Smrg 48, 48, 48, 91, 92, 93, 94, 48, 3446d522f475Smrg/* ` a b c d e f g */ 3447d522f475Smrg 96, 48, 48, 48, 48, 48, 48, 48, 3448d522f475Smrg/* h i j k l m n o */ 3449d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3450d522f475Smrg/* p q r s t u v w */ 3451d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3452d522f475Smrg/* x y z { | } ~ DEL */ 3453d522f475Smrg 48, 48, 48, 123, 124, 125, 126, 1, 3454d522f475Smrg/* x80 x81 x82 x83 IND NEL SSA ESA */ 3455d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3456d522f475Smrg/* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 3457d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3458d522f475Smrg/* DCS PU1 PU2 STS CCH MW SPA EPA */ 3459d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3460d522f475Smrg/* x98 x99 x9A CSI ST OSC PM APC */ 3461d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3462d522f475Smrg/* - i c/ L ox Y- | So */ 3463d522f475Smrg 160, 161, 162, 163, 164, 165, 166, 167, 3464d522f475Smrg/* .. c0 ip << _ R0 - */ 3465d522f475Smrg 168, 169, 170, 171, 172, 173, 174, 175, 3466d522f475Smrg/* o +- 2 3 ' u q| . */ 3467d522f475Smrg 176, 177, 178, 179, 180, 181, 182, 183, 3468d522f475Smrg/* , 1 2 >> 1/4 1/2 3/4 ? */ 3469d522f475Smrg 184, 185, 186, 187, 188, 189, 190, 191, 3470d522f475Smrg/* A` A' A^ A~ A: Ao AE C, */ 3471d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3472d522f475Smrg/* E` E' E^ E: I` I' I^ I: */ 3473d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3474d522f475Smrg/* D- N~ O` O' O^ O~ O: X */ 3475d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 215, 3476d522f475Smrg/* O/ U` U' U^ U: Y' P B */ 3477d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3478d522f475Smrg/* a` a' a^ a~ a: ao ae c, */ 3479d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3480d522f475Smrg/* e` e' e^ e: i` i' i^ i: */ 3481d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3482d522f475Smrg/* d n~ o` o' o^ o~ o: -: */ 3483d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 247, 3484d522f475Smrg/* o/ u` u' u^ u: y' P y: */ 3485d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48}; 3486d522f475Smrg/* *INDENT-ON* */ 3487d522f475Smrg 3488d522f475Smrgint 3489d522f475SmrgSetCharacterClassRange(int low, /* in range of [0..255] */ 3490d522f475Smrg int high, 3491d522f475Smrg int value) /* arbitrary */ 3492d522f475Smrg{ 3493d522f475Smrg 3494d522f475Smrg if (low < 0 || high > 255 || high < low) 3495d522f475Smrg return (-1); 3496d522f475Smrg 3497d522f475Smrg for (; low <= high; low++) 3498d522f475Smrg charClass[low] = value; 3499d522f475Smrg 3500d522f475Smrg return (0); 3501d522f475Smrg} 3502d522f475Smrg#endif 3503d522f475Smrg 3504d522f475Smrgstatic int 3505e0a2b6dfSmrgclass_of(LineData *ld, CELL *cell) 3506d522f475Smrg{ 3507d522f475Smrg CELL temp = *cell; 35080bd37d32Smrg int result = 0; 3509d522f475Smrg 3510d522f475Smrg#if OPT_DEC_CHRSET 3511956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 3512d522f475Smrg temp.col /= 2; 3513d522f475Smrg } 3514d522f475Smrg#endif 35150bd37d32Smrg if (temp.col < (int) ld->lineSize) 35160bd37d32Smrg result = CharacterClass((int) (ld->charData[temp.col])); 35170bd37d32Smrg return result; 3518d522f475Smrg} 3519956cc18dSsnj 3520956cc18dSsnj#if OPT_WIDE_CHARS 3521956cc18dSsnj#define CClassSelects(name, cclass) \ 3522956cc18dSsnj (CClassOf(name) == cclass \ 3523956cc18dSsnj || XTERM_CELL(screen->name.row, screen->name.col) == HIDDEN_CHAR) 3524d522f475Smrg#else 3525956cc18dSsnj#define CClassSelects(name, cclass) \ 3526956cc18dSsnj (class_of(ld.name, &((screen->name))) == cclass) 3527d522f475Smrg#endif 3528d522f475Smrg 3529956cc18dSsnj#define CClassOf(name) class_of(ld.name, &((screen->name))) 3530956cc18dSsnj 3531913cc679Smrg#if OPT_REPORT_CCLASS 3532913cc679Smrgstatic int 3533913cc679Smrgshow_cclass_range(int lo, int hi) 3534913cc679Smrg{ 3535913cc679Smrg int cclass = CharacterClass(lo); 3536913cc679Smrg int ident = (cclass == lo); 3537913cc679Smrg int more = 0; 3538913cc679Smrg if (ident) { 3539913cc679Smrg int ch; 3540913cc679Smrg for (ch = lo + 1; ch <= hi; ch++) { 3541913cc679Smrg if (CharacterClass(ch) != ch) { 3542913cc679Smrg ident = 0; 3543913cc679Smrg break; 3544913cc679Smrg } 3545913cc679Smrg } 3546913cc679Smrg if (ident && (hi < 255)) { 3547913cc679Smrg ch = hi + 1; 3548913cc679Smrg if (CharacterClass(ch) == ch) { 3549913cc679Smrg if (ch >= 255 || CharacterClass(ch + 1) != ch) { 3550913cc679Smrg more = 1; 3551913cc679Smrg } 3552913cc679Smrg } 3553913cc679Smrg } 3554913cc679Smrg } 3555913cc679Smrg if (!more) { 3556913cc679Smrg if (lo == hi) { 3557913cc679Smrg printf("\t%d", lo); 3558913cc679Smrg } else { 3559913cc679Smrg printf("\t%d-%d", lo, hi); 3560913cc679Smrg } 3561913cc679Smrg if (!ident) 3562913cc679Smrg printf(":%d", cclass); 3563913cc679Smrg if (hi < 255) 3564913cc679Smrg printf(", \\"); 3565913cc679Smrg printf("\n"); 3566913cc679Smrg } 3567913cc679Smrg return !more; 3568913cc679Smrg} 3569913cc679Smrg 3570913cc679Smrgvoid 3571913cc679Smrgreport_char_class(XtermWidget xw) 3572913cc679Smrg{ 3573913cc679Smrg /* simple table, to match documentation */ 3574913cc679Smrg static const char charnames[] = 3575913cc679Smrg "NUL\0" "SOH\0" "STX\0" "ETX\0" "EOT\0" "ENQ\0" "ACK\0" "BEL\0" 3576913cc679Smrg " BS\0" " HT\0" " NL\0" " VT\0" " NP\0" " CR\0" " SO\0" " SI\0" 3577913cc679Smrg "DLE\0" "DC1\0" "DC2\0" "DC3\0" "DC4\0" "NAK\0" "SYN\0" "ETB\0" 3578913cc679Smrg "CAN\0" " EM\0" "SUB\0" "ESC\0" " FS\0" " GS\0" " RS\0" " US\0" 3579913cc679Smrg " SP\0" " !\0" " \"\0" " #\0" " $\0" " %\0" " &\0" " '\0" 3580913cc679Smrg " (\0" " )\0" " *\0" " +\0" " ,\0" " -\0" " .\0" " /\0" 3581913cc679Smrg " 0\0" " 1\0" " 2\0" " 3\0" " 4\0" " 5\0" " 6\0" " 7\0" 3582913cc679Smrg " 8\0" " 9\0" " :\0" " ;\0" " <\0" " =\0" " >\0" " ?\0" 3583913cc679Smrg " @\0" " A\0" " B\0" " C\0" " D\0" " E\0" " F\0" " G\0" 3584913cc679Smrg " H\0" " I\0" " J\0" " K\0" " L\0" " M\0" " N\0" " O\0" 3585913cc679Smrg " P\0" " Q\0" " R\0" " S\0" " T\0" " U\0" " V\0" " W\0" 3586913cc679Smrg " X\0" " Y\0" " Z\0" " [\0" " \\\0" " ]\0" " ^\0" " _\0" 3587913cc679Smrg " `\0" " a\0" " b\0" " c\0" " d\0" " e\0" " f\0" " g\0" 3588913cc679Smrg " h\0" " i\0" " j\0" " k\0" " l\0" " m\0" " n\0" " o\0" 3589913cc679Smrg " p\0" " q\0" " r\0" " s\0" " t\0" " u\0" " v\0" " w\0" 3590913cc679Smrg " x\0" " y\0" " z\0" " {\0" " |\0" " }\0" " ~\0" "DEL\0" 3591913cc679Smrg "x80\0" "x81\0" "x82\0" "x83\0" "IND\0" "NEL\0" "SSA\0" "ESA\0" 3592913cc679Smrg "HTS\0" "HTJ\0" "VTS\0" "PLD\0" "PLU\0" " RI\0" "SS2\0" "SS3\0" 3593913cc679Smrg "DCS\0" "PU1\0" "PU2\0" "STS\0" "CCH\0" " MW\0" "SPA\0" "EPA\0" 3594913cc679Smrg "x98\0" "x99\0" "x9A\0" "CSI\0" " ST\0" "OSC\0" " PM\0" "APC\0" 3595913cc679Smrg " -\0" " i\0" " c/\0" " L\0" " ox\0" " Y-\0" " |\0" " So\0" 3596913cc679Smrg " ..\0" " c0\0" " ip\0" " <<\0" " _\0" " \0" " R0\0" " -\0" 3597913cc679Smrg " o\0" " +-\0" " 2\0" " 3\0" " '\0" " u\0" " q|\0" " .\0" 3598913cc679Smrg " ,\0" " 1\0" " 2\0" " >>\0" "1/4\0" "1/2\0" "3/4\0" " ?\0" 3599913cc679Smrg " A`\0" " A'\0" " A^\0" " A~\0" " A:\0" " Ao\0" " AE\0" " C,\0" 3600913cc679Smrg " E`\0" " E'\0" " E^\0" " E:\0" " I`\0" " I'\0" " I^\0" " I:\0" 3601913cc679Smrg " D-\0" " N~\0" " O`\0" " O'\0" " O^\0" " O~\0" " O:\0" " X\0" 3602913cc679Smrg " O/\0" " U`\0" " U'\0" " U^\0" " U:\0" " Y'\0" " P\0" " B\0" 3603913cc679Smrg " a`\0" " a'\0" " a^\0" " a~\0" " a:\0" " ao\0" " ae\0" " c,\0" 3604913cc679Smrg " e`\0" " e'\0" " e^\0" " e:\0" " i`\0" " i'\0" " i^\0" " i:\0" 3605913cc679Smrg " d\0" " n~\0" " o`\0" " o'\0" " o^\0" " o~\0" " o:\0" " -:\0" 3606913cc679Smrg " o/\0" " u`\0" " u'\0" " u^\0" " u:\0" " y'\0" " P\0" " y:\0"; 3607913cc679Smrg int ch, dh; 3608913cc679Smrg int class_p; 3609913cc679Smrg 3610913cc679Smrg (void) xw; 3611913cc679Smrg 3612913cc679Smrg printf("static int charClass[256] = {\n"); 3613913cc679Smrg for (ch = 0; ch < 256; ++ch) { 3614913cc679Smrg const char *s = charnames + (ch * 4); 3615913cc679Smrg if ((ch & 7) == 0) 3616913cc679Smrg printf("/*"); 3617913cc679Smrg printf(" %s ", s); 3618913cc679Smrg if (((ch + 1) & 7) == 0) { 3619913cc679Smrg printf("*/\n "); 3620913cc679Smrg for (dh = ch - 7; dh <= ch; ++dh) { 3621913cc679Smrg printf(" %3d%s", CharacterClass(dh), dh == 255 ? "};" : ","); 3622913cc679Smrg } 3623913cc679Smrg printf("\n"); 3624913cc679Smrg } 3625913cc679Smrg } 3626913cc679Smrg 3627913cc679Smrg /* print the table as if it were the charClass resource */ 3628913cc679Smrg printf("\n"); 3629913cc679Smrg printf("The table is equivalent to this \"charClass\" resource:\n"); 3630913cc679Smrg class_p = CharacterClass(dh = 0); 3631913cc679Smrg for (ch = 0; ch < 256; ++ch) { 3632913cc679Smrg int class_c = CharacterClass(ch); 3633913cc679Smrg if (class_c != class_p) { 3634913cc679Smrg if (show_cclass_range(dh, ch - 1)) { 3635913cc679Smrg dh = ch; 3636913cc679Smrg class_p = class_c; 3637913cc679Smrg } 3638913cc679Smrg } 3639913cc679Smrg } 3640913cc679Smrg if (dh < 255) { 3641913cc679Smrg show_cclass_range(dh, 255); 3642913cc679Smrg } 3643913cc679Smrg 3644913cc679Smrg if_OPT_WIDE_CHARS(TScreenOf(xw), { 3645913cc679Smrg /* if this is a wide-character configuration, print all intervals */ 3646913cc679Smrg report_wide_char_class(); 3647913cc679Smrg }); 3648913cc679Smrg} 3649913cc679Smrg#endif 3650913cc679Smrg 3651d522f475Smrg/* 3652d522f475Smrg * If the given column is past the end of text on the given row, bump to the 3653d522f475Smrg * beginning of the next line. 3654d522f475Smrg */ 3655d522f475Smrgstatic Boolean 3656e0a2b6dfSmrgokPosition(TScreen *screen, 3657e0a2b6dfSmrg LineData **ld, 3658e0a2b6dfSmrg CELL *cell) 3659d522f475Smrg{ 366020d2c4d2Smrg Boolean result = True; 366120d2c4d2Smrg 366220d2c4d2Smrg if (cell->row > screen->max_row) { 366320d2c4d2Smrg result = False; 3664f2e35a3aSmrg TRACE(("okPosition cell row %d > screen max %d\n", cell->row, screen->max_row)); 366520d2c4d2Smrg } else if (cell->col > (LastTextCol(screen, *ld, cell->row) + 1)) { 3666f2e35a3aSmrg TRACE(("okPosition cell col %d > screen max %d\n", cell->col, 3667f2e35a3aSmrg (LastTextCol(screen, *ld, cell->row) + 1))); 366820d2c4d2Smrg if (cell->row < screen->max_row) { 3669f2e35a3aSmrg TRACE(("okPosition cell row %d < screen max %d\n", cell->row, screen->max_row)); 367020d2c4d2Smrg cell->col = 0; 367120d2c4d2Smrg *ld = GET_LINEDATA(screen, ++cell->row); 367220d2c4d2Smrg result = False; 367320d2c4d2Smrg } 3674d522f475Smrg } 367520d2c4d2Smrg return result; 3676d522f475Smrg} 3677d522f475Smrg 3678d522f475Smrgstatic void 3679e0a2b6dfSmrgtrimLastLine(TScreen *screen, 3680e0a2b6dfSmrg LineData **ld, 3681e0a2b6dfSmrg CELL *last) 3682d522f475Smrg{ 368320d2c4d2Smrg if (screen->cutNewline && last->row < screen->max_row) { 3684d522f475Smrg last->col = 0; 3685956cc18dSsnj *ld = GET_LINEDATA(screen, ++last->row); 3686d522f475Smrg } else { 3687956cc18dSsnj last->col = LastTextCol(screen, *ld, last->row) + 1; 3688d522f475Smrg } 3689d522f475Smrg} 3690d522f475Smrg 3691d522f475Smrg#if OPT_SELECT_REGEX 3692d522f475Smrg/* 3693d522f475Smrg * Returns the first row of a wrapped line. 3694d522f475Smrg */ 3695d522f475Smrgstatic int 3696e0a2b6dfSmrgfirstRowOfLine(TScreen *screen, int row, Bool visible) 3697d522f475Smrg{ 3698956cc18dSsnj LineData *ld = 0; 3699d522f475Smrg int limit = visible ? 0 : -screen->savedlines; 3700d522f475Smrg 3701d522f475Smrg while (row > limit && 3702956cc18dSsnj (ld = GET_LINEDATA(screen, row - 1)) != 0 && 3703956cc18dSsnj LineTstWrapped(ld)) { 3704d522f475Smrg --row; 3705956cc18dSsnj } 3706d522f475Smrg return row; 3707d522f475Smrg} 3708d522f475Smrg 3709d522f475Smrg/* 3710d522f475Smrg * Returns the last row of a wrapped line. 3711d522f475Smrg */ 3712d522f475Smrgstatic int 3713e0a2b6dfSmrglastRowOfLine(TScreen *screen, int row) 3714d522f475Smrg{ 3715956cc18dSsnj LineData *ld; 3716956cc18dSsnj 3717d522f475Smrg while (row < screen->max_row && 3718956cc18dSsnj (ld = GET_LINEDATA(screen, row)) != 0 && 3719956cc18dSsnj LineTstWrapped(ld)) { 3720d522f475Smrg ++row; 3721956cc18dSsnj } 3722d522f475Smrg return row; 3723d522f475Smrg} 3724d522f475Smrg 3725d522f475Smrg/* 3726d522f475Smrg * Returns the number of cells on the range of rows. 3727d522f475Smrg */ 3728d522f475Smrgstatic unsigned 3729e0a2b6dfSmrglengthOfLines(TScreen *screen, int firstRow, int lastRow) 3730d522f475Smrg{ 3731d522f475Smrg unsigned length = 0; 3732d522f475Smrg int n; 3733d522f475Smrg 3734d522f475Smrg for (n = firstRow; n <= lastRow; ++n) { 3735956cc18dSsnj LineData *ld = GET_LINEDATA(screen, n); 3736956cc18dSsnj int value = LastTextCol(screen, ld, n); 3737d522f475Smrg if (value >= 0) 37382eaa94a1Schristos length += (unsigned) (value + 1); 3739d522f475Smrg } 3740d522f475Smrg return length; 3741d522f475Smrg} 3742d522f475Smrg 3743d522f475Smrg/* 3744d522f475Smrg * Make a copy of the wrapped-line which corresponds to the given row as a 3745d522f475Smrg * string of bytes. Construct an index for the columns from the beginning of 3746d522f475Smrg * the line. 3747d522f475Smrg */ 3748d522f475Smrgstatic char * 3749e0a2b6dfSmrgmake_indexed_text(TScreen *screen, int row, unsigned length, int *indexed) 3750d522f475Smrg{ 3751d522f475Smrg Char *result = 0; 375220d2c4d2Smrg size_t need = (length + 1); 3753d522f475Smrg 3754d522f475Smrg /* 3755d522f475Smrg * Get a quick upper bound to the number of bytes needed, if the whole 3756d522f475Smrg * string were UTF-8. 3757d522f475Smrg */ 3758d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3759956cc18dSsnj need *= ((screen->lineExtra + 1) * 6); 3760d522f475Smrg }); 3761d522f475Smrg 3762d522f475Smrg if ((result = TypeCallocN(Char, need + 1)) != 0) { 3763956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 3764d522f475Smrg unsigned used = 0; 3765d522f475Smrg Char *last = result; 3766d522f475Smrg 3767d522f475Smrg do { 3768d522f475Smrg int col = 0; 3769956cc18dSsnj int limit = LastTextCol(screen, ld, row); 3770d522f475Smrg 3771d522f475Smrg while (col <= limit) { 3772d522f475Smrg Char *next = last; 3773956cc18dSsnj unsigned data = ld->charData[col]; 3774d522f475Smrg 37750bd37d32Smrg assert(col < (int) ld->lineSize); 3776d522f475Smrg /* some internal points may not be drawn */ 3777d522f475Smrg if (data == 0) 3778d522f475Smrg data = ' '; 3779d522f475Smrg 3780d522f475Smrg if_WIDE_OR_NARROW(screen, { 3781d522f475Smrg next = convertToUTF8(last, data); 3782d522f475Smrg } 3783d522f475Smrg , { 3784d522f475Smrg *next++ = CharOf(data); 3785d522f475Smrg }); 3786d522f475Smrg 3787d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3788956cc18dSsnj size_t off; 3789956cc18dSsnj for_each_combData(off, ld) { 3790956cc18dSsnj data = ld->combData[off][col]; 3791956cc18dSsnj if (data == 0) 3792d522f475Smrg break; 3793d522f475Smrg next = convertToUTF8(next, data); 3794d522f475Smrg } 3795d522f475Smrg }); 3796d522f475Smrg 379720d2c4d2Smrg indexed[used] = (int) (last - result); 3798d522f475Smrg *next = 0; 3799d522f475Smrg /* TRACE(("index[%d.%d] %d:%s\n", row, used, indexed[used], last)); */ 3800d522f475Smrg last = next; 3801d522f475Smrg ++used; 3802d522f475Smrg ++col; 380320d2c4d2Smrg indexed[used] = (int) (next - result); 3804d522f475Smrg } 3805d522f475Smrg } while (used < length && 3806956cc18dSsnj LineTstWrapped(ld) && 3807956cc18dSsnj (ld = GET_LINEDATA(screen, ++row)) != 0 && 3808956cc18dSsnj row < screen->max_row); 3809d522f475Smrg } 3810d522f475Smrg /* TRACE(("result:%s\n", result)); */ 3811d522f475Smrg return (char *) result; 3812d522f475Smrg} 3813d522f475Smrg 3814d522f475Smrg/* 3815d522f475Smrg * Find the column given an offset into the character string by using the 3816d522f475Smrg * index constructed in make_indexed_text(). 3817d522f475Smrg */ 3818d522f475Smrgstatic int 3819d522f475SmrgindexToCol(int *indexed, int len, int off) 3820d522f475Smrg{ 3821d522f475Smrg int col = 0; 3822d522f475Smrg while (indexed[col] < len) { 3823d522f475Smrg if (indexed[col] >= off) 3824d522f475Smrg break; 3825d522f475Smrg ++col; 3826d522f475Smrg } 3827d522f475Smrg return col; 3828d522f475Smrg} 3829d522f475Smrg 3830d522f475Smrg/* 3831d522f475Smrg * Given a row number, and a column offset from that (which may be wrapped), 3832d522f475Smrg * set the cell to the actual row/column values. 3833d522f475Smrg */ 3834d522f475Smrgstatic void 3835e0a2b6dfSmrgcolumnToCell(TScreen *screen, int row, int col, CELL *cell) 3836d522f475Smrg{ 3837d522f475Smrg while (row < screen->max_row) { 383801037d57Smrg CLineData *ld = GET_LINEDATA(screen, row); 3839956cc18dSsnj int last = LastTextCol(screen, ld, row); 3840d522f475Smrg 3841d522f475Smrg /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */ 3842d522f475Smrg if (col <= last) { 3843d522f475Smrg break; 3844d522f475Smrg } 3845d522f475Smrg /* 3846d522f475Smrg * Stop if the current row does not wrap (does not continue the current 3847d522f475Smrg * line). 3848d522f475Smrg */ 3849956cc18dSsnj if (!LineTstWrapped(ld)) { 3850d522f475Smrg col = last + 1; 3851d522f475Smrg break; 3852d522f475Smrg } 3853d522f475Smrg col -= (last + 1); 3854d522f475Smrg ++row; 3855d522f475Smrg } 3856d522f475Smrg if (col < 0) 3857d522f475Smrg col = 0; 3858d522f475Smrg cell->row = row; 3859d522f475Smrg cell->col = col; 3860d522f475Smrg} 3861d522f475Smrg 3862d522f475Smrg/* 3863d522f475Smrg * Given a cell, find the corresponding column offset. 3864d522f475Smrg */ 3865d522f475Smrgstatic int 3866e0a2b6dfSmrgcellToColumn(TScreen *screen, CELL *cell) 3867d522f475Smrg{ 386801037d57Smrg CLineData *ld = 0; 3869d522f475Smrg int col = cell->col; 3870d522f475Smrg int row = firstRowOfLine(screen, cell->row, False); 3871d522f475Smrg while (row < cell->row) { 3872956cc18dSsnj ld = GET_LINEDATA(screen, row); 3873956cc18dSsnj col += LastTextCol(screen, ld, row++); 3874d522f475Smrg } 3875956cc18dSsnj#if OPT_DEC_CHRSET 3876956cc18dSsnj if (ld == 0) 3877956cc18dSsnj ld = GET_LINEDATA(screen, row); 3878956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3879956cc18dSsnj col /= 2; 3880956cc18dSsnj#endif 3881d522f475Smrg return col; 3882d522f475Smrg} 3883d522f475Smrg 3884d522f475Smrgstatic void 3885e0a2b6dfSmrgdo_select_regex(TScreen *screen, CELL *startc, CELL *endc) 3886d522f475Smrg{ 3887956cc18dSsnj LineData *ld = GET_LINEDATA(screen, startc->row); 3888d522f475Smrg int inx = ((screen->numberOfClicks - 1) % screen->maxClicks); 3889d522f475Smrg char *expr = screen->selectExpr[inx]; 3890d522f475Smrg regex_t preg; 3891d522f475Smrg regmatch_t match; 3892d522f475Smrg 389301037d57Smrg TRACE(("Select_REGEX[%d]:%s\n", inx, NonNull(expr))); 3894956cc18dSsnj if (okPosition(screen, &ld, startc) && expr != 0) { 3895d522f475Smrg if (regcomp(&preg, expr, REG_EXTENDED) == 0) { 3896d522f475Smrg int firstRow = firstRowOfLine(screen, startc->row, True); 3897d522f475Smrg int lastRow = lastRowOfLine(screen, firstRow); 3898d522f475Smrg unsigned size = lengthOfLines(screen, firstRow, lastRow); 3899d522f475Smrg int actual = cellToColumn(screen, startc); 39002e4f8982Smrg int *indexed; 3901d522f475Smrg 3902d522f475Smrg TRACE(("regcomp ok rows %d..%d bytes %d\n", 3903d522f475Smrg firstRow, lastRow, size)); 3904d522f475Smrg 3905d522f475Smrg if ((indexed = TypeCallocN(int, size + 1)) != 0) { 39062e4f8982Smrg char *search; 3907d522f475Smrg if ((search = make_indexed_text(screen, 3908d522f475Smrg firstRow, 3909d522f475Smrg size, 3910d522f475Smrg indexed)) != 0) { 39112eaa94a1Schristos int len = (int) strlen(search); 3912d522f475Smrg int col; 3913d522f475Smrg int best_col = -1; 3914d522f475Smrg int best_len = -1; 3915d522f475Smrg 3916913cc679Smrg startc->row = 0; 3917913cc679Smrg startc->col = 0; 3918913cc679Smrg endc->row = 0; 3919913cc679Smrg endc->col = 0; 3920913cc679Smrg 3921d522f475Smrg for (col = 0; indexed[col] < len; ++col) { 3922d522f475Smrg if (regexec(&preg, 3923d522f475Smrg search + indexed[col], 392420d2c4d2Smrg (size_t) 1, &match, 0) == 0) { 3925894e0ac8Smrg int start_inx = (int) (match.rm_so + indexed[col]); 3926894e0ac8Smrg int finis_inx = (int) (match.rm_eo + indexed[col]); 3927d522f475Smrg int start_col = indexToCol(indexed, len, start_inx); 3928d522f475Smrg int finis_col = indexToCol(indexed, len, finis_inx); 3929d522f475Smrg 3930d522f475Smrg if (start_col <= actual && 3931913cc679Smrg actual <= finis_col) { 3932d522f475Smrg int test = finis_col - start_col; 3933d522f475Smrg if (best_len < test) { 3934d522f475Smrg best_len = test; 3935d522f475Smrg best_col = start_col; 3936d522f475Smrg TRACE(("match column %d len %d\n", 3937d522f475Smrg best_col, 3938d522f475Smrg best_len)); 3939d522f475Smrg } 3940d522f475Smrg } 3941d522f475Smrg } 3942d522f475Smrg } 3943d522f475Smrg if (best_col >= 0) { 3944d522f475Smrg int best_nxt = best_col + best_len; 3945d522f475Smrg columnToCell(screen, firstRow, best_col, startc); 3946d522f475Smrg columnToCell(screen, firstRow, best_nxt, endc); 3947d522f475Smrg TRACE(("search::%s\n", search)); 3948d522f475Smrg TRACE(("indexed:%d..%d -> %d..%d\n", 3949d522f475Smrg best_col, best_nxt, 3950d522f475Smrg indexed[best_col], 3951d522f475Smrg indexed[best_nxt])); 3952d522f475Smrg TRACE(("matched:%d:%s\n", 3953d522f475Smrg indexed[best_nxt] + 1 - 3954d522f475Smrg indexed[best_col], 3955956cc18dSsnj visibleChars((Char *) (search + indexed[best_col]), 3956d522f475Smrg (unsigned) (indexed[best_nxt] + 3957d522f475Smrg 1 - 3958d522f475Smrg indexed[best_col])))); 3959d522f475Smrg } 3960d522f475Smrg free(search); 3961d522f475Smrg } 3962d522f475Smrg free(indexed); 3963956cc18dSsnj#if OPT_DEC_CHRSET 3964956cc18dSsnj if ((ld = GET_LINEDATA(screen, startc->row)) != 0) { 3965956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3966956cc18dSsnj startc->col *= 2; 3967956cc18dSsnj } 3968956cc18dSsnj if ((ld = GET_LINEDATA(screen, endc->row)) != 0) { 3969956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3970956cc18dSsnj endc->col *= 2; 3971956cc18dSsnj } 3972956cc18dSsnj#endif 3973d522f475Smrg } 3974d522f475Smrg regfree(&preg); 3975d522f475Smrg } 3976d522f475Smrg } 3977d522f475Smrg} 3978d522f475Smrg#endif /* OPT_SELECT_REGEX */ 3979d522f475Smrg 3980956cc18dSsnj#define InitRow(name) \ 3981956cc18dSsnj ld.name = GET_LINEDATA(screen, screen->name.row) 3982956cc18dSsnj 3983956cc18dSsnj#define NextRow(name) \ 3984956cc18dSsnj ld.name = GET_LINEDATA(screen, ++screen->name.row) 3985956cc18dSsnj 3986956cc18dSsnj#define PrevRow(name) \ 3987956cc18dSsnj ld.name = GET_LINEDATA(screen, --screen->name.row) 3988956cc18dSsnj 398920d2c4d2Smrg#define MoreRows(name) \ 399020d2c4d2Smrg (screen->name.row < screen->max_row) 399120d2c4d2Smrg 3992956cc18dSsnj#define isPrevWrapped(name) \ 3993956cc18dSsnj (screen->name.row > 0 \ 3994956cc18dSsnj && (ltmp = GET_LINEDATA(screen, screen->name.row - 1)) != 0 \ 3995956cc18dSsnj && LineTstWrapped(ltmp)) 3996956cc18dSsnj 3997d522f475Smrg/* 3998d522f475Smrg * sets startSel endSel 3999d522f475Smrg * ensuring that they have legal values 4000d522f475Smrg */ 4001d522f475Smrgstatic void 4002d522f475SmrgComputeSelect(XtermWidget xw, 4003e0a2b6dfSmrg CELL *startc, 4004e0a2b6dfSmrg CELL *endc, 4005f2e35a3aSmrg Bool extend, 4006f2e35a3aSmrg Bool normal) 4007d522f475Smrg{ 4008956cc18dSsnj TScreen *screen = TScreenOf(xw); 4009956cc18dSsnj 4010d522f475Smrg int cclass; 4011d522f475Smrg CELL first = *startc; 4012d522f475Smrg CELL last = *endc; 4013956cc18dSsnj Boolean ignored = False; 4014956cc18dSsnj 4015956cc18dSsnj struct { 4016956cc18dSsnj LineData *startSel; 4017956cc18dSsnj LineData *endSel; 4018956cc18dSsnj } ld; 4019956cc18dSsnj LineData *ltmp; 4020d522f475Smrg 4021d522f475Smrg TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n", 4022d522f475Smrg first.row, first.col, 4023d522f475Smrg last.row, last.col, 4024d522f475Smrg extend ? "" : "no")); 4025d522f475Smrg 4026d522f475Smrg#if OPT_WIDE_CHARS 4027d522f475Smrg if (first.col > 1 4028d522f475Smrg && isWideCell(first.row, first.col - 1) 4029d522f475Smrg && XTERM_CELL(first.row, first.col - 0) == HIDDEN_CHAR) { 403020d2c4d2Smrg TRACE(("Adjusting start. Changing downwards from %i.\n", first.col)); 4031d522f475Smrg first.col -= 1; 4032d522f475Smrg if (last.col == (first.col + 1)) 4033d522f475Smrg last.col--; 4034d522f475Smrg } 4035d522f475Smrg 4036d522f475Smrg if (last.col > 1 4037d522f475Smrg && isWideCell(last.row, last.col - 1) 4038d522f475Smrg && XTERM_CELL(last.row, last.col) == HIDDEN_CHAR) { 4039d522f475Smrg last.col += 1; 4040d522f475Smrg } 4041d522f475Smrg#endif 4042d522f475Smrg 4043d522f475Smrg if (Coordinate(screen, &first) <= Coordinate(screen, &last)) { 4044d522f475Smrg screen->startSel = screen->startRaw = first; 4045d522f475Smrg screen->endSel = screen->endRaw = last; 4046d522f475Smrg } else { /* Swap them */ 4047d522f475Smrg screen->startSel = screen->startRaw = last; 4048d522f475Smrg screen->endSel = screen->endRaw = first; 4049d522f475Smrg } 4050d522f475Smrg 4051956cc18dSsnj InitRow(startSel); 4052956cc18dSsnj InitRow(endSel); 4053956cc18dSsnj 4054d522f475Smrg switch (screen->selectUnit) { 4055d522f475Smrg case Select_CHAR: 4056956cc18dSsnj (void) okPosition(screen, &(ld.startSel), &(screen->startSel)); 4057956cc18dSsnj (void) okPosition(screen, &(ld.endSel), &(screen->endSel)); 4058d522f475Smrg break; 4059d522f475Smrg 4060d522f475Smrg case Select_WORD: 4061d522f475Smrg TRACE(("Select_WORD\n")); 4062956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 4063f2e35a3aSmrg CELL mark; 4064956cc18dSsnj cclass = CClassOf(startSel); 4065f2e35a3aSmrg TRACE(("...starting with class %d\n", cclass)); 4066d522f475Smrg do { 4067f2e35a3aSmrg mark = screen->startSel; 4068d522f475Smrg --screen->startSel.col; 4069956cc18dSsnj if (screen->startSel.col < 0 4070956cc18dSsnj && isPrevWrapped(startSel)) { 4071956cc18dSsnj PrevRow(startSel); 4072956cc18dSsnj screen->startSel.col = LastTextCol(screen, ld.startSel, screen->startSel.row); 4073d522f475Smrg } 4074d522f475Smrg } while (screen->startSel.col >= 0 4075956cc18dSsnj && CClassSelects(startSel, cclass)); 4076f2e35a3aSmrg if (normal) 4077f2e35a3aSmrg ++screen->startSel.col; 4078f2e35a3aSmrg else 4079f2e35a3aSmrg screen->startSel = mark; 4080d522f475Smrg } 4081d522f475Smrg#if OPT_WIDE_CHARS 4082f2e35a3aSmrg#define SkipHiddenCell(mark) \ 4083f2e35a3aSmrg if (mark.col && XTERM_CELL(mark.row, mark.col) == HIDDEN_CHAR) \ 4084f2e35a3aSmrg mark.col++ 4085f2e35a3aSmrg#else 4086f2e35a3aSmrg#define SkipHiddenCell(mark) /* nothing */ 4087d522f475Smrg#endif 4088f2e35a3aSmrg SkipHiddenCell(screen->startSel); 4089f2e35a3aSmrg 4090f2e35a3aSmrg if (!normal) { 4091f2e35a3aSmrg screen->endSel = screen->startSel; 4092f2e35a3aSmrg ld.endSel = ld.startSel; 4093f2e35a3aSmrg } 4094d522f475Smrg 4095956cc18dSsnj if (okPosition(screen, &(ld.endSel), &(screen->endSel))) { 40962e4f8982Smrg int length = LastTextCol(screen, ld.endSel, screen->endSel.row); 4097956cc18dSsnj cclass = CClassOf(endSel); 4098f2e35a3aSmrg TRACE(("...ending with class %d\n", cclass)); 4099d522f475Smrg do { 4100d522f475Smrg ++screen->endSel.col; 4101d522f475Smrg if (screen->endSel.col > length 4102956cc18dSsnj && LineTstWrapped(ld.endSel)) { 410320d2c4d2Smrg if (!MoreRows(endSel)) 410420d2c4d2Smrg break; 4105d522f475Smrg screen->endSel.col = 0; 4106956cc18dSsnj NextRow(endSel); 4107956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 4108d522f475Smrg } 4109d522f475Smrg } while (screen->endSel.col <= length 4110956cc18dSsnj && CClassSelects(endSel, cclass)); 4111f2e35a3aSmrg if (normal 4112f2e35a3aSmrg && screen->endSel.col > length + 1 411320d2c4d2Smrg && MoreRows(endSel)) { 4114d522f475Smrg screen->endSel.col = 0; 4115956cc18dSsnj NextRow(endSel); 4116d522f475Smrg } 4117d522f475Smrg } 4118f2e35a3aSmrg SkipHiddenCell(screen->endSel); 4119d522f475Smrg 4120d522f475Smrg screen->saveStartW = screen->startSel; 4121d522f475Smrg break; 4122d522f475Smrg 4123d522f475Smrg case Select_LINE: 4124d522f475Smrg TRACE(("Select_LINE\n")); 412520d2c4d2Smrg while (LineTstWrapped(ld.endSel) 412620d2c4d2Smrg && MoreRows(endSel)) { 4127956cc18dSsnj NextRow(endSel); 4128d522f475Smrg } 4129d522f475Smrg if (screen->cutToBeginningOfLine 4130d522f475Smrg || screen->startSel.row < screen->saveStartW.row) { 4131d522f475Smrg screen->startSel.col = 0; 4132956cc18dSsnj while (isPrevWrapped(startSel)) { 4133956cc18dSsnj PrevRow(startSel); 4134d522f475Smrg } 4135d522f475Smrg } else if (!extend) { 4136d522f475Smrg if ((first.row < screen->saveStartW.row) 4137d522f475Smrg || (isSameRow(&first, &(screen->saveStartW)) 4138d522f475Smrg && first.col < screen->saveStartW.col)) { 4139d522f475Smrg screen->startSel.col = 0; 4140956cc18dSsnj while (isPrevWrapped(startSel)) { 4141956cc18dSsnj PrevRow(startSel); 4142d522f475Smrg } 4143d522f475Smrg } else { 4144d522f475Smrg screen->startSel = screen->saveStartW; 4145d522f475Smrg } 4146d522f475Smrg } 4147956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 4148d522f475Smrg break; 4149d522f475Smrg 4150d522f475Smrg case Select_GROUP: /* paragraph */ 4151d522f475Smrg TRACE(("Select_GROUP\n")); 4152956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 4153d522f475Smrg /* scan backward for beginning of group */ 4154d522f475Smrg while (screen->startSel.row > 0 && 4155956cc18dSsnj (LastTextCol(screen, ld.startSel, screen->startSel.row - 4156956cc18dSsnj 1) > 0 || 4157956cc18dSsnj isPrevWrapped(startSel))) { 4158956cc18dSsnj PrevRow(startSel); 4159d522f475Smrg } 4160d522f475Smrg screen->startSel.col = 0; 4161d522f475Smrg /* scan forward for end of group */ 416220d2c4d2Smrg while (MoreRows(endSel) && 4163956cc18dSsnj (LastTextCol(screen, ld.endSel, screen->endSel.row + 1) > 4164956cc18dSsnj 0 || 4165956cc18dSsnj LineTstWrapped(ld.endSel))) { 4166956cc18dSsnj NextRow(endSel); 4167d522f475Smrg } 4168956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 4169d522f475Smrg } 4170d522f475Smrg break; 4171d522f475Smrg 4172d522f475Smrg case Select_PAGE: /* everything one can see */ 4173d522f475Smrg TRACE(("Select_PAGE\n")); 4174d522f475Smrg screen->startSel.row = 0; 4175d522f475Smrg screen->startSel.col = 0; 417620d2c4d2Smrg screen->endSel.row = MaxRows(screen); 4177d522f475Smrg screen->endSel.col = 0; 4178d522f475Smrg break; 4179d522f475Smrg 4180d522f475Smrg case Select_ALL: /* counts scrollback if in normal screen */ 4181d522f475Smrg TRACE(("Select_ALL\n")); 4182d522f475Smrg screen->startSel.row = -screen->savedlines; 4183d522f475Smrg screen->startSel.col = 0; 418420d2c4d2Smrg screen->endSel.row = MaxRows(screen); 4185d522f475Smrg screen->endSel.col = 0; 4186d522f475Smrg break; 4187d522f475Smrg 4188d522f475Smrg#if OPT_SELECT_REGEX 4189d522f475Smrg case Select_REGEX: 4190d522f475Smrg do_select_regex(screen, &(screen->startSel), &(screen->endSel)); 4191d522f475Smrg break; 4192d522f475Smrg#endif 4193d522f475Smrg 4194d522f475Smrg case NSELECTUNITS: /* always ignore */ 4195956cc18dSsnj ignored = True; 4196956cc18dSsnj break; 4197d522f475Smrg } 4198d522f475Smrg 4199956cc18dSsnj if (!ignored) { 4200956cc18dSsnj /* check boundaries */ 4201956cc18dSsnj ScrollSelection(screen, 0, False); 4202956cc18dSsnj TrackText(xw, &(screen->startSel), &(screen->endSel)); 4203956cc18dSsnj } 4204d522f475Smrg 4205d522f475Smrg return; 4206d522f475Smrg} 4207d522f475Smrg 4208d522f475Smrg/* Guaranteed (first.row, first.col) <= (last.row, last.col) */ 4209d522f475Smrgstatic void 4210d522f475SmrgTrackText(XtermWidget xw, 4211e0a2b6dfSmrg const CELL *firstp, 4212e0a2b6dfSmrg const CELL *lastp) 4213d522f475Smrg{ 4214956cc18dSsnj TScreen *screen = TScreenOf(xw); 4215d522f475Smrg int from, to; 4216d522f475Smrg CELL old_start, old_end; 4217d522f475Smrg CELL first = *firstp; 4218d522f475Smrg CELL last = *lastp; 4219d522f475Smrg 4220d522f475Smrg TRACE(("TrackText(first=%d,%d, last=%d,%d)\n", 4221d522f475Smrg first.row, first.col, last.row, last.col)); 4222d522f475Smrg 4223d522f475Smrg old_start = screen->startH; 4224d522f475Smrg old_end = screen->endH; 42250bd37d32Smrg TRACE(("...previous(first=%d,%d, last=%d,%d)\n", 42260bd37d32Smrg old_start.row, old_start.col, 42270bd37d32Smrg old_end.row, old_end.col)); 4228d522f475Smrg if (isSameCELL(&first, &old_start) && 42290bd37d32Smrg isSameCELL(&last, &old_end)) { 4230d522f475Smrg return; 42310bd37d32Smrg } 42320bd37d32Smrg 4233d522f475Smrg screen->startH = first; 4234d522f475Smrg screen->endH = last; 4235d522f475Smrg from = Coordinate(screen, &screen->startH); 4236d522f475Smrg to = Coordinate(screen, &screen->endH); 4237d522f475Smrg if (to <= screen->startHCoord || from > screen->endHCoord) { 4238d522f475Smrg /* No overlap whatsoever between old and new hilite */ 4239d522f475Smrg ReHiliteText(xw, &old_start, &old_end); 4240d522f475Smrg ReHiliteText(xw, &first, &last); 4241d522f475Smrg } else { 4242d522f475Smrg if (from < screen->startHCoord) { 4243d522f475Smrg /* Extend left end */ 4244d522f475Smrg ReHiliteText(xw, &first, &old_start); 4245d522f475Smrg } else if (from > screen->startHCoord) { 4246d522f475Smrg /* Shorten left end */ 4247d522f475Smrg ReHiliteText(xw, &old_start, &first); 4248d522f475Smrg } 4249d522f475Smrg if (to > screen->endHCoord) { 4250d522f475Smrg /* Extend right end */ 4251d522f475Smrg ReHiliteText(xw, &old_end, &last); 4252d522f475Smrg } else if (to < screen->endHCoord) { 4253d522f475Smrg /* Shorten right end */ 4254d522f475Smrg ReHiliteText(xw, &last, &old_end); 4255d522f475Smrg } 4256d522f475Smrg } 4257d522f475Smrg screen->startHCoord = from; 4258d522f475Smrg screen->endHCoord = to; 4259d522f475Smrg} 4260d522f475Smrg 4261f2e35a3aSmrgstatic void 4262f2e35a3aSmrgUnHiliteText(XtermWidget xw) 4263f2e35a3aSmrg{ 4264f2e35a3aSmrg TrackText(xw, &zeroCELL, &zeroCELL); 4265f2e35a3aSmrg} 4266f2e35a3aSmrg 4267d522f475Smrg/* Guaranteed that (first->row, first->col) <= (last->row, last->col) */ 4268d522f475Smrgstatic void 4269d522f475SmrgReHiliteText(XtermWidget xw, 4270e0a2b6dfSmrg CELL *firstp, 4271e0a2b6dfSmrg CELL *lastp) 4272d522f475Smrg{ 4273956cc18dSsnj TScreen *screen = TScreenOf(xw); 4274d522f475Smrg CELL first = *firstp; 4275d522f475Smrg CELL last = *lastp; 4276d522f475Smrg 4277d522f475Smrg TRACE(("ReHiliteText from %d.%d to %d.%d\n", 4278d522f475Smrg first.row, first.col, last.row, last.col)); 4279d522f475Smrg 4280d522f475Smrg if (first.row < 0) 4281d522f475Smrg first.row = first.col = 0; 4282d522f475Smrg else if (first.row > screen->max_row) 4283d522f475Smrg return; /* nothing to do, since last.row >= first.row */ 4284d522f475Smrg 4285d522f475Smrg if (last.row < 0) 4286d522f475Smrg return; /* nothing to do, since first.row <= last.row */ 4287d522f475Smrg else if (last.row > screen->max_row) { 4288d522f475Smrg last.row = screen->max_row; 4289d522f475Smrg last.col = MaxCols(screen); 4290d522f475Smrg } 4291d522f475Smrg if (isSameCELL(&first, &last)) 4292d522f475Smrg return; 4293d522f475Smrg 4294d522f475Smrg if (!isSameRow(&first, &last)) { /* do multiple rows */ 42952e4f8982Smrg int i; 4296d522f475Smrg if ((i = screen->max_col - first.col + 1) > 0) { /* first row */ 4297d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, i, True); 4298d522f475Smrg } 4299d522f475Smrg if ((i = last.row - first.row - 1) > 0) { /* middle rows */ 4300d522f475Smrg ScrnRefresh(xw, first.row + 1, 0, i, MaxCols(screen), True); 4301d522f475Smrg } 4302d522f475Smrg if (last.col > 0 && last.row <= screen->max_row) { /* last row */ 4303d522f475Smrg ScrnRefresh(xw, last.row, 0, 1, last.col, True); 4304d522f475Smrg } 4305d522f475Smrg } else { /* do single row */ 4306d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, last.col - first.col, True); 4307d522f475Smrg } 4308d522f475Smrg} 4309d522f475Smrg 4310d522f475Smrg/* 4311913cc679Smrg * Guaranteed that (cellc->row, cellc->col) <= (cell->row, cell->col), 4312913cc679Smrg * and that both points are valid 4313d522f475Smrg * (may have cell->row = screen->max_row+1, cell->col = 0). 4314d522f475Smrg */ 4315d522f475Smrgstatic void 4316d522f475SmrgSaltTextAway(XtermWidget xw, 4317f2e35a3aSmrg int which, 4318e0a2b6dfSmrg CELL *cellc, 4319e0a2b6dfSmrg CELL *cell) 4320d522f475Smrg{ 4321956cc18dSsnj TScreen *screen = TScreenOf(xw); 4322f2e35a3aSmrg SelectedCells *scp; 4323f2e35a3aSmrg int i; 4324d522f475Smrg int eol; 4325f2e35a3aSmrg int need = 0; 4326f2e35a3aSmrg size_t have = 0; 4327d522f475Smrg Char *line; 4328d522f475Smrg Char *lp; 4329d522f475Smrg CELL first = *cellc; 4330d522f475Smrg CELL last = *cell; 4331d522f475Smrg 4332f2e35a3aSmrg if (which < 0 || which >= MAX_SELECTIONS) { 4333f2e35a3aSmrg TRACE(("SaltTextAway - which selection?\n")); 4334f2e35a3aSmrg return; 4335f2e35a3aSmrg } 4336f2e35a3aSmrg scp = &(screen->selected_cells[which]); 4337f2e35a3aSmrg 4338f2e35a3aSmrg TRACE(("SaltTextAway which=%d, first=%d,%d, last=%d,%d\n", 4339f2e35a3aSmrg which, first.row, first.col, last.row, last.col)); 4340f2e35a3aSmrg 4341d522f475Smrg if (isSameRow(&first, &last) && first.col > last.col) { 43422e4f8982Smrg int tmp; 4343956cc18dSsnj EXCHANGE(first.col, last.col, tmp); 4344d522f475Smrg } 4345d522f475Smrg 4346d522f475Smrg --last.col; 4347d522f475Smrg /* first we need to know how long the string is before we can save it */ 4348d522f475Smrg 4349d522f475Smrg if (isSameRow(&last, &first)) { 4350f2e35a3aSmrg need = Length(screen, first.row, first.col, last.col); 4351d522f475Smrg } else { /* two cases, cut is on same line, cut spans multiple lines */ 4352f2e35a3aSmrg need += Length(screen, first.row, first.col, screen->max_col) + 1; 4353d522f475Smrg for (i = first.row + 1; i < last.row; i++) 4354f2e35a3aSmrg need += Length(screen, i, 0, screen->max_col) + 1; 4355d522f475Smrg if (last.col >= 0) 4356f2e35a3aSmrg need += Length(screen, last.row, 0, last.col); 4357d522f475Smrg } 4358d522f475Smrg 4359d522f475Smrg /* UTF-8 may require more space */ 4360d522f475Smrg if_OPT_WIDE_CHARS(screen, { 4361f2e35a3aSmrg if (need > 0) { 4362f2e35a3aSmrg if (screen->max_combining > 0) 4363f2e35a3aSmrg need += screen->max_combining; 4364f2e35a3aSmrg need *= 6; 4365f2e35a3aSmrg } 4366d522f475Smrg }); 4367d522f475Smrg 4368d522f475Smrg /* now get some memory to save it in */ 4369f2e35a3aSmrg if (need < 0) 4370f2e35a3aSmrg return; 4371d522f475Smrg 4372f2e35a3aSmrg if (scp->data_limit <= (unsigned) need) { 4373f2e35a3aSmrg if ((line = (Char *) malloc((size_t) need + 1)) == 0) 4374d522f475Smrg SysError(ERROR_BMALLOC2); 4375f2e35a3aSmrg free(scp->data_buffer); 4376f2e35a3aSmrg scp->data_buffer = line; 4377f2e35a3aSmrg scp->data_limit = (size_t) (need + 1); 4378d522f475Smrg } else { 4379f2e35a3aSmrg line = scp->data_buffer; 4380d522f475Smrg } 4381d522f475Smrg 4382f2e35a3aSmrg if (line == 0) 4383d522f475Smrg return; 4384d522f475Smrg 4385f2e35a3aSmrg line[need] = '\0'; /* make sure it is null terminated */ 4386d522f475Smrg lp = line; /* lp points to where to save the text */ 4387d522f475Smrg if (isSameRow(&last, &first)) { 4388d522f475Smrg lp = SaveText(screen, last.row, first.col, last.col, lp, &eol); 4389d522f475Smrg } else { 4390d522f475Smrg lp = SaveText(screen, first.row, first.col, screen->max_col, lp, &eol); 4391d522f475Smrg if (eol) 4392d522f475Smrg *lp++ = '\n'; /* put in newline at end of line */ 4393d522f475Smrg for (i = first.row + 1; i < last.row; i++) { 4394d522f475Smrg lp = SaveText(screen, i, 0, screen->max_col, lp, &eol); 4395d522f475Smrg if (eol) 4396d522f475Smrg *lp++ = '\n'; 4397d522f475Smrg } 4398d522f475Smrg if (last.col >= 0) 4399d522f475Smrg lp = SaveText(screen, last.row, 0, last.col, lp, &eol); 4400d522f475Smrg } 4401d522f475Smrg *lp = '\0'; /* make sure we have end marked */ 4402d522f475Smrg 4403f2e35a3aSmrg have = (size_t) (lp - line); 4404f2e35a3aSmrg /* 4405f2e35a3aSmrg * Scanning the buffer twice is unnecessary. Discard unwanted memory if 4406f2e35a3aSmrg * the estimate is too-far off. 4407f2e35a3aSmrg */ 4408f2e35a3aSmrg if ((have * 2) < (size_t) need) { 4409f2e35a3aSmrg Char *next; 4410f2e35a3aSmrg scp->data_limit = have + 1; 4411f2e35a3aSmrg next = realloc(line, scp->data_limit); 4412f2e35a3aSmrg if (next == NULL) { 4413f2e35a3aSmrg free(line); 4414f2e35a3aSmrg scp->data_length = 0; 4415f2e35a3aSmrg scp->data_limit = 0; 4416f2e35a3aSmrg } 4417f2e35a3aSmrg scp->data_buffer = next; 4418f2e35a3aSmrg } 4419f2e35a3aSmrg scp->data_length = have; 4420d522f475Smrg 4421f2e35a3aSmrg TRACE(("Salted TEXT:%u:%s\n", (unsigned) have, 4422f2e35a3aSmrg visibleChars(scp->data_buffer, (unsigned) have))); 4423d522f475Smrg} 4424d522f475Smrg 4425d522f475Smrg#if OPT_PASTE64 4426d522f475Smrgvoid 4427f2e35a3aSmrgClearSelectionBuffer(TScreen *screen, String selection) 4428d522f475Smrg{ 4429f2e35a3aSmrg int which = TargetToSelection(screen, selection); 4430f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[okSelectionCode(which)]); 4431f2e35a3aSmrg FreeAndNull(scp->data_buffer); 4432f2e35a3aSmrg scp->data_limit = 0; 4433f2e35a3aSmrg scp->data_length = 0; 4434d522f475Smrg screen->base64_count = 0; 4435d522f475Smrg} 4436d522f475Smrg 4437d522f475Smrgstatic void 4438f2e35a3aSmrgAppendStrToSelectionBuffer(SelectedCells * scp, Char *text, size_t len) 4439d522f475Smrg{ 4440d522f475Smrg if (len != 0) { 4441f2e35a3aSmrg size_t j = (scp->data_length + len); 4442f2e35a3aSmrg size_t k = j + (j >> 2) + 80; 4443f2e35a3aSmrg if (j + 1 >= scp->data_limit) { 4444f2e35a3aSmrg Char *line; 4445f2e35a3aSmrg if (!scp->data_length) { 4446f2e35a3aSmrg line = (Char *) malloc(k); 4447d522f475Smrg } else { 4448f2e35a3aSmrg line = (Char *) realloc(scp->data_buffer, k); 4449d522f475Smrg } 4450f2e35a3aSmrg if (line == 0) 4451f2e35a3aSmrg SysError(ERROR_BMALLOC2); 4452f2e35a3aSmrg scp->data_buffer = line; 4453f2e35a3aSmrg scp->data_limit = k; 4454d522f475Smrg } 4455f2e35a3aSmrg if (scp->data_buffer != 0) { 4456f2e35a3aSmrg memcpy(scp->data_buffer + scp->data_length, text, len); 4457f2e35a3aSmrg scp->data_length += len; 4458f2e35a3aSmrg scp->data_buffer[scp->data_length] = 0; 445920d2c4d2Smrg } 4460d522f475Smrg } 4461d522f475Smrg} 4462d522f475Smrg 4463d522f475Smrgvoid 4464f2e35a3aSmrgAppendToSelectionBuffer(TScreen *screen, unsigned c, String selection) 4465d522f475Smrg{ 4466f2e35a3aSmrg int which = TargetToSelection(screen, selection); 4467f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[okSelectionCode(which)]); 44682eaa94a1Schristos unsigned six; 4469d522f475Smrg Char ch; 4470d522f475Smrg 4471d522f475Smrg /* Decode base64 character */ 4472d522f475Smrg if (c >= 'A' && c <= 'Z') 4473d522f475Smrg six = c - 'A'; 4474d522f475Smrg else if (c >= 'a' && c <= 'z') 4475d522f475Smrg six = c - 'a' + 26; 4476d522f475Smrg else if (c >= '0' && c <= '9') 4477d522f475Smrg six = c - '0' + 52; 4478d522f475Smrg else if (c == '+') 4479d522f475Smrg six = 62; 4480d522f475Smrg else if (c == '/') 4481d522f475Smrg six = 63; 4482d522f475Smrg else 4483d522f475Smrg return; 4484d522f475Smrg 4485d522f475Smrg /* Accumulate bytes */ 4486d522f475Smrg switch (screen->base64_count) { 4487d522f475Smrg case 0: 4488d522f475Smrg screen->base64_accu = six; 4489d522f475Smrg screen->base64_count = 6; 4490d522f475Smrg break; 4491d522f475Smrg 4492d522f475Smrg case 2: 44932eaa94a1Schristos ch = CharOf((screen->base64_accu << 6) + six); 4494d522f475Smrg screen->base64_count = 0; 4495f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4496d522f475Smrg break; 4497d522f475Smrg 4498d522f475Smrg case 4: 44992eaa94a1Schristos ch = CharOf((screen->base64_accu << 4) + (six >> 2)); 4500d522f475Smrg screen->base64_accu = (six & 0x3); 4501d522f475Smrg screen->base64_count = 2; 4502f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4503d522f475Smrg break; 4504d522f475Smrg 4505d522f475Smrg case 6: 45062eaa94a1Schristos ch = CharOf((screen->base64_accu << 2) + (six >> 4)); 4507d522f475Smrg screen->base64_accu = (six & 0xF); 4508d522f475Smrg screen->base64_count = 4; 4509f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4510d522f475Smrg break; 4511d522f475Smrg } 4512d522f475Smrg} 4513d522f475Smrg 4514d522f475Smrgvoid 4515e0a2b6dfSmrgCompleteSelection(XtermWidget xw, String *args, Cardinal len) 4516d522f475Smrg{ 4517956cc18dSsnj TScreen *screen = TScreenOf(xw); 4518956cc18dSsnj 4519956cc18dSsnj screen->base64_count = 0; 4520956cc18dSsnj screen->base64_accu = 0; 4521d522f475Smrg _OwnSelection(xw, args, len); 4522d522f475Smrg} 4523d522f475Smrg#endif /* OPT_PASTE64 */ 4524d522f475Smrg 4525d522f475Smrgstatic Bool 4526d522f475Smrg_ConvertSelectionHelper(Widget w, 4527f2e35a3aSmrg SelectedCells * scp, 4528894e0ac8Smrg Atom *type, 4529d522f475Smrg XtPointer *value, 4530d522f475Smrg unsigned long *length, 4531d522f475Smrg int *format, 4532d522f475Smrg int (*conversion_function) (Display *, 4533d522f475Smrg char **, int, 4534d522f475Smrg XICCEncodingStyle, 4535d522f475Smrg XTextProperty *), 4536d522f475Smrg XICCEncodingStyle conversion_style) 4537d522f475Smrg{ 453801037d57Smrg *value = 0; 453901037d57Smrg *length = 0; 454001037d57Smrg *type = 0; 454101037d57Smrg *format = 0; 454201037d57Smrg 4543f2e35a3aSmrg if (getXtermWidget(w) != 0) { 4544d522f475Smrg Display *dpy = XtDisplay(w); 4545d522f475Smrg XTextProperty textprop; 454601037d57Smrg int out_n = 0; 454701037d57Smrg char *result = 0; 4548f2e35a3aSmrg char *the_data = (char *) scp->data_buffer; 454901037d57Smrg char *the_next; 4550f2e35a3aSmrg unsigned long remaining = scp->data_length; 455101037d57Smrg 455201037d57Smrg TRACE(("converting %ld:'%s'\n", 4553f2e35a3aSmrg (long) scp->data_length, 4554f2e35a3aSmrg visibleChars(scp->data_buffer, (unsigned) scp->data_length))); 455501037d57Smrg /* 455601037d57Smrg * For most selections, we can convert in one pass. It is possible 455701037d57Smrg * that some applications contain embedded nulls, e.g., using xterm's 455801037d57Smrg * paste64 feature. For those cases, we will build up the result in 455901037d57Smrg * parts. 456001037d57Smrg */ 4561f2e35a3aSmrg if (memchr(the_data, 0, scp->data_length) != 0) { 456201037d57Smrg TRACE(("selection contains embedded nulls\n")); 4563f2e35a3aSmrg result = calloc(scp->data_length + 1, sizeof(char)); 456401037d57Smrg } 4565d522f475Smrg 456601037d57Smrg next_try: 456701037d57Smrg memset(&textprop, 0, sizeof(textprop)); 4568d522f475Smrg if (conversion_function(dpy, &the_data, 1, 4569d522f475Smrg conversion_style, 4570d522f475Smrg &textprop) >= Success) { 457101037d57Smrg if ((result != 0) 457201037d57Smrg && (textprop.value != 0) 457301037d57Smrg && (textprop.format == 8)) { 457401037d57Smrg char *text_values = (char *) textprop.value; 457501037d57Smrg unsigned long in_n; 457601037d57Smrg 457701037d57Smrg if (out_n == 0) { 457801037d57Smrg *value = result; 457901037d57Smrg *type = textprop.encoding; 458001037d57Smrg *format = textprop.format; 458101037d57Smrg } 458201037d57Smrg for (in_n = 0; in_n < textprop.nitems; ++in_n) { 458301037d57Smrg result[out_n++] = text_values[in_n]; 458401037d57Smrg } 458501037d57Smrg *length += textprop.nitems; 458601037d57Smrg if ((the_next = memchr(the_data, 0, remaining)) != 0) { 458701037d57Smrg unsigned long this_was = (unsigned long) (the_next - the_data); 458801037d57Smrg this_was++; 458901037d57Smrg the_data += this_was; 459001037d57Smrg remaining -= this_was; 459101037d57Smrg result[out_n++] = 0; 459201037d57Smrg *length += 1; 459301037d57Smrg if (remaining) 459401037d57Smrg goto next_try; 459501037d57Smrg } 459601037d57Smrg return True; 459701037d57Smrg } else { 459801037d57Smrg free(result); 459901037d57Smrg *value = (XtPointer) textprop.value; 460001037d57Smrg *length = textprop.nitems; 460101037d57Smrg *type = textprop.encoding; 460201037d57Smrg *format = textprop.format; 460301037d57Smrg return True; 460401037d57Smrg } 4605d522f475Smrg } 460601037d57Smrg free(result); 4607d522f475Smrg } 4608d522f475Smrg return False; 4609d522f475Smrg} 4610d522f475Smrg 46112eaa94a1Schristosstatic Boolean 46122eaa94a1SchristosSaveConvertedLength(XtPointer *target, unsigned long source) 46132eaa94a1Schristos{ 46142eaa94a1Schristos Boolean result = False; 46152eaa94a1Schristos 46162eaa94a1Schristos *target = XtMalloc(4); 46172eaa94a1Schristos if (*target != 0) { 46182eaa94a1Schristos result = True; 46192eaa94a1Schristos if (sizeof(unsigned long) == 4) { 46202eaa94a1Schristos *(unsigned long *) *target = source; 46212eaa94a1Schristos } else if (sizeof(unsigned) == 4) { 462220d2c4d2Smrg *(unsigned *) *target = (unsigned) source; 46232eaa94a1Schristos } else if (sizeof(unsigned short) == 4) { 46242eaa94a1Schristos *(unsigned short *) *target = (unsigned short) source; 46252eaa94a1Schristos } else { 46262eaa94a1Schristos /* FIXME - does this depend on byte-order? */ 46272eaa94a1Schristos unsigned long temp = source; 462820d2c4d2Smrg memcpy((char *) *target, 462920d2c4d2Smrg ((char *) &temp) + sizeof(temp) - 4, 463020d2c4d2Smrg (size_t) 4); 46312eaa94a1Schristos } 46322eaa94a1Schristos } 46332eaa94a1Schristos return result; 46342eaa94a1Schristos} 46352eaa94a1Schristos 4636f2e35a3aSmrg#define keepClipboard(d,atom) ((screen->keepClipboard) && \ 4637f2e35a3aSmrg (atom == XA_CLIPBOARD(d))) 46382e4f8982Smrg 4639d522f475Smrgstatic Boolean 4640d522f475SmrgConvertSelection(Widget w, 4641894e0ac8Smrg Atom *selection, 4642894e0ac8Smrg Atom *target, 4643894e0ac8Smrg Atom *type, 4644d522f475Smrg XtPointer *value, 4645d522f475Smrg unsigned long *length, 4646d522f475Smrg int *format) 4647d522f475Smrg{ 4648d522f475Smrg Display *dpy = XtDisplay(w); 4649d522f475Smrg TScreen *screen; 4650f2e35a3aSmrg SelectedCells *scp; 4651d522f475Smrg Bool result = False; 4652d522f475Smrg 46532e4f8982Smrg Char *data; 46542e4f8982Smrg unsigned long data_length; 46552e4f8982Smrg 4656956cc18dSsnj XtermWidget xw; 4657956cc18dSsnj 4658956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 4659d522f475Smrg return False; 4660d522f475Smrg 4661956cc18dSsnj screen = TScreenOf(xw); 4662d522f475Smrg 4663f2e35a3aSmrg TRACE(("ConvertSelection %s -> %s\n", 4664f2e35a3aSmrg TraceAtomName(screen->display, *selection), 4665956cc18dSsnj visibleSelectionTarget(dpy, *target))); 4666956cc18dSsnj 4667f2e35a3aSmrg if (keepClipboard(dpy, *selection)) { 46682e4f8982Smrg TRACE(("asked for clipboard\n")); 4669f2e35a3aSmrg scp = &(screen->clipboard_data); 46702e4f8982Smrg } else { 46712e4f8982Smrg TRACE(("asked for selection\n")); 4672f2e35a3aSmrg scp = &(screen->selected_cells[AtomToSelection(dpy, *selection)]); 46732e4f8982Smrg } 46742e4f8982Smrg 4675f2e35a3aSmrg data = scp->data_buffer; 4676f2e35a3aSmrg data_length = scp->data_length; 46772e4f8982Smrg if (data == NULL) { 4678f2e35a3aSmrg TRACE(("...no selection-data\n")); 4679f2e35a3aSmrg return False; 468001037d57Smrg } 468101037d57Smrg 4682d522f475Smrg if (*target == XA_TARGETS(dpy)) { 4683d522f475Smrg Atom *targetP; 4684d522f475Smrg XPointer std_return = 0; 4685d522f475Smrg unsigned long std_length; 4686d522f475Smrg 4687d522f475Smrg if (XmuConvertStandardSelection(w, screen->selection_time, selection, 4688d522f475Smrg target, type, &std_return, 4689d522f475Smrg &std_length, format)) { 4690956cc18dSsnj Atom *my_targets = _SelectionTargets(w); 46912e4f8982Smrg Atom *allocP; 46922e4f8982Smrg Atom *std_targets; 4693956cc18dSsnj 4694956cc18dSsnj TRACE(("XmuConvertStandardSelection - success\n")); 4695a1f3da82Smrg std_targets = (Atom *) (void *) (std_return); 4696d522f475Smrg *length = std_length + 6; 4697d522f475Smrg 4698a1f3da82Smrg targetP = TypeXtMallocN(Atom, *length); 4699d522f475Smrg allocP = targetP; 4700d522f475Smrg 4701d522f475Smrg *value = (XtPointer) targetP; 4702d522f475Smrg 47030bd37d32Smrg if (my_targets != 0) { 47040bd37d32Smrg while (*my_targets != None) { 47050bd37d32Smrg *targetP++ = *my_targets++; 47060bd37d32Smrg } 4707956cc18dSsnj } 4708d522f475Smrg *targetP++ = XA_LENGTH(dpy); 4709d522f475Smrg *targetP++ = XA_LIST_LENGTH(dpy); 4710d522f475Smrg 47112eaa94a1Schristos *length = std_length + (unsigned long) (targetP - allocP); 4712d522f475Smrg 4713d522f475Smrg memcpy(targetP, std_targets, sizeof(Atom) * std_length); 4714d522f475Smrg XtFree((char *) std_targets); 4715d522f475Smrg *type = XA_ATOM; 4716d522f475Smrg *format = 32; 4717d522f475Smrg result = True; 4718956cc18dSsnj } else { 4719956cc18dSsnj TRACE(("XmuConvertStandardSelection - failed\n")); 4720d522f475Smrg } 4721d522f475Smrg } 4722d522f475Smrg#if OPT_WIDE_CHARS 4723d522f475Smrg else if (screen->wide_chars && *target == XA_STRING) { 4724d522f475Smrg result = 4725f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4726f2e35a3aSmrg type, value, length, format, 4727d522f475Smrg Xutf8TextListToTextProperty, 4728d522f475Smrg XStringStyle); 4729956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4730d522f475Smrg } else if (screen->wide_chars && *target == XA_UTF8_STRING(dpy)) { 4731d522f475Smrg result = 4732f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4733f2e35a3aSmrg type, value, length, format, 4734d522f475Smrg Xutf8TextListToTextProperty, 4735d522f475Smrg XUTF8StringStyle); 4736956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4737d522f475Smrg } else if (screen->wide_chars && *target == XA_TEXT(dpy)) { 4738d522f475Smrg result = 4739f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4740f2e35a3aSmrg type, value, length, format, 4741d522f475Smrg Xutf8TextListToTextProperty, 4742d522f475Smrg XStdICCTextStyle); 4743956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4744d522f475Smrg } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(dpy)) { 4745d522f475Smrg result = 4746f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4747f2e35a3aSmrg type, value, length, format, 4748d522f475Smrg Xutf8TextListToTextProperty, 4749d522f475Smrg XCompoundTextStyle); 4750956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4751d522f475Smrg } 4752d522f475Smrg#endif 4753d522f475Smrg 4754d522f475Smrg else if (*target == XA_STRING) { /* not wide_chars */ 4755d522f475Smrg /* We can only reach this point if the selection requestor 4756d522f475Smrg requested STRING before any of TEXT, COMPOUND_TEXT or 4757d522f475Smrg UTF8_STRING. We therefore assume that the requestor is not 4758d522f475Smrg properly internationalised, and dump raw eight-bit data 4759d522f475Smrg with no conversion into the selection. Yes, this breaks 4760d522f475Smrg the ICCCM in non-Latin-1 locales. */ 4761d522f475Smrg *type = XA_STRING; 4762f2e35a3aSmrg *value = (XtPointer) data; 4763f2e35a3aSmrg *length = data_length; 4764d522f475Smrg *format = 8; 4765d522f475Smrg result = True; 4766956cc18dSsnj TRACE(("...raw 8-bit data:%d\n", result)); 4767d522f475Smrg } else if (*target == XA_TEXT(dpy)) { /* not wide_chars */ 4768d522f475Smrg result = 4769f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4770f2e35a3aSmrg type, value, length, format, 4771d522f475Smrg XmbTextListToTextProperty, 4772d522f475Smrg XStdICCTextStyle); 4773956cc18dSsnj TRACE(("...XmbTextListToTextProperty(StdICC):%d\n", result)); 4774d522f475Smrg } else if (*target == XA_COMPOUND_TEXT(dpy)) { /* not wide_chars */ 4775d522f475Smrg result = 4776f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4777f2e35a3aSmrg type, value, length, format, 4778d522f475Smrg XmbTextListToTextProperty, 4779d522f475Smrg XCompoundTextStyle); 4780956cc18dSsnj TRACE(("...XmbTextListToTextProperty(Compound):%d\n", result)); 4781d522f475Smrg } 4782d522f475Smrg#ifdef X_HAVE_UTF8_STRING 4783d522f475Smrg else if (*target == XA_UTF8_STRING(dpy)) { /* not wide_chars */ 4784d522f475Smrg result = 4785f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4786f2e35a3aSmrg type, value, length, format, 4787d522f475Smrg XmbTextListToTextProperty, 4788d522f475Smrg XUTF8StringStyle); 4789956cc18dSsnj TRACE(("...XmbTextListToTextProperty(UTF8):%d\n", result)); 4790d522f475Smrg } 4791d522f475Smrg#endif 4792d522f475Smrg else if (*target == XA_LIST_LENGTH(dpy)) { 479320d2c4d2Smrg result = SaveConvertedLength(value, (unsigned long) 1); 4794d522f475Smrg *type = XA_INTEGER; 4795d522f475Smrg *length = 1; 4796d522f475Smrg *format = 32; 4797956cc18dSsnj TRACE(("...list of values:%d\n", result)); 4798d522f475Smrg } else if (*target == XA_LENGTH(dpy)) { 4799d522f475Smrg /* This value is wrong if we have UTF-8 text */ 4800f2e35a3aSmrg result = SaveConvertedLength(value, scp->data_length); 4801d522f475Smrg *type = XA_INTEGER; 4802d522f475Smrg *length = 1; 4803d522f475Smrg *format = 32; 4804956cc18dSsnj TRACE(("...list of values:%d\n", result)); 4805d522f475Smrg } else if (XmuConvertStandardSelection(w, 4806d522f475Smrg screen->selection_time, selection, 4807d522f475Smrg target, type, (XPointer *) value, 4808d522f475Smrg length, format)) { 4809d522f475Smrg result = True; 4810956cc18dSsnj TRACE(("...XmuConvertStandardSelection:%d\n", result)); 4811d522f475Smrg } 4812d522f475Smrg 4813d522f475Smrg /* else */ 48142eaa94a1Schristos return (Boolean) result; 4815d522f475Smrg} 4816d522f475Smrg 4817d522f475Smrgstatic void 4818894e0ac8SmrgLoseSelection(Widget w, Atom *selection) 4819d522f475Smrg{ 4820d522f475Smrg TScreen *screen; 4821d522f475Smrg Atom *atomP; 4822d522f475Smrg Cardinal i; 4823d522f475Smrg 4824956cc18dSsnj XtermWidget xw; 4825956cc18dSsnj 4826956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 4827d522f475Smrg return; 4828d522f475Smrg 4829956cc18dSsnj screen = TScreenOf(xw); 4830913cc679Smrg TRACE(("LoseSelection %s\n", TraceAtomName(screen->display, *selection))); 483101037d57Smrg 4832d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 4833d522f475Smrg i < screen->selection_count; i++, atomP++) { 4834d522f475Smrg if (*selection == *atomP) 4835d522f475Smrg *atomP = (Atom) 0; 4836d522f475Smrg if (CutBuffer(*atomP) >= 0) { 4837d522f475Smrg *atomP = (Atom) 0; 4838d522f475Smrg } 4839d522f475Smrg } 4840d522f475Smrg 4841d522f475Smrg for (i = screen->selection_count; i; i--) { 4842d522f475Smrg if (screen->selection_atoms[i - 1] != 0) 4843d522f475Smrg break; 4844d522f475Smrg } 4845d522f475Smrg screen->selection_count = i; 4846d522f475Smrg 4847d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 4848d522f475Smrg i < screen->selection_count; i++, atomP++) { 4849d522f475Smrg if (*atomP == (Atom) 0) { 4850d522f475Smrg *atomP = screen->selection_atoms[--screen->selection_count]; 4851d522f475Smrg } 4852d522f475Smrg } 4853d522f475Smrg 4854d522f475Smrg if (screen->selection_count == 0) 4855f2e35a3aSmrg UnHiliteText(xw); 4856d522f475Smrg} 4857d522f475Smrg 4858d522f475Smrg/* ARGSUSED */ 4859d522f475Smrgstatic void 4860d522f475SmrgSelectionDone(Widget w GCC_UNUSED, 4861894e0ac8Smrg Atom *selection GCC_UNUSED, 4862894e0ac8Smrg Atom *target GCC_UNUSED) 4863d522f475Smrg{ 4864d522f475Smrg /* empty proc so Intrinsics know we want to keep storage */ 486501037d57Smrg TRACE(("SelectionDone\n")); 4866d522f475Smrg} 4867d522f475Smrg 4868d522f475Smrgstatic void 4869d522f475Smrg_OwnSelection(XtermWidget xw, 4870e0a2b6dfSmrg String *selections, 4871d522f475Smrg Cardinal count) 4872d522f475Smrg{ 4873956cc18dSsnj TScreen *screen = TScreenOf(xw); 4874f2e35a3aSmrg Display *dpy = screen->display; 4875d522f475Smrg Atom *atoms = screen->selection_atoms; 4876d522f475Smrg Cardinal i; 4877d522f475Smrg Bool have_selection = False; 4878f2e35a3aSmrg SelectedCells *scp; 4879d522f475Smrg 488020d2c4d2Smrg if (count == 0) 488120d2c4d2Smrg return; 4882d522f475Smrg 4883f2e35a3aSmrg TRACE(("_OwnSelection count %d\n", count)); 4884d522f475Smrg selections = MapSelections(xw, selections, count); 4885d522f475Smrg 4886d522f475Smrg if (count > screen->sel_atoms_size) { 4887d522f475Smrg XtFree((char *) atoms); 4888a1f3da82Smrg atoms = TypeXtMallocN(Atom, count); 4889d522f475Smrg screen->selection_atoms = atoms; 4890d522f475Smrg screen->sel_atoms_size = count; 4891d522f475Smrg } 4892f2e35a3aSmrg XmuInternStrings(dpy, selections, count, atoms); 4893d522f475Smrg for (i = 0; i < count; i++) { 4894d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 4895d522f475Smrg if (cutbuffer >= 0) { 48962eaa94a1Schristos unsigned long limit = 4897f2e35a3aSmrg (unsigned long) (4 * XMaxRequestSize(dpy) - 32); 4898f2e35a3aSmrg scp = &(screen->selected_cells[CutBufferToCode(cutbuffer)]); 4899f2e35a3aSmrg if (scp->data_length > limit) { 490020d2c4d2Smrg TRACE(("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 4901f2e35a3aSmrg (unsigned long) scp->data_length, cutbuffer)); 49020bd37d32Smrg xtermWarning("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 4903f2e35a3aSmrg (unsigned long) scp->data_length, cutbuffer); 4904d522f475Smrg } else { 4905d522f475Smrg /* This used to just use the UTF-8 data, which was totally 4906894e0ac8Smrg * broken as not even the corresponding paste code in xterm 4907d522f475Smrg * understood this! So now it converts to Latin1 first. 4908d522f475Smrg * Robert Brady, 2000-09-05 4909d522f475Smrg */ 4910f2e35a3aSmrg unsigned long length = scp->data_length; 4911f2e35a3aSmrg Char *data = scp->data_buffer; 4912d522f475Smrg if_OPT_WIDE_CHARS((screen), { 4913956cc18dSsnj data = UTF8toLatin1(screen, data, length, &length); 4914d522f475Smrg }); 4915d522f475Smrg TRACE(("XStoreBuffer(%d)\n", cutbuffer)); 4916f2e35a3aSmrg XStoreBuffer(dpy, 4917d522f475Smrg (char *) data, 4918d522f475Smrg (int) length, 4919d522f475Smrg cutbuffer); 4920d522f475Smrg } 4921f2e35a3aSmrg } else { 4922f2e35a3aSmrg int which = AtomToSelection(dpy, atoms[i]); 4923f2e35a3aSmrg if (keepClipboard(dpy, atoms[i])) { 4924f2e35a3aSmrg Char *buf; 4925f2e35a3aSmrg SelectedCells *tcp = &(screen->clipboard_data); 4926f2e35a3aSmrg TRACE(("saving selection to clipboard buffer\n")); 4927f2e35a3aSmrg scp = &(screen->selected_cells[CLIPBOARD_CODE]); 4928f2e35a3aSmrg if ((buf = (Char *) malloc((size_t) scp->data_length)) == 0) 4929f2e35a3aSmrg SysError(ERROR_BMALLOC2); 49302e4f8982Smrg 4931f2e35a3aSmrg free(tcp->data_buffer); 4932f2e35a3aSmrg memcpy(buf, scp->data_buffer, scp->data_length); 4933f2e35a3aSmrg tcp->data_buffer = buf; 4934f2e35a3aSmrg tcp->data_limit = scp->data_length; 4935f2e35a3aSmrg tcp->data_length = scp->data_length; 4936f2e35a3aSmrg } 4937f2e35a3aSmrg scp = &(screen->selected_cells[which]); 4938f2e35a3aSmrg if (scp->data_length == 0) { 4939f2e35a3aSmrg TRACE(("XtDisownSelection(%s, @%ld)\n", 4940f2e35a3aSmrg TraceAtomName(screen->display, atoms[i]), 4941f2e35a3aSmrg (long) screen->selection_time)); 4942f2e35a3aSmrg XtDisownSelection((Widget) xw, 4943f2e35a3aSmrg atoms[i], 4944f2e35a3aSmrg screen->selection_time); 4945f2e35a3aSmrg } else if (!screen->replyToEmacs && atoms[i] != 0) { 4946f2e35a3aSmrg TRACE(("XtOwnSelection(%s, @%ld)\n", 4947f2e35a3aSmrg TraceAtomName(screen->display, atoms[i]), 4948f2e35a3aSmrg (long) screen->selection_time)); 4949f2e35a3aSmrg have_selection |= 4950f2e35a3aSmrg XtOwnSelection((Widget) xw, atoms[i], 4951f2e35a3aSmrg screen->selection_time, 4952f2e35a3aSmrg ConvertSelection, 4953f2e35a3aSmrg LoseSelection, 4954f2e35a3aSmrg SelectionDone); 4955f2e35a3aSmrg } 4956d522f475Smrg } 4957f2e35a3aSmrg TRACE(("... _OwnSelection used length %lu value %s\n", 4958f2e35a3aSmrg (unsigned long) scp->data_length, 4959f2e35a3aSmrg visibleChars(scp->data_buffer, 4960f2e35a3aSmrg (unsigned) scp->data_length))); 4961d522f475Smrg } 4962d522f475Smrg if (!screen->replyToEmacs) 4963d522f475Smrg screen->selection_count = count; 4964d522f475Smrg if (!have_selection) 4965f2e35a3aSmrg UnHiliteText(xw); 4966d522f475Smrg} 4967d522f475Smrg 4968d522f475Smrgstatic void 4969e0a2b6dfSmrgResetSelectionState(TScreen *screen) 4970d522f475Smrg{ 4971d522f475Smrg screen->selection_count = 0; 4972d522f475Smrg screen->startH = zeroCELL; 4973d522f475Smrg screen->endH = zeroCELL; 4974d522f475Smrg} 4975d522f475Smrg 4976d522f475Smrgvoid 4977d522f475SmrgDisownSelection(XtermWidget xw) 4978d522f475Smrg{ 4979956cc18dSsnj TScreen *screen = TScreenOf(xw); 4980d522f475Smrg Atom *atoms = screen->selection_atoms; 4981d522f475Smrg Cardinal count = screen->selection_count; 4982d522f475Smrg Cardinal i; 4983d522f475Smrg 4984d522f475Smrg TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n", 4985d522f475Smrg count, 4986d522f475Smrg screen->startH.row, 4987d522f475Smrg screen->startH.col, 4988d522f475Smrg screen->endH.row, 4989d522f475Smrg screen->endH.col)); 4990d522f475Smrg 4991d522f475Smrg for (i = 0; i < count; i++) { 4992d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 4993d522f475Smrg if (cutbuffer < 0) { 4994d522f475Smrg XtDisownSelection((Widget) xw, atoms[i], 4995d522f475Smrg screen->selection_time); 4996d522f475Smrg } 4997d522f475Smrg } 4998d522f475Smrg /* 4999d522f475Smrg * If none of the callbacks via XtDisownSelection() reset highlighting 5000d522f475Smrg * do it now. 5001d522f475Smrg */ 5002d522f475Smrg if (ScrnHaveSelection(screen)) { 5003d522f475Smrg /* save data which will be reset */ 5004d522f475Smrg CELL first = screen->startH; 5005d522f475Smrg CELL last = screen->endH; 5006d522f475Smrg 5007d522f475Smrg ResetSelectionState(screen); 5008d522f475Smrg ReHiliteText(xw, &first, &last); 5009d522f475Smrg } else { 5010d522f475Smrg ResetSelectionState(screen); 5011d522f475Smrg } 5012d522f475Smrg} 5013d522f475Smrg 5014d522f475Smrgvoid 5015d522f475SmrgUnhiliteSelection(XtermWidget xw) 5016d522f475Smrg{ 5017956cc18dSsnj TScreen *screen = TScreenOf(xw); 5018d522f475Smrg 5019d522f475Smrg if (ScrnHaveSelection(screen)) { 5020d522f475Smrg CELL first = screen->startH; 5021d522f475Smrg CELL last = screen->endH; 5022d522f475Smrg 5023d522f475Smrg screen->startH = zeroCELL; 5024d522f475Smrg screen->endH = zeroCELL; 5025d522f475Smrg ReHiliteText(xw, &first, &last); 5026d522f475Smrg } 5027d522f475Smrg} 5028d522f475Smrg 5029d522f475Smrg/* returns number of chars in line from scol to ecol out */ 5030d522f475Smrg/* ARGSUSED */ 5031d522f475Smrgstatic int 5032e0a2b6dfSmrgLength(TScreen *screen, 5033d522f475Smrg int row, 5034d522f475Smrg int scol, 5035d522f475Smrg int ecol) 5036d522f475Smrg{ 503701037d57Smrg CLineData *ld = GET_LINEDATA(screen, row); 503801037d57Smrg const int lastcol = LastTextCol(screen, ld, row); 5039d522f475Smrg 5040d522f475Smrg if (ecol > lastcol) 5041d522f475Smrg ecol = lastcol; 5042d522f475Smrg return (ecol - scol + 1); 5043d522f475Smrg} 5044d522f475Smrg 5045d522f475Smrg/* copies text into line, preallocated */ 5046d522f475Smrgstatic Char * 5047e0a2b6dfSmrgSaveText(TScreen *screen, 5048d522f475Smrg int row, 5049d522f475Smrg int scol, 5050d522f475Smrg int ecol, 5051e0a2b6dfSmrg Char *lp, /* pointer to where to put the text */ 5052d522f475Smrg int *eol) 5053d522f475Smrg{ 5054956cc18dSsnj LineData *ld; 5055d522f475Smrg int i = 0; 5056d522f475Smrg Char *result = lp; 5057d522f475Smrg#if OPT_WIDE_CHARS 50582eaa94a1Schristos unsigned previous = 0; 5059d522f475Smrg#endif 5060d522f475Smrg 5061956cc18dSsnj ld = GET_LINEDATA(screen, row); 5062d522f475Smrg i = Length(screen, row, scol, ecol); 5063d522f475Smrg ecol = scol + i; 5064d522f475Smrg#if OPT_DEC_CHRSET 5065956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 5066d522f475Smrg scol = (scol + 0) / 2; 5067d522f475Smrg ecol = (ecol + 1) / 2; 5068d522f475Smrg } 5069d522f475Smrg#endif 5070956cc18dSsnj *eol = !LineTstWrapped(ld); 5071d522f475Smrg for (i = scol; i < ecol; i++) { 50722e4f8982Smrg unsigned c; 50730bd37d32Smrg assert(i < (int) ld->lineSize); 5074956cc18dSsnj c = E2A(ld->charData[i]); 5075d522f475Smrg#if OPT_WIDE_CHARS 5076d522f475Smrg /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a 5077d522f475Smrg * wide character. 5078d522f475Smrg */ 5079894e0ac8Smrg if (c == HIDDEN_CHAR) { 5080894e0ac8Smrg if (isWide((int) previous)) { 5081894e0ac8Smrg previous = c; 5082894e0ac8Smrg /* Combining characters attached to double-width characters 5083894e0ac8Smrg are in memory attached to the HIDDEN_CHAR */ 5084894e0ac8Smrg if_OPT_WIDE_CHARS(screen, { 5085894e0ac8Smrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 5086894e0ac8Smrg size_t off; 5087894e0ac8Smrg for_each_combData(off, ld) { 50882e4f8982Smrg unsigned ch = ld->combData[off][i]; 5089894e0ac8Smrg if (ch == 0) 5090894e0ac8Smrg break; 5091894e0ac8Smrg lp = convertToUTF8(lp, ch); 5092894e0ac8Smrg } 5093d522f475Smrg } 5094894e0ac8Smrg }); 5095894e0ac8Smrg continue; 5096894e0ac8Smrg } else { 5097894e0ac8Smrg c = ' '; /* should not happen, but just in case... */ 5098894e0ac8Smrg } 5099d522f475Smrg } 5100d522f475Smrg previous = c; 5101e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 5102d522f475Smrg lp = convertToUTF8(lp, (c != 0) ? c : ' '); 5103d522f475Smrg if_OPT_WIDE_CHARS(screen, { 5104956cc18dSsnj size_t off; 5105956cc18dSsnj for_each_combData(off, ld) { 51062e4f8982Smrg unsigned ch = ld->combData[off][i]; 5107956cc18dSsnj if (ch == 0) 5108d522f475Smrg break; 5109d522f475Smrg lp = convertToUTF8(lp, ch); 5110d522f475Smrg } 5111d522f475Smrg }); 5112d522f475Smrg } else 5113d522f475Smrg#endif 5114d522f475Smrg { 5115d522f475Smrg if (c == 0) { 5116d522f475Smrg c = E2A(' '); 5117d522f475Smrg } else if (c < E2A(' ')) { 5118d522f475Smrg c = DECtoASCII(c); 5119d522f475Smrg } else if (c == 0x7f) { 5120d522f475Smrg c = 0x5f; 5121d522f475Smrg } 51222eaa94a1Schristos *lp++ = CharOf(A2E(c)); 5123d522f475Smrg } 5124d522f475Smrg if (c != E2A(' ')) 5125d522f475Smrg result = lp; 5126d522f475Smrg } 5127d522f475Smrg 5128d522f475Smrg /* 5129d522f475Smrg * If requested, trim trailing blanks from selected lines. Do not do this 5130d522f475Smrg * if the line is wrapped. 5131d522f475Smrg */ 5132d522f475Smrg if (!*eol || !screen->trim_selection) 5133d522f475Smrg result = lp; 5134d522f475Smrg 5135d522f475Smrg return (result); 5136d522f475Smrg} 5137d522f475Smrg 5138f2e35a3aSmrg/* 5139f2e35a3aSmrg * This adds together the bits: 5140f2e35a3aSmrg * shift key -> 1 5141f2e35a3aSmrg * meta key -> 2 5142f2e35a3aSmrg * control key -> 4 5143f2e35a3aSmrg */ 5144f2e35a3aSmrgstatic unsigned 5145f2e35a3aSmrgKeyState(XtermWidget xw, unsigned x) 5146f2e35a3aSmrg{ 5147f2e35a3aSmrg return ((((x) & (ShiftMask | ControlMask))) 5148f2e35a3aSmrg + (((x) & MetaMask(xw)) ? 2 : 0)); 5149f2e35a3aSmrg} 5150f2e35a3aSmrg 5151f2e35a3aSmrg/* 32 + following 8-bit word: 5152d522f475Smrg 5153d522f475Smrg 1:0 Button no: 0, 1, 2. 3=release. 5154d522f475Smrg 2 shift 5155d522f475Smrg 3 meta 5156d522f475Smrg 4 ctrl 5157d522f475Smrg 5 set for motion notify 5158f2e35a3aSmrg 6 set for wheel (and button 6 and 7) 5159f2e35a3aSmrg 7 set for buttons 8 to 11 5160d522f475Smrg*/ 5161d522f475Smrg 5162d522f475Smrg/* Position: 32 - 255. */ 5163a1f3da82Smrgstatic int 5164f2e35a3aSmrgBtnCode(XtermWidget xw, XButtonEvent *event, int button) 5165d522f475Smrg{ 5166f2e35a3aSmrg int result = (int) (32 + (KeyState(xw, event->state) << 2)); 5167d522f475Smrg 51680bd37d32Smrg if (event->type == MotionNotify) 51690bd37d32Smrg result += 32; 51700bd37d32Smrg 5171f2e35a3aSmrg if (button < 0) { 5172d522f475Smrg result += 3; 5173d522f475Smrg } else { 5174f2e35a3aSmrg result += button & 3; 5175f2e35a3aSmrg if (button & 4) 5176f2e35a3aSmrg result += 64; 5177f2e35a3aSmrg if (button & 8) 5178f2e35a3aSmrg result += 128; 5179d522f475Smrg } 51800bd37d32Smrg TRACE(("BtnCode button %d, %s state " FMT_MODIFIER_NAMES " ->%#x\n", 51810bd37d32Smrg button, 51820bd37d32Smrg visibleEventType(event->type), 51830bd37d32Smrg ARG_MODIFIER_NAMES(event->state), 51840bd37d32Smrg result)); 5185a1f3da82Smrg return result; 5186a1f3da82Smrg} 5187a1f3da82Smrg 5188a1f3da82Smrgstatic unsigned 5189913cc679SmrgEmitButtonCode(XtermWidget xw, 5190e0a2b6dfSmrg Char *line, 51910bd37d32Smrg unsigned count, 5192894e0ac8Smrg XButtonEvent *event, 51930bd37d32Smrg int button) 5194a1f3da82Smrg{ 5195913cc679Smrg TScreen *screen = TScreenOf(xw); 51960bd37d32Smrg int value; 5197a1f3da82Smrg 5198913cc679Smrg if (okSendMousePos(xw) == X10_MOUSE) { 51990bd37d32Smrg value = CharOf(' ' + button); 5200a1f3da82Smrg } else { 5201f2e35a3aSmrg value = BtnCode(xw, event, button); 52020bd37d32Smrg } 52030bd37d32Smrg 52040bd37d32Smrg switch (screen->extend_coords) { 52050bd37d32Smrg default: 52060bd37d32Smrg line[count++] = CharOf(value); 52070bd37d32Smrg break; 52080bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5209f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 52100bd37d32Smrg value -= 32; /* encoding starts at zero */ 52110bd37d32Smrg /* FALLTHRU */ 52120bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 52130bd37d32Smrg count += (unsigned) sprintf((char *) line + count, "%d", value); 52140bd37d32Smrg break; 52150bd37d32Smrg case SET_EXT_MODE_MOUSE: 52160bd37d32Smrg if (value < 128) { 52170bd37d32Smrg line[count++] = CharOf(value); 52180bd37d32Smrg } else { 52190bd37d32Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 52200bd37d32Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 52210bd37d32Smrg } 52220bd37d32Smrg break; 5223a1f3da82Smrg } 5224a1f3da82Smrg return count; 5225d522f475Smrg} 5226d522f475Smrg 52270bd37d32Smrgstatic int 52280bd37d32SmrgFirstBitN(int bits) 52290bd37d32Smrg{ 52300bd37d32Smrg int result = -1; 52310bd37d32Smrg if (bits > 0) { 52320bd37d32Smrg result = 0; 52330bd37d32Smrg while (!(bits & 1)) { 52340bd37d32Smrg bits /= 2; 52350bd37d32Smrg ++result; 52360bd37d32Smrg } 52370bd37d32Smrg } 52380bd37d32Smrg return result; 52390bd37d32Smrg} 52400bd37d32Smrg 52410bd37d32Smrg#define ButtonBit(button) ((button >= 0) ? (1 << (button)) : 0) 52420bd37d32Smrg 5243913cc679Smrg#define EMIT_BUTTON(button) EmitButtonCode(xw, line, count, event, button) 52440bd37d32Smrg 5245d522f475Smrgstatic void 5246894e0ac8SmrgEditorButton(XtermWidget xw, XButtonEvent *event) 5247d522f475Smrg{ 5248956cc18dSsnj TScreen *screen = TScreenOf(xw); 5249d522f475Smrg int pty = screen->respond; 52500bd37d32Smrg int mouse_limit = MouseLimit(screen); 52510bd37d32Smrg Char line[32]; 52520bd37d32Smrg Char final = 'M'; 5253d522f475Smrg int row, col; 5254d522f475Smrg int button; 5255d522f475Smrg unsigned count = 0; 5256d522f475Smrg Boolean changed = True; 5257d522f475Smrg 5258d522f475Smrg /* If button event, get button # adjusted for DEC compatibility */ 52592eaa94a1Schristos button = (int) (event->button - 1); 5260d522f475Smrg if (button >= 3) 5261d522f475Smrg button++; 5262d522f475Smrg 5263f2e35a3aSmrg /* Ignore buttons that cannot be encoded */ 5264f2e35a3aSmrg if (screen->send_mouse_pos == X10_MOUSE) { 5265f2e35a3aSmrg if (button > 3) 5266f2e35a3aSmrg return; 5267f2e35a3aSmrg } else if (screen->extend_coords == SET_SGR_EXT_MODE_MOUSE 5268f2e35a3aSmrg || screen->extend_coords == SET_URXVT_EXT_MODE_MOUSE 5269f2e35a3aSmrg || screen->extend_coords == SET_PIXEL_POSITION_MOUSE) { 5270f2e35a3aSmrg if (button > 15) { 5271f2e35a3aSmrg return; 5272f2e35a3aSmrg } 5273f2e35a3aSmrg } else { 5274f2e35a3aSmrg if (button > 11) { 5275f2e35a3aSmrg return; 5276f2e35a3aSmrg } 5277f2e35a3aSmrg } 5278d522f475Smrg 5279f2e35a3aSmrg if (screen->extend_coords == SET_PIXEL_POSITION_MOUSE) { 5280f2e35a3aSmrg row = event->y - OriginY(screen); 5281f2e35a3aSmrg col = event->x - OriginX(screen); 5282f2e35a3aSmrg } else { 5283f2e35a3aSmrg /* Compute character position of mouse pointer */ 5284f2e35a3aSmrg row = (event->y - screen->border) / FontHeight(screen); 5285f2e35a3aSmrg col = (event->x - OriginX(screen)) / FontWidth(screen); 5286d522f475Smrg 5287f2e35a3aSmrg /* Limit to screen dimensions */ 5288f2e35a3aSmrg if (row < 0) 5289f2e35a3aSmrg row = 0; 5290f2e35a3aSmrg else if (row > screen->max_row) 5291f2e35a3aSmrg row = screen->max_row; 5292492d43a5Smrg 5293f2e35a3aSmrg if (col < 0) 5294f2e35a3aSmrg col = 0; 5295f2e35a3aSmrg else if (col > screen->max_col) 5296f2e35a3aSmrg col = screen->max_col; 5297f2e35a3aSmrg 5298f2e35a3aSmrg if (mouse_limit > 0) { 5299f2e35a3aSmrg /* Limit to representable mouse dimensions */ 5300f2e35a3aSmrg if (row > mouse_limit) 5301f2e35a3aSmrg row = mouse_limit; 5302f2e35a3aSmrg if (col > mouse_limit) 5303f2e35a3aSmrg col = mouse_limit; 5304f2e35a3aSmrg } 53050bd37d32Smrg } 5306d522f475Smrg 5307d522f475Smrg /* Build key sequence starting with \E[M */ 5308d522f475Smrg if (screen->control_eight_bits) { 5309d522f475Smrg line[count++] = ANSI_CSI; 5310d522f475Smrg } else { 5311d522f475Smrg line[count++] = ANSI_ESC; 5312d522f475Smrg line[count++] = '['; 5313d522f475Smrg } 53140bd37d32Smrg switch (screen->extend_coords) { 53150bd37d32Smrg case 0: 53160bd37d32Smrg case SET_EXT_MODE_MOUSE: 5317d522f475Smrg#if OPT_SCO_FUNC_KEYS 53180bd37d32Smrg if (xw->keyboard.type == keyboardIsSCO) { 53190bd37d32Smrg /* 53200bd37d32Smrg * SCO function key F1 is \E[M, which would conflict with xterm's 53210bd37d32Smrg * normal kmous. 53220bd37d32Smrg */ 53230bd37d32Smrg line[count++] = '>'; 53240bd37d32Smrg } 5325d522f475Smrg#endif 53260bd37d32Smrg line[count++] = final; 53270bd37d32Smrg break; 53280bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5329f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 53300bd37d32Smrg line[count++] = '<'; 53310bd37d32Smrg break; 53320bd37d32Smrg } 5333d522f475Smrg 5334d522f475Smrg /* Add event code to key sequence */ 5335913cc679Smrg if (okSendMousePos(xw) == X10_MOUSE) { 53360bd37d32Smrg count = EMIT_BUTTON(button); 5337d522f475Smrg } else { 5338d522f475Smrg /* Button-Motion events */ 5339d522f475Smrg switch (event->type) { 5340d522f475Smrg case ButtonPress: 53410bd37d32Smrg screen->mouse_button |= ButtonBit(button); 53420bd37d32Smrg count = EMIT_BUTTON(button); 5343d522f475Smrg break; 5344d522f475Smrg case ButtonRelease: 5345d522f475Smrg /* 5346f2e35a3aSmrg * The (vertical) wheel mouse interface generates release-events 5347f2e35a3aSmrg * for buttons 4 and 5. 5348f2e35a3aSmrg * 5349f2e35a3aSmrg * The X10/X11 xterm protocol maps the release for buttons 1..3 to 5350f2e35a3aSmrg * a -1, which will be later mapped into a "0" (some button was 5351f2e35a3aSmrg * released), At this point, buttons 1..3 are encoded 0..2 (the 5352f2e35a3aSmrg * code 3 is unused). 5353f2e35a3aSmrg * 5354f2e35a3aSmrg * The SGR (extended) xterm mouse protocol keeps the button number 5355f2e35a3aSmrg * and uses a "m" to indicate button release. 5356f2e35a3aSmrg * 5357f2e35a3aSmrg * The behavior for mice with more buttons is unclear, and may be 5358f2e35a3aSmrg * revised -TD 5359d522f475Smrg */ 53600bd37d32Smrg screen->mouse_button &= ~ButtonBit(button); 5361f2e35a3aSmrg if (button < 3 || button > 5) { 53620bd37d32Smrg switch (screen->extend_coords) { 53630bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5364f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 53650bd37d32Smrg final = 'm'; 53660bd37d32Smrg break; 53670bd37d32Smrg default: 53680bd37d32Smrg button = -1; 53690bd37d32Smrg break; 53700bd37d32Smrg } 53710bd37d32Smrg } 53720bd37d32Smrg count = EMIT_BUTTON(button); 5373d522f475Smrg break; 5374d522f475Smrg case MotionNotify: 5375d522f475Smrg /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion 5376d522f475Smrg * events only if character cell has changed. 5377d522f475Smrg */ 5378d522f475Smrg if ((row == screen->mouse_row) 5379d522f475Smrg && (col == screen->mouse_col)) { 5380d522f475Smrg changed = False; 5381d522f475Smrg } else { 53820bd37d32Smrg count = EMIT_BUTTON(FirstBitN(screen->mouse_button)); 5383d522f475Smrg } 5384d522f475Smrg break; 5385d522f475Smrg default: 5386d522f475Smrg changed = False; 5387d522f475Smrg break; 5388d522f475Smrg } 5389d522f475Smrg } 5390d522f475Smrg 5391d522f475Smrg if (changed) { 5392d522f475Smrg screen->mouse_row = row; 5393d522f475Smrg screen->mouse_col = col; 5394d522f475Smrg 5395492d43a5Smrg TRACE(("mouse at %d,%d button+mask = %#x\n", row, col, line[count - 1])); 5396d522f475Smrg 5397492d43a5Smrg /* Add pointer position to key sequence */ 53980bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 5399492d43a5Smrg count = EmitMousePosition(screen, line, count, col); 54000bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 5401492d43a5Smrg count = EmitMousePosition(screen, line, count, row); 5402d522f475Smrg 54030bd37d32Smrg switch (screen->extend_coords) { 54040bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 54050bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 5406f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 54070bd37d32Smrg line[count++] = final; 54080bd37d32Smrg break; 54090bd37d32Smrg } 54100bd37d32Smrg 5411d522f475Smrg /* Transmit key sequence to process running under xterm */ 5412f2e35a3aSmrg TRACE(("EditorButton -> %s\n", visibleChars(line, count))); 5413d522f475Smrg v_write(pty, line, count); 5414d522f475Smrg } 5415d522f475Smrg return; 5416d522f475Smrg} 5417d522f475Smrg 5418913cc679Smrg/* 5419913cc679Smrg * Check the current send_mouse_pos against allowed mouse-operations, returning 5420913cc679Smrg * none if it is disallowed. 5421913cc679Smrg */ 5422913cc679SmrgXtermMouseModes 5423913cc679SmrgokSendMousePos(XtermWidget xw) 5424913cc679Smrg{ 5425913cc679Smrg TScreen *screen = TScreenOf(xw); 5426f2e35a3aSmrg XtermMouseModes result = (XtermMouseModes) screen->send_mouse_pos; 5427913cc679Smrg 5428f2e35a3aSmrg switch ((int) result) { 5429913cc679Smrg case MOUSE_OFF: 5430913cc679Smrg break; 5431913cc679Smrg case X10_MOUSE: 5432913cc679Smrg if (!AllowMouseOps(xw, emX10)) 5433913cc679Smrg result = MOUSE_OFF; 5434913cc679Smrg break; 5435913cc679Smrg case VT200_MOUSE: 5436913cc679Smrg if (!AllowMouseOps(xw, emVT200Click)) 5437913cc679Smrg result = MOUSE_OFF; 5438913cc679Smrg break; 5439913cc679Smrg case VT200_HIGHLIGHT_MOUSE: 5440913cc679Smrg if (!AllowMouseOps(xw, emVT200Hilite)) 5441913cc679Smrg result = MOUSE_OFF; 5442913cc679Smrg break; 5443913cc679Smrg case BTN_EVENT_MOUSE: 5444913cc679Smrg if (!AllowMouseOps(xw, emAnyButton)) 5445913cc679Smrg result = MOUSE_OFF; 5446913cc679Smrg break; 5447913cc679Smrg case ANY_EVENT_MOUSE: 5448913cc679Smrg if (!AllowMouseOps(xw, emAnyEvent)) 5449913cc679Smrg result = MOUSE_OFF; 5450913cc679Smrg break; 5451913cc679Smrg case DEC_LOCATOR: 5452913cc679Smrg if (!AllowMouseOps(xw, emLocator)) 5453913cc679Smrg result = MOUSE_OFF; 5454913cc679Smrg break; 5455913cc679Smrg } 5456913cc679Smrg return result; 5457913cc679Smrg} 5458913cc679Smrg 5459d522f475Smrg#if OPT_FOCUS_EVENT 5460913cc679Smrg/* 5461913cc679Smrg * Check the current send_focus_pos against allowed mouse-operations, returning 5462913cc679Smrg * none if it is disallowed. 5463913cc679Smrg */ 5464913cc679Smrgstatic int 5465913cc679SmrgokSendFocusPos(XtermWidget xw) 5466d522f475Smrg{ 5467956cc18dSsnj TScreen *screen = TScreenOf(xw); 5468913cc679Smrg int result = screen->send_focus_pos; 5469913cc679Smrg 5470913cc679Smrg if (!AllowMouseOps(xw, emFocusEvent)) { 5471913cc679Smrg result = False; 5472913cc679Smrg } 5473913cc679Smrg return result; 5474913cc679Smrg} 5475d522f475Smrg 5476913cc679Smrgvoid 5477913cc679SmrgSendFocusButton(XtermWidget xw, XFocusChangeEvent *event) 5478913cc679Smrg{ 5479913cc679Smrg if (okSendFocusPos(xw)) { 5480d522f475Smrg ANSI reply; 5481d522f475Smrg 5482d522f475Smrg memset(&reply, 0, sizeof(reply)); 5483d522f475Smrg reply.a_type = ANSI_CSI; 5484d522f475Smrg 5485d522f475Smrg#if OPT_SCO_FUNC_KEYS 5486d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 5487d522f475Smrg reply.a_pintro = '>'; 5488d522f475Smrg } 5489d522f475Smrg#endif 54902eaa94a1Schristos reply.a_final = CharOf((event->type == FocusIn) ? 'I' : 'O'); 5491d522f475Smrg unparseseq(xw, &reply); 5492d522f475Smrg } 5493d522f475Smrg return; 5494d522f475Smrg} 5495d522f475Smrg#endif /* OPT_FOCUS_EVENT */ 54960bd37d32Smrg 54970bd37d32Smrg#if OPT_SELECTION_OPS 54980bd37d32Smrg/* 54990bd37d32Smrg * Get the event-time, needed to process selections. 55000bd37d32Smrg */ 55010bd37d32Smrgstatic Time 5502894e0ac8SmrggetEventTime(XEvent *event) 55030bd37d32Smrg{ 55040bd37d32Smrg Time result; 55050bd37d32Smrg 55060bd37d32Smrg if (IsBtnEvent(event)) { 55070bd37d32Smrg result = ((XButtonEvent *) event)->time; 55080bd37d32Smrg } else if (IsKeyEvent(event)) { 55090bd37d32Smrg result = ((XKeyEvent *) event)->time; 55100bd37d32Smrg } else { 55110bd37d32Smrg result = 0; 55120bd37d32Smrg } 55130bd37d32Smrg 55140bd37d32Smrg return result; 55150bd37d32Smrg} 55160bd37d32Smrg 55170bd37d32Smrg/* obtain the selection string, passing the endpoints to caller's parameters */ 551801037d57Smrgstatic void 551901037d57SmrgdoSelectionFormat(XtermWidget xw, 552001037d57Smrg Widget w, 552101037d57Smrg XEvent *event, 552201037d57Smrg String *params, 552301037d57Smrg Cardinal *num_params, 552401037d57Smrg FormatSelect format_select) 55250bd37d32Smrg{ 55260bd37d32Smrg TScreen *screen = TScreenOf(xw); 552701037d57Smrg InternalSelect *mydata = &(screen->internal_select); 552801037d57Smrg 552901037d57Smrg memset(mydata, 0, sizeof(*mydata)); 553001037d57Smrg mydata->format = x_strdup(params[0]); 553101037d57Smrg mydata->format_select = format_select; 55320bd37d32Smrg 55330bd37d32Smrg screen->selectToBuffer = True; 5534f2e35a3aSmrg beginInternalSelect(xw); 5535f2e35a3aSmrg 55360bd37d32Smrg xtermGetSelection(w, getEventTime(event), params + 1, *num_params - 1, NULL); 5537f2e35a3aSmrg 5538f2e35a3aSmrg if (screen->selectToBuffer) 5539f2e35a3aSmrg finishInternalSelect(xw); 55400bd37d32Smrg} 55410bd37d32Smrg 55420bd37d32Smrg/* obtain data from the screen, passing the endpoints to caller's parameters */ 55430bd37d32Smrgstatic char * 5544913cc679SmrggetDataFromScreen(XtermWidget xw, XEvent *event, String method, CELL *start, CELL *finish) 55450bd37d32Smrg{ 55460bd37d32Smrg TScreen *screen = TScreenOf(xw); 55470bd37d32Smrg 55480bd37d32Smrg CELL save_old_start = screen->startH; 55490bd37d32Smrg CELL save_old_end = screen->endH; 55500bd37d32Smrg 55510bd37d32Smrg CELL save_startSel = screen->startSel; 55520bd37d32Smrg CELL save_startRaw = screen->startRaw; 55530bd37d32Smrg CELL save_finishSel = screen->endSel; 55540bd37d32Smrg CELL save_finishRaw = screen->endRaw; 55550bd37d32Smrg 55560bd37d32Smrg int save_firstValidRow = screen->firstValidRow; 55570bd37d32Smrg int save_lastValidRow = screen->lastValidRow; 55580bd37d32Smrg 555901037d57Smrg const Cardinal noClick = 0; 556001037d57Smrg int save_numberOfClicks = screen->numberOfClicks; 556101037d57Smrg 55620bd37d32Smrg SelectUnit saveUnits = screen->selectUnit; 556301037d57Smrg SelectUnit saveMap = screen->selectMap[noClick]; 55640bd37d32Smrg#if OPT_SELECT_REGEX 556501037d57Smrg char *saveExpr = screen->selectExpr[noClick]; 55660bd37d32Smrg#endif 5567f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[PRIMARY_CODE]); 5568f2e35a3aSmrg SelectedCells save_selection = *scp; 55690bd37d32Smrg 55700bd37d32Smrg char *result = 0; 55710bd37d32Smrg 55720bd37d32Smrg TRACE(("getDataFromScreen %s\n", method)); 55730bd37d32Smrg 5574f2e35a3aSmrg memset(scp, 0, sizeof(*scp)); 55750bd37d32Smrg 557601037d57Smrg screen->numberOfClicks = 1; 557701037d57Smrg lookupSelectUnit(xw, noClick, method); 557801037d57Smrg screen->selectUnit = screen->selectMap[noClick]; 55790bd37d32Smrg 55800bd37d32Smrg memset(start, 0, sizeof(*start)); 5581913cc679Smrg if (IsBtnEvent(event)) { 5582913cc679Smrg XButtonEvent *btn_event = (XButtonEvent *) event; 5583913cc679Smrg CELL cell; 5584913cc679Smrg screen->firstValidRow = 0; 5585913cc679Smrg screen->lastValidRow = screen->max_row; 5586913cc679Smrg PointToCELL(screen, btn_event->y, btn_event->x, &cell); 5587913cc679Smrg start->row = cell.row; 5588913cc679Smrg start->col = cell.col; 5589913cc679Smrg finish->row = cell.row; 5590913cc679Smrg finish->col = screen->max_col; 5591913cc679Smrg } else { 5592913cc679Smrg start->row = screen->cur_row; 5593913cc679Smrg start->col = screen->cur_col; 5594913cc679Smrg finish->row = screen->cur_row; 5595913cc679Smrg finish->col = screen->max_col; 5596913cc679Smrg } 55970bd37d32Smrg 5598f2e35a3aSmrg ComputeSelect(xw, start, finish, False, False); 5599f2e35a3aSmrg SaltTextAway(xw, 5600f2e35a3aSmrg TargetToSelection(screen, PRIMARY_NAME), 5601f2e35a3aSmrg &(screen->startSel), &(screen->endSel)); 56020bd37d32Smrg 5603f2e35a3aSmrg if (scp->data_limit && scp->data_buffer) { 5604f2e35a3aSmrg TRACE(("...getDataFromScreen selection-data %.*s\n", 5605f2e35a3aSmrg (int) scp->data_limit, 5606f2e35a3aSmrg scp->data_buffer)); 5607f2e35a3aSmrg result = malloc(scp->data_limit + 1); 56080bd37d32Smrg if (result) { 5609f2e35a3aSmrg memcpy(result, scp->data_buffer, scp->data_limit); 5610f2e35a3aSmrg result[scp->data_limit] = 0; 56110bd37d32Smrg } 5612f2e35a3aSmrg free(scp->data_buffer); 5613f2e35a3aSmrg scp->data_limit = 0; 56140bd37d32Smrg } 56150bd37d32Smrg 56160bd37d32Smrg TRACE(("...getDataFromScreen restoring previous selection\n")); 56170bd37d32Smrg 56180bd37d32Smrg screen->startSel = save_startSel; 56190bd37d32Smrg screen->startRaw = save_startRaw; 56200bd37d32Smrg screen->endSel = save_finishSel; 56210bd37d32Smrg screen->endRaw = save_finishRaw; 56220bd37d32Smrg 56230bd37d32Smrg screen->firstValidRow = save_firstValidRow; 56240bd37d32Smrg screen->lastValidRow = save_lastValidRow; 56250bd37d32Smrg 562601037d57Smrg screen->numberOfClicks = save_numberOfClicks; 56270bd37d32Smrg screen->selectUnit = saveUnits; 562801037d57Smrg screen->selectMap[noClick] = saveMap; 56290bd37d32Smrg#if OPT_SELECT_REGEX 563001037d57Smrg screen->selectExpr[noClick] = saveExpr; 56310bd37d32Smrg#endif 56320bd37d32Smrg 5633f2e35a3aSmrg screen->selected_cells[0] = save_selection; 56340bd37d32Smrg 56350bd37d32Smrg TrackText(xw, &save_old_start, &save_old_end); 56360bd37d32Smrg 56370bd37d32Smrg TRACE(("...getDataFromScreen done\n")); 56380bd37d32Smrg return result; 56390bd37d32Smrg} 56400bd37d32Smrg 56410bd37d32Smrg/* 56420bd37d32Smrg * Split-up the format before substituting data, to avoid quoting issues. 56430bd37d32Smrg * The resource mechanism has a limited ability to handle escapes. We take 56440bd37d32Smrg * the result as if it were an sh-type string and parse it into a regular 56450bd37d32Smrg * argv array. 56460bd37d32Smrg */ 56470bd37d32Smrgstatic char ** 56480bd37d32SmrgtokenizeFormat(String format) 56490bd37d32Smrg{ 56500bd37d32Smrg char **result = 0; 56510bd37d32Smrg 56520bd37d32Smrg format = x_skip_blanks(format); 56530bd37d32Smrg if (*format != '\0') { 56540bd37d32Smrg char *blob = x_strdup(format); 56552e4f8982Smrg int pass; 56560bd37d32Smrg 56570bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 56580bd37d32Smrg int used = 0; 56590bd37d32Smrg int first = 1; 56600bd37d32Smrg int escaped = 0; 56610bd37d32Smrg int squoted = 0; 56620bd37d32Smrg int dquoted = 0; 56632e4f8982Smrg int n; 5664f2e35a3aSmrg int argc = 0; 56650bd37d32Smrg 56660bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 56670bd37d32Smrg if (escaped) { 56680bd37d32Smrg blob[used++] = format[n]; 56690bd37d32Smrg escaped = 0; 56700bd37d32Smrg } else if (format[n] == '"') { 56710bd37d32Smrg if (!squoted) { 56720bd37d32Smrg if (!dquoted) 56730bd37d32Smrg blob[used++] = format[n]; 56740bd37d32Smrg dquoted = !dquoted; 56750bd37d32Smrg } 56760bd37d32Smrg } else if (format[n] == '\'') { 56770bd37d32Smrg if (!dquoted) { 56780bd37d32Smrg if (!squoted) 56790bd37d32Smrg blob[used++] = format[n]; 56800bd37d32Smrg squoted = !squoted; 56810bd37d32Smrg } 56820bd37d32Smrg } else if (format[n] == '\\') { 56830bd37d32Smrg blob[used++] = format[n]; 56840bd37d32Smrg escaped = 1; 56850bd37d32Smrg } else { 56860bd37d32Smrg if (first) { 56870bd37d32Smrg first = 0; 56880bd37d32Smrg if (pass) { 56890bd37d32Smrg result[argc] = &blob[n]; 56900bd37d32Smrg } 56910bd37d32Smrg ++argc; 56920bd37d32Smrg } 56930bd37d32Smrg if (isspace((Char) format[n])) { 56940bd37d32Smrg first = !isspace((Char) format[n + 1]); 56950bd37d32Smrg if (squoted || dquoted) { 56960bd37d32Smrg blob[used++] = format[n]; 56970bd37d32Smrg } else if (first) { 56980bd37d32Smrg blob[used++] = '\0'; 56990bd37d32Smrg } 57000bd37d32Smrg } else { 57010bd37d32Smrg blob[used++] = format[n]; 57020bd37d32Smrg } 57030bd37d32Smrg } 57040bd37d32Smrg } 57050bd37d32Smrg blob[used] = '\0'; 57060bd37d32Smrg assert(strlen(blob) <= strlen(format)); 57070bd37d32Smrg if (!pass) { 57080bd37d32Smrg result = TypeCallocN(char *, argc + 1); 57090bd37d32Smrg if (result == 0) { 57100bd37d32Smrg free(blob); 57110bd37d32Smrg break; 57120bd37d32Smrg } 57130bd37d32Smrg } 57140bd37d32Smrg } 57150bd37d32Smrg } 57160bd37d32Smrg#if OPT_TRACE 57170bd37d32Smrg if (result) { 5718f2e35a3aSmrg int n; 57190bd37d32Smrg TRACE(("tokenizeFormat %s\n", format)); 5720f2e35a3aSmrg for (n = 0; result[n]; ++n) { 5721f2e35a3aSmrg TRACE(("argv[%d] = %s\n", n, result[n])); 57220bd37d32Smrg } 57230bd37d32Smrg } 57240bd37d32Smrg#endif 57250bd37d32Smrg 57260bd37d32Smrg return result; 57270bd37d32Smrg} 57280bd37d32Smrg 57290bd37d32Smrgstatic void 5730e0a2b6dfSmrgformatVideoAttrs(XtermWidget xw, char *buffer, CELL *cell) 57310bd37d32Smrg{ 57320bd37d32Smrg TScreen *screen = TScreenOf(xw); 57330bd37d32Smrg LineData *ld = GET_LINEDATA(screen, cell->row); 57340bd37d32Smrg 57350bd37d32Smrg *buffer = '\0'; 57360bd37d32Smrg if (ld != 0 && cell->col < (int) ld->lineSize) { 5737894e0ac8Smrg IAttr attribs = ld->attribs[cell->col]; 57380bd37d32Smrg const char *delim = ""; 57390bd37d32Smrg 57400bd37d32Smrg if (attribs & INVERSE) { 57410bd37d32Smrg buffer += sprintf(buffer, "7"); 57420bd37d32Smrg delim = ";"; 57430bd37d32Smrg } 57440bd37d32Smrg if (attribs & UNDERLINE) { 57450bd37d32Smrg buffer += sprintf(buffer, "%s4", delim); 57460bd37d32Smrg delim = ";"; 57470bd37d32Smrg } 57480bd37d32Smrg if (attribs & BOLD) { 57490bd37d32Smrg buffer += sprintf(buffer, "%s1", delim); 57500bd37d32Smrg delim = ";"; 57510bd37d32Smrg } 57520bd37d32Smrg if (attribs & BLINK) { 57530bd37d32Smrg buffer += sprintf(buffer, "%s5", delim); 57540bd37d32Smrg delim = ";"; 57550bd37d32Smrg } 57560bd37d32Smrg#if OPT_ISO_COLORS 57570bd37d32Smrg if (attribs & FG_COLOR) { 5758f2e35a3aSmrg Pixel fg = extract_fg(xw, ld->color[cell->col], attribs); 57590bd37d32Smrg if (fg < 8) { 57600bd37d32Smrg fg += 30; 57610bd37d32Smrg } else if (fg < 16) { 57620bd37d32Smrg fg += 90; 57630bd37d32Smrg } else { 57640bd37d32Smrg buffer += sprintf(buffer, "%s38;5", delim); 57650bd37d32Smrg delim = ";"; 57660bd37d32Smrg } 5767f2e35a3aSmrg buffer += sprintf(buffer, "%s%lu", delim, fg); 57680bd37d32Smrg delim = ";"; 57690bd37d32Smrg } 57700bd37d32Smrg if (attribs & BG_COLOR) { 5771f2e35a3aSmrg Pixel bg = extract_bg(xw, ld->color[cell->col], attribs); 57720bd37d32Smrg if (bg < 8) { 57730bd37d32Smrg bg += 40; 57740bd37d32Smrg } else if (bg < 16) { 57750bd37d32Smrg bg += 100; 57760bd37d32Smrg } else { 57770bd37d32Smrg buffer += sprintf(buffer, "%s48;5", delim); 57780bd37d32Smrg delim = ";"; 57790bd37d32Smrg } 5780f2e35a3aSmrg (void) sprintf(buffer, "%s%lu", delim, bg); 57810bd37d32Smrg } 57820bd37d32Smrg#endif 57830bd37d32Smrg } 57840bd37d32Smrg} 57850bd37d32Smrg 57862e4f8982Smrgstatic char * 57872e4f8982SmrgformatStrlen(char *target, char *source, int freeit) 57882e4f8982Smrg{ 57892e4f8982Smrg if (source != 0) { 57902e4f8982Smrg sprintf(target, "%u", (unsigned) strlen(source)); 57912e4f8982Smrg if (freeit) { 57922e4f8982Smrg free(source); 57932e4f8982Smrg } 57942e4f8982Smrg } else { 57952e4f8982Smrg strcpy(target, "0"); 57962e4f8982Smrg } 57972e4f8982Smrg return target; 57982e4f8982Smrg} 57992e4f8982Smrg 58000bd37d32Smrg/* substitute data into format, reallocating the result */ 58010bd37d32Smrgstatic char * 58020bd37d32SmrgexpandFormat(XtermWidget xw, 58030bd37d32Smrg const char *format, 58040bd37d32Smrg char *data, 5805e0a2b6dfSmrg CELL *start, 5806e0a2b6dfSmrg CELL *finish) 58070bd37d32Smrg{ 58080bd37d32Smrg char *result = 0; 58090bd37d32Smrg if (!IsEmpty(format)) { 58100bd37d32Smrg static char empty[1]; 58110bd37d32Smrg int pass; 58120bd37d32Smrg int n; 58130bd37d32Smrg char numbers[80]; 58140bd37d32Smrg 58150bd37d32Smrg if (data == 0) 58160bd37d32Smrg data = empty; 58170bd37d32Smrg 58180bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 58190bd37d32Smrg size_t need = 0; 58200bd37d32Smrg 58210bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 58220bd37d32Smrg 58230bd37d32Smrg if (format[n] == '%') { 58242e4f8982Smrg char *value = 0; 58252e4f8982Smrg 58260bd37d32Smrg switch (format[++n]) { 58270bd37d32Smrg case '%': 58280bd37d32Smrg if (pass) { 58290bd37d32Smrg result[need] = format[n]; 58300bd37d32Smrg } 58310bd37d32Smrg ++need; 58320bd37d32Smrg break; 58330bd37d32Smrg case 'P': 58340bd37d32Smrg sprintf(numbers, "%d;%d", 58350bd37d32Smrg TScreenOf(xw)->topline + start->row + 1, 58360bd37d32Smrg start->col + 1); 58370bd37d32Smrg value = numbers; 58380bd37d32Smrg break; 58390bd37d32Smrg case 'p': 58400bd37d32Smrg sprintf(numbers, "%d;%d", 58410bd37d32Smrg TScreenOf(xw)->topline + finish->row + 1, 58420bd37d32Smrg finish->col + 1); 58430bd37d32Smrg value = numbers; 58440bd37d32Smrg break; 58452e4f8982Smrg case 'R': 58462e4f8982Smrg value = formatStrlen(numbers, x_strrtrim(data), 1); 58472e4f8982Smrg break; 58482e4f8982Smrg case 'r': 58492e4f8982Smrg value = x_strrtrim(data); 58502e4f8982Smrg break; 58510bd37d32Smrg case 'S': 58522e4f8982Smrg value = formatStrlen(numbers, data, 0); 58530bd37d32Smrg break; 58540bd37d32Smrg case 's': 58550bd37d32Smrg value = data; 58560bd37d32Smrg break; 58570bd37d32Smrg case 'T': 58582e4f8982Smrg value = formatStrlen(numbers, x_strtrim(data), 1); 58590bd37d32Smrg break; 58600bd37d32Smrg case 't': 58610bd37d32Smrg value = x_strtrim(data); 58620bd37d32Smrg break; 58630bd37d32Smrg case 'V': 58640bd37d32Smrg formatVideoAttrs(xw, numbers, start); 58650bd37d32Smrg value = numbers; 58660bd37d32Smrg break; 58670bd37d32Smrg case 'v': 58680bd37d32Smrg formatVideoAttrs(xw, numbers, finish); 58690bd37d32Smrg value = numbers; 58700bd37d32Smrg break; 58710bd37d32Smrg default: 58720bd37d32Smrg if (pass) { 58730bd37d32Smrg result[need] = format[n]; 58740bd37d32Smrg } 58750bd37d32Smrg --n; 58760bd37d32Smrg ++need; 58770bd37d32Smrg break; 58780bd37d32Smrg } 58790bd37d32Smrg if (value != 0) { 58800bd37d32Smrg if (pass) { 58810bd37d32Smrg strcpy(result + need, value); 58820bd37d32Smrg } 58830bd37d32Smrg need += strlen(value); 58840bd37d32Smrg if (value != numbers && value != data) { 58850bd37d32Smrg free(value); 58860bd37d32Smrg } 58870bd37d32Smrg } 58880bd37d32Smrg } else { 58890bd37d32Smrg if (pass) { 58900bd37d32Smrg result[need] = format[n]; 58910bd37d32Smrg } 58920bd37d32Smrg ++need; 58930bd37d32Smrg } 58940bd37d32Smrg } 58950bd37d32Smrg if (pass) { 58960bd37d32Smrg result[need] = '\0'; 58970bd37d32Smrg } else { 58980bd37d32Smrg ++need; 58990bd37d32Smrg result = malloc(need); 59000bd37d32Smrg if (result == 0) { 59010bd37d32Smrg break; 59020bd37d32Smrg } 59030bd37d32Smrg } 59040bd37d32Smrg } 59050bd37d32Smrg } 59060bd37d32Smrg TRACE(("expandFormat(%s) = %s\n", NonNull(format), NonNull(result))); 59070bd37d32Smrg return result; 59080bd37d32Smrg} 59090bd37d32Smrg 59100bd37d32Smrg/* execute the command after forking. The main process frees its data */ 59110bd37d32Smrgstatic void 59122e4f8982SmrgexecuteCommand(pid_t pid, char **argv) 59130bd37d32Smrg{ 59142e4f8982Smrg (void) pid; 59150bd37d32Smrg if (argv != 0 && argv[0] != 0) { 59162e4f8982Smrg char *child_cwd = ProcGetCWD(pid); 59172e4f8982Smrg 59180bd37d32Smrg if (fork() == 0) { 59192e4f8982Smrg if (child_cwd) { 59202e4f8982Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 59212e4f8982Smrg } 59220bd37d32Smrg execvp(argv[0], argv); 59230bd37d32Smrg exit(EXIT_FAILURE); 59240bd37d32Smrg } 5925913cc679Smrg free(child_cwd); 59260bd37d32Smrg } 59270bd37d32Smrg} 59280bd37d32Smrg 59290bd37d32Smrgstatic void 59300bd37d32SmrgfreeArgv(char *blob, char **argv) 59310bd37d32Smrg{ 59320bd37d32Smrg if (blob) { 59330bd37d32Smrg free(blob); 59340bd37d32Smrg if (argv) { 59352e4f8982Smrg int n; 59360bd37d32Smrg for (n = 0; argv[n]; ++n) 59370bd37d32Smrg free(argv[n]); 59380bd37d32Smrg free(argv); 59390bd37d32Smrg } 59400bd37d32Smrg } 59410bd37d32Smrg} 59420bd37d32Smrg 594301037d57Smrgstatic void 594401037d57SmrgreallyExecFormatted(Widget w, char *format, char *data, CELL *start, CELL *finish) 594501037d57Smrg{ 594601037d57Smrg XtermWidget xw; 594701037d57Smrg 594801037d57Smrg if ((xw = getXtermWidget(w)) != 0) { 594901037d57Smrg char **argv; 595001037d57Smrg 595101037d57Smrg if ((argv = tokenizeFormat(format)) != 0) { 59522e4f8982Smrg char *blob = argv[0]; 59532e4f8982Smrg int argc; 59542e4f8982Smrg 595501037d57Smrg for (argc = 0; argv[argc] != 0; ++argc) { 595601037d57Smrg argv[argc] = expandFormat(xw, argv[argc], data, start, finish); 595701037d57Smrg } 59582e4f8982Smrg executeCommand(TScreenOf(xw)->pid, argv); 595901037d57Smrg freeArgv(blob, argv); 596001037d57Smrg } 596101037d57Smrg } 596201037d57Smrg} 596301037d57Smrg 59640bd37d32Smrgvoid 59650bd37d32SmrgHandleExecFormatted(Widget w, 596601037d57Smrg XEvent *event, 5967e0a2b6dfSmrg String *params, /* selections */ 59680bd37d32Smrg Cardinal *num_params) 59690bd37d32Smrg{ 59700bd37d32Smrg XtermWidget xw; 59710bd37d32Smrg 5972f2e35a3aSmrg TRACE_EVENT("HandleExecFormatted", event, params, num_params); 597301037d57Smrg if ((xw = getXtermWidget(w)) != 0 && 597401037d57Smrg (*num_params > 1)) { 597501037d57Smrg doSelectionFormat(xw, w, event, params, num_params, reallyExecFormatted); 59760bd37d32Smrg } 59770bd37d32Smrg} 59780bd37d32Smrg 59790bd37d32Smrgvoid 59800bd37d32SmrgHandleExecSelectable(Widget w, 5981913cc679Smrg XEvent *event, 5982e0a2b6dfSmrg String *params, /* selections */ 59830bd37d32Smrg Cardinal *num_params) 59840bd37d32Smrg{ 59850bd37d32Smrg XtermWidget xw; 59860bd37d32Smrg 59870bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 5988f2e35a3aSmrg TRACE_EVENT("HandleExecSelectable", event, params, num_params); 59890bd37d32Smrg 59900bd37d32Smrg if (*num_params == 2) { 59910bd37d32Smrg CELL start, finish; 59920bd37d32Smrg char *data; 59930bd37d32Smrg char **argv; 59940bd37d32Smrg 5995913cc679Smrg data = getDataFromScreen(xw, event, params[1], &start, &finish); 59960bd37d32Smrg if (data != 0) { 59970bd37d32Smrg if ((argv = tokenizeFormat(params[0])) != 0) { 59982e4f8982Smrg char *blob = argv[0]; 59992e4f8982Smrg int argc; 60002e4f8982Smrg 60010bd37d32Smrg for (argc = 0; argv[argc] != 0; ++argc) { 60020bd37d32Smrg argv[argc] = expandFormat(xw, argv[argc], data, 60030bd37d32Smrg &start, &finish); 60040bd37d32Smrg } 60052e4f8982Smrg executeCommand(TScreenOf(xw)->pid, argv); 60060bd37d32Smrg freeArgv(blob, argv); 60070bd37d32Smrg } 6008894e0ac8Smrg free(data); 60090bd37d32Smrg } 60100bd37d32Smrg } 60110bd37d32Smrg } 60120bd37d32Smrg} 60130bd37d32Smrg 601401037d57Smrgstatic void 601501037d57SmrgreallyInsertFormatted(Widget w, char *format, char *data, CELL *start, CELL *finish) 601601037d57Smrg{ 601701037d57Smrg XtermWidget xw; 601801037d57Smrg 601901037d57Smrg if ((xw = getXtermWidget(w)) != 0) { 602001037d57Smrg char *exps; 602101037d57Smrg 602201037d57Smrg if ((exps = expandFormat(xw, format, data, start, finish)) != 0) { 602301037d57Smrg unparseputs(xw, exps); 602401037d57Smrg unparse_end(xw); 602501037d57Smrg free(exps); 602601037d57Smrg } 602701037d57Smrg } 602801037d57Smrg} 602901037d57Smrg 60300bd37d32Smrgvoid 60310bd37d32SmrgHandleInsertFormatted(Widget w, 603201037d57Smrg XEvent *event, 6033e0a2b6dfSmrg String *params, /* selections */ 60340bd37d32Smrg Cardinal *num_params) 60350bd37d32Smrg{ 60360bd37d32Smrg XtermWidget xw; 60370bd37d32Smrg 6038f2e35a3aSmrg TRACE_EVENT("HandleInsertFormatted", event, params, num_params); 603901037d57Smrg if ((xw = getXtermWidget(w)) != 0 && 604001037d57Smrg (*num_params > 1)) { 604101037d57Smrg doSelectionFormat(xw, w, event, params, num_params, reallyInsertFormatted); 60420bd37d32Smrg } 60430bd37d32Smrg} 60440bd37d32Smrg 60450bd37d32Smrgvoid 60460bd37d32SmrgHandleInsertSelectable(Widget w, 6047913cc679Smrg XEvent *event, 6048e0a2b6dfSmrg String *params, /* selections */ 60490bd37d32Smrg Cardinal *num_params) 60500bd37d32Smrg{ 60510bd37d32Smrg XtermWidget xw; 60520bd37d32Smrg 60530bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 6054f2e35a3aSmrg TRACE_EVENT("HandleInsertSelectable", event, params, num_params); 60550bd37d32Smrg 60560bd37d32Smrg if (*num_params == 2) { 60570bd37d32Smrg CELL start, finish; 60580bd37d32Smrg char *data; 60590bd37d32Smrg char *temp = x_strdup(params[0]); 60600bd37d32Smrg 6061913cc679Smrg data = getDataFromScreen(xw, event, params[1], &start, &finish); 60620bd37d32Smrg if (data != 0) { 60632e4f8982Smrg char *exps = expandFormat(xw, temp, data, &start, &finish); 60640bd37d32Smrg if (exps != 0) { 60650bd37d32Smrg unparseputs(xw, exps); 606601037d57Smrg unparse_end(xw); 60670bd37d32Smrg free(exps); 60680bd37d32Smrg } 60690bd37d32Smrg free(data); 60700bd37d32Smrg } 60710bd37d32Smrg free(temp); 60720bd37d32Smrg } 60730bd37d32Smrg } 60740bd37d32Smrg} 60750bd37d32Smrg#endif /* OPT_SELECTION_OPS */ 6076