button.c revision 5104ee6e
15104ee6eSmrg/* $XTermId: button.c,v 1.669 2025/01/03 00:20:00 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 45104ee6eSmrg * Copyright 1999-2024,2025 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> 8004b94745Smrg#include <xterm_io.h> 81d522f475Smrg 82d522f475Smrg#if OPT_SELECT_REGEX 83a5ae21e4Smrg#if defined(HAVE_PCRE2POSIX_H) 84f2e35a3aSmrg#include <pcre2posix.h> 85a5ae21e4Smrg 86a5ae21e4Smrg/* pcre2 used to provide its "POSIX" entrypoints using the same names as the 87a5ae21e4Smrg * standard ones in the C runtime, but that never worked because the linker 88a5ae21e4Smrg * would use the C runtime. Debian patched the library to fix this symbol 89a5ae21e4Smrg * conflict, but overlooked the header file, and Debian's patch was made 90a5ae21e4Smrg * obsolete when pcre2 was changed early in 2019 to provide different names. 91a5ae21e4Smrg * 92a5ae21e4Smrg * Here is a workaround to make the older version of Debian's package work. 93a5ae21e4Smrg */ 94a5ae21e4Smrg#if !defined(PCRE2regcomp) && defined(HAVE_PCRE2REGCOMP) 95a5ae21e4Smrg 96a5ae21e4Smrg#undef regcomp 97a5ae21e4Smrg#undef regexec 98a5ae21e4Smrg#undef regfree 99a5ae21e4Smrg 100a5ae21e4Smrg#ifdef __cplusplus 101a5ae21e4Smrgextern "C" { 102a5ae21e4Smrg#endif 103a5ae21e4Smrg PCRE2POSIX_EXP_DECL int PCRE2regcomp(regex_t *, const char *, int); 104a5ae21e4Smrg PCRE2POSIX_EXP_DECL int PCRE2regexec(const regex_t *, const char *, size_t, 105a5ae21e4Smrg regmatch_t *, int); 106a5ae21e4Smrg PCRE2POSIX_EXP_DECL void PCRE2regfree(regex_t *); 107a5ae21e4Smrg#ifdef __cplusplus 108a5ae21e4Smrg} /* extern "C" */ 109a5ae21e4Smrg#endif 110a5ae21e4Smrg#define regcomp(r,s,n) PCRE2regcomp(r,s,n) 111a5ae21e4Smrg#define regexec(r,s,n,m,x) PCRE2regexec(r,s,n,m,x) 112a5ae21e4Smrg#define regfree(r) PCRE2regfree(r) 113a5ae21e4Smrg#endif 114a5ae21e4Smrg/* end workaround... */ 115a5ae21e4Smrg#elif defined(HAVE_PCREPOSIX_H) 116d522f475Smrg#include <pcreposix.h> 117d522f475Smrg#else /* POSIX regex.h */ 118d522f475Smrg#include <sys/types.h> 119d522f475Smrg#include <regex.h> 120d522f475Smrg#endif 121a5ae21e4Smrg#endif /* OPT_SELECT_REGEX */ 122f2e35a3aSmrg 123f2e35a3aSmrg#ifdef HAVE_X11_TRANSLATEI_H 124f2e35a3aSmrg#include <X11/ConvertI.h> 125f2e35a3aSmrg#include <X11/TranslateI.h> 126f2e35a3aSmrg#else 127f2e35a3aSmrgextern String _XtPrintXlations(Widget w, 128f2e35a3aSmrg XtTranslations xlations, 129f2e35a3aSmrg Widget accelWidget, 130f2e35a3aSmrg _XtBoolean includeRHS); 131f2e35a3aSmrg#endif 132f2e35a3aSmrg 133f2e35a3aSmrg#define PRIMARY_NAME "PRIMARY" 134f2e35a3aSmrg#define CLIPBOARD_NAME "CLIPBOARD" 135f2e35a3aSmrg#define SECONDARY_NAME "SECONDARY" 136f2e35a3aSmrg 137f2e35a3aSmrg#define AtomToSelection(d,n) \ 138f2e35a3aSmrg (((n) == XA_CLIPBOARD(d)) \ 139f2e35a3aSmrg ? CLIPBOARD_CODE \ 140f2e35a3aSmrg : (((n) == XA_SECONDARY) \ 141f2e35a3aSmrg ? SECONDARY_CODE \ 142f2e35a3aSmrg : PRIMARY_CODE)) 143f2e35a3aSmrg 144f2e35a3aSmrg#define isSelectionCode(n) ((n) >= PRIMARY_CODE) 145f2e35a3aSmrg#define CutBufferToCode(n) ((n) + MAX_SELECTION_CODES) 146f2e35a3aSmrg#define okSelectionCode(n) (isSelectionCode(n) ? (n) : PRIMARY_CODE) 147d522f475Smrg 148d522f475Smrg#if OPT_WIDE_CHARS 149d522f475Smrg#include <ctype.h> 150d522f475Smrg#include <wcwidth.h> 151d522f475Smrg#else 152d522f475Smrg#define CharacterClass(value) \ 153f2e35a3aSmrg charClass[(value) & (int)((sizeof(charClass)/sizeof(charClass[0]))-1)] 154d522f475Smrg#endif 155d522f475Smrg 156956cc18dSsnj /* 157956cc18dSsnj * We'll generally map rows to indices when doing selection. 158956cc18dSsnj * Simplify that with a macro. 159956cc18dSsnj * 160956cc18dSsnj * Note that ROW2INX() is safe to use with auto increment/decrement for 161956cc18dSsnj * the row expression since that is evaluated once. 162956cc18dSsnj */ 163956cc18dSsnj#define GET_LINEDATA(screen, row) \ 164956cc18dSsnj getLineData(screen, ROW2INX(screen, row)) 165956cc18dSsnj 166f2e35a3aSmrg#define MaxMouseBtn 5 167492d43a5Smrg 168492d43a5Smrg#define IsBtnEvent(event) ((event)->type == ButtonPress || (event)->type == ButtonRelease) 1690bd37d32Smrg#define IsKeyEvent(event) ((event)->type == KeyPress || (event)->type == KeyRelease) 170d522f475Smrg 171d522f475Smrg#define Coordinate(s,c) ((c)->row * MaxCols(s) + (c)->col) 172d522f475Smrg 173d522f475Smrgstatic const CELL zeroCELL = 174d522f475Smrg{0, 0}; 175d522f475Smrg 176d522f475Smrg#if OPT_DEC_LOCATOR 177894e0ac8Smrgstatic Bool SendLocatorPosition(XtermWidget xw, XButtonEvent *event); 178894e0ac8Smrgstatic void CheckLocatorPosition(XtermWidget xw, XButtonEvent *event); 179d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 180d522f475Smrg 181d522f475Smrg/* Multi-click handling */ 182d522f475Smrg#if OPT_READLINE 183d522f475Smrgstatic Time lastButtonDownTime = 0; 184d522f475Smrgstatic int ExtendingSelection = 0; 185d522f475Smrgstatic Time lastButton3UpTime = 0; 186d522f475Smrgstatic Time lastButton3DoubleDownTime = 0; 187d522f475Smrgstatic CELL lastButton3; /* At the release time */ 188d522f475Smrg#endif /* OPT_READLINE */ 189d522f475Smrg 190e0a2b6dfSmrgstatic Char *SaveText(TScreen *screen, int row, int scol, int ecol, 191e0a2b6dfSmrg Char *lp, int *eol); 192e0a2b6dfSmrgstatic int Length(TScreen *screen, int row, int scol, int ecol); 1935104ee6eSmrgstatic void ComputeSelect(XtermWidget xw, const CELL *startc, const CELL *endc, 1945104ee6eSmrg Bool extend, Bool normal); 195894e0ac8Smrgstatic void EditorButton(XtermWidget xw, XButtonEvent *event); 196894e0ac8Smrgstatic void EndExtend(XtermWidget w, XEvent *event, String *params, Cardinal 197d522f475Smrg num_params, Bool use_cursor_loc); 198e0a2b6dfSmrgstatic void ExtendExtend(XtermWidget xw, const CELL *cell); 199e0a2b6dfSmrgstatic void PointToCELL(TScreen *screen, int y, int x, CELL *cell); 2005104ee6eSmrgstatic void ReHiliteText(XtermWidget xw, const CELL *first, const CELL *last); 2015104ee6eSmrgstatic void SaltTextAway(XtermWidget xw, int which, const CELL *cellc, const CELL *cell); 202894e0ac8Smrgstatic void SelectSet(XtermWidget xw, XEvent *event, String *params, Cardinal num_params); 203d522f475Smrgstatic void SelectionReceived PROTO_XT_SEL_CB_ARGS; 204e0a2b6dfSmrgstatic void StartSelect(XtermWidget xw, const CELL *cell); 205894e0ac8Smrgstatic void TrackDown(XtermWidget xw, XButtonEvent *event); 206e0a2b6dfSmrgstatic void TrackText(XtermWidget xw, const CELL *first, const CELL *last); 207f2e35a3aSmrgstatic void UnHiliteText(XtermWidget xw); 208e0a2b6dfSmrgstatic void _OwnSelection(XtermWidget xw, String *selections, Cardinal count); 209894e0ac8Smrgstatic void do_select_end(XtermWidget xw, XEvent *event, String *params, 210d522f475Smrg Cardinal *num_params, Bool use_cursor_loc); 211d522f475Smrg 212492d43a5Smrg#define MOUSE_LIMIT (255 - 32) 213d522f475Smrg 214492d43a5Smrg/* Send SET_EXT_SIZE_MOUSE to enable offsets up to EXT_MOUSE_LIMIT */ 215492d43a5Smrg#define EXT_MOUSE_LIMIT (2047 - 32) 216492d43a5Smrg#define EXT_MOUSE_START (127 - 32) 217d522f475Smrg 2180bd37d32Smrgstatic int 219e0a2b6dfSmrgMouseLimit(TScreen *screen) 2200bd37d32Smrg{ 2210bd37d32Smrg int mouse_limit; 2220bd37d32Smrg 2230bd37d32Smrg switch (screen->extend_coords) { 2240bd37d32Smrg default: 2250bd37d32Smrg mouse_limit = MOUSE_LIMIT; 2260bd37d32Smrg break; 2270bd37d32Smrg case SET_EXT_MODE_MOUSE: 2280bd37d32Smrg mouse_limit = EXT_MOUSE_LIMIT; 2290bd37d32Smrg break; 2300bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 2310bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 232f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 2330bd37d32Smrg mouse_limit = -1; 2340bd37d32Smrg break; 2350bd37d32Smrg } 2360bd37d32Smrg return mouse_limit; 2370bd37d32Smrg} 2380bd37d32Smrg 239492d43a5Smrgstatic unsigned 240e0a2b6dfSmrgEmitMousePosition(TScreen *screen, Char line[], unsigned count, int value) 241492d43a5Smrg{ 2420bd37d32Smrg int mouse_limit = MouseLimit(screen); 243492d43a5Smrg 244492d43a5Smrg /* 245492d43a5Smrg * Add pointer position to key sequence 246492d43a5Smrg * 247492d43a5Smrg * In extended mode we encode large positions as two-byte UTF-8. 248492d43a5Smrg * 249492d43a5Smrg * NOTE: historically, it was possible to emit 256, which became 250492d43a5Smrg * zero by truncation to 8 bits. While this was arguably a bug, 251492d43a5Smrg * it's also somewhat useful as a past-end marker. We preserve 252492d43a5Smrg * this behavior for both normal and extended mouse modes. 253492d43a5Smrg */ 2540bd37d32Smrg switch (screen->extend_coords) { 2550bd37d32Smrg default: 2560bd37d32Smrg if (value == mouse_limit) { 2570bd37d32Smrg line[count++] = CharOf(0); 2580bd37d32Smrg } else { 2590bd37d32Smrg line[count++] = CharOf(' ' + value + 1); 2600bd37d32Smrg } 2610bd37d32Smrg break; 2620bd37d32Smrg case SET_EXT_MODE_MOUSE: 2630bd37d32Smrg if (value == mouse_limit) { 2640bd37d32Smrg line[count++] = CharOf(0); 2650bd37d32Smrg } else if (value < EXT_MOUSE_START) { 2660bd37d32Smrg line[count++] = CharOf(' ' + value + 1); 2670bd37d32Smrg } else { 2680bd37d32Smrg value += ' ' + 1; 2690bd37d32Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 2700bd37d32Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 2710bd37d32Smrg } 2720bd37d32Smrg break; 2730bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 2740bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 275f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 2760bd37d32Smrg count += (unsigned) sprintf((char *) line + count, "%d", value + 1); 2770bd37d32Smrg break; 2780bd37d32Smrg } 2790bd37d32Smrg return count; 2800bd37d32Smrg} 2810bd37d32Smrg 2820bd37d32Smrgstatic unsigned 283e0a2b6dfSmrgEmitMousePositionSeparator(TScreen *screen, Char line[], unsigned count) 2840bd37d32Smrg{ 2850bd37d32Smrg switch (screen->extend_coords) { 2860bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 2870bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 288f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 2890bd37d32Smrg line[count++] = ';'; 2900bd37d32Smrg break; 291d522f475Smrg } 292492d43a5Smrg return count; 293492d43a5Smrg} 294d522f475Smrg 295f2e35a3aSmrgenum { 296f2e35a3aSmrg scanMods, 297f2e35a3aSmrg scanKey, 298f2e35a3aSmrg scanColon, 299f2e35a3aSmrg scanFunc, 300f2e35a3aSmrg scanArgs 301f2e35a3aSmrg}; 302f2e35a3aSmrg 303f2e35a3aSmrg#if OPT_TRACE > 1 304f2e35a3aSmrgstatic const char * 305f2e35a3aSmrgvisibleScan(int mode) 306f2e35a3aSmrg{ 307f2e35a3aSmrg const char *result = "?"; 308f2e35a3aSmrg#define DATA(name) case name: result = #name; break 309f2e35a3aSmrg switch (mode) { 310f2e35a3aSmrg DATA(scanMods); 311f2e35a3aSmrg DATA(scanKey); 312f2e35a3aSmrg DATA(scanColon); 313f2e35a3aSmrg DATA(scanFunc); 314f2e35a3aSmrg DATA(scanArgs); 315f2e35a3aSmrg } 316f2e35a3aSmrg#undef DATA 317f2e35a3aSmrg return result; 318f2e35a3aSmrg} 319f2e35a3aSmrg#endif 320f2e35a3aSmrg 321f2e35a3aSmrg#define L_BRACK '<' 322f2e35a3aSmrg#define R_BRACK '>' 323f2e35a3aSmrg#define L_PAREN '(' 324f2e35a3aSmrg#define R_PAREN ')' 325f2e35a3aSmrg 326f2e35a3aSmrgstatic char * 327f2e35a3aSmrgscanTrans(char *source, int *this_is, int *next_is, unsigned *first, unsigned *last) 328f2e35a3aSmrg{ 329f2e35a3aSmrg char *target = source; 330f2e35a3aSmrg 331f2e35a3aSmrg *first = *last = 0; 332f2e35a3aSmrg if (IsEmpty(target)) { 3335104ee6eSmrg target = NULL; 334f2e35a3aSmrg } else { 335f2e35a3aSmrg do { 3364419d26bSmrg char ch; 337f2e35a3aSmrg while (IsSpace(*target)) 338f2e35a3aSmrg target++; 339f2e35a3aSmrg *first = (unsigned) (target - source); 340f2e35a3aSmrg switch (*this_is = *next_is) { 341f2e35a3aSmrg case scanMods: 342f2e35a3aSmrg while ((ch = *target)) { 343f2e35a3aSmrg if (IsSpace(ch)) { 344f2e35a3aSmrg break; 345f2e35a3aSmrg } else if (ch == L_BRACK) { 346f2e35a3aSmrg *next_is = scanKey; 347f2e35a3aSmrg break; 348f2e35a3aSmrg } else if (ch == ':') { 349f2e35a3aSmrg *next_is = scanColon; 350f2e35a3aSmrg break; 351f2e35a3aSmrg } else if (ch == '~' && target != source) { 352f2e35a3aSmrg break; 353f2e35a3aSmrg } 354f2e35a3aSmrg target++; 355f2e35a3aSmrg } 356f2e35a3aSmrg break; 357f2e35a3aSmrg case scanKey: 358f2e35a3aSmrg while ((ch = *target)) { 359f2e35a3aSmrg if (IsSpace(ch)) { 360f2e35a3aSmrg break; 361f2e35a3aSmrg } else if (ch == ':') { 362f2e35a3aSmrg *next_is = scanColon; 363f2e35a3aSmrg break; 364f2e35a3aSmrg } 365f2e35a3aSmrg target++; 366f2e35a3aSmrg if (ch == R_BRACK) 367f2e35a3aSmrg break; 368f2e35a3aSmrg } 369f2e35a3aSmrg break; 370f2e35a3aSmrg case scanColon: 371f2e35a3aSmrg *next_is = scanFunc; 372f2e35a3aSmrg target++; 373f2e35a3aSmrg break; 374f2e35a3aSmrg case scanFunc: 375f2e35a3aSmrg while ((ch = *target)) { 376f2e35a3aSmrg if (IsSpace(ch)) { 377f2e35a3aSmrg break; 378f2e35a3aSmrg } else if (ch == L_PAREN) { 379f2e35a3aSmrg *next_is = scanArgs; 380f2e35a3aSmrg break; 381f2e35a3aSmrg } 382f2e35a3aSmrg target++; 383f2e35a3aSmrg } 384f2e35a3aSmrg break; 385f2e35a3aSmrg case scanArgs: 386f2e35a3aSmrg while ((ch = *target)) { 387f2e35a3aSmrg if (ch == R_PAREN) { 388f2e35a3aSmrg target++; 389f2e35a3aSmrg *next_is = scanFunc; 390f2e35a3aSmrg break; 391f2e35a3aSmrg } 392f2e35a3aSmrg target++; 393f2e35a3aSmrg } 394f2e35a3aSmrg break; 395f2e35a3aSmrg } 396f2e35a3aSmrg *last = (unsigned) (target - source); 397f2e35a3aSmrg if (*target == '\n') { 398f2e35a3aSmrg *next_is = scanMods; 399f2e35a3aSmrg target++; 400f2e35a3aSmrg } 401f2e35a3aSmrg } while (*first == *last); 402f2e35a3aSmrg } 403f2e35a3aSmrg return target; 404f2e35a3aSmrg} 405f2e35a3aSmrg 406f2e35a3aSmrgvoid 407f2e35a3aSmrgxtermButtonInit(XtermWidget xw) 408f2e35a3aSmrg{ 409f2e35a3aSmrg Widget w = (Widget) xw; 410f2e35a3aSmrg XErrorHandler save = XSetErrorHandler(ignore_x11_error); 411f2e35a3aSmrg XtTranslations xlations; 412f2e35a3aSmrg Widget xcelerat; 413f2e35a3aSmrg String result; 414f2e35a3aSmrg 415f2e35a3aSmrg XtVaGetValues(w, 416f2e35a3aSmrg XtNtranslations, &xlations, 417f2e35a3aSmrg XtNaccelerators, &xcelerat, 418f2e35a3aSmrg (XtPointer) 0); 419f2e35a3aSmrg result = _XtPrintXlations(w, xlations, xcelerat, True); 420f2e35a3aSmrg if (result) { 421f2e35a3aSmrg static const char *table[] = 422f2e35a3aSmrg { 423f2e35a3aSmrg "insert-selection", 424f2e35a3aSmrg "select-end", 425f2e35a3aSmrg "select-extend", 426f2e35a3aSmrg "select-start", 427f2e35a3aSmrg "start-extend", 428f2e35a3aSmrg }; 429f2e35a3aSmrg char *data = x_strdup(result); 430f2e35a3aSmrg char *next; 431f2e35a3aSmrg int state = scanMods; 432f2e35a3aSmrg int state2 = scanMods; 433f2e35a3aSmrg unsigned first; 434f2e35a3aSmrg unsigned last; 435f2e35a3aSmrg int have_button = -1; 436f2e35a3aSmrg Bool want_button = False; 437f2e35a3aSmrg Bool have_shift = False; 438f2e35a3aSmrg unsigned allowed = 0; 439f2e35a3aSmrg unsigned disallow = 0; 440f2e35a3aSmrg 441f2e35a3aSmrg TRACE(("xtermButtonInit length %ld\n", (long) strlen(result))); 442f2e35a3aSmrg xw->keyboard.print_translations = data; 4435104ee6eSmrg while ((next = scanTrans(data, &state, &state2, &first, &last)) != NULL) { 444f2e35a3aSmrg unsigned len = (last - first); 445f2e35a3aSmrg TRACE2(("parse %s:%d..%d '%.*s'\n", 446f2e35a3aSmrg visibleScan(state), first, last, 447f2e35a3aSmrg len, data + first)); 448f2e35a3aSmrg if (state == scanMods) { 449f2e35a3aSmrg if (len > 1 && data[first] == '~') { 450f2e35a3aSmrg len--; 451f2e35a3aSmrg first++; 452f2e35a3aSmrg } 453f2e35a3aSmrg if (len == 7 && !x_strncasecmp(data + first, "button", len - 1)) { 454f2e35a3aSmrg have_button = data[first + 6] - '0'; 455f2e35a3aSmrg } else if (len == 5 && !x_strncasecmp(data + first, "shift", len)) { 456f2e35a3aSmrg have_shift = True; 457f2e35a3aSmrg } 458f2e35a3aSmrg } else if (state == scanKey) { 459f2e35a3aSmrg if (!x_strncasecmp(data + first, "<buttonpress>", len) || 460f2e35a3aSmrg !x_strncasecmp(data + first, "<buttonrelease>", len)) { 461f2e35a3aSmrg want_button = True; 462f2e35a3aSmrg } else if (want_button) { 463f2e35a3aSmrg have_button = data[first] - '0'; 464f2e35a3aSmrg want_button = False; 465f2e35a3aSmrg } 466f2e35a3aSmrg } else if (state == scanFunc && have_button > 0) { 467f2e35a3aSmrg Cardinal n; 468f2e35a3aSmrg unsigned bmask = 1U << (have_button - 1); 469f2e35a3aSmrg for (n = 0; n < XtNumber(table); ++n) { 470f2e35a3aSmrg if (!x_strncasecmp(table[n], data + first, len)) { 471f2e35a3aSmrg TRACE(("...button %d: %s%s\n", 472f2e35a3aSmrg have_button, table[n], 473f2e35a3aSmrg have_shift ? " (disallow)" : "")); 474f2e35a3aSmrg if (have_shift) 475f2e35a3aSmrg disallow |= bmask; 476f2e35a3aSmrg else 477f2e35a3aSmrg allowed |= bmask; 478f2e35a3aSmrg break; 479f2e35a3aSmrg } 480f2e35a3aSmrg } 481f2e35a3aSmrg } 482f2e35a3aSmrg if (state2 == scanMods && state >= scanColon) { 483f2e35a3aSmrg have_button = -1; 484f2e35a3aSmrg want_button = False; 485f2e35a3aSmrg have_shift = False; 486f2e35a3aSmrg } 487f2e35a3aSmrg state = state2; 488f2e35a3aSmrg data = next; 489f2e35a3aSmrg } 490f2e35a3aSmrg XFree((char *) result); 491f2e35a3aSmrg xw->keyboard.shift_buttons = allowed & ~disallow; 492f2e35a3aSmrg#if OPT_TRACE 493f2e35a3aSmrg if (xw->keyboard.shift_buttons) { 494f2e35a3aSmrg int button = 0; 495f2e35a3aSmrg unsigned mask = xw->keyboard.shift_buttons; 496f2e35a3aSmrg TRACE(("...Buttons used for selection that can be overridden:")); 497f2e35a3aSmrg while (mask != 0) { 498f2e35a3aSmrg ++button; 499f2e35a3aSmrg if ((mask & 1) != 0) 500f2e35a3aSmrg TRACE((" %d", button)); 501f2e35a3aSmrg mask >>= 1; 502f2e35a3aSmrg } 503f2e35a3aSmrg TRACE(("\n")); 504f2e35a3aSmrg } else { 505f2e35a3aSmrg TRACE(("...No buttons used with selection can be overridden\n")); 506f2e35a3aSmrg } 507f2e35a3aSmrg#endif 508f2e35a3aSmrg } 509f2e35a3aSmrg XSetErrorHandler(save); 510f2e35a3aSmrg} 511f2e35a3aSmrg 512f2e35a3aSmrg/* 513f2e35a3aSmrg * Shift and control are regular X11 modifiers, but meta is not: 514f2e35a3aSmrg * + X10 (which had no xmodmap utility) had a meta mask, but X11 did not. 515f2e35a3aSmrg * + X11R1 introduced xmodmap, along with the current set of modifier masks. 516f2e35a3aSmrg * The meta key has been assumed to be mod1 since X11R1. 517f2e35a3aSmrg * The initial xterm logic in X11 was different, but gave the same result. 518f2e35a3aSmrg * + X11R2 modified xterm was to eliminate the X10 table which provided part of 519f2e35a3aSmrg * the meta logic. 520f2e35a3aSmrg * + X11R3 modified Xt, making Meta_L and Meta_R assignable via xmodmap, and 521f2e35a3aSmrg * equating Alt with Meta. Neither Alt/Meta are modifiers, but Alt is more 522f2e35a3aSmrg * likely to be on the keyboard. This release also added keymap tables for 523f2e35a3aSmrg * the server; Meta was used frequently in HP keymaps, which were the most 524f2e35a3aSmrg * extensive set of keymaps. 525f2e35a3aSmrg * + X11R4 mentions Meta in the ICCCM, stating that if Meta_L or Meta_R are 526f2e35a3aSmrg * found in the keysyms for a given modifier, that the client should use 527f2e35a3aSmrg * that modifier. 528f2e35a3aSmrg * 529f2e35a3aSmrg * This function follows the ICCCM, picking the modifier which contains the 530f2e35a3aSmrg * Meta_L/Meta_R keysyms (if available), falling back to the Alt_L/Alt_R 531f2e35a3aSmrg * (as per X11R3), and ultimately to mod1 (per X11R1). 532f2e35a3aSmrg */ 533f2e35a3aSmrgstatic unsigned 534f2e35a3aSmrgMetaMask(XtermWidget xw) 535f2e35a3aSmrg{ 536f2e35a3aSmrg#if OPT_NUM_LOCK 537f2e35a3aSmrg unsigned meta = xw->work.meta_mods; 538f2e35a3aSmrg if (meta == 0) 539f2e35a3aSmrg meta = xw->work.alt_mods; 540f2e35a3aSmrg if (meta == 0) 541f2e35a3aSmrg meta = Mod1Mask; 542f2e35a3aSmrg#else 543f2e35a3aSmrg unsigned meta = Mod1Mask; 544f2e35a3aSmrg (void) xw; 545f2e35a3aSmrg#endif 546f2e35a3aSmrg return meta; 547f2e35a3aSmrg} 548f2e35a3aSmrg 549f2e35a3aSmrg/* 550f2e35a3aSmrg * Returns a mask of the modifiers we may use for modifying the mouse protocol 551f2e35a3aSmrg * response strings. 552f2e35a3aSmrg */ 553f2e35a3aSmrgstatic unsigned 554f2e35a3aSmrgOurModifiers(XtermWidget xw) 555f2e35a3aSmrg{ 556f2e35a3aSmrg return (ShiftMask 557f2e35a3aSmrg | ControlMask 558f2e35a3aSmrg | MetaMask(xw)); 559f2e35a3aSmrg} 560f2e35a3aSmrg 561f2e35a3aSmrg/* 562f2e35a3aSmrg * The actual check for the shift-mask, to see if it should tell xterm to 563f2e35a3aSmrg * override mouse-protocol in favor of select/paste actions depends upon 564f2e35a3aSmrg * whether the shiftEscape resource is set to true/always vs false/never. 565f2e35a3aSmrg */ 566f2e35a3aSmrgstatic Boolean 567f2e35a3aSmrgShiftOverride(XtermWidget xw, unsigned state, int button) 568f2e35a3aSmrg{ 569f2e35a3aSmrg unsigned check = (state & OurModifiers(xw)); 570f2e35a3aSmrg Boolean result = False; 571f2e35a3aSmrg 572f2e35a3aSmrg if (check & ShiftMask) { 573f2e35a3aSmrg if (xw->keyboard.shift_escape == ssFalse || 574f2e35a3aSmrg xw->keyboard.shift_escape == ssNever) { 575f2e35a3aSmrg result = True; 576f2e35a3aSmrg } else if (xw->keyboard.shift_escape == ssTrue) { 577f2e35a3aSmrg /* 578f2e35a3aSmrg * Check if the button is one that we found does not directly use 579f2e35a3aSmrg * the shift-modifier in its bindings to select/copy actions. 580f2e35a3aSmrg */ 581f2e35a3aSmrg if (button > 0 && button <= MaxMouseBtn) { 582f2e35a3aSmrg if (xw->keyboard.shift_buttons & (1U << (button - 1))) { 583f2e35a3aSmrg result = True; 584f2e35a3aSmrg } 585f2e35a3aSmrg } else { 586f2e35a3aSmrg result = True; /* unlikely, and we don't care */ 587f2e35a3aSmrg } 588f2e35a3aSmrg } 589f2e35a3aSmrg } 590f2e35a3aSmrg TRACE2(("ShiftOverride ( %#x -> %#x ) %d\n", state, check, result)); 591f2e35a3aSmrg return result; 592f2e35a3aSmrg} 593f2e35a3aSmrg 594f2e35a3aSmrg/* 595f2e35a3aSmrg * Normally xterm treats the shift-modifier specially when the mouse protocol 596f2e35a3aSmrg * is active. The translations resource binds otherwise unmodified button 597f2e35a3aSmrg * for these mouse-related events: 598f2e35a3aSmrg * 599f2e35a3aSmrg * ~Meta <Btn1Down>:select-start() \n\ 600f2e35a3aSmrg * ~Meta <Btn1Motion>:select-extend() \n\ 601f2e35a3aSmrg * ~Ctrl ~Meta <Btn2Up>:insert-selection(SELECT, CUT_BUFFER0) \n\ 602f2e35a3aSmrg * ~Ctrl ~Meta <Btn3Down>:start-extend() \n\ 603f2e35a3aSmrg * ~Meta <Btn3Motion>:select-extend() \n\ 604f2e35a3aSmrg * <BtnUp>:select-end(SELECT, CUT_BUFFER0) \n\ 605f2e35a3aSmrg * 606f2e35a3aSmrg * There is no API in the X libraries which would tell us if a given mouse 607f2e35a3aSmrg * button is bound to one of these actions. These functions make the choice 608f2e35a3aSmrg * configurable. 609f2e35a3aSmrg */ 610f2e35a3aSmrgstatic Bool 611f2e35a3aSmrgInterpretButton(XtermWidget xw, XButtonEvent *event) 612f2e35a3aSmrg{ 613f2e35a3aSmrg Bool result = False; 614f2e35a3aSmrg 615f2e35a3aSmrg if (ShiftOverride(xw, event->state, (int) event->button)) { 616f2e35a3aSmrg TRACE(("...shift-button #%d overrides mouse-protocol\n", event->button)); 617f2e35a3aSmrg result = True; 618f2e35a3aSmrg } 619f2e35a3aSmrg return result; 620f2e35a3aSmrg} 621f2e35a3aSmrg 622f2e35a3aSmrg#define Button1Index 8 /* X.h should have done this */ 623f2e35a3aSmrg 624f2e35a3aSmrgstatic int 625f2e35a3aSmrgMotionButton(unsigned state) 626f2e35a3aSmrg{ 627f2e35a3aSmrg unsigned bmask = state >> Button1Index; 628f2e35a3aSmrg int result = 1; 629f2e35a3aSmrg 630f2e35a3aSmrg if (bmask != 0) { 631f2e35a3aSmrg while (!(bmask & 1)) { 632f2e35a3aSmrg ++result; 633f2e35a3aSmrg bmask >>= 1; 634f2e35a3aSmrg } 635f2e35a3aSmrg } 636f2e35a3aSmrg return result; 637f2e35a3aSmrg} 638f2e35a3aSmrg 639f2e35a3aSmrgstatic Bool 640f2e35a3aSmrgInterpretEvent(XtermWidget xw, XEvent *event) 641f2e35a3aSmrg{ 642f2e35a3aSmrg Bool result = False; /* if not a button, is motion */ 643f2e35a3aSmrg 644f2e35a3aSmrg if (IsBtnEvent(event)) { 645f2e35a3aSmrg result = InterpretButton(xw, (XButtonEvent *) event); 646f2e35a3aSmrg } else if (event->type == MotionNotify) { 647f2e35a3aSmrg unsigned state = event->xmotion.state; 648f2e35a3aSmrg int button = MotionButton(state); 649f2e35a3aSmrg 650f2e35a3aSmrg if (ShiftOverride(xw, state, button)) { 651f2e35a3aSmrg TRACE(("...shift-motion #%d (%d,%d) overrides mouse-protocol\n", 652f2e35a3aSmrg button, 653f2e35a3aSmrg event->xmotion.y, 654f2e35a3aSmrg event->xmotion.x)); 655f2e35a3aSmrg result = True; 656f2e35a3aSmrg } 657f2e35a3aSmrg } 658f2e35a3aSmrg return result; 659f2e35a3aSmrg} 660f2e35a3aSmrg 661f2e35a3aSmrg#define OverrideEvent(event) InterpretEvent(xw, event) 662f2e35a3aSmrg#define OverrideButton(event) InterpretButton(xw, event) 663f2e35a3aSmrg 664f2e35a3aSmrg/* 665f2e35a3aSmrg * Returns true if we handled the event here, and nothing more is needed. 666f2e35a3aSmrg */ 667492d43a5SmrgBool 668894e0ac8SmrgSendMousePosition(XtermWidget xw, XEvent *event) 669492d43a5Smrg{ 670492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 671492d43a5Smrg Bool result = False; 672d522f475Smrg 673913cc679Smrg switch (okSendMousePos(xw)) { 674492d43a5Smrg case MOUSE_OFF: 675492d43a5Smrg /* If send_mouse_pos mode isn't on, we shouldn't be here */ 676492d43a5Smrg break; 677d522f475Smrg 678d522f475Smrg case BTN_EVENT_MOUSE: 679d522f475Smrg case ANY_EVENT_MOUSE: 680f2e35a3aSmrg if (!OverrideEvent(event)) { 681492d43a5Smrg /* xterm extension for motion reporting. June 1998 */ 682492d43a5Smrg /* EditorButton() will distinguish between the modes */ 683492d43a5Smrg switch (event->type) { 684492d43a5Smrg case MotionNotify: 685492d43a5Smrg my_event->button = 0; 686492d43a5Smrg /* FALLTHRU */ 687492d43a5Smrg case ButtonPress: 688492d43a5Smrg /* FALLTHRU */ 689492d43a5Smrg case ButtonRelease: 690492d43a5Smrg EditorButton(xw, my_event); 691492d43a5Smrg result = True; 692492d43a5Smrg break; 6932eaa94a1Schristos } 694d522f475Smrg } 695492d43a5Smrg break; 696d522f475Smrg 697913cc679Smrg case X10_MOUSE: /* X10 compatibility sequences */ 698492d43a5Smrg if (IsBtnEvent(event)) { 699f2e35a3aSmrg if (!OverrideButton(my_event)) { 700913cc679Smrg if (my_event->type == ButtonPress) 701492d43a5Smrg EditorButton(xw, my_event); 702913cc679Smrg result = True; 703913cc679Smrg } 704913cc679Smrg } 705913cc679Smrg break; 706492d43a5Smrg 707913cc679Smrg case VT200_HIGHLIGHT_MOUSE: /* DEC vt200 hilite tracking */ 708913cc679Smrg if (IsBtnEvent(event)) { 709f2e35a3aSmrg if (!OverrideButton(my_event)) { 710f2e35a3aSmrg if (my_event->type == ButtonPress && 711f2e35a3aSmrg my_event->button == Button1) { 712f2e35a3aSmrg TrackDown(xw, my_event); 713f2e35a3aSmrg } else { 714f2e35a3aSmrg EditorButton(xw, my_event); 715f2e35a3aSmrg } 716913cc679Smrg result = True; 717913cc679Smrg } 718913cc679Smrg } 719913cc679Smrg break; 720492d43a5Smrg 721913cc679Smrg case VT200_MOUSE: /* DEC vt200 compatible */ 722913cc679Smrg if (IsBtnEvent(event)) { 723f2e35a3aSmrg if (!OverrideButton(my_event)) { 724913cc679Smrg EditorButton(xw, my_event); 725913cc679Smrg result = True; 726913cc679Smrg } 727913cc679Smrg } 728913cc679Smrg break; 729913cc679Smrg 730913cc679Smrg case DEC_LOCATOR: 731492d43a5Smrg#if OPT_DEC_LOCATOR 732f2e35a3aSmrg if (IsBtnEvent(event) || event->type == MotionNotify) { 733913cc679Smrg result = SendLocatorPosition(xw, my_event); 734492d43a5Smrg } 735f2e35a3aSmrg#endif /* OPT_DEC_LOCATOR */ 736913cc679Smrg break; 737d522f475Smrg } 738492d43a5Smrg return result; 739d522f475Smrg} 740d522f475Smrg 741d522f475Smrg#if OPT_DEC_LOCATOR 742d522f475Smrg 743d522f475Smrg#define LocatorCoords( row, col, x, y, oor ) \ 744d522f475Smrg if( screen->locator_pixels ) { \ 745d522f475Smrg (oor)=False; (row) = (y)+1; (col) = (x)+1; \ 746d522f475Smrg /* Limit to screen dimensions */ \ 747d522f475Smrg if ((row) < 1) (row) = 1,(oor)=True; \ 748d522f475Smrg else if ((row) > screen->border*2+Height(screen)) \ 749d522f475Smrg (row) = screen->border*2+Height(screen),(oor)=True; \ 750d522f475Smrg if ((col) < 1) (col) = 1,(oor)=True; \ 751d522f475Smrg else if ((col) > OriginX(screen)*2+Width(screen)) \ 752d522f475Smrg (col) = OriginX(screen)*2+Width(screen),(oor)=True; \ 753d522f475Smrg } else { \ 754d522f475Smrg (oor)=False; \ 755d522f475Smrg /* Compute character position of mouse pointer */ \ 756d522f475Smrg (row) = ((y) - screen->border) / FontHeight(screen); \ 757d522f475Smrg (col) = ((x) - OriginX(screen)) / FontWidth(screen); \ 758d522f475Smrg /* Limit to screen dimensions */ \ 759d522f475Smrg if ((row) < 0) (row) = 0,(oor)=True; \ 760d522f475Smrg else if ((row) > screen->max_row) \ 761d522f475Smrg (row) = screen->max_row,(oor)=True; \ 762d522f475Smrg if ((col) < 0) (col) = 0,(oor)=True; \ 763d522f475Smrg else if ((col) > screen->max_col) \ 764d522f475Smrg (col) = screen->max_col,(oor)=True; \ 765d522f475Smrg (row)++; (col)++; \ 766d522f475Smrg } 767d522f475Smrg 768d522f475Smrgstatic Bool 769894e0ac8SmrgSendLocatorPosition(XtermWidget xw, XButtonEvent *event) 770d522f475Smrg{ 771d522f475Smrg ANSI reply; 772956cc18dSsnj TScreen *screen = TScreenOf(xw); 773d522f475Smrg int row, col; 774d522f475Smrg Bool oor; 775d522f475Smrg int button; 7762eaa94a1Schristos unsigned state; 777d522f475Smrg 778d522f475Smrg /* Make sure the event is an appropriate type */ 779f2e35a3aSmrg if (IsBtnEvent(event)) { 780f2e35a3aSmrg if (OverrideButton(event)) 781f2e35a3aSmrg return (False); 782f2e35a3aSmrg } else { 783f2e35a3aSmrg if (!screen->loc_filter) 784f2e35a3aSmrg return (False); 785f2e35a3aSmrg } 786d522f475Smrg 787d522f475Smrg if ((event->type == ButtonPress && 788d522f475Smrg !(screen->locator_events & LOC_BTNS_DN)) || 789d522f475Smrg (event->type == ButtonRelease && 790d522f475Smrg !(screen->locator_events & LOC_BTNS_UP))) 791d522f475Smrg return (True); 792d522f475Smrg 793d522f475Smrg if (event->type == MotionNotify) { 794d522f475Smrg CheckLocatorPosition(xw, event); 795d522f475Smrg return (True); 796d522f475Smrg } 797d522f475Smrg 798d522f475Smrg /* get button # */ 799492d43a5Smrg button = (int) event->button - 1; 800d522f475Smrg 801492d43a5Smrg LocatorCoords(row, col, event->x, event->y, oor); 802d522f475Smrg 803d522f475Smrg /* 804d522f475Smrg * DECterm mouse: 805d522f475Smrg * 806d522f475Smrg * ESCAPE '[' event ; mask ; row ; column '&' 'w' 807d522f475Smrg */ 808d522f475Smrg memset(&reply, 0, sizeof(reply)); 809d522f475Smrg reply.a_type = ANSI_CSI; 810d522f475Smrg 811d522f475Smrg if (oor) { 812d522f475Smrg reply.a_nparam = 1; 813d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 814d522f475Smrg reply.a_inters = '&'; 815d522f475Smrg reply.a_final = 'w'; 816d522f475Smrg unparseseq(xw, &reply); 817d522f475Smrg 818d522f475Smrg if (screen->locator_reset) { 819d522f475Smrg MotionOff(screen, xw); 820d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 821d522f475Smrg } 822d522f475Smrg return (True); 823d522f475Smrg } 824d522f475Smrg 825d522f475Smrg /* 826d522f475Smrg * event: 827d522f475Smrg * 1 no buttons 828d522f475Smrg * 2 left button down 829d522f475Smrg * 3 left button up 830d522f475Smrg * 4 middle button down 831d522f475Smrg * 5 middle button up 832d522f475Smrg * 6 right button down 833d522f475Smrg * 7 right button up 834d522f475Smrg * 8 M4 down 835d522f475Smrg * 9 M4 up 836d522f475Smrg */ 837d522f475Smrg reply.a_nparam = 4; 838d522f475Smrg switch (event->type) { 839d522f475Smrg case ButtonPress: 8402eaa94a1Schristos reply.a_param[0] = (ParmType) (2 + (button << 1)); 841d522f475Smrg break; 842d522f475Smrg case ButtonRelease: 8432eaa94a1Schristos reply.a_param[0] = (ParmType) (3 + (button << 1)); 844d522f475Smrg break; 845d522f475Smrg default: 846d522f475Smrg return (True); 847d522f475Smrg } 848d522f475Smrg /* 849d522f475Smrg * mask: 850913cc679Smrg * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 851913cc679Smrg * M4 down left down middle down right down 852d522f475Smrg * 853d522f475Smrg * Notice that Button1 (left) and Button3 (right) are swapped in the mask. 854d522f475Smrg * Also, mask should be the state after the button press/release, 855d522f475Smrg * X provides the state not including the button press/release. 856d522f475Smrg */ 857492d43a5Smrg state = (event->state 858d522f475Smrg & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8; 8594e40088cSchristos /* update mask to "after" state */ 86020d2c4d2Smrg state ^= ((unsigned) (1 << button)); 8614e40088cSchristos /* swap Button1 & Button3 */ 862956cc18dSsnj state = ((state & (unsigned) ~(4 | 1)) 863956cc18dSsnj | ((state & 1) ? 4 : 0) 864956cc18dSsnj | ((state & 4) ? 1 : 0)); 865d522f475Smrg 8662eaa94a1Schristos reply.a_param[1] = (ParmType) state; 8672eaa94a1Schristos reply.a_param[2] = (ParmType) row; 8682eaa94a1Schristos reply.a_param[3] = (ParmType) col; 869d522f475Smrg reply.a_inters = '&'; 870d522f475Smrg reply.a_final = 'w'; 871d522f475Smrg 872d522f475Smrg unparseseq(xw, &reply); 873d522f475Smrg 874d522f475Smrg if (screen->locator_reset) { 875d522f475Smrg MotionOff(screen, xw); 876d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 877d522f475Smrg } 878d522f475Smrg 879d522f475Smrg /* 880913cc679Smrg * DECterm turns the Locator off if a button is pressed while a filter 881913cc679Smrg * rectangle is active. This might be a bug, but I don't know, so I'll 882913cc679Smrg * emulate it anyway. 883d522f475Smrg */ 884d522f475Smrg if (screen->loc_filter) { 885d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 886d522f475Smrg screen->loc_filter = False; 887d522f475Smrg screen->locator_events = 0; 888d522f475Smrg MotionOff(screen, xw); 889d522f475Smrg } 890d522f475Smrg 891d522f475Smrg return (True); 892d522f475Smrg} 893d522f475Smrg 894d522f475Smrg/* 895d522f475Smrg * mask: 896d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 897d522f475Smrg * M4 down left down middle down right down 898d522f475Smrg * 899d522f475Smrg * Button1 (left) and Button3 (right) are swapped in the mask relative to X. 900d522f475Smrg */ 901d522f475Smrg#define ButtonState(state, mask) \ 902913cc679Smrg{ int stemp = (int) (((mask) & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8); \ 903d522f475Smrg /* swap Button1 & Button3 */ \ 904913cc679Smrg (state) = (stemp & ~(4|1)) | ((stemp & 1) ? 4 : 0) | ((stemp & 4) ? 1 : 0); \ 905d522f475Smrg} 906d522f475Smrg 907d522f475Smrgvoid 908d522f475SmrgGetLocatorPosition(XtermWidget xw) 909d522f475Smrg{ 910d522f475Smrg ANSI reply; 911956cc18dSsnj TScreen *screen = TScreenOf(xw); 912d522f475Smrg Window root, child; 913d522f475Smrg int rx, ry, x, y; 914f2e35a3aSmrg unsigned int mask = 0; 915d522f475Smrg int row = 0, col = 0; 916d522f475Smrg Bool oor = False; 917d522f475Smrg Bool ret = False; 918d522f475Smrg int state; 919d522f475Smrg 920d522f475Smrg /* 921913cc679Smrg * DECterm turns the Locator off if the position is requested while a 922913cc679Smrg * filter rectangle is active. This might be a bug, but I don't know, so 923913cc679Smrg * I'll emulate it anyways. 924d522f475Smrg */ 925d522f475Smrg if (screen->loc_filter) { 926d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 927d522f475Smrg screen->loc_filter = False; 928d522f475Smrg screen->locator_events = 0; 929d522f475Smrg MotionOff(screen, xw); 930d522f475Smrg } 931d522f475Smrg 932d522f475Smrg memset(&reply, 0, sizeof(reply)); 933d522f475Smrg reply.a_type = ANSI_CSI; 934d522f475Smrg 935913cc679Smrg if (okSendMousePos(xw) == DEC_LOCATOR) { 936d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), &root, 937d522f475Smrg &child, &rx, &ry, &x, &y, &mask); 938d522f475Smrg if (ret) { 939d522f475Smrg LocatorCoords(row, col, x, y, oor); 940d522f475Smrg } 941d522f475Smrg } 942d522f475Smrg if (ret == False || oor) { 943d522f475Smrg reply.a_nparam = 1; 944d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 945d522f475Smrg reply.a_inters = '&'; 946d522f475Smrg reply.a_final = 'w'; 947d522f475Smrg unparseseq(xw, &reply); 948d522f475Smrg 949d522f475Smrg if (screen->locator_reset) { 950d522f475Smrg MotionOff(screen, xw); 951d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 952d522f475Smrg } 953d522f475Smrg return; 954d522f475Smrg } 955d522f475Smrg 956d522f475Smrg ButtonState(state, mask); 957d522f475Smrg 958d522f475Smrg reply.a_nparam = 4; 959d522f475Smrg reply.a_param[0] = 1; /* Event - 1 = response to locator request */ 9602eaa94a1Schristos reply.a_param[1] = (ParmType) state; 9612eaa94a1Schristos reply.a_param[2] = (ParmType) row; 9622eaa94a1Schristos reply.a_param[3] = (ParmType) col; 963d522f475Smrg reply.a_inters = '&'; 964d522f475Smrg reply.a_final = 'w'; 965d522f475Smrg unparseseq(xw, &reply); 966d522f475Smrg 967d522f475Smrg if (screen->locator_reset) { 968d522f475Smrg MotionOff(screen, xw); 969d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 970d522f475Smrg } 971d522f475Smrg} 972d522f475Smrg 973d522f475Smrgvoid 974d522f475SmrgInitLocatorFilter(XtermWidget xw) 975d522f475Smrg{ 976d522f475Smrg ANSI reply; 977956cc18dSsnj TScreen *screen = TScreenOf(xw); 978d522f475Smrg Window root, child; 979d522f475Smrg int rx, ry, x, y; 980d522f475Smrg unsigned int mask; 981d522f475Smrg int row = 0, col = 0; 982d522f475Smrg Bool oor = 0; 983d522f475Smrg Bool ret; 984d522f475Smrg 985d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), 986d522f475Smrg &root, &child, &rx, &ry, &x, &y, &mask); 987d522f475Smrg if (ret) { 988d522f475Smrg LocatorCoords(row, col, x, y, oor); 989d522f475Smrg } 990d522f475Smrg if (ret == False || oor) { 991d522f475Smrg /* Locator is unavailable */ 992d522f475Smrg 993d522f475Smrg if (screen->loc_filter_top != LOC_FILTER_POS || 994d522f475Smrg screen->loc_filter_left != LOC_FILTER_POS || 995d522f475Smrg screen->loc_filter_bottom != LOC_FILTER_POS || 996d522f475Smrg screen->loc_filter_right != LOC_FILTER_POS) { 997d522f475Smrg /* 998d522f475Smrg * If any explicit coordinates were received, 999d522f475Smrg * report immediately with no coordinates. 1000d522f475Smrg */ 1001d522f475Smrg memset(&reply, 0, sizeof(reply)); 1002d522f475Smrg reply.a_type = ANSI_CSI; 1003d522f475Smrg reply.a_nparam = 1; 1004d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 1005d522f475Smrg reply.a_inters = '&'; 1006d522f475Smrg reply.a_final = 'w'; 1007d522f475Smrg unparseseq(xw, &reply); 1008d522f475Smrg 1009d522f475Smrg if (screen->locator_reset) { 1010d522f475Smrg MotionOff(screen, xw); 1011d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 1012d522f475Smrg } 1013d522f475Smrg } else { 1014d522f475Smrg /* 1015d522f475Smrg * No explicit coordinates were received, and the pointer is 1016d522f475Smrg * unavailable. Report when the pointer re-enters the window. 1017d522f475Smrg */ 1018d522f475Smrg screen->loc_filter = True; 1019d522f475Smrg MotionOn(screen, xw); 1020d522f475Smrg } 1021d522f475Smrg return; 1022d522f475Smrg } 1023d522f475Smrg 1024d522f475Smrg /* 1025d522f475Smrg * Adjust rectangle coordinates: 1026d522f475Smrg * 1. Replace "LOC_FILTER_POS" with current coordinates 1027d522f475Smrg * 2. Limit coordinates to screen size 1028d522f475Smrg * 3. make sure top and left are less than bottom and right, resp. 1029d522f475Smrg */ 1030d522f475Smrg if (screen->locator_pixels) { 1031d522f475Smrg rx = OriginX(screen) * 2 + Width(screen); 1032d522f475Smrg ry = screen->border * 2 + Height(screen); 1033d522f475Smrg } else { 1034d522f475Smrg rx = screen->max_col; 1035d522f475Smrg ry = screen->max_row; 1036d522f475Smrg } 1037d522f475Smrg 1038d522f475Smrg#define Adjust( coord, def, max ) \ 1039d522f475Smrg if( (coord) == LOC_FILTER_POS ) (coord) = (def); \ 1040d522f475Smrg else if ((coord) < 1) (coord) = 1; \ 1041d522f475Smrg else if ((coord) > (max)) (coord) = (max) 1042d522f475Smrg 1043d522f475Smrg Adjust(screen->loc_filter_top, row, ry); 1044d522f475Smrg Adjust(screen->loc_filter_left, col, rx); 1045d522f475Smrg Adjust(screen->loc_filter_bottom, row, ry); 1046d522f475Smrg Adjust(screen->loc_filter_right, col, rx); 1047d522f475Smrg 1048d522f475Smrg if (screen->loc_filter_top > screen->loc_filter_bottom) { 1049d522f475Smrg ry = screen->loc_filter_top; 1050d522f475Smrg screen->loc_filter_top = screen->loc_filter_bottom; 1051d522f475Smrg screen->loc_filter_bottom = ry; 1052d522f475Smrg } 1053d522f475Smrg 1054d522f475Smrg if (screen->loc_filter_left > screen->loc_filter_right) { 1055d522f475Smrg rx = screen->loc_filter_left; 1056d522f475Smrg screen->loc_filter_left = screen->loc_filter_right; 1057d522f475Smrg screen->loc_filter_right = rx; 1058d522f475Smrg } 1059d522f475Smrg 1060d522f475Smrg if ((col < screen->loc_filter_left) || 1061d522f475Smrg (col > screen->loc_filter_right) || 1062d522f475Smrg (row < screen->loc_filter_top) || 1063d522f475Smrg (row > screen->loc_filter_bottom)) { 10642e4f8982Smrg int state; 10652e4f8982Smrg 1066d522f475Smrg /* Pointer is already outside the rectangle - report immediately */ 1067d522f475Smrg ButtonState(state, mask); 1068d522f475Smrg 1069d522f475Smrg memset(&reply, 0, sizeof(reply)); 1070d522f475Smrg reply.a_type = ANSI_CSI; 1071d522f475Smrg reply.a_nparam = 4; 1072d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 10732eaa94a1Schristos reply.a_param[1] = (ParmType) state; 10742eaa94a1Schristos reply.a_param[2] = (ParmType) row; 10752eaa94a1Schristos reply.a_param[3] = (ParmType) col; 1076d522f475Smrg reply.a_inters = '&'; 1077d522f475Smrg reply.a_final = 'w'; 1078d522f475Smrg unparseseq(xw, &reply); 1079d522f475Smrg 1080d522f475Smrg if (screen->locator_reset) { 1081d522f475Smrg MotionOff(screen, xw); 1082d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 1083d522f475Smrg } 1084d522f475Smrg return; 1085d522f475Smrg } 1086d522f475Smrg 1087d522f475Smrg /* 1088d522f475Smrg * Rectangle is set up. Allow pointer tracking 1089d522f475Smrg * to detect if the mouse leaves the rectangle. 1090d522f475Smrg */ 1091d522f475Smrg screen->loc_filter = True; 1092d522f475Smrg MotionOn(screen, xw); 1093d522f475Smrg} 1094d522f475Smrg 1095d522f475Smrgstatic void 1096894e0ac8SmrgCheckLocatorPosition(XtermWidget xw, XButtonEvent *event) 1097d522f475Smrg{ 1098d522f475Smrg ANSI reply; 1099956cc18dSsnj TScreen *screen = TScreenOf(xw); 1100d522f475Smrg int row, col; 1101d522f475Smrg Bool oor; 1102d522f475Smrg 1103492d43a5Smrg LocatorCoords(row, col, event->x, event->y, oor); 1104d522f475Smrg 1105d522f475Smrg /* 1106d522f475Smrg * Send report if the pointer left the filter rectangle, if 1107d522f475Smrg * the pointer left the window, or if the filter rectangle 1108d522f475Smrg * had no coordinates and the pointer re-entered the window. 1109d522f475Smrg */ 1110d522f475Smrg if (oor || (screen->loc_filter_top == LOC_FILTER_POS) || 1111d522f475Smrg (col < screen->loc_filter_left) || 1112d522f475Smrg (col > screen->loc_filter_right) || 1113d522f475Smrg (row < screen->loc_filter_top) || 1114d522f475Smrg (row > screen->loc_filter_bottom)) { 1115d522f475Smrg /* Filter triggered - disable it */ 1116d522f475Smrg screen->loc_filter = False; 1117d522f475Smrg MotionOff(screen, xw); 1118d522f475Smrg 1119d522f475Smrg memset(&reply, 0, sizeof(reply)); 1120d522f475Smrg reply.a_type = ANSI_CSI; 1121d522f475Smrg if (oor) { 1122d522f475Smrg reply.a_nparam = 1; 1123d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 1124d522f475Smrg } else { 11252e4f8982Smrg int state; 11262e4f8982Smrg 1127492d43a5Smrg ButtonState(state, event->state); 1128d522f475Smrg 1129d522f475Smrg reply.a_nparam = 4; 1130d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 11312eaa94a1Schristos reply.a_param[1] = (ParmType) state; 11322eaa94a1Schristos reply.a_param[2] = (ParmType) row; 11332eaa94a1Schristos reply.a_param[3] = (ParmType) col; 1134d522f475Smrg } 1135d522f475Smrg 1136d522f475Smrg reply.a_inters = '&'; 1137d522f475Smrg reply.a_final = 'w'; 1138d522f475Smrg unparseseq(xw, &reply); 1139d522f475Smrg 1140d522f475Smrg if (screen->locator_reset) { 1141d522f475Smrg MotionOff(screen, xw); 1142d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 1143d522f475Smrg } 1144d522f475Smrg } 1145d522f475Smrg} 1146d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 1147d522f475Smrg 1148d522f475Smrg#if OPT_READLINE 1149d522f475Smrgstatic int 1150913cc679SmrgisClick1_clean(XtermWidget xw, XButtonEvent *event) 1151d522f475Smrg{ 1152913cc679Smrg TScreen *screen = TScreenOf(xw); 1153d522f475Smrg int delta; 1154d522f475Smrg 1155d522f475Smrg /* Disable on Shift-Click-1, including the application-mouse modes */ 1156f2e35a3aSmrg if (OverrideButton(event) 1157f2e35a3aSmrg || (okSendMousePos(xw) != MOUSE_OFF) 1158f2e35a3aSmrg || ExtendingSelection) /* Was moved */ 1159d522f475Smrg return 0; 1160d522f475Smrg 1161d522f475Smrg if (event->type != ButtonRelease) 1162d522f475Smrg return 0; 1163d522f475Smrg 1164d522f475Smrg if (lastButtonDownTime == (Time) 0) { 1165d522f475Smrg /* first time or once in a blue moon */ 1166d522f475Smrg delta = screen->multiClickTime + 1; 1167492d43a5Smrg } else if (event->time > lastButtonDownTime) { 1168d522f475Smrg /* most of the time */ 1169492d43a5Smrg delta = (int) (event->time - lastButtonDownTime); 1170d522f475Smrg } else { 1171d522f475Smrg /* time has rolled over since lastButtonUpTime */ 1172492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->time); 1173d522f475Smrg } 1174d522f475Smrg 1175d522f475Smrg return delta <= screen->multiClickTime; 1176d522f475Smrg} 1177d522f475Smrg 1178d522f475Smrgstatic int 1179f2e35a3aSmrgisDoubleClick3(XtermWidget xw, TScreen *screen, XButtonEvent *event) 1180d522f475Smrg{ 1181d522f475Smrg int delta; 1182d522f475Smrg 1183d522f475Smrg if (event->type != ButtonRelease 1184f2e35a3aSmrg || OverrideButton(event) 1185492d43a5Smrg || event->button != Button3) { 1186d522f475Smrg lastButton3UpTime = 0; /* Disable the cached info */ 1187d522f475Smrg return 0; 1188d522f475Smrg } 1189d522f475Smrg /* Process Btn3Release. */ 1190d522f475Smrg if (lastButton3DoubleDownTime == (Time) 0) { 1191d522f475Smrg /* No previous click or once in a blue moon */ 1192d522f475Smrg delta = screen->multiClickTime + 1; 1193492d43a5Smrg } else if (event->time > lastButton3DoubleDownTime) { 1194d522f475Smrg /* most of the time */ 1195492d43a5Smrg delta = (int) (event->time - lastButton3DoubleDownTime); 1196d522f475Smrg } else { 1197d522f475Smrg /* time has rolled over since lastButton3DoubleDownTime */ 1198492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButton3DoubleDownTime) + event->time); 1199d522f475Smrg } 1200d522f475Smrg if (delta <= screen->multiClickTime) { 1201d522f475Smrg /* Double click */ 1202d522f475Smrg CELL cell; 1203d522f475Smrg 1204d522f475Smrg /* Cannot check ExtendingSelection, since mouse-3 always sets it */ 1205492d43a5Smrg PointToCELL(screen, event->y, event->x, &cell); 1206d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 1207d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the third click */ 1208d522f475Smrg return 1; 1209d522f475Smrg } 1210d522f475Smrg } 1211d522f475Smrg /* Not a double click, memorize for future check. */ 1212492d43a5Smrg lastButton3UpTime = event->time; 1213492d43a5Smrg PointToCELL(screen, event->y, event->x, &lastButton3); 1214d522f475Smrg return 0; 1215d522f475Smrg} 1216d522f475Smrg 1217d522f475Smrgstatic int 1218f2e35a3aSmrgCheckSecondPress3(XtermWidget xw, TScreen *screen, XEvent *event) 1219d522f475Smrg{ 1220d522f475Smrg int delta; 1221d522f475Smrg 1222d522f475Smrg if (event->type != ButtonPress 1223f2e35a3aSmrg || OverrideEvent(event) 1224d522f475Smrg || event->xbutton.button != Button3) { 1225d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the cached info */ 1226d522f475Smrg return 0; 1227d522f475Smrg } 1228d522f475Smrg /* Process Btn3Press. */ 1229d522f475Smrg if (lastButton3UpTime == (Time) 0) { 1230d522f475Smrg /* No previous click or once in a blue moon */ 1231d522f475Smrg delta = screen->multiClickTime + 1; 1232d522f475Smrg } else if (event->xbutton.time > lastButton3UpTime) { 1233d522f475Smrg /* most of the time */ 12342eaa94a1Schristos delta = (int) (event->xbutton.time - lastButton3UpTime); 1235d522f475Smrg } else { 1236d522f475Smrg /* time has rolled over since lastButton3UpTime */ 12372eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButton3UpTime) + event->xbutton.time); 1238d522f475Smrg } 1239d522f475Smrg if (delta <= screen->multiClickTime) { 1240d522f475Smrg CELL cell; 1241d522f475Smrg 1242d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 1243d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 1244d522f475Smrg /* A candidate for a double-click */ 1245d522f475Smrg lastButton3DoubleDownTime = event->xbutton.time; 1246d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &lastButton3); 1247d522f475Smrg return 1; 1248d522f475Smrg } 1249d522f475Smrg lastButton3UpTime = 0; /* Disable the info about the previous click */ 1250d522f475Smrg } 1251d522f475Smrg /* Either too long, or moved, disable. */ 1252d522f475Smrg lastButton3DoubleDownTime = 0; 1253d522f475Smrg return 0; 1254d522f475Smrg} 1255d522f475Smrg 1256d522f475Smrgstatic int 1257e0a2b6dfSmrgrowOnCurrentLine(TScreen *screen, 1258d522f475Smrg int line, 1259d522f475Smrg int *deltap) /* must be XButtonEvent */ 1260d522f475Smrg{ 1261956cc18dSsnj int result = 1; 1262d522f475Smrg 1263d522f475Smrg *deltap = 0; 12642e4f8982Smrg 1265956cc18dSsnj if (line != screen->cur_row) { 12662e4f8982Smrg int l1, l2; 12672e4f8982Smrg 1268f2e35a3aSmrg if (line < screen->cur_row) { 1269f2e35a3aSmrg l1 = line; 1270f2e35a3aSmrg l2 = screen->cur_row; 1271f2e35a3aSmrg } else { 1272f2e35a3aSmrg l2 = line; 1273f2e35a3aSmrg l1 = screen->cur_row; 1274f2e35a3aSmrg } 1275956cc18dSsnj l1--; 1276956cc18dSsnj while (++l1 < l2) { 1277956cc18dSsnj LineData *ld = GET_LINEDATA(screen, l1); 1278956cc18dSsnj if (!LineTstWrapped(ld)) { 1279956cc18dSsnj result = 0; 1280956cc18dSsnj break; 1281956cc18dSsnj } 1282956cc18dSsnj } 1283956cc18dSsnj if (result) { 1284956cc18dSsnj /* Everything is on one "wrapped line" now */ 1285956cc18dSsnj *deltap = line - screen->cur_row; 1286956cc18dSsnj } 1287956cc18dSsnj } 1288956cc18dSsnj return result; 1289d522f475Smrg} 1290d522f475Smrg 1291d522f475Smrgstatic int 1292894e0ac8SmrgeventRow(TScreen *screen, XEvent *event) /* must be XButtonEvent */ 1293d522f475Smrg{ 1294d522f475Smrg return (event->xbutton.y - screen->border) / FontHeight(screen); 1295d522f475Smrg} 1296d522f475Smrg 1297d522f475Smrgstatic int 1298894e0ac8SmrgeventColBetween(TScreen *screen, XEvent *event) /* must be XButtonEvent */ 1299d522f475Smrg{ 1300d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 1301d522f475Smrg return ((event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) / 2) 1302d522f475Smrg / FontWidth(screen)); 1303d522f475Smrg} 1304d522f475Smrg 1305d522f475Smrgstatic int 13065307cd1aSmrgReadLineMovePoint(XtermWidget xw, int col, int ldelta) 1307d522f475Smrg{ 13085307cd1aSmrg TScreen *screen = TScreenOf(xw); 1309d522f475Smrg Char line[6]; 1310d522f475Smrg unsigned count = 0; 1311d522f475Smrg 1312d522f475Smrg col += ldelta * MaxCols(screen) - screen->cur_col; 1313d522f475Smrg if (col == 0) 1314d522f475Smrg return 0; 1315d522f475Smrg if (screen->control_eight_bits) { 1316d522f475Smrg line[count++] = ANSI_CSI; 1317d522f475Smrg } else { 1318d522f475Smrg line[count++] = ANSI_ESC; 13195307cd1aSmrg line[count++] = (xw->keyboard.flags & MODE_DECCKM) ? 'O' : '['; 1320d522f475Smrg } 132120d2c4d2Smrg line[count] = CharOf(col > 0 ? 'C' : 'D'); 1322d522f475Smrg if (col < 0) 1323d522f475Smrg col = -col; 1324d522f475Smrg while (col--) 13255307cd1aSmrg v_write(screen->respond, line, (size_t) 3); 1326d522f475Smrg return 1; 1327d522f475Smrg} 1328d522f475Smrg 1329d522f475Smrgstatic int 1330e0a2b6dfSmrgReadLineDelete(TScreen *screen, CELL *cell1, CELL *cell2) 1331d522f475Smrg{ 1332d522f475Smrg int del; 13335307cd1aSmrg Char erases[2]; 13345307cd1aSmrg 13355307cd1aSmrg erases[0] = (Char) get_tty_erase(screen->respond, XTERM_ERASE, "pty"); 13365307cd1aSmrg erases[1] = 0; 1337d522f475Smrg 1338d522f475Smrg del = (cell2->col - cell1->col) + ((cell2->row - cell1->row) * MaxCols(screen)); 1339d522f475Smrg if (del <= 0) /* Just in case... */ 1340d522f475Smrg return 0; 1341d522f475Smrg while (del--) 13425307cd1aSmrg v_write(screen->respond, erases, (size_t) 1); 1343d522f475Smrg return 1; 1344d522f475Smrg} 1345492d43a5Smrg 1346492d43a5Smrgstatic void 1347913cc679SmrgreadlineExtend(XtermWidget xw, XEvent *event) 1348492d43a5Smrg{ 1349913cc679Smrg TScreen *screen = TScreenOf(xw); 1350492d43a5Smrg int ldelta1, ldelta2; 1351492d43a5Smrg 1352492d43a5Smrg if (IsBtnEvent(event)) { 1353492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 1354913cc679Smrg if (isClick1_clean(xw, my_event) 1355492d43a5Smrg && SCREEN_FLAG(screen, click1_moves) 1356492d43a5Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta1)) { 13575307cd1aSmrg ReadLineMovePoint(xw, eventColBetween(screen, event), ldelta1); 1358492d43a5Smrg } 1359f2e35a3aSmrg if (isDoubleClick3(xw, screen, my_event) 1360492d43a5Smrg && SCREEN_FLAG(screen, dclick3_deletes) 1361492d43a5Smrg && rowOnCurrentLine(screen, screen->startSel.row, &ldelta1) 1362492d43a5Smrg && rowOnCurrentLine(screen, screen->endSel.row, &ldelta2)) { 13635307cd1aSmrg ReadLineMovePoint(xw, screen->endSel.col, ldelta2); 1364492d43a5Smrg ReadLineDelete(screen, &screen->startSel, &(screen->endSel)); 1365492d43a5Smrg } 1366492d43a5Smrg } 1367492d43a5Smrg} 1368d522f475Smrg#endif /* OPT_READLINE */ 1369d522f475Smrg 1370d522f475Smrg/* ^XM-G<line+' '><col+' '> */ 1371d522f475Smrgvoid 1372d522f475SmrgDiredButton(Widget w, 1373894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1374e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 1375d522f475Smrg Cardinal *num_params GCC_UNUSED) 1376d522f475Smrg{ 1377956cc18dSsnj XtermWidget xw; 1378956cc18dSsnj 13795104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 1380956cc18dSsnj TScreen *screen = TScreenOf(xw); 1381d522f475Smrg 1382492d43a5Smrg if (IsBtnEvent(event) 13832eaa94a1Schristos && (event->xbutton.y >= screen->border) 13842eaa94a1Schristos && (event->xbutton.x >= OriginX(screen))) { 13852e4f8982Smrg Char Line[6]; 13862e4f8982Smrg unsigned line, col; 13872e4f8982Smrg 138820d2c4d2Smrg line = (unsigned) ((event->xbutton.y - screen->border) 138920d2c4d2Smrg / FontHeight(screen)); 139020d2c4d2Smrg col = (unsigned) ((event->xbutton.x - OriginX(screen)) 139120d2c4d2Smrg / FontWidth(screen)); 1392d522f475Smrg Line[0] = CONTROL('X'); 1393d522f475Smrg Line[1] = ANSI_ESC; 1394d522f475Smrg Line[2] = 'G'; 13952eaa94a1Schristos Line[3] = CharOf(' ' + col); 13962eaa94a1Schristos Line[4] = CharOf(' ' + line); 13975307cd1aSmrg v_write(screen->respond, Line, (size_t) 5); 1398d522f475Smrg } 1399d522f475Smrg } 1400d522f475Smrg} 1401d522f475Smrg 1402d522f475Smrg#if OPT_READLINE 1403d522f475Smrgvoid 1404d522f475SmrgReadLineButton(Widget w, 1405894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1406f2e35a3aSmrg String *params, /* selections */ 1407f2e35a3aSmrg Cardinal *num_params) 1408d522f475Smrg{ 1409956cc18dSsnj XtermWidget xw; 1410956cc18dSsnj 14115104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 1412956cc18dSsnj TScreen *screen = TScreenOf(xw); 1413d522f475Smrg Char Line[6]; 1414d522f475Smrg int line, col, ldelta = 0; 1415d522f475Smrg 1416492d43a5Smrg if (!IsBtnEvent(event) 1417913cc679Smrg || (okSendMousePos(xw) != MOUSE_OFF) || ExtendingSelection) 1418d522f475Smrg goto finish; 1419d522f475Smrg if (event->type == ButtonRelease) { 1420d522f475Smrg int delta; 1421d522f475Smrg 1422d522f475Smrg if (lastButtonDownTime == (Time) 0) { 1423d522f475Smrg /* first time and once in a blue moon */ 1424d522f475Smrg delta = screen->multiClickTime + 1; 1425d522f475Smrg } else if (event->xbutton.time > lastButtonDownTime) { 1426d522f475Smrg /* most of the time */ 14272eaa94a1Schristos delta = (int) (event->xbutton.time - lastButtonDownTime); 1428d522f475Smrg } else { 1429d522f475Smrg /* time has rolled over since lastButtonUpTime */ 14302eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time); 1431d522f475Smrg } 1432d522f475Smrg if (delta > screen->multiClickTime) 1433d522f475Smrg goto finish; /* All this work for this... */ 1434d522f475Smrg } 1435d522f475Smrg line = (event->xbutton.y - screen->border) / FontHeight(screen); 1436956cc18dSsnj if (!rowOnCurrentLine(screen, line, &ldelta)) 1437956cc18dSsnj goto finish; 1438d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 1439d522f475Smrg col = (event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) 1440d522f475Smrg / 2) 1441d522f475Smrg / FontWidth(screen) - screen->cur_col + ldelta * MaxCols(screen); 1442d522f475Smrg if (col == 0) 1443d522f475Smrg goto finish; 1444d522f475Smrg Line[0] = ANSI_ESC; 14455307cd1aSmrg Line[1] = (xw->keyboard.flags & MODE_DECCKM) ? 'O' : '['; 14462eaa94a1Schristos Line[2] = CharOf(col > 0 ? 'C' : 'D'); 1447d522f475Smrg if (col < 0) 1448d522f475Smrg col = -col; 1449d522f475Smrg while (col--) 14505307cd1aSmrg v_write(screen->respond, Line, (size_t) 3); 1451d522f475Smrg finish: 1452d522f475Smrg if (event->type == ButtonRelease) 1453d522f475Smrg do_select_end(xw, event, params, num_params, False); 1454d522f475Smrg } 1455d522f475Smrg} 1456d522f475Smrg#endif /* OPT_READLINE */ 1457d522f475Smrg 1458d522f475Smrg/* repeats <ESC>n or <ESC>p */ 1459d522f475Smrgvoid 1460d522f475SmrgViButton(Widget w, 1461894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1462e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 1463d522f475Smrg Cardinal *num_params GCC_UNUSED) 1464d522f475Smrg{ 1465956cc18dSsnj XtermWidget xw; 1466956cc18dSsnj 14675104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 1468956cc18dSsnj TScreen *screen = TScreenOf(xw); 1469d522f475Smrg int pty = screen->respond; 1470d522f475Smrg 1471492d43a5Smrg if (IsBtnEvent(event)) { 14722e4f8982Smrg int line; 1473d522f475Smrg 1474d522f475Smrg line = screen->cur_row - 1475d522f475Smrg ((event->xbutton.y - screen->border) / FontHeight(screen)); 14762e4f8982Smrg 1477d522f475Smrg if (line != 0) { 14782e4f8982Smrg Char Line[6]; 14792e4f8982Smrg 1480d522f475Smrg Line[0] = ANSI_ESC; /* force an exit from insert-mode */ 14815307cd1aSmrg v_write(pty, Line, (size_t) 1); 1482d522f475Smrg 1483d522f475Smrg if (line < 0) { 1484d522f475Smrg line = -line; 1485d522f475Smrg Line[0] = CONTROL('n'); 1486d522f475Smrg } else { 1487d522f475Smrg Line[0] = CONTROL('p'); 1488d522f475Smrg } 1489d522f475Smrg while (--line >= 0) 14905307cd1aSmrg v_write(pty, Line, (size_t) 1); 1491d522f475Smrg } 1492d522f475Smrg } 1493d522f475Smrg } 1494d522f475Smrg} 1495d522f475Smrg 1496d522f475Smrg/* 1497d522f475Smrg * This function handles button-motion events 1498d522f475Smrg */ 1499d522f475Smrg/*ARGSUSED*/ 1500d522f475Smrgvoid 1501d522f475SmrgHandleSelectExtend(Widget w, 1502894e0ac8Smrg XEvent *event, /* must be XMotionEvent */ 1503e0a2b6dfSmrg String *params GCC_UNUSED, 1504d522f475Smrg Cardinal *num_params GCC_UNUSED) 1505d522f475Smrg{ 1506956cc18dSsnj XtermWidget xw; 1507956cc18dSsnj 15085104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 1509956cc18dSsnj TScreen *screen = TScreenOf(xw); 1510d522f475Smrg CELL cell; 1511d522f475Smrg 1512f2e35a3aSmrg TRACE_EVENT("HandleSelectExtend", event, params, num_params); 15130bd37d32Smrg 1514d522f475Smrg screen->selection_time = event->xmotion.time; 1515d522f475Smrg switch (screen->eventMode) { 1516d522f475Smrg /* If not in one of the DEC mouse-reporting modes */ 1517d522f475Smrg case LEFTEXTENSION: 1518d522f475Smrg case RIGHTEXTENSION: 1519d522f475Smrg PointToCELL(screen, event->xmotion.y, event->xmotion.x, &cell); 1520d522f475Smrg ExtendExtend(xw, &cell); 1521d522f475Smrg break; 1522d522f475Smrg 1523d522f475Smrg /* If in motion reporting mode, send mouse position to 1524d522f475Smrg character process as a key sequence \E[M... */ 1525d522f475Smrg case NORMAL: 1526d522f475Smrg /* will get here if send_mouse_pos != MOUSE_OFF */ 1527913cc679Smrg if (okSendMousePos(xw) == BTN_EVENT_MOUSE 1528913cc679Smrg || okSendMousePos(xw) == ANY_EVENT_MOUSE) { 1529d522f475Smrg (void) SendMousePosition(xw, event); 1530d522f475Smrg } 1531d522f475Smrg break; 1532d522f475Smrg } 1533d522f475Smrg } 1534d522f475Smrg} 1535d522f475Smrg 1536d522f475Smrgvoid 1537d522f475SmrgHandleKeyboardSelectExtend(Widget w, 1538894e0ac8Smrg XEvent *event GCC_UNUSED, /* must be XButtonEvent */ 1539e0a2b6dfSmrg String *params GCC_UNUSED, 1540d522f475Smrg Cardinal *num_params GCC_UNUSED) 1541d522f475Smrg{ 1542956cc18dSsnj XtermWidget xw; 1543956cc18dSsnj 15445104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 1545956cc18dSsnj TScreen *screen = TScreenOf(xw); 15460bd37d32Smrg 1547f2e35a3aSmrg TRACE_EVENT("HandleKeyboardSelectExtend", event, params, num_params); 1548d522f475Smrg ExtendExtend(xw, &screen->cursorp); 1549d522f475Smrg } 1550d522f475Smrg} 1551d522f475Smrg 1552d522f475Smrgstatic void 1553d522f475Smrgdo_select_end(XtermWidget xw, 1554894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1555e0a2b6dfSmrg String *params, /* selections */ 1556d522f475Smrg Cardinal *num_params, 1557d522f475Smrg Bool use_cursor_loc) 1558d522f475Smrg{ 1559956cc18dSsnj TScreen *screen = TScreenOf(xw); 1560d522f475Smrg 1561d522f475Smrg screen->selection_time = event->xbutton.time; 1562f2e35a3aSmrg 1563f2e35a3aSmrg TRACE(("do_select_end %s @%ld\n", 1564f2e35a3aSmrg visibleEventMode(screen->eventMode), 1565f2e35a3aSmrg screen->selection_time)); 1566f2e35a3aSmrg 1567d522f475Smrg switch (screen->eventMode) { 1568d522f475Smrg case NORMAL: 1569d522f475Smrg (void) SendMousePosition(xw, event); 1570d522f475Smrg break; 1571d522f475Smrg case LEFTEXTENSION: 1572d522f475Smrg case RIGHTEXTENSION: 1573d522f475Smrg EndExtend(xw, event, params, *num_params, use_cursor_loc); 1574d522f475Smrg#if OPT_READLINE 1575913cc679Smrg readlineExtend(xw, event); 1576d522f475Smrg#endif /* OPT_READLINE */ 1577d522f475Smrg break; 1578d522f475Smrg } 1579d522f475Smrg} 1580d522f475Smrg 1581d522f475Smrgvoid 1582d522f475SmrgHandleSelectEnd(Widget w, 1583894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1584e0a2b6dfSmrg String *params, /* selections */ 1585d522f475Smrg Cardinal *num_params) 1586d522f475Smrg{ 1587956cc18dSsnj XtermWidget xw; 1588956cc18dSsnj 15895104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 15900bd37d32Smrg TRACE(("HandleSelectEnd\n")); 1591956cc18dSsnj do_select_end(xw, event, params, num_params, False); 1592956cc18dSsnj } 1593d522f475Smrg} 1594d522f475Smrg 1595d522f475Smrgvoid 1596d522f475SmrgHandleKeyboardSelectEnd(Widget w, 1597894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1598e0a2b6dfSmrg String *params, /* selections */ 1599d522f475Smrg Cardinal *num_params) 1600d522f475Smrg{ 1601956cc18dSsnj XtermWidget xw; 1602956cc18dSsnj 16035104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 16040bd37d32Smrg TRACE(("HandleKeyboardSelectEnd\n")); 1605956cc18dSsnj do_select_end(xw, event, params, num_params, True); 1606956cc18dSsnj } 1607d522f475Smrg} 1608d522f475Smrg 1609f2e35a3aSmrgvoid 1610f2e35a3aSmrgHandlePointerMotion(Widget w, 1611f2e35a3aSmrg XEvent *event, 1612f2e35a3aSmrg String *params, /* selections */ 1613f2e35a3aSmrg Cardinal *num_params) 1614f2e35a3aSmrg{ 1615f2e35a3aSmrg XtermWidget xw; 1616f2e35a3aSmrg 1617f2e35a3aSmrg (void) params; 1618f2e35a3aSmrg (void) num_params; 16195104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 1620f2e35a3aSmrg TRACE(("HandlePointerMotion\n")); 1621f2e35a3aSmrg if (event->type == MotionNotify) 1622f2e35a3aSmrg (void) SendMousePosition(xw, event); 1623f2e35a3aSmrg } 1624f2e35a3aSmrg} 1625f2e35a3aSmrg 1626f2e35a3aSmrgvoid 1627f2e35a3aSmrgHandlePointerButton(Widget w, 1628f2e35a3aSmrg XEvent *event, 1629f2e35a3aSmrg String *params, /* selections */ 1630f2e35a3aSmrg Cardinal *num_params) 1631f2e35a3aSmrg{ 1632f2e35a3aSmrg XtermWidget xw; 1633f2e35a3aSmrg 1634f2e35a3aSmrg (void) params; 1635f2e35a3aSmrg (void) num_params; 16365104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 1637f2e35a3aSmrg TRACE(("HandlePointerButton\n")); 1638f2e35a3aSmrg if (IsBtnEvent(event)) 1639f2e35a3aSmrg (void) SendMousePosition(xw, event); 1640f2e35a3aSmrg } 1641f2e35a3aSmrg} 1642f2e35a3aSmrg 1643492d43a5Smrg/* 16446879286fSmrg * Copy the selection data to the given target(s). 1645492d43a5Smrg */ 1646492d43a5Smrgvoid 16476879286fSmrgHandleCopySelection(Widget w, 1648894e0ac8Smrg XEvent *event, 1649e0a2b6dfSmrg String *params, /* list of targets */ 16506879286fSmrg Cardinal *num_params) 1651492d43a5Smrg{ 1652492d43a5Smrg XtermWidget xw; 1653492d43a5Smrg 16545104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 1655f2e35a3aSmrg TRACE_EVENT("HandleCopySelection", event, params, num_params); 16566879286fSmrg SelectSet(xw, event, params, *num_params); 1657492d43a5Smrg } 1658492d43a5Smrg} 1659492d43a5Smrg 1660d522f475Smrgstruct _SelectionList { 1661d522f475Smrg String *params; 1662d522f475Smrg Cardinal count; 1663d522f475Smrg Atom *targets; 1664d522f475Smrg Time time; 1665d522f475Smrg}; 1666d522f475Smrg 1667d522f475Smrgstatic unsigned 1668d522f475SmrgDECtoASCII(unsigned ch) 1669d522f475Smrg{ 1670d522f475Smrg if (xtermIsDecGraphic(ch)) { 16712eaa94a1Schristos ch = CharOf("###########+++++##-##++++|######"[ch]); 16722eaa94a1Schristos /* 01234567890123456789012345678901 */ 167304b94745Smrg } else { 167404b94745Smrg ch = '?'; /* DEC Technical has no mapping */ 1675d522f475Smrg } 1676d522f475Smrg return ch; 1677d522f475Smrg} 167820d2c4d2Smrg 167920d2c4d2Smrg#if OPT_WIDE_CHARS 168020d2c4d2Smrgstatic Cardinal 1681e0a2b6dfSmrgaddXtermChar(Char **buffer, Cardinal *used, Cardinal offset, unsigned value) 168220d2c4d2Smrg{ 168320d2c4d2Smrg if (offset + 1 >= *used) { 168420d2c4d2Smrg *used = 1 + (2 * (offset + 1)); 168520d2c4d2Smrg allocXtermChars(buffer, *used); 168620d2c4d2Smrg } 168720d2c4d2Smrg (*buffer)[offset++] = (Char) value; 168820d2c4d2Smrg return offset; 168920d2c4d2Smrg} 169020d2c4d2Smrg#define AddChar(buffer, used, offset, value) \ 169120d2c4d2Smrg offset = addXtermChar(buffer, used, offset, (unsigned) value) 169220d2c4d2Smrg 1693d522f475Smrg/* 1694d522f475Smrg * Convert a UTF-8 string to Latin-1, replacing non Latin-1 characters by `#', 1695d522f475Smrg * or ASCII/Latin-1 equivalents for special cases. 1696d522f475Smrg */ 1697d522f475Smrgstatic Char * 1698e0a2b6dfSmrgUTF8toLatin1(TScreen *screen, Char *s, unsigned long len, unsigned long *result) 1699d522f475Smrg{ 1700d522f475Smrg static Char *buffer; 1701956cc18dSsnj static Cardinal used; 1702d522f475Smrg 170320d2c4d2Smrg Cardinal offset = 0; 1704d522f475Smrg 170520d2c4d2Smrg if (len != 0) { 1706d522f475Smrg PtyData data; 170704b94745Smrg Boolean save_vt100 = screen->vt100_graphics; 1708d522f475Smrg 1709d522f475Smrg fakePtyData(&data, s, s + len); 171004b94745Smrg screen->vt100_graphics = False; /* temporary override */ 1711894e0ac8Smrg while (decodeUtf8(screen, &data)) { 1712956cc18dSsnj Bool fails = False; 1713956cc18dSsnj Bool extra = False; 1714f2e35a3aSmrg IChar value; 1715f2e35a3aSmrg skipPtyData(&data, value); 171604b94745Smrg if (is_UCS_SPECIAL(value)) { 1717956cc18dSsnj fails = True; 1718d522f475Smrg } else if (value < 256) { 171920d2c4d2Smrg AddChar(&buffer, &used, offset, CharOf(value)); 1720d522f475Smrg } else { 1721f2e35a3aSmrg unsigned eqv = ucs2dec(screen, value); 172204b94745Smrg if (xtermIsInternalCs(eqv)) { 172320d2c4d2Smrg AddChar(&buffer, &used, offset, DECtoASCII(eqv)); 1724d522f475Smrg } else { 1725d522f475Smrg eqv = AsciiEquivs(value); 1726956cc18dSsnj if (eqv == value) { 1727956cc18dSsnj fails = True; 1728956cc18dSsnj } else { 172920d2c4d2Smrg AddChar(&buffer, &used, offset, eqv); 1730956cc18dSsnj } 1731956cc18dSsnj if (isWide((wchar_t) value)) 1732956cc18dSsnj extra = True; 1733956cc18dSsnj } 1734956cc18dSsnj } 1735956cc18dSsnj 1736956cc18dSsnj /* 1737956cc18dSsnj * If we're not able to plug in a single-byte result, insert the 1738956cc18dSsnj * defaultString (which normally is a single "#", but could be 1739956cc18dSsnj * whatever the user wants). 1740956cc18dSsnj */ 1741956cc18dSsnj if (fails) { 17422e4f8982Smrg const Char *p; 17432e4f8982Smrg 1744492d43a5Smrg for (p = (const Char *) screen->default_string; *p != '\0'; ++p) { 174520d2c4d2Smrg AddChar(&buffer, &used, offset, *p); 1746d522f475Smrg } 1747d522f475Smrg } 1748956cc18dSsnj if (extra) 174920d2c4d2Smrg AddChar(&buffer, &used, offset, ' '); 1750d522f475Smrg } 175120d2c4d2Smrg AddChar(&buffer, &used, offset, '\0'); 175204b94745Smrg screen->vt100_graphics = save_vt100; 175320d2c4d2Smrg *result = (unsigned long) (offset - 1); 1754d522f475Smrg } else { 1755d522f475Smrg *result = 0; 1756d522f475Smrg } 1757d522f475Smrg return buffer; 1758d522f475Smrg} 175920d2c4d2Smrg 176020d2c4d2Smrgint 176120d2c4d2SmrgxtermUtf8ToTextList(XtermWidget xw, 176220d2c4d2Smrg XTextProperty * text_prop, 176320d2c4d2Smrg char ***text_list, 176420d2c4d2Smrg int *text_list_count) 176520d2c4d2Smrg{ 176620d2c4d2Smrg TScreen *screen = TScreenOf(xw); 176720d2c4d2Smrg Display *dpy = screen->display; 176820d2c4d2Smrg int rc = -1; 176920d2c4d2Smrg 177020d2c4d2Smrg if (text_prop->format == 8 177120d2c4d2Smrg && (rc = Xutf8TextPropertyToTextList(dpy, text_prop, 177220d2c4d2Smrg text_list, 177320d2c4d2Smrg text_list_count)) >= 0) { 177420d2c4d2Smrg if (*text_list != NULL && *text_list_count != 0) { 177520d2c4d2Smrg int i; 177620d2c4d2Smrg Char *data; 177720d2c4d2Smrg char **new_text_list, *tmp; 177820d2c4d2Smrg unsigned long size, new_size; 177920d2c4d2Smrg 178020d2c4d2Smrg TRACE(("xtermUtf8ToTextList size %d\n", *text_list_count)); 178120d2c4d2Smrg 178220d2c4d2Smrg /* 178320d2c4d2Smrg * XLib StringList actually uses only two pointers, one for the 178420d2c4d2Smrg * list itself, and one for the data. Pointer to the data is the 178520d2c4d2Smrg * first element of the list, the rest (if any) list elements point 178620d2c4d2Smrg * to the same memory block as the first element 178720d2c4d2Smrg */ 178820d2c4d2Smrg new_size = 0; 178920d2c4d2Smrg for (i = 0; i < *text_list_count; ++i) { 179020d2c4d2Smrg data = (Char *) (*text_list)[i]; 179120d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 179220d2c4d2Smrg (void) UTF8toLatin1(screen, data, size, &size); 179320d2c4d2Smrg new_size += size + 1; 179420d2c4d2Smrg } 1795a1f3da82Smrg new_text_list = TypeXtMallocN(char *, *text_list_count); 179620d2c4d2Smrg new_text_list[0] = tmp = XtMalloc((Cardinal) new_size); 179720d2c4d2Smrg for (i = 0; i < (*text_list_count); ++i) { 179820d2c4d2Smrg data = (Char *) (*text_list)[i]; 179920d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 18005104ee6eSmrg if ((data = UTF8toLatin1(screen, data, size, &size)) != NULL) { 18010bd37d32Smrg memcpy(tmp, data, size + 1); 18020bd37d32Smrg new_text_list[i] = tmp; 18030bd37d32Smrg tmp += size + 1; 18040bd37d32Smrg } 180520d2c4d2Smrg } 180620d2c4d2Smrg XFreeStringList((*text_list)); 180720d2c4d2Smrg *text_list = new_text_list; 180820d2c4d2Smrg } else { 180920d2c4d2Smrg rc = -1; 181020d2c4d2Smrg } 181120d2c4d2Smrg } 181220d2c4d2Smrg return rc; 181320d2c4d2Smrg} 1814d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1815d522f475Smrg 1816956cc18dSsnjstatic char * 1817956cc18dSsnjparseItem(char *value, char *nextc) 1818d522f475Smrg{ 1819956cc18dSsnj char *nextp = value; 1820956cc18dSsnj while (*nextp != '\0' && *nextp != ',') { 1821956cc18dSsnj *nextp = x_toupper(*nextp); 1822956cc18dSsnj ++nextp; 1823956cc18dSsnj } 1824956cc18dSsnj *nextc = *nextp; 1825956cc18dSsnj *nextp = '\0'; 1826d522f475Smrg 1827956cc18dSsnj return nextp; 1828956cc18dSsnj} 1829d522f475Smrg 1830956cc18dSsnj/* 1831956cc18dSsnj * All of the wanted strings are unique in the first character, so we can 1832956cc18dSsnj * use simple abbreviations. 1833956cc18dSsnj */ 1834956cc18dSsnjstatic Bool 1835956cc18dSsnjsameItem(const char *actual, const char *wanted) 1836956cc18dSsnj{ 1837956cc18dSsnj Bool result = False; 1838956cc18dSsnj size_t have = strlen(actual); 1839956cc18dSsnj size_t need = strlen(wanted); 1840d522f475Smrg 1841956cc18dSsnj if (have != 0 && have <= need) { 1842956cc18dSsnj if (!strncmp(actual, wanted, have)) { 1843956cc18dSsnj TRACE(("...matched \"%s\"\n", wanted)); 1844956cc18dSsnj result = True; 1845956cc18dSsnj } 1846956cc18dSsnj } 1847956cc18dSsnj 1848956cc18dSsnj return result; 1849956cc18dSsnj} 1850956cc18dSsnj 1851956cc18dSsnj/* 1852956cc18dSsnj * Handle the eightBitSelectTypes or utf8SelectTypes resource values. 1853956cc18dSsnj */ 1854956cc18dSsnjstatic Bool 1855894e0ac8SmrgoverrideTargets(Widget w, String value, Atom **resultp) 1856956cc18dSsnj{ 1857956cc18dSsnj Bool override = False; 1858956cc18dSsnj XtermWidget xw; 1859956cc18dSsnj 18605104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 1861956cc18dSsnj TScreen *screen = TScreenOf(xw); 1862956cc18dSsnj 186320d2c4d2Smrg if (!IsEmpty(value)) { 1864492d43a5Smrg char *copied = x_strdup(value); 18655104ee6eSmrg if (copied != NULL) { 18665104ee6eSmrg Atom *result = NULL; 1867956cc18dSsnj Cardinal count = 1; 1868956cc18dSsnj int n; 1869d522f475Smrg 1870956cc18dSsnj TRACE(("decoding SelectTypes \"%s\"\n", value)); 1871956cc18dSsnj for (n = 0; copied[n] != '\0'; ++n) { 1872956cc18dSsnj if (copied[n] == ',') 1873956cc18dSsnj ++count; 1874956cc18dSsnj } 1875a1f3da82Smrg result = TypeXtMallocN(Atom, (2 * count) + 1); 1876956cc18dSsnj if (result == NULL) { 1877956cc18dSsnj TRACE(("Couldn't allocate selection types\n")); 1878956cc18dSsnj } else { 1879956cc18dSsnj char nextc = '?'; 188020d2c4d2Smrg char *listp = (char *) copied; 1881956cc18dSsnj count = 0; 1882956cc18dSsnj do { 1883956cc18dSsnj char *nextp = parseItem(listp, &nextc); 18840bd37d32Smrg char *item = x_strtrim(listp); 18850bd37d32Smrg size_t len = (item ? strlen(item) : 0); 1886956cc18dSsnj 1887956cc18dSsnj if (len == 0) { 1888a1f3da82Smrg /* EMPTY */ ; 1889956cc18dSsnj } 1890956cc18dSsnj#if OPT_WIDE_CHARS 18910bd37d32Smrg else if (sameItem(item, "UTF8")) { 1892956cc18dSsnj result[count++] = XA_UTF8_STRING(XtDisplay(w)); 1893956cc18dSsnj } 1894956cc18dSsnj#endif 18950bd37d32Smrg else if (sameItem(item, "I18N")) { 1896956cc18dSsnj if (screen->i18nSelections) { 1897956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 1898956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1899956cc18dSsnj } 19000bd37d32Smrg } else if (sameItem(item, "TEXT")) { 1901956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 19020bd37d32Smrg } else if (sameItem(item, "COMPOUND_TEXT")) { 1903956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 19040bd37d32Smrg } else if (sameItem(item, "STRING")) { 1905956cc18dSsnj result[count++] = XA_STRING; 1906956cc18dSsnj } 1907956cc18dSsnj *nextp++ = nextc; 1908956cc18dSsnj listp = nextp; 19090bd37d32Smrg free(item); 1910956cc18dSsnj } while (nextc != '\0'); 1911956cc18dSsnj if (count) { 1912956cc18dSsnj result[count] = None; 1913956cc18dSsnj override = True; 1914956cc18dSsnj *resultp = result; 1915956cc18dSsnj } else { 1916956cc18dSsnj XtFree((char *) result); 1917956cc18dSsnj } 1918956cc18dSsnj } 19190bd37d32Smrg free(copied); 1920956cc18dSsnj } else { 1921956cc18dSsnj TRACE(("Couldn't allocate copy of selection types\n")); 1922d522f475Smrg } 1923956cc18dSsnj } 1924956cc18dSsnj } 1925956cc18dSsnj return override; 1926956cc18dSsnj} 1927956cc18dSsnj 1928956cc18dSsnj#if OPT_WIDE_CHARS 1929956cc18dSsnjstatic Atom * 1930e0a2b6dfSmrgallocUtf8Targets(Widget w, TScreen *screen) 1931956cc18dSsnj{ 1932956cc18dSsnj Atom **resultp = &(screen->selection_targets_utf8); 1933956cc18dSsnj 19345104ee6eSmrg if (*resultp == NULL) { 1935956cc18dSsnj Atom *result; 1936956cc18dSsnj 1937956cc18dSsnj if (!overrideTargets(w, screen->utf8_select_types, &result)) { 1938a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1939956cc18dSsnj if (result == NULL) { 1940956cc18dSsnj TRACE(("Couldn't allocate utf-8 selection targets\n")); 1941956cc18dSsnj } else { 1942956cc18dSsnj int n = 0; 1943956cc18dSsnj 1944e39b573cSmrg if (XSupportsLocale()) { 1945e39b573cSmrg result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1946d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1947e39b573cSmrg if (screen->i18nSelections) { 1948e39b573cSmrg result[n++] = XA_TEXT(XtDisplay(w)); 1949e39b573cSmrg result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1950e39b573cSmrg } 1951d522f475Smrg#endif 1952e39b573cSmrg } 1953956cc18dSsnj result[n++] = XA_STRING; 1954956cc18dSsnj result[n] = None; 1955956cc18dSsnj } 1956d522f475Smrg } 1957956cc18dSsnj 1958956cc18dSsnj *resultp = result; 1959d522f475Smrg } 1960956cc18dSsnj 1961956cc18dSsnj return *resultp; 1962956cc18dSsnj} 1963d522f475Smrg#endif 1964d522f475Smrg 1965956cc18dSsnjstatic Atom * 1966e0a2b6dfSmrgalloc8bitTargets(Widget w, TScreen *screen) 1967956cc18dSsnj{ 1968956cc18dSsnj Atom **resultp = &(screen->selection_targets_8bit); 1969956cc18dSsnj 19705104ee6eSmrg if (*resultp == NULL) { 19715104ee6eSmrg Atom *result = NULL; 1972956cc18dSsnj 1973956cc18dSsnj if (!overrideTargets(w, screen->eightbit_select_types, &result)) { 1974a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1975956cc18dSsnj if (result == NULL) { 1976956cc18dSsnj TRACE(("Couldn't allocate 8bit selection targets\n")); 1977956cc18dSsnj } else { 1978956cc18dSsnj int n = 0; 1979956cc18dSsnj 1980e39b573cSmrg if (XSupportsLocale()) { 1981d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1982e39b573cSmrg result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1983956cc18dSsnj#endif 1984e39b573cSmrg if (screen->i18nSelections) { 1985e39b573cSmrg result[n++] = XA_TEXT(XtDisplay(w)); 1986e39b573cSmrg result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1987e39b573cSmrg } 1988956cc18dSsnj } 1989956cc18dSsnj result[n++] = XA_STRING; 1990956cc18dSsnj result[n] = None; 1991956cc18dSsnj } 1992956cc18dSsnj } 1993956cc18dSsnj 1994956cc18dSsnj *resultp = result; 1995956cc18dSsnj } 1996956cc18dSsnj 1997956cc18dSsnj return *resultp; 1998956cc18dSsnj} 1999956cc18dSsnj 2000956cc18dSsnjstatic Atom * 2001956cc18dSsnj_SelectionTargets(Widget w) 2002956cc18dSsnj{ 2003956cc18dSsnj Atom *result; 2004956cc18dSsnj XtermWidget xw; 2005956cc18dSsnj 20065104ee6eSmrg if ((xw = getXtermWidget(w)) == NULL) { 2007956cc18dSsnj result = NULL; 2008956cc18dSsnj } else { 20092e4f8982Smrg TScreen *screen = TScreenOf(xw); 2010956cc18dSsnj 2011956cc18dSsnj#if OPT_WIDE_CHARS 2012956cc18dSsnj if (screen->wide_chars) { 2013956cc18dSsnj result = allocUtf8Targets(w, screen); 2014956cc18dSsnj } else 2015d522f475Smrg#endif 2016956cc18dSsnj { 2017956cc18dSsnj /* not screen->wide_chars */ 2018956cc18dSsnj result = alloc8bitTargets(w, screen); 2019d522f475Smrg } 2020d522f475Smrg } 2021956cc18dSsnj 2022956cc18dSsnj return result; 2023d522f475Smrg} 2024d522f475Smrg 20255307cd1aSmrg#define isSELECT(value) (!strcmp(NonNull(value), "SELECT")) 2026d522f475Smrg 2027f2e35a3aSmrgstatic int 2028f2e35a3aSmrgDefaultSelection(TScreen *screen) 2029f2e35a3aSmrg{ 2030f2e35a3aSmrg return (screen->selectToClipboard ? 1 : 0); 2031f2e35a3aSmrg} 2032f2e35a3aSmrg 2033f2e35a3aSmrgstatic int 2034f2e35a3aSmrgTargetToSelection(TScreen *screen, String name) 2035f2e35a3aSmrg{ 2036f2e35a3aSmrg int result = -1; 2037f2e35a3aSmrg int cutb; 2038f2e35a3aSmrg 2039f2e35a3aSmrg if (isSELECT(name)) { 2040f2e35a3aSmrg result = DefaultSelection(screen); 2041f2e35a3aSmrg } else if (!strcmp(name, PRIMARY_NAME)) { 2042f2e35a3aSmrg result = PRIMARY_CODE; 2043f2e35a3aSmrg } else if (!strcmp(name, CLIPBOARD_NAME)) { 2044f2e35a3aSmrg result = CLIPBOARD_CODE; 2045f2e35a3aSmrg } else if (!strcmp(name, SECONDARY_NAME)) { 2046f2e35a3aSmrg result = SECONDARY_CODE; 2047f2e35a3aSmrg } else if (sscanf(name, "CUT_BUFFER%d", &cutb) == 1) { 2048f2e35a3aSmrg if (cutb >= 0 && cutb < MAX_CUT_BUFFER) { 2049f2e35a3aSmrg result = CutBufferToCode(cutb); 2050f2e35a3aSmrg } else { 2051f2e35a3aSmrg xtermWarning("unexpected cut-buffer code: %d\n", cutb); 2052f2e35a3aSmrg } 2053f2e35a3aSmrg } else { 2054f2e35a3aSmrg xtermWarning("unexpected selection target: %s\n", name); 2055f2e35a3aSmrg } 2056f2e35a3aSmrg TRACE2(("TargetToSelection(%s) ->%d\n", name, result)); 2057f2e35a3aSmrg return result; 2058f2e35a3aSmrg} 2059f2e35a3aSmrg 2060f2e35a3aSmrgvoid 2061d522f475SmrgUnmapSelections(XtermWidget xw) 2062d522f475Smrg{ 2063956cc18dSsnj TScreen *screen = TScreenOf(xw); 2064d522f475Smrg 20655307cd1aSmrg FreeAndNull(screen->mappedSelect); 2066d522f475Smrg} 2067d522f475Smrg 2068d522f475Smrg/* 2069d522f475Smrg * xterm generally uses the primary selection. Some applications prefer 2070d522f475Smrg * (or are limited to) the clipboard. Since the translations resource is 2071d522f475Smrg * complicated, users seldom change the way it affects selection. But it 2072d522f475Smrg * is simple to remap the choice between primary and clipboard before the 2073d522f475Smrg * call to XmuInternStrings(). 2074d522f475Smrg */ 2075d522f475Smrgstatic String * 2076e0a2b6dfSmrgMapSelections(XtermWidget xw, String *params, Cardinal num_params) 2077d522f475Smrg{ 2078d522f475Smrg String *result = params; 2079d522f475Smrg 20805104ee6eSmrg if (params != NULL && num_params > 0) { 2081d522f475Smrg Cardinal j; 2082d522f475Smrg Boolean map = False; 2083d522f475Smrg 2084d522f475Smrg for (j = 0; j < num_params; ++j) { 2085d522f475Smrg TRACE(("param[%d]:%s\n", j, params[j])); 2086d522f475Smrg if (isSELECT(params[j])) { 2087d522f475Smrg map = True; 2088d522f475Smrg break; 2089d522f475Smrg } 2090d522f475Smrg } 2091d522f475Smrg if (map) { 2092956cc18dSsnj TScreen *screen = TScreenOf(xw); 2093956cc18dSsnj const char *mapTo = (screen->selectToClipboard 2094f2e35a3aSmrg ? CLIPBOARD_NAME 2095f2e35a3aSmrg : PRIMARY_NAME); 2096d522f475Smrg 2097d522f475Smrg UnmapSelections(xw); 20985104ee6eSmrg if ((result = TypeMallocN(String, num_params + 1)) != NULL) { 20995104ee6eSmrg result[num_params] = NULL; 2100d522f475Smrg for (j = 0; j < num_params; ++j) { 21015307cd1aSmrg result[j] = (String) (isSELECT(params[j]) 2102d522f475Smrg ? mapTo 21035307cd1aSmrg : params[j]); 21045104ee6eSmrg if (result[j] == NULL) { 2105d522f475Smrg UnmapSelections(xw); 2106f2e35a3aSmrg FreeAndNull(result); 2107d522f475Smrg break; 2108d522f475Smrg } 2109d522f475Smrg } 2110956cc18dSsnj screen->mappedSelect = result; 2111d522f475Smrg } 2112d522f475Smrg } 2113d522f475Smrg } 2114d522f475Smrg return result; 2115d522f475Smrg} 2116d522f475Smrg 2117d522f475Smrg/* 2118d522f475Smrg * Lookup the cut-buffer number, which will be in the range 0-7. 2119f2e35a3aSmrg * If it is not a cut-buffer, it is a type of selection, e.g., primary. 2120d522f475Smrg */ 2121d522f475Smrgstatic int 212220d2c4d2SmrgCutBuffer(Atom code) 2123d522f475Smrg{ 2124d522f475Smrg int cutbuffer; 212520d2c4d2Smrg switch ((unsigned) code) { 2126d522f475Smrg case XA_CUT_BUFFER0: 2127d522f475Smrg cutbuffer = 0; 2128d522f475Smrg break; 2129d522f475Smrg case XA_CUT_BUFFER1: 2130d522f475Smrg cutbuffer = 1; 2131d522f475Smrg break; 2132d522f475Smrg case XA_CUT_BUFFER2: 2133d522f475Smrg cutbuffer = 2; 2134d522f475Smrg break; 2135d522f475Smrg case XA_CUT_BUFFER3: 2136d522f475Smrg cutbuffer = 3; 2137d522f475Smrg break; 2138d522f475Smrg case XA_CUT_BUFFER4: 2139d522f475Smrg cutbuffer = 4; 2140d522f475Smrg break; 2141d522f475Smrg case XA_CUT_BUFFER5: 2142d522f475Smrg cutbuffer = 5; 2143d522f475Smrg break; 2144d522f475Smrg case XA_CUT_BUFFER6: 2145d522f475Smrg cutbuffer = 6; 2146d522f475Smrg break; 2147d522f475Smrg case XA_CUT_BUFFER7: 2148d522f475Smrg cutbuffer = 7; 2149d522f475Smrg break; 2150d522f475Smrg default: 2151d522f475Smrg cutbuffer = -1; 2152d522f475Smrg break; 2153d522f475Smrg } 2154f2e35a3aSmrg TRACE2(("CutBuffer(%d) = %d\n", (int) code, cutbuffer)); 2155d522f475Smrg return cutbuffer; 2156d522f475Smrg} 2157d522f475Smrg 2158d522f475Smrg#if OPT_PASTE64 2159d522f475Smrgstatic void 2160d522f475SmrgFinishPaste64(XtermWidget xw) 2161d522f475Smrg{ 2162956cc18dSsnj TScreen *screen = TScreenOf(xw); 2163956cc18dSsnj 2164956cc18dSsnj TRACE(("FinishPaste64(%d)\n", screen->base64_paste)); 2165956cc18dSsnj if (screen->base64_paste) { 2166956cc18dSsnj screen->base64_paste = 0; 2167956cc18dSsnj unparseputc1(xw, screen->base64_final); 2168d522f475Smrg unparse_end(xw); 2169d522f475Smrg } 2170d522f475Smrg} 2171d522f475Smrg#endif 2172d522f475Smrg 2173d522f475Smrg#if !OPT_PASTE64 2174d522f475Smrgstatic 2175d522f475Smrg#endif 2176d522f475Smrgvoid 2177d522f475SmrgxtermGetSelection(Widget w, 2178d522f475Smrg Time ev_time, 2179e0a2b6dfSmrg String *params, /* selections in precedence order */ 2180d522f475Smrg Cardinal num_params, 2181894e0ac8Smrg Atom *targets) 2182d522f475Smrg{ 2183d522f475Smrg Atom selection; 2184d522f475Smrg int cutbuffer; 2185d522f475Smrg Atom target; 2186d522f475Smrg 2187956cc18dSsnj XtermWidget xw; 2188956cc18dSsnj 218920d2c4d2Smrg if (num_params == 0) 219020d2c4d2Smrg return; 21915104ee6eSmrg if ((xw = getXtermWidget(w)) == NULL) 2192d522f475Smrg return; 2193d522f475Smrg 2194e0a2b6dfSmrg TRACE(("xtermGetSelection num_params %d @%ld\n", num_params, ev_time)); 2195956cc18dSsnj params = MapSelections(xw, params, num_params); 2196d522f475Smrg 2197d522f475Smrg XmuInternStrings(XtDisplay(w), params, (Cardinal) 1, &selection); 2198d522f475Smrg cutbuffer = CutBuffer(selection); 2199d522f475Smrg 2200956cc18dSsnj TRACE(("Cutbuffer: %d, target: %s\n", cutbuffer, 2201956cc18dSsnj (targets 2202956cc18dSsnj ? visibleSelectionTarget(XtDisplay(w), targets[0]) 2203956cc18dSsnj : "None"))); 2204d522f475Smrg 2205d522f475Smrg if (cutbuffer >= 0) { 2206d522f475Smrg int inbytes; 2207d522f475Smrg unsigned long nbytes; 2208d522f475Smrg int fmt8 = 8; 2209d522f475Smrg Atom type = XA_STRING; 2210d522f475Smrg char *line; 2211d522f475Smrg 2212d522f475Smrg /* 'line' is freed in SelectionReceived */ 2213d522f475Smrg line = XFetchBuffer(XtDisplay(w), &inbytes, cutbuffer); 2214d522f475Smrg nbytes = (unsigned long) inbytes; 2215d522f475Smrg 22160bd37d32Smrg if (nbytes > 0) { 2217d522f475Smrg SelectionReceived(w, NULL, &selection, &type, (XtPointer) line, 2218d522f475Smrg &nbytes, &fmt8); 22190bd37d32Smrg } else if (num_params > 1) { 2220d522f475Smrg xtermGetSelection(w, ev_time, params + 1, num_params - 1, NULL); 2221d522f475Smrg } 2222d522f475Smrg#if OPT_PASTE64 2223d522f475Smrg else { 2224956cc18dSsnj FinishPaste64(xw); 2225d522f475Smrg } 2226d522f475Smrg#endif 2227d522f475Smrg } else { 2228d522f475Smrg 2229d522f475Smrg if (targets == NULL || targets[0] == None) { 2230d522f475Smrg targets = _SelectionTargets(w); 2231d522f475Smrg } 2232d522f475Smrg 22335104ee6eSmrg if (targets != NULL) { 22342e4f8982Smrg struct _SelectionList *list; 22352e4f8982Smrg 2236d522f475Smrg target = targets[0]; 2237d522f475Smrg 2238d522f475Smrg if (targets[1] == None) { /* last target in list */ 2239d522f475Smrg params++; 2240d522f475Smrg num_params--; 2241d522f475Smrg targets = _SelectionTargets(w); 2242d522f475Smrg } else { 2243d522f475Smrg targets = &(targets[1]); 2244d522f475Smrg } 2245d522f475Smrg 2246d522f475Smrg if (num_params) { 2247d522f475Smrg /* 'list' is freed in SelectionReceived */ 2248a1f3da82Smrg list = TypeXtMalloc(struct _SelectionList); 22495104ee6eSmrg if (list != NULL) { 2250d522f475Smrg list->params = params; 2251d522f475Smrg list->count = num_params; 2252d522f475Smrg list->targets = targets; 2253d522f475Smrg list->time = ev_time; 2254d522f475Smrg } 2255d522f475Smrg } else { 2256d522f475Smrg list = NULL; 2257d522f475Smrg } 2258d522f475Smrg 2259d522f475Smrg XtGetSelectionValue(w, selection, 2260d522f475Smrg target, 2261d522f475Smrg SelectionReceived, 2262d522f475Smrg (XtPointer) list, ev_time); 2263d522f475Smrg } 2264d522f475Smrg } 2265d522f475Smrg} 2266d522f475Smrg 2267d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 2268d522f475Smrgstatic void 2269e0a2b6dfSmrgGettingSelection(Display *dpy, Atom type, Char *line, unsigned long len) 2270d522f475Smrg{ 2271d522f475Smrg Char *cp; 2272913cc679Smrg const char *name = TraceAtomName(dpy, type); 2273d522f475Smrg 227401037d57Smrg TRACE(("Getting %s (type=%ld, length=%ld)\n", name, (long int) type, len)); 2275d522f475Smrg for (cp = line; cp < line + len; cp++) { 2276956cc18dSsnj TRACE(("[%d:%lu]", (int) (cp + 1 - line), len)); 2277d522f475Smrg if (isprint(*cp)) { 2278d522f475Smrg TRACE(("%c\n", *cp)); 2279d522f475Smrg } else { 2280d522f475Smrg TRACE(("\\x%02x\n", *cp)); 2281d522f475Smrg } 2282d522f475Smrg } 2283d522f475Smrg} 2284d522f475Smrg#else 2285d522f475Smrg#define GettingSelection(dpy,type,line,len) /* nothing */ 2286d522f475Smrg#endif 2287d522f475Smrg 22885104ee6eSmrg#define tty_vwrite(pty,lag,l) v_write(pty,lag,(size_t) l) 2289d522f475Smrg 2290d522f475Smrg#if OPT_PASTE64 2291d522f475Smrg/* Return base64 code character given 6-bit number */ 2292d522f475Smrgstatic const char base64_code[] = "\ 2293d522f475SmrgABCDEFGHIJKLMNOPQRSTUVWXYZ\ 2294d522f475Smrgabcdefghijklmnopqrstuvwxyz\ 2295d522f475Smrg0123456789+/"; 2296d522f475Smrgstatic void 2297e0a2b6dfSmrgbase64_flush(TScreen *screen) 2298d522f475Smrg{ 2299d522f475Smrg Char x; 230001037d57Smrg 230101037d57Smrg TRACE(("base64_flush count %d, pad %d (%d)\n", 230201037d57Smrg screen->base64_count, 230301037d57Smrg screen->base64_pad, 230401037d57Smrg screen->base64_pad & 3)); 230501037d57Smrg 2306d522f475Smrg switch (screen->base64_count) { 2307d522f475Smrg case 0: 2308d522f475Smrg break; 2309d522f475Smrg case 2: 23102eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 4]); 2311d522f475Smrg tty_vwrite(screen->respond, &x, 1); 2312d522f475Smrg break; 2313d522f475Smrg case 4: 23142eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 2]); 2315d522f475Smrg tty_vwrite(screen->respond, &x, 1); 2316d522f475Smrg break; 2317d522f475Smrg } 231801037d57Smrg if (screen->base64_pad & 3) { 2319d522f475Smrg tty_vwrite(screen->respond, 2320492d43a5Smrg (const Char *) "===", 232101037d57Smrg (unsigned) (3 - (screen->base64_pad & 3))); 232201037d57Smrg } 2323d522f475Smrg screen->base64_count = 0; 2324d522f475Smrg screen->base64_accu = 0; 2325d522f475Smrg screen->base64_pad = 0; 2326d522f475Smrg} 2327d522f475Smrg#endif /* OPT_PASTE64 */ 2328d522f475Smrg 2329e0a2b6dfSmrg/* 2330e0a2b6dfSmrg * Translate ISO-8859-1 or UTF-8 data to NRCS. 2331e0a2b6dfSmrg */ 2332d522f475Smrgstatic void 23335307cd1aSmrgToNational(XtermWidget xw, Char *buffer, size_t *length) 2334e0a2b6dfSmrg{ 2335f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2336f2e35a3aSmrg DECNRCM_codes gsetL = screen->gsets[screen->curgl]; 2337f2e35a3aSmrg DECNRCM_codes gsetR = screen->gsets[screen->curgr]; 2338e0a2b6dfSmrg 2339e0a2b6dfSmrg#if OPT_WIDE_CHARS 2340e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 23412e4f8982Smrg Char *p; 2342e0a2b6dfSmrg PtyData *data = TypeXtMallocX(PtyData, *length); 2343e0a2b6dfSmrg 2344e0a2b6dfSmrg memset(data, 0, sizeof(*data)); 2345e0a2b6dfSmrg data->next = data->buffer; 2346e0a2b6dfSmrg data->last = data->buffer + *length; 23475307cd1aSmrg memcpy(data->buffer, buffer, *length); 2348e0a2b6dfSmrg p = buffer; 2349e0a2b6dfSmrg while (data->next < data->last) { 23502e4f8982Smrg unsigned chr, out, gl, gr; 23512e4f8982Smrg 2352894e0ac8Smrg if (!decodeUtf8(screen, data)) { 2353e0a2b6dfSmrg data->utf_size = 1; 2354e0a2b6dfSmrg data->utf_data = data->next[0]; 2355e0a2b6dfSmrg } 2356e0a2b6dfSmrg data->next += data->utf_size; 2357e0a2b6dfSmrg chr = data->utf_data; 2358e0a2b6dfSmrg out = chr; 2359f2e35a3aSmrg if ((gl = xtermCharSetIn(xw, chr, gsetL)) != chr) { 2360e0a2b6dfSmrg out = gl; 2361f2e35a3aSmrg } else if ((gr = xtermCharSetIn(xw, chr, gsetR)) != chr) { 2362e0a2b6dfSmrg out = gr; 2363e0a2b6dfSmrg } 2364e0a2b6dfSmrg *p++ = (Char) ((out < 256) ? out : ' '); 2365e0a2b6dfSmrg } 23665307cd1aSmrg *length = (size_t) (p - buffer); 2367e0a2b6dfSmrg free(data); 2368e0a2b6dfSmrg } else 2369e0a2b6dfSmrg#endif 2370e0a2b6dfSmrg { 23712e4f8982Smrg Char *p; 23722e4f8982Smrg 23735307cd1aSmrg for (p = buffer; (size_t) (p - buffer) < *length; ++p) { 23742e4f8982Smrg unsigned gl, gr; 23752e4f8982Smrg unsigned chr = *p; 23762e4f8982Smrg unsigned out = chr; 2377f2e35a3aSmrg if ((gl = xtermCharSetIn(xw, chr, gsetL)) != chr) { 2378e0a2b6dfSmrg out = gl; 2379f2e35a3aSmrg } else if ((gr = xtermCharSetIn(xw, chr, gsetR)) != chr) { 2380e0a2b6dfSmrg out = gr; 2381e0a2b6dfSmrg } 2382e0a2b6dfSmrg *p = (Char) out; 2383e0a2b6dfSmrg } 2384e0a2b6dfSmrg } 2385e0a2b6dfSmrg} 2386e0a2b6dfSmrg 2387e0a2b6dfSmrgstatic void 23885307cd1aSmrg_qWriteSelectionData(XtermWidget xw, Char *lag, size_t length) 2389d522f475Smrg{ 23900bd37d32Smrg TScreen *screen = TScreenOf(xw); 23910bd37d32Smrg 2392e0a2b6dfSmrg /* 2393e0a2b6dfSmrg * If we are pasting into a window which is using NRCS, we want to map 2394e0a2b6dfSmrg * the text from the normal encoding (ISO-8859-1 or UTF-8) into the coding 2395e0a2b6dfSmrg * that an application would use to write characters with NRCS. 2396e0a2b6dfSmrg * 2397e0a2b6dfSmrg * TODO: handle conversion from UTF-8, and adjust length. This can be done 2398e0a2b6dfSmrg * in the same buffer because the target is always 8-bit. 2399e0a2b6dfSmrg */ 2400e0a2b6dfSmrg if ((xw->flags & NATIONAL) && (length != 0)) { 2401f2e35a3aSmrg ToNational(xw, lag, &length); 2402e0a2b6dfSmrg } 2403d522f475Smrg#if OPT_PASTE64 2404d522f475Smrg if (screen->base64_paste) { 2405d522f475Smrg /* Send data as base64 */ 2406d522f475Smrg Char *p = lag; 2407d522f475Smrg Char buf[64]; 2408d522f475Smrg unsigned x = 0; 24090bd37d32Smrg 24105307cd1aSmrg TRACE(("convert to base64 %lu:%s\n", 24115307cd1aSmrg (unsigned long) length, 24125307cd1aSmrg visibleChars(p, length))); 241301037d57Smrg 24140bd37d32Smrg /* 24150bd37d32Smrg * Handle the case where the selection is from _this_ xterm, which 24160bd37d32Smrg * puts part of the reply in the buffer before the selection callback 24170bd37d32Smrg * happens. 24180bd37d32Smrg */ 24190bd37d32Smrg if (screen->base64_paste && screen->unparse_len) { 24200bd37d32Smrg unparse_end(xw); 24210bd37d32Smrg } 2422d522f475Smrg while (length--) { 2423d522f475Smrg switch (screen->base64_count) { 2424d522f475Smrg case 0: 24252eaa94a1Schristos buf[x++] = CharOf(base64_code[*p >> 2]); 24262eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0x3); 2427d522f475Smrg screen->base64_count = 2; 2428d522f475Smrg ++p; 2429d522f475Smrg break; 2430d522f475Smrg case 2: 24312eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 4) + 24322eaa94a1Schristos (*p >> 4)]); 24332eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0xF); 2434d522f475Smrg screen->base64_count = 4; 2435d522f475Smrg ++p; 2436d522f475Smrg break; 2437d522f475Smrg case 4: 24382eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 2) + 24392eaa94a1Schristos (*p >> 6)]); 24402eaa94a1Schristos buf[x++] = CharOf(base64_code[*p & 0x3F]); 2441d522f475Smrg screen->base64_accu = 0; 2442d522f475Smrg screen->base64_count = 0; 2443d522f475Smrg ++p; 2444d522f475Smrg break; 2445d522f475Smrg } 2446d522f475Smrg if (x >= 63) { 2447d522f475Smrg /* Write 63 or 64 characters */ 2448d522f475Smrg screen->base64_pad += x; 244901037d57Smrg TRACE(("writing base64 interim %s\n", visibleChars(buf, x))); 2450d522f475Smrg tty_vwrite(screen->respond, buf, x); 2451d522f475Smrg x = 0; 2452d522f475Smrg } 2453d522f475Smrg } 2454d522f475Smrg if (x != 0) { 2455d522f475Smrg screen->base64_pad += x; 245601037d57Smrg TRACE(("writing base64 finish %s\n", visibleChars(buf, x))); 2457d522f475Smrg tty_vwrite(screen->respond, buf, x); 2458d522f475Smrg } 2459d522f475Smrg } else 2460d522f475Smrg#endif /* OPT_PASTE64 */ 2461d522f475Smrg#if OPT_READLINE 2462d522f475Smrg if (SCREEN_FLAG(screen, paste_quotes)) { 24635307cd1aSmrg Char quote[2]; 24645307cd1aSmrg quote[0] = (Char) get_tty_lnext(screen->respond, XTERM_LNEXT, "pty"); 24655307cd1aSmrg quote[1] = 0; 24665307cd1aSmrg TRACE(("writing quoted selection data %s\n", visibleChars(lag, length))); 2467d522f475Smrg while (length--) { 24685307cd1aSmrg tty_vwrite(screen->respond, quote, 1); 2469d522f475Smrg tty_vwrite(screen->respond, lag++, 1); 2470d522f475Smrg } 2471d522f475Smrg } else 2472d522f475Smrg#endif 247301037d57Smrg { 24745307cd1aSmrg TRACE(("writing selection data %s\n", visibleChars(lag, length))); 2475d522f475Smrg tty_vwrite(screen->respond, lag, length); 247601037d57Smrg } 2477d522f475Smrg} 2478d522f475Smrg 2479d522f475Smrgstatic void 2480e0a2b6dfSmrg_WriteSelectionData(XtermWidget xw, Char *line, size_t length) 2481d522f475Smrg{ 24825307cd1aSmrg#if OPT_PASTE64 || OPT_READLINE 24830bd37d32Smrg TScreen *screen = TScreenOf(xw); 24842e4f8982Smrg#endif 2485d522f475Smrg 2486d522f475Smrg#if OPT_PASTE64 2487d522f475Smrg if (screen->base64_paste) { 24885307cd1aSmrg _qWriteSelectionData(xw, line, length); 2489d522f475Smrg base64_flush(screen); 2490d522f475Smrg } else 2491d522f475Smrg#endif 2492d522f475Smrg { 2493d522f475Smrg if (!SCREEN_FLAG(screen, paste_literal_nl)) { 24945307cd1aSmrg size_t n; 24955307cd1aSmrg for (n = 0; n < length; ++n) { 24965307cd1aSmrg if (line[n] == '\n') { 24975307cd1aSmrg line[n] = '\r'; 2498d522f475Smrg } 2499d522f475Smrg } 2500d522f475Smrg } 2501d522f475Smrg 25025307cd1aSmrg _qWriteSelectionData(xw, line, length); 2503d522f475Smrg } 2504d522f475Smrg} 2505d522f475Smrg 2506f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2507d522f475Smrgstatic void 2508e0a2b6dfSmrg_WriteKey(TScreen *screen, const Char *in) 2509d522f475Smrg{ 2510d522f475Smrg Char line[16]; 2511d522f475Smrg unsigned count = 0; 2512492d43a5Smrg size_t length = strlen((const char *) in); 2513d522f475Smrg 2514d522f475Smrg if (screen->control_eight_bits) { 2515d522f475Smrg line[count++] = ANSI_CSI; 2516d522f475Smrg } else { 2517d522f475Smrg line[count++] = ANSI_ESC; 2518d522f475Smrg line[count++] = '['; 2519d522f475Smrg } 2520d522f475Smrg while (length--) 2521d522f475Smrg line[count++] = *in++; 2522d522f475Smrg line[count++] = '~'; 2523d522f475Smrg tty_vwrite(screen->respond, line, count); 2524d522f475Smrg} 2525d522f475Smrg#endif /* OPT_READLINE */ 2526d522f475Smrg 25270bd37d32Smrg/* 25280bd37d32Smrg * Unless enabled by the user, strip control characters other than formatting. 25290bd37d32Smrg */ 25300bd37d32Smrgstatic size_t 25310bd37d32SmrgremoveControls(XtermWidget xw, char *value) 25320bd37d32Smrg{ 25330bd37d32Smrg TScreen *screen = TScreenOf(xw); 25340bd37d32Smrg size_t dst = 0; 25350bd37d32Smrg 25360bd37d32Smrg if (screen->allowPasteControls) { 25370bd37d32Smrg dst = strlen(value); 25380bd37d32Smrg } else { 25392e4f8982Smrg size_t src = 0; 254004b94745Smrg Boolean *disallowed = screen->disallow_paste_ops; 254104b94745Smrg TERMIO_STRUCT data; 254204b94745Smrg char current_chars[epLAST]; 254304b94745Smrg 254404b94745Smrg if (disallowed[epSTTY] && ttyGetAttr(screen->respond, &data) == 0) { 254504b94745Smrg int n; 254604b94745Smrg int disabled = xtermDisabledChar(); 254704b94745Smrg 254804b94745Smrg TRACE(("disallow(STTY):")); 254904b94745Smrg memcpy(current_chars, disallowed, sizeof(current_chars)); 255004b94745Smrg 255104b94745Smrg for (n = 0; n < NCCS; ++n) { 255204b94745Smrg PasteControls nc = (data.c_cc[n] < 32 255304b94745Smrg ? data.c_cc[n] 255404b94745Smrg : (data.c_cc[n] == 127 255504b94745Smrg ? epDEL 255604b94745Smrg : epLAST)); 255704b94745Smrg if (nc == epNUL || nc == epLAST) 255804b94745Smrg continue; 255904b94745Smrg if (CharOf(data.c_cc[n]) == CharOf(disabled)) 256004b94745Smrg continue; 256104b94745Smrg if ((n == VMIN || n == VTIME) && !(data.c_lflag & ICANON)) 256204b94745Smrg continue; 256304b94745Smrg switch (n) { 256404b94745Smrg /* POSIX */ 256504b94745Smrg case VEOF: 256604b94745Smrg case VEOL: 256704b94745Smrg case VERASE: 256804b94745Smrg case VINTR: 256904b94745Smrg case VKILL: 257004b94745Smrg case VQUIT: 257104b94745Smrg case VSTART: 257204b94745Smrg case VSTOP: 257304b94745Smrg case VSUSP: 257404b94745Smrg /* system-dependent */ 257504b94745Smrg#ifdef VDISCARD 257604b94745Smrg case VDISCARD: 257704b94745Smrg#endif 257804b94745Smrg#ifdef VDSUSP 257904b94745Smrg case VDSUSP: 258004b94745Smrg#endif 258104b94745Smrg#ifdef VEOL2 258204b94745Smrg case VEOL2: 258304b94745Smrg#endif 258404b94745Smrg#ifdef VLNEXT 258504b94745Smrg case VLNEXT: 258604b94745Smrg#endif 258704b94745Smrg#ifdef VREPRINT 258804b94745Smrg case VREPRINT: 258904b94745Smrg#endif 259004b94745Smrg#ifdef VSTATUS 259104b94745Smrg case VSTATUS: 259204b94745Smrg#endif 259304b94745Smrg#ifdef VSWTC 259404b94745Smrg case VSWTC: /* System V SWTCH */ 259504b94745Smrg#endif 259604b94745Smrg#ifdef VWERASE 259704b94745Smrg case VWERASE: 259804b94745Smrg#endif 259904b94745Smrg break; 260004b94745Smrg default: 260104b94745Smrg continue; 260204b94745Smrg } 260304b94745Smrg if (nc != epLAST) { 260404b94745Smrg TRACE((" \\%03o", data.c_cc[n])); 260504b94745Smrg current_chars[nc] = 1; 260604b94745Smrg } 260704b94745Smrg } 260804b94745Smrg TRACE(("\n")); 260904b94745Smrg disallowed = current_chars; 261004b94745Smrg } 26110bd37d32Smrg while ((value[dst] = value[src]) != '\0') { 26120bd37d32Smrg int ch = CharOf(value[src++]); 2613f2e35a3aSmrg 2614f2e35a3aSmrg#define ReplacePaste(n) \ 261504b94745Smrg if (disallowed[n]) \ 2616f2e35a3aSmrg value[dst] = ' ' 2617f2e35a3aSmrg 26180bd37d32Smrg if (ch < 32) { 2619f2e35a3aSmrg ReplacePaste(epC0); 2620f2e35a3aSmrg ReplacePaste(ch); 2621f2e35a3aSmrg ++dst; 2622f2e35a3aSmrg } else if (ch == ANSI_DEL) { 2623f2e35a3aSmrg ReplacePaste(epDEL); 2624f2e35a3aSmrg ++dst; 26250bd37d32Smrg } 26260bd37d32Smrg#if OPT_WIDE_CHARS 2627e0a2b6dfSmrg else if (screen->utf8_inparse || screen->utf8_nrc_mode) 26280bd37d32Smrg ++dst; 26290bd37d32Smrg#endif 26300bd37d32Smrg#if OPT_C1_PRINT || OPT_WIDE_CHARS 26310bd37d32Smrg else if (screen->c1_printable) 26320bd37d32Smrg ++dst; 26330bd37d32Smrg#endif 26340bd37d32Smrg else if (ch >= 128 && ch < 160) 26350bd37d32Smrg continue; 26360bd37d32Smrg else 26370bd37d32Smrg ++dst; 26380bd37d32Smrg } 26390bd37d32Smrg } 26400bd37d32Smrg return dst; 26410bd37d32Smrg} 26420bd37d32Smrg 2643f2e35a3aSmrg#if OPT_SELECTION_OPS 2644f2e35a3aSmrgstatic void 2645f2e35a3aSmrgbeginInternalSelect(XtermWidget xw) 2646f2e35a3aSmrg{ 2647f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2648f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2649f2e35a3aSmrg 2650f2e35a3aSmrg (void) mydata; 2651f2e35a3aSmrg /* override flags so that SelectionReceived only updates a buffer */ 2652f2e35a3aSmrg#if OPT_PASTE64 2653f2e35a3aSmrg mydata->base64_paste = screen->base64_paste; 2654f2e35a3aSmrg screen->base64_paste = 0; 2655f2e35a3aSmrg#endif 2656f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2657f2e35a3aSmrg mydata->paste_brackets = screen->paste_brackets; 2658f2e35a3aSmrg SCREEN_FLAG_unset(screen, paste_brackets); 2659f2e35a3aSmrg#endif 2660f2e35a3aSmrg} 2661f2e35a3aSmrg 2662f2e35a3aSmrgstatic void 2663f2e35a3aSmrgfinishInternalSelect(XtermWidget xw) 2664f2e35a3aSmrg{ 2665f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2666f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2667f2e35a3aSmrg 2668f2e35a3aSmrg (void) mydata; 2669f2e35a3aSmrg#if OPT_PASTE64 2670f2e35a3aSmrg screen->base64_paste = mydata->base64_paste; 2671f2e35a3aSmrg#endif 2672f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2673f2e35a3aSmrg screen->paste_brackets = mydata->paste_brackets; 2674f2e35a3aSmrg#endif 2675f2e35a3aSmrg} 2676f2e35a3aSmrg 2677f2e35a3aSmrg#else 2678f2e35a3aSmrg#define finishInternalSelect(xw) /* nothing */ 2679f2e35a3aSmrg#endif /* OPT_SELECTION_OPS */ 2680f2e35a3aSmrg 2681d522f475Smrg/* SelectionReceived: stuff received selection text into pty */ 2682d522f475Smrg 2683d522f475Smrg/* ARGSUSED */ 2684d522f475Smrgstatic void 2685d522f475SmrgSelectionReceived(Widget w, 2686d522f475Smrg XtPointer client_data, 2687894e0ac8Smrg Atom *selection GCC_UNUSED, 2688894e0ac8Smrg Atom *type, 2689d522f475Smrg XtPointer value, 2690d522f475Smrg unsigned long *length, 2691d522f475Smrg int *format) 2692d522f475Smrg{ 2693d522f475Smrg char **text_list = NULL; 26942e4f8982Smrg int text_list_count = 0; 2695d522f475Smrg XTextProperty text_prop; 2696d522f475Smrg TScreen *screen; 2697d522f475Smrg Display *dpy; 2698d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 2699d522f475Smrg Char *line = (Char *) value; 2700d522f475Smrg#endif 2701d522f475Smrg 2702956cc18dSsnj XtermWidget xw; 2703956cc18dSsnj 27045104ee6eSmrg if ((xw = getXtermWidget(w)) == NULL) 2705d522f475Smrg return; 2706956cc18dSsnj 2707956cc18dSsnj screen = TScreenOf(xw); 2708d522f475Smrg dpy = XtDisplay(w); 2709d522f475Smrg 2710d522f475Smrg if (*type == 0 /*XT_CONVERT_FAIL */ 2711d522f475Smrg || *length == 0 271201037d57Smrg || value == NULL) { 271301037d57Smrg TRACE(("...no data to convert\n")); 2714d522f475Smrg goto fail; 271501037d57Smrg } 2716d522f475Smrg 2717d522f475Smrg text_prop.value = (unsigned char *) value; 2718d522f475Smrg text_prop.encoding = *type; 2719d522f475Smrg text_prop.format = *format; 2720d522f475Smrg text_prop.nitems = *length; 2721d522f475Smrg 272201037d57Smrg TRACE(("SelectionReceived %s %s format %d, nitems %ld\n", 2723913cc679Smrg TraceAtomName(screen->display, *selection), 2724956cc18dSsnj visibleSelectionTarget(dpy, text_prop.encoding), 2725956cc18dSsnj text_prop.format, 2726956cc18dSsnj text_prop.nitems)); 2727956cc18dSsnj 2728d522f475Smrg#if OPT_WIDE_CHARS 2729e39b573cSmrg if (XSupportsLocale() && screen->wide_chars) { 2730d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2731d522f475Smrg *type == XA_STRING || 2732d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2733d522f475Smrg GettingSelection(dpy, *type, line, *length); 2734d522f475Smrg if (Xutf8TextPropertyToTextList(dpy, &text_prop, 2735d522f475Smrg &text_list, 2736d522f475Smrg &text_list_count) < 0) { 2737e39b573cSmrg TRACE(("default Xutf8 Conversion failed\n")); 2738d522f475Smrg text_list = NULL; 2739d522f475Smrg } 2740d522f475Smrg } 2741d522f475Smrg } else 2742d522f475Smrg#endif /* OPT_WIDE_CHARS */ 2743d522f475Smrg { 2744d522f475Smrg /* Convert the selection to locale's multibyte encoding. */ 2745d522f475Smrg 2746d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2747d522f475Smrg *type == XA_STRING || 2748d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2749d522f475Smrg Status rc; 2750d522f475Smrg 2751d522f475Smrg GettingSelection(dpy, *type, line, *length); 2752d522f475Smrg 2753d522f475Smrg#if OPT_WIDE_CHARS 2754d522f475Smrg if (*type == XA_UTF8_STRING(dpy) && 2755d522f475Smrg !(screen->wide_chars || screen->c1_printable)) { 275620d2c4d2Smrg rc = xtermUtf8ToTextList(xw, &text_prop, 275720d2c4d2Smrg &text_list, &text_list_count); 2758d522f475Smrg } else 2759d522f475Smrg#endif 2760e39b573cSmrg if (*type == XA_STRING && (!XSupportsLocale() || screen->brokenSelections)) { 2761d522f475Smrg rc = XTextPropertyToStringList(&text_prop, 2762d522f475Smrg &text_list, &text_list_count); 2763d522f475Smrg } else { 2764d522f475Smrg rc = XmbTextPropertyToTextList(dpy, &text_prop, 2765d522f475Smrg &text_list, 2766d522f475Smrg &text_list_count); 2767d522f475Smrg } 2768d522f475Smrg if (rc < 0) { 2769d522f475Smrg TRACE(("Conversion failed\n")); 2770d522f475Smrg text_list = NULL; 2771d522f475Smrg } 2772d522f475Smrg } 2773d522f475Smrg } 2774d522f475Smrg 2775d522f475Smrg if (text_list != NULL && text_list_count != 0) { 2776d522f475Smrg int i; 2777d522f475Smrg 2778d522f475Smrg#if OPT_PASTE64 2779d522f475Smrg if (screen->base64_paste) { 2780a1f3da82Smrg /* EMPTY */ ; 2781d522f475Smrg } else 2782d522f475Smrg#endif 2783f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2784f2e35a3aSmrg if (SCREEN_FLAG(screen, paste_brackets) && !screen->selectToBuffer) { 2785492d43a5Smrg _WriteKey(screen, (const Char *) "200"); 2786d522f475Smrg } 2787d522f475Smrg#endif 2788d522f475Smrg for (i = 0; i < text_list_count; i++) { 27890bd37d32Smrg size_t len = removeControls(xw, text_list[i]); 279001037d57Smrg 27910bd37d32Smrg if (screen->selectToBuffer) { 279201037d57Smrg InternalSelect *mydata = &(screen->internal_select); 2793f2e35a3aSmrg if (!mydata->done) { 2794f2e35a3aSmrg size_t have = (mydata->buffer 2795f2e35a3aSmrg ? strlen(mydata->buffer) 2796f2e35a3aSmrg : 0); 2797f2e35a3aSmrg size_t need = have + len + 1; 2798f2e35a3aSmrg char *buffer = realloc(mydata->buffer, need); 2799f2e35a3aSmrg 28005104ee6eSmrg if (buffer != NULL) { 2801f2e35a3aSmrg strcpy(buffer + have, text_list[i]); 2802f2e35a3aSmrg mydata->buffer = buffer; 2803f2e35a3aSmrg } 2804f2e35a3aSmrg TRACE(("FormatSelect %d.%d .. %d.%d %s\n", 2805f2e35a3aSmrg screen->startSel.row, 2806f2e35a3aSmrg screen->startSel.col, 2807f2e35a3aSmrg screen->endSel.row, 2808f2e35a3aSmrg screen->endSel.col, 2809f2e35a3aSmrg mydata->buffer)); 2810f2e35a3aSmrg mydata->format_select(w, mydata->format, mydata->buffer, 2811f2e35a3aSmrg &(screen->startSel), 2812f2e35a3aSmrg &(screen->endSel)); 2813f2e35a3aSmrg mydata->done = True; 28140bd37d32Smrg } 281501037d57Smrg 28160bd37d32Smrg } else { 28170bd37d32Smrg _WriteSelectionData(xw, (Char *) text_list[i], len); 28180bd37d32Smrg } 2819d522f475Smrg } 2820d522f475Smrg#if OPT_PASTE64 2821d522f475Smrg if (screen->base64_paste) { 2822956cc18dSsnj FinishPaste64(xw); 2823d522f475Smrg } else 2824d522f475Smrg#endif 2825f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2826f2e35a3aSmrg if (SCREEN_FLAG(screen, paste_brackets) && !screen->selectToBuffer) { 2827492d43a5Smrg _WriteKey(screen, (const Char *) "201"); 2828d522f475Smrg } 2829d522f475Smrg#endif 2830f2e35a3aSmrg if (screen->selectToBuffer) { 2831f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2832f2e35a3aSmrg finishInternalSelect(xw); 2833f2e35a3aSmrg if (mydata->done) { 2834f2e35a3aSmrg free(mydata->format); 2835f2e35a3aSmrg free(mydata->buffer); 2836f2e35a3aSmrg memset(mydata, 0, sizeof(*mydata)); 2837f2e35a3aSmrg } 2838f2e35a3aSmrg screen->selectToBuffer = False; 2839f2e35a3aSmrg } 2840d522f475Smrg XFreeStringList(text_list); 284101037d57Smrg } else { 284201037d57Smrg TRACE(("...empty text-list\n")); 2843d522f475Smrg goto fail; 284401037d57Smrg } 2845d522f475Smrg 2846d522f475Smrg XtFree((char *) client_data); 2847d522f475Smrg XtFree((char *) value); 2848d522f475Smrg 2849d522f475Smrg return; 2850d522f475Smrg 2851d522f475Smrg fail: 28525104ee6eSmrg if (client_data != NULL) { 2853d522f475Smrg struct _SelectionList *list = (struct _SelectionList *) client_data; 2854956cc18dSsnj 2855956cc18dSsnj TRACE(("SelectionReceived ->xtermGetSelection\n")); 2856d522f475Smrg xtermGetSelection(w, list->time, 2857d522f475Smrg list->params, list->count, list->targets); 2858d522f475Smrg XtFree((char *) client_data); 2859d522f475Smrg#if OPT_PASTE64 2860d522f475Smrg } else { 2861956cc18dSsnj FinishPaste64(xw); 2862d522f475Smrg#endif 2863d522f475Smrg } 2864d522f475Smrg return; 2865d522f475Smrg} 2866d522f475Smrg 2867d522f475Smrgvoid 2868d522f475SmrgHandleInsertSelection(Widget w, 2869894e0ac8Smrg XEvent *event, /* assumed to be XButtonEvent* */ 2870e0a2b6dfSmrg String *params, /* selections in precedence order */ 2871d522f475Smrg Cardinal *num_params) 2872d522f475Smrg{ 2873956cc18dSsnj XtermWidget xw; 2874d522f475Smrg 28755104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 2876f2e35a3aSmrg TRACE_EVENT("HandleInsertSelection", event, params, num_params); 2877d522f475Smrg if (!SendMousePosition(xw, event)) { 2878d522f475Smrg#if OPT_READLINE 2879d522f475Smrg int ldelta; 2880956cc18dSsnj TScreen *screen = TScreenOf(xw); 2881492d43a5Smrg if (IsBtnEvent(event) 2882f2e35a3aSmrg && !OverrideEvent(event) 2883913cc679Smrg && (okSendMousePos(xw) == MOUSE_OFF) 2884d522f475Smrg && SCREEN_FLAG(screen, paste_moves) 2885d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta)) 28865307cd1aSmrg ReadLineMovePoint(xw, eventColBetween(screen, event), ldelta); 2887d522f475Smrg#endif /* OPT_READLINE */ 2888d522f475Smrg 2889d522f475Smrg xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL); 2890d522f475Smrg } 2891d522f475Smrg } 2892d522f475Smrg} 2893d522f475Smrg 2894d522f475Smrgstatic SelectUnit 2895956cc18dSsnjEvalSelectUnit(XtermWidget xw, 2896d522f475Smrg Time buttonDownTime, 2897d522f475Smrg SelectUnit defaultUnit, 2898d522f475Smrg unsigned int button) 2899d522f475Smrg{ 2900956cc18dSsnj TScreen *screen = TScreenOf(xw); 2901d522f475Smrg SelectUnit result; 2902d522f475Smrg int delta; 2903d522f475Smrg 2904d522f475Smrg if (button != screen->lastButton) { 290520d2c4d2Smrg delta = screen->multiClickTime + 1; 2906d522f475Smrg } else if (screen->lastButtonUpTime == (Time) 0) { 2907d522f475Smrg /* first time and once in a blue moon */ 2908d522f475Smrg delta = screen->multiClickTime + 1; 2909d522f475Smrg } else if (buttonDownTime > screen->lastButtonUpTime) { 2910d522f475Smrg /* most of the time */ 29112eaa94a1Schristos delta = (int) (buttonDownTime - screen->lastButtonUpTime); 2912d522f475Smrg } else { 2913d522f475Smrg /* time has rolled over since lastButtonUpTime */ 29142eaa94a1Schristos delta = (int) ((((Time) ~ 0) - screen->lastButtonUpTime) + buttonDownTime); 2915d522f475Smrg } 2916d522f475Smrg 29175104ee6eSmrg#if OPT_BLOCK_SELECT 29185104ee6eSmrg if (screen->blockSelecting 29195104ee6eSmrg || screen->blockSelecting != screen->lastSelectWasBlock) { 29205104ee6eSmrg /* No word, line, paragraph selecting when block selecting 29215104ee6eSmrg or when our last click was a block select */ 29225104ee6eSmrg screen->numberOfClicks = 1; 29235104ee6eSmrg result = defaultUnit; 29245104ee6eSmrg } else 29255104ee6eSmrg#endif 2926d522f475Smrg if (delta > screen->multiClickTime) { 2927d522f475Smrg screen->numberOfClicks = 1; 2928d522f475Smrg result = defaultUnit; 2929d522f475Smrg } else { 2930d522f475Smrg result = screen->selectMap[screen->numberOfClicks % screen->maxClicks]; 2931d522f475Smrg screen->numberOfClicks += 1; 2932d522f475Smrg } 2933d522f475Smrg TRACE(("EvalSelectUnit(%d) = %d\n", screen->numberOfClicks, result)); 2934d522f475Smrg return result; 2935d522f475Smrg} 2936d522f475Smrg 2937d522f475Smrgstatic void 2938d522f475Smrgdo_select_start(XtermWidget xw, 2939894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2940e0a2b6dfSmrg CELL *cell) 2941d522f475Smrg{ 2942956cc18dSsnj TScreen *screen = TScreenOf(xw); 2943d522f475Smrg 2944d522f475Smrg if (SendMousePosition(xw, event)) 2945d522f475Smrg return; 2946956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2947d522f475Smrg event->xbutton.time, 2948d522f475Smrg Select_CHAR, 2949d522f475Smrg event->xbutton.button); 2950d522f475Smrg screen->replyToEmacs = False; 2951d522f475Smrg 2952d522f475Smrg#if OPT_READLINE 2953d522f475Smrg lastButtonDownTime = event->xbutton.time; 2954d522f475Smrg#endif 2955d522f475Smrg 2956d522f475Smrg StartSelect(xw, cell); 2957d522f475Smrg} 2958d522f475Smrg 2959d522f475Smrg/* ARGSUSED */ 2960d522f475Smrgvoid 2961d522f475SmrgHandleSelectStart(Widget w, 2962894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2963e0a2b6dfSmrg String *params GCC_UNUSED, 2964d522f475Smrg Cardinal *num_params GCC_UNUSED) 2965d522f475Smrg{ 2966956cc18dSsnj XtermWidget xw; 2967956cc18dSsnj 29685104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 2969956cc18dSsnj TScreen *screen = TScreenOf(xw); 2970d522f475Smrg CELL cell; 2971d522f475Smrg 2972f2e35a3aSmrg TRACE_EVENT("HandleSelectStart", event, params, num_params); 2973d522f475Smrg screen->firstValidRow = 0; 2974d522f475Smrg screen->lastValidRow = screen->max_row; 2975d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2976d522f475Smrg 2977d522f475Smrg#if OPT_READLINE 2978d522f475Smrg ExtendingSelection = 0; 2979d522f475Smrg#endif 2980d522f475Smrg 29815104ee6eSmrg#if OPT_BLOCK_SELECT 29825104ee6eSmrg screen->blockSelecting = 29835104ee6eSmrg (*num_params >= 1 && !strcmp(params[0], "block")) ? 1 : 0; 29845104ee6eSmrg#endif 29855104ee6eSmrg 2986d522f475Smrg do_select_start(xw, event, &cell); 2987d522f475Smrg } 2988d522f475Smrg} 2989d522f475Smrg 2990d522f475Smrg/* ARGSUSED */ 2991d522f475Smrgvoid 2992d522f475SmrgHandleKeyboardSelectStart(Widget w, 2993894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2994e0a2b6dfSmrg String *params GCC_UNUSED, 2995d522f475Smrg Cardinal *num_params GCC_UNUSED) 2996d522f475Smrg{ 2997956cc18dSsnj XtermWidget xw; 2998956cc18dSsnj 29995104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 3000956cc18dSsnj TScreen *screen = TScreenOf(xw); 30010bd37d32Smrg 3002f2e35a3aSmrg TRACE_EVENT("HandleKeyboardSelectStart", event, params, num_params); 3003d522f475Smrg do_select_start(xw, event, &screen->cursorp); 3004d522f475Smrg } 3005d522f475Smrg} 3006d522f475Smrg 3007d522f475Smrgstatic void 3008894e0ac8SmrgTrackDown(XtermWidget xw, XButtonEvent *event) 3009d522f475Smrg{ 3010956cc18dSsnj TScreen *screen = TScreenOf(xw); 3011d522f475Smrg CELL cell; 3012d522f475Smrg 3013956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 3014d522f475Smrg event->time, 3015d522f475Smrg Select_CHAR, 3016d522f475Smrg event->button); 3017d522f475Smrg if (screen->numberOfClicks > 1) { 3018d522f475Smrg PointToCELL(screen, event->y, event->x, &cell); 3019d522f475Smrg screen->replyToEmacs = True; 3020d522f475Smrg StartSelect(xw, &cell); 3021d522f475Smrg } else { 3022d522f475Smrg screen->waitingForTrackInfo = True; 3023492d43a5Smrg EditorButton(xw, event); 3024d522f475Smrg } 3025d522f475Smrg} 3026d522f475Smrg 3027d522f475Smrg#define boundsCheck(x) if (x < 0) \ 3028d522f475Smrg x = 0; \ 3029d522f475Smrg else if (x >= screen->max_row) \ 3030d522f475Smrg x = screen->max_row 3031d522f475Smrg 3032d522f475Smrgvoid 3033d522f475SmrgTrackMouse(XtermWidget xw, 3034d522f475Smrg int func, 30355104ee6eSmrg const CELL *start, 3036d522f475Smrg int firstrow, 3037d522f475Smrg int lastrow) 3038d522f475Smrg{ 3039956cc18dSsnj TScreen *screen = TScreenOf(xw); 3040d522f475Smrg 3041d522f475Smrg if (screen->waitingForTrackInfo) { /* if Timed, ignore */ 3042d522f475Smrg screen->waitingForTrackInfo = False; 3043d522f475Smrg 3044d522f475Smrg if (func != 0) { 3045d522f475Smrg CELL first = *start; 3046d522f475Smrg 3047d522f475Smrg boundsCheck(first.row); 3048d522f475Smrg boundsCheck(firstrow); 3049d522f475Smrg boundsCheck(lastrow); 3050d522f475Smrg screen->firstValidRow = firstrow; 3051d522f475Smrg screen->lastValidRow = lastrow; 3052d522f475Smrg screen->replyToEmacs = True; 3053d522f475Smrg StartSelect(xw, &first); 3054d522f475Smrg } 3055d522f475Smrg } 3056d522f475Smrg} 3057d522f475Smrg 3058d522f475Smrgstatic void 3059e0a2b6dfSmrgStartSelect(XtermWidget xw, const CELL *cell) 3060d522f475Smrg{ 3061956cc18dSsnj TScreen *screen = TScreenOf(xw); 3062d522f475Smrg 3063d522f475Smrg TRACE(("StartSelect row=%d, col=%d\n", cell->row, cell->col)); 3064d522f475Smrg if (screen->cursor_state) 3065f2e35a3aSmrg HideCursor(xw); 3066d522f475Smrg if (screen->numberOfClicks == 1) { 3067d522f475Smrg /* set start of selection */ 3068d522f475Smrg screen->rawPos = *cell; 3069d522f475Smrg } 3070d522f475Smrg /* else use old values in rawPos */ 3071d522f475Smrg screen->saveStartR = screen->startExt = screen->rawPos; 3072d522f475Smrg screen->saveEndR = screen->endExt = screen->rawPos; 3073d522f475Smrg if (Coordinate(screen, cell) < Coordinate(screen, &(screen->rawPos))) { 3074d522f475Smrg screen->eventMode = LEFTEXTENSION; 3075d522f475Smrg screen->startExt = *cell; 3076d522f475Smrg } else { 3077d522f475Smrg screen->eventMode = RIGHTEXTENSION; 3078d522f475Smrg screen->endExt = *cell; 3079d522f475Smrg } 3080f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False, True); 3081d522f475Smrg} 3082d522f475Smrg 3083d522f475Smrgstatic void 3084d522f475SmrgEndExtend(XtermWidget xw, 3085894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 3086e0a2b6dfSmrg String *params, /* selections */ 3087d522f475Smrg Cardinal num_params, 3088d522f475Smrg Bool use_cursor_loc) 3089d522f475Smrg{ 3090d522f475Smrg CELL cell; 3091956cc18dSsnj TScreen *screen = TScreenOf(xw); 3092d522f475Smrg 3093f2e35a3aSmrg TRACE_EVENT("EndExtend", event, params, &num_params); 3094d522f475Smrg if (use_cursor_loc) { 3095d522f475Smrg cell = screen->cursorp; 3096d522f475Smrg } else { 3097d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 3098d522f475Smrg } 3099d522f475Smrg ExtendExtend(xw, &cell); 31002e4f8982Smrg 3101d522f475Smrg screen->lastButtonUpTime = event->xbutton.time; 3102d522f475Smrg screen->lastButton = event->xbutton.button; 31035104ee6eSmrg#if OPT_BLOCK_SELECT 31045104ee6eSmrg screen->lastSelectWasBlock = screen->blockSelecting; 31055104ee6eSmrg#endif 31062e4f8982Smrg 3107d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 3108d522f475Smrg if (screen->replyToEmacs) { 31092e4f8982Smrg Char line[64]; 31102e4f8982Smrg unsigned count = 0; 31112e4f8982Smrg 3112d522f475Smrg if (screen->control_eight_bits) { 3113d522f475Smrg line[count++] = ANSI_CSI; 3114d522f475Smrg } else { 3115d522f475Smrg line[count++] = ANSI_ESC; 3116d522f475Smrg line[count++] = '['; 3117d522f475Smrg } 3118d522f475Smrg if (isSameCELL(&(screen->rawPos), &(screen->startSel)) 3119d522f475Smrg && isSameCELL(&cell, &(screen->endSel))) { 3120d522f475Smrg /* Use short-form emacs select */ 31210bd37d32Smrg 31220bd37d32Smrg switch (screen->extend_coords) { 31230bd37d32Smrg case 0: 31240bd37d32Smrg case SET_EXT_MODE_MOUSE: 31250bd37d32Smrg line[count++] = 't'; 31260bd37d32Smrg break; 31270bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 3128f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 31290bd37d32Smrg line[count++] = '<'; 31300bd37d32Smrg break; 31310bd37d32Smrg } 31320bd37d32Smrg 3133492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 31340bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3135492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 31360bd37d32Smrg 31370bd37d32Smrg switch (screen->extend_coords) { 31380bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 31390bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 3140f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 31410bd37d32Smrg line[count++] = 't'; 31420bd37d32Smrg break; 31430bd37d32Smrg } 3144d522f475Smrg } else { 3145d522f475Smrg /* long-form, specify everything */ 31460bd37d32Smrg 31470bd37d32Smrg switch (screen->extend_coords) { 31480bd37d32Smrg case 0: 31490bd37d32Smrg case SET_EXT_MODE_MOUSE: 31500bd37d32Smrg line[count++] = 'T'; 31510bd37d32Smrg break; 31520bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 3153f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 31540bd37d32Smrg line[count++] = '<'; 31550bd37d32Smrg break; 31560bd37d32Smrg } 31570bd37d32Smrg 3158492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.col); 31590bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3160492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.row); 31610bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3162492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 31630bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3164492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 31650bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3166492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.col); 31670bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3168492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.row); 31690bd37d32Smrg 31700bd37d32Smrg switch (screen->extend_coords) { 31710bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 31720bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 3173f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 31740bd37d32Smrg line[count++] = 'T'; 31750bd37d32Smrg break; 31760bd37d32Smrg } 3177d522f475Smrg } 31785307cd1aSmrg v_write(screen->respond, line, (size_t) count); 3179f2e35a3aSmrg UnHiliteText(xw); 3180d522f475Smrg } 3181d522f475Smrg } 3182d522f475Smrg SelectSet(xw, event, params, num_params); 3183d522f475Smrg screen->eventMode = NORMAL; 3184d522f475Smrg} 3185d522f475Smrg 3186d522f475Smrgvoid 3187d522f475SmrgHandleSelectSet(Widget w, 3188894e0ac8Smrg XEvent *event, 3189e0a2b6dfSmrg String *params, 3190d522f475Smrg Cardinal *num_params) 3191d522f475Smrg{ 3192956cc18dSsnj XtermWidget xw; 3193956cc18dSsnj 31945104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 3195f2e35a3aSmrg TRACE_EVENT("HandleSelectSet", event, params, num_params); 3196956cc18dSsnj SelectSet(xw, event, params, *num_params); 3197d522f475Smrg } 3198d522f475Smrg} 3199d522f475Smrg 3200d522f475Smrg/* ARGSUSED */ 3201d522f475Smrgstatic void 3202d522f475SmrgSelectSet(XtermWidget xw, 3203894e0ac8Smrg XEvent *event GCC_UNUSED, 3204e0a2b6dfSmrg String *params, 3205d522f475Smrg Cardinal num_params) 3206d522f475Smrg{ 3207956cc18dSsnj TScreen *screen = TScreenOf(xw); 3208d522f475Smrg 3209d522f475Smrg TRACE(("SelectSet\n")); 3210d522f475Smrg /* Only do select stuff if non-null select */ 3211d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 3212f2e35a3aSmrg Cardinal n; 3213f2e35a3aSmrg for (n = 0; n < num_params; ++n) { 3214f2e35a3aSmrg SaltTextAway(xw, 3215f2e35a3aSmrg TargetToSelection(screen, params[n]), 3216f2e35a3aSmrg &(screen->startSel), &(screen->endSel)); 3217f2e35a3aSmrg } 32180bd37d32Smrg _OwnSelection(xw, params, num_params); 3219d522f475Smrg } else { 32200bd37d32Smrg ScrnDisownSelection(xw); 3221d522f475Smrg } 3222d522f475Smrg} 3223d522f475Smrg 3224d522f475Smrg#define Abs(x) ((x) < 0 ? -(x) : (x)) 3225d522f475Smrg 3226d522f475Smrg/* ARGSUSED */ 3227d522f475Smrgstatic void 3228d522f475Smrgdo_start_extend(XtermWidget xw, 3229894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3230e0a2b6dfSmrg String *params GCC_UNUSED, 3231d522f475Smrg Cardinal *num_params GCC_UNUSED, 3232d522f475Smrg Bool use_cursor_loc) 3233d522f475Smrg{ 3234956cc18dSsnj TScreen *screen = TScreenOf(xw); 3235d522f475Smrg int coord; 3236d522f475Smrg CELL cell; 3237d522f475Smrg 3238d522f475Smrg if (SendMousePosition(xw, event)) 3239d522f475Smrg return; 3240d522f475Smrg 3241d522f475Smrg screen->firstValidRow = 0; 3242d522f475Smrg screen->lastValidRow = screen->max_row; 3243d522f475Smrg#if OPT_READLINE 3244f2e35a3aSmrg if (OverrideEvent(event) 3245d522f475Smrg || event->xbutton.button != Button3 3246d522f475Smrg || !(SCREEN_FLAG(screen, dclick3_deletes))) 3247d522f475Smrg#endif 3248956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 3249d522f475Smrg event->xbutton.time, 3250d522f475Smrg screen->selectUnit, 3251d522f475Smrg event->xbutton.button); 3252d522f475Smrg screen->replyToEmacs = False; 3253d522f475Smrg 3254d522f475Smrg#if OPT_READLINE 3255f2e35a3aSmrg CheckSecondPress3(xw, screen, event); 3256d522f475Smrg#endif 3257d522f475Smrg 3258d522f475Smrg if (screen->numberOfClicks == 1 3259f2e35a3aSmrg || (SCREEN_FLAG(screen, dclick3_deletes) 3260f2e35a3aSmrg && !OverrideEvent(event))) { 3261d522f475Smrg /* Save existing selection so we can reestablish it if the guy 3262d522f475Smrg extends past the other end of the selection */ 3263d522f475Smrg screen->saveStartR = screen->startExt = screen->startRaw; 3264d522f475Smrg screen->saveEndR = screen->endExt = screen->endRaw; 3265d522f475Smrg } else { 3266d522f475Smrg /* He just needed the selection mode changed, use old values. */ 3267d522f475Smrg screen->startExt = screen->startRaw = screen->saveStartR; 3268d522f475Smrg screen->endExt = screen->endRaw = screen->saveEndR; 3269d522f475Smrg } 3270d522f475Smrg if (use_cursor_loc) { 3271d522f475Smrg cell = screen->cursorp; 3272d522f475Smrg } else { 3273d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 3274d522f475Smrg } 3275d522f475Smrg coord = Coordinate(screen, &cell); 3276d522f475Smrg 3277d522f475Smrg if (Abs(coord - Coordinate(screen, &(screen->startSel))) 3278d522f475Smrg < Abs(coord - Coordinate(screen, &(screen->endSel))) 3279d522f475Smrg || coord < Coordinate(screen, &(screen->startSel))) { 3280d522f475Smrg /* point is close to left side of selection */ 3281d522f475Smrg screen->eventMode = LEFTEXTENSION; 3282d522f475Smrg screen->startExt = cell; 3283d522f475Smrg } else { 3284d522f475Smrg /* point is close to left side of selection */ 3285d522f475Smrg screen->eventMode = RIGHTEXTENSION; 3286d522f475Smrg screen->endExt = cell; 3287d522f475Smrg } 3288f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), True, True); 3289d522f475Smrg 3290d522f475Smrg#if OPT_READLINE 3291d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 3292d522f475Smrg ExtendingSelection = 1; 3293d522f475Smrg#endif 3294d522f475Smrg} 3295d522f475Smrg 3296d522f475Smrgstatic void 3297e0a2b6dfSmrgExtendExtend(XtermWidget xw, const CELL *cell) 3298d522f475Smrg{ 3299956cc18dSsnj TScreen *screen = TScreenOf(xw); 3300d522f475Smrg int coord = Coordinate(screen, cell); 3301d522f475Smrg 3302d522f475Smrg TRACE(("ExtendExtend row=%d, col=%d\n", cell->row, cell->col)); 3303d522f475Smrg if (screen->eventMode == LEFTEXTENSION 3304d522f475Smrg && ((coord + (screen->selectUnit != Select_CHAR)) 3305d522f475Smrg > Coordinate(screen, &(screen->endSel)))) { 3306d522f475Smrg /* Whoops, he's changed his mind. Do RIGHTEXTENSION */ 3307d522f475Smrg screen->eventMode = RIGHTEXTENSION; 3308d522f475Smrg screen->startExt = screen->saveStartR; 3309d522f475Smrg } else if (screen->eventMode == RIGHTEXTENSION 3310d522f475Smrg && coord < Coordinate(screen, &(screen->startSel))) { 3311d522f475Smrg /* Whoops, he's changed his mind. Do LEFTEXTENSION */ 3312d522f475Smrg screen->eventMode = LEFTEXTENSION; 3313d522f475Smrg screen->endExt = screen->saveEndR; 3314d522f475Smrg } 3315d522f475Smrg if (screen->eventMode == LEFTEXTENSION) { 3316d522f475Smrg screen->startExt = *cell; 3317d522f475Smrg } else { 3318d522f475Smrg screen->endExt = *cell; 3319d522f475Smrg } 3320f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False, True); 3321d522f475Smrg 3322d522f475Smrg#if OPT_READLINE 3323d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 3324d522f475Smrg ExtendingSelection = 1; 3325d522f475Smrg#endif 3326d522f475Smrg} 3327d522f475Smrg 3328d522f475Smrgvoid 3329d522f475SmrgHandleStartExtend(Widget w, 3330894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3331e0a2b6dfSmrg String *params, /* unused */ 3332d522f475Smrg Cardinal *num_params) /* unused */ 3333d522f475Smrg{ 3334956cc18dSsnj XtermWidget xw; 3335956cc18dSsnj 33365104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 3337f2e35a3aSmrg TRACE_EVENT("HandleStartExtend", event, params, num_params); 3338956cc18dSsnj do_start_extend(xw, event, params, num_params, False); 3339956cc18dSsnj } 3340d522f475Smrg} 3341d522f475Smrg 3342d522f475Smrgvoid 3343d522f475SmrgHandleKeyboardStartExtend(Widget w, 3344894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3345e0a2b6dfSmrg String *params, /* unused */ 3346d522f475Smrg Cardinal *num_params) /* unused */ 3347d522f475Smrg{ 3348956cc18dSsnj XtermWidget xw; 3349956cc18dSsnj 33505104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 3351f2e35a3aSmrg TRACE_EVENT("HandleKeyboardStartExtend", event, params, num_params); 3352956cc18dSsnj do_start_extend(xw, event, params, num_params, True); 3353956cc18dSsnj } 3354d522f475Smrg} 3355d522f475Smrg 3356d522f475Smrgvoid 3357e0a2b6dfSmrgScrollSelection(TScreen *screen, int amount, Bool always) 3358d522f475Smrg{ 3359d522f475Smrg int minrow = INX2ROW(screen, -screen->savedlines); 3360d522f475Smrg int maxrow = INX2ROW(screen, screen->max_row); 3361d522f475Smrg int maxcol = screen->max_col; 3362d522f475Smrg 3363d522f475Smrg#define scroll_update_one(cell) \ 3364d522f475Smrg (cell)->row += amount; \ 3365d522f475Smrg if ((cell)->row < minrow) { \ 3366d522f475Smrg (cell)->row = minrow; \ 3367d522f475Smrg (cell)->col = 0; \ 3368d522f475Smrg } \ 3369d522f475Smrg if ((cell)->row > maxrow) { \ 3370d522f475Smrg (cell)->row = maxrow; \ 3371d522f475Smrg (cell)->col = maxcol; \ 3372d522f475Smrg } 3373d522f475Smrg 3374d522f475Smrg scroll_update_one(&(screen->startRaw)); 3375d522f475Smrg scroll_update_one(&(screen->endRaw)); 3376d522f475Smrg scroll_update_one(&(screen->startSel)); 3377d522f475Smrg scroll_update_one(&(screen->endSel)); 3378d522f475Smrg 3379d522f475Smrg scroll_update_one(&(screen->rawPos)); 3380d522f475Smrg 3381d522f475Smrg /* 3382d522f475Smrg * If we are told to scroll the selection but it lies outside the scrolling 3383d522f475Smrg * margins, then that could cause the selection to move (bad). It is not 3384d522f475Smrg * simple to fix, because this function is called both for the scrollbar 3385d522f475Smrg * actions as well as application scrolling. The 'always' flag is set in 3386d522f475Smrg * the former case. The rest of the logic handles the latter. 3387d522f475Smrg */ 3388d522f475Smrg if (ScrnHaveSelection(screen)) { 3389d522f475Smrg int adjust; 3390d522f475Smrg 3391d522f475Smrg adjust = ROW2INX(screen, screen->startH.row); 3392d522f475Smrg if (always 33930bd37d32Smrg || !ScrnHaveRowMargins(screen) 33940bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 3395d522f475Smrg scroll_update_one(&screen->startH); 3396d522f475Smrg } 3397d522f475Smrg adjust = ROW2INX(screen, screen->endH.row); 3398d522f475Smrg if (always 33990bd37d32Smrg || !ScrnHaveRowMargins(screen) 34000bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 3401d522f475Smrg scroll_update_one(&screen->endH); 3402d522f475Smrg } 3403d522f475Smrg } 3404d522f475Smrg 3405d522f475Smrg screen->startHCoord = Coordinate(screen, &screen->startH); 3406d522f475Smrg screen->endHCoord = Coordinate(screen, &screen->endH); 3407d522f475Smrg} 3408d522f475Smrg 3409d522f475Smrg/*ARGSUSED*/ 3410d522f475Smrgvoid 3411f2e35a3aSmrgResizeSelection(TScreen *screen, int rows, int cols) 3412d522f475Smrg{ 3413d522f475Smrg rows--; /* decr to get 0-max */ 3414d522f475Smrg cols--; 3415d522f475Smrg 3416d522f475Smrg if (screen->startRaw.row > rows) 3417d522f475Smrg screen->startRaw.row = rows; 3418d522f475Smrg if (screen->startSel.row > rows) 3419d522f475Smrg screen->startSel.row = rows; 3420d522f475Smrg if (screen->endRaw.row > rows) 3421d522f475Smrg screen->endRaw.row = rows; 3422d522f475Smrg if (screen->endSel.row > rows) 3423d522f475Smrg screen->endSel.row = rows; 3424d522f475Smrg if (screen->rawPos.row > rows) 3425d522f475Smrg screen->rawPos.row = rows; 3426d522f475Smrg 3427d522f475Smrg if (screen->startRaw.col > cols) 3428d522f475Smrg screen->startRaw.col = cols; 3429d522f475Smrg if (screen->startSel.col > cols) 3430d522f475Smrg screen->startSel.col = cols; 3431d522f475Smrg if (screen->endRaw.col > cols) 3432d522f475Smrg screen->endRaw.col = cols; 3433d522f475Smrg if (screen->endSel.col > cols) 3434d522f475Smrg screen->endSel.col = cols; 3435d522f475Smrg if (screen->rawPos.col > cols) 3436d522f475Smrg screen->rawPos.col = cols; 3437d522f475Smrg} 3438d522f475Smrg 3439d522f475Smrg#if OPT_WIDE_CHARS 3440f2e35a3aSmrg#define isWideCell(row, col) isWideFrg((int)XTERM_CELL(row, col)) 3441d522f475Smrg#endif 3442d522f475Smrg 3443d522f475Smrgstatic void 3444e0a2b6dfSmrgPointToCELL(TScreen *screen, 3445d522f475Smrg int y, 3446d522f475Smrg int x, 3447e0a2b6dfSmrg CELL *cell) 3448d522f475Smrg/* Convert pixel coordinates to character coordinates. 3449d522f475Smrg Rows are clipped between firstValidRow and lastValidRow. 3450d522f475Smrg Columns are clipped between to be 0 or greater, but are not clipped to some 3451d522f475Smrg maximum value. */ 3452d522f475Smrg{ 3453d522f475Smrg cell->row = (y - screen->border) / FontHeight(screen); 3454d522f475Smrg if (cell->row < screen->firstValidRow) 3455d522f475Smrg cell->row = screen->firstValidRow; 3456d522f475Smrg else if (cell->row > screen->lastValidRow) 3457d522f475Smrg cell->row = screen->lastValidRow; 3458d522f475Smrg cell->col = (x - OriginX(screen)) / FontWidth(screen); 3459d522f475Smrg if (cell->col < 0) 3460d522f475Smrg cell->col = 0; 3461d522f475Smrg else if (cell->col > MaxCols(screen)) { 3462d522f475Smrg cell->col = MaxCols(screen); 3463d522f475Smrg } 3464d522f475Smrg#if OPT_WIDE_CHARS 3465d522f475Smrg /* 3466d522f475Smrg * If we got a click on the right half of a doublewidth character, 3467d522f475Smrg * pretend it happened on the left half. 3468d522f475Smrg */ 3469d522f475Smrg if (cell->col > 0 3470d522f475Smrg && isWideCell(cell->row, cell->col - 1) 3471d522f475Smrg && (XTERM_CELL(cell->row, cell->col) == HIDDEN_CHAR)) { 3472d522f475Smrg cell->col -= 1; 3473d522f475Smrg } 3474d522f475Smrg#endif 3475d522f475Smrg} 3476d522f475Smrg 3477d522f475Smrg/* 3478d522f475Smrg * Find the last column at which text was drawn on the given row. 3479d522f475Smrg */ 3480d522f475Smrgstatic int 348101037d57SmrgLastTextCol(TScreen *screen, CLineData *ld, int row) 3482d522f475Smrg{ 348320d2c4d2Smrg int i = -1; 3484d522f475Smrg 34855104ee6eSmrg if (ld != NULL) { 348620d2c4d2Smrg if (okScrnRow(screen, row)) { 34872e4f8982Smrg const IAttr *ch; 348820d2c4d2Smrg for (i = screen->max_col, 348920d2c4d2Smrg ch = ld->attribs + i; 349020d2c4d2Smrg i >= 0 && !(*ch & CHARDRAWN); 349120d2c4d2Smrg ch--, i--) { 349220d2c4d2Smrg ; 349320d2c4d2Smrg } 3494d522f475Smrg#if OPT_DEC_CHRSET 349520d2c4d2Smrg if (CSET_DOUBLE(GetLineDblCS(ld))) { 349620d2c4d2Smrg i *= 2; 349720d2c4d2Smrg } 3498d522f475Smrg#endif 349920d2c4d2Smrg } 3500d522f475Smrg } 3501d522f475Smrg return (i); 3502d522f475Smrg} 3503d522f475Smrg 3504d522f475Smrg#if !OPT_WIDE_CHARS 3505d522f475Smrg/* 3506d522f475Smrg** double click table for cut and paste in 8 bits 3507d522f475Smrg** 3508d522f475Smrg** This table is divided in four parts : 3509d522f475Smrg** 3510d522f475Smrg** - control characters [0,0x1f] U [0x80,0x9f] 3511d522f475Smrg** - separators [0x20,0x3f] U [0xa0,0xb9] 3512d522f475Smrg** - binding characters [0x40,0x7f] U [0xc0,0xff] 3513d522f475Smrg** - exceptions 3514d522f475Smrg*/ 3515d522f475Smrg/* *INDENT-OFF* */ 3516d522f475Smrgstatic int charClass[256] = 3517d522f475Smrg{ 3518d522f475Smrg/* NUL SOH STX ETX EOT ENQ ACK BEL */ 3519d522f475Smrg 32, 1, 1, 1, 1, 1, 1, 1, 35200bd37d32Smrg/* BS HT NL VT FF CR SO SI */ 3521d522f475Smrg 1, 32, 1, 1, 1, 1, 1, 1, 3522d522f475Smrg/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 3523d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3524d522f475Smrg/* CAN EM SUB ESC FS GS RS US */ 3525d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3526d522f475Smrg/* SP ! " # $ % & ' */ 3527d522f475Smrg 32, 33, 34, 35, 36, 37, 38, 39, 3528d522f475Smrg/* ( ) * + , - . / */ 3529d522f475Smrg 40, 41, 42, 43, 44, 45, 46, 47, 3530d522f475Smrg/* 0 1 2 3 4 5 6 7 */ 3531d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3532d522f475Smrg/* 8 9 : ; < = > ? */ 3533d522f475Smrg 48, 48, 58, 59, 60, 61, 62, 63, 3534d522f475Smrg/* @ A B C D E F G */ 3535d522f475Smrg 64, 48, 48, 48, 48, 48, 48, 48, 3536d522f475Smrg/* H I J K L M N O */ 3537d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3538d522f475Smrg/* P Q R S T U V W */ 3539d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3540d522f475Smrg/* X Y Z [ \ ] ^ _ */ 3541d522f475Smrg 48, 48, 48, 91, 92, 93, 94, 48, 3542d522f475Smrg/* ` a b c d e f g */ 3543d522f475Smrg 96, 48, 48, 48, 48, 48, 48, 48, 3544d522f475Smrg/* h i j k l m n o */ 3545d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3546d522f475Smrg/* p q r s t u v w */ 3547d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3548d522f475Smrg/* x y z { | } ~ DEL */ 3549d522f475Smrg 48, 48, 48, 123, 124, 125, 126, 1, 3550d522f475Smrg/* x80 x81 x82 x83 IND NEL SSA ESA */ 3551d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3552d522f475Smrg/* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 3553d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3554d522f475Smrg/* DCS PU1 PU2 STS CCH MW SPA EPA */ 3555d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3556d522f475Smrg/* x98 x99 x9A CSI ST OSC PM APC */ 3557d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3558d522f475Smrg/* - i c/ L ox Y- | So */ 3559d522f475Smrg 160, 161, 162, 163, 164, 165, 166, 167, 3560d522f475Smrg/* .. c0 ip << _ R0 - */ 3561d522f475Smrg 168, 169, 170, 171, 172, 173, 174, 175, 3562d522f475Smrg/* o +- 2 3 ' u q| . */ 3563d522f475Smrg 176, 177, 178, 179, 180, 181, 182, 183, 3564d522f475Smrg/* , 1 2 >> 1/4 1/2 3/4 ? */ 3565d522f475Smrg 184, 185, 186, 187, 188, 189, 190, 191, 3566d522f475Smrg/* A` A' A^ A~ A: Ao AE C, */ 3567d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3568d522f475Smrg/* E` E' E^ E: I` I' I^ I: */ 3569d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3570d522f475Smrg/* D- N~ O` O' O^ O~ O: X */ 3571d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 215, 3572d522f475Smrg/* O/ U` U' U^ U: Y' P B */ 3573d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3574d522f475Smrg/* a` a' a^ a~ a: ao ae c, */ 3575d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3576d522f475Smrg/* e` e' e^ e: i` i' i^ i: */ 3577d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3578d522f475Smrg/* d n~ o` o' o^ o~ o: -: */ 3579d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 247, 3580d522f475Smrg/* o/ u` u' u^ u: y' P y: */ 3581d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48}; 3582d522f475Smrg/* *INDENT-ON* */ 3583d522f475Smrg 3584d522f475Smrgint 3585d522f475SmrgSetCharacterClassRange(int low, /* in range of [0..255] */ 3586d522f475Smrg int high, 3587d522f475Smrg int value) /* arbitrary */ 3588d522f475Smrg{ 3589d522f475Smrg 3590d522f475Smrg if (low < 0 || high > 255 || high < low) 3591d522f475Smrg return (-1); 3592d522f475Smrg 3593d522f475Smrg for (; low <= high; low++) 3594d522f475Smrg charClass[low] = value; 3595d522f475Smrg 3596d522f475Smrg return (0); 3597d522f475Smrg} 3598d522f475Smrg#endif 3599d522f475Smrg 3600d522f475Smrgstatic int 36015104ee6eSmrgclass_of(LineData *ld, const CELL *cell) 3602d522f475Smrg{ 3603d522f475Smrg CELL temp = *cell; 36040bd37d32Smrg int result = 0; 3605d522f475Smrg 3606d522f475Smrg#if OPT_DEC_CHRSET 3607956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 3608d522f475Smrg temp.col /= 2; 3609d522f475Smrg } 3610d522f475Smrg#endif 36110bd37d32Smrg if (temp.col < (int) ld->lineSize) 36120bd37d32Smrg result = CharacterClass((int) (ld->charData[temp.col])); 36130bd37d32Smrg return result; 3614d522f475Smrg} 3615956cc18dSsnj 3616956cc18dSsnj#if OPT_WIDE_CHARS 3617956cc18dSsnj#define CClassSelects(name, cclass) \ 3618956cc18dSsnj (CClassOf(name) == cclass \ 3619956cc18dSsnj || XTERM_CELL(screen->name.row, screen->name.col) == HIDDEN_CHAR) 3620d522f475Smrg#else 3621956cc18dSsnj#define CClassSelects(name, cclass) \ 3622956cc18dSsnj (class_of(ld.name, &((screen->name))) == cclass) 3623d522f475Smrg#endif 3624d522f475Smrg 3625956cc18dSsnj#define CClassOf(name) class_of(ld.name, &((screen->name))) 3626956cc18dSsnj 3627913cc679Smrg#if OPT_REPORT_CCLASS 3628913cc679Smrgstatic int 3629913cc679Smrgshow_cclass_range(int lo, int hi) 3630913cc679Smrg{ 3631913cc679Smrg int cclass = CharacterClass(lo); 3632913cc679Smrg int ident = (cclass == lo); 3633913cc679Smrg int more = 0; 3634913cc679Smrg if (ident) { 3635913cc679Smrg int ch; 3636913cc679Smrg for (ch = lo + 1; ch <= hi; ch++) { 3637913cc679Smrg if (CharacterClass(ch) != ch) { 3638913cc679Smrg ident = 0; 3639913cc679Smrg break; 3640913cc679Smrg } 3641913cc679Smrg } 3642913cc679Smrg if (ident && (hi < 255)) { 3643913cc679Smrg ch = hi + 1; 3644913cc679Smrg if (CharacterClass(ch) == ch) { 3645913cc679Smrg if (ch >= 255 || CharacterClass(ch + 1) != ch) { 3646913cc679Smrg more = 1; 3647913cc679Smrg } 3648913cc679Smrg } 3649913cc679Smrg } 3650913cc679Smrg } 3651913cc679Smrg if (!more) { 3652913cc679Smrg if (lo == hi) { 3653913cc679Smrg printf("\t%d", lo); 3654913cc679Smrg } else { 3655913cc679Smrg printf("\t%d-%d", lo, hi); 3656913cc679Smrg } 3657913cc679Smrg if (!ident) 3658913cc679Smrg printf(":%d", cclass); 3659913cc679Smrg if (hi < 255) 3660913cc679Smrg printf(", \\"); 3661913cc679Smrg printf("\n"); 3662913cc679Smrg } 3663913cc679Smrg return !more; 3664913cc679Smrg} 3665913cc679Smrg 3666913cc679Smrgvoid 3667913cc679Smrgreport_char_class(XtermWidget xw) 3668913cc679Smrg{ 3669913cc679Smrg /* simple table, to match documentation */ 3670913cc679Smrg static const char charnames[] = 3671913cc679Smrg "NUL\0" "SOH\0" "STX\0" "ETX\0" "EOT\0" "ENQ\0" "ACK\0" "BEL\0" 3672913cc679Smrg " BS\0" " HT\0" " NL\0" " VT\0" " NP\0" " CR\0" " SO\0" " SI\0" 3673913cc679Smrg "DLE\0" "DC1\0" "DC2\0" "DC3\0" "DC4\0" "NAK\0" "SYN\0" "ETB\0" 3674913cc679Smrg "CAN\0" " EM\0" "SUB\0" "ESC\0" " FS\0" " GS\0" " RS\0" " US\0" 3675913cc679Smrg " SP\0" " !\0" " \"\0" " #\0" " $\0" " %\0" " &\0" " '\0" 3676913cc679Smrg " (\0" " )\0" " *\0" " +\0" " ,\0" " -\0" " .\0" " /\0" 3677913cc679Smrg " 0\0" " 1\0" " 2\0" " 3\0" " 4\0" " 5\0" " 6\0" " 7\0" 3678913cc679Smrg " 8\0" " 9\0" " :\0" " ;\0" " <\0" " =\0" " >\0" " ?\0" 3679913cc679Smrg " @\0" " A\0" " B\0" " C\0" " D\0" " E\0" " F\0" " G\0" 3680913cc679Smrg " H\0" " I\0" " J\0" " K\0" " L\0" " M\0" " N\0" " O\0" 3681913cc679Smrg " P\0" " Q\0" " R\0" " S\0" " T\0" " U\0" " V\0" " W\0" 3682913cc679Smrg " X\0" " Y\0" " Z\0" " [\0" " \\\0" " ]\0" " ^\0" " _\0" 3683913cc679Smrg " `\0" " a\0" " b\0" " c\0" " d\0" " e\0" " f\0" " g\0" 3684913cc679Smrg " h\0" " i\0" " j\0" " k\0" " l\0" " m\0" " n\0" " o\0" 3685913cc679Smrg " p\0" " q\0" " r\0" " s\0" " t\0" " u\0" " v\0" " w\0" 3686913cc679Smrg " x\0" " y\0" " z\0" " {\0" " |\0" " }\0" " ~\0" "DEL\0" 3687913cc679Smrg "x80\0" "x81\0" "x82\0" "x83\0" "IND\0" "NEL\0" "SSA\0" "ESA\0" 3688913cc679Smrg "HTS\0" "HTJ\0" "VTS\0" "PLD\0" "PLU\0" " RI\0" "SS2\0" "SS3\0" 3689913cc679Smrg "DCS\0" "PU1\0" "PU2\0" "STS\0" "CCH\0" " MW\0" "SPA\0" "EPA\0" 3690913cc679Smrg "x98\0" "x99\0" "x9A\0" "CSI\0" " ST\0" "OSC\0" " PM\0" "APC\0" 3691913cc679Smrg " -\0" " i\0" " c/\0" " L\0" " ox\0" " Y-\0" " |\0" " So\0" 3692913cc679Smrg " ..\0" " c0\0" " ip\0" " <<\0" " _\0" " \0" " R0\0" " -\0" 3693913cc679Smrg " o\0" " +-\0" " 2\0" " 3\0" " '\0" " u\0" " q|\0" " .\0" 3694913cc679Smrg " ,\0" " 1\0" " 2\0" " >>\0" "1/4\0" "1/2\0" "3/4\0" " ?\0" 3695913cc679Smrg " A`\0" " A'\0" " A^\0" " A~\0" " A:\0" " Ao\0" " AE\0" " C,\0" 3696913cc679Smrg " E`\0" " E'\0" " E^\0" " E:\0" " I`\0" " I'\0" " I^\0" " I:\0" 3697913cc679Smrg " D-\0" " N~\0" " O`\0" " O'\0" " O^\0" " O~\0" " O:\0" " X\0" 3698913cc679Smrg " O/\0" " U`\0" " U'\0" " U^\0" " U:\0" " Y'\0" " P\0" " B\0" 3699913cc679Smrg " a`\0" " a'\0" " a^\0" " a~\0" " a:\0" " ao\0" " ae\0" " c,\0" 3700913cc679Smrg " e`\0" " e'\0" " e^\0" " e:\0" " i`\0" " i'\0" " i^\0" " i:\0" 3701913cc679Smrg " d\0" " n~\0" " o`\0" " o'\0" " o^\0" " o~\0" " o:\0" " -:\0" 3702913cc679Smrg " o/\0" " u`\0" " u'\0" " u^\0" " u:\0" " y'\0" " P\0" " y:\0"; 3703913cc679Smrg int ch, dh; 3704913cc679Smrg int class_p; 3705913cc679Smrg 3706913cc679Smrg (void) xw; 3707913cc679Smrg 3708913cc679Smrg printf("static int charClass[256] = {\n"); 3709913cc679Smrg for (ch = 0; ch < 256; ++ch) { 3710913cc679Smrg const char *s = charnames + (ch * 4); 3711913cc679Smrg if ((ch & 7) == 0) 3712913cc679Smrg printf("/*"); 3713913cc679Smrg printf(" %s ", s); 3714913cc679Smrg if (((ch + 1) & 7) == 0) { 3715913cc679Smrg printf("*/\n "); 3716913cc679Smrg for (dh = ch - 7; dh <= ch; ++dh) { 3717913cc679Smrg printf(" %3d%s", CharacterClass(dh), dh == 255 ? "};" : ","); 3718913cc679Smrg } 3719913cc679Smrg printf("\n"); 3720913cc679Smrg } 3721913cc679Smrg } 3722913cc679Smrg 3723913cc679Smrg /* print the table as if it were the charClass resource */ 3724913cc679Smrg printf("\n"); 3725913cc679Smrg printf("The table is equivalent to this \"charClass\" resource:\n"); 3726913cc679Smrg class_p = CharacterClass(dh = 0); 3727913cc679Smrg for (ch = 0; ch < 256; ++ch) { 3728913cc679Smrg int class_c = CharacterClass(ch); 3729913cc679Smrg if (class_c != class_p) { 3730913cc679Smrg if (show_cclass_range(dh, ch - 1)) { 3731913cc679Smrg dh = ch; 3732913cc679Smrg class_p = class_c; 3733913cc679Smrg } 3734913cc679Smrg } 3735913cc679Smrg } 3736913cc679Smrg if (dh < 255) { 3737913cc679Smrg show_cclass_range(dh, 255); 3738913cc679Smrg } 3739913cc679Smrg 3740913cc679Smrg if_OPT_WIDE_CHARS(TScreenOf(xw), { 3741913cc679Smrg /* if this is a wide-character configuration, print all intervals */ 3742913cc679Smrg report_wide_char_class(); 3743913cc679Smrg }); 3744913cc679Smrg} 3745913cc679Smrg#endif 3746913cc679Smrg 3747d522f475Smrg/* 3748d522f475Smrg * If the given column is past the end of text on the given row, bump to the 3749d522f475Smrg * beginning of the next line. 3750d522f475Smrg */ 3751d522f475Smrgstatic Boolean 3752e0a2b6dfSmrgokPosition(TScreen *screen, 3753e0a2b6dfSmrg LineData **ld, 3754e0a2b6dfSmrg CELL *cell) 3755d522f475Smrg{ 375620d2c4d2Smrg Boolean result = True; 375720d2c4d2Smrg 37585104ee6eSmrg assert(ld != NULL); 37595104ee6eSmrg assert(*ld != NULL); 37605104ee6eSmrg 37615104ee6eSmrg if (*ld == NULL) { 37625104ee6eSmrg result = False; 37635104ee6eSmrg TRACE(("okPosition LineData is null!\n")); 37645104ee6eSmrg } else if (cell->row > screen->max_row) { 376520d2c4d2Smrg result = False; 3766f2e35a3aSmrg TRACE(("okPosition cell row %d > screen max %d\n", cell->row, screen->max_row)); 376720d2c4d2Smrg } else if (cell->col > (LastTextCol(screen, *ld, cell->row) + 1)) { 3768f2e35a3aSmrg TRACE(("okPosition cell col %d > screen max %d\n", cell->col, 3769f2e35a3aSmrg (LastTextCol(screen, *ld, cell->row) + 1))); 377020d2c4d2Smrg if (cell->row < screen->max_row) { 3771f2e35a3aSmrg TRACE(("okPosition cell row %d < screen max %d\n", cell->row, screen->max_row)); 377220d2c4d2Smrg cell->col = 0; 377320d2c4d2Smrg *ld = GET_LINEDATA(screen, ++cell->row); 377420d2c4d2Smrg result = False; 377520d2c4d2Smrg } 3776d522f475Smrg } 377720d2c4d2Smrg return result; 3778d522f475Smrg} 3779d522f475Smrg 3780d522f475Smrgstatic void 3781e0a2b6dfSmrgtrimLastLine(TScreen *screen, 3782e0a2b6dfSmrg LineData **ld, 3783e0a2b6dfSmrg CELL *last) 3784d522f475Smrg{ 378520d2c4d2Smrg if (screen->cutNewline && last->row < screen->max_row) { 3786d522f475Smrg last->col = 0; 3787956cc18dSsnj *ld = GET_LINEDATA(screen, ++last->row); 3788d522f475Smrg } else { 3789956cc18dSsnj last->col = LastTextCol(screen, *ld, last->row) + 1; 3790d522f475Smrg } 3791d522f475Smrg} 3792d522f475Smrg 3793d522f475Smrg#if OPT_SELECT_REGEX 3794d522f475Smrg/* 3795d522f475Smrg * Returns the first row of a wrapped line. 3796d522f475Smrg */ 3797d522f475Smrgstatic int 3798e0a2b6dfSmrgfirstRowOfLine(TScreen *screen, int row, Bool visible) 3799d522f475Smrg{ 38005104ee6eSmrg LineData *ld = NULL; 3801d522f475Smrg int limit = visible ? 0 : -screen->savedlines; 3802d522f475Smrg 3803d522f475Smrg while (row > limit && 38045104ee6eSmrg (ld = GET_LINEDATA(screen, row - 1)) != NULL && 3805956cc18dSsnj LineTstWrapped(ld)) { 3806d522f475Smrg --row; 3807956cc18dSsnj } 3808d522f475Smrg return row; 3809d522f475Smrg} 3810d522f475Smrg 3811d522f475Smrg/* 3812d522f475Smrg * Returns the last row of a wrapped line. 3813d522f475Smrg */ 3814d522f475Smrgstatic int 3815e0a2b6dfSmrglastRowOfLine(TScreen *screen, int row) 3816d522f475Smrg{ 3817956cc18dSsnj LineData *ld; 3818956cc18dSsnj 3819d522f475Smrg while (row < screen->max_row && 38205104ee6eSmrg (ld = GET_LINEDATA(screen, row)) != NULL && 3821956cc18dSsnj LineTstWrapped(ld)) { 3822d522f475Smrg ++row; 3823956cc18dSsnj } 3824d522f475Smrg return row; 3825d522f475Smrg} 3826d522f475Smrg 3827d522f475Smrg/* 3828d522f475Smrg * Returns the number of cells on the range of rows. 3829d522f475Smrg */ 3830d522f475Smrgstatic unsigned 3831e0a2b6dfSmrglengthOfLines(TScreen *screen, int firstRow, int lastRow) 3832d522f475Smrg{ 3833d522f475Smrg unsigned length = 0; 3834d522f475Smrg int n; 3835d522f475Smrg 3836d522f475Smrg for (n = firstRow; n <= lastRow; ++n) { 3837956cc18dSsnj LineData *ld = GET_LINEDATA(screen, n); 3838956cc18dSsnj int value = LastTextCol(screen, ld, n); 3839d522f475Smrg if (value >= 0) 38402eaa94a1Schristos length += (unsigned) (value + 1); 3841d522f475Smrg } 3842d522f475Smrg return length; 3843d522f475Smrg} 3844d522f475Smrg 3845d522f475Smrg/* 3846d522f475Smrg * Make a copy of the wrapped-line which corresponds to the given row as a 3847d522f475Smrg * string of bytes. Construct an index for the columns from the beginning of 3848d522f475Smrg * the line. 3849d522f475Smrg */ 3850d522f475Smrgstatic char * 3851e0a2b6dfSmrgmake_indexed_text(TScreen *screen, int row, unsigned length, int *indexed) 3852d522f475Smrg{ 38535104ee6eSmrg Char *result = NULL; 385420d2c4d2Smrg size_t need = (length + 1); 3855d522f475Smrg 3856d522f475Smrg /* 3857d522f475Smrg * Get a quick upper bound to the number of bytes needed, if the whole 3858d522f475Smrg * string were UTF-8. 3859d522f475Smrg */ 3860d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3861956cc18dSsnj need *= ((screen->lineExtra + 1) * 6); 3862d522f475Smrg }); 3863d522f475Smrg 38645104ee6eSmrg if ((result = TypeCallocN(Char, need + 1)) != NULL) { 3865956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 3866d522f475Smrg unsigned used = 0; 3867d522f475Smrg Char *last = result; 3868d522f475Smrg 3869d522f475Smrg do { 3870d522f475Smrg int col = 0; 3871956cc18dSsnj int limit = LastTextCol(screen, ld, row); 3872d522f475Smrg 3873d522f475Smrg while (col <= limit) { 3874d522f475Smrg Char *next = last; 3875956cc18dSsnj unsigned data = ld->charData[col]; 3876d522f475Smrg 38770bd37d32Smrg assert(col < (int) ld->lineSize); 3878d522f475Smrg /* some internal points may not be drawn */ 3879d522f475Smrg if (data == 0) 3880d522f475Smrg data = ' '; 3881d522f475Smrg 3882d522f475Smrg if_WIDE_OR_NARROW(screen, { 3883d522f475Smrg next = convertToUTF8(last, data); 3884d522f475Smrg } 3885d522f475Smrg , { 3886d522f475Smrg *next++ = CharOf(data); 3887d522f475Smrg }); 3888d522f475Smrg 3889d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3890956cc18dSsnj size_t off; 3891956cc18dSsnj for_each_combData(off, ld) { 3892956cc18dSsnj data = ld->combData[off][col]; 3893956cc18dSsnj if (data == 0) 3894d522f475Smrg break; 3895d522f475Smrg next = convertToUTF8(next, data); 3896d522f475Smrg } 3897d522f475Smrg }); 3898d522f475Smrg 389920d2c4d2Smrg indexed[used] = (int) (last - result); 3900d522f475Smrg *next = 0; 3901d522f475Smrg /* TRACE(("index[%d.%d] %d:%s\n", row, used, indexed[used], last)); */ 3902d522f475Smrg last = next; 3903d522f475Smrg ++used; 3904d522f475Smrg ++col; 390520d2c4d2Smrg indexed[used] = (int) (next - result); 3906d522f475Smrg } 3907d522f475Smrg } while (used < length && 3908956cc18dSsnj LineTstWrapped(ld) && 39095104ee6eSmrg (ld = GET_LINEDATA(screen, ++row)) != NULL && 3910956cc18dSsnj row < screen->max_row); 3911d522f475Smrg } 3912d522f475Smrg /* TRACE(("result:%s\n", result)); */ 3913d522f475Smrg return (char *) result; 3914d522f475Smrg} 3915d522f475Smrg 3916d522f475Smrg/* 3917d522f475Smrg * Find the column given an offset into the character string by using the 3918d522f475Smrg * index constructed in make_indexed_text(). 3919d522f475Smrg */ 3920d522f475Smrgstatic int 39215104ee6eSmrgindexToCol(const int *indexed, int len, int off) 3922d522f475Smrg{ 3923d522f475Smrg int col = 0; 3924d522f475Smrg while (indexed[col] < len) { 3925d522f475Smrg if (indexed[col] >= off) 3926d522f475Smrg break; 3927d522f475Smrg ++col; 3928d522f475Smrg } 3929d522f475Smrg return col; 3930d522f475Smrg} 3931d522f475Smrg 3932d522f475Smrg/* 3933d522f475Smrg * Given a row number, and a column offset from that (which may be wrapped), 3934d522f475Smrg * set the cell to the actual row/column values. 3935d522f475Smrg */ 3936d522f475Smrgstatic void 3937e0a2b6dfSmrgcolumnToCell(TScreen *screen, int row, int col, CELL *cell) 3938d522f475Smrg{ 3939d522f475Smrg while (row < screen->max_row) { 394001037d57Smrg CLineData *ld = GET_LINEDATA(screen, row); 3941956cc18dSsnj int last = LastTextCol(screen, ld, row); 3942d522f475Smrg 3943d522f475Smrg /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */ 3944d522f475Smrg if (col <= last) { 3945d522f475Smrg break; 3946d522f475Smrg } 3947d522f475Smrg /* 3948d522f475Smrg * Stop if the current row does not wrap (does not continue the current 3949d522f475Smrg * line). 3950d522f475Smrg */ 3951956cc18dSsnj if (!LineTstWrapped(ld)) { 3952d522f475Smrg col = last + 1; 3953d522f475Smrg break; 3954d522f475Smrg } 3955d522f475Smrg col -= (last + 1); 3956d522f475Smrg ++row; 3957d522f475Smrg } 3958d522f475Smrg if (col < 0) 3959d522f475Smrg col = 0; 3960d522f475Smrg cell->row = row; 3961d522f475Smrg cell->col = col; 3962d522f475Smrg} 3963d522f475Smrg 3964d522f475Smrg/* 3965d522f475Smrg * Given a cell, find the corresponding column offset. 3966d522f475Smrg */ 3967d522f475Smrgstatic int 3968e0a2b6dfSmrgcellToColumn(TScreen *screen, CELL *cell) 3969d522f475Smrg{ 39705104ee6eSmrg CLineData *ld = NULL; 3971d522f475Smrg int col = cell->col; 3972d522f475Smrg int row = firstRowOfLine(screen, cell->row, False); 3973d522f475Smrg while (row < cell->row) { 3974956cc18dSsnj ld = GET_LINEDATA(screen, row); 3975956cc18dSsnj col += LastTextCol(screen, ld, row++); 3976d522f475Smrg } 3977956cc18dSsnj#if OPT_DEC_CHRSET 39785104ee6eSmrg if (ld == NULL) 3979956cc18dSsnj ld = GET_LINEDATA(screen, row); 3980956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3981956cc18dSsnj col /= 2; 3982956cc18dSsnj#endif 3983d522f475Smrg return col; 3984d522f475Smrg} 3985d522f475Smrg 3986d522f475Smrgstatic void 3987e0a2b6dfSmrgdo_select_regex(TScreen *screen, CELL *startc, CELL *endc) 3988d522f475Smrg{ 3989956cc18dSsnj LineData *ld = GET_LINEDATA(screen, startc->row); 3990d522f475Smrg int inx = ((screen->numberOfClicks - 1) % screen->maxClicks); 3991d522f475Smrg char *expr = screen->selectExpr[inx]; 3992d522f475Smrg regex_t preg; 3993d522f475Smrg regmatch_t match; 3994d522f475Smrg 399501037d57Smrg TRACE(("Select_REGEX[%d]:%s\n", inx, NonNull(expr))); 39965104ee6eSmrg if (okPosition(screen, &ld, startc) && expr != NULL) { 3997d522f475Smrg if (regcomp(&preg, expr, REG_EXTENDED) == 0) { 3998d522f475Smrg int firstRow = firstRowOfLine(screen, startc->row, True); 3999d522f475Smrg int lastRow = lastRowOfLine(screen, firstRow); 4000d522f475Smrg unsigned size = lengthOfLines(screen, firstRow, lastRow); 4001d522f475Smrg int actual = cellToColumn(screen, startc); 40022e4f8982Smrg int *indexed; 4003d522f475Smrg 4004d522f475Smrg TRACE(("regcomp ok rows %d..%d bytes %d\n", 4005d522f475Smrg firstRow, lastRow, size)); 4006d522f475Smrg 40075104ee6eSmrg if ((indexed = TypeCallocN(int, size + 1)) != NULL) { 40082e4f8982Smrg char *search; 4009d522f475Smrg if ((search = make_indexed_text(screen, 4010d522f475Smrg firstRow, 4011d522f475Smrg size, 40125104ee6eSmrg indexed)) != NULL) { 40132eaa94a1Schristos int len = (int) strlen(search); 4014d522f475Smrg int col; 401504b94745Smrg int offset; 4016d522f475Smrg int best_col = -1; 4017d522f475Smrg int best_len = -1; 4018d522f475Smrg 4019913cc679Smrg startc->row = 0; 4020913cc679Smrg startc->col = 0; 4021913cc679Smrg endc->row = 0; 4022913cc679Smrg endc->col = 0; 4023913cc679Smrg 402404b94745Smrg for (col = 0; (offset = indexed[col]) < len; ++col) { 4025d522f475Smrg if (regexec(&preg, 402604b94745Smrg search + offset, 402704b94745Smrg (size_t) 1, &match, 402804b94745Smrg col ? REG_NOTBOL : 0) == 0) { 402904b94745Smrg int start_inx = (int) (match.rm_so + offset); 403004b94745Smrg int finis_inx = (int) (match.rm_eo + offset); 4031d522f475Smrg int start_col = indexToCol(indexed, len, start_inx); 4032d522f475Smrg int finis_col = indexToCol(indexed, len, finis_inx); 4033d522f475Smrg 4034d522f475Smrg if (start_col <= actual && 4035913cc679Smrg actual <= finis_col) { 4036d522f475Smrg int test = finis_col - start_col; 4037d522f475Smrg if (best_len < test) { 4038d522f475Smrg best_len = test; 4039d522f475Smrg best_col = start_col; 4040d522f475Smrg TRACE(("match column %d len %d\n", 4041d522f475Smrg best_col, 4042d522f475Smrg best_len)); 4043d522f475Smrg } 4044d522f475Smrg } 4045d522f475Smrg } 4046d522f475Smrg } 4047d522f475Smrg if (best_col >= 0) { 4048d522f475Smrg int best_nxt = best_col + best_len; 4049d522f475Smrg columnToCell(screen, firstRow, best_col, startc); 4050d522f475Smrg columnToCell(screen, firstRow, best_nxt, endc); 4051d522f475Smrg TRACE(("search::%s\n", search)); 4052d522f475Smrg TRACE(("indexed:%d..%d -> %d..%d\n", 4053d522f475Smrg best_col, best_nxt, 4054d522f475Smrg indexed[best_col], 4055d522f475Smrg indexed[best_nxt])); 4056d522f475Smrg TRACE(("matched:%d:%s\n", 405704b94745Smrg indexed[best_nxt] - 4058d522f475Smrg indexed[best_col], 4059956cc18dSsnj visibleChars((Char *) (search + indexed[best_col]), 406004b94745Smrg (unsigned) (indexed[best_nxt] - 4061d522f475Smrg indexed[best_col])))); 4062d522f475Smrg } 4063d522f475Smrg free(search); 4064d522f475Smrg } 4065d522f475Smrg free(indexed); 4066956cc18dSsnj#if OPT_DEC_CHRSET 40675104ee6eSmrg if ((ld = GET_LINEDATA(screen, startc->row)) != NULL) { 4068956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 4069956cc18dSsnj startc->col *= 2; 4070956cc18dSsnj } 40715104ee6eSmrg if ((ld = GET_LINEDATA(screen, endc->row)) != NULL) { 4072956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 4073956cc18dSsnj endc->col *= 2; 4074956cc18dSsnj } 4075956cc18dSsnj#endif 4076d522f475Smrg } 4077d522f475Smrg regfree(&preg); 4078d522f475Smrg } 4079d522f475Smrg } 4080d522f475Smrg} 4081d522f475Smrg#endif /* OPT_SELECT_REGEX */ 4082d522f475Smrg 4083956cc18dSsnj#define InitRow(name) \ 4084956cc18dSsnj ld.name = GET_LINEDATA(screen, screen->name.row) 4085956cc18dSsnj 4086956cc18dSsnj#define NextRow(name) \ 4087956cc18dSsnj ld.name = GET_LINEDATA(screen, ++screen->name.row) 4088956cc18dSsnj 4089956cc18dSsnj#define PrevRow(name) \ 4090956cc18dSsnj ld.name = GET_LINEDATA(screen, --screen->name.row) 4091956cc18dSsnj 409220d2c4d2Smrg#define MoreRows(name) \ 409320d2c4d2Smrg (screen->name.row < screen->max_row) 409420d2c4d2Smrg 4095956cc18dSsnj#define isPrevWrapped(name) \ 4096956cc18dSsnj (screen->name.row > 0 \ 40975104ee6eSmrg && (ltmp = GET_LINEDATA(screen, screen->name.row - 1)) != NULL \ 4098956cc18dSsnj && LineTstWrapped(ltmp)) 4099956cc18dSsnj 4100d522f475Smrg/* 4101d522f475Smrg * sets startSel endSel 4102d522f475Smrg * ensuring that they have legal values 4103d522f475Smrg */ 4104d522f475Smrgstatic void 4105d522f475SmrgComputeSelect(XtermWidget xw, 41065104ee6eSmrg const CELL *startc, 41075104ee6eSmrg const CELL *endc, 4108f2e35a3aSmrg Bool extend, 4109f2e35a3aSmrg Bool normal) 4110d522f475Smrg{ 4111956cc18dSsnj TScreen *screen = TScreenOf(xw); 4112956cc18dSsnj 4113d522f475Smrg int cclass; 4114d522f475Smrg CELL first = *startc; 4115d522f475Smrg CELL last = *endc; 4116956cc18dSsnj Boolean ignored = False; 4117956cc18dSsnj 4118956cc18dSsnj struct { 4119956cc18dSsnj LineData *startSel; 4120956cc18dSsnj LineData *endSel; 4121956cc18dSsnj } ld; 4122956cc18dSsnj LineData *ltmp; 4123d522f475Smrg 4124d522f475Smrg TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n", 4125d522f475Smrg first.row, first.col, 4126d522f475Smrg last.row, last.col, 4127d522f475Smrg extend ? "" : "no")); 4128d522f475Smrg 4129d522f475Smrg#if OPT_WIDE_CHARS 4130d522f475Smrg if (first.col > 1 4131d522f475Smrg && isWideCell(first.row, first.col - 1) 4132d522f475Smrg && XTERM_CELL(first.row, first.col - 0) == HIDDEN_CHAR) { 413320d2c4d2Smrg TRACE(("Adjusting start. Changing downwards from %i.\n", first.col)); 4134d522f475Smrg first.col -= 1; 4135d522f475Smrg if (last.col == (first.col + 1)) 4136d522f475Smrg last.col--; 4137d522f475Smrg } 4138d522f475Smrg 4139d522f475Smrg if (last.col > 1 4140d522f475Smrg && isWideCell(last.row, last.col - 1) 4141d522f475Smrg && XTERM_CELL(last.row, last.col) == HIDDEN_CHAR) { 4142d522f475Smrg last.col += 1; 4143d522f475Smrg } 4144d522f475Smrg#endif 4145d522f475Smrg 4146d522f475Smrg if (Coordinate(screen, &first) <= Coordinate(screen, &last)) { 4147d522f475Smrg screen->startSel = screen->startRaw = first; 4148d522f475Smrg screen->endSel = screen->endRaw = last; 4149d522f475Smrg } else { /* Swap them */ 4150d522f475Smrg screen->startSel = screen->startRaw = last; 4151d522f475Smrg screen->endSel = screen->endRaw = first; 4152d522f475Smrg } 4153d522f475Smrg 4154956cc18dSsnj InitRow(startSel); 4155956cc18dSsnj InitRow(endSel); 4156956cc18dSsnj 4157d522f475Smrg switch (screen->selectUnit) { 4158d522f475Smrg case Select_CHAR: 41595104ee6eSmrg#if OPT_BLOCK_SELECT 41605104ee6eSmrg /* Allow block selecting past EOL */ 41615104ee6eSmrg if (screen->blockSelecting) 41625104ee6eSmrg break; 41635104ee6eSmrg#endif 4164956cc18dSsnj (void) okPosition(screen, &(ld.startSel), &(screen->startSel)); 4165956cc18dSsnj (void) okPosition(screen, &(ld.endSel), &(screen->endSel)); 4166d522f475Smrg break; 4167d522f475Smrg 4168d522f475Smrg case Select_WORD: 4169d522f475Smrg TRACE(("Select_WORD\n")); 4170956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 4171f2e35a3aSmrg CELL mark; 4172956cc18dSsnj cclass = CClassOf(startSel); 4173f2e35a3aSmrg TRACE(("...starting with class %d\n", cclass)); 4174d522f475Smrg do { 4175f2e35a3aSmrg mark = screen->startSel; 4176d522f475Smrg --screen->startSel.col; 4177956cc18dSsnj if (screen->startSel.col < 0 4178956cc18dSsnj && isPrevWrapped(startSel)) { 4179956cc18dSsnj PrevRow(startSel); 4180956cc18dSsnj screen->startSel.col = LastTextCol(screen, ld.startSel, screen->startSel.row); 4181d522f475Smrg } 4182d522f475Smrg } while (screen->startSel.col >= 0 4183956cc18dSsnj && CClassSelects(startSel, cclass)); 4184f2e35a3aSmrg if (normal) 4185f2e35a3aSmrg ++screen->startSel.col; 4186f2e35a3aSmrg else 4187f2e35a3aSmrg screen->startSel = mark; 4188d522f475Smrg } 4189d522f475Smrg#if OPT_WIDE_CHARS 4190f2e35a3aSmrg#define SkipHiddenCell(mark) \ 4191f2e35a3aSmrg if (mark.col && XTERM_CELL(mark.row, mark.col) == HIDDEN_CHAR) \ 4192f2e35a3aSmrg mark.col++ 4193f2e35a3aSmrg#else 4194f2e35a3aSmrg#define SkipHiddenCell(mark) /* nothing */ 4195d522f475Smrg#endif 4196f2e35a3aSmrg SkipHiddenCell(screen->startSel); 4197f2e35a3aSmrg 4198f2e35a3aSmrg if (!normal) { 4199f2e35a3aSmrg screen->endSel = screen->startSel; 4200f2e35a3aSmrg ld.endSel = ld.startSel; 4201f2e35a3aSmrg } 4202d522f475Smrg 4203956cc18dSsnj if (okPosition(screen, &(ld.endSel), &(screen->endSel))) { 42042e4f8982Smrg int length = LastTextCol(screen, ld.endSel, screen->endSel.row); 4205956cc18dSsnj cclass = CClassOf(endSel); 4206f2e35a3aSmrg TRACE(("...ending with class %d\n", cclass)); 4207d522f475Smrg do { 4208d522f475Smrg ++screen->endSel.col; 4209d522f475Smrg if (screen->endSel.col > length 4210956cc18dSsnj && LineTstWrapped(ld.endSel)) { 421120d2c4d2Smrg if (!MoreRows(endSel)) 421220d2c4d2Smrg break; 4213d522f475Smrg screen->endSel.col = 0; 4214956cc18dSsnj NextRow(endSel); 4215956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 4216d522f475Smrg } 4217d522f475Smrg } while (screen->endSel.col <= length 4218956cc18dSsnj && CClassSelects(endSel, cclass)); 4219f2e35a3aSmrg if (normal 4220f2e35a3aSmrg && screen->endSel.col > length + 1 422120d2c4d2Smrg && MoreRows(endSel)) { 4222d522f475Smrg screen->endSel.col = 0; 4223956cc18dSsnj NextRow(endSel); 4224d522f475Smrg } 4225d522f475Smrg } 4226f2e35a3aSmrg SkipHiddenCell(screen->endSel); 4227d522f475Smrg 4228d522f475Smrg screen->saveStartW = screen->startSel; 4229d522f475Smrg break; 4230d522f475Smrg 4231d522f475Smrg case Select_LINE: 4232d522f475Smrg TRACE(("Select_LINE\n")); 423320d2c4d2Smrg while (LineTstWrapped(ld.endSel) 423420d2c4d2Smrg && MoreRows(endSel)) { 4235956cc18dSsnj NextRow(endSel); 4236d522f475Smrg } 4237d522f475Smrg if (screen->cutToBeginningOfLine 4238d522f475Smrg || screen->startSel.row < screen->saveStartW.row) { 4239d522f475Smrg screen->startSel.col = 0; 4240956cc18dSsnj while (isPrevWrapped(startSel)) { 4241956cc18dSsnj PrevRow(startSel); 4242d522f475Smrg } 4243d522f475Smrg } else if (!extend) { 4244d522f475Smrg if ((first.row < screen->saveStartW.row) 4245d522f475Smrg || (isSameRow(&first, &(screen->saveStartW)) 4246d522f475Smrg && first.col < screen->saveStartW.col)) { 4247d522f475Smrg screen->startSel.col = 0; 4248956cc18dSsnj while (isPrevWrapped(startSel)) { 4249956cc18dSsnj PrevRow(startSel); 4250d522f475Smrg } 4251d522f475Smrg } else { 4252d522f475Smrg screen->startSel = screen->saveStartW; 4253d522f475Smrg } 4254d522f475Smrg } 4255956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 4256d522f475Smrg break; 4257d522f475Smrg 4258d522f475Smrg case Select_GROUP: /* paragraph */ 4259d522f475Smrg TRACE(("Select_GROUP\n")); 4260956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 4261d522f475Smrg /* scan backward for beginning of group */ 4262d522f475Smrg while (screen->startSel.row > 0 && 4263956cc18dSsnj (LastTextCol(screen, ld.startSel, screen->startSel.row - 4264956cc18dSsnj 1) > 0 || 4265956cc18dSsnj isPrevWrapped(startSel))) { 4266956cc18dSsnj PrevRow(startSel); 4267d522f475Smrg } 4268d522f475Smrg screen->startSel.col = 0; 4269d522f475Smrg /* scan forward for end of group */ 427020d2c4d2Smrg while (MoreRows(endSel) && 4271956cc18dSsnj (LastTextCol(screen, ld.endSel, screen->endSel.row + 1) > 4272956cc18dSsnj 0 || 4273956cc18dSsnj LineTstWrapped(ld.endSel))) { 4274956cc18dSsnj NextRow(endSel); 4275d522f475Smrg } 4276956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 4277d522f475Smrg } 4278d522f475Smrg break; 4279d522f475Smrg 4280d522f475Smrg case Select_PAGE: /* everything one can see */ 4281d522f475Smrg TRACE(("Select_PAGE\n")); 4282d522f475Smrg screen->startSel.row = 0; 4283d522f475Smrg screen->startSel.col = 0; 428420d2c4d2Smrg screen->endSel.row = MaxRows(screen); 4285d522f475Smrg screen->endSel.col = 0; 4286d522f475Smrg break; 4287d522f475Smrg 4288d522f475Smrg case Select_ALL: /* counts scrollback if in normal screen */ 4289d522f475Smrg TRACE(("Select_ALL\n")); 4290d522f475Smrg screen->startSel.row = -screen->savedlines; 4291d522f475Smrg screen->startSel.col = 0; 429220d2c4d2Smrg screen->endSel.row = MaxRows(screen); 4293d522f475Smrg screen->endSel.col = 0; 4294d522f475Smrg break; 4295d522f475Smrg 4296d522f475Smrg#if OPT_SELECT_REGEX 4297d522f475Smrg case Select_REGEX: 4298d522f475Smrg do_select_regex(screen, &(screen->startSel), &(screen->endSel)); 4299d522f475Smrg break; 4300d522f475Smrg#endif 4301d522f475Smrg 4302d522f475Smrg case NSELECTUNITS: /* always ignore */ 4303956cc18dSsnj ignored = True; 4304956cc18dSsnj break; 4305d522f475Smrg } 4306d522f475Smrg 4307956cc18dSsnj if (!ignored) { 4308956cc18dSsnj /* check boundaries */ 4309956cc18dSsnj ScrollSelection(screen, 0, False); 4310956cc18dSsnj TrackText(xw, &(screen->startSel), &(screen->endSel)); 4311956cc18dSsnj } 4312d522f475Smrg 4313d522f475Smrg return; 4314d522f475Smrg} 4315d522f475Smrg 4316d522f475Smrg/* Guaranteed (first.row, first.col) <= (last.row, last.col) */ 4317d522f475Smrgstatic void 4318d522f475SmrgTrackText(XtermWidget xw, 4319e0a2b6dfSmrg const CELL *firstp, 4320e0a2b6dfSmrg const CELL *lastp) 4321d522f475Smrg{ 4322956cc18dSsnj TScreen *screen = TScreenOf(xw); 4323d522f475Smrg int from, to; 4324d522f475Smrg CELL old_start, old_end; 4325d522f475Smrg CELL first = *firstp; 4326d522f475Smrg CELL last = *lastp; 4327d522f475Smrg 4328d522f475Smrg TRACE(("TrackText(first=%d,%d, last=%d,%d)\n", 4329d522f475Smrg first.row, first.col, last.row, last.col)); 4330d522f475Smrg 4331d522f475Smrg old_start = screen->startH; 4332d522f475Smrg old_end = screen->endH; 43330bd37d32Smrg TRACE(("...previous(first=%d,%d, last=%d,%d)\n", 43340bd37d32Smrg old_start.row, old_start.col, 43350bd37d32Smrg old_end.row, old_end.col)); 4336d522f475Smrg if (isSameCELL(&first, &old_start) && 43370bd37d32Smrg isSameCELL(&last, &old_end)) { 4338d522f475Smrg return; 43390bd37d32Smrg } 43400bd37d32Smrg 4341d522f475Smrg screen->startH = first; 4342d522f475Smrg screen->endH = last; 4343d522f475Smrg from = Coordinate(screen, &screen->startH); 4344d522f475Smrg to = Coordinate(screen, &screen->endH); 43455104ee6eSmrg if (to <= screen->startHCoord || from > screen->endHCoord 43465104ee6eSmrg#if OPT_BLOCK_SELECT 43475104ee6eSmrg || screen->blockSelecting 43485104ee6eSmrg || screen->blockSelecting != screen->lastSelectWasBlock 43495104ee6eSmrg#endif 43505104ee6eSmrg ) { 43515104ee6eSmrg#if OPT_BLOCK_SELECT 43525104ee6eSmrg /* Either no overlap whatsoever between old and new hilite, 43535104ee6eSmrg or we're in block select mode (or just came from it), 43545104ee6eSmrg in which case there is no optimization possible. */ 43555104ee6eSmrg if (screen->lastSelectWasBlock) { 43565104ee6eSmrg /* If we just came from block select mode, we need to 43575104ee6eSmrg unhighlight more aggressively. */ 43585104ee6eSmrg old_start.col = 0; 43595104ee6eSmrg old_end.col = MaxCols(screen); 43605104ee6eSmrg } 43615104ee6eSmrg#endif 4362d522f475Smrg ReHiliteText(xw, &old_start, &old_end); 4363d522f475Smrg ReHiliteText(xw, &first, &last); 4364d522f475Smrg } else { 4365d522f475Smrg if (from < screen->startHCoord) { 4366d522f475Smrg /* Extend left end */ 4367d522f475Smrg ReHiliteText(xw, &first, &old_start); 4368d522f475Smrg } else if (from > screen->startHCoord) { 4369d522f475Smrg /* Shorten left end */ 4370d522f475Smrg ReHiliteText(xw, &old_start, &first); 4371d522f475Smrg } 4372d522f475Smrg if (to > screen->endHCoord) { 4373d522f475Smrg /* Extend right end */ 4374d522f475Smrg ReHiliteText(xw, &old_end, &last); 4375d522f475Smrg } else if (to < screen->endHCoord) { 4376d522f475Smrg /* Shorten right end */ 4377d522f475Smrg ReHiliteText(xw, &last, &old_end); 4378d522f475Smrg } 4379d522f475Smrg } 4380d522f475Smrg screen->startHCoord = from; 4381d522f475Smrg screen->endHCoord = to; 4382d522f475Smrg} 4383d522f475Smrg 4384f2e35a3aSmrgstatic void 4385f2e35a3aSmrgUnHiliteText(XtermWidget xw) 4386f2e35a3aSmrg{ 4387f2e35a3aSmrg TrackText(xw, &zeroCELL, &zeroCELL); 4388f2e35a3aSmrg} 4389f2e35a3aSmrg 4390d522f475Smrg/* Guaranteed that (first->row, first->col) <= (last->row, last->col) */ 4391d522f475Smrgstatic void 4392d522f475SmrgReHiliteText(XtermWidget xw, 43935104ee6eSmrg const CELL *firstp, 43945104ee6eSmrg const CELL *lastp) 4395d522f475Smrg{ 4396956cc18dSsnj TScreen *screen = TScreenOf(xw); 4397d522f475Smrg CELL first = *firstp; 4398d522f475Smrg CELL last = *lastp; 4399d522f475Smrg 4400d522f475Smrg TRACE(("ReHiliteText from %d.%d to %d.%d\n", 4401d522f475Smrg first.row, first.col, last.row, last.col)); 4402d522f475Smrg 4403d522f475Smrg if (first.row < 0) 4404d522f475Smrg first.row = first.col = 0; 4405d522f475Smrg else if (first.row > screen->max_row) 4406d522f475Smrg return; /* nothing to do, since last.row >= first.row */ 4407d522f475Smrg 4408d522f475Smrg if (last.row < 0) 4409d522f475Smrg return; /* nothing to do, since first.row <= last.row */ 4410d522f475Smrg else if (last.row > screen->max_row) { 4411d522f475Smrg last.row = screen->max_row; 4412d522f475Smrg last.col = MaxCols(screen); 4413d522f475Smrg } 4414d522f475Smrg if (isSameCELL(&first, &last)) 4415d522f475Smrg return; 4416d522f475Smrg 44175104ee6eSmrg#if OPT_BLOCK_SELECT 44185104ee6eSmrg if (screen->blockSelecting) { 44195104ee6eSmrg /* In block select mode, there is no special case for the first or 44205104ee6eSmrg last rows. Also, unlike normal selections, there can be 44215104ee6eSmrg unselected text on both sides of the selection per row, so we 44225104ee6eSmrg refresh all columns. */ 44235104ee6eSmrg int row; 44245104ee6eSmrg for (row = first.row; row <= last.row; row++) { 44255104ee6eSmrg ScrnRefresh(xw, row, 0, 1, MaxCols(screen), True); 44265104ee6eSmrg } 44275104ee6eSmrg } else 44285104ee6eSmrg#endif 4429d522f475Smrg if (!isSameRow(&first, &last)) { /* do multiple rows */ 44302e4f8982Smrg int i; 4431d522f475Smrg if ((i = screen->max_col - first.col + 1) > 0) { /* first row */ 4432d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, i, True); 4433d522f475Smrg } 4434d522f475Smrg if ((i = last.row - first.row - 1) > 0) { /* middle rows */ 4435d522f475Smrg ScrnRefresh(xw, first.row + 1, 0, i, MaxCols(screen), True); 4436d522f475Smrg } 4437d522f475Smrg if (last.col > 0 && last.row <= screen->max_row) { /* last row */ 4438d522f475Smrg ScrnRefresh(xw, last.row, 0, 1, last.col, True); 4439d522f475Smrg } 4440d522f475Smrg } else { /* do single row */ 4441d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, last.col - first.col, True); 4442d522f475Smrg } 4443d522f475Smrg} 4444d522f475Smrg 4445d522f475Smrg/* 4446913cc679Smrg * Guaranteed that (cellc->row, cellc->col) <= (cell->row, cell->col), 4447913cc679Smrg * and that both points are valid 4448d522f475Smrg * (may have cell->row = screen->max_row+1, cell->col = 0). 4449d522f475Smrg */ 4450d522f475Smrgstatic void 4451d522f475SmrgSaltTextAway(XtermWidget xw, 4452f2e35a3aSmrg int which, 44535104ee6eSmrg const CELL *cellc, 44545104ee6eSmrg const CELL *cell) 4455d522f475Smrg{ 4456956cc18dSsnj TScreen *screen = TScreenOf(xw); 4457f2e35a3aSmrg SelectedCells *scp; 4458f2e35a3aSmrg int i; 4459d522f475Smrg int eol; 4460f2e35a3aSmrg int need = 0; 4461f2e35a3aSmrg size_t have = 0; 4462d522f475Smrg Char *line; 4463d522f475Smrg Char *lp; 4464d522f475Smrg CELL first = *cellc; 4465d522f475Smrg CELL last = *cell; 4466d522f475Smrg 4467f2e35a3aSmrg if (which < 0 || which >= MAX_SELECTIONS) { 4468f2e35a3aSmrg TRACE(("SaltTextAway - which selection?\n")); 4469f2e35a3aSmrg return; 4470f2e35a3aSmrg } 4471f2e35a3aSmrg scp = &(screen->selected_cells[which]); 4472f2e35a3aSmrg 4473f2e35a3aSmrg TRACE(("SaltTextAway which=%d, first=%d,%d, last=%d,%d\n", 4474f2e35a3aSmrg which, first.row, first.col, last.row, last.col)); 4475f2e35a3aSmrg 4476d522f475Smrg if (isSameRow(&first, &last) && first.col > last.col) { 44772e4f8982Smrg int tmp; 4478956cc18dSsnj EXCHANGE(first.col, last.col, tmp); 4479d522f475Smrg } 4480d522f475Smrg 4481d522f475Smrg --last.col; 4482d522f475Smrg /* first we need to know how long the string is before we can save it */ 4483d522f475Smrg 4484d522f475Smrg if (isSameRow(&last, &first)) { 4485f2e35a3aSmrg need = Length(screen, first.row, first.col, last.col); 4486d522f475Smrg } else { /* two cases, cut is on same line, cut spans multiple lines */ 4487f2e35a3aSmrg need += Length(screen, first.row, first.col, screen->max_col) + 1; 4488d522f475Smrg for (i = first.row + 1; i < last.row; i++) 4489f2e35a3aSmrg need += Length(screen, i, 0, screen->max_col) + 1; 4490d522f475Smrg if (last.col >= 0) 4491f2e35a3aSmrg need += Length(screen, last.row, 0, last.col); 4492d522f475Smrg } 4493d522f475Smrg 4494d522f475Smrg /* UTF-8 may require more space */ 4495d522f475Smrg if_OPT_WIDE_CHARS(screen, { 4496f2e35a3aSmrg if (need > 0) { 4497f2e35a3aSmrg if (screen->max_combining > 0) 4498f2e35a3aSmrg need += screen->max_combining; 4499f2e35a3aSmrg need *= 6; 4500f2e35a3aSmrg } 4501d522f475Smrg }); 4502d522f475Smrg 4503d522f475Smrg /* now get some memory to save it in */ 4504f2e35a3aSmrg if (need < 0) 4505f2e35a3aSmrg return; 4506d522f475Smrg 4507f2e35a3aSmrg if (scp->data_limit <= (unsigned) need) { 45085104ee6eSmrg if ((line = (Char *) malloc((size_t) need + 1)) == NULL) 4509d522f475Smrg SysError(ERROR_BMALLOC2); 4510f2e35a3aSmrg free(scp->data_buffer); 4511f2e35a3aSmrg scp->data_buffer = line; 4512f2e35a3aSmrg scp->data_limit = (size_t) (need + 1); 4513d522f475Smrg } else { 4514f2e35a3aSmrg line = scp->data_buffer; 4515d522f475Smrg } 4516d522f475Smrg 45175104ee6eSmrg if (line == NULL) 4518d522f475Smrg return; 4519d522f475Smrg 4520f2e35a3aSmrg line[need] = '\0'; /* make sure it is null terminated */ 4521d522f475Smrg lp = line; /* lp points to where to save the text */ 4522d522f475Smrg if (isSameRow(&last, &first)) { 4523d522f475Smrg lp = SaveText(screen, last.row, first.col, last.col, lp, &eol); 45245104ee6eSmrg } 45255104ee6eSmrg#if OPT_BLOCK_SELECT 45265104ee6eSmrg else if (screen->blockSelecting) { 45275104ee6eSmrg /* In block select mode, find the left most column of the block. 45285104ee6eSmrg This can be from either the start or the end of the selection. */ 45295104ee6eSmrg int blockFirst, blockLast; 45305104ee6eSmrg if (first.col < last.col) { 45315104ee6eSmrg blockFirst = first.col; 45325104ee6eSmrg blockLast = last.col; 45335104ee6eSmrg } else { 45345104ee6eSmrg blockFirst = last.col; 45355104ee6eSmrg blockLast = first.col; 45365104ee6eSmrg } 45375104ee6eSmrg for (i = first.row; i <= last.row; i++) { 45385104ee6eSmrg lp = SaveText(screen, i, blockFirst, blockLast, lp, &eol); 45395104ee6eSmrg if (i < last.row || eol) 45405104ee6eSmrg *lp++ = '\n'; 45415104ee6eSmrg } 45425104ee6eSmrg } 45435104ee6eSmrg#endif 45445104ee6eSmrg else { 4545d522f475Smrg lp = SaveText(screen, first.row, first.col, screen->max_col, lp, &eol); 4546d522f475Smrg if (eol) 4547d522f475Smrg *lp++ = '\n'; /* put in newline at end of line */ 4548d522f475Smrg for (i = first.row + 1; i < last.row; i++) { 4549d522f475Smrg lp = SaveText(screen, i, 0, screen->max_col, lp, &eol); 4550d522f475Smrg if (eol) 4551d522f475Smrg *lp++ = '\n'; 4552d522f475Smrg } 4553d522f475Smrg if (last.col >= 0) 4554d522f475Smrg lp = SaveText(screen, last.row, 0, last.col, lp, &eol); 4555d522f475Smrg } 4556d522f475Smrg *lp = '\0'; /* make sure we have end marked */ 4557d522f475Smrg 4558f2e35a3aSmrg have = (size_t) (lp - line); 4559f2e35a3aSmrg /* 4560f2e35a3aSmrg * Scanning the buffer twice is unnecessary. Discard unwanted memory if 4561f2e35a3aSmrg * the estimate is too-far off. 4562f2e35a3aSmrg */ 4563f2e35a3aSmrg if ((have * 2) < (size_t) need) { 4564f2e35a3aSmrg Char *next; 4565f2e35a3aSmrg scp->data_limit = have + 1; 4566f2e35a3aSmrg next = realloc(line, scp->data_limit); 4567f2e35a3aSmrg if (next == NULL) { 4568f2e35a3aSmrg free(line); 4569f2e35a3aSmrg scp->data_length = 0; 4570f2e35a3aSmrg scp->data_limit = 0; 4571f2e35a3aSmrg } 4572f2e35a3aSmrg scp->data_buffer = next; 4573f2e35a3aSmrg } 4574f2e35a3aSmrg scp->data_length = have; 4575d522f475Smrg 4576f2e35a3aSmrg TRACE(("Salted TEXT:%u:%s\n", (unsigned) have, 4577f2e35a3aSmrg visibleChars(scp->data_buffer, (unsigned) have))); 4578d522f475Smrg} 4579d522f475Smrg 4580d522f475Smrg#if OPT_PASTE64 4581d522f475Smrgvoid 4582f2e35a3aSmrgClearSelectionBuffer(TScreen *screen, String selection) 4583d522f475Smrg{ 4584f2e35a3aSmrg int which = TargetToSelection(screen, selection); 4585f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[okSelectionCode(which)]); 4586f2e35a3aSmrg FreeAndNull(scp->data_buffer); 4587f2e35a3aSmrg scp->data_limit = 0; 4588f2e35a3aSmrg scp->data_length = 0; 4589d522f475Smrg screen->base64_count = 0; 4590d522f475Smrg} 4591d522f475Smrg 4592d522f475Smrgstatic void 4593f2e35a3aSmrgAppendStrToSelectionBuffer(SelectedCells * scp, Char *text, size_t len) 4594d522f475Smrg{ 4595d522f475Smrg if (len != 0) { 4596f2e35a3aSmrg size_t j = (scp->data_length + len); 4597f2e35a3aSmrg size_t k = j + (j >> 2) + 80; 4598f2e35a3aSmrg if (j + 1 >= scp->data_limit) { 4599f2e35a3aSmrg Char *line; 4600f2e35a3aSmrg if (!scp->data_length) { 4601f2e35a3aSmrg line = (Char *) malloc(k); 4602d522f475Smrg } else { 4603f2e35a3aSmrg line = (Char *) realloc(scp->data_buffer, k); 4604d522f475Smrg } 46055104ee6eSmrg if (line == NULL) 4606f2e35a3aSmrg SysError(ERROR_BMALLOC2); 4607f2e35a3aSmrg scp->data_buffer = line; 4608f2e35a3aSmrg scp->data_limit = k; 4609d522f475Smrg } 46105104ee6eSmrg if (scp->data_buffer != NULL) { 4611f2e35a3aSmrg memcpy(scp->data_buffer + scp->data_length, text, len); 4612f2e35a3aSmrg scp->data_length += len; 4613f2e35a3aSmrg scp->data_buffer[scp->data_length] = 0; 461420d2c4d2Smrg } 4615d522f475Smrg } 4616d522f475Smrg} 4617d522f475Smrg 4618d522f475Smrgvoid 4619f2e35a3aSmrgAppendToSelectionBuffer(TScreen *screen, unsigned c, String selection) 4620d522f475Smrg{ 4621f2e35a3aSmrg int which = TargetToSelection(screen, selection); 4622f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[okSelectionCode(which)]); 46232eaa94a1Schristos unsigned six; 4624d522f475Smrg Char ch; 4625d522f475Smrg 4626d522f475Smrg /* Decode base64 character */ 4627d522f475Smrg if (c >= 'A' && c <= 'Z') 4628d522f475Smrg six = c - 'A'; 4629d522f475Smrg else if (c >= 'a' && c <= 'z') 4630d522f475Smrg six = c - 'a' + 26; 4631d522f475Smrg else if (c >= '0' && c <= '9') 4632d522f475Smrg six = c - '0' + 52; 4633d522f475Smrg else if (c == '+') 4634d522f475Smrg six = 62; 4635d522f475Smrg else if (c == '/') 4636d522f475Smrg six = 63; 4637d522f475Smrg else 4638d522f475Smrg return; 4639d522f475Smrg 4640d522f475Smrg /* Accumulate bytes */ 4641d522f475Smrg switch (screen->base64_count) { 4642d522f475Smrg case 0: 4643d522f475Smrg screen->base64_accu = six; 4644d522f475Smrg screen->base64_count = 6; 4645d522f475Smrg break; 4646d522f475Smrg 4647d522f475Smrg case 2: 46482eaa94a1Schristos ch = CharOf((screen->base64_accu << 6) + six); 4649d522f475Smrg screen->base64_count = 0; 4650f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4651d522f475Smrg break; 4652d522f475Smrg 4653d522f475Smrg case 4: 46542eaa94a1Schristos ch = CharOf((screen->base64_accu << 4) + (six >> 2)); 4655d522f475Smrg screen->base64_accu = (six & 0x3); 4656d522f475Smrg screen->base64_count = 2; 4657f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4658d522f475Smrg break; 4659d522f475Smrg 4660d522f475Smrg case 6: 46612eaa94a1Schristos ch = CharOf((screen->base64_accu << 2) + (six >> 4)); 4662d522f475Smrg screen->base64_accu = (six & 0xF); 4663d522f475Smrg screen->base64_count = 4; 4664f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4665d522f475Smrg break; 4666d522f475Smrg } 4667d522f475Smrg} 4668d522f475Smrg 4669d522f475Smrgvoid 4670e0a2b6dfSmrgCompleteSelection(XtermWidget xw, String *args, Cardinal len) 4671d522f475Smrg{ 4672956cc18dSsnj TScreen *screen = TScreenOf(xw); 4673956cc18dSsnj 4674956cc18dSsnj screen->base64_count = 0; 4675956cc18dSsnj screen->base64_accu = 0; 4676d522f475Smrg _OwnSelection(xw, args, len); 4677d522f475Smrg} 4678d522f475Smrg#endif /* OPT_PASTE64 */ 4679d522f475Smrg 4680d522f475Smrgstatic Bool 4681d522f475Smrg_ConvertSelectionHelper(Widget w, 4682f2e35a3aSmrg SelectedCells * scp, 4683894e0ac8Smrg Atom *type, 4684d522f475Smrg XtPointer *value, 4685d522f475Smrg unsigned long *length, 4686d522f475Smrg int *format, 4687d522f475Smrg int (*conversion_function) (Display *, 4688d522f475Smrg char **, int, 4689d522f475Smrg XICCEncodingStyle, 4690d522f475Smrg XTextProperty *), 4691d522f475Smrg XICCEncodingStyle conversion_style) 4692d522f475Smrg{ 46935104ee6eSmrg *value = NULL; 469401037d57Smrg *length = 0; 469501037d57Smrg *type = 0; 469601037d57Smrg *format = 0; 469701037d57Smrg 46985104ee6eSmrg if (getXtermWidget(w) != NULL) { 4699d522f475Smrg Display *dpy = XtDisplay(w); 4700d522f475Smrg XTextProperty textprop; 470101037d57Smrg int out_n = 0; 47025104ee6eSmrg char *result = NULL; 4703f2e35a3aSmrg char *the_data = (char *) scp->data_buffer; 470401037d57Smrg char *the_next; 4705f2e35a3aSmrg unsigned long remaining = scp->data_length; 470601037d57Smrg 470701037d57Smrg TRACE(("converting %ld:'%s'\n", 4708f2e35a3aSmrg (long) scp->data_length, 4709f2e35a3aSmrg visibleChars(scp->data_buffer, (unsigned) scp->data_length))); 471001037d57Smrg /* 471101037d57Smrg * For most selections, we can convert in one pass. It is possible 471201037d57Smrg * that some applications contain embedded nulls, e.g., using xterm's 471301037d57Smrg * paste64 feature. For those cases, we will build up the result in 471401037d57Smrg * parts. 471501037d57Smrg */ 47165104ee6eSmrg if (memchr(the_data, 0, scp->data_length) != NULL) { 471701037d57Smrg TRACE(("selection contains embedded nulls\n")); 4718f2e35a3aSmrg result = calloc(scp->data_length + 1, sizeof(char)); 471901037d57Smrg } 4720d522f475Smrg 472101037d57Smrg next_try: 472201037d57Smrg memset(&textprop, 0, sizeof(textprop)); 4723d522f475Smrg if (conversion_function(dpy, &the_data, 1, 4724d522f475Smrg conversion_style, 4725d522f475Smrg &textprop) >= Success) { 47265104ee6eSmrg if ((result != NULL) 47275104ee6eSmrg && (textprop.value != NULL) 472801037d57Smrg && (textprop.format == 8)) { 472901037d57Smrg char *text_values = (char *) textprop.value; 473001037d57Smrg unsigned long in_n; 473101037d57Smrg 473201037d57Smrg if (out_n == 0) { 473301037d57Smrg *value = result; 473401037d57Smrg *type = textprop.encoding; 473501037d57Smrg *format = textprop.format; 473601037d57Smrg } 473701037d57Smrg for (in_n = 0; in_n < textprop.nitems; ++in_n) { 473801037d57Smrg result[out_n++] = text_values[in_n]; 473901037d57Smrg } 474001037d57Smrg *length += textprop.nitems; 47415104ee6eSmrg if ((the_next = memchr(the_data, 0, remaining)) != NULL) { 474201037d57Smrg unsigned long this_was = (unsigned long) (the_next - the_data); 474301037d57Smrg this_was++; 474401037d57Smrg the_data += this_was; 474501037d57Smrg remaining -= this_was; 474601037d57Smrg result[out_n++] = 0; 474701037d57Smrg *length += 1; 474801037d57Smrg if (remaining) 474901037d57Smrg goto next_try; 475001037d57Smrg } 475101037d57Smrg return True; 475201037d57Smrg } else { 475301037d57Smrg free(result); 475401037d57Smrg *value = (XtPointer) textprop.value; 475501037d57Smrg *length = textprop.nitems; 475601037d57Smrg *type = textprop.encoding; 475701037d57Smrg *format = textprop.format; 475801037d57Smrg return True; 475901037d57Smrg } 4760d522f475Smrg } 476101037d57Smrg free(result); 4762d522f475Smrg } 4763d522f475Smrg return False; 4764d522f475Smrg} 4765d522f475Smrg 47662eaa94a1Schristosstatic Boolean 47672eaa94a1SchristosSaveConvertedLength(XtPointer *target, unsigned long source) 47682eaa94a1Schristos{ 47692eaa94a1Schristos Boolean result = False; 47702eaa94a1Schristos 47712eaa94a1Schristos *target = XtMalloc(4); 47725104ee6eSmrg if (*target != NULL) { 47732eaa94a1Schristos result = True; 47742eaa94a1Schristos if (sizeof(unsigned long) == 4) { 47752eaa94a1Schristos *(unsigned long *) *target = source; 47762eaa94a1Schristos } else if (sizeof(unsigned) == 4) { 477720d2c4d2Smrg *(unsigned *) *target = (unsigned) source; 47782eaa94a1Schristos } else if (sizeof(unsigned short) == 4) { 47792eaa94a1Schristos *(unsigned short *) *target = (unsigned short) source; 47802eaa94a1Schristos } else { 47812eaa94a1Schristos /* FIXME - does this depend on byte-order? */ 47822eaa94a1Schristos unsigned long temp = source; 478320d2c4d2Smrg memcpy((char *) *target, 478420d2c4d2Smrg ((char *) &temp) + sizeof(temp) - 4, 478520d2c4d2Smrg (size_t) 4); 47862eaa94a1Schristos } 47872eaa94a1Schristos } 47882eaa94a1Schristos return result; 47892eaa94a1Schristos} 47902eaa94a1Schristos 4791f2e35a3aSmrg#define keepClipboard(d,atom) ((screen->keepClipboard) && \ 4792f2e35a3aSmrg (atom == XA_CLIPBOARD(d))) 47932e4f8982Smrg 4794d522f475Smrgstatic Boolean 4795d522f475SmrgConvertSelection(Widget w, 4796894e0ac8Smrg Atom *selection, 4797894e0ac8Smrg Atom *target, 4798894e0ac8Smrg Atom *type, 4799d522f475Smrg XtPointer *value, 4800d522f475Smrg unsigned long *length, 4801d522f475Smrg int *format) 4802d522f475Smrg{ 4803d522f475Smrg Display *dpy = XtDisplay(w); 4804d522f475Smrg TScreen *screen; 4805f2e35a3aSmrg SelectedCells *scp; 4806d522f475Smrg Bool result = False; 4807d522f475Smrg 48082e4f8982Smrg Char *data; 48092e4f8982Smrg unsigned long data_length; 48102e4f8982Smrg 4811956cc18dSsnj XtermWidget xw; 4812956cc18dSsnj 48135104ee6eSmrg if ((xw = getXtermWidget(w)) == NULL) 4814d522f475Smrg return False; 4815d522f475Smrg 4816956cc18dSsnj screen = TScreenOf(xw); 4817d522f475Smrg 4818f2e35a3aSmrg TRACE(("ConvertSelection %s -> %s\n", 4819f2e35a3aSmrg TraceAtomName(screen->display, *selection), 4820956cc18dSsnj visibleSelectionTarget(dpy, *target))); 4821956cc18dSsnj 4822f2e35a3aSmrg if (keepClipboard(dpy, *selection)) { 48232e4f8982Smrg TRACE(("asked for clipboard\n")); 4824f2e35a3aSmrg scp = &(screen->clipboard_data); 48252e4f8982Smrg } else { 48262e4f8982Smrg TRACE(("asked for selection\n")); 4827f2e35a3aSmrg scp = &(screen->selected_cells[AtomToSelection(dpy, *selection)]); 48282e4f8982Smrg } 48292e4f8982Smrg 4830f2e35a3aSmrg data = scp->data_buffer; 4831f2e35a3aSmrg data_length = scp->data_length; 48322e4f8982Smrg if (data == NULL) { 4833f2e35a3aSmrg TRACE(("...no selection-data\n")); 4834f2e35a3aSmrg return False; 483501037d57Smrg } 483601037d57Smrg 4837d522f475Smrg if (*target == XA_TARGETS(dpy)) { 4838d522f475Smrg Atom *targetP; 48395104ee6eSmrg XPointer std_return = NULL; 4840d522f475Smrg unsigned long std_length; 4841d522f475Smrg 4842d522f475Smrg if (XmuConvertStandardSelection(w, screen->selection_time, selection, 4843d522f475Smrg target, type, &std_return, 4844d522f475Smrg &std_length, format)) { 4845956cc18dSsnj Atom *my_targets = _SelectionTargets(w); 48462e4f8982Smrg Atom *allocP; 48472e4f8982Smrg Atom *std_targets; 4848956cc18dSsnj 4849956cc18dSsnj TRACE(("XmuConvertStandardSelection - success\n")); 4850a1f3da82Smrg std_targets = (Atom *) (void *) (std_return); 4851d522f475Smrg *length = std_length + 6; 4852d522f475Smrg 4853a1f3da82Smrg targetP = TypeXtMallocN(Atom, *length); 4854d522f475Smrg allocP = targetP; 4855d522f475Smrg 4856d522f475Smrg *value = (XtPointer) targetP; 4857d522f475Smrg 48585104ee6eSmrg if (my_targets != NULL) { 48590bd37d32Smrg while (*my_targets != None) { 48600bd37d32Smrg *targetP++ = *my_targets++; 48610bd37d32Smrg } 4862956cc18dSsnj } 4863d522f475Smrg *targetP++ = XA_LENGTH(dpy); 4864d522f475Smrg *targetP++ = XA_LIST_LENGTH(dpy); 4865d522f475Smrg 48662eaa94a1Schristos *length = std_length + (unsigned long) (targetP - allocP); 4867d522f475Smrg 4868d522f475Smrg memcpy(targetP, std_targets, sizeof(Atom) * std_length); 4869d522f475Smrg XtFree((char *) std_targets); 4870d522f475Smrg *type = XA_ATOM; 4871d522f475Smrg *format = 32; 4872d522f475Smrg result = True; 4873956cc18dSsnj } else { 4874956cc18dSsnj TRACE(("XmuConvertStandardSelection - failed\n")); 4875d522f475Smrg } 4876d522f475Smrg } 4877d522f475Smrg#if OPT_WIDE_CHARS 4878d522f475Smrg else if (screen->wide_chars && *target == XA_STRING) { 4879d522f475Smrg result = 4880f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4881f2e35a3aSmrg type, value, length, format, 4882d522f475Smrg Xutf8TextListToTextProperty, 4883d522f475Smrg XStringStyle); 4884956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4885d522f475Smrg } else if (screen->wide_chars && *target == XA_UTF8_STRING(dpy)) { 4886d522f475Smrg result = 4887f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4888f2e35a3aSmrg type, value, length, format, 4889d522f475Smrg Xutf8TextListToTextProperty, 4890d522f475Smrg XUTF8StringStyle); 4891956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4892d522f475Smrg } else if (screen->wide_chars && *target == XA_TEXT(dpy)) { 4893d522f475Smrg result = 4894f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4895f2e35a3aSmrg type, value, length, format, 4896d522f475Smrg Xutf8TextListToTextProperty, 4897d522f475Smrg XStdICCTextStyle); 4898956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4899d522f475Smrg } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(dpy)) { 4900d522f475Smrg result = 4901f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4902f2e35a3aSmrg type, value, length, format, 4903d522f475Smrg Xutf8TextListToTextProperty, 4904d522f475Smrg XCompoundTextStyle); 4905956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4906d522f475Smrg } 4907d522f475Smrg#endif 4908d522f475Smrg 4909d522f475Smrg else if (*target == XA_STRING) { /* not wide_chars */ 4910d522f475Smrg /* We can only reach this point if the selection requestor 4911d522f475Smrg requested STRING before any of TEXT, COMPOUND_TEXT or 4912d522f475Smrg UTF8_STRING. We therefore assume that the requestor is not 4913d522f475Smrg properly internationalised, and dump raw eight-bit data 4914d522f475Smrg with no conversion into the selection. Yes, this breaks 4915d522f475Smrg the ICCCM in non-Latin-1 locales. */ 4916d522f475Smrg *type = XA_STRING; 4917f2e35a3aSmrg *value = (XtPointer) data; 4918f2e35a3aSmrg *length = data_length; 4919d522f475Smrg *format = 8; 4920d522f475Smrg result = True; 4921956cc18dSsnj TRACE(("...raw 8-bit data:%d\n", result)); 4922d522f475Smrg } else if (*target == XA_TEXT(dpy)) { /* not wide_chars */ 4923d522f475Smrg result = 4924f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4925f2e35a3aSmrg type, value, length, format, 4926d522f475Smrg XmbTextListToTextProperty, 4927d522f475Smrg XStdICCTextStyle); 4928956cc18dSsnj TRACE(("...XmbTextListToTextProperty(StdICC):%d\n", result)); 4929d522f475Smrg } else if (*target == XA_COMPOUND_TEXT(dpy)) { /* not wide_chars */ 4930d522f475Smrg result = 4931f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4932f2e35a3aSmrg type, value, length, format, 4933d522f475Smrg XmbTextListToTextProperty, 4934d522f475Smrg XCompoundTextStyle); 4935956cc18dSsnj TRACE(("...XmbTextListToTextProperty(Compound):%d\n", result)); 4936d522f475Smrg } 4937d522f475Smrg#ifdef X_HAVE_UTF8_STRING 4938d522f475Smrg else if (*target == XA_UTF8_STRING(dpy)) { /* not wide_chars */ 4939d522f475Smrg result = 4940f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4941f2e35a3aSmrg type, value, length, format, 4942d522f475Smrg XmbTextListToTextProperty, 4943d522f475Smrg XUTF8StringStyle); 4944956cc18dSsnj TRACE(("...XmbTextListToTextProperty(UTF8):%d\n", result)); 4945d522f475Smrg } 4946d522f475Smrg#endif 4947d522f475Smrg else if (*target == XA_LIST_LENGTH(dpy)) { 494820d2c4d2Smrg result = SaveConvertedLength(value, (unsigned long) 1); 4949d522f475Smrg *type = XA_INTEGER; 4950d522f475Smrg *length = 1; 4951d522f475Smrg *format = 32; 4952956cc18dSsnj TRACE(("...list of values:%d\n", result)); 4953d522f475Smrg } else if (*target == XA_LENGTH(dpy)) { 4954d522f475Smrg /* This value is wrong if we have UTF-8 text */ 4955f2e35a3aSmrg result = SaveConvertedLength(value, scp->data_length); 4956d522f475Smrg *type = XA_INTEGER; 4957d522f475Smrg *length = 1; 4958d522f475Smrg *format = 32; 4959956cc18dSsnj TRACE(("...list of values:%d\n", result)); 4960d522f475Smrg } else if (XmuConvertStandardSelection(w, 4961d522f475Smrg screen->selection_time, selection, 4962d522f475Smrg target, type, (XPointer *) value, 4963d522f475Smrg length, format)) { 4964d522f475Smrg result = True; 4965956cc18dSsnj TRACE(("...XmuConvertStandardSelection:%d\n", result)); 4966d522f475Smrg } 4967d522f475Smrg 4968d522f475Smrg /* else */ 49692eaa94a1Schristos return (Boolean) result; 4970d522f475Smrg} 4971d522f475Smrg 4972d522f475Smrgstatic void 4973894e0ac8SmrgLoseSelection(Widget w, Atom *selection) 4974d522f475Smrg{ 4975d522f475Smrg TScreen *screen; 4976d522f475Smrg Atom *atomP; 4977d522f475Smrg Cardinal i; 4978d522f475Smrg 4979956cc18dSsnj XtermWidget xw; 4980956cc18dSsnj 49815104ee6eSmrg if ((xw = getXtermWidget(w)) == NULL) 4982d522f475Smrg return; 4983d522f475Smrg 4984956cc18dSsnj screen = TScreenOf(xw); 4985913cc679Smrg TRACE(("LoseSelection %s\n", TraceAtomName(screen->display, *selection))); 498601037d57Smrg 4987d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 4988d522f475Smrg i < screen->selection_count; i++, atomP++) { 4989d522f475Smrg if (*selection == *atomP) 4990d522f475Smrg *atomP = (Atom) 0; 4991d522f475Smrg if (CutBuffer(*atomP) >= 0) { 4992d522f475Smrg *atomP = (Atom) 0; 4993d522f475Smrg } 4994d522f475Smrg } 4995d522f475Smrg 4996d522f475Smrg for (i = screen->selection_count; i; i--) { 4997d522f475Smrg if (screen->selection_atoms[i - 1] != 0) 4998d522f475Smrg break; 4999d522f475Smrg } 5000d522f475Smrg screen->selection_count = i; 5001d522f475Smrg 5002d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 5003d522f475Smrg i < screen->selection_count; i++, atomP++) { 5004d522f475Smrg if (*atomP == (Atom) 0) { 5005d522f475Smrg *atomP = screen->selection_atoms[--screen->selection_count]; 5006d522f475Smrg } 5007d522f475Smrg } 5008d522f475Smrg 5009d522f475Smrg if (screen->selection_count == 0) 5010f2e35a3aSmrg UnHiliteText(xw); 5011d522f475Smrg} 5012d522f475Smrg 5013d522f475Smrg/* ARGSUSED */ 5014d522f475Smrgstatic void 5015d522f475SmrgSelectionDone(Widget w GCC_UNUSED, 5016894e0ac8Smrg Atom *selection GCC_UNUSED, 5017894e0ac8Smrg Atom *target GCC_UNUSED) 5018d522f475Smrg{ 5019d522f475Smrg /* empty proc so Intrinsics know we want to keep storage */ 502001037d57Smrg TRACE(("SelectionDone\n")); 5021d522f475Smrg} 5022d522f475Smrg 5023d522f475Smrgstatic void 5024d522f475Smrg_OwnSelection(XtermWidget xw, 5025e0a2b6dfSmrg String *selections, 5026d522f475Smrg Cardinal count) 5027d522f475Smrg{ 5028956cc18dSsnj TScreen *screen = TScreenOf(xw); 5029f2e35a3aSmrg Display *dpy = screen->display; 5030d522f475Smrg Atom *atoms = screen->selection_atoms; 5031d522f475Smrg Cardinal i; 5032d522f475Smrg Bool have_selection = False; 5033f2e35a3aSmrg SelectedCells *scp; 5034d522f475Smrg 503520d2c4d2Smrg if (count == 0) 503620d2c4d2Smrg return; 5037d522f475Smrg 5038f2e35a3aSmrg TRACE(("_OwnSelection count %d\n", count)); 5039d522f475Smrg selections = MapSelections(xw, selections, count); 5040d522f475Smrg 5041d522f475Smrg if (count > screen->sel_atoms_size) { 5042d522f475Smrg XtFree((char *) atoms); 5043a1f3da82Smrg atoms = TypeXtMallocN(Atom, count); 5044d522f475Smrg screen->selection_atoms = atoms; 5045d522f475Smrg screen->sel_atoms_size = count; 5046d522f475Smrg } 5047f2e35a3aSmrg XmuInternStrings(dpy, selections, count, atoms); 5048d522f475Smrg for (i = 0; i < count; i++) { 5049d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 5050d522f475Smrg if (cutbuffer >= 0) { 50512eaa94a1Schristos unsigned long limit = 5052f2e35a3aSmrg (unsigned long) (4 * XMaxRequestSize(dpy) - 32); 5053f2e35a3aSmrg scp = &(screen->selected_cells[CutBufferToCode(cutbuffer)]); 5054f2e35a3aSmrg if (scp->data_length > limit) { 505520d2c4d2Smrg TRACE(("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 5056f2e35a3aSmrg (unsigned long) scp->data_length, cutbuffer)); 50570bd37d32Smrg xtermWarning("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 5058f2e35a3aSmrg (unsigned long) scp->data_length, cutbuffer); 5059d522f475Smrg } else { 5060d522f475Smrg /* This used to just use the UTF-8 data, which was totally 5061894e0ac8Smrg * broken as not even the corresponding paste code in xterm 5062d522f475Smrg * understood this! So now it converts to Latin1 first. 5063d522f475Smrg * Robert Brady, 2000-09-05 5064d522f475Smrg */ 5065f2e35a3aSmrg unsigned long length = scp->data_length; 5066f2e35a3aSmrg Char *data = scp->data_buffer; 5067d522f475Smrg if_OPT_WIDE_CHARS((screen), { 5068956cc18dSsnj data = UTF8toLatin1(screen, data, length, &length); 5069d522f475Smrg }); 5070d522f475Smrg TRACE(("XStoreBuffer(%d)\n", cutbuffer)); 5071f2e35a3aSmrg XStoreBuffer(dpy, 5072d522f475Smrg (char *) data, 5073d522f475Smrg (int) length, 5074d522f475Smrg cutbuffer); 5075d522f475Smrg } 5076f2e35a3aSmrg } else { 5077f2e35a3aSmrg int which = AtomToSelection(dpy, atoms[i]); 5078f2e35a3aSmrg if (keepClipboard(dpy, atoms[i])) { 5079f2e35a3aSmrg Char *buf; 5080f2e35a3aSmrg SelectedCells *tcp = &(screen->clipboard_data); 5081f2e35a3aSmrg TRACE(("saving selection to clipboard buffer\n")); 5082f2e35a3aSmrg scp = &(screen->selected_cells[CLIPBOARD_CODE]); 50835104ee6eSmrg if ((buf = (Char *) malloc((size_t) scp->data_length)) == NULL) { 5084f2e35a3aSmrg SysError(ERROR_BMALLOC2); 50855307cd1aSmrg } else { 50865307cd1aSmrg free(tcp->data_buffer); 50875307cd1aSmrg memcpy(buf, scp->data_buffer, scp->data_length); 50885307cd1aSmrg tcp->data_buffer = buf; 50895307cd1aSmrg tcp->data_limit = scp->data_length; 50905307cd1aSmrg tcp->data_length = scp->data_length; 50915307cd1aSmrg } 5092f2e35a3aSmrg } 5093f2e35a3aSmrg scp = &(screen->selected_cells[which]); 5094f2e35a3aSmrg if (scp->data_length == 0) { 5095f2e35a3aSmrg TRACE(("XtDisownSelection(%s, @%ld)\n", 5096f2e35a3aSmrg TraceAtomName(screen->display, atoms[i]), 5097f2e35a3aSmrg (long) screen->selection_time)); 5098f2e35a3aSmrg XtDisownSelection((Widget) xw, 5099f2e35a3aSmrg atoms[i], 5100f2e35a3aSmrg screen->selection_time); 5101f2e35a3aSmrg } else if (!screen->replyToEmacs && atoms[i] != 0) { 5102f2e35a3aSmrg TRACE(("XtOwnSelection(%s, @%ld)\n", 5103f2e35a3aSmrg TraceAtomName(screen->display, atoms[i]), 5104f2e35a3aSmrg (long) screen->selection_time)); 5105f2e35a3aSmrg have_selection |= 5106f2e35a3aSmrg XtOwnSelection((Widget) xw, atoms[i], 5107f2e35a3aSmrg screen->selection_time, 5108f2e35a3aSmrg ConvertSelection, 5109f2e35a3aSmrg LoseSelection, 5110f2e35a3aSmrg SelectionDone); 5111f2e35a3aSmrg } 5112d522f475Smrg } 5113f2e35a3aSmrg TRACE(("... _OwnSelection used length %lu value %s\n", 5114f2e35a3aSmrg (unsigned long) scp->data_length, 5115f2e35a3aSmrg visibleChars(scp->data_buffer, 5116f2e35a3aSmrg (unsigned) scp->data_length))); 5117d522f475Smrg } 5118d522f475Smrg if (!screen->replyToEmacs) 5119d522f475Smrg screen->selection_count = count; 5120d522f475Smrg if (!have_selection) 5121f2e35a3aSmrg UnHiliteText(xw); 5122d522f475Smrg} 5123d522f475Smrg 5124d522f475Smrgstatic void 5125e0a2b6dfSmrgResetSelectionState(TScreen *screen) 5126d522f475Smrg{ 5127d522f475Smrg screen->selection_count = 0; 5128d522f475Smrg screen->startH = zeroCELL; 5129d522f475Smrg screen->endH = zeroCELL; 5130d522f475Smrg} 5131d522f475Smrg 5132d522f475Smrgvoid 5133d522f475SmrgDisownSelection(XtermWidget xw) 5134d522f475Smrg{ 5135956cc18dSsnj TScreen *screen = TScreenOf(xw); 5136d522f475Smrg Atom *atoms = screen->selection_atoms; 5137d522f475Smrg Cardinal count = screen->selection_count; 5138d522f475Smrg Cardinal i; 5139d522f475Smrg 5140d522f475Smrg TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n", 5141d522f475Smrg count, 5142d522f475Smrg screen->startH.row, 5143d522f475Smrg screen->startH.col, 5144d522f475Smrg screen->endH.row, 5145d522f475Smrg screen->endH.col)); 5146d522f475Smrg 5147d522f475Smrg for (i = 0; i < count; i++) { 5148d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 5149d522f475Smrg if (cutbuffer < 0) { 5150d522f475Smrg XtDisownSelection((Widget) xw, atoms[i], 5151d522f475Smrg screen->selection_time); 5152d522f475Smrg } 5153d522f475Smrg } 5154d522f475Smrg /* 5155d522f475Smrg * If none of the callbacks via XtDisownSelection() reset highlighting 5156d522f475Smrg * do it now. 5157d522f475Smrg */ 5158d522f475Smrg if (ScrnHaveSelection(screen)) { 5159d522f475Smrg /* save data which will be reset */ 5160d522f475Smrg CELL first = screen->startH; 5161d522f475Smrg CELL last = screen->endH; 5162d522f475Smrg 5163d522f475Smrg ResetSelectionState(screen); 5164d522f475Smrg ReHiliteText(xw, &first, &last); 5165d522f475Smrg } else { 5166d522f475Smrg ResetSelectionState(screen); 5167d522f475Smrg } 5168d522f475Smrg} 5169d522f475Smrg 5170d522f475Smrgvoid 5171d522f475SmrgUnhiliteSelection(XtermWidget xw) 5172d522f475Smrg{ 5173956cc18dSsnj TScreen *screen = TScreenOf(xw); 5174d522f475Smrg 5175d522f475Smrg if (ScrnHaveSelection(screen)) { 5176d522f475Smrg CELL first = screen->startH; 5177d522f475Smrg CELL last = screen->endH; 5178d522f475Smrg 5179d522f475Smrg screen->startH = zeroCELL; 5180d522f475Smrg screen->endH = zeroCELL; 5181d522f475Smrg ReHiliteText(xw, &first, &last); 5182d522f475Smrg } 5183d522f475Smrg} 5184d522f475Smrg 5185d522f475Smrg/* returns number of chars in line from scol to ecol out */ 5186d522f475Smrg/* ARGSUSED */ 5187d522f475Smrgstatic int 5188e0a2b6dfSmrgLength(TScreen *screen, 5189d522f475Smrg int row, 5190d522f475Smrg int scol, 5191d522f475Smrg int ecol) 5192d522f475Smrg{ 519301037d57Smrg CLineData *ld = GET_LINEDATA(screen, row); 519401037d57Smrg const int lastcol = LastTextCol(screen, ld, row); 5195d522f475Smrg 5196d522f475Smrg if (ecol > lastcol) 5197d522f475Smrg ecol = lastcol; 5198d522f475Smrg return (ecol - scol + 1); 5199d522f475Smrg} 5200d522f475Smrg 5201d522f475Smrg/* copies text into line, preallocated */ 5202d522f475Smrgstatic Char * 5203e0a2b6dfSmrgSaveText(TScreen *screen, 5204d522f475Smrg int row, 5205d522f475Smrg int scol, 5206d522f475Smrg int ecol, 5207e0a2b6dfSmrg Char *lp, /* pointer to where to put the text */ 5208d522f475Smrg int *eol) 5209d522f475Smrg{ 5210956cc18dSsnj LineData *ld; 5211d522f475Smrg int i = 0; 5212d522f475Smrg Char *result = lp; 5213d522f475Smrg#if OPT_WIDE_CHARS 52142eaa94a1Schristos unsigned previous = 0; 5215d522f475Smrg#endif 5216d522f475Smrg 5217956cc18dSsnj ld = GET_LINEDATA(screen, row); 5218d522f475Smrg i = Length(screen, row, scol, ecol); 5219d522f475Smrg ecol = scol + i; 5220d522f475Smrg#if OPT_DEC_CHRSET 5221956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 5222d522f475Smrg scol = (scol + 0) / 2; 5223d522f475Smrg ecol = (ecol + 1) / 2; 5224d522f475Smrg } 5225d522f475Smrg#endif 5226956cc18dSsnj *eol = !LineTstWrapped(ld); 5227d522f475Smrg for (i = scol; i < ecol; i++) { 52282e4f8982Smrg unsigned c; 52295104ee6eSmrg if (i >= (int) ld->lineSize) { 52305104ee6eSmrg /* The terminal was probably resized */ 52315104ee6eSmrg *lp++ = CharOf(' '); 52325104ee6eSmrg continue; 52335104ee6eSmrg } 52345104ee6eSmrg c = ld->charData[i]; 523504b94745Smrg if (ld->attribs[i] & INVISIBLE) 523604b94745Smrg continue; 5237d522f475Smrg#if OPT_WIDE_CHARS 5238d522f475Smrg /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a 5239d522f475Smrg * wide character. 5240d522f475Smrg */ 5241894e0ac8Smrg if (c == HIDDEN_CHAR) { 5242894e0ac8Smrg if (isWide((int) previous)) { 5243894e0ac8Smrg previous = c; 5244894e0ac8Smrg /* Combining characters attached to double-width characters 5245894e0ac8Smrg are in memory attached to the HIDDEN_CHAR */ 5246894e0ac8Smrg if_OPT_WIDE_CHARS(screen, { 5247894e0ac8Smrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 5248894e0ac8Smrg size_t off; 5249894e0ac8Smrg for_each_combData(off, ld) { 52502e4f8982Smrg unsigned ch = ld->combData[off][i]; 5251894e0ac8Smrg if (ch == 0) 5252894e0ac8Smrg break; 5253894e0ac8Smrg lp = convertToUTF8(lp, ch); 5254894e0ac8Smrg } 5255d522f475Smrg } 5256894e0ac8Smrg }); 5257894e0ac8Smrg continue; 5258894e0ac8Smrg } else { 5259894e0ac8Smrg c = ' '; /* should not happen, but just in case... */ 5260894e0ac8Smrg } 5261d522f475Smrg } 5262d522f475Smrg previous = c; 5263e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 5264d522f475Smrg lp = convertToUTF8(lp, (c != 0) ? c : ' '); 5265d522f475Smrg if_OPT_WIDE_CHARS(screen, { 5266956cc18dSsnj size_t off; 5267956cc18dSsnj for_each_combData(off, ld) { 52682e4f8982Smrg unsigned ch = ld->combData[off][i]; 5269956cc18dSsnj if (ch == 0) 5270d522f475Smrg break; 5271d522f475Smrg lp = convertToUTF8(lp, ch); 5272d522f475Smrg } 5273d522f475Smrg }); 5274d522f475Smrg } else 5275d522f475Smrg#endif 5276d522f475Smrg { 5277d522f475Smrg if (c == 0) { 52785104ee6eSmrg c = ' '; 52795104ee6eSmrg } else if (c < ' ') { 5280d522f475Smrg c = DECtoASCII(c); 5281d522f475Smrg } else if (c == 0x7f) { 5282d522f475Smrg c = 0x5f; 5283d522f475Smrg } 52845104ee6eSmrg *lp++ = CharOf(c); 5285d522f475Smrg } 52865104ee6eSmrg if (c != ' ') 5287d522f475Smrg result = lp; 5288d522f475Smrg } 5289d522f475Smrg 5290d522f475Smrg /* 5291d522f475Smrg * If requested, trim trailing blanks from selected lines. Do not do this 5292d522f475Smrg * if the line is wrapped. 5293d522f475Smrg */ 5294d522f475Smrg if (!*eol || !screen->trim_selection) 5295d522f475Smrg result = lp; 5296d522f475Smrg 5297d522f475Smrg return (result); 5298d522f475Smrg} 5299d522f475Smrg 5300f2e35a3aSmrg/* 5301f2e35a3aSmrg * This adds together the bits: 5302f2e35a3aSmrg * shift key -> 1 5303f2e35a3aSmrg * meta key -> 2 5304f2e35a3aSmrg * control key -> 4 5305f2e35a3aSmrg */ 5306f2e35a3aSmrgstatic unsigned 5307f2e35a3aSmrgKeyState(XtermWidget xw, unsigned x) 5308f2e35a3aSmrg{ 5309f2e35a3aSmrg return ((((x) & (ShiftMask | ControlMask))) 5310f2e35a3aSmrg + (((x) & MetaMask(xw)) ? 2 : 0)); 5311f2e35a3aSmrg} 5312f2e35a3aSmrg 5313f2e35a3aSmrg/* 32 + following 8-bit word: 5314d522f475Smrg 5315d522f475Smrg 1:0 Button no: 0, 1, 2. 3=release. 5316d522f475Smrg 2 shift 5317d522f475Smrg 3 meta 5318d522f475Smrg 4 ctrl 5319d522f475Smrg 5 set for motion notify 5320f2e35a3aSmrg 6 set for wheel (and button 6 and 7) 5321f2e35a3aSmrg 7 set for buttons 8 to 11 5322d522f475Smrg*/ 5323d522f475Smrg 5324d522f475Smrg/* Position: 32 - 255. */ 5325a1f3da82Smrgstatic int 5326f2e35a3aSmrgBtnCode(XtermWidget xw, XButtonEvent *event, int button) 5327d522f475Smrg{ 5328f2e35a3aSmrg int result = (int) (32 + (KeyState(xw, event->state) << 2)); 5329d522f475Smrg 53300bd37d32Smrg if (event->type == MotionNotify) 53310bd37d32Smrg result += 32; 53320bd37d32Smrg 5333f2e35a3aSmrg if (button < 0) { 5334d522f475Smrg result += 3; 5335d522f475Smrg } else { 5336f2e35a3aSmrg result += button & 3; 5337f2e35a3aSmrg if (button & 4) 5338f2e35a3aSmrg result += 64; 5339f2e35a3aSmrg if (button & 8) 5340f2e35a3aSmrg result += 128; 5341d522f475Smrg } 53420bd37d32Smrg TRACE(("BtnCode button %d, %s state " FMT_MODIFIER_NAMES " ->%#x\n", 53430bd37d32Smrg button, 53440bd37d32Smrg visibleEventType(event->type), 53450bd37d32Smrg ARG_MODIFIER_NAMES(event->state), 53460bd37d32Smrg result)); 5347a1f3da82Smrg return result; 5348a1f3da82Smrg} 5349a1f3da82Smrg 5350a1f3da82Smrgstatic unsigned 5351913cc679SmrgEmitButtonCode(XtermWidget xw, 5352e0a2b6dfSmrg Char *line, 53530bd37d32Smrg unsigned count, 5354894e0ac8Smrg XButtonEvent *event, 53550bd37d32Smrg int button) 5356a1f3da82Smrg{ 5357913cc679Smrg TScreen *screen = TScreenOf(xw); 53580bd37d32Smrg int value; 5359a1f3da82Smrg 5360913cc679Smrg if (okSendMousePos(xw) == X10_MOUSE) { 53610bd37d32Smrg value = CharOf(' ' + button); 5362a1f3da82Smrg } else { 5363f2e35a3aSmrg value = BtnCode(xw, event, button); 53640bd37d32Smrg } 53650bd37d32Smrg 53660bd37d32Smrg switch (screen->extend_coords) { 53670bd37d32Smrg default: 53680bd37d32Smrg line[count++] = CharOf(value); 53690bd37d32Smrg break; 53700bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5371f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 53720bd37d32Smrg value -= 32; /* encoding starts at zero */ 53730bd37d32Smrg /* FALLTHRU */ 53740bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 53750bd37d32Smrg count += (unsigned) sprintf((char *) line + count, "%d", value); 53760bd37d32Smrg break; 53770bd37d32Smrg case SET_EXT_MODE_MOUSE: 53780bd37d32Smrg if (value < 128) { 53790bd37d32Smrg line[count++] = CharOf(value); 53800bd37d32Smrg } else { 53810bd37d32Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 53820bd37d32Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 53830bd37d32Smrg } 53840bd37d32Smrg break; 5385a1f3da82Smrg } 5386a1f3da82Smrg return count; 5387d522f475Smrg} 5388d522f475Smrg 53890bd37d32Smrgstatic int 53900bd37d32SmrgFirstBitN(int bits) 53910bd37d32Smrg{ 53920bd37d32Smrg int result = -1; 53930bd37d32Smrg if (bits > 0) { 53940bd37d32Smrg result = 0; 53950bd37d32Smrg while (!(bits & 1)) { 53960bd37d32Smrg bits /= 2; 53970bd37d32Smrg ++result; 53980bd37d32Smrg } 53990bd37d32Smrg } 54000bd37d32Smrg return result; 54010bd37d32Smrg} 54020bd37d32Smrg 54030bd37d32Smrg#define ButtonBit(button) ((button >= 0) ? (1 << (button)) : 0) 54040bd37d32Smrg 5405913cc679Smrg#define EMIT_BUTTON(button) EmitButtonCode(xw, line, count, event, button) 54060bd37d32Smrg 5407d522f475Smrgstatic void 5408894e0ac8SmrgEditorButton(XtermWidget xw, XButtonEvent *event) 5409d522f475Smrg{ 5410956cc18dSsnj TScreen *screen = TScreenOf(xw); 5411d522f475Smrg int pty = screen->respond; 54120bd37d32Smrg int mouse_limit = MouseLimit(screen); 54130bd37d32Smrg Char line[32]; 54140bd37d32Smrg Char final = 'M'; 5415d522f475Smrg int row, col; 5416d522f475Smrg int button; 5417d522f475Smrg unsigned count = 0; 5418d522f475Smrg Boolean changed = True; 5419d522f475Smrg 5420d522f475Smrg /* If button event, get button # adjusted for DEC compatibility */ 54212eaa94a1Schristos button = (int) (event->button - 1); 5422d522f475Smrg if (button >= 3) 5423d522f475Smrg button++; 5424d522f475Smrg 5425f2e35a3aSmrg /* Ignore buttons that cannot be encoded */ 5426f2e35a3aSmrg if (screen->send_mouse_pos == X10_MOUSE) { 5427f2e35a3aSmrg if (button > 3) 5428f2e35a3aSmrg return; 5429f2e35a3aSmrg } else if (screen->extend_coords == SET_SGR_EXT_MODE_MOUSE 5430f2e35a3aSmrg || screen->extend_coords == SET_URXVT_EXT_MODE_MOUSE 5431f2e35a3aSmrg || screen->extend_coords == SET_PIXEL_POSITION_MOUSE) { 5432f2e35a3aSmrg if (button > 15) { 5433f2e35a3aSmrg return; 5434f2e35a3aSmrg } 5435f2e35a3aSmrg } else { 5436f2e35a3aSmrg if (button > 11) { 5437f2e35a3aSmrg return; 5438f2e35a3aSmrg } 5439f2e35a3aSmrg } 5440d522f475Smrg 5441f2e35a3aSmrg if (screen->extend_coords == SET_PIXEL_POSITION_MOUSE) { 5442f2e35a3aSmrg row = event->y - OriginY(screen); 5443f2e35a3aSmrg col = event->x - OriginX(screen); 5444f2e35a3aSmrg } else { 5445f2e35a3aSmrg /* Compute character position of mouse pointer */ 5446f2e35a3aSmrg row = (event->y - screen->border) / FontHeight(screen); 5447f2e35a3aSmrg col = (event->x - OriginX(screen)) / FontWidth(screen); 5448d522f475Smrg 5449f2e35a3aSmrg /* Limit to screen dimensions */ 5450f2e35a3aSmrg if (row < 0) 5451f2e35a3aSmrg row = 0; 5452f2e35a3aSmrg else if (row > screen->max_row) 5453f2e35a3aSmrg row = screen->max_row; 5454492d43a5Smrg 5455f2e35a3aSmrg if (col < 0) 5456f2e35a3aSmrg col = 0; 5457f2e35a3aSmrg else if (col > screen->max_col) 5458f2e35a3aSmrg col = screen->max_col; 5459f2e35a3aSmrg 5460f2e35a3aSmrg if (mouse_limit > 0) { 5461f2e35a3aSmrg /* Limit to representable mouse dimensions */ 5462f2e35a3aSmrg if (row > mouse_limit) 5463f2e35a3aSmrg row = mouse_limit; 5464f2e35a3aSmrg if (col > mouse_limit) 5465f2e35a3aSmrg col = mouse_limit; 5466f2e35a3aSmrg } 54670bd37d32Smrg } 5468d522f475Smrg 5469d522f475Smrg /* Build key sequence starting with \E[M */ 5470d522f475Smrg if (screen->control_eight_bits) { 5471d522f475Smrg line[count++] = ANSI_CSI; 5472d522f475Smrg } else { 5473d522f475Smrg line[count++] = ANSI_ESC; 5474d522f475Smrg line[count++] = '['; 5475d522f475Smrg } 54760bd37d32Smrg switch (screen->extend_coords) { 54770bd37d32Smrg case 0: 54780bd37d32Smrg case SET_EXT_MODE_MOUSE: 5479d522f475Smrg#if OPT_SCO_FUNC_KEYS 54800bd37d32Smrg if (xw->keyboard.type == keyboardIsSCO) { 54810bd37d32Smrg /* 54820bd37d32Smrg * SCO function key F1 is \E[M, which would conflict with xterm's 54830bd37d32Smrg * normal kmous. 54840bd37d32Smrg */ 54850bd37d32Smrg line[count++] = '>'; 54860bd37d32Smrg } 5487d522f475Smrg#endif 54880bd37d32Smrg line[count++] = final; 54890bd37d32Smrg break; 54900bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5491f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 54920bd37d32Smrg line[count++] = '<'; 54930bd37d32Smrg break; 54940bd37d32Smrg } 5495d522f475Smrg 5496d522f475Smrg /* Add event code to key sequence */ 5497913cc679Smrg if (okSendMousePos(xw) == X10_MOUSE) { 54980bd37d32Smrg count = EMIT_BUTTON(button); 5499d522f475Smrg } else { 5500d522f475Smrg /* Button-Motion events */ 5501d522f475Smrg switch (event->type) { 5502d522f475Smrg case ButtonPress: 55030bd37d32Smrg screen->mouse_button |= ButtonBit(button); 55040bd37d32Smrg count = EMIT_BUTTON(button); 5505d522f475Smrg break; 5506d522f475Smrg case ButtonRelease: 5507d522f475Smrg /* 5508f2e35a3aSmrg * The (vertical) wheel mouse interface generates release-events 5509f2e35a3aSmrg * for buttons 4 and 5. 5510f2e35a3aSmrg * 5511f2e35a3aSmrg * The X10/X11 xterm protocol maps the release for buttons 1..3 to 5512f2e35a3aSmrg * a -1, which will be later mapped into a "0" (some button was 5513f2e35a3aSmrg * released), At this point, buttons 1..3 are encoded 0..2 (the 5514f2e35a3aSmrg * code 3 is unused). 5515f2e35a3aSmrg * 5516f2e35a3aSmrg * The SGR (extended) xterm mouse protocol keeps the button number 5517f2e35a3aSmrg * and uses a "m" to indicate button release. 5518f2e35a3aSmrg * 5519f2e35a3aSmrg * The behavior for mice with more buttons is unclear, and may be 5520f2e35a3aSmrg * revised -TD 5521d522f475Smrg */ 55220bd37d32Smrg screen->mouse_button &= ~ButtonBit(button); 5523f2e35a3aSmrg if (button < 3 || button > 5) { 55240bd37d32Smrg switch (screen->extend_coords) { 55250bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5526f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 55270bd37d32Smrg final = 'm'; 55280bd37d32Smrg break; 55290bd37d32Smrg default: 55300bd37d32Smrg button = -1; 55310bd37d32Smrg break; 55320bd37d32Smrg } 55330bd37d32Smrg } 55340bd37d32Smrg count = EMIT_BUTTON(button); 5535d522f475Smrg break; 5536d522f475Smrg case MotionNotify: 5537d522f475Smrg /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion 5538d522f475Smrg * events only if character cell has changed. 5539d522f475Smrg */ 5540d522f475Smrg if ((row == screen->mouse_row) 5541d522f475Smrg && (col == screen->mouse_col)) { 5542d522f475Smrg changed = False; 5543d522f475Smrg } else { 55440bd37d32Smrg count = EMIT_BUTTON(FirstBitN(screen->mouse_button)); 5545d522f475Smrg } 5546d522f475Smrg break; 5547d522f475Smrg default: 5548d522f475Smrg changed = False; 5549d522f475Smrg break; 5550d522f475Smrg } 5551d522f475Smrg } 5552d522f475Smrg 5553d522f475Smrg if (changed) { 5554d522f475Smrg screen->mouse_row = row; 5555d522f475Smrg screen->mouse_col = col; 5556d522f475Smrg 5557492d43a5Smrg TRACE(("mouse at %d,%d button+mask = %#x\n", row, col, line[count - 1])); 5558d522f475Smrg 5559492d43a5Smrg /* Add pointer position to key sequence */ 55600bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 5561492d43a5Smrg count = EmitMousePosition(screen, line, count, col); 55620bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 5563492d43a5Smrg count = EmitMousePosition(screen, line, count, row); 5564d522f475Smrg 55650bd37d32Smrg switch (screen->extend_coords) { 55660bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 55670bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 5568f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 55690bd37d32Smrg line[count++] = final; 55700bd37d32Smrg break; 55710bd37d32Smrg } 55720bd37d32Smrg 5573d522f475Smrg /* Transmit key sequence to process running under xterm */ 5574f2e35a3aSmrg TRACE(("EditorButton -> %s\n", visibleChars(line, count))); 55755307cd1aSmrg v_write(pty, line, (size_t) count); 5576d522f475Smrg } 5577d522f475Smrg return; 5578d522f475Smrg} 5579d522f475Smrg 5580913cc679Smrg/* 5581913cc679Smrg * Check the current send_mouse_pos against allowed mouse-operations, returning 5582913cc679Smrg * none if it is disallowed. 5583913cc679Smrg */ 5584913cc679SmrgXtermMouseModes 5585913cc679SmrgokSendMousePos(XtermWidget xw) 5586913cc679Smrg{ 5587913cc679Smrg TScreen *screen = TScreenOf(xw); 5588f2e35a3aSmrg XtermMouseModes result = (XtermMouseModes) screen->send_mouse_pos; 5589913cc679Smrg 5590f2e35a3aSmrg switch ((int) result) { 5591913cc679Smrg case MOUSE_OFF: 5592913cc679Smrg break; 5593913cc679Smrg case X10_MOUSE: 5594913cc679Smrg if (!AllowMouseOps(xw, emX10)) 5595913cc679Smrg result = MOUSE_OFF; 5596913cc679Smrg break; 5597913cc679Smrg case VT200_MOUSE: 5598913cc679Smrg if (!AllowMouseOps(xw, emVT200Click)) 5599913cc679Smrg result = MOUSE_OFF; 5600913cc679Smrg break; 5601913cc679Smrg case VT200_HIGHLIGHT_MOUSE: 5602913cc679Smrg if (!AllowMouseOps(xw, emVT200Hilite)) 5603913cc679Smrg result = MOUSE_OFF; 5604913cc679Smrg break; 5605913cc679Smrg case BTN_EVENT_MOUSE: 5606913cc679Smrg if (!AllowMouseOps(xw, emAnyButton)) 5607913cc679Smrg result = MOUSE_OFF; 5608913cc679Smrg break; 5609913cc679Smrg case ANY_EVENT_MOUSE: 5610913cc679Smrg if (!AllowMouseOps(xw, emAnyEvent)) 5611913cc679Smrg result = MOUSE_OFF; 5612913cc679Smrg break; 5613913cc679Smrg case DEC_LOCATOR: 5614913cc679Smrg if (!AllowMouseOps(xw, emLocator)) 5615913cc679Smrg result = MOUSE_OFF; 5616913cc679Smrg break; 5617913cc679Smrg } 5618913cc679Smrg return result; 5619913cc679Smrg} 5620913cc679Smrg 5621d522f475Smrg#if OPT_FOCUS_EVENT 5622913cc679Smrg/* 5623913cc679Smrg * Check the current send_focus_pos against allowed mouse-operations, returning 5624913cc679Smrg * none if it is disallowed. 5625913cc679Smrg */ 5626913cc679Smrgstatic int 5627913cc679SmrgokSendFocusPos(XtermWidget xw) 5628d522f475Smrg{ 5629956cc18dSsnj TScreen *screen = TScreenOf(xw); 5630913cc679Smrg int result = screen->send_focus_pos; 5631913cc679Smrg 5632913cc679Smrg if (!AllowMouseOps(xw, emFocusEvent)) { 5633913cc679Smrg result = False; 5634913cc679Smrg } 5635913cc679Smrg return result; 5636913cc679Smrg} 5637d522f475Smrg 5638913cc679Smrgvoid 5639913cc679SmrgSendFocusButton(XtermWidget xw, XFocusChangeEvent *event) 5640913cc679Smrg{ 5641913cc679Smrg if (okSendFocusPos(xw)) { 5642d522f475Smrg ANSI reply; 5643d522f475Smrg 5644d522f475Smrg memset(&reply, 0, sizeof(reply)); 5645d522f475Smrg reply.a_type = ANSI_CSI; 5646d522f475Smrg 5647d522f475Smrg#if OPT_SCO_FUNC_KEYS 5648d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 5649d522f475Smrg reply.a_pintro = '>'; 5650d522f475Smrg } 5651d522f475Smrg#endif 56522eaa94a1Schristos reply.a_final = CharOf((event->type == FocusIn) ? 'I' : 'O'); 5653d522f475Smrg unparseseq(xw, &reply); 5654d522f475Smrg } 5655d522f475Smrg return; 5656d522f475Smrg} 5657d522f475Smrg#endif /* OPT_FOCUS_EVENT */ 56580bd37d32Smrg 56590bd37d32Smrg#if OPT_SELECTION_OPS 56600bd37d32Smrg/* 56610bd37d32Smrg * Get the event-time, needed to process selections. 56620bd37d32Smrg */ 56630bd37d32Smrgstatic Time 5664894e0ac8SmrggetEventTime(XEvent *event) 56650bd37d32Smrg{ 56660bd37d32Smrg Time result; 56670bd37d32Smrg 56680bd37d32Smrg if (IsBtnEvent(event)) { 56690bd37d32Smrg result = ((XButtonEvent *) event)->time; 56700bd37d32Smrg } else if (IsKeyEvent(event)) { 56710bd37d32Smrg result = ((XKeyEvent *) event)->time; 56720bd37d32Smrg } else { 56730bd37d32Smrg result = 0; 56740bd37d32Smrg } 56750bd37d32Smrg 56760bd37d32Smrg return result; 56770bd37d32Smrg} 56780bd37d32Smrg 56790bd37d32Smrg/* obtain the selection string, passing the endpoints to caller's parameters */ 568001037d57Smrgstatic void 568101037d57SmrgdoSelectionFormat(XtermWidget xw, 568201037d57Smrg Widget w, 568301037d57Smrg XEvent *event, 568401037d57Smrg String *params, 56855104ee6eSmrg const Cardinal *num_params, 568601037d57Smrg FormatSelect format_select) 56870bd37d32Smrg{ 56880bd37d32Smrg TScreen *screen = TScreenOf(xw); 568901037d57Smrg InternalSelect *mydata = &(screen->internal_select); 569001037d57Smrg 569101037d57Smrg memset(mydata, 0, sizeof(*mydata)); 569201037d57Smrg mydata->format = x_strdup(params[0]); 569301037d57Smrg mydata->format_select = format_select; 56940bd37d32Smrg 56950bd37d32Smrg screen->selectToBuffer = True; 5696f2e35a3aSmrg beginInternalSelect(xw); 5697f2e35a3aSmrg 56980bd37d32Smrg xtermGetSelection(w, getEventTime(event), params + 1, *num_params - 1, NULL); 5699f2e35a3aSmrg 5700f2e35a3aSmrg if (screen->selectToBuffer) 5701f2e35a3aSmrg finishInternalSelect(xw); 57020bd37d32Smrg} 57030bd37d32Smrg 57040bd37d32Smrg/* obtain data from the screen, passing the endpoints to caller's parameters */ 57050bd37d32Smrgstatic char * 5706913cc679SmrggetDataFromScreen(XtermWidget xw, XEvent *event, String method, CELL *start, CELL *finish) 57070bd37d32Smrg{ 57080bd37d32Smrg TScreen *screen = TScreenOf(xw); 57090bd37d32Smrg 57100bd37d32Smrg CELL save_old_start = screen->startH; 57110bd37d32Smrg CELL save_old_end = screen->endH; 57120bd37d32Smrg 57130bd37d32Smrg CELL save_startSel = screen->startSel; 57140bd37d32Smrg CELL save_startRaw = screen->startRaw; 57150bd37d32Smrg CELL save_finishSel = screen->endSel; 57160bd37d32Smrg CELL save_finishRaw = screen->endRaw; 57170bd37d32Smrg 57180bd37d32Smrg int save_firstValidRow = screen->firstValidRow; 57190bd37d32Smrg int save_lastValidRow = screen->lastValidRow; 57200bd37d32Smrg 572101037d57Smrg const Cardinal noClick = 0; 572201037d57Smrg int save_numberOfClicks = screen->numberOfClicks; 572301037d57Smrg 57240bd37d32Smrg SelectUnit saveUnits = screen->selectUnit; 572501037d57Smrg SelectUnit saveMap = screen->selectMap[noClick]; 57260bd37d32Smrg#if OPT_SELECT_REGEX 572701037d57Smrg char *saveExpr = screen->selectExpr[noClick]; 57280bd37d32Smrg#endif 5729f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[PRIMARY_CODE]); 5730f2e35a3aSmrg SelectedCells save_selection = *scp; 57310bd37d32Smrg 57325104ee6eSmrg char *result = NULL; 57330bd37d32Smrg 57340bd37d32Smrg TRACE(("getDataFromScreen %s\n", method)); 57350bd37d32Smrg 5736f2e35a3aSmrg memset(scp, 0, sizeof(*scp)); 57370bd37d32Smrg 573801037d57Smrg screen->numberOfClicks = 1; 573901037d57Smrg lookupSelectUnit(xw, noClick, method); 574001037d57Smrg screen->selectUnit = screen->selectMap[noClick]; 57410bd37d32Smrg 57420bd37d32Smrg memset(start, 0, sizeof(*start)); 5743913cc679Smrg if (IsBtnEvent(event)) { 5744913cc679Smrg XButtonEvent *btn_event = (XButtonEvent *) event; 5745913cc679Smrg CELL cell; 5746913cc679Smrg screen->firstValidRow = 0; 5747913cc679Smrg screen->lastValidRow = screen->max_row; 5748913cc679Smrg PointToCELL(screen, btn_event->y, btn_event->x, &cell); 5749913cc679Smrg start->row = cell.row; 5750913cc679Smrg start->col = cell.col; 5751913cc679Smrg finish->row = cell.row; 5752913cc679Smrg finish->col = screen->max_col; 5753913cc679Smrg } else { 5754913cc679Smrg start->row = screen->cur_row; 5755913cc679Smrg start->col = screen->cur_col; 5756913cc679Smrg finish->row = screen->cur_row; 5757913cc679Smrg finish->col = screen->max_col; 5758913cc679Smrg } 57590bd37d32Smrg 5760f2e35a3aSmrg ComputeSelect(xw, start, finish, False, False); 5761f2e35a3aSmrg SaltTextAway(xw, 5762f2e35a3aSmrg TargetToSelection(screen, PRIMARY_NAME), 5763f2e35a3aSmrg &(screen->startSel), &(screen->endSel)); 57640bd37d32Smrg 5765f2e35a3aSmrg if (scp->data_limit && scp->data_buffer) { 5766f2e35a3aSmrg TRACE(("...getDataFromScreen selection-data %.*s\n", 5767f2e35a3aSmrg (int) scp->data_limit, 5768f2e35a3aSmrg scp->data_buffer)); 5769f2e35a3aSmrg result = malloc(scp->data_limit + 1); 57700bd37d32Smrg if (result) { 5771f2e35a3aSmrg memcpy(result, scp->data_buffer, scp->data_limit); 5772f2e35a3aSmrg result[scp->data_limit] = 0; 57730bd37d32Smrg } 5774f2e35a3aSmrg free(scp->data_buffer); 5775f2e35a3aSmrg scp->data_limit = 0; 57760bd37d32Smrg } 57770bd37d32Smrg 57780bd37d32Smrg TRACE(("...getDataFromScreen restoring previous selection\n")); 57790bd37d32Smrg 57800bd37d32Smrg screen->startSel = save_startSel; 57810bd37d32Smrg screen->startRaw = save_startRaw; 57820bd37d32Smrg screen->endSel = save_finishSel; 57830bd37d32Smrg screen->endRaw = save_finishRaw; 57840bd37d32Smrg 57850bd37d32Smrg screen->firstValidRow = save_firstValidRow; 57860bd37d32Smrg screen->lastValidRow = save_lastValidRow; 57870bd37d32Smrg 578801037d57Smrg screen->numberOfClicks = save_numberOfClicks; 57890bd37d32Smrg screen->selectUnit = saveUnits; 579001037d57Smrg screen->selectMap[noClick] = saveMap; 57910bd37d32Smrg#if OPT_SELECT_REGEX 579201037d57Smrg screen->selectExpr[noClick] = saveExpr; 57930bd37d32Smrg#endif 57940bd37d32Smrg 5795f2e35a3aSmrg screen->selected_cells[0] = save_selection; 57960bd37d32Smrg 57970bd37d32Smrg TrackText(xw, &save_old_start, &save_old_end); 57980bd37d32Smrg 57990bd37d32Smrg TRACE(("...getDataFromScreen done\n")); 58000bd37d32Smrg return result; 58010bd37d32Smrg} 58020bd37d32Smrg 58035307cd1aSmrg#if OPT_EXEC_SELECTION 58040bd37d32Smrg/* 58050bd37d32Smrg * Split-up the format before substituting data, to avoid quoting issues. 58060bd37d32Smrg * The resource mechanism has a limited ability to handle escapes. We take 58070bd37d32Smrg * the result as if it were an sh-type string and parse it into a regular 58080bd37d32Smrg * argv array. 58090bd37d32Smrg */ 58100bd37d32Smrgstatic char ** 58110bd37d32SmrgtokenizeFormat(String format) 58120bd37d32Smrg{ 58135104ee6eSmrg char **result = NULL; 58140bd37d32Smrg 58150bd37d32Smrg format = x_skip_blanks(format); 58160bd37d32Smrg if (*format != '\0') { 58170bd37d32Smrg char *blob = x_strdup(format); 58182e4f8982Smrg int pass; 58190bd37d32Smrg 58200bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 58210bd37d32Smrg int used = 0; 58220bd37d32Smrg int first = 1; 58230bd37d32Smrg int escaped = 0; 58240bd37d32Smrg int squoted = 0; 58250bd37d32Smrg int dquoted = 0; 58262e4f8982Smrg int n; 5827f2e35a3aSmrg int argc = 0; 58280bd37d32Smrg 58290bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 58300bd37d32Smrg if (escaped) { 58310bd37d32Smrg blob[used++] = format[n]; 58320bd37d32Smrg escaped = 0; 58330bd37d32Smrg } else if (format[n] == '"') { 58340bd37d32Smrg if (!squoted) { 58350bd37d32Smrg if (!dquoted) 58360bd37d32Smrg blob[used++] = format[n]; 58370bd37d32Smrg dquoted = !dquoted; 58380bd37d32Smrg } 58390bd37d32Smrg } else if (format[n] == '\'') { 58400bd37d32Smrg if (!dquoted) { 58410bd37d32Smrg if (!squoted) 58420bd37d32Smrg blob[used++] = format[n]; 58430bd37d32Smrg squoted = !squoted; 58440bd37d32Smrg } 58450bd37d32Smrg } else if (format[n] == '\\') { 58460bd37d32Smrg blob[used++] = format[n]; 58470bd37d32Smrg escaped = 1; 58480bd37d32Smrg } else { 58490bd37d32Smrg if (first) { 58500bd37d32Smrg first = 0; 58510bd37d32Smrg if (pass) { 58520bd37d32Smrg result[argc] = &blob[n]; 58530bd37d32Smrg } 58540bd37d32Smrg ++argc; 58550bd37d32Smrg } 58560bd37d32Smrg if (isspace((Char) format[n])) { 58570bd37d32Smrg first = !isspace((Char) format[n + 1]); 58580bd37d32Smrg if (squoted || dquoted) { 58590bd37d32Smrg blob[used++] = format[n]; 58600bd37d32Smrg } else if (first) { 58610bd37d32Smrg blob[used++] = '\0'; 58620bd37d32Smrg } 58630bd37d32Smrg } else { 58640bd37d32Smrg blob[used++] = format[n]; 58650bd37d32Smrg } 58660bd37d32Smrg } 58670bd37d32Smrg } 58680bd37d32Smrg blob[used] = '\0'; 58690bd37d32Smrg assert(strlen(blob) <= strlen(format)); 58700bd37d32Smrg if (!pass) { 58710bd37d32Smrg result = TypeCallocN(char *, argc + 1); 58725104ee6eSmrg if (result == NULL) { 58730bd37d32Smrg free(blob); 58740bd37d32Smrg break; 58750bd37d32Smrg } 58760bd37d32Smrg } 58770bd37d32Smrg } 58780bd37d32Smrg } 58790bd37d32Smrg#if OPT_TRACE 58800bd37d32Smrg if (result) { 5881f2e35a3aSmrg int n; 58820bd37d32Smrg TRACE(("tokenizeFormat %s\n", format)); 5883f2e35a3aSmrg for (n = 0; result[n]; ++n) { 5884f2e35a3aSmrg TRACE(("argv[%d] = %s\n", n, result[n])); 58850bd37d32Smrg } 58860bd37d32Smrg } 58870bd37d32Smrg#endif 58880bd37d32Smrg 58890bd37d32Smrg return result; 58900bd37d32Smrg} 58915307cd1aSmrg#endif /* OPT_EXEC_SELECTION */ 58920bd37d32Smrg 58930bd37d32Smrgstatic void 5894e0a2b6dfSmrgformatVideoAttrs(XtermWidget xw, char *buffer, CELL *cell) 58950bd37d32Smrg{ 58960bd37d32Smrg TScreen *screen = TScreenOf(xw); 58970bd37d32Smrg LineData *ld = GET_LINEDATA(screen, cell->row); 58980bd37d32Smrg 58990bd37d32Smrg *buffer = '\0'; 59005104ee6eSmrg if (ld != NULL && cell->col < (int) ld->lineSize) { 5901894e0ac8Smrg IAttr attribs = ld->attribs[cell->col]; 59020bd37d32Smrg const char *delim = ""; 59030bd37d32Smrg 59040bd37d32Smrg if (attribs & INVERSE) { 59050bd37d32Smrg buffer += sprintf(buffer, "7"); 59060bd37d32Smrg delim = ";"; 59070bd37d32Smrg } 59080bd37d32Smrg if (attribs & UNDERLINE) { 59090bd37d32Smrg buffer += sprintf(buffer, "%s4", delim); 59100bd37d32Smrg delim = ";"; 59110bd37d32Smrg } 59120bd37d32Smrg if (attribs & BOLD) { 59130bd37d32Smrg buffer += sprintf(buffer, "%s1", delim); 59140bd37d32Smrg delim = ";"; 59150bd37d32Smrg } 59160bd37d32Smrg if (attribs & BLINK) { 59170bd37d32Smrg buffer += sprintf(buffer, "%s5", delim); 59180bd37d32Smrg delim = ";"; 59190bd37d32Smrg } 59200bd37d32Smrg#if OPT_ISO_COLORS 59210bd37d32Smrg if (attribs & FG_COLOR) { 5922f2e35a3aSmrg Pixel fg = extract_fg(xw, ld->color[cell->col], attribs); 59230bd37d32Smrg if (fg < 8) { 59240bd37d32Smrg fg += 30; 59250bd37d32Smrg } else if (fg < 16) { 59260bd37d32Smrg fg += 90; 59270bd37d32Smrg } else { 59280bd37d32Smrg buffer += sprintf(buffer, "%s38;5", delim); 59290bd37d32Smrg delim = ";"; 59300bd37d32Smrg } 5931f2e35a3aSmrg buffer += sprintf(buffer, "%s%lu", delim, fg); 59320bd37d32Smrg delim = ";"; 59330bd37d32Smrg } 59340bd37d32Smrg if (attribs & BG_COLOR) { 5935f2e35a3aSmrg Pixel bg = extract_bg(xw, ld->color[cell->col], attribs); 59360bd37d32Smrg if (bg < 8) { 59370bd37d32Smrg bg += 40; 59380bd37d32Smrg } else if (bg < 16) { 59390bd37d32Smrg bg += 100; 59400bd37d32Smrg } else { 59410bd37d32Smrg buffer += sprintf(buffer, "%s48;5", delim); 59420bd37d32Smrg delim = ";"; 59430bd37d32Smrg } 5944f2e35a3aSmrg (void) sprintf(buffer, "%s%lu", delim, bg); 59450bd37d32Smrg } 59460bd37d32Smrg#endif 59470bd37d32Smrg } 59480bd37d32Smrg} 59490bd37d32Smrg 59502e4f8982Smrgstatic char * 59512e4f8982SmrgformatStrlen(char *target, char *source, int freeit) 59522e4f8982Smrg{ 59535104ee6eSmrg if (source != NULL) { 59542e4f8982Smrg sprintf(target, "%u", (unsigned) strlen(source)); 59552e4f8982Smrg if (freeit) { 59562e4f8982Smrg free(source); 59572e4f8982Smrg } 59582e4f8982Smrg } else { 59592e4f8982Smrg strcpy(target, "0"); 59602e4f8982Smrg } 59612e4f8982Smrg return target; 59622e4f8982Smrg} 59632e4f8982Smrg 59640bd37d32Smrg/* substitute data into format, reallocating the result */ 59650bd37d32Smrgstatic char * 59660bd37d32SmrgexpandFormat(XtermWidget xw, 59670bd37d32Smrg const char *format, 59680bd37d32Smrg char *data, 5969e0a2b6dfSmrg CELL *start, 5970e0a2b6dfSmrg CELL *finish) 59710bd37d32Smrg{ 59725104ee6eSmrg char *result = NULL; 59730bd37d32Smrg if (!IsEmpty(format)) { 59740bd37d32Smrg static char empty[1]; 59750bd37d32Smrg int pass; 59760bd37d32Smrg int n; 59770bd37d32Smrg char numbers[80]; 59780bd37d32Smrg 59795104ee6eSmrg if (data == NULL) 59800bd37d32Smrg data = empty; 59810bd37d32Smrg 59820bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 59830bd37d32Smrg size_t need = 0; 59840bd37d32Smrg 59850bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 59860bd37d32Smrg 59870bd37d32Smrg if (format[n] == '%') { 59885104ee6eSmrg char *value = NULL; 59892e4f8982Smrg 59900bd37d32Smrg switch (format[++n]) { 59910bd37d32Smrg case '%': 59920bd37d32Smrg if (pass) { 59930bd37d32Smrg result[need] = format[n]; 59940bd37d32Smrg } 59950bd37d32Smrg ++need; 59960bd37d32Smrg break; 59970bd37d32Smrg case 'P': 59980bd37d32Smrg sprintf(numbers, "%d;%d", 59990bd37d32Smrg TScreenOf(xw)->topline + start->row + 1, 60000bd37d32Smrg start->col + 1); 60010bd37d32Smrg value = numbers; 60020bd37d32Smrg break; 60030bd37d32Smrg case 'p': 60040bd37d32Smrg sprintf(numbers, "%d;%d", 60050bd37d32Smrg TScreenOf(xw)->topline + finish->row + 1, 60060bd37d32Smrg finish->col + 1); 60070bd37d32Smrg value = numbers; 60080bd37d32Smrg break; 60092e4f8982Smrg case 'R': 60102e4f8982Smrg value = formatStrlen(numbers, x_strrtrim(data), 1); 60112e4f8982Smrg break; 60122e4f8982Smrg case 'r': 60132e4f8982Smrg value = x_strrtrim(data); 60142e4f8982Smrg break; 60150bd37d32Smrg case 'S': 60162e4f8982Smrg value = formatStrlen(numbers, data, 0); 60170bd37d32Smrg break; 60180bd37d32Smrg case 's': 60190bd37d32Smrg value = data; 60200bd37d32Smrg break; 60210bd37d32Smrg case 'T': 60222e4f8982Smrg value = formatStrlen(numbers, x_strtrim(data), 1); 60230bd37d32Smrg break; 60240bd37d32Smrg case 't': 60250bd37d32Smrg value = x_strtrim(data); 60260bd37d32Smrg break; 60270bd37d32Smrg case 'V': 60280bd37d32Smrg formatVideoAttrs(xw, numbers, start); 60290bd37d32Smrg value = numbers; 60300bd37d32Smrg break; 60310bd37d32Smrg case 'v': 60320bd37d32Smrg formatVideoAttrs(xw, numbers, finish); 60330bd37d32Smrg value = numbers; 60340bd37d32Smrg break; 60350bd37d32Smrg default: 60360bd37d32Smrg if (pass) { 60370bd37d32Smrg result[need] = format[n]; 60380bd37d32Smrg } 60390bd37d32Smrg --n; 60400bd37d32Smrg ++need; 60410bd37d32Smrg break; 60420bd37d32Smrg } 60435104ee6eSmrg if (value != NULL) { 60440bd37d32Smrg if (pass) { 60450bd37d32Smrg strcpy(result + need, value); 60460bd37d32Smrg } 60470bd37d32Smrg need += strlen(value); 60480bd37d32Smrg if (value != numbers && value != data) { 60490bd37d32Smrg free(value); 60500bd37d32Smrg } 60510bd37d32Smrg } 60520bd37d32Smrg } else { 60530bd37d32Smrg if (pass) { 60540bd37d32Smrg result[need] = format[n]; 60550bd37d32Smrg } 60560bd37d32Smrg ++need; 60570bd37d32Smrg } 60580bd37d32Smrg } 60590bd37d32Smrg if (pass) { 60600bd37d32Smrg result[need] = '\0'; 60610bd37d32Smrg } else { 60620bd37d32Smrg ++need; 60630bd37d32Smrg result = malloc(need); 60645104ee6eSmrg if (result == NULL) { 60650bd37d32Smrg break; 60660bd37d32Smrg } 60670bd37d32Smrg } 60680bd37d32Smrg } 60690bd37d32Smrg } 60700bd37d32Smrg TRACE(("expandFormat(%s) = %s\n", NonNull(format), NonNull(result))); 60710bd37d32Smrg return result; 60720bd37d32Smrg} 60730bd37d32Smrg 60745307cd1aSmrg#if OPT_EXEC_SELECTION 60750bd37d32Smrg/* execute the command after forking. The main process frees its data */ 60760bd37d32Smrgstatic void 60772e4f8982SmrgexecuteCommand(pid_t pid, char **argv) 60780bd37d32Smrg{ 60792e4f8982Smrg (void) pid; 60805104ee6eSmrg if (argv != NULL && argv[0] != NULL) { 60812e4f8982Smrg char *child_cwd = ProcGetCWD(pid); 60822e4f8982Smrg 60830bd37d32Smrg if (fork() == 0) { 60842e4f8982Smrg if (child_cwd) { 60852e4f8982Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 60862e4f8982Smrg } 60870bd37d32Smrg execvp(argv[0], argv); 60880bd37d32Smrg exit(EXIT_FAILURE); 60890bd37d32Smrg } 6090913cc679Smrg free(child_cwd); 60910bd37d32Smrg } 60920bd37d32Smrg} 60930bd37d32Smrg 60940bd37d32Smrgstatic void 60950bd37d32SmrgfreeArgv(char *blob, char **argv) 60960bd37d32Smrg{ 60970bd37d32Smrg if (blob) { 60980bd37d32Smrg free(blob); 60990bd37d32Smrg if (argv) { 61002e4f8982Smrg int n; 61010bd37d32Smrg for (n = 0; argv[n]; ++n) 61020bd37d32Smrg free(argv[n]); 61030bd37d32Smrg free(argv); 61040bd37d32Smrg } 61050bd37d32Smrg } 61060bd37d32Smrg} 61070bd37d32Smrg 610801037d57Smrgstatic void 610901037d57SmrgreallyExecFormatted(Widget w, char *format, char *data, CELL *start, CELL *finish) 611001037d57Smrg{ 611101037d57Smrg XtermWidget xw; 611201037d57Smrg 61135104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 611401037d57Smrg char **argv; 611501037d57Smrg 61165104ee6eSmrg if ((argv = tokenizeFormat(format)) != NULL) { 61172e4f8982Smrg char *blob = argv[0]; 61182e4f8982Smrg int argc; 61192e4f8982Smrg 61205104ee6eSmrg for (argc = 0; argv[argc] != NULL; ++argc) { 612101037d57Smrg argv[argc] = expandFormat(xw, argv[argc], data, start, finish); 612201037d57Smrg } 61232e4f8982Smrg executeCommand(TScreenOf(xw)->pid, argv); 612401037d57Smrg freeArgv(blob, argv); 612501037d57Smrg } 612601037d57Smrg } 612701037d57Smrg} 612801037d57Smrg 61290bd37d32Smrgvoid 61300bd37d32SmrgHandleExecFormatted(Widget w, 613101037d57Smrg XEvent *event, 6132e0a2b6dfSmrg String *params, /* selections */ 61330bd37d32Smrg Cardinal *num_params) 61340bd37d32Smrg{ 61350bd37d32Smrg XtermWidget xw; 61360bd37d32Smrg 6137f2e35a3aSmrg TRACE_EVENT("HandleExecFormatted", event, params, num_params); 61385104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL && 613901037d57Smrg (*num_params > 1)) { 614001037d57Smrg doSelectionFormat(xw, w, event, params, num_params, reallyExecFormatted); 61410bd37d32Smrg } 61420bd37d32Smrg} 61430bd37d32Smrg 61440bd37d32Smrgvoid 61450bd37d32SmrgHandleExecSelectable(Widget w, 6146913cc679Smrg XEvent *event, 6147e0a2b6dfSmrg String *params, /* selections */ 61480bd37d32Smrg Cardinal *num_params) 61490bd37d32Smrg{ 61500bd37d32Smrg XtermWidget xw; 61510bd37d32Smrg 61525104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 6153f2e35a3aSmrg TRACE_EVENT("HandleExecSelectable", event, params, num_params); 61540bd37d32Smrg 61550bd37d32Smrg if (*num_params == 2) { 61560bd37d32Smrg CELL start, finish; 61570bd37d32Smrg char *data; 61580bd37d32Smrg char **argv; 61590bd37d32Smrg 6160913cc679Smrg data = getDataFromScreen(xw, event, params[1], &start, &finish); 61615104ee6eSmrg if (data != NULL) { 61625104ee6eSmrg if ((argv = tokenizeFormat(params[0])) != NULL) { 61632e4f8982Smrg char *blob = argv[0]; 61642e4f8982Smrg int argc; 61652e4f8982Smrg 61665104ee6eSmrg for (argc = 0; argv[argc] != NULL; ++argc) { 61670bd37d32Smrg argv[argc] = expandFormat(xw, argv[argc], data, 61680bd37d32Smrg &start, &finish); 61690bd37d32Smrg } 61702e4f8982Smrg executeCommand(TScreenOf(xw)->pid, argv); 61710bd37d32Smrg freeArgv(blob, argv); 61720bd37d32Smrg } 6173894e0ac8Smrg free(data); 61740bd37d32Smrg } 61750bd37d32Smrg } 61760bd37d32Smrg } 61770bd37d32Smrg} 61785307cd1aSmrg#endif /* OPT_EXEC_SELECTION */ 61790bd37d32Smrg 618001037d57Smrgstatic void 618101037d57SmrgreallyInsertFormatted(Widget w, char *format, char *data, CELL *start, CELL *finish) 618201037d57Smrg{ 618301037d57Smrg XtermWidget xw; 618401037d57Smrg 61855104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 618601037d57Smrg char *exps; 618701037d57Smrg 61885104ee6eSmrg if ((exps = expandFormat(xw, format, data, start, finish)) != NULL) { 618901037d57Smrg unparseputs(xw, exps); 619001037d57Smrg unparse_end(xw); 619101037d57Smrg free(exps); 619201037d57Smrg } 619301037d57Smrg } 619401037d57Smrg} 619501037d57Smrg 61960bd37d32Smrgvoid 61970bd37d32SmrgHandleInsertFormatted(Widget w, 619801037d57Smrg XEvent *event, 6199e0a2b6dfSmrg String *params, /* selections */ 62000bd37d32Smrg Cardinal *num_params) 62010bd37d32Smrg{ 62020bd37d32Smrg XtermWidget xw; 62030bd37d32Smrg 6204f2e35a3aSmrg TRACE_EVENT("HandleInsertFormatted", event, params, num_params); 62055104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL && 620601037d57Smrg (*num_params > 1)) { 620701037d57Smrg doSelectionFormat(xw, w, event, params, num_params, reallyInsertFormatted); 62080bd37d32Smrg } 62090bd37d32Smrg} 62100bd37d32Smrg 62110bd37d32Smrgvoid 62120bd37d32SmrgHandleInsertSelectable(Widget w, 6213913cc679Smrg XEvent *event, 6214e0a2b6dfSmrg String *params, /* selections */ 62150bd37d32Smrg Cardinal *num_params) 62160bd37d32Smrg{ 62170bd37d32Smrg XtermWidget xw; 62180bd37d32Smrg 62195104ee6eSmrg if ((xw = getXtermWidget(w)) != NULL) { 6220f2e35a3aSmrg TRACE_EVENT("HandleInsertSelectable", event, params, num_params); 62210bd37d32Smrg 62220bd37d32Smrg if (*num_params == 2) { 62230bd37d32Smrg CELL start, finish; 62240bd37d32Smrg char *data; 62250bd37d32Smrg char *temp = x_strdup(params[0]); 62260bd37d32Smrg 6227913cc679Smrg data = getDataFromScreen(xw, event, params[1], &start, &finish); 62285104ee6eSmrg if (data != NULL) { 62292e4f8982Smrg char *exps = expandFormat(xw, temp, data, &start, &finish); 62305104ee6eSmrg if (exps != NULL) { 62310bd37d32Smrg unparseputs(xw, exps); 623201037d57Smrg unparse_end(xw); 62330bd37d32Smrg free(exps); 62340bd37d32Smrg } 62350bd37d32Smrg free(data); 62360bd37d32Smrg } 62370bd37d32Smrg free(temp); 62380bd37d32Smrg } 62390bd37d32Smrg } 62400bd37d32Smrg} 62410bd37d32Smrg#endif /* OPT_SELECTION_OPS */ 6242