button.c revision 04b94745
104b94745Smrg/* $XTermId: button.c,v 1.663 2024/04/19 07:42:00 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 404b94745Smrg * Copyright 1999-2023,2024 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); 193f2e35a3aSmrgstatic void ComputeSelect(XtermWidget xw, CELL *startc, CELL *endc, Bool 194f2e35a3aSmrg 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); 200e0a2b6dfSmrgstatic void ReHiliteText(XtermWidget xw, CELL *first, CELL *last); 201f2e35a3aSmrgstatic void SaltTextAway(XtermWidget xw, int which, CELL *cellc, 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)) { 333f2e35a3aSmrg target = 0; 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; 443f2e35a3aSmrg while ((next = scanTrans(data, &state, &state2, &first, &last)) != 0) { 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 1379956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 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 1411956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 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 1467956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 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 1508956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 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 1544956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 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 1589956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 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 1603956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 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; 1619f2e35a3aSmrg if ((xw = getXtermWidget(w)) != 0) { 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; 1636f2e35a3aSmrg if ((xw = getXtermWidget(w)) != 0) { 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 1654492d43a5Smrg if ((xw = getXtermWidget(w)) != 0) { 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; 18000bd37d32Smrg if ((data = UTF8toLatin1(screen, data, size, &size)) != 0) { 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 1860956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1861956cc18dSsnj TScreen *screen = TScreenOf(xw); 1862956cc18dSsnj 186320d2c4d2Smrg if (!IsEmpty(value)) { 1864492d43a5Smrg char *copied = x_strdup(value); 1865956cc18dSsnj if (copied != 0) { 1866956cc18dSsnj Atom *result = 0; 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 1934956cc18dSsnj if (*resultp == 0) { 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 1970956cc18dSsnj if (*resultp == 0) { 1971956cc18dSsnj Atom *result = 0; 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 2006956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) { 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 2080913cc679Smrg if (params != 0 && 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); 2098d522f475Smrg if ((result = TypeMallocN(String, num_params + 1)) != 0) { 2099d522f475Smrg result[num_params] = 0; 2100d522f475Smrg for (j = 0; j < num_params; ++j) { 21015307cd1aSmrg result[j] = (String) (isSELECT(params[j]) 2102d522f475Smrg ? mapTo 21035307cd1aSmrg : params[j]); 2104d522f475Smrg if (result[j] == 0) { 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; 2191956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 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 2233d522f475Smrg if (targets != 0) { 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); 2249d522f475Smrg if (list != 0) { 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 2288d522f475Smrg#ifdef VMS 2289d522f475Smrg# define tty_vwrite(pty,lag,l) tt_write(lag,l) 2290d522f475Smrg#else /* !( VMS ) */ 22915307cd1aSmrg# define tty_vwrite(pty,lag,l) v_write(pty,lag,(size_t) l) 2292d522f475Smrg#endif /* defined VMS */ 2293d522f475Smrg 2294d522f475Smrg#if OPT_PASTE64 2295d522f475Smrg/* Return base64 code character given 6-bit number */ 2296d522f475Smrgstatic const char base64_code[] = "\ 2297d522f475SmrgABCDEFGHIJKLMNOPQRSTUVWXYZ\ 2298d522f475Smrgabcdefghijklmnopqrstuvwxyz\ 2299d522f475Smrg0123456789+/"; 2300d522f475Smrgstatic void 2301e0a2b6dfSmrgbase64_flush(TScreen *screen) 2302d522f475Smrg{ 2303d522f475Smrg Char x; 230401037d57Smrg 230501037d57Smrg TRACE(("base64_flush count %d, pad %d (%d)\n", 230601037d57Smrg screen->base64_count, 230701037d57Smrg screen->base64_pad, 230801037d57Smrg screen->base64_pad & 3)); 230901037d57Smrg 2310d522f475Smrg switch (screen->base64_count) { 2311d522f475Smrg case 0: 2312d522f475Smrg break; 2313d522f475Smrg case 2: 23142eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 4]); 2315d522f475Smrg tty_vwrite(screen->respond, &x, 1); 2316d522f475Smrg break; 2317d522f475Smrg case 4: 23182eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 2]); 2319d522f475Smrg tty_vwrite(screen->respond, &x, 1); 2320d522f475Smrg break; 2321d522f475Smrg } 232201037d57Smrg if (screen->base64_pad & 3) { 2323d522f475Smrg tty_vwrite(screen->respond, 2324492d43a5Smrg (const Char *) "===", 232501037d57Smrg (unsigned) (3 - (screen->base64_pad & 3))); 232601037d57Smrg } 2327d522f475Smrg screen->base64_count = 0; 2328d522f475Smrg screen->base64_accu = 0; 2329d522f475Smrg screen->base64_pad = 0; 2330d522f475Smrg} 2331d522f475Smrg#endif /* OPT_PASTE64 */ 2332d522f475Smrg 2333e0a2b6dfSmrg/* 2334e0a2b6dfSmrg * Translate ISO-8859-1 or UTF-8 data to NRCS. 2335e0a2b6dfSmrg */ 2336d522f475Smrgstatic void 23375307cd1aSmrgToNational(XtermWidget xw, Char *buffer, size_t *length) 2338e0a2b6dfSmrg{ 2339f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2340f2e35a3aSmrg DECNRCM_codes gsetL = screen->gsets[screen->curgl]; 2341f2e35a3aSmrg DECNRCM_codes gsetR = screen->gsets[screen->curgr]; 2342e0a2b6dfSmrg 2343e0a2b6dfSmrg#if OPT_WIDE_CHARS 2344e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 23452e4f8982Smrg Char *p; 2346e0a2b6dfSmrg PtyData *data = TypeXtMallocX(PtyData, *length); 2347e0a2b6dfSmrg 2348e0a2b6dfSmrg memset(data, 0, sizeof(*data)); 2349e0a2b6dfSmrg data->next = data->buffer; 2350e0a2b6dfSmrg data->last = data->buffer + *length; 23515307cd1aSmrg memcpy(data->buffer, buffer, *length); 2352e0a2b6dfSmrg p = buffer; 2353e0a2b6dfSmrg while (data->next < data->last) { 23542e4f8982Smrg unsigned chr, out, gl, gr; 23552e4f8982Smrg 2356894e0ac8Smrg if (!decodeUtf8(screen, data)) { 2357e0a2b6dfSmrg data->utf_size = 1; 2358e0a2b6dfSmrg data->utf_data = data->next[0]; 2359e0a2b6dfSmrg } 2360e0a2b6dfSmrg data->next += data->utf_size; 2361e0a2b6dfSmrg chr = data->utf_data; 2362e0a2b6dfSmrg out = chr; 2363f2e35a3aSmrg if ((gl = xtermCharSetIn(xw, chr, gsetL)) != chr) { 2364e0a2b6dfSmrg out = gl; 2365f2e35a3aSmrg } else if ((gr = xtermCharSetIn(xw, chr, gsetR)) != chr) { 2366e0a2b6dfSmrg out = gr; 2367e0a2b6dfSmrg } 2368e0a2b6dfSmrg *p++ = (Char) ((out < 256) ? out : ' '); 2369e0a2b6dfSmrg } 23705307cd1aSmrg *length = (size_t) (p - buffer); 2371e0a2b6dfSmrg free(data); 2372e0a2b6dfSmrg } else 2373e0a2b6dfSmrg#endif 2374e0a2b6dfSmrg { 23752e4f8982Smrg Char *p; 23762e4f8982Smrg 23775307cd1aSmrg for (p = buffer; (size_t) (p - buffer) < *length; ++p) { 23782e4f8982Smrg unsigned gl, gr; 23792e4f8982Smrg unsigned chr = *p; 23802e4f8982Smrg unsigned out = chr; 2381f2e35a3aSmrg if ((gl = xtermCharSetIn(xw, chr, gsetL)) != chr) { 2382e0a2b6dfSmrg out = gl; 2383f2e35a3aSmrg } else if ((gr = xtermCharSetIn(xw, chr, gsetR)) != chr) { 2384e0a2b6dfSmrg out = gr; 2385e0a2b6dfSmrg } 2386e0a2b6dfSmrg *p = (Char) out; 2387e0a2b6dfSmrg } 2388e0a2b6dfSmrg } 2389e0a2b6dfSmrg} 2390e0a2b6dfSmrg 2391e0a2b6dfSmrgstatic void 23925307cd1aSmrg_qWriteSelectionData(XtermWidget xw, Char *lag, size_t length) 2393d522f475Smrg{ 23940bd37d32Smrg TScreen *screen = TScreenOf(xw); 23950bd37d32Smrg 2396e0a2b6dfSmrg /* 2397e0a2b6dfSmrg * If we are pasting into a window which is using NRCS, we want to map 2398e0a2b6dfSmrg * the text from the normal encoding (ISO-8859-1 or UTF-8) into the coding 2399e0a2b6dfSmrg * that an application would use to write characters with NRCS. 2400e0a2b6dfSmrg * 2401e0a2b6dfSmrg * TODO: handle conversion from UTF-8, and adjust length. This can be done 2402e0a2b6dfSmrg * in the same buffer because the target is always 8-bit. 2403e0a2b6dfSmrg */ 2404e0a2b6dfSmrg if ((xw->flags & NATIONAL) && (length != 0)) { 2405f2e35a3aSmrg ToNational(xw, lag, &length); 2406e0a2b6dfSmrg } 2407d522f475Smrg#if OPT_PASTE64 2408d522f475Smrg if (screen->base64_paste) { 2409d522f475Smrg /* Send data as base64 */ 2410d522f475Smrg Char *p = lag; 2411d522f475Smrg Char buf[64]; 2412d522f475Smrg unsigned x = 0; 24130bd37d32Smrg 24145307cd1aSmrg TRACE(("convert to base64 %lu:%s\n", 24155307cd1aSmrg (unsigned long) length, 24165307cd1aSmrg visibleChars(p, length))); 241701037d57Smrg 24180bd37d32Smrg /* 24190bd37d32Smrg * Handle the case where the selection is from _this_ xterm, which 24200bd37d32Smrg * puts part of the reply in the buffer before the selection callback 24210bd37d32Smrg * happens. 24220bd37d32Smrg */ 24230bd37d32Smrg if (screen->base64_paste && screen->unparse_len) { 24240bd37d32Smrg unparse_end(xw); 24250bd37d32Smrg } 2426d522f475Smrg while (length--) { 2427d522f475Smrg switch (screen->base64_count) { 2428d522f475Smrg case 0: 24292eaa94a1Schristos buf[x++] = CharOf(base64_code[*p >> 2]); 24302eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0x3); 2431d522f475Smrg screen->base64_count = 2; 2432d522f475Smrg ++p; 2433d522f475Smrg break; 2434d522f475Smrg case 2: 24352eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 4) + 24362eaa94a1Schristos (*p >> 4)]); 24372eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0xF); 2438d522f475Smrg screen->base64_count = 4; 2439d522f475Smrg ++p; 2440d522f475Smrg break; 2441d522f475Smrg case 4: 24422eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 2) + 24432eaa94a1Schristos (*p >> 6)]); 24442eaa94a1Schristos buf[x++] = CharOf(base64_code[*p & 0x3F]); 2445d522f475Smrg screen->base64_accu = 0; 2446d522f475Smrg screen->base64_count = 0; 2447d522f475Smrg ++p; 2448d522f475Smrg break; 2449d522f475Smrg } 2450d522f475Smrg if (x >= 63) { 2451d522f475Smrg /* Write 63 or 64 characters */ 2452d522f475Smrg screen->base64_pad += x; 245301037d57Smrg TRACE(("writing base64 interim %s\n", visibleChars(buf, x))); 2454d522f475Smrg tty_vwrite(screen->respond, buf, x); 2455d522f475Smrg x = 0; 2456d522f475Smrg } 2457d522f475Smrg } 2458d522f475Smrg if (x != 0) { 2459d522f475Smrg screen->base64_pad += x; 246001037d57Smrg TRACE(("writing base64 finish %s\n", visibleChars(buf, x))); 2461d522f475Smrg tty_vwrite(screen->respond, buf, x); 2462d522f475Smrg } 2463d522f475Smrg } else 2464d522f475Smrg#endif /* OPT_PASTE64 */ 2465d522f475Smrg#if OPT_READLINE 2466d522f475Smrg if (SCREEN_FLAG(screen, paste_quotes)) { 24675307cd1aSmrg Char quote[2]; 24685307cd1aSmrg quote[0] = (Char) get_tty_lnext(screen->respond, XTERM_LNEXT, "pty"); 24695307cd1aSmrg quote[1] = 0; 24705307cd1aSmrg TRACE(("writing quoted selection data %s\n", visibleChars(lag, length))); 2471d522f475Smrg while (length--) { 24725307cd1aSmrg tty_vwrite(screen->respond, quote, 1); 2473d522f475Smrg tty_vwrite(screen->respond, lag++, 1); 2474d522f475Smrg } 2475d522f475Smrg } else 2476d522f475Smrg#endif 247701037d57Smrg { 24785307cd1aSmrg TRACE(("writing selection data %s\n", visibleChars(lag, length))); 2479d522f475Smrg tty_vwrite(screen->respond, lag, length); 248001037d57Smrg } 2481d522f475Smrg} 2482d522f475Smrg 2483d522f475Smrgstatic void 2484e0a2b6dfSmrg_WriteSelectionData(XtermWidget xw, Char *line, size_t length) 2485d522f475Smrg{ 24865307cd1aSmrg#if OPT_PASTE64 || OPT_READLINE 24870bd37d32Smrg TScreen *screen = TScreenOf(xw); 24882e4f8982Smrg#endif 2489d522f475Smrg 2490d522f475Smrg /* in the VMS version, if tt_pasting isn't set to True then qio 2491d522f475Smrg reads aren't blocked and an infinite loop is entered, where the 2492d522f475Smrg pasted text shows up as new input, goes in again, shows up 2493d522f475Smrg again, ad nauseum. */ 2494d522f475Smrg#ifdef VMS 2495d522f475Smrg tt_pasting = True; 2496d522f475Smrg#endif 2497d522f475Smrg 2498d522f475Smrg#if OPT_PASTE64 2499d522f475Smrg if (screen->base64_paste) { 25005307cd1aSmrg _qWriteSelectionData(xw, line, length); 2501d522f475Smrg base64_flush(screen); 2502d522f475Smrg } else 2503d522f475Smrg#endif 2504d522f475Smrg { 2505d522f475Smrg if (!SCREEN_FLAG(screen, paste_literal_nl)) { 25065307cd1aSmrg size_t n; 25075307cd1aSmrg for (n = 0; n < length; ++n) { 25085307cd1aSmrg if (line[n] == '\n') { 25095307cd1aSmrg line[n] = '\r'; 2510d522f475Smrg } 2511d522f475Smrg } 2512d522f475Smrg } 2513d522f475Smrg 25145307cd1aSmrg _qWriteSelectionData(xw, line, length); 2515d522f475Smrg } 2516d522f475Smrg#ifdef VMS 2517d522f475Smrg tt_pasting = False; 2518d522f475Smrg tt_start_read(); /* reenable reads or a character may be lost */ 2519d522f475Smrg#endif 2520d522f475Smrg} 2521d522f475Smrg 2522f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2523d522f475Smrgstatic void 2524e0a2b6dfSmrg_WriteKey(TScreen *screen, const Char *in) 2525d522f475Smrg{ 2526d522f475Smrg Char line[16]; 2527d522f475Smrg unsigned count = 0; 2528492d43a5Smrg size_t length = strlen((const char *) in); 2529d522f475Smrg 2530d522f475Smrg if (screen->control_eight_bits) { 2531d522f475Smrg line[count++] = ANSI_CSI; 2532d522f475Smrg } else { 2533d522f475Smrg line[count++] = ANSI_ESC; 2534d522f475Smrg line[count++] = '['; 2535d522f475Smrg } 2536d522f475Smrg while (length--) 2537d522f475Smrg line[count++] = *in++; 2538d522f475Smrg line[count++] = '~'; 2539d522f475Smrg tty_vwrite(screen->respond, line, count); 2540d522f475Smrg} 2541d522f475Smrg#endif /* OPT_READLINE */ 2542d522f475Smrg 25430bd37d32Smrg/* 25440bd37d32Smrg * Unless enabled by the user, strip control characters other than formatting. 25450bd37d32Smrg */ 25460bd37d32Smrgstatic size_t 25470bd37d32SmrgremoveControls(XtermWidget xw, char *value) 25480bd37d32Smrg{ 25490bd37d32Smrg TScreen *screen = TScreenOf(xw); 25500bd37d32Smrg size_t dst = 0; 25510bd37d32Smrg 25520bd37d32Smrg if (screen->allowPasteControls) { 25530bd37d32Smrg dst = strlen(value); 25540bd37d32Smrg } else { 25552e4f8982Smrg size_t src = 0; 255604b94745Smrg Boolean *disallowed = screen->disallow_paste_ops; 255704b94745Smrg TERMIO_STRUCT data; 255804b94745Smrg char current_chars[epLAST]; 255904b94745Smrg 256004b94745Smrg if (disallowed[epSTTY] && ttyGetAttr(screen->respond, &data) == 0) { 256104b94745Smrg int n; 256204b94745Smrg int disabled = xtermDisabledChar(); 256304b94745Smrg 256404b94745Smrg TRACE(("disallow(STTY):")); 256504b94745Smrg memcpy(current_chars, disallowed, sizeof(current_chars)); 256604b94745Smrg 256704b94745Smrg for (n = 0; n < NCCS; ++n) { 256804b94745Smrg PasteControls nc = (data.c_cc[n] < 32 256904b94745Smrg ? data.c_cc[n] 257004b94745Smrg : (data.c_cc[n] == 127 257104b94745Smrg ? epDEL 257204b94745Smrg : epLAST)); 257304b94745Smrg if (nc == epNUL || nc == epLAST) 257404b94745Smrg continue; 257504b94745Smrg if (CharOf(data.c_cc[n]) == CharOf(disabled)) 257604b94745Smrg continue; 257704b94745Smrg if ((n == VMIN || n == VTIME) && !(data.c_lflag & ICANON)) 257804b94745Smrg continue; 257904b94745Smrg switch (n) { 258004b94745Smrg /* POSIX */ 258104b94745Smrg case VEOF: 258204b94745Smrg case VEOL: 258304b94745Smrg case VERASE: 258404b94745Smrg case VINTR: 258504b94745Smrg case VKILL: 258604b94745Smrg case VQUIT: 258704b94745Smrg case VSTART: 258804b94745Smrg case VSTOP: 258904b94745Smrg case VSUSP: 259004b94745Smrg /* system-dependent */ 259104b94745Smrg#ifdef VDISCARD 259204b94745Smrg case VDISCARD: 259304b94745Smrg#endif 259404b94745Smrg#ifdef VDSUSP 259504b94745Smrg case VDSUSP: 259604b94745Smrg#endif 259704b94745Smrg#ifdef VEOL2 259804b94745Smrg case VEOL2: 259904b94745Smrg#endif 260004b94745Smrg#ifdef VLNEXT 260104b94745Smrg case VLNEXT: 260204b94745Smrg#endif 260304b94745Smrg#ifdef VREPRINT 260404b94745Smrg case VREPRINT: 260504b94745Smrg#endif 260604b94745Smrg#ifdef VSTATUS 260704b94745Smrg case VSTATUS: 260804b94745Smrg#endif 260904b94745Smrg#ifdef VSWTC 261004b94745Smrg case VSWTC: /* System V SWTCH */ 261104b94745Smrg#endif 261204b94745Smrg#ifdef VWERASE 261304b94745Smrg case VWERASE: 261404b94745Smrg#endif 261504b94745Smrg break; 261604b94745Smrg default: 261704b94745Smrg continue; 261804b94745Smrg } 261904b94745Smrg if (nc != epLAST) { 262004b94745Smrg TRACE((" \\%03o", data.c_cc[n])); 262104b94745Smrg current_chars[nc] = 1; 262204b94745Smrg } 262304b94745Smrg } 262404b94745Smrg TRACE(("\n")); 262504b94745Smrg disallowed = current_chars; 262604b94745Smrg } 26270bd37d32Smrg while ((value[dst] = value[src]) != '\0') { 26280bd37d32Smrg int ch = CharOf(value[src++]); 2629f2e35a3aSmrg 2630f2e35a3aSmrg#define ReplacePaste(n) \ 263104b94745Smrg if (disallowed[n]) \ 2632f2e35a3aSmrg value[dst] = ' ' 2633f2e35a3aSmrg 26340bd37d32Smrg if (ch < 32) { 2635f2e35a3aSmrg ReplacePaste(epC0); 2636f2e35a3aSmrg ReplacePaste(ch); 2637f2e35a3aSmrg ++dst; 2638f2e35a3aSmrg } else if (ch == ANSI_DEL) { 2639f2e35a3aSmrg ReplacePaste(epDEL); 2640f2e35a3aSmrg ++dst; 26410bd37d32Smrg } 26420bd37d32Smrg#if OPT_WIDE_CHARS 2643e0a2b6dfSmrg else if (screen->utf8_inparse || screen->utf8_nrc_mode) 26440bd37d32Smrg ++dst; 26450bd37d32Smrg#endif 26460bd37d32Smrg#if OPT_C1_PRINT || OPT_WIDE_CHARS 26470bd37d32Smrg else if (screen->c1_printable) 26480bd37d32Smrg ++dst; 26490bd37d32Smrg#endif 26500bd37d32Smrg else if (ch >= 128 && ch < 160) 26510bd37d32Smrg continue; 26520bd37d32Smrg else 26530bd37d32Smrg ++dst; 26540bd37d32Smrg } 26550bd37d32Smrg } 26560bd37d32Smrg return dst; 26570bd37d32Smrg} 26580bd37d32Smrg 2659f2e35a3aSmrg#if OPT_SELECTION_OPS 2660f2e35a3aSmrgstatic void 2661f2e35a3aSmrgbeginInternalSelect(XtermWidget xw) 2662f2e35a3aSmrg{ 2663f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2664f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2665f2e35a3aSmrg 2666f2e35a3aSmrg (void) mydata; 2667f2e35a3aSmrg /* override flags so that SelectionReceived only updates a buffer */ 2668f2e35a3aSmrg#if OPT_PASTE64 2669f2e35a3aSmrg mydata->base64_paste = screen->base64_paste; 2670f2e35a3aSmrg screen->base64_paste = 0; 2671f2e35a3aSmrg#endif 2672f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2673f2e35a3aSmrg mydata->paste_brackets = screen->paste_brackets; 2674f2e35a3aSmrg SCREEN_FLAG_unset(screen, paste_brackets); 2675f2e35a3aSmrg#endif 2676f2e35a3aSmrg} 2677f2e35a3aSmrg 2678f2e35a3aSmrgstatic void 2679f2e35a3aSmrgfinishInternalSelect(XtermWidget xw) 2680f2e35a3aSmrg{ 2681f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2682f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2683f2e35a3aSmrg 2684f2e35a3aSmrg (void) mydata; 2685f2e35a3aSmrg#if OPT_PASTE64 2686f2e35a3aSmrg screen->base64_paste = mydata->base64_paste; 2687f2e35a3aSmrg#endif 2688f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2689f2e35a3aSmrg screen->paste_brackets = mydata->paste_brackets; 2690f2e35a3aSmrg#endif 2691f2e35a3aSmrg} 2692f2e35a3aSmrg 2693f2e35a3aSmrg#else 2694f2e35a3aSmrg#define finishInternalSelect(xw) /* nothing */ 2695f2e35a3aSmrg#endif /* OPT_SELECTION_OPS */ 2696f2e35a3aSmrg 2697d522f475Smrg/* SelectionReceived: stuff received selection text into pty */ 2698d522f475Smrg 2699d522f475Smrg/* ARGSUSED */ 2700d522f475Smrgstatic void 2701d522f475SmrgSelectionReceived(Widget w, 2702d522f475Smrg XtPointer client_data, 2703894e0ac8Smrg Atom *selection GCC_UNUSED, 2704894e0ac8Smrg Atom *type, 2705d522f475Smrg XtPointer value, 2706d522f475Smrg unsigned long *length, 2707d522f475Smrg int *format) 2708d522f475Smrg{ 2709d522f475Smrg char **text_list = NULL; 27102e4f8982Smrg int text_list_count = 0; 2711d522f475Smrg XTextProperty text_prop; 2712d522f475Smrg TScreen *screen; 2713d522f475Smrg Display *dpy; 2714d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 2715d522f475Smrg Char *line = (Char *) value; 2716d522f475Smrg#endif 2717d522f475Smrg 2718956cc18dSsnj XtermWidget xw; 2719956cc18dSsnj 2720956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 2721d522f475Smrg return; 2722956cc18dSsnj 2723956cc18dSsnj screen = TScreenOf(xw); 2724d522f475Smrg dpy = XtDisplay(w); 2725d522f475Smrg 2726d522f475Smrg if (*type == 0 /*XT_CONVERT_FAIL */ 2727d522f475Smrg || *length == 0 272801037d57Smrg || value == NULL) { 272901037d57Smrg TRACE(("...no data to convert\n")); 2730d522f475Smrg goto fail; 273101037d57Smrg } 2732d522f475Smrg 2733d522f475Smrg text_prop.value = (unsigned char *) value; 2734d522f475Smrg text_prop.encoding = *type; 2735d522f475Smrg text_prop.format = *format; 2736d522f475Smrg text_prop.nitems = *length; 2737d522f475Smrg 273801037d57Smrg TRACE(("SelectionReceived %s %s format %d, nitems %ld\n", 2739913cc679Smrg TraceAtomName(screen->display, *selection), 2740956cc18dSsnj visibleSelectionTarget(dpy, text_prop.encoding), 2741956cc18dSsnj text_prop.format, 2742956cc18dSsnj text_prop.nitems)); 2743956cc18dSsnj 2744d522f475Smrg#if OPT_WIDE_CHARS 2745e39b573cSmrg if (XSupportsLocale() && screen->wide_chars) { 2746d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2747d522f475Smrg *type == XA_STRING || 2748d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2749d522f475Smrg GettingSelection(dpy, *type, line, *length); 2750d522f475Smrg if (Xutf8TextPropertyToTextList(dpy, &text_prop, 2751d522f475Smrg &text_list, 2752d522f475Smrg &text_list_count) < 0) { 2753e39b573cSmrg TRACE(("default Xutf8 Conversion failed\n")); 2754d522f475Smrg text_list = NULL; 2755d522f475Smrg } 2756d522f475Smrg } 2757d522f475Smrg } else 2758d522f475Smrg#endif /* OPT_WIDE_CHARS */ 2759d522f475Smrg { 2760d522f475Smrg /* Convert the selection to locale's multibyte encoding. */ 2761d522f475Smrg 2762d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2763d522f475Smrg *type == XA_STRING || 2764d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2765d522f475Smrg Status rc; 2766d522f475Smrg 2767d522f475Smrg GettingSelection(dpy, *type, line, *length); 2768d522f475Smrg 2769d522f475Smrg#if OPT_WIDE_CHARS 2770d522f475Smrg if (*type == XA_UTF8_STRING(dpy) && 2771d522f475Smrg !(screen->wide_chars || screen->c1_printable)) { 277220d2c4d2Smrg rc = xtermUtf8ToTextList(xw, &text_prop, 277320d2c4d2Smrg &text_list, &text_list_count); 2774d522f475Smrg } else 2775d522f475Smrg#endif 2776e39b573cSmrg if (*type == XA_STRING && (!XSupportsLocale() || screen->brokenSelections)) { 2777d522f475Smrg rc = XTextPropertyToStringList(&text_prop, 2778d522f475Smrg &text_list, &text_list_count); 2779d522f475Smrg } else { 2780d522f475Smrg rc = XmbTextPropertyToTextList(dpy, &text_prop, 2781d522f475Smrg &text_list, 2782d522f475Smrg &text_list_count); 2783d522f475Smrg } 2784d522f475Smrg if (rc < 0) { 2785d522f475Smrg TRACE(("Conversion failed\n")); 2786d522f475Smrg text_list = NULL; 2787d522f475Smrg } 2788d522f475Smrg } 2789d522f475Smrg } 2790d522f475Smrg 2791d522f475Smrg if (text_list != NULL && text_list_count != 0) { 2792d522f475Smrg int i; 2793d522f475Smrg 2794d522f475Smrg#if OPT_PASTE64 2795d522f475Smrg if (screen->base64_paste) { 2796a1f3da82Smrg /* EMPTY */ ; 2797d522f475Smrg } else 2798d522f475Smrg#endif 2799f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2800f2e35a3aSmrg if (SCREEN_FLAG(screen, paste_brackets) && !screen->selectToBuffer) { 2801492d43a5Smrg _WriteKey(screen, (const Char *) "200"); 2802d522f475Smrg } 2803d522f475Smrg#endif 2804d522f475Smrg for (i = 0; i < text_list_count; i++) { 28050bd37d32Smrg size_t len = removeControls(xw, text_list[i]); 280601037d57Smrg 28070bd37d32Smrg if (screen->selectToBuffer) { 280801037d57Smrg InternalSelect *mydata = &(screen->internal_select); 2809f2e35a3aSmrg if (!mydata->done) { 2810f2e35a3aSmrg size_t have = (mydata->buffer 2811f2e35a3aSmrg ? strlen(mydata->buffer) 2812f2e35a3aSmrg : 0); 2813f2e35a3aSmrg size_t need = have + len + 1; 2814f2e35a3aSmrg char *buffer = realloc(mydata->buffer, need); 2815f2e35a3aSmrg 2816f2e35a3aSmrg if (buffer != 0) { 2817f2e35a3aSmrg strcpy(buffer + have, text_list[i]); 2818f2e35a3aSmrg mydata->buffer = buffer; 2819f2e35a3aSmrg } 2820f2e35a3aSmrg TRACE(("FormatSelect %d.%d .. %d.%d %s\n", 2821f2e35a3aSmrg screen->startSel.row, 2822f2e35a3aSmrg screen->startSel.col, 2823f2e35a3aSmrg screen->endSel.row, 2824f2e35a3aSmrg screen->endSel.col, 2825f2e35a3aSmrg mydata->buffer)); 2826f2e35a3aSmrg mydata->format_select(w, mydata->format, mydata->buffer, 2827f2e35a3aSmrg &(screen->startSel), 2828f2e35a3aSmrg &(screen->endSel)); 2829f2e35a3aSmrg mydata->done = True; 28300bd37d32Smrg } 283101037d57Smrg 28320bd37d32Smrg } else { 28330bd37d32Smrg _WriteSelectionData(xw, (Char *) text_list[i], len); 28340bd37d32Smrg } 2835d522f475Smrg } 2836d522f475Smrg#if OPT_PASTE64 2837d522f475Smrg if (screen->base64_paste) { 2838956cc18dSsnj FinishPaste64(xw); 2839d522f475Smrg } else 2840d522f475Smrg#endif 2841f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2842f2e35a3aSmrg if (SCREEN_FLAG(screen, paste_brackets) && !screen->selectToBuffer) { 2843492d43a5Smrg _WriteKey(screen, (const Char *) "201"); 2844d522f475Smrg } 2845d522f475Smrg#endif 2846f2e35a3aSmrg if (screen->selectToBuffer) { 2847f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2848f2e35a3aSmrg finishInternalSelect(xw); 2849f2e35a3aSmrg if (mydata->done) { 2850f2e35a3aSmrg free(mydata->format); 2851f2e35a3aSmrg free(mydata->buffer); 2852f2e35a3aSmrg memset(mydata, 0, sizeof(*mydata)); 2853f2e35a3aSmrg } 2854f2e35a3aSmrg screen->selectToBuffer = False; 2855f2e35a3aSmrg } 2856d522f475Smrg XFreeStringList(text_list); 285701037d57Smrg } else { 285801037d57Smrg TRACE(("...empty text-list\n")); 2859d522f475Smrg goto fail; 286001037d57Smrg } 2861d522f475Smrg 2862d522f475Smrg XtFree((char *) client_data); 2863d522f475Smrg XtFree((char *) value); 2864d522f475Smrg 2865d522f475Smrg return; 2866d522f475Smrg 2867d522f475Smrg fail: 2868d522f475Smrg if (client_data != 0) { 2869d522f475Smrg struct _SelectionList *list = (struct _SelectionList *) client_data; 2870956cc18dSsnj 2871956cc18dSsnj TRACE(("SelectionReceived ->xtermGetSelection\n")); 2872d522f475Smrg xtermGetSelection(w, list->time, 2873d522f475Smrg list->params, list->count, list->targets); 2874d522f475Smrg XtFree((char *) client_data); 2875d522f475Smrg#if OPT_PASTE64 2876d522f475Smrg } else { 2877956cc18dSsnj FinishPaste64(xw); 2878d522f475Smrg#endif 2879d522f475Smrg } 2880d522f475Smrg return; 2881d522f475Smrg} 2882d522f475Smrg 2883d522f475Smrgvoid 2884d522f475SmrgHandleInsertSelection(Widget w, 2885894e0ac8Smrg XEvent *event, /* assumed to be XButtonEvent* */ 2886e0a2b6dfSmrg String *params, /* selections in precedence order */ 2887d522f475Smrg Cardinal *num_params) 2888d522f475Smrg{ 2889956cc18dSsnj XtermWidget xw; 2890d522f475Smrg 2891956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2892f2e35a3aSmrg TRACE_EVENT("HandleInsertSelection", event, params, num_params); 2893d522f475Smrg if (!SendMousePosition(xw, event)) { 2894d522f475Smrg#if OPT_READLINE 2895d522f475Smrg int ldelta; 2896956cc18dSsnj TScreen *screen = TScreenOf(xw); 2897492d43a5Smrg if (IsBtnEvent(event) 2898f2e35a3aSmrg && !OverrideEvent(event) 2899913cc679Smrg && (okSendMousePos(xw) == MOUSE_OFF) 2900d522f475Smrg && SCREEN_FLAG(screen, paste_moves) 2901d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta)) 29025307cd1aSmrg ReadLineMovePoint(xw, eventColBetween(screen, event), ldelta); 2903d522f475Smrg#endif /* OPT_READLINE */ 2904d522f475Smrg 2905d522f475Smrg xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL); 2906d522f475Smrg } 2907d522f475Smrg } 2908d522f475Smrg} 2909d522f475Smrg 2910d522f475Smrgstatic SelectUnit 2911956cc18dSsnjEvalSelectUnit(XtermWidget xw, 2912d522f475Smrg Time buttonDownTime, 2913d522f475Smrg SelectUnit defaultUnit, 2914d522f475Smrg unsigned int button) 2915d522f475Smrg{ 2916956cc18dSsnj TScreen *screen = TScreenOf(xw); 2917d522f475Smrg SelectUnit result; 2918d522f475Smrg int delta; 2919d522f475Smrg 2920d522f475Smrg if (button != screen->lastButton) { 292120d2c4d2Smrg delta = screen->multiClickTime + 1; 2922d522f475Smrg } else if (screen->lastButtonUpTime == (Time) 0) { 2923d522f475Smrg /* first time and once in a blue moon */ 2924d522f475Smrg delta = screen->multiClickTime + 1; 2925d522f475Smrg } else if (buttonDownTime > screen->lastButtonUpTime) { 2926d522f475Smrg /* most of the time */ 29272eaa94a1Schristos delta = (int) (buttonDownTime - screen->lastButtonUpTime); 2928d522f475Smrg } else { 2929d522f475Smrg /* time has rolled over since lastButtonUpTime */ 29302eaa94a1Schristos delta = (int) ((((Time) ~ 0) - screen->lastButtonUpTime) + buttonDownTime); 2931d522f475Smrg } 2932d522f475Smrg 2933d522f475Smrg if (delta > screen->multiClickTime) { 2934d522f475Smrg screen->numberOfClicks = 1; 2935d522f475Smrg result = defaultUnit; 2936d522f475Smrg } else { 2937d522f475Smrg result = screen->selectMap[screen->numberOfClicks % screen->maxClicks]; 2938d522f475Smrg screen->numberOfClicks += 1; 2939d522f475Smrg } 2940d522f475Smrg TRACE(("EvalSelectUnit(%d) = %d\n", screen->numberOfClicks, result)); 2941d522f475Smrg return result; 2942d522f475Smrg} 2943d522f475Smrg 2944d522f475Smrgstatic void 2945d522f475Smrgdo_select_start(XtermWidget xw, 2946894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2947e0a2b6dfSmrg CELL *cell) 2948d522f475Smrg{ 2949956cc18dSsnj TScreen *screen = TScreenOf(xw); 2950d522f475Smrg 2951d522f475Smrg if (SendMousePosition(xw, event)) 2952d522f475Smrg return; 2953956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2954d522f475Smrg event->xbutton.time, 2955d522f475Smrg Select_CHAR, 2956d522f475Smrg event->xbutton.button); 2957d522f475Smrg screen->replyToEmacs = False; 2958d522f475Smrg 2959d522f475Smrg#if OPT_READLINE 2960d522f475Smrg lastButtonDownTime = event->xbutton.time; 2961d522f475Smrg#endif 2962d522f475Smrg 2963d522f475Smrg StartSelect(xw, cell); 2964d522f475Smrg} 2965d522f475Smrg 2966d522f475Smrg/* ARGSUSED */ 2967d522f475Smrgvoid 2968d522f475SmrgHandleSelectStart(Widget w, 2969894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2970e0a2b6dfSmrg String *params GCC_UNUSED, 2971d522f475Smrg Cardinal *num_params GCC_UNUSED) 2972d522f475Smrg{ 2973956cc18dSsnj XtermWidget xw; 2974956cc18dSsnj 2975956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2976956cc18dSsnj TScreen *screen = TScreenOf(xw); 2977d522f475Smrg CELL cell; 2978d522f475Smrg 2979f2e35a3aSmrg TRACE_EVENT("HandleSelectStart", event, params, num_params); 2980d522f475Smrg screen->firstValidRow = 0; 2981d522f475Smrg screen->lastValidRow = screen->max_row; 2982d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2983d522f475Smrg 2984d522f475Smrg#if OPT_READLINE 2985d522f475Smrg ExtendingSelection = 0; 2986d522f475Smrg#endif 2987d522f475Smrg 2988d522f475Smrg do_select_start(xw, event, &cell); 2989d522f475Smrg } 2990d522f475Smrg} 2991d522f475Smrg 2992d522f475Smrg/* ARGSUSED */ 2993d522f475Smrgvoid 2994d522f475SmrgHandleKeyboardSelectStart(Widget w, 2995894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2996e0a2b6dfSmrg String *params GCC_UNUSED, 2997d522f475Smrg Cardinal *num_params GCC_UNUSED) 2998d522f475Smrg{ 2999956cc18dSsnj XtermWidget xw; 3000956cc18dSsnj 3001956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3002956cc18dSsnj TScreen *screen = TScreenOf(xw); 30030bd37d32Smrg 3004f2e35a3aSmrg TRACE_EVENT("HandleKeyboardSelectStart", event, params, num_params); 3005d522f475Smrg do_select_start(xw, event, &screen->cursorp); 3006d522f475Smrg } 3007d522f475Smrg} 3008d522f475Smrg 3009d522f475Smrgstatic void 3010894e0ac8SmrgTrackDown(XtermWidget xw, XButtonEvent *event) 3011d522f475Smrg{ 3012956cc18dSsnj TScreen *screen = TScreenOf(xw); 3013d522f475Smrg CELL cell; 3014d522f475Smrg 3015956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 3016d522f475Smrg event->time, 3017d522f475Smrg Select_CHAR, 3018d522f475Smrg event->button); 3019d522f475Smrg if (screen->numberOfClicks > 1) { 3020d522f475Smrg PointToCELL(screen, event->y, event->x, &cell); 3021d522f475Smrg screen->replyToEmacs = True; 3022d522f475Smrg StartSelect(xw, &cell); 3023d522f475Smrg } else { 3024d522f475Smrg screen->waitingForTrackInfo = True; 3025492d43a5Smrg EditorButton(xw, event); 3026d522f475Smrg } 3027d522f475Smrg} 3028d522f475Smrg 3029d522f475Smrg#define boundsCheck(x) if (x < 0) \ 3030d522f475Smrg x = 0; \ 3031d522f475Smrg else if (x >= screen->max_row) \ 3032d522f475Smrg x = screen->max_row 3033d522f475Smrg 3034d522f475Smrgvoid 3035d522f475SmrgTrackMouse(XtermWidget xw, 3036d522f475Smrg int func, 3037e0a2b6dfSmrg CELL *start, 3038d522f475Smrg int firstrow, 3039d522f475Smrg int lastrow) 3040d522f475Smrg{ 3041956cc18dSsnj TScreen *screen = TScreenOf(xw); 3042d522f475Smrg 3043d522f475Smrg if (screen->waitingForTrackInfo) { /* if Timed, ignore */ 3044d522f475Smrg screen->waitingForTrackInfo = False; 3045d522f475Smrg 3046d522f475Smrg if (func != 0) { 3047d522f475Smrg CELL first = *start; 3048d522f475Smrg 3049d522f475Smrg boundsCheck(first.row); 3050d522f475Smrg boundsCheck(firstrow); 3051d522f475Smrg boundsCheck(lastrow); 3052d522f475Smrg screen->firstValidRow = firstrow; 3053d522f475Smrg screen->lastValidRow = lastrow; 3054d522f475Smrg screen->replyToEmacs = True; 3055d522f475Smrg StartSelect(xw, &first); 3056d522f475Smrg } 3057d522f475Smrg } 3058d522f475Smrg} 3059d522f475Smrg 3060d522f475Smrgstatic void 3061e0a2b6dfSmrgStartSelect(XtermWidget xw, const CELL *cell) 3062d522f475Smrg{ 3063956cc18dSsnj TScreen *screen = TScreenOf(xw); 3064d522f475Smrg 3065d522f475Smrg TRACE(("StartSelect row=%d, col=%d\n", cell->row, cell->col)); 3066d522f475Smrg if (screen->cursor_state) 3067f2e35a3aSmrg HideCursor(xw); 3068d522f475Smrg if (screen->numberOfClicks == 1) { 3069d522f475Smrg /* set start of selection */ 3070d522f475Smrg screen->rawPos = *cell; 3071d522f475Smrg } 3072d522f475Smrg /* else use old values in rawPos */ 3073d522f475Smrg screen->saveStartR = screen->startExt = screen->rawPos; 3074d522f475Smrg screen->saveEndR = screen->endExt = screen->rawPos; 3075d522f475Smrg if (Coordinate(screen, cell) < Coordinate(screen, &(screen->rawPos))) { 3076d522f475Smrg screen->eventMode = LEFTEXTENSION; 3077d522f475Smrg screen->startExt = *cell; 3078d522f475Smrg } else { 3079d522f475Smrg screen->eventMode = RIGHTEXTENSION; 3080d522f475Smrg screen->endExt = *cell; 3081d522f475Smrg } 3082f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False, True); 3083d522f475Smrg} 3084d522f475Smrg 3085d522f475Smrgstatic void 3086d522f475SmrgEndExtend(XtermWidget xw, 3087894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 3088e0a2b6dfSmrg String *params, /* selections */ 3089d522f475Smrg Cardinal num_params, 3090d522f475Smrg Bool use_cursor_loc) 3091d522f475Smrg{ 3092d522f475Smrg CELL cell; 3093956cc18dSsnj TScreen *screen = TScreenOf(xw); 3094d522f475Smrg 3095f2e35a3aSmrg TRACE_EVENT("EndExtend", event, params, &num_params); 3096d522f475Smrg if (use_cursor_loc) { 3097d522f475Smrg cell = screen->cursorp; 3098d522f475Smrg } else { 3099d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 3100d522f475Smrg } 3101d522f475Smrg ExtendExtend(xw, &cell); 31022e4f8982Smrg 3103d522f475Smrg screen->lastButtonUpTime = event->xbutton.time; 3104d522f475Smrg screen->lastButton = event->xbutton.button; 31052e4f8982Smrg 3106d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 3107d522f475Smrg if (screen->replyToEmacs) { 31082e4f8982Smrg Char line[64]; 31092e4f8982Smrg unsigned count = 0; 31102e4f8982Smrg 3111d522f475Smrg if (screen->control_eight_bits) { 3112d522f475Smrg line[count++] = ANSI_CSI; 3113d522f475Smrg } else { 3114d522f475Smrg line[count++] = ANSI_ESC; 3115d522f475Smrg line[count++] = '['; 3116d522f475Smrg } 3117d522f475Smrg if (isSameCELL(&(screen->rawPos), &(screen->startSel)) 3118d522f475Smrg && isSameCELL(&cell, &(screen->endSel))) { 3119d522f475Smrg /* Use short-form emacs select */ 31200bd37d32Smrg 31210bd37d32Smrg switch (screen->extend_coords) { 31220bd37d32Smrg case 0: 31230bd37d32Smrg case SET_EXT_MODE_MOUSE: 31240bd37d32Smrg line[count++] = 't'; 31250bd37d32Smrg break; 31260bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 3127f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 31280bd37d32Smrg line[count++] = '<'; 31290bd37d32Smrg break; 31300bd37d32Smrg } 31310bd37d32Smrg 3132492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 31330bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3134492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 31350bd37d32Smrg 31360bd37d32Smrg switch (screen->extend_coords) { 31370bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 31380bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 3139f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 31400bd37d32Smrg line[count++] = 't'; 31410bd37d32Smrg break; 31420bd37d32Smrg } 3143d522f475Smrg } else { 3144d522f475Smrg /* long-form, specify everything */ 31450bd37d32Smrg 31460bd37d32Smrg switch (screen->extend_coords) { 31470bd37d32Smrg case 0: 31480bd37d32Smrg case SET_EXT_MODE_MOUSE: 31490bd37d32Smrg line[count++] = 'T'; 31500bd37d32Smrg break; 31510bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 3152f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 31530bd37d32Smrg line[count++] = '<'; 31540bd37d32Smrg break; 31550bd37d32Smrg } 31560bd37d32Smrg 3157492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.col); 31580bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3159492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.row); 31600bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3161492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 31620bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3163492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 31640bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3165492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.col); 31660bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3167492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.row); 31680bd37d32Smrg 31690bd37d32Smrg switch (screen->extend_coords) { 31700bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 31710bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 3172f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 31730bd37d32Smrg line[count++] = 'T'; 31740bd37d32Smrg break; 31750bd37d32Smrg } 3176d522f475Smrg } 31775307cd1aSmrg v_write(screen->respond, line, (size_t) count); 3178f2e35a3aSmrg UnHiliteText(xw); 3179d522f475Smrg } 3180d522f475Smrg } 3181d522f475Smrg SelectSet(xw, event, params, num_params); 3182d522f475Smrg screen->eventMode = NORMAL; 3183d522f475Smrg} 3184d522f475Smrg 3185d522f475Smrgvoid 3186d522f475SmrgHandleSelectSet(Widget w, 3187894e0ac8Smrg XEvent *event, 3188e0a2b6dfSmrg String *params, 3189d522f475Smrg Cardinal *num_params) 3190d522f475Smrg{ 3191956cc18dSsnj XtermWidget xw; 3192956cc18dSsnj 3193956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3194f2e35a3aSmrg TRACE_EVENT("HandleSelectSet", event, params, num_params); 3195956cc18dSsnj SelectSet(xw, event, params, *num_params); 3196d522f475Smrg } 3197d522f475Smrg} 3198d522f475Smrg 3199d522f475Smrg/* ARGSUSED */ 3200d522f475Smrgstatic void 3201d522f475SmrgSelectSet(XtermWidget xw, 3202894e0ac8Smrg XEvent *event GCC_UNUSED, 3203e0a2b6dfSmrg String *params, 3204d522f475Smrg Cardinal num_params) 3205d522f475Smrg{ 3206956cc18dSsnj TScreen *screen = TScreenOf(xw); 3207d522f475Smrg 3208d522f475Smrg TRACE(("SelectSet\n")); 3209d522f475Smrg /* Only do select stuff if non-null select */ 3210d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 3211f2e35a3aSmrg Cardinal n; 3212f2e35a3aSmrg for (n = 0; n < num_params; ++n) { 3213f2e35a3aSmrg SaltTextAway(xw, 3214f2e35a3aSmrg TargetToSelection(screen, params[n]), 3215f2e35a3aSmrg &(screen->startSel), &(screen->endSel)); 3216f2e35a3aSmrg } 32170bd37d32Smrg _OwnSelection(xw, params, num_params); 3218d522f475Smrg } else { 32190bd37d32Smrg ScrnDisownSelection(xw); 3220d522f475Smrg } 3221d522f475Smrg} 3222d522f475Smrg 3223d522f475Smrg#define Abs(x) ((x) < 0 ? -(x) : (x)) 3224d522f475Smrg 3225d522f475Smrg/* ARGSUSED */ 3226d522f475Smrgstatic void 3227d522f475Smrgdo_start_extend(XtermWidget xw, 3228894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3229e0a2b6dfSmrg String *params GCC_UNUSED, 3230d522f475Smrg Cardinal *num_params GCC_UNUSED, 3231d522f475Smrg Bool use_cursor_loc) 3232d522f475Smrg{ 3233956cc18dSsnj TScreen *screen = TScreenOf(xw); 3234d522f475Smrg int coord; 3235d522f475Smrg CELL cell; 3236d522f475Smrg 3237d522f475Smrg if (SendMousePosition(xw, event)) 3238d522f475Smrg return; 3239d522f475Smrg 3240d522f475Smrg screen->firstValidRow = 0; 3241d522f475Smrg screen->lastValidRow = screen->max_row; 3242d522f475Smrg#if OPT_READLINE 3243f2e35a3aSmrg if (OverrideEvent(event) 3244d522f475Smrg || event->xbutton.button != Button3 3245d522f475Smrg || !(SCREEN_FLAG(screen, dclick3_deletes))) 3246d522f475Smrg#endif 3247956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 3248d522f475Smrg event->xbutton.time, 3249d522f475Smrg screen->selectUnit, 3250d522f475Smrg event->xbutton.button); 3251d522f475Smrg screen->replyToEmacs = False; 3252d522f475Smrg 3253d522f475Smrg#if OPT_READLINE 3254f2e35a3aSmrg CheckSecondPress3(xw, screen, event); 3255d522f475Smrg#endif 3256d522f475Smrg 3257d522f475Smrg if (screen->numberOfClicks == 1 3258f2e35a3aSmrg || (SCREEN_FLAG(screen, dclick3_deletes) 3259f2e35a3aSmrg && !OverrideEvent(event))) { 3260d522f475Smrg /* Save existing selection so we can reestablish it if the guy 3261d522f475Smrg extends past the other end of the selection */ 3262d522f475Smrg screen->saveStartR = screen->startExt = screen->startRaw; 3263d522f475Smrg screen->saveEndR = screen->endExt = screen->endRaw; 3264d522f475Smrg } else { 3265d522f475Smrg /* He just needed the selection mode changed, use old values. */ 3266d522f475Smrg screen->startExt = screen->startRaw = screen->saveStartR; 3267d522f475Smrg screen->endExt = screen->endRaw = screen->saveEndR; 3268d522f475Smrg } 3269d522f475Smrg if (use_cursor_loc) { 3270d522f475Smrg cell = screen->cursorp; 3271d522f475Smrg } else { 3272d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 3273d522f475Smrg } 3274d522f475Smrg coord = Coordinate(screen, &cell); 3275d522f475Smrg 3276d522f475Smrg if (Abs(coord - Coordinate(screen, &(screen->startSel))) 3277d522f475Smrg < Abs(coord - Coordinate(screen, &(screen->endSel))) 3278d522f475Smrg || coord < Coordinate(screen, &(screen->startSel))) { 3279d522f475Smrg /* point is close to left side of selection */ 3280d522f475Smrg screen->eventMode = LEFTEXTENSION; 3281d522f475Smrg screen->startExt = cell; 3282d522f475Smrg } else { 3283d522f475Smrg /* point is close to left side of selection */ 3284d522f475Smrg screen->eventMode = RIGHTEXTENSION; 3285d522f475Smrg screen->endExt = cell; 3286d522f475Smrg } 3287f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), True, True); 3288d522f475Smrg 3289d522f475Smrg#if OPT_READLINE 3290d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 3291d522f475Smrg ExtendingSelection = 1; 3292d522f475Smrg#endif 3293d522f475Smrg} 3294d522f475Smrg 3295d522f475Smrgstatic void 3296e0a2b6dfSmrgExtendExtend(XtermWidget xw, const CELL *cell) 3297d522f475Smrg{ 3298956cc18dSsnj TScreen *screen = TScreenOf(xw); 3299d522f475Smrg int coord = Coordinate(screen, cell); 3300d522f475Smrg 3301d522f475Smrg TRACE(("ExtendExtend row=%d, col=%d\n", cell->row, cell->col)); 3302d522f475Smrg if (screen->eventMode == LEFTEXTENSION 3303d522f475Smrg && ((coord + (screen->selectUnit != Select_CHAR)) 3304d522f475Smrg > Coordinate(screen, &(screen->endSel)))) { 3305d522f475Smrg /* Whoops, he's changed his mind. Do RIGHTEXTENSION */ 3306d522f475Smrg screen->eventMode = RIGHTEXTENSION; 3307d522f475Smrg screen->startExt = screen->saveStartR; 3308d522f475Smrg } else if (screen->eventMode == RIGHTEXTENSION 3309d522f475Smrg && coord < Coordinate(screen, &(screen->startSel))) { 3310d522f475Smrg /* Whoops, he's changed his mind. Do LEFTEXTENSION */ 3311d522f475Smrg screen->eventMode = LEFTEXTENSION; 3312d522f475Smrg screen->endExt = screen->saveEndR; 3313d522f475Smrg } 3314d522f475Smrg if (screen->eventMode == LEFTEXTENSION) { 3315d522f475Smrg screen->startExt = *cell; 3316d522f475Smrg } else { 3317d522f475Smrg screen->endExt = *cell; 3318d522f475Smrg } 3319f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False, True); 3320d522f475Smrg 3321d522f475Smrg#if OPT_READLINE 3322d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 3323d522f475Smrg ExtendingSelection = 1; 3324d522f475Smrg#endif 3325d522f475Smrg} 3326d522f475Smrg 3327d522f475Smrgvoid 3328d522f475SmrgHandleStartExtend(Widget w, 3329894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3330e0a2b6dfSmrg String *params, /* unused */ 3331d522f475Smrg Cardinal *num_params) /* unused */ 3332d522f475Smrg{ 3333956cc18dSsnj XtermWidget xw; 3334956cc18dSsnj 3335956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3336f2e35a3aSmrg TRACE_EVENT("HandleStartExtend", event, params, num_params); 3337956cc18dSsnj do_start_extend(xw, event, params, num_params, False); 3338956cc18dSsnj } 3339d522f475Smrg} 3340d522f475Smrg 3341d522f475Smrgvoid 3342d522f475SmrgHandleKeyboardStartExtend(Widget w, 3343894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3344e0a2b6dfSmrg String *params, /* unused */ 3345d522f475Smrg Cardinal *num_params) /* unused */ 3346d522f475Smrg{ 3347956cc18dSsnj XtermWidget xw; 3348956cc18dSsnj 3349956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3350f2e35a3aSmrg TRACE_EVENT("HandleKeyboardStartExtend", event, params, num_params); 3351956cc18dSsnj do_start_extend(xw, event, params, num_params, True); 3352956cc18dSsnj } 3353d522f475Smrg} 3354d522f475Smrg 3355d522f475Smrgvoid 3356e0a2b6dfSmrgScrollSelection(TScreen *screen, int amount, Bool always) 3357d522f475Smrg{ 3358d522f475Smrg int minrow = INX2ROW(screen, -screen->savedlines); 3359d522f475Smrg int maxrow = INX2ROW(screen, screen->max_row); 3360d522f475Smrg int maxcol = screen->max_col; 3361d522f475Smrg 3362d522f475Smrg#define scroll_update_one(cell) \ 3363d522f475Smrg (cell)->row += amount; \ 3364d522f475Smrg if ((cell)->row < minrow) { \ 3365d522f475Smrg (cell)->row = minrow; \ 3366d522f475Smrg (cell)->col = 0; \ 3367d522f475Smrg } \ 3368d522f475Smrg if ((cell)->row > maxrow) { \ 3369d522f475Smrg (cell)->row = maxrow; \ 3370d522f475Smrg (cell)->col = maxcol; \ 3371d522f475Smrg } 3372d522f475Smrg 3373d522f475Smrg scroll_update_one(&(screen->startRaw)); 3374d522f475Smrg scroll_update_one(&(screen->endRaw)); 3375d522f475Smrg scroll_update_one(&(screen->startSel)); 3376d522f475Smrg scroll_update_one(&(screen->endSel)); 3377d522f475Smrg 3378d522f475Smrg scroll_update_one(&(screen->rawPos)); 3379d522f475Smrg 3380d522f475Smrg /* 3381d522f475Smrg * If we are told to scroll the selection but it lies outside the scrolling 3382d522f475Smrg * margins, then that could cause the selection to move (bad). It is not 3383d522f475Smrg * simple to fix, because this function is called both for the scrollbar 3384d522f475Smrg * actions as well as application scrolling. The 'always' flag is set in 3385d522f475Smrg * the former case. The rest of the logic handles the latter. 3386d522f475Smrg */ 3387d522f475Smrg if (ScrnHaveSelection(screen)) { 3388d522f475Smrg int adjust; 3389d522f475Smrg 3390d522f475Smrg adjust = ROW2INX(screen, screen->startH.row); 3391d522f475Smrg if (always 33920bd37d32Smrg || !ScrnHaveRowMargins(screen) 33930bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 3394d522f475Smrg scroll_update_one(&screen->startH); 3395d522f475Smrg } 3396d522f475Smrg adjust = ROW2INX(screen, screen->endH.row); 3397d522f475Smrg if (always 33980bd37d32Smrg || !ScrnHaveRowMargins(screen) 33990bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 3400d522f475Smrg scroll_update_one(&screen->endH); 3401d522f475Smrg } 3402d522f475Smrg } 3403d522f475Smrg 3404d522f475Smrg screen->startHCoord = Coordinate(screen, &screen->startH); 3405d522f475Smrg screen->endHCoord = Coordinate(screen, &screen->endH); 3406d522f475Smrg} 3407d522f475Smrg 3408d522f475Smrg/*ARGSUSED*/ 3409d522f475Smrgvoid 3410f2e35a3aSmrgResizeSelection(TScreen *screen, int rows, int cols) 3411d522f475Smrg{ 3412d522f475Smrg rows--; /* decr to get 0-max */ 3413d522f475Smrg cols--; 3414d522f475Smrg 3415d522f475Smrg if (screen->startRaw.row > rows) 3416d522f475Smrg screen->startRaw.row = rows; 3417d522f475Smrg if (screen->startSel.row > rows) 3418d522f475Smrg screen->startSel.row = rows; 3419d522f475Smrg if (screen->endRaw.row > rows) 3420d522f475Smrg screen->endRaw.row = rows; 3421d522f475Smrg if (screen->endSel.row > rows) 3422d522f475Smrg screen->endSel.row = rows; 3423d522f475Smrg if (screen->rawPos.row > rows) 3424d522f475Smrg screen->rawPos.row = rows; 3425d522f475Smrg 3426d522f475Smrg if (screen->startRaw.col > cols) 3427d522f475Smrg screen->startRaw.col = cols; 3428d522f475Smrg if (screen->startSel.col > cols) 3429d522f475Smrg screen->startSel.col = cols; 3430d522f475Smrg if (screen->endRaw.col > cols) 3431d522f475Smrg screen->endRaw.col = cols; 3432d522f475Smrg if (screen->endSel.col > cols) 3433d522f475Smrg screen->endSel.col = cols; 3434d522f475Smrg if (screen->rawPos.col > cols) 3435d522f475Smrg screen->rawPos.col = cols; 3436d522f475Smrg} 3437d522f475Smrg 3438d522f475Smrg#if OPT_WIDE_CHARS 3439f2e35a3aSmrg#define isWideCell(row, col) isWideFrg((int)XTERM_CELL(row, col)) 3440d522f475Smrg#endif 3441d522f475Smrg 3442d522f475Smrgstatic void 3443e0a2b6dfSmrgPointToCELL(TScreen *screen, 3444d522f475Smrg int y, 3445d522f475Smrg int x, 3446e0a2b6dfSmrg CELL *cell) 3447d522f475Smrg/* Convert pixel coordinates to character coordinates. 3448d522f475Smrg Rows are clipped between firstValidRow and lastValidRow. 3449d522f475Smrg Columns are clipped between to be 0 or greater, but are not clipped to some 3450d522f475Smrg maximum value. */ 3451d522f475Smrg{ 3452d522f475Smrg cell->row = (y - screen->border) / FontHeight(screen); 3453d522f475Smrg if (cell->row < screen->firstValidRow) 3454d522f475Smrg cell->row = screen->firstValidRow; 3455d522f475Smrg else if (cell->row > screen->lastValidRow) 3456d522f475Smrg cell->row = screen->lastValidRow; 3457d522f475Smrg cell->col = (x - OriginX(screen)) / FontWidth(screen); 3458d522f475Smrg if (cell->col < 0) 3459d522f475Smrg cell->col = 0; 3460d522f475Smrg else if (cell->col > MaxCols(screen)) { 3461d522f475Smrg cell->col = MaxCols(screen); 3462d522f475Smrg } 3463d522f475Smrg#if OPT_WIDE_CHARS 3464d522f475Smrg /* 3465d522f475Smrg * If we got a click on the right half of a doublewidth character, 3466d522f475Smrg * pretend it happened on the left half. 3467d522f475Smrg */ 3468d522f475Smrg if (cell->col > 0 3469d522f475Smrg && isWideCell(cell->row, cell->col - 1) 3470d522f475Smrg && (XTERM_CELL(cell->row, cell->col) == HIDDEN_CHAR)) { 3471d522f475Smrg cell->col -= 1; 3472d522f475Smrg } 3473d522f475Smrg#endif 3474d522f475Smrg} 3475d522f475Smrg 3476d522f475Smrg/* 3477d522f475Smrg * Find the last column at which text was drawn on the given row. 3478d522f475Smrg */ 3479d522f475Smrgstatic int 348001037d57SmrgLastTextCol(TScreen *screen, CLineData *ld, int row) 3481d522f475Smrg{ 348220d2c4d2Smrg int i = -1; 3483d522f475Smrg 348420d2c4d2Smrg if (ld != 0) { 348520d2c4d2Smrg if (okScrnRow(screen, row)) { 34862e4f8982Smrg const IAttr *ch; 348720d2c4d2Smrg for (i = screen->max_col, 348820d2c4d2Smrg ch = ld->attribs + i; 348920d2c4d2Smrg i >= 0 && !(*ch & CHARDRAWN); 349020d2c4d2Smrg ch--, i--) { 349120d2c4d2Smrg ; 349220d2c4d2Smrg } 3493d522f475Smrg#if OPT_DEC_CHRSET 349420d2c4d2Smrg if (CSET_DOUBLE(GetLineDblCS(ld))) { 349520d2c4d2Smrg i *= 2; 349620d2c4d2Smrg } 3497d522f475Smrg#endif 349820d2c4d2Smrg } 3499d522f475Smrg } 3500d522f475Smrg return (i); 3501d522f475Smrg} 3502d522f475Smrg 3503d522f475Smrg#if !OPT_WIDE_CHARS 3504d522f475Smrg/* 3505d522f475Smrg** double click table for cut and paste in 8 bits 3506d522f475Smrg** 3507d522f475Smrg** This table is divided in four parts : 3508d522f475Smrg** 3509d522f475Smrg** - control characters [0,0x1f] U [0x80,0x9f] 3510d522f475Smrg** - separators [0x20,0x3f] U [0xa0,0xb9] 3511d522f475Smrg** - binding characters [0x40,0x7f] U [0xc0,0xff] 3512d522f475Smrg** - exceptions 3513d522f475Smrg*/ 3514d522f475Smrg/* *INDENT-OFF* */ 3515d522f475Smrgstatic int charClass[256] = 3516d522f475Smrg{ 3517d522f475Smrg/* NUL SOH STX ETX EOT ENQ ACK BEL */ 3518d522f475Smrg 32, 1, 1, 1, 1, 1, 1, 1, 35190bd37d32Smrg/* BS HT NL VT FF CR SO SI */ 3520d522f475Smrg 1, 32, 1, 1, 1, 1, 1, 1, 3521d522f475Smrg/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 3522d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3523d522f475Smrg/* CAN EM SUB ESC FS GS RS US */ 3524d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3525d522f475Smrg/* SP ! " # $ % & ' */ 3526d522f475Smrg 32, 33, 34, 35, 36, 37, 38, 39, 3527d522f475Smrg/* ( ) * + , - . / */ 3528d522f475Smrg 40, 41, 42, 43, 44, 45, 46, 47, 3529d522f475Smrg/* 0 1 2 3 4 5 6 7 */ 3530d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3531d522f475Smrg/* 8 9 : ; < = > ? */ 3532d522f475Smrg 48, 48, 58, 59, 60, 61, 62, 63, 3533d522f475Smrg/* @ A B C D E F G */ 3534d522f475Smrg 64, 48, 48, 48, 48, 48, 48, 48, 3535d522f475Smrg/* H I J K L M N O */ 3536d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3537d522f475Smrg/* P Q R S T U V W */ 3538d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3539d522f475Smrg/* X Y Z [ \ ] ^ _ */ 3540d522f475Smrg 48, 48, 48, 91, 92, 93, 94, 48, 3541d522f475Smrg/* ` a b c d e f g */ 3542d522f475Smrg 96, 48, 48, 48, 48, 48, 48, 48, 3543d522f475Smrg/* h i j k l m n o */ 3544d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3545d522f475Smrg/* p q r s t u v w */ 3546d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3547d522f475Smrg/* x y z { | } ~ DEL */ 3548d522f475Smrg 48, 48, 48, 123, 124, 125, 126, 1, 3549d522f475Smrg/* x80 x81 x82 x83 IND NEL SSA ESA */ 3550d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3551d522f475Smrg/* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 3552d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3553d522f475Smrg/* DCS PU1 PU2 STS CCH MW SPA EPA */ 3554d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3555d522f475Smrg/* x98 x99 x9A CSI ST OSC PM APC */ 3556d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3557d522f475Smrg/* - i c/ L ox Y- | So */ 3558d522f475Smrg 160, 161, 162, 163, 164, 165, 166, 167, 3559d522f475Smrg/* .. c0 ip << _ R0 - */ 3560d522f475Smrg 168, 169, 170, 171, 172, 173, 174, 175, 3561d522f475Smrg/* o +- 2 3 ' u q| . */ 3562d522f475Smrg 176, 177, 178, 179, 180, 181, 182, 183, 3563d522f475Smrg/* , 1 2 >> 1/4 1/2 3/4 ? */ 3564d522f475Smrg 184, 185, 186, 187, 188, 189, 190, 191, 3565d522f475Smrg/* A` A' A^ A~ A: Ao AE C, */ 3566d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3567d522f475Smrg/* E` E' E^ E: I` I' I^ I: */ 3568d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3569d522f475Smrg/* D- N~ O` O' O^ O~ O: X */ 3570d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 215, 3571d522f475Smrg/* O/ U` U' U^ U: Y' P B */ 3572d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3573d522f475Smrg/* a` a' a^ a~ a: ao ae c, */ 3574d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3575d522f475Smrg/* e` e' e^ e: i` i' i^ i: */ 3576d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3577d522f475Smrg/* d n~ o` o' o^ o~ o: -: */ 3578d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 247, 3579d522f475Smrg/* o/ u` u' u^ u: y' P y: */ 3580d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48}; 3581d522f475Smrg/* *INDENT-ON* */ 3582d522f475Smrg 3583d522f475Smrgint 3584d522f475SmrgSetCharacterClassRange(int low, /* in range of [0..255] */ 3585d522f475Smrg int high, 3586d522f475Smrg int value) /* arbitrary */ 3587d522f475Smrg{ 3588d522f475Smrg 3589d522f475Smrg if (low < 0 || high > 255 || high < low) 3590d522f475Smrg return (-1); 3591d522f475Smrg 3592d522f475Smrg for (; low <= high; low++) 3593d522f475Smrg charClass[low] = value; 3594d522f475Smrg 3595d522f475Smrg return (0); 3596d522f475Smrg} 3597d522f475Smrg#endif 3598d522f475Smrg 3599d522f475Smrgstatic int 3600e0a2b6dfSmrgclass_of(LineData *ld, CELL *cell) 3601d522f475Smrg{ 3602d522f475Smrg CELL temp = *cell; 36030bd37d32Smrg int result = 0; 3604d522f475Smrg 3605d522f475Smrg#if OPT_DEC_CHRSET 3606956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 3607d522f475Smrg temp.col /= 2; 3608d522f475Smrg } 3609d522f475Smrg#endif 36100bd37d32Smrg if (temp.col < (int) ld->lineSize) 36110bd37d32Smrg result = CharacterClass((int) (ld->charData[temp.col])); 36120bd37d32Smrg return result; 3613d522f475Smrg} 3614956cc18dSsnj 3615956cc18dSsnj#if OPT_WIDE_CHARS 3616956cc18dSsnj#define CClassSelects(name, cclass) \ 3617956cc18dSsnj (CClassOf(name) == cclass \ 3618956cc18dSsnj || XTERM_CELL(screen->name.row, screen->name.col) == HIDDEN_CHAR) 3619d522f475Smrg#else 3620956cc18dSsnj#define CClassSelects(name, cclass) \ 3621956cc18dSsnj (class_of(ld.name, &((screen->name))) == cclass) 3622d522f475Smrg#endif 3623d522f475Smrg 3624956cc18dSsnj#define CClassOf(name) class_of(ld.name, &((screen->name))) 3625956cc18dSsnj 3626913cc679Smrg#if OPT_REPORT_CCLASS 3627913cc679Smrgstatic int 3628913cc679Smrgshow_cclass_range(int lo, int hi) 3629913cc679Smrg{ 3630913cc679Smrg int cclass = CharacterClass(lo); 3631913cc679Smrg int ident = (cclass == lo); 3632913cc679Smrg int more = 0; 3633913cc679Smrg if (ident) { 3634913cc679Smrg int ch; 3635913cc679Smrg for (ch = lo + 1; ch <= hi; ch++) { 3636913cc679Smrg if (CharacterClass(ch) != ch) { 3637913cc679Smrg ident = 0; 3638913cc679Smrg break; 3639913cc679Smrg } 3640913cc679Smrg } 3641913cc679Smrg if (ident && (hi < 255)) { 3642913cc679Smrg ch = hi + 1; 3643913cc679Smrg if (CharacterClass(ch) == ch) { 3644913cc679Smrg if (ch >= 255 || CharacterClass(ch + 1) != ch) { 3645913cc679Smrg more = 1; 3646913cc679Smrg } 3647913cc679Smrg } 3648913cc679Smrg } 3649913cc679Smrg } 3650913cc679Smrg if (!more) { 3651913cc679Smrg if (lo == hi) { 3652913cc679Smrg printf("\t%d", lo); 3653913cc679Smrg } else { 3654913cc679Smrg printf("\t%d-%d", lo, hi); 3655913cc679Smrg } 3656913cc679Smrg if (!ident) 3657913cc679Smrg printf(":%d", cclass); 3658913cc679Smrg if (hi < 255) 3659913cc679Smrg printf(", \\"); 3660913cc679Smrg printf("\n"); 3661913cc679Smrg } 3662913cc679Smrg return !more; 3663913cc679Smrg} 3664913cc679Smrg 3665913cc679Smrgvoid 3666913cc679Smrgreport_char_class(XtermWidget xw) 3667913cc679Smrg{ 3668913cc679Smrg /* simple table, to match documentation */ 3669913cc679Smrg static const char charnames[] = 3670913cc679Smrg "NUL\0" "SOH\0" "STX\0" "ETX\0" "EOT\0" "ENQ\0" "ACK\0" "BEL\0" 3671913cc679Smrg " BS\0" " HT\0" " NL\0" " VT\0" " NP\0" " CR\0" " SO\0" " SI\0" 3672913cc679Smrg "DLE\0" "DC1\0" "DC2\0" "DC3\0" "DC4\0" "NAK\0" "SYN\0" "ETB\0" 3673913cc679Smrg "CAN\0" " EM\0" "SUB\0" "ESC\0" " FS\0" " GS\0" " RS\0" " US\0" 3674913cc679Smrg " SP\0" " !\0" " \"\0" " #\0" " $\0" " %\0" " &\0" " '\0" 3675913cc679Smrg " (\0" " )\0" " *\0" " +\0" " ,\0" " -\0" " .\0" " /\0" 3676913cc679Smrg " 0\0" " 1\0" " 2\0" " 3\0" " 4\0" " 5\0" " 6\0" " 7\0" 3677913cc679Smrg " 8\0" " 9\0" " :\0" " ;\0" " <\0" " =\0" " >\0" " ?\0" 3678913cc679Smrg " @\0" " A\0" " B\0" " C\0" " D\0" " E\0" " F\0" " G\0" 3679913cc679Smrg " H\0" " I\0" " J\0" " K\0" " L\0" " M\0" " N\0" " O\0" 3680913cc679Smrg " P\0" " Q\0" " R\0" " S\0" " T\0" " U\0" " V\0" " W\0" 3681913cc679Smrg " X\0" " Y\0" " Z\0" " [\0" " \\\0" " ]\0" " ^\0" " _\0" 3682913cc679Smrg " `\0" " a\0" " b\0" " c\0" " d\0" " e\0" " f\0" " g\0" 3683913cc679Smrg " h\0" " i\0" " j\0" " k\0" " l\0" " m\0" " n\0" " o\0" 3684913cc679Smrg " p\0" " q\0" " r\0" " s\0" " t\0" " u\0" " v\0" " w\0" 3685913cc679Smrg " x\0" " y\0" " z\0" " {\0" " |\0" " }\0" " ~\0" "DEL\0" 3686913cc679Smrg "x80\0" "x81\0" "x82\0" "x83\0" "IND\0" "NEL\0" "SSA\0" "ESA\0" 3687913cc679Smrg "HTS\0" "HTJ\0" "VTS\0" "PLD\0" "PLU\0" " RI\0" "SS2\0" "SS3\0" 3688913cc679Smrg "DCS\0" "PU1\0" "PU2\0" "STS\0" "CCH\0" " MW\0" "SPA\0" "EPA\0" 3689913cc679Smrg "x98\0" "x99\0" "x9A\0" "CSI\0" " ST\0" "OSC\0" " PM\0" "APC\0" 3690913cc679Smrg " -\0" " i\0" " c/\0" " L\0" " ox\0" " Y-\0" " |\0" " So\0" 3691913cc679Smrg " ..\0" " c0\0" " ip\0" " <<\0" " _\0" " \0" " R0\0" " -\0" 3692913cc679Smrg " o\0" " +-\0" " 2\0" " 3\0" " '\0" " u\0" " q|\0" " .\0" 3693913cc679Smrg " ,\0" " 1\0" " 2\0" " >>\0" "1/4\0" "1/2\0" "3/4\0" " ?\0" 3694913cc679Smrg " A`\0" " A'\0" " A^\0" " A~\0" " A:\0" " Ao\0" " AE\0" " C,\0" 3695913cc679Smrg " E`\0" " E'\0" " E^\0" " E:\0" " I`\0" " I'\0" " I^\0" " I:\0" 3696913cc679Smrg " D-\0" " N~\0" " O`\0" " O'\0" " O^\0" " O~\0" " O:\0" " X\0" 3697913cc679Smrg " O/\0" " U`\0" " U'\0" " U^\0" " U:\0" " Y'\0" " P\0" " B\0" 3698913cc679Smrg " a`\0" " a'\0" " a^\0" " a~\0" " a:\0" " ao\0" " ae\0" " c,\0" 3699913cc679Smrg " e`\0" " e'\0" " e^\0" " e:\0" " i`\0" " i'\0" " i^\0" " i:\0" 3700913cc679Smrg " d\0" " n~\0" " o`\0" " o'\0" " o^\0" " o~\0" " o:\0" " -:\0" 3701913cc679Smrg " o/\0" " u`\0" " u'\0" " u^\0" " u:\0" " y'\0" " P\0" " y:\0"; 3702913cc679Smrg int ch, dh; 3703913cc679Smrg int class_p; 3704913cc679Smrg 3705913cc679Smrg (void) xw; 3706913cc679Smrg 3707913cc679Smrg printf("static int charClass[256] = {\n"); 3708913cc679Smrg for (ch = 0; ch < 256; ++ch) { 3709913cc679Smrg const char *s = charnames + (ch * 4); 3710913cc679Smrg if ((ch & 7) == 0) 3711913cc679Smrg printf("/*"); 3712913cc679Smrg printf(" %s ", s); 3713913cc679Smrg if (((ch + 1) & 7) == 0) { 3714913cc679Smrg printf("*/\n "); 3715913cc679Smrg for (dh = ch - 7; dh <= ch; ++dh) { 3716913cc679Smrg printf(" %3d%s", CharacterClass(dh), dh == 255 ? "};" : ","); 3717913cc679Smrg } 3718913cc679Smrg printf("\n"); 3719913cc679Smrg } 3720913cc679Smrg } 3721913cc679Smrg 3722913cc679Smrg /* print the table as if it were the charClass resource */ 3723913cc679Smrg printf("\n"); 3724913cc679Smrg printf("The table is equivalent to this \"charClass\" resource:\n"); 3725913cc679Smrg class_p = CharacterClass(dh = 0); 3726913cc679Smrg for (ch = 0; ch < 256; ++ch) { 3727913cc679Smrg int class_c = CharacterClass(ch); 3728913cc679Smrg if (class_c != class_p) { 3729913cc679Smrg if (show_cclass_range(dh, ch - 1)) { 3730913cc679Smrg dh = ch; 3731913cc679Smrg class_p = class_c; 3732913cc679Smrg } 3733913cc679Smrg } 3734913cc679Smrg } 3735913cc679Smrg if (dh < 255) { 3736913cc679Smrg show_cclass_range(dh, 255); 3737913cc679Smrg } 3738913cc679Smrg 3739913cc679Smrg if_OPT_WIDE_CHARS(TScreenOf(xw), { 3740913cc679Smrg /* if this is a wide-character configuration, print all intervals */ 3741913cc679Smrg report_wide_char_class(); 3742913cc679Smrg }); 3743913cc679Smrg} 3744913cc679Smrg#endif 3745913cc679Smrg 3746d522f475Smrg/* 3747d522f475Smrg * If the given column is past the end of text on the given row, bump to the 3748d522f475Smrg * beginning of the next line. 3749d522f475Smrg */ 3750d522f475Smrgstatic Boolean 3751e0a2b6dfSmrgokPosition(TScreen *screen, 3752e0a2b6dfSmrg LineData **ld, 3753e0a2b6dfSmrg CELL *cell) 3754d522f475Smrg{ 375520d2c4d2Smrg Boolean result = True; 375620d2c4d2Smrg 375720d2c4d2Smrg if (cell->row > screen->max_row) { 375820d2c4d2Smrg result = False; 3759f2e35a3aSmrg TRACE(("okPosition cell row %d > screen max %d\n", cell->row, screen->max_row)); 376020d2c4d2Smrg } else if (cell->col > (LastTextCol(screen, *ld, cell->row) + 1)) { 3761f2e35a3aSmrg TRACE(("okPosition cell col %d > screen max %d\n", cell->col, 3762f2e35a3aSmrg (LastTextCol(screen, *ld, cell->row) + 1))); 376320d2c4d2Smrg if (cell->row < screen->max_row) { 3764f2e35a3aSmrg TRACE(("okPosition cell row %d < screen max %d\n", cell->row, screen->max_row)); 376520d2c4d2Smrg cell->col = 0; 376620d2c4d2Smrg *ld = GET_LINEDATA(screen, ++cell->row); 376720d2c4d2Smrg result = False; 376820d2c4d2Smrg } 3769d522f475Smrg } 377020d2c4d2Smrg return result; 3771d522f475Smrg} 3772d522f475Smrg 3773d522f475Smrgstatic void 3774e0a2b6dfSmrgtrimLastLine(TScreen *screen, 3775e0a2b6dfSmrg LineData **ld, 3776e0a2b6dfSmrg CELL *last) 3777d522f475Smrg{ 377820d2c4d2Smrg if (screen->cutNewline && last->row < screen->max_row) { 3779d522f475Smrg last->col = 0; 3780956cc18dSsnj *ld = GET_LINEDATA(screen, ++last->row); 3781d522f475Smrg } else { 3782956cc18dSsnj last->col = LastTextCol(screen, *ld, last->row) + 1; 3783d522f475Smrg } 3784d522f475Smrg} 3785d522f475Smrg 3786d522f475Smrg#if OPT_SELECT_REGEX 3787d522f475Smrg/* 3788d522f475Smrg * Returns the first row of a wrapped line. 3789d522f475Smrg */ 3790d522f475Smrgstatic int 3791e0a2b6dfSmrgfirstRowOfLine(TScreen *screen, int row, Bool visible) 3792d522f475Smrg{ 3793956cc18dSsnj LineData *ld = 0; 3794d522f475Smrg int limit = visible ? 0 : -screen->savedlines; 3795d522f475Smrg 3796d522f475Smrg while (row > limit && 3797956cc18dSsnj (ld = GET_LINEDATA(screen, row - 1)) != 0 && 3798956cc18dSsnj LineTstWrapped(ld)) { 3799d522f475Smrg --row; 3800956cc18dSsnj } 3801d522f475Smrg return row; 3802d522f475Smrg} 3803d522f475Smrg 3804d522f475Smrg/* 3805d522f475Smrg * Returns the last row of a wrapped line. 3806d522f475Smrg */ 3807d522f475Smrgstatic int 3808e0a2b6dfSmrglastRowOfLine(TScreen *screen, int row) 3809d522f475Smrg{ 3810956cc18dSsnj LineData *ld; 3811956cc18dSsnj 3812d522f475Smrg while (row < screen->max_row && 3813956cc18dSsnj (ld = GET_LINEDATA(screen, row)) != 0 && 3814956cc18dSsnj LineTstWrapped(ld)) { 3815d522f475Smrg ++row; 3816956cc18dSsnj } 3817d522f475Smrg return row; 3818d522f475Smrg} 3819d522f475Smrg 3820d522f475Smrg/* 3821d522f475Smrg * Returns the number of cells on the range of rows. 3822d522f475Smrg */ 3823d522f475Smrgstatic unsigned 3824e0a2b6dfSmrglengthOfLines(TScreen *screen, int firstRow, int lastRow) 3825d522f475Smrg{ 3826d522f475Smrg unsigned length = 0; 3827d522f475Smrg int n; 3828d522f475Smrg 3829d522f475Smrg for (n = firstRow; n <= lastRow; ++n) { 3830956cc18dSsnj LineData *ld = GET_LINEDATA(screen, n); 3831956cc18dSsnj int value = LastTextCol(screen, ld, n); 3832d522f475Smrg if (value >= 0) 38332eaa94a1Schristos length += (unsigned) (value + 1); 3834d522f475Smrg } 3835d522f475Smrg return length; 3836d522f475Smrg} 3837d522f475Smrg 3838d522f475Smrg/* 3839d522f475Smrg * Make a copy of the wrapped-line which corresponds to the given row as a 3840d522f475Smrg * string of bytes. Construct an index for the columns from the beginning of 3841d522f475Smrg * the line. 3842d522f475Smrg */ 3843d522f475Smrgstatic char * 3844e0a2b6dfSmrgmake_indexed_text(TScreen *screen, int row, unsigned length, int *indexed) 3845d522f475Smrg{ 3846d522f475Smrg Char *result = 0; 384720d2c4d2Smrg size_t need = (length + 1); 3848d522f475Smrg 3849d522f475Smrg /* 3850d522f475Smrg * Get a quick upper bound to the number of bytes needed, if the whole 3851d522f475Smrg * string were UTF-8. 3852d522f475Smrg */ 3853d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3854956cc18dSsnj need *= ((screen->lineExtra + 1) * 6); 3855d522f475Smrg }); 3856d522f475Smrg 3857d522f475Smrg if ((result = TypeCallocN(Char, need + 1)) != 0) { 3858956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 3859d522f475Smrg unsigned used = 0; 3860d522f475Smrg Char *last = result; 3861d522f475Smrg 3862d522f475Smrg do { 3863d522f475Smrg int col = 0; 3864956cc18dSsnj int limit = LastTextCol(screen, ld, row); 3865d522f475Smrg 3866d522f475Smrg while (col <= limit) { 3867d522f475Smrg Char *next = last; 3868956cc18dSsnj unsigned data = ld->charData[col]; 3869d522f475Smrg 38700bd37d32Smrg assert(col < (int) ld->lineSize); 3871d522f475Smrg /* some internal points may not be drawn */ 3872d522f475Smrg if (data == 0) 3873d522f475Smrg data = ' '; 3874d522f475Smrg 3875d522f475Smrg if_WIDE_OR_NARROW(screen, { 3876d522f475Smrg next = convertToUTF8(last, data); 3877d522f475Smrg } 3878d522f475Smrg , { 3879d522f475Smrg *next++ = CharOf(data); 3880d522f475Smrg }); 3881d522f475Smrg 3882d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3883956cc18dSsnj size_t off; 3884956cc18dSsnj for_each_combData(off, ld) { 3885956cc18dSsnj data = ld->combData[off][col]; 3886956cc18dSsnj if (data == 0) 3887d522f475Smrg break; 3888d522f475Smrg next = convertToUTF8(next, data); 3889d522f475Smrg } 3890d522f475Smrg }); 3891d522f475Smrg 389220d2c4d2Smrg indexed[used] = (int) (last - result); 3893d522f475Smrg *next = 0; 3894d522f475Smrg /* TRACE(("index[%d.%d] %d:%s\n", row, used, indexed[used], last)); */ 3895d522f475Smrg last = next; 3896d522f475Smrg ++used; 3897d522f475Smrg ++col; 389820d2c4d2Smrg indexed[used] = (int) (next - result); 3899d522f475Smrg } 3900d522f475Smrg } while (used < length && 3901956cc18dSsnj LineTstWrapped(ld) && 3902956cc18dSsnj (ld = GET_LINEDATA(screen, ++row)) != 0 && 3903956cc18dSsnj row < screen->max_row); 3904d522f475Smrg } 3905d522f475Smrg /* TRACE(("result:%s\n", result)); */ 3906d522f475Smrg return (char *) result; 3907d522f475Smrg} 3908d522f475Smrg 3909d522f475Smrg/* 3910d522f475Smrg * Find the column given an offset into the character string by using the 3911d522f475Smrg * index constructed in make_indexed_text(). 3912d522f475Smrg */ 3913d522f475Smrgstatic int 3914d522f475SmrgindexToCol(int *indexed, int len, int off) 3915d522f475Smrg{ 3916d522f475Smrg int col = 0; 3917d522f475Smrg while (indexed[col] < len) { 3918d522f475Smrg if (indexed[col] >= off) 3919d522f475Smrg break; 3920d522f475Smrg ++col; 3921d522f475Smrg } 3922d522f475Smrg return col; 3923d522f475Smrg} 3924d522f475Smrg 3925d522f475Smrg/* 3926d522f475Smrg * Given a row number, and a column offset from that (which may be wrapped), 3927d522f475Smrg * set the cell to the actual row/column values. 3928d522f475Smrg */ 3929d522f475Smrgstatic void 3930e0a2b6dfSmrgcolumnToCell(TScreen *screen, int row, int col, CELL *cell) 3931d522f475Smrg{ 3932d522f475Smrg while (row < screen->max_row) { 393301037d57Smrg CLineData *ld = GET_LINEDATA(screen, row); 3934956cc18dSsnj int last = LastTextCol(screen, ld, row); 3935d522f475Smrg 3936d522f475Smrg /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */ 3937d522f475Smrg if (col <= last) { 3938d522f475Smrg break; 3939d522f475Smrg } 3940d522f475Smrg /* 3941d522f475Smrg * Stop if the current row does not wrap (does not continue the current 3942d522f475Smrg * line). 3943d522f475Smrg */ 3944956cc18dSsnj if (!LineTstWrapped(ld)) { 3945d522f475Smrg col = last + 1; 3946d522f475Smrg break; 3947d522f475Smrg } 3948d522f475Smrg col -= (last + 1); 3949d522f475Smrg ++row; 3950d522f475Smrg } 3951d522f475Smrg if (col < 0) 3952d522f475Smrg col = 0; 3953d522f475Smrg cell->row = row; 3954d522f475Smrg cell->col = col; 3955d522f475Smrg} 3956d522f475Smrg 3957d522f475Smrg/* 3958d522f475Smrg * Given a cell, find the corresponding column offset. 3959d522f475Smrg */ 3960d522f475Smrgstatic int 3961e0a2b6dfSmrgcellToColumn(TScreen *screen, CELL *cell) 3962d522f475Smrg{ 396301037d57Smrg CLineData *ld = 0; 3964d522f475Smrg int col = cell->col; 3965d522f475Smrg int row = firstRowOfLine(screen, cell->row, False); 3966d522f475Smrg while (row < cell->row) { 3967956cc18dSsnj ld = GET_LINEDATA(screen, row); 3968956cc18dSsnj col += LastTextCol(screen, ld, row++); 3969d522f475Smrg } 3970956cc18dSsnj#if OPT_DEC_CHRSET 3971956cc18dSsnj if (ld == 0) 3972956cc18dSsnj ld = GET_LINEDATA(screen, row); 3973956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3974956cc18dSsnj col /= 2; 3975956cc18dSsnj#endif 3976d522f475Smrg return col; 3977d522f475Smrg} 3978d522f475Smrg 3979d522f475Smrgstatic void 3980e0a2b6dfSmrgdo_select_regex(TScreen *screen, CELL *startc, CELL *endc) 3981d522f475Smrg{ 3982956cc18dSsnj LineData *ld = GET_LINEDATA(screen, startc->row); 3983d522f475Smrg int inx = ((screen->numberOfClicks - 1) % screen->maxClicks); 3984d522f475Smrg char *expr = screen->selectExpr[inx]; 3985d522f475Smrg regex_t preg; 3986d522f475Smrg regmatch_t match; 3987d522f475Smrg 398801037d57Smrg TRACE(("Select_REGEX[%d]:%s\n", inx, NonNull(expr))); 3989956cc18dSsnj if (okPosition(screen, &ld, startc) && expr != 0) { 3990d522f475Smrg if (regcomp(&preg, expr, REG_EXTENDED) == 0) { 3991d522f475Smrg int firstRow = firstRowOfLine(screen, startc->row, True); 3992d522f475Smrg int lastRow = lastRowOfLine(screen, firstRow); 3993d522f475Smrg unsigned size = lengthOfLines(screen, firstRow, lastRow); 3994d522f475Smrg int actual = cellToColumn(screen, startc); 39952e4f8982Smrg int *indexed; 3996d522f475Smrg 3997d522f475Smrg TRACE(("regcomp ok rows %d..%d bytes %d\n", 3998d522f475Smrg firstRow, lastRow, size)); 3999d522f475Smrg 4000d522f475Smrg if ((indexed = TypeCallocN(int, size + 1)) != 0) { 40012e4f8982Smrg char *search; 4002d522f475Smrg if ((search = make_indexed_text(screen, 4003d522f475Smrg firstRow, 4004d522f475Smrg size, 4005d522f475Smrg indexed)) != 0) { 40062eaa94a1Schristos int len = (int) strlen(search); 4007d522f475Smrg int col; 400804b94745Smrg int offset; 4009d522f475Smrg int best_col = -1; 4010d522f475Smrg int best_len = -1; 4011d522f475Smrg 4012913cc679Smrg startc->row = 0; 4013913cc679Smrg startc->col = 0; 4014913cc679Smrg endc->row = 0; 4015913cc679Smrg endc->col = 0; 4016913cc679Smrg 401704b94745Smrg for (col = 0; (offset = indexed[col]) < len; ++col) { 4018d522f475Smrg if (regexec(&preg, 401904b94745Smrg search + offset, 402004b94745Smrg (size_t) 1, &match, 402104b94745Smrg col ? REG_NOTBOL : 0) == 0) { 402204b94745Smrg int start_inx = (int) (match.rm_so + offset); 402304b94745Smrg int finis_inx = (int) (match.rm_eo + offset); 4024d522f475Smrg int start_col = indexToCol(indexed, len, start_inx); 4025d522f475Smrg int finis_col = indexToCol(indexed, len, finis_inx); 4026d522f475Smrg 4027d522f475Smrg if (start_col <= actual && 4028913cc679Smrg actual <= finis_col) { 4029d522f475Smrg int test = finis_col - start_col; 4030d522f475Smrg if (best_len < test) { 4031d522f475Smrg best_len = test; 4032d522f475Smrg best_col = start_col; 4033d522f475Smrg TRACE(("match column %d len %d\n", 4034d522f475Smrg best_col, 4035d522f475Smrg best_len)); 4036d522f475Smrg } 4037d522f475Smrg } 4038d522f475Smrg } 4039d522f475Smrg } 4040d522f475Smrg if (best_col >= 0) { 4041d522f475Smrg int best_nxt = best_col + best_len; 4042d522f475Smrg columnToCell(screen, firstRow, best_col, startc); 4043d522f475Smrg columnToCell(screen, firstRow, best_nxt, endc); 4044d522f475Smrg TRACE(("search::%s\n", search)); 4045d522f475Smrg TRACE(("indexed:%d..%d -> %d..%d\n", 4046d522f475Smrg best_col, best_nxt, 4047d522f475Smrg indexed[best_col], 4048d522f475Smrg indexed[best_nxt])); 4049d522f475Smrg TRACE(("matched:%d:%s\n", 405004b94745Smrg indexed[best_nxt] - 4051d522f475Smrg indexed[best_col], 4052956cc18dSsnj visibleChars((Char *) (search + indexed[best_col]), 405304b94745Smrg (unsigned) (indexed[best_nxt] - 4054d522f475Smrg indexed[best_col])))); 4055d522f475Smrg } 4056d522f475Smrg free(search); 4057d522f475Smrg } 4058d522f475Smrg free(indexed); 4059956cc18dSsnj#if OPT_DEC_CHRSET 4060956cc18dSsnj if ((ld = GET_LINEDATA(screen, startc->row)) != 0) { 4061956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 4062956cc18dSsnj startc->col *= 2; 4063956cc18dSsnj } 4064956cc18dSsnj if ((ld = GET_LINEDATA(screen, endc->row)) != 0) { 4065956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 4066956cc18dSsnj endc->col *= 2; 4067956cc18dSsnj } 4068956cc18dSsnj#endif 4069d522f475Smrg } 4070d522f475Smrg regfree(&preg); 4071d522f475Smrg } 4072d522f475Smrg } 4073d522f475Smrg} 4074d522f475Smrg#endif /* OPT_SELECT_REGEX */ 4075d522f475Smrg 4076956cc18dSsnj#define InitRow(name) \ 4077956cc18dSsnj ld.name = GET_LINEDATA(screen, screen->name.row) 4078956cc18dSsnj 4079956cc18dSsnj#define NextRow(name) \ 4080956cc18dSsnj ld.name = GET_LINEDATA(screen, ++screen->name.row) 4081956cc18dSsnj 4082956cc18dSsnj#define PrevRow(name) \ 4083956cc18dSsnj ld.name = GET_LINEDATA(screen, --screen->name.row) 4084956cc18dSsnj 408520d2c4d2Smrg#define MoreRows(name) \ 408620d2c4d2Smrg (screen->name.row < screen->max_row) 408720d2c4d2Smrg 4088956cc18dSsnj#define isPrevWrapped(name) \ 4089956cc18dSsnj (screen->name.row > 0 \ 4090956cc18dSsnj && (ltmp = GET_LINEDATA(screen, screen->name.row - 1)) != 0 \ 4091956cc18dSsnj && LineTstWrapped(ltmp)) 4092956cc18dSsnj 4093d522f475Smrg/* 4094d522f475Smrg * sets startSel endSel 4095d522f475Smrg * ensuring that they have legal values 4096d522f475Smrg */ 4097d522f475Smrgstatic void 4098d522f475SmrgComputeSelect(XtermWidget xw, 4099e0a2b6dfSmrg CELL *startc, 4100e0a2b6dfSmrg CELL *endc, 4101f2e35a3aSmrg Bool extend, 4102f2e35a3aSmrg Bool normal) 4103d522f475Smrg{ 4104956cc18dSsnj TScreen *screen = TScreenOf(xw); 4105956cc18dSsnj 4106d522f475Smrg int cclass; 4107d522f475Smrg CELL first = *startc; 4108d522f475Smrg CELL last = *endc; 4109956cc18dSsnj Boolean ignored = False; 4110956cc18dSsnj 4111956cc18dSsnj struct { 4112956cc18dSsnj LineData *startSel; 4113956cc18dSsnj LineData *endSel; 4114956cc18dSsnj } ld; 4115956cc18dSsnj LineData *ltmp; 4116d522f475Smrg 4117d522f475Smrg TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n", 4118d522f475Smrg first.row, first.col, 4119d522f475Smrg last.row, last.col, 4120d522f475Smrg extend ? "" : "no")); 4121d522f475Smrg 4122d522f475Smrg#if OPT_WIDE_CHARS 4123d522f475Smrg if (first.col > 1 4124d522f475Smrg && isWideCell(first.row, first.col - 1) 4125d522f475Smrg && XTERM_CELL(first.row, first.col - 0) == HIDDEN_CHAR) { 412620d2c4d2Smrg TRACE(("Adjusting start. Changing downwards from %i.\n", first.col)); 4127d522f475Smrg first.col -= 1; 4128d522f475Smrg if (last.col == (first.col + 1)) 4129d522f475Smrg last.col--; 4130d522f475Smrg } 4131d522f475Smrg 4132d522f475Smrg if (last.col > 1 4133d522f475Smrg && isWideCell(last.row, last.col - 1) 4134d522f475Smrg && XTERM_CELL(last.row, last.col) == HIDDEN_CHAR) { 4135d522f475Smrg last.col += 1; 4136d522f475Smrg } 4137d522f475Smrg#endif 4138d522f475Smrg 4139d522f475Smrg if (Coordinate(screen, &first) <= Coordinate(screen, &last)) { 4140d522f475Smrg screen->startSel = screen->startRaw = first; 4141d522f475Smrg screen->endSel = screen->endRaw = last; 4142d522f475Smrg } else { /* Swap them */ 4143d522f475Smrg screen->startSel = screen->startRaw = last; 4144d522f475Smrg screen->endSel = screen->endRaw = first; 4145d522f475Smrg } 4146d522f475Smrg 4147956cc18dSsnj InitRow(startSel); 4148956cc18dSsnj InitRow(endSel); 4149956cc18dSsnj 4150d522f475Smrg switch (screen->selectUnit) { 4151d522f475Smrg case Select_CHAR: 4152956cc18dSsnj (void) okPosition(screen, &(ld.startSel), &(screen->startSel)); 4153956cc18dSsnj (void) okPosition(screen, &(ld.endSel), &(screen->endSel)); 4154d522f475Smrg break; 4155d522f475Smrg 4156d522f475Smrg case Select_WORD: 4157d522f475Smrg TRACE(("Select_WORD\n")); 4158956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 4159f2e35a3aSmrg CELL mark; 4160956cc18dSsnj cclass = CClassOf(startSel); 4161f2e35a3aSmrg TRACE(("...starting with class %d\n", cclass)); 4162d522f475Smrg do { 4163f2e35a3aSmrg mark = screen->startSel; 4164d522f475Smrg --screen->startSel.col; 4165956cc18dSsnj if (screen->startSel.col < 0 4166956cc18dSsnj && isPrevWrapped(startSel)) { 4167956cc18dSsnj PrevRow(startSel); 4168956cc18dSsnj screen->startSel.col = LastTextCol(screen, ld.startSel, screen->startSel.row); 4169d522f475Smrg } 4170d522f475Smrg } while (screen->startSel.col >= 0 4171956cc18dSsnj && CClassSelects(startSel, cclass)); 4172f2e35a3aSmrg if (normal) 4173f2e35a3aSmrg ++screen->startSel.col; 4174f2e35a3aSmrg else 4175f2e35a3aSmrg screen->startSel = mark; 4176d522f475Smrg } 4177d522f475Smrg#if OPT_WIDE_CHARS 4178f2e35a3aSmrg#define SkipHiddenCell(mark) \ 4179f2e35a3aSmrg if (mark.col && XTERM_CELL(mark.row, mark.col) == HIDDEN_CHAR) \ 4180f2e35a3aSmrg mark.col++ 4181f2e35a3aSmrg#else 4182f2e35a3aSmrg#define SkipHiddenCell(mark) /* nothing */ 4183d522f475Smrg#endif 4184f2e35a3aSmrg SkipHiddenCell(screen->startSel); 4185f2e35a3aSmrg 4186f2e35a3aSmrg if (!normal) { 4187f2e35a3aSmrg screen->endSel = screen->startSel; 4188f2e35a3aSmrg ld.endSel = ld.startSel; 4189f2e35a3aSmrg } 4190d522f475Smrg 4191956cc18dSsnj if (okPosition(screen, &(ld.endSel), &(screen->endSel))) { 41922e4f8982Smrg int length = LastTextCol(screen, ld.endSel, screen->endSel.row); 4193956cc18dSsnj cclass = CClassOf(endSel); 4194f2e35a3aSmrg TRACE(("...ending with class %d\n", cclass)); 4195d522f475Smrg do { 4196d522f475Smrg ++screen->endSel.col; 4197d522f475Smrg if (screen->endSel.col > length 4198956cc18dSsnj && LineTstWrapped(ld.endSel)) { 419920d2c4d2Smrg if (!MoreRows(endSel)) 420020d2c4d2Smrg break; 4201d522f475Smrg screen->endSel.col = 0; 4202956cc18dSsnj NextRow(endSel); 4203956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 4204d522f475Smrg } 4205d522f475Smrg } while (screen->endSel.col <= length 4206956cc18dSsnj && CClassSelects(endSel, cclass)); 4207f2e35a3aSmrg if (normal 4208f2e35a3aSmrg && screen->endSel.col > length + 1 420920d2c4d2Smrg && MoreRows(endSel)) { 4210d522f475Smrg screen->endSel.col = 0; 4211956cc18dSsnj NextRow(endSel); 4212d522f475Smrg } 4213d522f475Smrg } 4214f2e35a3aSmrg SkipHiddenCell(screen->endSel); 4215d522f475Smrg 4216d522f475Smrg screen->saveStartW = screen->startSel; 4217d522f475Smrg break; 4218d522f475Smrg 4219d522f475Smrg case Select_LINE: 4220d522f475Smrg TRACE(("Select_LINE\n")); 422120d2c4d2Smrg while (LineTstWrapped(ld.endSel) 422220d2c4d2Smrg && MoreRows(endSel)) { 4223956cc18dSsnj NextRow(endSel); 4224d522f475Smrg } 4225d522f475Smrg if (screen->cutToBeginningOfLine 4226d522f475Smrg || screen->startSel.row < screen->saveStartW.row) { 4227d522f475Smrg screen->startSel.col = 0; 4228956cc18dSsnj while (isPrevWrapped(startSel)) { 4229956cc18dSsnj PrevRow(startSel); 4230d522f475Smrg } 4231d522f475Smrg } else if (!extend) { 4232d522f475Smrg if ((first.row < screen->saveStartW.row) 4233d522f475Smrg || (isSameRow(&first, &(screen->saveStartW)) 4234d522f475Smrg && first.col < screen->saveStartW.col)) { 4235d522f475Smrg screen->startSel.col = 0; 4236956cc18dSsnj while (isPrevWrapped(startSel)) { 4237956cc18dSsnj PrevRow(startSel); 4238d522f475Smrg } 4239d522f475Smrg } else { 4240d522f475Smrg screen->startSel = screen->saveStartW; 4241d522f475Smrg } 4242d522f475Smrg } 4243956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 4244d522f475Smrg break; 4245d522f475Smrg 4246d522f475Smrg case Select_GROUP: /* paragraph */ 4247d522f475Smrg TRACE(("Select_GROUP\n")); 4248956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 4249d522f475Smrg /* scan backward for beginning of group */ 4250d522f475Smrg while (screen->startSel.row > 0 && 4251956cc18dSsnj (LastTextCol(screen, ld.startSel, screen->startSel.row - 4252956cc18dSsnj 1) > 0 || 4253956cc18dSsnj isPrevWrapped(startSel))) { 4254956cc18dSsnj PrevRow(startSel); 4255d522f475Smrg } 4256d522f475Smrg screen->startSel.col = 0; 4257d522f475Smrg /* scan forward for end of group */ 425820d2c4d2Smrg while (MoreRows(endSel) && 4259956cc18dSsnj (LastTextCol(screen, ld.endSel, screen->endSel.row + 1) > 4260956cc18dSsnj 0 || 4261956cc18dSsnj LineTstWrapped(ld.endSel))) { 4262956cc18dSsnj NextRow(endSel); 4263d522f475Smrg } 4264956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 4265d522f475Smrg } 4266d522f475Smrg break; 4267d522f475Smrg 4268d522f475Smrg case Select_PAGE: /* everything one can see */ 4269d522f475Smrg TRACE(("Select_PAGE\n")); 4270d522f475Smrg screen->startSel.row = 0; 4271d522f475Smrg screen->startSel.col = 0; 427220d2c4d2Smrg screen->endSel.row = MaxRows(screen); 4273d522f475Smrg screen->endSel.col = 0; 4274d522f475Smrg break; 4275d522f475Smrg 4276d522f475Smrg case Select_ALL: /* counts scrollback if in normal screen */ 4277d522f475Smrg TRACE(("Select_ALL\n")); 4278d522f475Smrg screen->startSel.row = -screen->savedlines; 4279d522f475Smrg screen->startSel.col = 0; 428020d2c4d2Smrg screen->endSel.row = MaxRows(screen); 4281d522f475Smrg screen->endSel.col = 0; 4282d522f475Smrg break; 4283d522f475Smrg 4284d522f475Smrg#if OPT_SELECT_REGEX 4285d522f475Smrg case Select_REGEX: 4286d522f475Smrg do_select_regex(screen, &(screen->startSel), &(screen->endSel)); 4287d522f475Smrg break; 4288d522f475Smrg#endif 4289d522f475Smrg 4290d522f475Smrg case NSELECTUNITS: /* always ignore */ 4291956cc18dSsnj ignored = True; 4292956cc18dSsnj break; 4293d522f475Smrg } 4294d522f475Smrg 4295956cc18dSsnj if (!ignored) { 4296956cc18dSsnj /* check boundaries */ 4297956cc18dSsnj ScrollSelection(screen, 0, False); 4298956cc18dSsnj TrackText(xw, &(screen->startSel), &(screen->endSel)); 4299956cc18dSsnj } 4300d522f475Smrg 4301d522f475Smrg return; 4302d522f475Smrg} 4303d522f475Smrg 4304d522f475Smrg/* Guaranteed (first.row, first.col) <= (last.row, last.col) */ 4305d522f475Smrgstatic void 4306d522f475SmrgTrackText(XtermWidget xw, 4307e0a2b6dfSmrg const CELL *firstp, 4308e0a2b6dfSmrg const CELL *lastp) 4309d522f475Smrg{ 4310956cc18dSsnj TScreen *screen = TScreenOf(xw); 4311d522f475Smrg int from, to; 4312d522f475Smrg CELL old_start, old_end; 4313d522f475Smrg CELL first = *firstp; 4314d522f475Smrg CELL last = *lastp; 4315d522f475Smrg 4316d522f475Smrg TRACE(("TrackText(first=%d,%d, last=%d,%d)\n", 4317d522f475Smrg first.row, first.col, last.row, last.col)); 4318d522f475Smrg 4319d522f475Smrg old_start = screen->startH; 4320d522f475Smrg old_end = screen->endH; 43210bd37d32Smrg TRACE(("...previous(first=%d,%d, last=%d,%d)\n", 43220bd37d32Smrg old_start.row, old_start.col, 43230bd37d32Smrg old_end.row, old_end.col)); 4324d522f475Smrg if (isSameCELL(&first, &old_start) && 43250bd37d32Smrg isSameCELL(&last, &old_end)) { 4326d522f475Smrg return; 43270bd37d32Smrg } 43280bd37d32Smrg 4329d522f475Smrg screen->startH = first; 4330d522f475Smrg screen->endH = last; 4331d522f475Smrg from = Coordinate(screen, &screen->startH); 4332d522f475Smrg to = Coordinate(screen, &screen->endH); 4333d522f475Smrg if (to <= screen->startHCoord || from > screen->endHCoord) { 4334d522f475Smrg /* No overlap whatsoever between old and new hilite */ 4335d522f475Smrg ReHiliteText(xw, &old_start, &old_end); 4336d522f475Smrg ReHiliteText(xw, &first, &last); 4337d522f475Smrg } else { 4338d522f475Smrg if (from < screen->startHCoord) { 4339d522f475Smrg /* Extend left end */ 4340d522f475Smrg ReHiliteText(xw, &first, &old_start); 4341d522f475Smrg } else if (from > screen->startHCoord) { 4342d522f475Smrg /* Shorten left end */ 4343d522f475Smrg ReHiliteText(xw, &old_start, &first); 4344d522f475Smrg } 4345d522f475Smrg if (to > screen->endHCoord) { 4346d522f475Smrg /* Extend right end */ 4347d522f475Smrg ReHiliteText(xw, &old_end, &last); 4348d522f475Smrg } else if (to < screen->endHCoord) { 4349d522f475Smrg /* Shorten right end */ 4350d522f475Smrg ReHiliteText(xw, &last, &old_end); 4351d522f475Smrg } 4352d522f475Smrg } 4353d522f475Smrg screen->startHCoord = from; 4354d522f475Smrg screen->endHCoord = to; 4355d522f475Smrg} 4356d522f475Smrg 4357f2e35a3aSmrgstatic void 4358f2e35a3aSmrgUnHiliteText(XtermWidget xw) 4359f2e35a3aSmrg{ 4360f2e35a3aSmrg TrackText(xw, &zeroCELL, &zeroCELL); 4361f2e35a3aSmrg} 4362f2e35a3aSmrg 4363d522f475Smrg/* Guaranteed that (first->row, first->col) <= (last->row, last->col) */ 4364d522f475Smrgstatic void 4365d522f475SmrgReHiliteText(XtermWidget xw, 4366e0a2b6dfSmrg CELL *firstp, 4367e0a2b6dfSmrg CELL *lastp) 4368d522f475Smrg{ 4369956cc18dSsnj TScreen *screen = TScreenOf(xw); 4370d522f475Smrg CELL first = *firstp; 4371d522f475Smrg CELL last = *lastp; 4372d522f475Smrg 4373d522f475Smrg TRACE(("ReHiliteText from %d.%d to %d.%d\n", 4374d522f475Smrg first.row, first.col, last.row, last.col)); 4375d522f475Smrg 4376d522f475Smrg if (first.row < 0) 4377d522f475Smrg first.row = first.col = 0; 4378d522f475Smrg else if (first.row > screen->max_row) 4379d522f475Smrg return; /* nothing to do, since last.row >= first.row */ 4380d522f475Smrg 4381d522f475Smrg if (last.row < 0) 4382d522f475Smrg return; /* nothing to do, since first.row <= last.row */ 4383d522f475Smrg else if (last.row > screen->max_row) { 4384d522f475Smrg last.row = screen->max_row; 4385d522f475Smrg last.col = MaxCols(screen); 4386d522f475Smrg } 4387d522f475Smrg if (isSameCELL(&first, &last)) 4388d522f475Smrg return; 4389d522f475Smrg 4390d522f475Smrg if (!isSameRow(&first, &last)) { /* do multiple rows */ 43912e4f8982Smrg int i; 4392d522f475Smrg if ((i = screen->max_col - first.col + 1) > 0) { /* first row */ 4393d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, i, True); 4394d522f475Smrg } 4395d522f475Smrg if ((i = last.row - first.row - 1) > 0) { /* middle rows */ 4396d522f475Smrg ScrnRefresh(xw, first.row + 1, 0, i, MaxCols(screen), True); 4397d522f475Smrg } 4398d522f475Smrg if (last.col > 0 && last.row <= screen->max_row) { /* last row */ 4399d522f475Smrg ScrnRefresh(xw, last.row, 0, 1, last.col, True); 4400d522f475Smrg } 4401d522f475Smrg } else { /* do single row */ 4402d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, last.col - first.col, True); 4403d522f475Smrg } 4404d522f475Smrg} 4405d522f475Smrg 4406d522f475Smrg/* 4407913cc679Smrg * Guaranteed that (cellc->row, cellc->col) <= (cell->row, cell->col), 4408913cc679Smrg * and that both points are valid 4409d522f475Smrg * (may have cell->row = screen->max_row+1, cell->col = 0). 4410d522f475Smrg */ 4411d522f475Smrgstatic void 4412d522f475SmrgSaltTextAway(XtermWidget xw, 4413f2e35a3aSmrg int which, 4414e0a2b6dfSmrg CELL *cellc, 4415e0a2b6dfSmrg CELL *cell) 4416d522f475Smrg{ 4417956cc18dSsnj TScreen *screen = TScreenOf(xw); 4418f2e35a3aSmrg SelectedCells *scp; 4419f2e35a3aSmrg int i; 4420d522f475Smrg int eol; 4421f2e35a3aSmrg int need = 0; 4422f2e35a3aSmrg size_t have = 0; 4423d522f475Smrg Char *line; 4424d522f475Smrg Char *lp; 4425d522f475Smrg CELL first = *cellc; 4426d522f475Smrg CELL last = *cell; 4427d522f475Smrg 4428f2e35a3aSmrg if (which < 0 || which >= MAX_SELECTIONS) { 4429f2e35a3aSmrg TRACE(("SaltTextAway - which selection?\n")); 4430f2e35a3aSmrg return; 4431f2e35a3aSmrg } 4432f2e35a3aSmrg scp = &(screen->selected_cells[which]); 4433f2e35a3aSmrg 4434f2e35a3aSmrg TRACE(("SaltTextAway which=%d, first=%d,%d, last=%d,%d\n", 4435f2e35a3aSmrg which, first.row, first.col, last.row, last.col)); 4436f2e35a3aSmrg 4437d522f475Smrg if (isSameRow(&first, &last) && first.col > last.col) { 44382e4f8982Smrg int tmp; 4439956cc18dSsnj EXCHANGE(first.col, last.col, tmp); 4440d522f475Smrg } 4441d522f475Smrg 4442d522f475Smrg --last.col; 4443d522f475Smrg /* first we need to know how long the string is before we can save it */ 4444d522f475Smrg 4445d522f475Smrg if (isSameRow(&last, &first)) { 4446f2e35a3aSmrg need = Length(screen, first.row, first.col, last.col); 4447d522f475Smrg } else { /* two cases, cut is on same line, cut spans multiple lines */ 4448f2e35a3aSmrg need += Length(screen, first.row, first.col, screen->max_col) + 1; 4449d522f475Smrg for (i = first.row + 1; i < last.row; i++) 4450f2e35a3aSmrg need += Length(screen, i, 0, screen->max_col) + 1; 4451d522f475Smrg if (last.col >= 0) 4452f2e35a3aSmrg need += Length(screen, last.row, 0, last.col); 4453d522f475Smrg } 4454d522f475Smrg 4455d522f475Smrg /* UTF-8 may require more space */ 4456d522f475Smrg if_OPT_WIDE_CHARS(screen, { 4457f2e35a3aSmrg if (need > 0) { 4458f2e35a3aSmrg if (screen->max_combining > 0) 4459f2e35a3aSmrg need += screen->max_combining; 4460f2e35a3aSmrg need *= 6; 4461f2e35a3aSmrg } 4462d522f475Smrg }); 4463d522f475Smrg 4464d522f475Smrg /* now get some memory to save it in */ 4465f2e35a3aSmrg if (need < 0) 4466f2e35a3aSmrg return; 4467d522f475Smrg 4468f2e35a3aSmrg if (scp->data_limit <= (unsigned) need) { 4469f2e35a3aSmrg if ((line = (Char *) malloc((size_t) need + 1)) == 0) 4470d522f475Smrg SysError(ERROR_BMALLOC2); 4471f2e35a3aSmrg free(scp->data_buffer); 4472f2e35a3aSmrg scp->data_buffer = line; 4473f2e35a3aSmrg scp->data_limit = (size_t) (need + 1); 4474d522f475Smrg } else { 4475f2e35a3aSmrg line = scp->data_buffer; 4476d522f475Smrg } 4477d522f475Smrg 4478f2e35a3aSmrg if (line == 0) 4479d522f475Smrg return; 4480d522f475Smrg 4481f2e35a3aSmrg line[need] = '\0'; /* make sure it is null terminated */ 4482d522f475Smrg lp = line; /* lp points to where to save the text */ 4483d522f475Smrg if (isSameRow(&last, &first)) { 4484d522f475Smrg lp = SaveText(screen, last.row, first.col, last.col, lp, &eol); 4485d522f475Smrg } else { 4486d522f475Smrg lp = SaveText(screen, first.row, first.col, screen->max_col, lp, &eol); 4487d522f475Smrg if (eol) 4488d522f475Smrg *lp++ = '\n'; /* put in newline at end of line */ 4489d522f475Smrg for (i = first.row + 1; i < last.row; i++) { 4490d522f475Smrg lp = SaveText(screen, i, 0, screen->max_col, lp, &eol); 4491d522f475Smrg if (eol) 4492d522f475Smrg *lp++ = '\n'; 4493d522f475Smrg } 4494d522f475Smrg if (last.col >= 0) 4495d522f475Smrg lp = SaveText(screen, last.row, 0, last.col, lp, &eol); 4496d522f475Smrg } 4497d522f475Smrg *lp = '\0'; /* make sure we have end marked */ 4498d522f475Smrg 4499f2e35a3aSmrg have = (size_t) (lp - line); 4500f2e35a3aSmrg /* 4501f2e35a3aSmrg * Scanning the buffer twice is unnecessary. Discard unwanted memory if 4502f2e35a3aSmrg * the estimate is too-far off. 4503f2e35a3aSmrg */ 4504f2e35a3aSmrg if ((have * 2) < (size_t) need) { 4505f2e35a3aSmrg Char *next; 4506f2e35a3aSmrg scp->data_limit = have + 1; 4507f2e35a3aSmrg next = realloc(line, scp->data_limit); 4508f2e35a3aSmrg if (next == NULL) { 4509f2e35a3aSmrg free(line); 4510f2e35a3aSmrg scp->data_length = 0; 4511f2e35a3aSmrg scp->data_limit = 0; 4512f2e35a3aSmrg } 4513f2e35a3aSmrg scp->data_buffer = next; 4514f2e35a3aSmrg } 4515f2e35a3aSmrg scp->data_length = have; 4516d522f475Smrg 4517f2e35a3aSmrg TRACE(("Salted TEXT:%u:%s\n", (unsigned) have, 4518f2e35a3aSmrg visibleChars(scp->data_buffer, (unsigned) have))); 4519d522f475Smrg} 4520d522f475Smrg 4521d522f475Smrg#if OPT_PASTE64 4522d522f475Smrgvoid 4523f2e35a3aSmrgClearSelectionBuffer(TScreen *screen, String selection) 4524d522f475Smrg{ 4525f2e35a3aSmrg int which = TargetToSelection(screen, selection); 4526f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[okSelectionCode(which)]); 4527f2e35a3aSmrg FreeAndNull(scp->data_buffer); 4528f2e35a3aSmrg scp->data_limit = 0; 4529f2e35a3aSmrg scp->data_length = 0; 4530d522f475Smrg screen->base64_count = 0; 4531d522f475Smrg} 4532d522f475Smrg 4533d522f475Smrgstatic void 4534f2e35a3aSmrgAppendStrToSelectionBuffer(SelectedCells * scp, Char *text, size_t len) 4535d522f475Smrg{ 4536d522f475Smrg if (len != 0) { 4537f2e35a3aSmrg size_t j = (scp->data_length + len); 4538f2e35a3aSmrg size_t k = j + (j >> 2) + 80; 4539f2e35a3aSmrg if (j + 1 >= scp->data_limit) { 4540f2e35a3aSmrg Char *line; 4541f2e35a3aSmrg if (!scp->data_length) { 4542f2e35a3aSmrg line = (Char *) malloc(k); 4543d522f475Smrg } else { 4544f2e35a3aSmrg line = (Char *) realloc(scp->data_buffer, k); 4545d522f475Smrg } 4546f2e35a3aSmrg if (line == 0) 4547f2e35a3aSmrg SysError(ERROR_BMALLOC2); 4548f2e35a3aSmrg scp->data_buffer = line; 4549f2e35a3aSmrg scp->data_limit = k; 4550d522f475Smrg } 4551f2e35a3aSmrg if (scp->data_buffer != 0) { 4552f2e35a3aSmrg memcpy(scp->data_buffer + scp->data_length, text, len); 4553f2e35a3aSmrg scp->data_length += len; 4554f2e35a3aSmrg scp->data_buffer[scp->data_length] = 0; 455520d2c4d2Smrg } 4556d522f475Smrg } 4557d522f475Smrg} 4558d522f475Smrg 4559d522f475Smrgvoid 4560f2e35a3aSmrgAppendToSelectionBuffer(TScreen *screen, unsigned c, String selection) 4561d522f475Smrg{ 4562f2e35a3aSmrg int which = TargetToSelection(screen, selection); 4563f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[okSelectionCode(which)]); 45642eaa94a1Schristos unsigned six; 4565d522f475Smrg Char ch; 4566d522f475Smrg 4567d522f475Smrg /* Decode base64 character */ 4568d522f475Smrg if (c >= 'A' && c <= 'Z') 4569d522f475Smrg six = c - 'A'; 4570d522f475Smrg else if (c >= 'a' && c <= 'z') 4571d522f475Smrg six = c - 'a' + 26; 4572d522f475Smrg else if (c >= '0' && c <= '9') 4573d522f475Smrg six = c - '0' + 52; 4574d522f475Smrg else if (c == '+') 4575d522f475Smrg six = 62; 4576d522f475Smrg else if (c == '/') 4577d522f475Smrg six = 63; 4578d522f475Smrg else 4579d522f475Smrg return; 4580d522f475Smrg 4581d522f475Smrg /* Accumulate bytes */ 4582d522f475Smrg switch (screen->base64_count) { 4583d522f475Smrg case 0: 4584d522f475Smrg screen->base64_accu = six; 4585d522f475Smrg screen->base64_count = 6; 4586d522f475Smrg break; 4587d522f475Smrg 4588d522f475Smrg case 2: 45892eaa94a1Schristos ch = CharOf((screen->base64_accu << 6) + six); 4590d522f475Smrg screen->base64_count = 0; 4591f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4592d522f475Smrg break; 4593d522f475Smrg 4594d522f475Smrg case 4: 45952eaa94a1Schristos ch = CharOf((screen->base64_accu << 4) + (six >> 2)); 4596d522f475Smrg screen->base64_accu = (six & 0x3); 4597d522f475Smrg screen->base64_count = 2; 4598f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4599d522f475Smrg break; 4600d522f475Smrg 4601d522f475Smrg case 6: 46022eaa94a1Schristos ch = CharOf((screen->base64_accu << 2) + (six >> 4)); 4603d522f475Smrg screen->base64_accu = (six & 0xF); 4604d522f475Smrg screen->base64_count = 4; 4605f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4606d522f475Smrg break; 4607d522f475Smrg } 4608d522f475Smrg} 4609d522f475Smrg 4610d522f475Smrgvoid 4611e0a2b6dfSmrgCompleteSelection(XtermWidget xw, String *args, Cardinal len) 4612d522f475Smrg{ 4613956cc18dSsnj TScreen *screen = TScreenOf(xw); 4614956cc18dSsnj 4615956cc18dSsnj screen->base64_count = 0; 4616956cc18dSsnj screen->base64_accu = 0; 4617d522f475Smrg _OwnSelection(xw, args, len); 4618d522f475Smrg} 4619d522f475Smrg#endif /* OPT_PASTE64 */ 4620d522f475Smrg 4621d522f475Smrgstatic Bool 4622d522f475Smrg_ConvertSelectionHelper(Widget w, 4623f2e35a3aSmrg SelectedCells * scp, 4624894e0ac8Smrg Atom *type, 4625d522f475Smrg XtPointer *value, 4626d522f475Smrg unsigned long *length, 4627d522f475Smrg int *format, 4628d522f475Smrg int (*conversion_function) (Display *, 4629d522f475Smrg char **, int, 4630d522f475Smrg XICCEncodingStyle, 4631d522f475Smrg XTextProperty *), 4632d522f475Smrg XICCEncodingStyle conversion_style) 4633d522f475Smrg{ 463401037d57Smrg *value = 0; 463501037d57Smrg *length = 0; 463601037d57Smrg *type = 0; 463701037d57Smrg *format = 0; 463801037d57Smrg 4639f2e35a3aSmrg if (getXtermWidget(w) != 0) { 4640d522f475Smrg Display *dpy = XtDisplay(w); 4641d522f475Smrg XTextProperty textprop; 464201037d57Smrg int out_n = 0; 464301037d57Smrg char *result = 0; 4644f2e35a3aSmrg char *the_data = (char *) scp->data_buffer; 464501037d57Smrg char *the_next; 4646f2e35a3aSmrg unsigned long remaining = scp->data_length; 464701037d57Smrg 464801037d57Smrg TRACE(("converting %ld:'%s'\n", 4649f2e35a3aSmrg (long) scp->data_length, 4650f2e35a3aSmrg visibleChars(scp->data_buffer, (unsigned) scp->data_length))); 465101037d57Smrg /* 465201037d57Smrg * For most selections, we can convert in one pass. It is possible 465301037d57Smrg * that some applications contain embedded nulls, e.g., using xterm's 465401037d57Smrg * paste64 feature. For those cases, we will build up the result in 465501037d57Smrg * parts. 465601037d57Smrg */ 4657f2e35a3aSmrg if (memchr(the_data, 0, scp->data_length) != 0) { 465801037d57Smrg TRACE(("selection contains embedded nulls\n")); 4659f2e35a3aSmrg result = calloc(scp->data_length + 1, sizeof(char)); 466001037d57Smrg } 4661d522f475Smrg 466201037d57Smrg next_try: 466301037d57Smrg memset(&textprop, 0, sizeof(textprop)); 4664d522f475Smrg if (conversion_function(dpy, &the_data, 1, 4665d522f475Smrg conversion_style, 4666d522f475Smrg &textprop) >= Success) { 466701037d57Smrg if ((result != 0) 466801037d57Smrg && (textprop.value != 0) 466901037d57Smrg && (textprop.format == 8)) { 467001037d57Smrg char *text_values = (char *) textprop.value; 467101037d57Smrg unsigned long in_n; 467201037d57Smrg 467301037d57Smrg if (out_n == 0) { 467401037d57Smrg *value = result; 467501037d57Smrg *type = textprop.encoding; 467601037d57Smrg *format = textprop.format; 467701037d57Smrg } 467801037d57Smrg for (in_n = 0; in_n < textprop.nitems; ++in_n) { 467901037d57Smrg result[out_n++] = text_values[in_n]; 468001037d57Smrg } 468101037d57Smrg *length += textprop.nitems; 468201037d57Smrg if ((the_next = memchr(the_data, 0, remaining)) != 0) { 468301037d57Smrg unsigned long this_was = (unsigned long) (the_next - the_data); 468401037d57Smrg this_was++; 468501037d57Smrg the_data += this_was; 468601037d57Smrg remaining -= this_was; 468701037d57Smrg result[out_n++] = 0; 468801037d57Smrg *length += 1; 468901037d57Smrg if (remaining) 469001037d57Smrg goto next_try; 469101037d57Smrg } 469201037d57Smrg return True; 469301037d57Smrg } else { 469401037d57Smrg free(result); 469501037d57Smrg *value = (XtPointer) textprop.value; 469601037d57Smrg *length = textprop.nitems; 469701037d57Smrg *type = textprop.encoding; 469801037d57Smrg *format = textprop.format; 469901037d57Smrg return True; 470001037d57Smrg } 4701d522f475Smrg } 470201037d57Smrg free(result); 4703d522f475Smrg } 4704d522f475Smrg return False; 4705d522f475Smrg} 4706d522f475Smrg 47072eaa94a1Schristosstatic Boolean 47082eaa94a1SchristosSaveConvertedLength(XtPointer *target, unsigned long source) 47092eaa94a1Schristos{ 47102eaa94a1Schristos Boolean result = False; 47112eaa94a1Schristos 47122eaa94a1Schristos *target = XtMalloc(4); 47132eaa94a1Schristos if (*target != 0) { 47142eaa94a1Schristos result = True; 47152eaa94a1Schristos if (sizeof(unsigned long) == 4) { 47162eaa94a1Schristos *(unsigned long *) *target = source; 47172eaa94a1Schristos } else if (sizeof(unsigned) == 4) { 471820d2c4d2Smrg *(unsigned *) *target = (unsigned) source; 47192eaa94a1Schristos } else if (sizeof(unsigned short) == 4) { 47202eaa94a1Schristos *(unsigned short *) *target = (unsigned short) source; 47212eaa94a1Schristos } else { 47222eaa94a1Schristos /* FIXME - does this depend on byte-order? */ 47232eaa94a1Schristos unsigned long temp = source; 472420d2c4d2Smrg memcpy((char *) *target, 472520d2c4d2Smrg ((char *) &temp) + sizeof(temp) - 4, 472620d2c4d2Smrg (size_t) 4); 47272eaa94a1Schristos } 47282eaa94a1Schristos } 47292eaa94a1Schristos return result; 47302eaa94a1Schristos} 47312eaa94a1Schristos 4732f2e35a3aSmrg#define keepClipboard(d,atom) ((screen->keepClipboard) && \ 4733f2e35a3aSmrg (atom == XA_CLIPBOARD(d))) 47342e4f8982Smrg 4735d522f475Smrgstatic Boolean 4736d522f475SmrgConvertSelection(Widget w, 4737894e0ac8Smrg Atom *selection, 4738894e0ac8Smrg Atom *target, 4739894e0ac8Smrg Atom *type, 4740d522f475Smrg XtPointer *value, 4741d522f475Smrg unsigned long *length, 4742d522f475Smrg int *format) 4743d522f475Smrg{ 4744d522f475Smrg Display *dpy = XtDisplay(w); 4745d522f475Smrg TScreen *screen; 4746f2e35a3aSmrg SelectedCells *scp; 4747d522f475Smrg Bool result = False; 4748d522f475Smrg 47492e4f8982Smrg Char *data; 47502e4f8982Smrg unsigned long data_length; 47512e4f8982Smrg 4752956cc18dSsnj XtermWidget xw; 4753956cc18dSsnj 4754956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 4755d522f475Smrg return False; 4756d522f475Smrg 4757956cc18dSsnj screen = TScreenOf(xw); 4758d522f475Smrg 4759f2e35a3aSmrg TRACE(("ConvertSelection %s -> %s\n", 4760f2e35a3aSmrg TraceAtomName(screen->display, *selection), 4761956cc18dSsnj visibleSelectionTarget(dpy, *target))); 4762956cc18dSsnj 4763f2e35a3aSmrg if (keepClipboard(dpy, *selection)) { 47642e4f8982Smrg TRACE(("asked for clipboard\n")); 4765f2e35a3aSmrg scp = &(screen->clipboard_data); 47662e4f8982Smrg } else { 47672e4f8982Smrg TRACE(("asked for selection\n")); 4768f2e35a3aSmrg scp = &(screen->selected_cells[AtomToSelection(dpy, *selection)]); 47692e4f8982Smrg } 47702e4f8982Smrg 4771f2e35a3aSmrg data = scp->data_buffer; 4772f2e35a3aSmrg data_length = scp->data_length; 47732e4f8982Smrg if (data == NULL) { 4774f2e35a3aSmrg TRACE(("...no selection-data\n")); 4775f2e35a3aSmrg return False; 477601037d57Smrg } 477701037d57Smrg 4778d522f475Smrg if (*target == XA_TARGETS(dpy)) { 4779d522f475Smrg Atom *targetP; 4780d522f475Smrg XPointer std_return = 0; 4781d522f475Smrg unsigned long std_length; 4782d522f475Smrg 4783d522f475Smrg if (XmuConvertStandardSelection(w, screen->selection_time, selection, 4784d522f475Smrg target, type, &std_return, 4785d522f475Smrg &std_length, format)) { 4786956cc18dSsnj Atom *my_targets = _SelectionTargets(w); 47872e4f8982Smrg Atom *allocP; 47882e4f8982Smrg Atom *std_targets; 4789956cc18dSsnj 4790956cc18dSsnj TRACE(("XmuConvertStandardSelection - success\n")); 4791a1f3da82Smrg std_targets = (Atom *) (void *) (std_return); 4792d522f475Smrg *length = std_length + 6; 4793d522f475Smrg 4794a1f3da82Smrg targetP = TypeXtMallocN(Atom, *length); 4795d522f475Smrg allocP = targetP; 4796d522f475Smrg 4797d522f475Smrg *value = (XtPointer) targetP; 4798d522f475Smrg 47990bd37d32Smrg if (my_targets != 0) { 48000bd37d32Smrg while (*my_targets != None) { 48010bd37d32Smrg *targetP++ = *my_targets++; 48020bd37d32Smrg } 4803956cc18dSsnj } 4804d522f475Smrg *targetP++ = XA_LENGTH(dpy); 4805d522f475Smrg *targetP++ = XA_LIST_LENGTH(dpy); 4806d522f475Smrg 48072eaa94a1Schristos *length = std_length + (unsigned long) (targetP - allocP); 4808d522f475Smrg 4809d522f475Smrg memcpy(targetP, std_targets, sizeof(Atom) * std_length); 4810d522f475Smrg XtFree((char *) std_targets); 4811d522f475Smrg *type = XA_ATOM; 4812d522f475Smrg *format = 32; 4813d522f475Smrg result = True; 4814956cc18dSsnj } else { 4815956cc18dSsnj TRACE(("XmuConvertStandardSelection - failed\n")); 4816d522f475Smrg } 4817d522f475Smrg } 4818d522f475Smrg#if OPT_WIDE_CHARS 4819d522f475Smrg else if (screen->wide_chars && *target == XA_STRING) { 4820d522f475Smrg result = 4821f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4822f2e35a3aSmrg type, value, length, format, 4823d522f475Smrg Xutf8TextListToTextProperty, 4824d522f475Smrg XStringStyle); 4825956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4826d522f475Smrg } else if (screen->wide_chars && *target == XA_UTF8_STRING(dpy)) { 4827d522f475Smrg result = 4828f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4829f2e35a3aSmrg type, value, length, format, 4830d522f475Smrg Xutf8TextListToTextProperty, 4831d522f475Smrg XUTF8StringStyle); 4832956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4833d522f475Smrg } else if (screen->wide_chars && *target == XA_TEXT(dpy)) { 4834d522f475Smrg result = 4835f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4836f2e35a3aSmrg type, value, length, format, 4837d522f475Smrg Xutf8TextListToTextProperty, 4838d522f475Smrg XStdICCTextStyle); 4839956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4840d522f475Smrg } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(dpy)) { 4841d522f475Smrg result = 4842f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4843f2e35a3aSmrg type, value, length, format, 4844d522f475Smrg Xutf8TextListToTextProperty, 4845d522f475Smrg XCompoundTextStyle); 4846956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4847d522f475Smrg } 4848d522f475Smrg#endif 4849d522f475Smrg 4850d522f475Smrg else if (*target == XA_STRING) { /* not wide_chars */ 4851d522f475Smrg /* We can only reach this point if the selection requestor 4852d522f475Smrg requested STRING before any of TEXT, COMPOUND_TEXT or 4853d522f475Smrg UTF8_STRING. We therefore assume that the requestor is not 4854d522f475Smrg properly internationalised, and dump raw eight-bit data 4855d522f475Smrg with no conversion into the selection. Yes, this breaks 4856d522f475Smrg the ICCCM in non-Latin-1 locales. */ 4857d522f475Smrg *type = XA_STRING; 4858f2e35a3aSmrg *value = (XtPointer) data; 4859f2e35a3aSmrg *length = data_length; 4860d522f475Smrg *format = 8; 4861d522f475Smrg result = True; 4862956cc18dSsnj TRACE(("...raw 8-bit data:%d\n", result)); 4863d522f475Smrg } else if (*target == XA_TEXT(dpy)) { /* not wide_chars */ 4864d522f475Smrg result = 4865f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4866f2e35a3aSmrg type, value, length, format, 4867d522f475Smrg XmbTextListToTextProperty, 4868d522f475Smrg XStdICCTextStyle); 4869956cc18dSsnj TRACE(("...XmbTextListToTextProperty(StdICC):%d\n", result)); 4870d522f475Smrg } else if (*target == XA_COMPOUND_TEXT(dpy)) { /* not wide_chars */ 4871d522f475Smrg result = 4872f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4873f2e35a3aSmrg type, value, length, format, 4874d522f475Smrg XmbTextListToTextProperty, 4875d522f475Smrg XCompoundTextStyle); 4876956cc18dSsnj TRACE(("...XmbTextListToTextProperty(Compound):%d\n", result)); 4877d522f475Smrg } 4878d522f475Smrg#ifdef X_HAVE_UTF8_STRING 4879d522f475Smrg else if (*target == XA_UTF8_STRING(dpy)) { /* not wide_chars */ 4880d522f475Smrg result = 4881f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4882f2e35a3aSmrg type, value, length, format, 4883d522f475Smrg XmbTextListToTextProperty, 4884d522f475Smrg XUTF8StringStyle); 4885956cc18dSsnj TRACE(("...XmbTextListToTextProperty(UTF8):%d\n", result)); 4886d522f475Smrg } 4887d522f475Smrg#endif 4888d522f475Smrg else if (*target == XA_LIST_LENGTH(dpy)) { 488920d2c4d2Smrg result = SaveConvertedLength(value, (unsigned long) 1); 4890d522f475Smrg *type = XA_INTEGER; 4891d522f475Smrg *length = 1; 4892d522f475Smrg *format = 32; 4893956cc18dSsnj TRACE(("...list of values:%d\n", result)); 4894d522f475Smrg } else if (*target == XA_LENGTH(dpy)) { 4895d522f475Smrg /* This value is wrong if we have UTF-8 text */ 4896f2e35a3aSmrg result = SaveConvertedLength(value, scp->data_length); 4897d522f475Smrg *type = XA_INTEGER; 4898d522f475Smrg *length = 1; 4899d522f475Smrg *format = 32; 4900956cc18dSsnj TRACE(("...list of values:%d\n", result)); 4901d522f475Smrg } else if (XmuConvertStandardSelection(w, 4902d522f475Smrg screen->selection_time, selection, 4903d522f475Smrg target, type, (XPointer *) value, 4904d522f475Smrg length, format)) { 4905d522f475Smrg result = True; 4906956cc18dSsnj TRACE(("...XmuConvertStandardSelection:%d\n", result)); 4907d522f475Smrg } 4908d522f475Smrg 4909d522f475Smrg /* else */ 49102eaa94a1Schristos return (Boolean) result; 4911d522f475Smrg} 4912d522f475Smrg 4913d522f475Smrgstatic void 4914894e0ac8SmrgLoseSelection(Widget w, Atom *selection) 4915d522f475Smrg{ 4916d522f475Smrg TScreen *screen; 4917d522f475Smrg Atom *atomP; 4918d522f475Smrg Cardinal i; 4919d522f475Smrg 4920956cc18dSsnj XtermWidget xw; 4921956cc18dSsnj 4922956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 4923d522f475Smrg return; 4924d522f475Smrg 4925956cc18dSsnj screen = TScreenOf(xw); 4926913cc679Smrg TRACE(("LoseSelection %s\n", TraceAtomName(screen->display, *selection))); 492701037d57Smrg 4928d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 4929d522f475Smrg i < screen->selection_count; i++, atomP++) { 4930d522f475Smrg if (*selection == *atomP) 4931d522f475Smrg *atomP = (Atom) 0; 4932d522f475Smrg if (CutBuffer(*atomP) >= 0) { 4933d522f475Smrg *atomP = (Atom) 0; 4934d522f475Smrg } 4935d522f475Smrg } 4936d522f475Smrg 4937d522f475Smrg for (i = screen->selection_count; i; i--) { 4938d522f475Smrg if (screen->selection_atoms[i - 1] != 0) 4939d522f475Smrg break; 4940d522f475Smrg } 4941d522f475Smrg screen->selection_count = i; 4942d522f475Smrg 4943d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 4944d522f475Smrg i < screen->selection_count; i++, atomP++) { 4945d522f475Smrg if (*atomP == (Atom) 0) { 4946d522f475Smrg *atomP = screen->selection_atoms[--screen->selection_count]; 4947d522f475Smrg } 4948d522f475Smrg } 4949d522f475Smrg 4950d522f475Smrg if (screen->selection_count == 0) 4951f2e35a3aSmrg UnHiliteText(xw); 4952d522f475Smrg} 4953d522f475Smrg 4954d522f475Smrg/* ARGSUSED */ 4955d522f475Smrgstatic void 4956d522f475SmrgSelectionDone(Widget w GCC_UNUSED, 4957894e0ac8Smrg Atom *selection GCC_UNUSED, 4958894e0ac8Smrg Atom *target GCC_UNUSED) 4959d522f475Smrg{ 4960d522f475Smrg /* empty proc so Intrinsics know we want to keep storage */ 496101037d57Smrg TRACE(("SelectionDone\n")); 4962d522f475Smrg} 4963d522f475Smrg 4964d522f475Smrgstatic void 4965d522f475Smrg_OwnSelection(XtermWidget xw, 4966e0a2b6dfSmrg String *selections, 4967d522f475Smrg Cardinal count) 4968d522f475Smrg{ 4969956cc18dSsnj TScreen *screen = TScreenOf(xw); 4970f2e35a3aSmrg Display *dpy = screen->display; 4971d522f475Smrg Atom *atoms = screen->selection_atoms; 4972d522f475Smrg Cardinal i; 4973d522f475Smrg Bool have_selection = False; 4974f2e35a3aSmrg SelectedCells *scp; 4975d522f475Smrg 497620d2c4d2Smrg if (count == 0) 497720d2c4d2Smrg return; 4978d522f475Smrg 4979f2e35a3aSmrg TRACE(("_OwnSelection count %d\n", count)); 4980d522f475Smrg selections = MapSelections(xw, selections, count); 4981d522f475Smrg 4982d522f475Smrg if (count > screen->sel_atoms_size) { 4983d522f475Smrg XtFree((char *) atoms); 4984a1f3da82Smrg atoms = TypeXtMallocN(Atom, count); 4985d522f475Smrg screen->selection_atoms = atoms; 4986d522f475Smrg screen->sel_atoms_size = count; 4987d522f475Smrg } 4988f2e35a3aSmrg XmuInternStrings(dpy, selections, count, atoms); 4989d522f475Smrg for (i = 0; i < count; i++) { 4990d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 4991d522f475Smrg if (cutbuffer >= 0) { 49922eaa94a1Schristos unsigned long limit = 4993f2e35a3aSmrg (unsigned long) (4 * XMaxRequestSize(dpy) - 32); 4994f2e35a3aSmrg scp = &(screen->selected_cells[CutBufferToCode(cutbuffer)]); 4995f2e35a3aSmrg if (scp->data_length > limit) { 499620d2c4d2Smrg TRACE(("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 4997f2e35a3aSmrg (unsigned long) scp->data_length, cutbuffer)); 49980bd37d32Smrg xtermWarning("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 4999f2e35a3aSmrg (unsigned long) scp->data_length, cutbuffer); 5000d522f475Smrg } else { 5001d522f475Smrg /* This used to just use the UTF-8 data, which was totally 5002894e0ac8Smrg * broken as not even the corresponding paste code in xterm 5003d522f475Smrg * understood this! So now it converts to Latin1 first. 5004d522f475Smrg * Robert Brady, 2000-09-05 5005d522f475Smrg */ 5006f2e35a3aSmrg unsigned long length = scp->data_length; 5007f2e35a3aSmrg Char *data = scp->data_buffer; 5008d522f475Smrg if_OPT_WIDE_CHARS((screen), { 5009956cc18dSsnj data = UTF8toLatin1(screen, data, length, &length); 5010d522f475Smrg }); 5011d522f475Smrg TRACE(("XStoreBuffer(%d)\n", cutbuffer)); 5012f2e35a3aSmrg XStoreBuffer(dpy, 5013d522f475Smrg (char *) data, 5014d522f475Smrg (int) length, 5015d522f475Smrg cutbuffer); 5016d522f475Smrg } 5017f2e35a3aSmrg } else { 5018f2e35a3aSmrg int which = AtomToSelection(dpy, atoms[i]); 5019f2e35a3aSmrg if (keepClipboard(dpy, atoms[i])) { 5020f2e35a3aSmrg Char *buf; 5021f2e35a3aSmrg SelectedCells *tcp = &(screen->clipboard_data); 5022f2e35a3aSmrg TRACE(("saving selection to clipboard buffer\n")); 5023f2e35a3aSmrg scp = &(screen->selected_cells[CLIPBOARD_CODE]); 50245307cd1aSmrg if ((buf = (Char *) malloc((size_t) scp->data_length)) == 0) { 5025f2e35a3aSmrg SysError(ERROR_BMALLOC2); 50265307cd1aSmrg } else { 50275307cd1aSmrg free(tcp->data_buffer); 50285307cd1aSmrg memcpy(buf, scp->data_buffer, scp->data_length); 50295307cd1aSmrg tcp->data_buffer = buf; 50305307cd1aSmrg tcp->data_limit = scp->data_length; 50315307cd1aSmrg tcp->data_length = scp->data_length; 50325307cd1aSmrg } 5033f2e35a3aSmrg } 5034f2e35a3aSmrg scp = &(screen->selected_cells[which]); 5035f2e35a3aSmrg if (scp->data_length == 0) { 5036f2e35a3aSmrg TRACE(("XtDisownSelection(%s, @%ld)\n", 5037f2e35a3aSmrg TraceAtomName(screen->display, atoms[i]), 5038f2e35a3aSmrg (long) screen->selection_time)); 5039f2e35a3aSmrg XtDisownSelection((Widget) xw, 5040f2e35a3aSmrg atoms[i], 5041f2e35a3aSmrg screen->selection_time); 5042f2e35a3aSmrg } else if (!screen->replyToEmacs && atoms[i] != 0) { 5043f2e35a3aSmrg TRACE(("XtOwnSelection(%s, @%ld)\n", 5044f2e35a3aSmrg TraceAtomName(screen->display, atoms[i]), 5045f2e35a3aSmrg (long) screen->selection_time)); 5046f2e35a3aSmrg have_selection |= 5047f2e35a3aSmrg XtOwnSelection((Widget) xw, atoms[i], 5048f2e35a3aSmrg screen->selection_time, 5049f2e35a3aSmrg ConvertSelection, 5050f2e35a3aSmrg LoseSelection, 5051f2e35a3aSmrg SelectionDone); 5052f2e35a3aSmrg } 5053d522f475Smrg } 5054f2e35a3aSmrg TRACE(("... _OwnSelection used length %lu value %s\n", 5055f2e35a3aSmrg (unsigned long) scp->data_length, 5056f2e35a3aSmrg visibleChars(scp->data_buffer, 5057f2e35a3aSmrg (unsigned) scp->data_length))); 5058d522f475Smrg } 5059d522f475Smrg if (!screen->replyToEmacs) 5060d522f475Smrg screen->selection_count = count; 5061d522f475Smrg if (!have_selection) 5062f2e35a3aSmrg UnHiliteText(xw); 5063d522f475Smrg} 5064d522f475Smrg 5065d522f475Smrgstatic void 5066e0a2b6dfSmrgResetSelectionState(TScreen *screen) 5067d522f475Smrg{ 5068d522f475Smrg screen->selection_count = 0; 5069d522f475Smrg screen->startH = zeroCELL; 5070d522f475Smrg screen->endH = zeroCELL; 5071d522f475Smrg} 5072d522f475Smrg 5073d522f475Smrgvoid 5074d522f475SmrgDisownSelection(XtermWidget xw) 5075d522f475Smrg{ 5076956cc18dSsnj TScreen *screen = TScreenOf(xw); 5077d522f475Smrg Atom *atoms = screen->selection_atoms; 5078d522f475Smrg Cardinal count = screen->selection_count; 5079d522f475Smrg Cardinal i; 5080d522f475Smrg 5081d522f475Smrg TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n", 5082d522f475Smrg count, 5083d522f475Smrg screen->startH.row, 5084d522f475Smrg screen->startH.col, 5085d522f475Smrg screen->endH.row, 5086d522f475Smrg screen->endH.col)); 5087d522f475Smrg 5088d522f475Smrg for (i = 0; i < count; i++) { 5089d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 5090d522f475Smrg if (cutbuffer < 0) { 5091d522f475Smrg XtDisownSelection((Widget) xw, atoms[i], 5092d522f475Smrg screen->selection_time); 5093d522f475Smrg } 5094d522f475Smrg } 5095d522f475Smrg /* 5096d522f475Smrg * If none of the callbacks via XtDisownSelection() reset highlighting 5097d522f475Smrg * do it now. 5098d522f475Smrg */ 5099d522f475Smrg if (ScrnHaveSelection(screen)) { 5100d522f475Smrg /* save data which will be reset */ 5101d522f475Smrg CELL first = screen->startH; 5102d522f475Smrg CELL last = screen->endH; 5103d522f475Smrg 5104d522f475Smrg ResetSelectionState(screen); 5105d522f475Smrg ReHiliteText(xw, &first, &last); 5106d522f475Smrg } else { 5107d522f475Smrg ResetSelectionState(screen); 5108d522f475Smrg } 5109d522f475Smrg} 5110d522f475Smrg 5111d522f475Smrgvoid 5112d522f475SmrgUnhiliteSelection(XtermWidget xw) 5113d522f475Smrg{ 5114956cc18dSsnj TScreen *screen = TScreenOf(xw); 5115d522f475Smrg 5116d522f475Smrg if (ScrnHaveSelection(screen)) { 5117d522f475Smrg CELL first = screen->startH; 5118d522f475Smrg CELL last = screen->endH; 5119d522f475Smrg 5120d522f475Smrg screen->startH = zeroCELL; 5121d522f475Smrg screen->endH = zeroCELL; 5122d522f475Smrg ReHiliteText(xw, &first, &last); 5123d522f475Smrg } 5124d522f475Smrg} 5125d522f475Smrg 5126d522f475Smrg/* returns number of chars in line from scol to ecol out */ 5127d522f475Smrg/* ARGSUSED */ 5128d522f475Smrgstatic int 5129e0a2b6dfSmrgLength(TScreen *screen, 5130d522f475Smrg int row, 5131d522f475Smrg int scol, 5132d522f475Smrg int ecol) 5133d522f475Smrg{ 513401037d57Smrg CLineData *ld = GET_LINEDATA(screen, row); 513501037d57Smrg const int lastcol = LastTextCol(screen, ld, row); 5136d522f475Smrg 5137d522f475Smrg if (ecol > lastcol) 5138d522f475Smrg ecol = lastcol; 5139d522f475Smrg return (ecol - scol + 1); 5140d522f475Smrg} 5141d522f475Smrg 5142d522f475Smrg/* copies text into line, preallocated */ 5143d522f475Smrgstatic Char * 5144e0a2b6dfSmrgSaveText(TScreen *screen, 5145d522f475Smrg int row, 5146d522f475Smrg int scol, 5147d522f475Smrg int ecol, 5148e0a2b6dfSmrg Char *lp, /* pointer to where to put the text */ 5149d522f475Smrg int *eol) 5150d522f475Smrg{ 5151956cc18dSsnj LineData *ld; 5152d522f475Smrg int i = 0; 5153d522f475Smrg Char *result = lp; 5154d522f475Smrg#if OPT_WIDE_CHARS 51552eaa94a1Schristos unsigned previous = 0; 5156d522f475Smrg#endif 5157d522f475Smrg 5158956cc18dSsnj ld = GET_LINEDATA(screen, row); 5159d522f475Smrg i = Length(screen, row, scol, ecol); 5160d522f475Smrg ecol = scol + i; 5161d522f475Smrg#if OPT_DEC_CHRSET 5162956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 5163d522f475Smrg scol = (scol + 0) / 2; 5164d522f475Smrg ecol = (ecol + 1) / 2; 5165d522f475Smrg } 5166d522f475Smrg#endif 5167956cc18dSsnj *eol = !LineTstWrapped(ld); 5168d522f475Smrg for (i = scol; i < ecol; i++) { 51692e4f8982Smrg unsigned c; 51700bd37d32Smrg assert(i < (int) ld->lineSize); 5171956cc18dSsnj c = E2A(ld->charData[i]); 517204b94745Smrg if (ld->attribs[i] & INVISIBLE) 517304b94745Smrg continue; 5174d522f475Smrg#if OPT_WIDE_CHARS 5175d522f475Smrg /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a 5176d522f475Smrg * wide character. 5177d522f475Smrg */ 5178894e0ac8Smrg if (c == HIDDEN_CHAR) { 5179894e0ac8Smrg if (isWide((int) previous)) { 5180894e0ac8Smrg previous = c; 5181894e0ac8Smrg /* Combining characters attached to double-width characters 5182894e0ac8Smrg are in memory attached to the HIDDEN_CHAR */ 5183894e0ac8Smrg if_OPT_WIDE_CHARS(screen, { 5184894e0ac8Smrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 5185894e0ac8Smrg size_t off; 5186894e0ac8Smrg for_each_combData(off, ld) { 51872e4f8982Smrg unsigned ch = ld->combData[off][i]; 5188894e0ac8Smrg if (ch == 0) 5189894e0ac8Smrg break; 5190894e0ac8Smrg lp = convertToUTF8(lp, ch); 5191894e0ac8Smrg } 5192d522f475Smrg } 5193894e0ac8Smrg }); 5194894e0ac8Smrg continue; 5195894e0ac8Smrg } else { 5196894e0ac8Smrg c = ' '; /* should not happen, but just in case... */ 5197894e0ac8Smrg } 5198d522f475Smrg } 5199d522f475Smrg previous = c; 5200e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 5201d522f475Smrg lp = convertToUTF8(lp, (c != 0) ? c : ' '); 5202d522f475Smrg if_OPT_WIDE_CHARS(screen, { 5203956cc18dSsnj size_t off; 5204956cc18dSsnj for_each_combData(off, ld) { 52052e4f8982Smrg unsigned ch = ld->combData[off][i]; 5206956cc18dSsnj if (ch == 0) 5207d522f475Smrg break; 5208d522f475Smrg lp = convertToUTF8(lp, ch); 5209d522f475Smrg } 5210d522f475Smrg }); 5211d522f475Smrg } else 5212d522f475Smrg#endif 5213d522f475Smrg { 5214d522f475Smrg if (c == 0) { 5215d522f475Smrg c = E2A(' '); 5216d522f475Smrg } else if (c < E2A(' ')) { 5217d522f475Smrg c = DECtoASCII(c); 5218d522f475Smrg } else if (c == 0x7f) { 5219d522f475Smrg c = 0x5f; 5220d522f475Smrg } 52212eaa94a1Schristos *lp++ = CharOf(A2E(c)); 5222d522f475Smrg } 5223d522f475Smrg if (c != E2A(' ')) 5224d522f475Smrg result = lp; 5225d522f475Smrg } 5226d522f475Smrg 5227d522f475Smrg /* 5228d522f475Smrg * If requested, trim trailing blanks from selected lines. Do not do this 5229d522f475Smrg * if the line is wrapped. 5230d522f475Smrg */ 5231d522f475Smrg if (!*eol || !screen->trim_selection) 5232d522f475Smrg result = lp; 5233d522f475Smrg 5234d522f475Smrg return (result); 5235d522f475Smrg} 5236d522f475Smrg 5237f2e35a3aSmrg/* 5238f2e35a3aSmrg * This adds together the bits: 5239f2e35a3aSmrg * shift key -> 1 5240f2e35a3aSmrg * meta key -> 2 5241f2e35a3aSmrg * control key -> 4 5242f2e35a3aSmrg */ 5243f2e35a3aSmrgstatic unsigned 5244f2e35a3aSmrgKeyState(XtermWidget xw, unsigned x) 5245f2e35a3aSmrg{ 5246f2e35a3aSmrg return ((((x) & (ShiftMask | ControlMask))) 5247f2e35a3aSmrg + (((x) & MetaMask(xw)) ? 2 : 0)); 5248f2e35a3aSmrg} 5249f2e35a3aSmrg 5250f2e35a3aSmrg/* 32 + following 8-bit word: 5251d522f475Smrg 5252d522f475Smrg 1:0 Button no: 0, 1, 2. 3=release. 5253d522f475Smrg 2 shift 5254d522f475Smrg 3 meta 5255d522f475Smrg 4 ctrl 5256d522f475Smrg 5 set for motion notify 5257f2e35a3aSmrg 6 set for wheel (and button 6 and 7) 5258f2e35a3aSmrg 7 set for buttons 8 to 11 5259d522f475Smrg*/ 5260d522f475Smrg 5261d522f475Smrg/* Position: 32 - 255. */ 5262a1f3da82Smrgstatic int 5263f2e35a3aSmrgBtnCode(XtermWidget xw, XButtonEvent *event, int button) 5264d522f475Smrg{ 5265f2e35a3aSmrg int result = (int) (32 + (KeyState(xw, event->state) << 2)); 5266d522f475Smrg 52670bd37d32Smrg if (event->type == MotionNotify) 52680bd37d32Smrg result += 32; 52690bd37d32Smrg 5270f2e35a3aSmrg if (button < 0) { 5271d522f475Smrg result += 3; 5272d522f475Smrg } else { 5273f2e35a3aSmrg result += button & 3; 5274f2e35a3aSmrg if (button & 4) 5275f2e35a3aSmrg result += 64; 5276f2e35a3aSmrg if (button & 8) 5277f2e35a3aSmrg result += 128; 5278d522f475Smrg } 52790bd37d32Smrg TRACE(("BtnCode button %d, %s state " FMT_MODIFIER_NAMES " ->%#x\n", 52800bd37d32Smrg button, 52810bd37d32Smrg visibleEventType(event->type), 52820bd37d32Smrg ARG_MODIFIER_NAMES(event->state), 52830bd37d32Smrg result)); 5284a1f3da82Smrg return result; 5285a1f3da82Smrg} 5286a1f3da82Smrg 5287a1f3da82Smrgstatic unsigned 5288913cc679SmrgEmitButtonCode(XtermWidget xw, 5289e0a2b6dfSmrg Char *line, 52900bd37d32Smrg unsigned count, 5291894e0ac8Smrg XButtonEvent *event, 52920bd37d32Smrg int button) 5293a1f3da82Smrg{ 5294913cc679Smrg TScreen *screen = TScreenOf(xw); 52950bd37d32Smrg int value; 5296a1f3da82Smrg 5297913cc679Smrg if (okSendMousePos(xw) == X10_MOUSE) { 52980bd37d32Smrg value = CharOf(' ' + button); 5299a1f3da82Smrg } else { 5300f2e35a3aSmrg value = BtnCode(xw, event, button); 53010bd37d32Smrg } 53020bd37d32Smrg 53030bd37d32Smrg switch (screen->extend_coords) { 53040bd37d32Smrg default: 53050bd37d32Smrg line[count++] = CharOf(value); 53060bd37d32Smrg break; 53070bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5308f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 53090bd37d32Smrg value -= 32; /* encoding starts at zero */ 53100bd37d32Smrg /* FALLTHRU */ 53110bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 53120bd37d32Smrg count += (unsigned) sprintf((char *) line + count, "%d", value); 53130bd37d32Smrg break; 53140bd37d32Smrg case SET_EXT_MODE_MOUSE: 53150bd37d32Smrg if (value < 128) { 53160bd37d32Smrg line[count++] = CharOf(value); 53170bd37d32Smrg } else { 53180bd37d32Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 53190bd37d32Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 53200bd37d32Smrg } 53210bd37d32Smrg break; 5322a1f3da82Smrg } 5323a1f3da82Smrg return count; 5324d522f475Smrg} 5325d522f475Smrg 53260bd37d32Smrgstatic int 53270bd37d32SmrgFirstBitN(int bits) 53280bd37d32Smrg{ 53290bd37d32Smrg int result = -1; 53300bd37d32Smrg if (bits > 0) { 53310bd37d32Smrg result = 0; 53320bd37d32Smrg while (!(bits & 1)) { 53330bd37d32Smrg bits /= 2; 53340bd37d32Smrg ++result; 53350bd37d32Smrg } 53360bd37d32Smrg } 53370bd37d32Smrg return result; 53380bd37d32Smrg} 53390bd37d32Smrg 53400bd37d32Smrg#define ButtonBit(button) ((button >= 0) ? (1 << (button)) : 0) 53410bd37d32Smrg 5342913cc679Smrg#define EMIT_BUTTON(button) EmitButtonCode(xw, line, count, event, button) 53430bd37d32Smrg 5344d522f475Smrgstatic void 5345894e0ac8SmrgEditorButton(XtermWidget xw, XButtonEvent *event) 5346d522f475Smrg{ 5347956cc18dSsnj TScreen *screen = TScreenOf(xw); 5348d522f475Smrg int pty = screen->respond; 53490bd37d32Smrg int mouse_limit = MouseLimit(screen); 53500bd37d32Smrg Char line[32]; 53510bd37d32Smrg Char final = 'M'; 5352d522f475Smrg int row, col; 5353d522f475Smrg int button; 5354d522f475Smrg unsigned count = 0; 5355d522f475Smrg Boolean changed = True; 5356d522f475Smrg 5357d522f475Smrg /* If button event, get button # adjusted for DEC compatibility */ 53582eaa94a1Schristos button = (int) (event->button - 1); 5359d522f475Smrg if (button >= 3) 5360d522f475Smrg button++; 5361d522f475Smrg 5362f2e35a3aSmrg /* Ignore buttons that cannot be encoded */ 5363f2e35a3aSmrg if (screen->send_mouse_pos == X10_MOUSE) { 5364f2e35a3aSmrg if (button > 3) 5365f2e35a3aSmrg return; 5366f2e35a3aSmrg } else if (screen->extend_coords == SET_SGR_EXT_MODE_MOUSE 5367f2e35a3aSmrg || screen->extend_coords == SET_URXVT_EXT_MODE_MOUSE 5368f2e35a3aSmrg || screen->extend_coords == SET_PIXEL_POSITION_MOUSE) { 5369f2e35a3aSmrg if (button > 15) { 5370f2e35a3aSmrg return; 5371f2e35a3aSmrg } 5372f2e35a3aSmrg } else { 5373f2e35a3aSmrg if (button > 11) { 5374f2e35a3aSmrg return; 5375f2e35a3aSmrg } 5376f2e35a3aSmrg } 5377d522f475Smrg 5378f2e35a3aSmrg if (screen->extend_coords == SET_PIXEL_POSITION_MOUSE) { 5379f2e35a3aSmrg row = event->y - OriginY(screen); 5380f2e35a3aSmrg col = event->x - OriginX(screen); 5381f2e35a3aSmrg } else { 5382f2e35a3aSmrg /* Compute character position of mouse pointer */ 5383f2e35a3aSmrg row = (event->y - screen->border) / FontHeight(screen); 5384f2e35a3aSmrg col = (event->x - OriginX(screen)) / FontWidth(screen); 5385d522f475Smrg 5386f2e35a3aSmrg /* Limit to screen dimensions */ 5387f2e35a3aSmrg if (row < 0) 5388f2e35a3aSmrg row = 0; 5389f2e35a3aSmrg else if (row > screen->max_row) 5390f2e35a3aSmrg row = screen->max_row; 5391492d43a5Smrg 5392f2e35a3aSmrg if (col < 0) 5393f2e35a3aSmrg col = 0; 5394f2e35a3aSmrg else if (col > screen->max_col) 5395f2e35a3aSmrg col = screen->max_col; 5396f2e35a3aSmrg 5397f2e35a3aSmrg if (mouse_limit > 0) { 5398f2e35a3aSmrg /* Limit to representable mouse dimensions */ 5399f2e35a3aSmrg if (row > mouse_limit) 5400f2e35a3aSmrg row = mouse_limit; 5401f2e35a3aSmrg if (col > mouse_limit) 5402f2e35a3aSmrg col = mouse_limit; 5403f2e35a3aSmrg } 54040bd37d32Smrg } 5405d522f475Smrg 5406d522f475Smrg /* Build key sequence starting with \E[M */ 5407d522f475Smrg if (screen->control_eight_bits) { 5408d522f475Smrg line[count++] = ANSI_CSI; 5409d522f475Smrg } else { 5410d522f475Smrg line[count++] = ANSI_ESC; 5411d522f475Smrg line[count++] = '['; 5412d522f475Smrg } 54130bd37d32Smrg switch (screen->extend_coords) { 54140bd37d32Smrg case 0: 54150bd37d32Smrg case SET_EXT_MODE_MOUSE: 5416d522f475Smrg#if OPT_SCO_FUNC_KEYS 54170bd37d32Smrg if (xw->keyboard.type == keyboardIsSCO) { 54180bd37d32Smrg /* 54190bd37d32Smrg * SCO function key F1 is \E[M, which would conflict with xterm's 54200bd37d32Smrg * normal kmous. 54210bd37d32Smrg */ 54220bd37d32Smrg line[count++] = '>'; 54230bd37d32Smrg } 5424d522f475Smrg#endif 54250bd37d32Smrg line[count++] = final; 54260bd37d32Smrg break; 54270bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5428f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 54290bd37d32Smrg line[count++] = '<'; 54300bd37d32Smrg break; 54310bd37d32Smrg } 5432d522f475Smrg 5433d522f475Smrg /* Add event code to key sequence */ 5434913cc679Smrg if (okSendMousePos(xw) == X10_MOUSE) { 54350bd37d32Smrg count = EMIT_BUTTON(button); 5436d522f475Smrg } else { 5437d522f475Smrg /* Button-Motion events */ 5438d522f475Smrg switch (event->type) { 5439d522f475Smrg case ButtonPress: 54400bd37d32Smrg screen->mouse_button |= ButtonBit(button); 54410bd37d32Smrg count = EMIT_BUTTON(button); 5442d522f475Smrg break; 5443d522f475Smrg case ButtonRelease: 5444d522f475Smrg /* 5445f2e35a3aSmrg * The (vertical) wheel mouse interface generates release-events 5446f2e35a3aSmrg * for buttons 4 and 5. 5447f2e35a3aSmrg * 5448f2e35a3aSmrg * The X10/X11 xterm protocol maps the release for buttons 1..3 to 5449f2e35a3aSmrg * a -1, which will be later mapped into a "0" (some button was 5450f2e35a3aSmrg * released), At this point, buttons 1..3 are encoded 0..2 (the 5451f2e35a3aSmrg * code 3 is unused). 5452f2e35a3aSmrg * 5453f2e35a3aSmrg * The SGR (extended) xterm mouse protocol keeps the button number 5454f2e35a3aSmrg * and uses a "m" to indicate button release. 5455f2e35a3aSmrg * 5456f2e35a3aSmrg * The behavior for mice with more buttons is unclear, and may be 5457f2e35a3aSmrg * revised -TD 5458d522f475Smrg */ 54590bd37d32Smrg screen->mouse_button &= ~ButtonBit(button); 5460f2e35a3aSmrg if (button < 3 || button > 5) { 54610bd37d32Smrg switch (screen->extend_coords) { 54620bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5463f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 54640bd37d32Smrg final = 'm'; 54650bd37d32Smrg break; 54660bd37d32Smrg default: 54670bd37d32Smrg button = -1; 54680bd37d32Smrg break; 54690bd37d32Smrg } 54700bd37d32Smrg } 54710bd37d32Smrg count = EMIT_BUTTON(button); 5472d522f475Smrg break; 5473d522f475Smrg case MotionNotify: 5474d522f475Smrg /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion 5475d522f475Smrg * events only if character cell has changed. 5476d522f475Smrg */ 5477d522f475Smrg if ((row == screen->mouse_row) 5478d522f475Smrg && (col == screen->mouse_col)) { 5479d522f475Smrg changed = False; 5480d522f475Smrg } else { 54810bd37d32Smrg count = EMIT_BUTTON(FirstBitN(screen->mouse_button)); 5482d522f475Smrg } 5483d522f475Smrg break; 5484d522f475Smrg default: 5485d522f475Smrg changed = False; 5486d522f475Smrg break; 5487d522f475Smrg } 5488d522f475Smrg } 5489d522f475Smrg 5490d522f475Smrg if (changed) { 5491d522f475Smrg screen->mouse_row = row; 5492d522f475Smrg screen->mouse_col = col; 5493d522f475Smrg 5494492d43a5Smrg TRACE(("mouse at %d,%d button+mask = %#x\n", row, col, line[count - 1])); 5495d522f475Smrg 5496492d43a5Smrg /* Add pointer position to key sequence */ 54970bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 5498492d43a5Smrg count = EmitMousePosition(screen, line, count, col); 54990bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 5500492d43a5Smrg count = EmitMousePosition(screen, line, count, row); 5501d522f475Smrg 55020bd37d32Smrg switch (screen->extend_coords) { 55030bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 55040bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 5505f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 55060bd37d32Smrg line[count++] = final; 55070bd37d32Smrg break; 55080bd37d32Smrg } 55090bd37d32Smrg 5510d522f475Smrg /* Transmit key sequence to process running under xterm */ 5511f2e35a3aSmrg TRACE(("EditorButton -> %s\n", visibleChars(line, count))); 55125307cd1aSmrg v_write(pty, line, (size_t) count); 5513d522f475Smrg } 5514d522f475Smrg return; 5515d522f475Smrg} 5516d522f475Smrg 5517913cc679Smrg/* 5518913cc679Smrg * Check the current send_mouse_pos against allowed mouse-operations, returning 5519913cc679Smrg * none if it is disallowed. 5520913cc679Smrg */ 5521913cc679SmrgXtermMouseModes 5522913cc679SmrgokSendMousePos(XtermWidget xw) 5523913cc679Smrg{ 5524913cc679Smrg TScreen *screen = TScreenOf(xw); 5525f2e35a3aSmrg XtermMouseModes result = (XtermMouseModes) screen->send_mouse_pos; 5526913cc679Smrg 5527f2e35a3aSmrg switch ((int) result) { 5528913cc679Smrg case MOUSE_OFF: 5529913cc679Smrg break; 5530913cc679Smrg case X10_MOUSE: 5531913cc679Smrg if (!AllowMouseOps(xw, emX10)) 5532913cc679Smrg result = MOUSE_OFF; 5533913cc679Smrg break; 5534913cc679Smrg case VT200_MOUSE: 5535913cc679Smrg if (!AllowMouseOps(xw, emVT200Click)) 5536913cc679Smrg result = MOUSE_OFF; 5537913cc679Smrg break; 5538913cc679Smrg case VT200_HIGHLIGHT_MOUSE: 5539913cc679Smrg if (!AllowMouseOps(xw, emVT200Hilite)) 5540913cc679Smrg result = MOUSE_OFF; 5541913cc679Smrg break; 5542913cc679Smrg case BTN_EVENT_MOUSE: 5543913cc679Smrg if (!AllowMouseOps(xw, emAnyButton)) 5544913cc679Smrg result = MOUSE_OFF; 5545913cc679Smrg break; 5546913cc679Smrg case ANY_EVENT_MOUSE: 5547913cc679Smrg if (!AllowMouseOps(xw, emAnyEvent)) 5548913cc679Smrg result = MOUSE_OFF; 5549913cc679Smrg break; 5550913cc679Smrg case DEC_LOCATOR: 5551913cc679Smrg if (!AllowMouseOps(xw, emLocator)) 5552913cc679Smrg result = MOUSE_OFF; 5553913cc679Smrg break; 5554913cc679Smrg } 5555913cc679Smrg return result; 5556913cc679Smrg} 5557913cc679Smrg 5558d522f475Smrg#if OPT_FOCUS_EVENT 5559913cc679Smrg/* 5560913cc679Smrg * Check the current send_focus_pos against allowed mouse-operations, returning 5561913cc679Smrg * none if it is disallowed. 5562913cc679Smrg */ 5563913cc679Smrgstatic int 5564913cc679SmrgokSendFocusPos(XtermWidget xw) 5565d522f475Smrg{ 5566956cc18dSsnj TScreen *screen = TScreenOf(xw); 5567913cc679Smrg int result = screen->send_focus_pos; 5568913cc679Smrg 5569913cc679Smrg if (!AllowMouseOps(xw, emFocusEvent)) { 5570913cc679Smrg result = False; 5571913cc679Smrg } 5572913cc679Smrg return result; 5573913cc679Smrg} 5574d522f475Smrg 5575913cc679Smrgvoid 5576913cc679SmrgSendFocusButton(XtermWidget xw, XFocusChangeEvent *event) 5577913cc679Smrg{ 5578913cc679Smrg if (okSendFocusPos(xw)) { 5579d522f475Smrg ANSI reply; 5580d522f475Smrg 5581d522f475Smrg memset(&reply, 0, sizeof(reply)); 5582d522f475Smrg reply.a_type = ANSI_CSI; 5583d522f475Smrg 5584d522f475Smrg#if OPT_SCO_FUNC_KEYS 5585d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 5586d522f475Smrg reply.a_pintro = '>'; 5587d522f475Smrg } 5588d522f475Smrg#endif 55892eaa94a1Schristos reply.a_final = CharOf((event->type == FocusIn) ? 'I' : 'O'); 5590d522f475Smrg unparseseq(xw, &reply); 5591d522f475Smrg } 5592d522f475Smrg return; 5593d522f475Smrg} 5594d522f475Smrg#endif /* OPT_FOCUS_EVENT */ 55950bd37d32Smrg 55960bd37d32Smrg#if OPT_SELECTION_OPS 55970bd37d32Smrg/* 55980bd37d32Smrg * Get the event-time, needed to process selections. 55990bd37d32Smrg */ 56000bd37d32Smrgstatic Time 5601894e0ac8SmrggetEventTime(XEvent *event) 56020bd37d32Smrg{ 56030bd37d32Smrg Time result; 56040bd37d32Smrg 56050bd37d32Smrg if (IsBtnEvent(event)) { 56060bd37d32Smrg result = ((XButtonEvent *) event)->time; 56070bd37d32Smrg } else if (IsKeyEvent(event)) { 56080bd37d32Smrg result = ((XKeyEvent *) event)->time; 56090bd37d32Smrg } else { 56100bd37d32Smrg result = 0; 56110bd37d32Smrg } 56120bd37d32Smrg 56130bd37d32Smrg return result; 56140bd37d32Smrg} 56150bd37d32Smrg 56160bd37d32Smrg/* obtain the selection string, passing the endpoints to caller's parameters */ 561701037d57Smrgstatic void 561801037d57SmrgdoSelectionFormat(XtermWidget xw, 561901037d57Smrg Widget w, 562001037d57Smrg XEvent *event, 562101037d57Smrg String *params, 562201037d57Smrg Cardinal *num_params, 562301037d57Smrg FormatSelect format_select) 56240bd37d32Smrg{ 56250bd37d32Smrg TScreen *screen = TScreenOf(xw); 562601037d57Smrg InternalSelect *mydata = &(screen->internal_select); 562701037d57Smrg 562801037d57Smrg memset(mydata, 0, sizeof(*mydata)); 562901037d57Smrg mydata->format = x_strdup(params[0]); 563001037d57Smrg mydata->format_select = format_select; 56310bd37d32Smrg 56320bd37d32Smrg screen->selectToBuffer = True; 5633f2e35a3aSmrg beginInternalSelect(xw); 5634f2e35a3aSmrg 56350bd37d32Smrg xtermGetSelection(w, getEventTime(event), params + 1, *num_params - 1, NULL); 5636f2e35a3aSmrg 5637f2e35a3aSmrg if (screen->selectToBuffer) 5638f2e35a3aSmrg finishInternalSelect(xw); 56390bd37d32Smrg} 56400bd37d32Smrg 56410bd37d32Smrg/* obtain data from the screen, passing the endpoints to caller's parameters */ 56420bd37d32Smrgstatic char * 5643913cc679SmrggetDataFromScreen(XtermWidget xw, XEvent *event, String method, CELL *start, CELL *finish) 56440bd37d32Smrg{ 56450bd37d32Smrg TScreen *screen = TScreenOf(xw); 56460bd37d32Smrg 56470bd37d32Smrg CELL save_old_start = screen->startH; 56480bd37d32Smrg CELL save_old_end = screen->endH; 56490bd37d32Smrg 56500bd37d32Smrg CELL save_startSel = screen->startSel; 56510bd37d32Smrg CELL save_startRaw = screen->startRaw; 56520bd37d32Smrg CELL save_finishSel = screen->endSel; 56530bd37d32Smrg CELL save_finishRaw = screen->endRaw; 56540bd37d32Smrg 56550bd37d32Smrg int save_firstValidRow = screen->firstValidRow; 56560bd37d32Smrg int save_lastValidRow = screen->lastValidRow; 56570bd37d32Smrg 565801037d57Smrg const Cardinal noClick = 0; 565901037d57Smrg int save_numberOfClicks = screen->numberOfClicks; 566001037d57Smrg 56610bd37d32Smrg SelectUnit saveUnits = screen->selectUnit; 566201037d57Smrg SelectUnit saveMap = screen->selectMap[noClick]; 56630bd37d32Smrg#if OPT_SELECT_REGEX 566401037d57Smrg char *saveExpr = screen->selectExpr[noClick]; 56650bd37d32Smrg#endif 5666f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[PRIMARY_CODE]); 5667f2e35a3aSmrg SelectedCells save_selection = *scp; 56680bd37d32Smrg 56690bd37d32Smrg char *result = 0; 56700bd37d32Smrg 56710bd37d32Smrg TRACE(("getDataFromScreen %s\n", method)); 56720bd37d32Smrg 5673f2e35a3aSmrg memset(scp, 0, sizeof(*scp)); 56740bd37d32Smrg 567501037d57Smrg screen->numberOfClicks = 1; 567601037d57Smrg lookupSelectUnit(xw, noClick, method); 567701037d57Smrg screen->selectUnit = screen->selectMap[noClick]; 56780bd37d32Smrg 56790bd37d32Smrg memset(start, 0, sizeof(*start)); 5680913cc679Smrg if (IsBtnEvent(event)) { 5681913cc679Smrg XButtonEvent *btn_event = (XButtonEvent *) event; 5682913cc679Smrg CELL cell; 5683913cc679Smrg screen->firstValidRow = 0; 5684913cc679Smrg screen->lastValidRow = screen->max_row; 5685913cc679Smrg PointToCELL(screen, btn_event->y, btn_event->x, &cell); 5686913cc679Smrg start->row = cell.row; 5687913cc679Smrg start->col = cell.col; 5688913cc679Smrg finish->row = cell.row; 5689913cc679Smrg finish->col = screen->max_col; 5690913cc679Smrg } else { 5691913cc679Smrg start->row = screen->cur_row; 5692913cc679Smrg start->col = screen->cur_col; 5693913cc679Smrg finish->row = screen->cur_row; 5694913cc679Smrg finish->col = screen->max_col; 5695913cc679Smrg } 56960bd37d32Smrg 5697f2e35a3aSmrg ComputeSelect(xw, start, finish, False, False); 5698f2e35a3aSmrg SaltTextAway(xw, 5699f2e35a3aSmrg TargetToSelection(screen, PRIMARY_NAME), 5700f2e35a3aSmrg &(screen->startSel), &(screen->endSel)); 57010bd37d32Smrg 5702f2e35a3aSmrg if (scp->data_limit && scp->data_buffer) { 5703f2e35a3aSmrg TRACE(("...getDataFromScreen selection-data %.*s\n", 5704f2e35a3aSmrg (int) scp->data_limit, 5705f2e35a3aSmrg scp->data_buffer)); 5706f2e35a3aSmrg result = malloc(scp->data_limit + 1); 57070bd37d32Smrg if (result) { 5708f2e35a3aSmrg memcpy(result, scp->data_buffer, scp->data_limit); 5709f2e35a3aSmrg result[scp->data_limit] = 0; 57100bd37d32Smrg } 5711f2e35a3aSmrg free(scp->data_buffer); 5712f2e35a3aSmrg scp->data_limit = 0; 57130bd37d32Smrg } 57140bd37d32Smrg 57150bd37d32Smrg TRACE(("...getDataFromScreen restoring previous selection\n")); 57160bd37d32Smrg 57170bd37d32Smrg screen->startSel = save_startSel; 57180bd37d32Smrg screen->startRaw = save_startRaw; 57190bd37d32Smrg screen->endSel = save_finishSel; 57200bd37d32Smrg screen->endRaw = save_finishRaw; 57210bd37d32Smrg 57220bd37d32Smrg screen->firstValidRow = save_firstValidRow; 57230bd37d32Smrg screen->lastValidRow = save_lastValidRow; 57240bd37d32Smrg 572501037d57Smrg screen->numberOfClicks = save_numberOfClicks; 57260bd37d32Smrg screen->selectUnit = saveUnits; 572701037d57Smrg screen->selectMap[noClick] = saveMap; 57280bd37d32Smrg#if OPT_SELECT_REGEX 572901037d57Smrg screen->selectExpr[noClick] = saveExpr; 57300bd37d32Smrg#endif 57310bd37d32Smrg 5732f2e35a3aSmrg screen->selected_cells[0] = save_selection; 57330bd37d32Smrg 57340bd37d32Smrg TrackText(xw, &save_old_start, &save_old_end); 57350bd37d32Smrg 57360bd37d32Smrg TRACE(("...getDataFromScreen done\n")); 57370bd37d32Smrg return result; 57380bd37d32Smrg} 57390bd37d32Smrg 57405307cd1aSmrg#if OPT_EXEC_SELECTION 57410bd37d32Smrg/* 57420bd37d32Smrg * Split-up the format before substituting data, to avoid quoting issues. 57430bd37d32Smrg * The resource mechanism has a limited ability to handle escapes. We take 57440bd37d32Smrg * the result as if it were an sh-type string and parse it into a regular 57450bd37d32Smrg * argv array. 57460bd37d32Smrg */ 57470bd37d32Smrgstatic char ** 57480bd37d32SmrgtokenizeFormat(String format) 57490bd37d32Smrg{ 57500bd37d32Smrg char **result = 0; 57510bd37d32Smrg 57520bd37d32Smrg format = x_skip_blanks(format); 57530bd37d32Smrg if (*format != '\0') { 57540bd37d32Smrg char *blob = x_strdup(format); 57552e4f8982Smrg int pass; 57560bd37d32Smrg 57570bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 57580bd37d32Smrg int used = 0; 57590bd37d32Smrg int first = 1; 57600bd37d32Smrg int escaped = 0; 57610bd37d32Smrg int squoted = 0; 57620bd37d32Smrg int dquoted = 0; 57632e4f8982Smrg int n; 5764f2e35a3aSmrg int argc = 0; 57650bd37d32Smrg 57660bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 57670bd37d32Smrg if (escaped) { 57680bd37d32Smrg blob[used++] = format[n]; 57690bd37d32Smrg escaped = 0; 57700bd37d32Smrg } else if (format[n] == '"') { 57710bd37d32Smrg if (!squoted) { 57720bd37d32Smrg if (!dquoted) 57730bd37d32Smrg blob[used++] = format[n]; 57740bd37d32Smrg dquoted = !dquoted; 57750bd37d32Smrg } 57760bd37d32Smrg } else if (format[n] == '\'') { 57770bd37d32Smrg if (!dquoted) { 57780bd37d32Smrg if (!squoted) 57790bd37d32Smrg blob[used++] = format[n]; 57800bd37d32Smrg squoted = !squoted; 57810bd37d32Smrg } 57820bd37d32Smrg } else if (format[n] == '\\') { 57830bd37d32Smrg blob[used++] = format[n]; 57840bd37d32Smrg escaped = 1; 57850bd37d32Smrg } else { 57860bd37d32Smrg if (first) { 57870bd37d32Smrg first = 0; 57880bd37d32Smrg if (pass) { 57890bd37d32Smrg result[argc] = &blob[n]; 57900bd37d32Smrg } 57910bd37d32Smrg ++argc; 57920bd37d32Smrg } 57930bd37d32Smrg if (isspace((Char) format[n])) { 57940bd37d32Smrg first = !isspace((Char) format[n + 1]); 57950bd37d32Smrg if (squoted || dquoted) { 57960bd37d32Smrg blob[used++] = format[n]; 57970bd37d32Smrg } else if (first) { 57980bd37d32Smrg blob[used++] = '\0'; 57990bd37d32Smrg } 58000bd37d32Smrg } else { 58010bd37d32Smrg blob[used++] = format[n]; 58020bd37d32Smrg } 58030bd37d32Smrg } 58040bd37d32Smrg } 58050bd37d32Smrg blob[used] = '\0'; 58060bd37d32Smrg assert(strlen(blob) <= strlen(format)); 58070bd37d32Smrg if (!pass) { 58080bd37d32Smrg result = TypeCallocN(char *, argc + 1); 58090bd37d32Smrg if (result == 0) { 58100bd37d32Smrg free(blob); 58110bd37d32Smrg break; 58120bd37d32Smrg } 58130bd37d32Smrg } 58140bd37d32Smrg } 58150bd37d32Smrg } 58160bd37d32Smrg#if OPT_TRACE 58170bd37d32Smrg if (result) { 5818f2e35a3aSmrg int n; 58190bd37d32Smrg TRACE(("tokenizeFormat %s\n", format)); 5820f2e35a3aSmrg for (n = 0; result[n]; ++n) { 5821f2e35a3aSmrg TRACE(("argv[%d] = %s\n", n, result[n])); 58220bd37d32Smrg } 58230bd37d32Smrg } 58240bd37d32Smrg#endif 58250bd37d32Smrg 58260bd37d32Smrg return result; 58270bd37d32Smrg} 58285307cd1aSmrg#endif /* OPT_EXEC_SELECTION */ 58290bd37d32Smrg 58300bd37d32Smrgstatic void 5831e0a2b6dfSmrgformatVideoAttrs(XtermWidget xw, char *buffer, CELL *cell) 58320bd37d32Smrg{ 58330bd37d32Smrg TScreen *screen = TScreenOf(xw); 58340bd37d32Smrg LineData *ld = GET_LINEDATA(screen, cell->row); 58350bd37d32Smrg 58360bd37d32Smrg *buffer = '\0'; 58370bd37d32Smrg if (ld != 0 && cell->col < (int) ld->lineSize) { 5838894e0ac8Smrg IAttr attribs = ld->attribs[cell->col]; 58390bd37d32Smrg const char *delim = ""; 58400bd37d32Smrg 58410bd37d32Smrg if (attribs & INVERSE) { 58420bd37d32Smrg buffer += sprintf(buffer, "7"); 58430bd37d32Smrg delim = ";"; 58440bd37d32Smrg } 58450bd37d32Smrg if (attribs & UNDERLINE) { 58460bd37d32Smrg buffer += sprintf(buffer, "%s4", delim); 58470bd37d32Smrg delim = ";"; 58480bd37d32Smrg } 58490bd37d32Smrg if (attribs & BOLD) { 58500bd37d32Smrg buffer += sprintf(buffer, "%s1", delim); 58510bd37d32Smrg delim = ";"; 58520bd37d32Smrg } 58530bd37d32Smrg if (attribs & BLINK) { 58540bd37d32Smrg buffer += sprintf(buffer, "%s5", delim); 58550bd37d32Smrg delim = ";"; 58560bd37d32Smrg } 58570bd37d32Smrg#if OPT_ISO_COLORS 58580bd37d32Smrg if (attribs & FG_COLOR) { 5859f2e35a3aSmrg Pixel fg = extract_fg(xw, ld->color[cell->col], attribs); 58600bd37d32Smrg if (fg < 8) { 58610bd37d32Smrg fg += 30; 58620bd37d32Smrg } else if (fg < 16) { 58630bd37d32Smrg fg += 90; 58640bd37d32Smrg } else { 58650bd37d32Smrg buffer += sprintf(buffer, "%s38;5", delim); 58660bd37d32Smrg delim = ";"; 58670bd37d32Smrg } 5868f2e35a3aSmrg buffer += sprintf(buffer, "%s%lu", delim, fg); 58690bd37d32Smrg delim = ";"; 58700bd37d32Smrg } 58710bd37d32Smrg if (attribs & BG_COLOR) { 5872f2e35a3aSmrg Pixel bg = extract_bg(xw, ld->color[cell->col], attribs); 58730bd37d32Smrg if (bg < 8) { 58740bd37d32Smrg bg += 40; 58750bd37d32Smrg } else if (bg < 16) { 58760bd37d32Smrg bg += 100; 58770bd37d32Smrg } else { 58780bd37d32Smrg buffer += sprintf(buffer, "%s48;5", delim); 58790bd37d32Smrg delim = ";"; 58800bd37d32Smrg } 5881f2e35a3aSmrg (void) sprintf(buffer, "%s%lu", delim, bg); 58820bd37d32Smrg } 58830bd37d32Smrg#endif 58840bd37d32Smrg } 58850bd37d32Smrg} 58860bd37d32Smrg 58872e4f8982Smrgstatic char * 58882e4f8982SmrgformatStrlen(char *target, char *source, int freeit) 58892e4f8982Smrg{ 58902e4f8982Smrg if (source != 0) { 58912e4f8982Smrg sprintf(target, "%u", (unsigned) strlen(source)); 58922e4f8982Smrg if (freeit) { 58932e4f8982Smrg free(source); 58942e4f8982Smrg } 58952e4f8982Smrg } else { 58962e4f8982Smrg strcpy(target, "0"); 58972e4f8982Smrg } 58982e4f8982Smrg return target; 58992e4f8982Smrg} 59002e4f8982Smrg 59010bd37d32Smrg/* substitute data into format, reallocating the result */ 59020bd37d32Smrgstatic char * 59030bd37d32SmrgexpandFormat(XtermWidget xw, 59040bd37d32Smrg const char *format, 59050bd37d32Smrg char *data, 5906e0a2b6dfSmrg CELL *start, 5907e0a2b6dfSmrg CELL *finish) 59080bd37d32Smrg{ 59090bd37d32Smrg char *result = 0; 59100bd37d32Smrg if (!IsEmpty(format)) { 59110bd37d32Smrg static char empty[1]; 59120bd37d32Smrg int pass; 59130bd37d32Smrg int n; 59140bd37d32Smrg char numbers[80]; 59150bd37d32Smrg 59160bd37d32Smrg if (data == 0) 59170bd37d32Smrg data = empty; 59180bd37d32Smrg 59190bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 59200bd37d32Smrg size_t need = 0; 59210bd37d32Smrg 59220bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 59230bd37d32Smrg 59240bd37d32Smrg if (format[n] == '%') { 59252e4f8982Smrg char *value = 0; 59262e4f8982Smrg 59270bd37d32Smrg switch (format[++n]) { 59280bd37d32Smrg case '%': 59290bd37d32Smrg if (pass) { 59300bd37d32Smrg result[need] = format[n]; 59310bd37d32Smrg } 59320bd37d32Smrg ++need; 59330bd37d32Smrg break; 59340bd37d32Smrg case 'P': 59350bd37d32Smrg sprintf(numbers, "%d;%d", 59360bd37d32Smrg TScreenOf(xw)->topline + start->row + 1, 59370bd37d32Smrg start->col + 1); 59380bd37d32Smrg value = numbers; 59390bd37d32Smrg break; 59400bd37d32Smrg case 'p': 59410bd37d32Smrg sprintf(numbers, "%d;%d", 59420bd37d32Smrg TScreenOf(xw)->topline + finish->row + 1, 59430bd37d32Smrg finish->col + 1); 59440bd37d32Smrg value = numbers; 59450bd37d32Smrg break; 59462e4f8982Smrg case 'R': 59472e4f8982Smrg value = formatStrlen(numbers, x_strrtrim(data), 1); 59482e4f8982Smrg break; 59492e4f8982Smrg case 'r': 59502e4f8982Smrg value = x_strrtrim(data); 59512e4f8982Smrg break; 59520bd37d32Smrg case 'S': 59532e4f8982Smrg value = formatStrlen(numbers, data, 0); 59540bd37d32Smrg break; 59550bd37d32Smrg case 's': 59560bd37d32Smrg value = data; 59570bd37d32Smrg break; 59580bd37d32Smrg case 'T': 59592e4f8982Smrg value = formatStrlen(numbers, x_strtrim(data), 1); 59600bd37d32Smrg break; 59610bd37d32Smrg case 't': 59620bd37d32Smrg value = x_strtrim(data); 59630bd37d32Smrg break; 59640bd37d32Smrg case 'V': 59650bd37d32Smrg formatVideoAttrs(xw, numbers, start); 59660bd37d32Smrg value = numbers; 59670bd37d32Smrg break; 59680bd37d32Smrg case 'v': 59690bd37d32Smrg formatVideoAttrs(xw, numbers, finish); 59700bd37d32Smrg value = numbers; 59710bd37d32Smrg break; 59720bd37d32Smrg default: 59730bd37d32Smrg if (pass) { 59740bd37d32Smrg result[need] = format[n]; 59750bd37d32Smrg } 59760bd37d32Smrg --n; 59770bd37d32Smrg ++need; 59780bd37d32Smrg break; 59790bd37d32Smrg } 59800bd37d32Smrg if (value != 0) { 59810bd37d32Smrg if (pass) { 59820bd37d32Smrg strcpy(result + need, value); 59830bd37d32Smrg } 59840bd37d32Smrg need += strlen(value); 59850bd37d32Smrg if (value != numbers && value != data) { 59860bd37d32Smrg free(value); 59870bd37d32Smrg } 59880bd37d32Smrg } 59890bd37d32Smrg } else { 59900bd37d32Smrg if (pass) { 59910bd37d32Smrg result[need] = format[n]; 59920bd37d32Smrg } 59930bd37d32Smrg ++need; 59940bd37d32Smrg } 59950bd37d32Smrg } 59960bd37d32Smrg if (pass) { 59970bd37d32Smrg result[need] = '\0'; 59980bd37d32Smrg } else { 59990bd37d32Smrg ++need; 60000bd37d32Smrg result = malloc(need); 60010bd37d32Smrg if (result == 0) { 60020bd37d32Smrg break; 60030bd37d32Smrg } 60040bd37d32Smrg } 60050bd37d32Smrg } 60060bd37d32Smrg } 60070bd37d32Smrg TRACE(("expandFormat(%s) = %s\n", NonNull(format), NonNull(result))); 60080bd37d32Smrg return result; 60090bd37d32Smrg} 60100bd37d32Smrg 60115307cd1aSmrg#if OPT_EXEC_SELECTION 60120bd37d32Smrg/* execute the command after forking. The main process frees its data */ 60130bd37d32Smrgstatic void 60142e4f8982SmrgexecuteCommand(pid_t pid, char **argv) 60150bd37d32Smrg{ 60162e4f8982Smrg (void) pid; 60170bd37d32Smrg if (argv != 0 && argv[0] != 0) { 60182e4f8982Smrg char *child_cwd = ProcGetCWD(pid); 60192e4f8982Smrg 60200bd37d32Smrg if (fork() == 0) { 60212e4f8982Smrg if (child_cwd) { 60222e4f8982Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 60232e4f8982Smrg } 60240bd37d32Smrg execvp(argv[0], argv); 60250bd37d32Smrg exit(EXIT_FAILURE); 60260bd37d32Smrg } 6027913cc679Smrg free(child_cwd); 60280bd37d32Smrg } 60290bd37d32Smrg} 60300bd37d32Smrg 60310bd37d32Smrgstatic void 60320bd37d32SmrgfreeArgv(char *blob, char **argv) 60330bd37d32Smrg{ 60340bd37d32Smrg if (blob) { 60350bd37d32Smrg free(blob); 60360bd37d32Smrg if (argv) { 60372e4f8982Smrg int n; 60380bd37d32Smrg for (n = 0; argv[n]; ++n) 60390bd37d32Smrg free(argv[n]); 60400bd37d32Smrg free(argv); 60410bd37d32Smrg } 60420bd37d32Smrg } 60430bd37d32Smrg} 60440bd37d32Smrg 604501037d57Smrgstatic void 604601037d57SmrgreallyExecFormatted(Widget w, char *format, char *data, CELL *start, CELL *finish) 604701037d57Smrg{ 604801037d57Smrg XtermWidget xw; 604901037d57Smrg 605001037d57Smrg if ((xw = getXtermWidget(w)) != 0) { 605101037d57Smrg char **argv; 605201037d57Smrg 605301037d57Smrg if ((argv = tokenizeFormat(format)) != 0) { 60542e4f8982Smrg char *blob = argv[0]; 60552e4f8982Smrg int argc; 60562e4f8982Smrg 605701037d57Smrg for (argc = 0; argv[argc] != 0; ++argc) { 605801037d57Smrg argv[argc] = expandFormat(xw, argv[argc], data, start, finish); 605901037d57Smrg } 60602e4f8982Smrg executeCommand(TScreenOf(xw)->pid, argv); 606101037d57Smrg freeArgv(blob, argv); 606201037d57Smrg } 606301037d57Smrg } 606401037d57Smrg} 606501037d57Smrg 60660bd37d32Smrgvoid 60670bd37d32SmrgHandleExecFormatted(Widget w, 606801037d57Smrg XEvent *event, 6069e0a2b6dfSmrg String *params, /* selections */ 60700bd37d32Smrg Cardinal *num_params) 60710bd37d32Smrg{ 60720bd37d32Smrg XtermWidget xw; 60730bd37d32Smrg 6074f2e35a3aSmrg TRACE_EVENT("HandleExecFormatted", event, params, num_params); 607501037d57Smrg if ((xw = getXtermWidget(w)) != 0 && 607601037d57Smrg (*num_params > 1)) { 607701037d57Smrg doSelectionFormat(xw, w, event, params, num_params, reallyExecFormatted); 60780bd37d32Smrg } 60790bd37d32Smrg} 60800bd37d32Smrg 60810bd37d32Smrgvoid 60820bd37d32SmrgHandleExecSelectable(Widget w, 6083913cc679Smrg XEvent *event, 6084e0a2b6dfSmrg String *params, /* selections */ 60850bd37d32Smrg Cardinal *num_params) 60860bd37d32Smrg{ 60870bd37d32Smrg XtermWidget xw; 60880bd37d32Smrg 60890bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 6090f2e35a3aSmrg TRACE_EVENT("HandleExecSelectable", event, params, num_params); 60910bd37d32Smrg 60920bd37d32Smrg if (*num_params == 2) { 60930bd37d32Smrg CELL start, finish; 60940bd37d32Smrg char *data; 60950bd37d32Smrg char **argv; 60960bd37d32Smrg 6097913cc679Smrg data = getDataFromScreen(xw, event, params[1], &start, &finish); 60980bd37d32Smrg if (data != 0) { 60990bd37d32Smrg if ((argv = tokenizeFormat(params[0])) != 0) { 61002e4f8982Smrg char *blob = argv[0]; 61012e4f8982Smrg int argc; 61022e4f8982Smrg 61030bd37d32Smrg for (argc = 0; argv[argc] != 0; ++argc) { 61040bd37d32Smrg argv[argc] = expandFormat(xw, argv[argc], data, 61050bd37d32Smrg &start, &finish); 61060bd37d32Smrg } 61072e4f8982Smrg executeCommand(TScreenOf(xw)->pid, argv); 61080bd37d32Smrg freeArgv(blob, argv); 61090bd37d32Smrg } 6110894e0ac8Smrg free(data); 61110bd37d32Smrg } 61120bd37d32Smrg } 61130bd37d32Smrg } 61140bd37d32Smrg} 61155307cd1aSmrg#endif /* OPT_EXEC_SELECTION */ 61160bd37d32Smrg 611701037d57Smrgstatic void 611801037d57SmrgreallyInsertFormatted(Widget w, char *format, char *data, CELL *start, CELL *finish) 611901037d57Smrg{ 612001037d57Smrg XtermWidget xw; 612101037d57Smrg 612201037d57Smrg if ((xw = getXtermWidget(w)) != 0) { 612301037d57Smrg char *exps; 612401037d57Smrg 612501037d57Smrg if ((exps = expandFormat(xw, format, data, start, finish)) != 0) { 612601037d57Smrg unparseputs(xw, exps); 612701037d57Smrg unparse_end(xw); 612801037d57Smrg free(exps); 612901037d57Smrg } 613001037d57Smrg } 613101037d57Smrg} 613201037d57Smrg 61330bd37d32Smrgvoid 61340bd37d32SmrgHandleInsertFormatted(Widget w, 613501037d57Smrg XEvent *event, 6136e0a2b6dfSmrg String *params, /* selections */ 61370bd37d32Smrg Cardinal *num_params) 61380bd37d32Smrg{ 61390bd37d32Smrg XtermWidget xw; 61400bd37d32Smrg 6141f2e35a3aSmrg TRACE_EVENT("HandleInsertFormatted", event, params, num_params); 614201037d57Smrg if ((xw = getXtermWidget(w)) != 0 && 614301037d57Smrg (*num_params > 1)) { 614401037d57Smrg doSelectionFormat(xw, w, event, params, num_params, reallyInsertFormatted); 61450bd37d32Smrg } 61460bd37d32Smrg} 61470bd37d32Smrg 61480bd37d32Smrgvoid 61490bd37d32SmrgHandleInsertSelectable(Widget w, 6150913cc679Smrg XEvent *event, 6151e0a2b6dfSmrg String *params, /* selections */ 61520bd37d32Smrg Cardinal *num_params) 61530bd37d32Smrg{ 61540bd37d32Smrg XtermWidget xw; 61550bd37d32Smrg 61560bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 6157f2e35a3aSmrg TRACE_EVENT("HandleInsertSelectable", event, params, num_params); 61580bd37d32Smrg 61590bd37d32Smrg if (*num_params == 2) { 61600bd37d32Smrg CELL start, finish; 61610bd37d32Smrg char *data; 61620bd37d32Smrg char *temp = x_strdup(params[0]); 61630bd37d32Smrg 6164913cc679Smrg data = getDataFromScreen(xw, event, params[1], &start, &finish); 61650bd37d32Smrg if (data != 0) { 61662e4f8982Smrg char *exps = expandFormat(xw, temp, data, &start, &finish); 61670bd37d32Smrg if (exps != 0) { 61680bd37d32Smrg unparseputs(xw, exps); 616901037d57Smrg unparse_end(xw); 61700bd37d32Smrg free(exps); 61710bd37d32Smrg } 61720bd37d32Smrg free(data); 61730bd37d32Smrg } 61740bd37d32Smrg free(temp); 61750bd37d32Smrg } 61760bd37d32Smrg } 61770bd37d32Smrg} 61780bd37d32Smrg#endif /* OPT_SELECTION_OPS */ 6179