button.c revision 4419d26b
14419d26bSmrg/* $XTermId: button.c,v 1.638 2021/11/26 01:27:25 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4f2e35a3aSmrg * Copyright 1999-2020,2021 by Thomas E. Dickey 5d522f475Smrg * 6d522f475Smrg * All Rights Reserved 7d522f475Smrg * 8d522f475Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9d522f475Smrg * copy of this software and associated documentation files (the 10d522f475Smrg * "Software"), to deal in the Software without restriction, including 11d522f475Smrg * without limitation the rights to use, copy, modify, merge, publish, 12d522f475Smrg * distribute, sublicense, and/or sell copies of the Software, and to 13d522f475Smrg * permit persons to whom the Software is furnished to do so, subject to 14d522f475Smrg * the following conditions: 15d522f475Smrg * 16d522f475Smrg * The above copyright notice and this permission notice shall be included 17d522f475Smrg * in all copies or substantial portions of the Software. 18d522f475Smrg * 19d522f475Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20d522f475Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21d522f475Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22d522f475Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23d522f475Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24d522f475Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25d522f475Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26d522f475Smrg * 27d522f475Smrg * Except as contained in this notice, the name(s) of the above copyright 28d522f475Smrg * holders shall not be used in advertising or otherwise to promote the 29d522f475Smrg * sale, use or other dealings in this Software without prior written 30d522f475Smrg * authorization. 31d522f475Smrg * 32d522f475Smrg * 33d522f475Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 34d522f475Smrg * 35d522f475Smrg * All Rights Reserved 36d522f475Smrg * 37d522f475Smrg * Permission to use, copy, modify, and distribute this software and its 38d522f475Smrg * documentation for any purpose and without fee is hereby granted, 39d522f475Smrg * provided that the above copyright notice appear in all copies and that 40d522f475Smrg * both that copyright notice and this permission notice appear in 41d522f475Smrg * supporting documentation, and that the name of Digital Equipment 42d522f475Smrg * Corporation not be used in advertising or publicity pertaining to 43d522f475Smrg * distribution of the software without specific, written prior permission. 44d522f475Smrg * 45d522f475Smrg * 46d522f475Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 47d522f475Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 48d522f475Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 49d522f475Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 50d522f475Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 51d522f475Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 52d522f475Smrg * SOFTWARE. 53d522f475Smrg */ 54d522f475Smrg 55d522f475Smrg/* 56d522f475Smrgbutton.c Handles button events in the terminal emulator. 57d522f475Smrg does cut/paste operations, change modes via menu, 58d522f475Smrg passes button events through to some applications. 59d522f475Smrg J. Gettys. 60d522f475Smrg*/ 61d522f475Smrg 62d522f475Smrg#include <xterm.h> 63d522f475Smrg 64d522f475Smrg#include <stdio.h> 650bd37d32Smrg#include <ctype.h> 6620d2c4d2Smrg#include <assert.h> 67d522f475Smrg 68d522f475Smrg#include <X11/Xatom.h> 69d522f475Smrg#include <X11/Xmu/Atoms.h> 70d522f475Smrg#include <X11/Xmu/StdSel.h> 71d522f475Smrg 72d522f475Smrg#include <xutf8.h> 73d522f475Smrg#include <fontutils.h> 74d522f475Smrg 75d522f475Smrg#include <data.h> 76d522f475Smrg#include <error.h> 77d522f475Smrg#include <menu.h> 78d522f475Smrg#include <charclass.h> 79d522f475Smrg#include <xstrings.h> 80d522f475Smrg 81d522f475Smrg#if OPT_SELECT_REGEX 82a5ae21e4Smrg#if defined(HAVE_PCRE2POSIX_H) 83f2e35a3aSmrg#include <pcre2posix.h> 84a5ae21e4Smrg 85a5ae21e4Smrg/* pcre2 used to provide its "POSIX" entrypoints using the same names as the 86a5ae21e4Smrg * standard ones in the C runtime, but that never worked because the linker 87a5ae21e4Smrg * would use the C runtime. Debian patched the library to fix this symbol 88a5ae21e4Smrg * conflict, but overlooked the header file, and Debian's patch was made 89a5ae21e4Smrg * obsolete when pcre2 was changed early in 2019 to provide different names. 90a5ae21e4Smrg * 91a5ae21e4Smrg * Here is a workaround to make the older version of Debian's package work. 92a5ae21e4Smrg */ 93a5ae21e4Smrg#if !defined(PCRE2regcomp) && defined(HAVE_PCRE2REGCOMP) 94a5ae21e4Smrg 95a5ae21e4Smrg#undef regcomp 96a5ae21e4Smrg#undef regexec 97a5ae21e4Smrg#undef regfree 98a5ae21e4Smrg 99a5ae21e4Smrg#ifdef __cplusplus 100a5ae21e4Smrgextern "C" { 101a5ae21e4Smrg#endif 102a5ae21e4Smrg PCRE2POSIX_EXP_DECL int PCRE2regcomp(regex_t *, const char *, int); 103a5ae21e4Smrg PCRE2POSIX_EXP_DECL int PCRE2regexec(const regex_t *, const char *, size_t, 104a5ae21e4Smrg regmatch_t *, int); 105a5ae21e4Smrg PCRE2POSIX_EXP_DECL void PCRE2regfree(regex_t *); 106a5ae21e4Smrg#ifdef __cplusplus 107a5ae21e4Smrg} /* extern "C" */ 108a5ae21e4Smrg#endif 109a5ae21e4Smrg#define regcomp(r,s,n) PCRE2regcomp(r,s,n) 110a5ae21e4Smrg#define regexec(r,s,n,m,x) PCRE2regexec(r,s,n,m,x) 111a5ae21e4Smrg#define regfree(r) PCRE2regfree(r) 112a5ae21e4Smrg#endif 113a5ae21e4Smrg/* end workaround... */ 114a5ae21e4Smrg#elif defined(HAVE_PCREPOSIX_H) 115d522f475Smrg#include <pcreposix.h> 116d522f475Smrg#else /* POSIX regex.h */ 117d522f475Smrg#include <sys/types.h> 118d522f475Smrg#include <regex.h> 119d522f475Smrg#endif 120a5ae21e4Smrg#endif /* OPT_SELECT_REGEX */ 121f2e35a3aSmrg 122f2e35a3aSmrg#ifdef HAVE_X11_TRANSLATEI_H 123f2e35a3aSmrg#include <X11/ConvertI.h> 124f2e35a3aSmrg#include <X11/TranslateI.h> 125f2e35a3aSmrg#else 126f2e35a3aSmrgextern String _XtPrintXlations(Widget w, 127f2e35a3aSmrg XtTranslations xlations, 128f2e35a3aSmrg Widget accelWidget, 129f2e35a3aSmrg _XtBoolean includeRHS); 130f2e35a3aSmrg#endif 131f2e35a3aSmrg 132f2e35a3aSmrg#define PRIMARY_NAME "PRIMARY" 133f2e35a3aSmrg#define CLIPBOARD_NAME "CLIPBOARD" 134f2e35a3aSmrg#define SECONDARY_NAME "SECONDARY" 135f2e35a3aSmrg 136f2e35a3aSmrg#define AtomToSelection(d,n) \ 137f2e35a3aSmrg (((n) == XA_CLIPBOARD(d)) \ 138f2e35a3aSmrg ? CLIPBOARD_CODE \ 139f2e35a3aSmrg : (((n) == XA_SECONDARY) \ 140f2e35a3aSmrg ? SECONDARY_CODE \ 141f2e35a3aSmrg : PRIMARY_CODE)) 142f2e35a3aSmrg 143f2e35a3aSmrg#define isSelectionCode(n) ((n) >= PRIMARY_CODE) 144f2e35a3aSmrg#define CutBufferToCode(n) ((n) + MAX_SELECTION_CODES) 145f2e35a3aSmrg#define okSelectionCode(n) (isSelectionCode(n) ? (n) : PRIMARY_CODE) 146d522f475Smrg 147d522f475Smrg#if OPT_WIDE_CHARS 148d522f475Smrg#include <ctype.h> 149d522f475Smrg#include <wcwidth.h> 150d522f475Smrg#else 151d522f475Smrg#define CharacterClass(value) \ 152f2e35a3aSmrg charClass[(value) & (int)((sizeof(charClass)/sizeof(charClass[0]))-1)] 153d522f475Smrg#endif 154d522f475Smrg 155956cc18dSsnj /* 156956cc18dSsnj * We'll generally map rows to indices when doing selection. 157956cc18dSsnj * Simplify that with a macro. 158956cc18dSsnj * 159956cc18dSsnj * Note that ROW2INX() is safe to use with auto increment/decrement for 160956cc18dSsnj * the row expression since that is evaluated once. 161956cc18dSsnj */ 162956cc18dSsnj#define GET_LINEDATA(screen, row) \ 163956cc18dSsnj getLineData(screen, ROW2INX(screen, row)) 164956cc18dSsnj 165f2e35a3aSmrg#define MaxMouseBtn 5 166492d43a5Smrg 167492d43a5Smrg#define IsBtnEvent(event) ((event)->type == ButtonPress || (event)->type == ButtonRelease) 1680bd37d32Smrg#define IsKeyEvent(event) ((event)->type == KeyPress || (event)->type == KeyRelease) 169d522f475Smrg 170d522f475Smrg#define Coordinate(s,c) ((c)->row * MaxCols(s) + (c)->col) 171d522f475Smrg 172d522f475Smrgstatic const CELL zeroCELL = 173d522f475Smrg{0, 0}; 174d522f475Smrg 175d522f475Smrg#if OPT_DEC_LOCATOR 176894e0ac8Smrgstatic Bool SendLocatorPosition(XtermWidget xw, XButtonEvent *event); 177894e0ac8Smrgstatic void CheckLocatorPosition(XtermWidget xw, XButtonEvent *event); 178d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 179d522f475Smrg 180d522f475Smrg/* Multi-click handling */ 181d522f475Smrg#if OPT_READLINE 182d522f475Smrgstatic Time lastButtonDownTime = 0; 183d522f475Smrgstatic int ExtendingSelection = 0; 184d522f475Smrgstatic Time lastButton3UpTime = 0; 185d522f475Smrgstatic Time lastButton3DoubleDownTime = 0; 186d522f475Smrgstatic CELL lastButton3; /* At the release time */ 187d522f475Smrg#endif /* OPT_READLINE */ 188d522f475Smrg 189e0a2b6dfSmrgstatic Char *SaveText(TScreen *screen, int row, int scol, int ecol, 190e0a2b6dfSmrg Char *lp, int *eol); 191e0a2b6dfSmrgstatic int Length(TScreen *screen, int row, int scol, int ecol); 192f2e35a3aSmrgstatic void ComputeSelect(XtermWidget xw, CELL *startc, CELL *endc, Bool 193f2e35a3aSmrg extend, Bool normal); 194894e0ac8Smrgstatic void EditorButton(XtermWidget xw, XButtonEvent *event); 195894e0ac8Smrgstatic void EndExtend(XtermWidget w, XEvent *event, String *params, Cardinal 196d522f475Smrg num_params, Bool use_cursor_loc); 197e0a2b6dfSmrgstatic void ExtendExtend(XtermWidget xw, const CELL *cell); 198e0a2b6dfSmrgstatic void PointToCELL(TScreen *screen, int y, int x, CELL *cell); 199e0a2b6dfSmrgstatic void ReHiliteText(XtermWidget xw, CELL *first, CELL *last); 200f2e35a3aSmrgstatic void SaltTextAway(XtermWidget xw, int which, CELL *cellc, CELL *cell); 201894e0ac8Smrgstatic void SelectSet(XtermWidget xw, XEvent *event, String *params, Cardinal num_params); 202d522f475Smrgstatic void SelectionReceived PROTO_XT_SEL_CB_ARGS; 203e0a2b6dfSmrgstatic void StartSelect(XtermWidget xw, const CELL *cell); 204894e0ac8Smrgstatic void TrackDown(XtermWidget xw, XButtonEvent *event); 205e0a2b6dfSmrgstatic void TrackText(XtermWidget xw, const CELL *first, const CELL *last); 206f2e35a3aSmrgstatic void UnHiliteText(XtermWidget xw); 207e0a2b6dfSmrgstatic void _OwnSelection(XtermWidget xw, String *selections, Cardinal count); 208894e0ac8Smrgstatic void do_select_end(XtermWidget xw, XEvent *event, String *params, 209d522f475Smrg Cardinal *num_params, Bool use_cursor_loc); 210d522f475Smrg 211492d43a5Smrg#define MOUSE_LIMIT (255 - 32) 212d522f475Smrg 213492d43a5Smrg/* Send SET_EXT_SIZE_MOUSE to enable offsets up to EXT_MOUSE_LIMIT */ 214492d43a5Smrg#define EXT_MOUSE_LIMIT (2047 - 32) 215492d43a5Smrg#define EXT_MOUSE_START (127 - 32) 216d522f475Smrg 2170bd37d32Smrgstatic int 218e0a2b6dfSmrgMouseLimit(TScreen *screen) 2190bd37d32Smrg{ 2200bd37d32Smrg int mouse_limit; 2210bd37d32Smrg 2220bd37d32Smrg switch (screen->extend_coords) { 2230bd37d32Smrg default: 2240bd37d32Smrg mouse_limit = MOUSE_LIMIT; 2250bd37d32Smrg break; 2260bd37d32Smrg case SET_EXT_MODE_MOUSE: 2270bd37d32Smrg mouse_limit = EXT_MOUSE_LIMIT; 2280bd37d32Smrg break; 2290bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 2300bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 231f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 2320bd37d32Smrg mouse_limit = -1; 2330bd37d32Smrg break; 2340bd37d32Smrg } 2350bd37d32Smrg return mouse_limit; 2360bd37d32Smrg} 2370bd37d32Smrg 238492d43a5Smrgstatic unsigned 239e0a2b6dfSmrgEmitMousePosition(TScreen *screen, Char line[], unsigned count, int value) 240492d43a5Smrg{ 2410bd37d32Smrg int mouse_limit = MouseLimit(screen); 242492d43a5Smrg 243492d43a5Smrg /* 244492d43a5Smrg * Add pointer position to key sequence 245492d43a5Smrg * 246492d43a5Smrg * In extended mode we encode large positions as two-byte UTF-8. 247492d43a5Smrg * 248492d43a5Smrg * NOTE: historically, it was possible to emit 256, which became 249492d43a5Smrg * zero by truncation to 8 bits. While this was arguably a bug, 250492d43a5Smrg * it's also somewhat useful as a past-end marker. We preserve 251492d43a5Smrg * this behavior for both normal and extended mouse modes. 252492d43a5Smrg */ 2530bd37d32Smrg switch (screen->extend_coords) { 2540bd37d32Smrg default: 2550bd37d32Smrg if (value == mouse_limit) { 2560bd37d32Smrg line[count++] = CharOf(0); 2570bd37d32Smrg } else { 2580bd37d32Smrg line[count++] = CharOf(' ' + value + 1); 2590bd37d32Smrg } 2600bd37d32Smrg break; 2610bd37d32Smrg case SET_EXT_MODE_MOUSE: 2620bd37d32Smrg if (value == mouse_limit) { 2630bd37d32Smrg line[count++] = CharOf(0); 2640bd37d32Smrg } else if (value < EXT_MOUSE_START) { 2650bd37d32Smrg line[count++] = CharOf(' ' + value + 1); 2660bd37d32Smrg } else { 2670bd37d32Smrg value += ' ' + 1; 2680bd37d32Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 2690bd37d32Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 2700bd37d32Smrg } 2710bd37d32Smrg break; 2720bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 2730bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 274f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 2750bd37d32Smrg count += (unsigned) sprintf((char *) line + count, "%d", value + 1); 2760bd37d32Smrg break; 2770bd37d32Smrg } 2780bd37d32Smrg return count; 2790bd37d32Smrg} 2800bd37d32Smrg 2810bd37d32Smrgstatic unsigned 282e0a2b6dfSmrgEmitMousePositionSeparator(TScreen *screen, Char line[], unsigned count) 2830bd37d32Smrg{ 2840bd37d32Smrg switch (screen->extend_coords) { 2850bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 2860bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 287f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 2880bd37d32Smrg line[count++] = ';'; 2890bd37d32Smrg break; 290d522f475Smrg } 291492d43a5Smrg return count; 292492d43a5Smrg} 293d522f475Smrg 294f2e35a3aSmrgenum { 295f2e35a3aSmrg scanMods, 296f2e35a3aSmrg scanKey, 297f2e35a3aSmrg scanColon, 298f2e35a3aSmrg scanFunc, 299f2e35a3aSmrg scanArgs 300f2e35a3aSmrg}; 301f2e35a3aSmrg 302f2e35a3aSmrg#if OPT_TRACE > 1 303f2e35a3aSmrgstatic const char * 304f2e35a3aSmrgvisibleScan(int mode) 305f2e35a3aSmrg{ 306f2e35a3aSmrg const char *result = "?"; 307f2e35a3aSmrg#define DATA(name) case name: result = #name; break 308f2e35a3aSmrg switch (mode) { 309f2e35a3aSmrg DATA(scanMods); 310f2e35a3aSmrg DATA(scanKey); 311f2e35a3aSmrg DATA(scanColon); 312f2e35a3aSmrg DATA(scanFunc); 313f2e35a3aSmrg DATA(scanArgs); 314f2e35a3aSmrg } 315f2e35a3aSmrg#undef DATA 316f2e35a3aSmrg return result; 317f2e35a3aSmrg} 318f2e35a3aSmrg#endif 319f2e35a3aSmrg 320f2e35a3aSmrg#define L_BRACK '<' 321f2e35a3aSmrg#define R_BRACK '>' 322f2e35a3aSmrg#define L_PAREN '(' 323f2e35a3aSmrg#define R_PAREN ')' 324f2e35a3aSmrg 325f2e35a3aSmrgstatic char * 326f2e35a3aSmrgscanTrans(char *source, int *this_is, int *next_is, unsigned *first, unsigned *last) 327f2e35a3aSmrg{ 328f2e35a3aSmrg char *target = source; 329f2e35a3aSmrg 330f2e35a3aSmrg *first = *last = 0; 331f2e35a3aSmrg if (IsEmpty(target)) { 332f2e35a3aSmrg target = 0; 333f2e35a3aSmrg } else { 334f2e35a3aSmrg do { 3354419d26bSmrg char ch; 336f2e35a3aSmrg while (IsSpace(*target)) 337f2e35a3aSmrg target++; 338f2e35a3aSmrg *first = (unsigned) (target - source); 339f2e35a3aSmrg switch (*this_is = *next_is) { 340f2e35a3aSmrg case scanMods: 341f2e35a3aSmrg while ((ch = *target)) { 342f2e35a3aSmrg if (IsSpace(ch)) { 343f2e35a3aSmrg break; 344f2e35a3aSmrg } else if (ch == L_BRACK) { 345f2e35a3aSmrg *next_is = scanKey; 346f2e35a3aSmrg break; 347f2e35a3aSmrg } else if (ch == ':') { 348f2e35a3aSmrg *next_is = scanColon; 349f2e35a3aSmrg break; 350f2e35a3aSmrg } else if (ch == '~' && target != source) { 351f2e35a3aSmrg break; 352f2e35a3aSmrg } 353f2e35a3aSmrg target++; 354f2e35a3aSmrg } 355f2e35a3aSmrg break; 356f2e35a3aSmrg case scanKey: 357f2e35a3aSmrg while ((ch = *target)) { 358f2e35a3aSmrg if (IsSpace(ch)) { 359f2e35a3aSmrg break; 360f2e35a3aSmrg } else if (ch == ':') { 361f2e35a3aSmrg *next_is = scanColon; 362f2e35a3aSmrg break; 363f2e35a3aSmrg } 364f2e35a3aSmrg target++; 365f2e35a3aSmrg if (ch == R_BRACK) 366f2e35a3aSmrg break; 367f2e35a3aSmrg } 368f2e35a3aSmrg break; 369f2e35a3aSmrg case scanColon: 370f2e35a3aSmrg *next_is = scanFunc; 371f2e35a3aSmrg target++; 372f2e35a3aSmrg break; 373f2e35a3aSmrg case scanFunc: 374f2e35a3aSmrg while ((ch = *target)) { 375f2e35a3aSmrg if (IsSpace(ch)) { 376f2e35a3aSmrg break; 377f2e35a3aSmrg } else if (ch == L_PAREN) { 378f2e35a3aSmrg *next_is = scanArgs; 379f2e35a3aSmrg break; 380f2e35a3aSmrg } 381f2e35a3aSmrg target++; 382f2e35a3aSmrg } 383f2e35a3aSmrg break; 384f2e35a3aSmrg case scanArgs: 385f2e35a3aSmrg while ((ch = *target)) { 386f2e35a3aSmrg if (ch == R_PAREN) { 387f2e35a3aSmrg target++; 388f2e35a3aSmrg *next_is = scanFunc; 389f2e35a3aSmrg break; 390f2e35a3aSmrg } 391f2e35a3aSmrg target++; 392f2e35a3aSmrg } 393f2e35a3aSmrg break; 394f2e35a3aSmrg } 395f2e35a3aSmrg *last = (unsigned) (target - source); 396f2e35a3aSmrg if (*target == '\n') { 397f2e35a3aSmrg *next_is = scanMods; 398f2e35a3aSmrg target++; 399f2e35a3aSmrg } 400f2e35a3aSmrg } while (*first == *last); 401f2e35a3aSmrg } 402f2e35a3aSmrg return target; 403f2e35a3aSmrg} 404f2e35a3aSmrg 405f2e35a3aSmrgvoid 406f2e35a3aSmrgxtermButtonInit(XtermWidget xw) 407f2e35a3aSmrg{ 408f2e35a3aSmrg Widget w = (Widget) xw; 409f2e35a3aSmrg XErrorHandler save = XSetErrorHandler(ignore_x11_error); 410f2e35a3aSmrg XtTranslations xlations; 411f2e35a3aSmrg Widget xcelerat; 412f2e35a3aSmrg String result; 413f2e35a3aSmrg 414f2e35a3aSmrg XtVaGetValues(w, 415f2e35a3aSmrg XtNtranslations, &xlations, 416f2e35a3aSmrg XtNaccelerators, &xcelerat, 417f2e35a3aSmrg (XtPointer) 0); 418f2e35a3aSmrg result = _XtPrintXlations(w, xlations, xcelerat, True); 419f2e35a3aSmrg if (result) { 420f2e35a3aSmrg static const char *table[] = 421f2e35a3aSmrg { 422f2e35a3aSmrg "insert-selection", 423f2e35a3aSmrg "select-end", 424f2e35a3aSmrg "select-extend", 425f2e35a3aSmrg "select-start", 426f2e35a3aSmrg "start-extend", 427f2e35a3aSmrg }; 428f2e35a3aSmrg char *data = x_strdup(result); 429f2e35a3aSmrg char *next; 430f2e35a3aSmrg int state = scanMods; 431f2e35a3aSmrg int state2 = scanMods; 432f2e35a3aSmrg unsigned first; 433f2e35a3aSmrg unsigned last; 434f2e35a3aSmrg int have_button = -1; 435f2e35a3aSmrg Bool want_button = False; 436f2e35a3aSmrg Bool have_shift = False; 437f2e35a3aSmrg unsigned allowed = 0; 438f2e35a3aSmrg unsigned disallow = 0; 439f2e35a3aSmrg 440f2e35a3aSmrg TRACE(("xtermButtonInit length %ld\n", (long) strlen(result))); 441f2e35a3aSmrg xw->keyboard.print_translations = data; 442f2e35a3aSmrg while ((next = scanTrans(data, &state, &state2, &first, &last)) != 0) { 443f2e35a3aSmrg unsigned len = (last - first); 444f2e35a3aSmrg TRACE2(("parse %s:%d..%d '%.*s'\n", 445f2e35a3aSmrg visibleScan(state), first, last, 446f2e35a3aSmrg len, data + first)); 447f2e35a3aSmrg if (state == scanMods) { 448f2e35a3aSmrg if (len > 1 && data[first] == '~') { 449f2e35a3aSmrg len--; 450f2e35a3aSmrg first++; 451f2e35a3aSmrg } 452f2e35a3aSmrg if (len == 7 && !x_strncasecmp(data + first, "button", len - 1)) { 453f2e35a3aSmrg have_button = data[first + 6] - '0'; 454f2e35a3aSmrg } else if (len == 5 && !x_strncasecmp(data + first, "shift", len)) { 455f2e35a3aSmrg have_shift = True; 456f2e35a3aSmrg } 457f2e35a3aSmrg } else if (state == scanKey) { 458f2e35a3aSmrg if (!x_strncasecmp(data + first, "<buttonpress>", len) || 459f2e35a3aSmrg !x_strncasecmp(data + first, "<buttonrelease>", len)) { 460f2e35a3aSmrg want_button = True; 461f2e35a3aSmrg } else if (want_button) { 462f2e35a3aSmrg have_button = data[first] - '0'; 463f2e35a3aSmrg want_button = False; 464f2e35a3aSmrg } 465f2e35a3aSmrg } else if (state == scanFunc && have_button > 0) { 466f2e35a3aSmrg Cardinal n; 467f2e35a3aSmrg unsigned bmask = 1U << (have_button - 1); 468f2e35a3aSmrg for (n = 0; n < XtNumber(table); ++n) { 469f2e35a3aSmrg if (!x_strncasecmp(table[n], data + first, len)) { 470f2e35a3aSmrg TRACE(("...button %d: %s%s\n", 471f2e35a3aSmrg have_button, table[n], 472f2e35a3aSmrg have_shift ? " (disallow)" : "")); 473f2e35a3aSmrg if (have_shift) 474f2e35a3aSmrg disallow |= bmask; 475f2e35a3aSmrg else 476f2e35a3aSmrg allowed |= bmask; 477f2e35a3aSmrg break; 478f2e35a3aSmrg } 479f2e35a3aSmrg } 480f2e35a3aSmrg } 481f2e35a3aSmrg if (state2 == scanMods && state >= scanColon) { 482f2e35a3aSmrg have_button = -1; 483f2e35a3aSmrg want_button = False; 484f2e35a3aSmrg have_shift = False; 485f2e35a3aSmrg } 486f2e35a3aSmrg state = state2; 487f2e35a3aSmrg data = next; 488f2e35a3aSmrg } 489f2e35a3aSmrg XFree((char *) result); 490f2e35a3aSmrg xw->keyboard.shift_buttons = allowed & ~disallow; 491f2e35a3aSmrg#if OPT_TRACE 492f2e35a3aSmrg if (xw->keyboard.shift_buttons) { 493f2e35a3aSmrg int button = 0; 494f2e35a3aSmrg unsigned mask = xw->keyboard.shift_buttons; 495f2e35a3aSmrg TRACE(("...Buttons used for selection that can be overridden:")); 496f2e35a3aSmrg while (mask != 0) { 497f2e35a3aSmrg ++button; 498f2e35a3aSmrg if ((mask & 1) != 0) 499f2e35a3aSmrg TRACE((" %d", button)); 500f2e35a3aSmrg mask >>= 1; 501f2e35a3aSmrg } 502f2e35a3aSmrg TRACE(("\n")); 503f2e35a3aSmrg } else { 504f2e35a3aSmrg TRACE(("...No buttons used with selection can be overridden\n")); 505f2e35a3aSmrg } 506f2e35a3aSmrg#endif 507f2e35a3aSmrg } 508f2e35a3aSmrg XSetErrorHandler(save); 509f2e35a3aSmrg} 510f2e35a3aSmrg 511f2e35a3aSmrg/* 512f2e35a3aSmrg * Shift and control are regular X11 modifiers, but meta is not: 513f2e35a3aSmrg * + X10 (which had no xmodmap utility) had a meta mask, but X11 did not. 514f2e35a3aSmrg * + X11R1 introduced xmodmap, along with the current set of modifier masks. 515f2e35a3aSmrg * The meta key has been assumed to be mod1 since X11R1. 516f2e35a3aSmrg * The initial xterm logic in X11 was different, but gave the same result. 517f2e35a3aSmrg * + X11R2 modified xterm was to eliminate the X10 table which provided part of 518f2e35a3aSmrg * the meta logic. 519f2e35a3aSmrg * + X11R3 modified Xt, making Meta_L and Meta_R assignable via xmodmap, and 520f2e35a3aSmrg * equating Alt with Meta. Neither Alt/Meta are modifiers, but Alt is more 521f2e35a3aSmrg * likely to be on the keyboard. This release also added keymap tables for 522f2e35a3aSmrg * the server; Meta was used frequently in HP keymaps, which were the most 523f2e35a3aSmrg * extensive set of keymaps. 524f2e35a3aSmrg * + X11R4 mentions Meta in the ICCCM, stating that if Meta_L or Meta_R are 525f2e35a3aSmrg * found in the keysyms for a given modifier, that the client should use 526f2e35a3aSmrg * that modifier. 527f2e35a3aSmrg * 528f2e35a3aSmrg * This function follows the ICCCM, picking the modifier which contains the 529f2e35a3aSmrg * Meta_L/Meta_R keysyms (if available), falling back to the Alt_L/Alt_R 530f2e35a3aSmrg * (as per X11R3), and ultimately to mod1 (per X11R1). 531f2e35a3aSmrg */ 532f2e35a3aSmrgstatic unsigned 533f2e35a3aSmrgMetaMask(XtermWidget xw) 534f2e35a3aSmrg{ 535f2e35a3aSmrg#if OPT_NUM_LOCK 536f2e35a3aSmrg unsigned meta = xw->work.meta_mods; 537f2e35a3aSmrg if (meta == 0) 538f2e35a3aSmrg meta = xw->work.alt_mods; 539f2e35a3aSmrg if (meta == 0) 540f2e35a3aSmrg meta = Mod1Mask; 541f2e35a3aSmrg#else 542f2e35a3aSmrg unsigned meta = Mod1Mask; 543f2e35a3aSmrg (void) xw; 544f2e35a3aSmrg#endif 545f2e35a3aSmrg return meta; 546f2e35a3aSmrg} 547f2e35a3aSmrg 548f2e35a3aSmrg/* 549f2e35a3aSmrg * Returns a mask of the modifiers we may use for modifying the mouse protocol 550f2e35a3aSmrg * response strings. 551f2e35a3aSmrg */ 552f2e35a3aSmrgstatic unsigned 553f2e35a3aSmrgOurModifiers(XtermWidget xw) 554f2e35a3aSmrg{ 555f2e35a3aSmrg return (ShiftMask 556f2e35a3aSmrg | ControlMask 557f2e35a3aSmrg | MetaMask(xw)); 558f2e35a3aSmrg} 559f2e35a3aSmrg 560f2e35a3aSmrg/* 561f2e35a3aSmrg * The actual check for the shift-mask, to see if it should tell xterm to 562f2e35a3aSmrg * override mouse-protocol in favor of select/paste actions depends upon 563f2e35a3aSmrg * whether the shiftEscape resource is set to true/always vs false/never. 564f2e35a3aSmrg */ 565f2e35a3aSmrgstatic Boolean 566f2e35a3aSmrgShiftOverride(XtermWidget xw, unsigned state, int button) 567f2e35a3aSmrg{ 568f2e35a3aSmrg unsigned check = (state & OurModifiers(xw)); 569f2e35a3aSmrg Boolean result = False; 570f2e35a3aSmrg 571f2e35a3aSmrg if (check & ShiftMask) { 572f2e35a3aSmrg if (xw->keyboard.shift_escape == ssFalse || 573f2e35a3aSmrg xw->keyboard.shift_escape == ssNever) { 574f2e35a3aSmrg result = True; 575f2e35a3aSmrg } else if (xw->keyboard.shift_escape == ssTrue) { 576f2e35a3aSmrg /* 577f2e35a3aSmrg * Check if the button is one that we found does not directly use 578f2e35a3aSmrg * the shift-modifier in its bindings to select/copy actions. 579f2e35a3aSmrg */ 580f2e35a3aSmrg if (button > 0 && button <= MaxMouseBtn) { 581f2e35a3aSmrg if (xw->keyboard.shift_buttons & (1U << (button - 1))) { 582f2e35a3aSmrg result = True; 583f2e35a3aSmrg } 584f2e35a3aSmrg } else { 585f2e35a3aSmrg result = True; /* unlikely, and we don't care */ 586f2e35a3aSmrg } 587f2e35a3aSmrg } 588f2e35a3aSmrg } 589f2e35a3aSmrg TRACE2(("ShiftOverride ( %#x -> %#x ) %d\n", state, check, result)); 590f2e35a3aSmrg return result; 591f2e35a3aSmrg} 592f2e35a3aSmrg 593f2e35a3aSmrg/* 594f2e35a3aSmrg * Normally xterm treats the shift-modifier specially when the mouse protocol 595f2e35a3aSmrg * is active. The translations resource binds otherwise unmodified button 596f2e35a3aSmrg * for these mouse-related events: 597f2e35a3aSmrg * 598f2e35a3aSmrg * ~Meta <Btn1Down>:select-start() \n\ 599f2e35a3aSmrg * ~Meta <Btn1Motion>:select-extend() \n\ 600f2e35a3aSmrg * ~Ctrl ~Meta <Btn2Up>:insert-selection(SELECT, CUT_BUFFER0) \n\ 601f2e35a3aSmrg * ~Ctrl ~Meta <Btn3Down>:start-extend() \n\ 602f2e35a3aSmrg * ~Meta <Btn3Motion>:select-extend() \n\ 603f2e35a3aSmrg * <BtnUp>:select-end(SELECT, CUT_BUFFER0) \n\ 604f2e35a3aSmrg * 605f2e35a3aSmrg * There is no API in the X libraries which would tell us if a given mouse 606f2e35a3aSmrg * button is bound to one of these actions. These functions make the choice 607f2e35a3aSmrg * configurable. 608f2e35a3aSmrg */ 609f2e35a3aSmrgstatic Bool 610f2e35a3aSmrgInterpretButton(XtermWidget xw, XButtonEvent *event) 611f2e35a3aSmrg{ 612f2e35a3aSmrg Bool result = False; 613f2e35a3aSmrg 614f2e35a3aSmrg if (ShiftOverride(xw, event->state, (int) event->button)) { 615f2e35a3aSmrg TRACE(("...shift-button #%d overrides mouse-protocol\n", event->button)); 616f2e35a3aSmrg result = True; 617f2e35a3aSmrg } 618f2e35a3aSmrg return result; 619f2e35a3aSmrg} 620f2e35a3aSmrg 621f2e35a3aSmrg#define Button1Index 8 /* X.h should have done this */ 622f2e35a3aSmrg 623f2e35a3aSmrgstatic int 624f2e35a3aSmrgMotionButton(unsigned state) 625f2e35a3aSmrg{ 626f2e35a3aSmrg unsigned bmask = state >> Button1Index; 627f2e35a3aSmrg int result = 1; 628f2e35a3aSmrg 629f2e35a3aSmrg if (bmask != 0) { 630f2e35a3aSmrg while (!(bmask & 1)) { 631f2e35a3aSmrg ++result; 632f2e35a3aSmrg bmask >>= 1; 633f2e35a3aSmrg } 634f2e35a3aSmrg } 635f2e35a3aSmrg return result; 636f2e35a3aSmrg} 637f2e35a3aSmrg 638f2e35a3aSmrgstatic Bool 639f2e35a3aSmrgInterpretEvent(XtermWidget xw, XEvent *event) 640f2e35a3aSmrg{ 641f2e35a3aSmrg Bool result = False; /* if not a button, is motion */ 642f2e35a3aSmrg 643f2e35a3aSmrg if (IsBtnEvent(event)) { 644f2e35a3aSmrg result = InterpretButton(xw, (XButtonEvent *) event); 645f2e35a3aSmrg } else if (event->type == MotionNotify) { 646f2e35a3aSmrg unsigned state = event->xmotion.state; 647f2e35a3aSmrg int button = MotionButton(state); 648f2e35a3aSmrg 649f2e35a3aSmrg if (ShiftOverride(xw, state, button)) { 650f2e35a3aSmrg TRACE(("...shift-motion #%d (%d,%d) overrides mouse-protocol\n", 651f2e35a3aSmrg button, 652f2e35a3aSmrg event->xmotion.y, 653f2e35a3aSmrg event->xmotion.x)); 654f2e35a3aSmrg result = True; 655f2e35a3aSmrg } 656f2e35a3aSmrg } 657f2e35a3aSmrg return result; 658f2e35a3aSmrg} 659f2e35a3aSmrg 660f2e35a3aSmrg#define OverrideEvent(event) InterpretEvent(xw, event) 661f2e35a3aSmrg#define OverrideButton(event) InterpretButton(xw, event) 662f2e35a3aSmrg 663f2e35a3aSmrg/* 664f2e35a3aSmrg * Returns true if we handled the event here, and nothing more is needed. 665f2e35a3aSmrg */ 666492d43a5SmrgBool 667894e0ac8SmrgSendMousePosition(XtermWidget xw, XEvent *event) 668492d43a5Smrg{ 669492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 670492d43a5Smrg Bool result = False; 671d522f475Smrg 672913cc679Smrg switch (okSendMousePos(xw)) { 673492d43a5Smrg case MOUSE_OFF: 674492d43a5Smrg /* If send_mouse_pos mode isn't on, we shouldn't be here */ 675492d43a5Smrg break; 676d522f475Smrg 677d522f475Smrg case BTN_EVENT_MOUSE: 678d522f475Smrg case ANY_EVENT_MOUSE: 679f2e35a3aSmrg if (!OverrideEvent(event)) { 680492d43a5Smrg /* xterm extension for motion reporting. June 1998 */ 681492d43a5Smrg /* EditorButton() will distinguish between the modes */ 682492d43a5Smrg switch (event->type) { 683492d43a5Smrg case MotionNotify: 684492d43a5Smrg my_event->button = 0; 685492d43a5Smrg /* FALLTHRU */ 686492d43a5Smrg case ButtonPress: 687492d43a5Smrg /* FALLTHRU */ 688492d43a5Smrg case ButtonRelease: 689492d43a5Smrg EditorButton(xw, my_event); 690492d43a5Smrg result = True; 691492d43a5Smrg break; 6922eaa94a1Schristos } 693d522f475Smrg } 694492d43a5Smrg break; 695d522f475Smrg 696913cc679Smrg case X10_MOUSE: /* X10 compatibility sequences */ 697492d43a5Smrg if (IsBtnEvent(event)) { 698f2e35a3aSmrg if (!OverrideButton(my_event)) { 699913cc679Smrg if (my_event->type == ButtonPress) 700492d43a5Smrg EditorButton(xw, my_event); 701913cc679Smrg result = True; 702913cc679Smrg } 703913cc679Smrg } 704913cc679Smrg break; 705492d43a5Smrg 706913cc679Smrg case VT200_HIGHLIGHT_MOUSE: /* DEC vt200 hilite tracking */ 707913cc679Smrg if (IsBtnEvent(event)) { 708f2e35a3aSmrg if (!OverrideButton(my_event)) { 709f2e35a3aSmrg if (my_event->type == ButtonPress && 710f2e35a3aSmrg my_event->button == Button1) { 711f2e35a3aSmrg TrackDown(xw, my_event); 712f2e35a3aSmrg } else { 713f2e35a3aSmrg EditorButton(xw, my_event); 714f2e35a3aSmrg } 715913cc679Smrg result = True; 716913cc679Smrg } 717913cc679Smrg } 718913cc679Smrg break; 719492d43a5Smrg 720913cc679Smrg case VT200_MOUSE: /* DEC vt200 compatible */ 721913cc679Smrg if (IsBtnEvent(event)) { 722f2e35a3aSmrg if (!OverrideButton(my_event)) { 723913cc679Smrg EditorButton(xw, my_event); 724913cc679Smrg result = True; 725913cc679Smrg } 726913cc679Smrg } 727913cc679Smrg break; 728913cc679Smrg 729913cc679Smrg case DEC_LOCATOR: 730492d43a5Smrg#if OPT_DEC_LOCATOR 731f2e35a3aSmrg if (IsBtnEvent(event) || event->type == MotionNotify) { 732913cc679Smrg result = SendLocatorPosition(xw, my_event); 733492d43a5Smrg } 734f2e35a3aSmrg#endif /* OPT_DEC_LOCATOR */ 735913cc679Smrg break; 736d522f475Smrg } 737492d43a5Smrg return result; 738d522f475Smrg} 739d522f475Smrg 740d522f475Smrg#if OPT_DEC_LOCATOR 741d522f475Smrg 742d522f475Smrg#define LocatorCoords( row, col, x, y, oor ) \ 743d522f475Smrg if( screen->locator_pixels ) { \ 744d522f475Smrg (oor)=False; (row) = (y)+1; (col) = (x)+1; \ 745d522f475Smrg /* Limit to screen dimensions */ \ 746d522f475Smrg if ((row) < 1) (row) = 1,(oor)=True; \ 747d522f475Smrg else if ((row) > screen->border*2+Height(screen)) \ 748d522f475Smrg (row) = screen->border*2+Height(screen),(oor)=True; \ 749d522f475Smrg if ((col) < 1) (col) = 1,(oor)=True; \ 750d522f475Smrg else if ((col) > OriginX(screen)*2+Width(screen)) \ 751d522f475Smrg (col) = OriginX(screen)*2+Width(screen),(oor)=True; \ 752d522f475Smrg } else { \ 753d522f475Smrg (oor)=False; \ 754d522f475Smrg /* Compute character position of mouse pointer */ \ 755d522f475Smrg (row) = ((y) - screen->border) / FontHeight(screen); \ 756d522f475Smrg (col) = ((x) - OriginX(screen)) / FontWidth(screen); \ 757d522f475Smrg /* Limit to screen dimensions */ \ 758d522f475Smrg if ((row) < 0) (row) = 0,(oor)=True; \ 759d522f475Smrg else if ((row) > screen->max_row) \ 760d522f475Smrg (row) = screen->max_row,(oor)=True; \ 761d522f475Smrg if ((col) < 0) (col) = 0,(oor)=True; \ 762d522f475Smrg else if ((col) > screen->max_col) \ 763d522f475Smrg (col) = screen->max_col,(oor)=True; \ 764d522f475Smrg (row)++; (col)++; \ 765d522f475Smrg } 766d522f475Smrg 767d522f475Smrgstatic Bool 768894e0ac8SmrgSendLocatorPosition(XtermWidget xw, XButtonEvent *event) 769d522f475Smrg{ 770d522f475Smrg ANSI reply; 771956cc18dSsnj TScreen *screen = TScreenOf(xw); 772d522f475Smrg int row, col; 773d522f475Smrg Bool oor; 774d522f475Smrg int button; 7752eaa94a1Schristos unsigned state; 776d522f475Smrg 777d522f475Smrg /* Make sure the event is an appropriate type */ 778f2e35a3aSmrg if (IsBtnEvent(event)) { 779f2e35a3aSmrg if (OverrideButton(event)) 780f2e35a3aSmrg return (False); 781f2e35a3aSmrg } else { 782f2e35a3aSmrg if (!screen->loc_filter) 783f2e35a3aSmrg return (False); 784f2e35a3aSmrg } 785d522f475Smrg 786d522f475Smrg if ((event->type == ButtonPress && 787d522f475Smrg !(screen->locator_events & LOC_BTNS_DN)) || 788d522f475Smrg (event->type == ButtonRelease && 789d522f475Smrg !(screen->locator_events & LOC_BTNS_UP))) 790d522f475Smrg return (True); 791d522f475Smrg 792d522f475Smrg if (event->type == MotionNotify) { 793d522f475Smrg CheckLocatorPosition(xw, event); 794d522f475Smrg return (True); 795d522f475Smrg } 796d522f475Smrg 797d522f475Smrg /* get button # */ 798492d43a5Smrg button = (int) event->button - 1; 799d522f475Smrg 800492d43a5Smrg LocatorCoords(row, col, event->x, event->y, oor); 801d522f475Smrg 802d522f475Smrg /* 803d522f475Smrg * DECterm mouse: 804d522f475Smrg * 805d522f475Smrg * ESCAPE '[' event ; mask ; row ; column '&' 'w' 806d522f475Smrg */ 807d522f475Smrg memset(&reply, 0, sizeof(reply)); 808d522f475Smrg reply.a_type = ANSI_CSI; 809d522f475Smrg 810d522f475Smrg if (oor) { 811d522f475Smrg reply.a_nparam = 1; 812d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 813d522f475Smrg reply.a_inters = '&'; 814d522f475Smrg reply.a_final = 'w'; 815d522f475Smrg unparseseq(xw, &reply); 816d522f475Smrg 817d522f475Smrg if (screen->locator_reset) { 818d522f475Smrg MotionOff(screen, xw); 819d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 820d522f475Smrg } 821d522f475Smrg return (True); 822d522f475Smrg } 823d522f475Smrg 824d522f475Smrg /* 825d522f475Smrg * event: 826d522f475Smrg * 1 no buttons 827d522f475Smrg * 2 left button down 828d522f475Smrg * 3 left button up 829d522f475Smrg * 4 middle button down 830d522f475Smrg * 5 middle button up 831d522f475Smrg * 6 right button down 832d522f475Smrg * 7 right button up 833d522f475Smrg * 8 M4 down 834d522f475Smrg * 9 M4 up 835d522f475Smrg */ 836d522f475Smrg reply.a_nparam = 4; 837d522f475Smrg switch (event->type) { 838d522f475Smrg case ButtonPress: 8392eaa94a1Schristos reply.a_param[0] = (ParmType) (2 + (button << 1)); 840d522f475Smrg break; 841d522f475Smrg case ButtonRelease: 8422eaa94a1Schristos reply.a_param[0] = (ParmType) (3 + (button << 1)); 843d522f475Smrg break; 844d522f475Smrg default: 845d522f475Smrg return (True); 846d522f475Smrg } 847d522f475Smrg /* 848d522f475Smrg * mask: 849913cc679Smrg * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 850913cc679Smrg * M4 down left down middle down right down 851d522f475Smrg * 852d522f475Smrg * Notice that Button1 (left) and Button3 (right) are swapped in the mask. 853d522f475Smrg * Also, mask should be the state after the button press/release, 854d522f475Smrg * X provides the state not including the button press/release. 855d522f475Smrg */ 856492d43a5Smrg state = (event->state 857d522f475Smrg & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8; 8584e40088cSchristos /* update mask to "after" state */ 85920d2c4d2Smrg state ^= ((unsigned) (1 << button)); 8604e40088cSchristos /* swap Button1 & Button3 */ 861956cc18dSsnj state = ((state & (unsigned) ~(4 | 1)) 862956cc18dSsnj | ((state & 1) ? 4 : 0) 863956cc18dSsnj | ((state & 4) ? 1 : 0)); 864d522f475Smrg 8652eaa94a1Schristos reply.a_param[1] = (ParmType) state; 8662eaa94a1Schristos reply.a_param[2] = (ParmType) row; 8672eaa94a1Schristos reply.a_param[3] = (ParmType) col; 868d522f475Smrg reply.a_inters = '&'; 869d522f475Smrg reply.a_final = 'w'; 870d522f475Smrg 871d522f475Smrg unparseseq(xw, &reply); 872d522f475Smrg 873d522f475Smrg if (screen->locator_reset) { 874d522f475Smrg MotionOff(screen, xw); 875d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 876d522f475Smrg } 877d522f475Smrg 878d522f475Smrg /* 879913cc679Smrg * DECterm turns the Locator off if a button is pressed while a filter 880913cc679Smrg * rectangle is active. This might be a bug, but I don't know, so I'll 881913cc679Smrg * emulate it anyway. 882d522f475Smrg */ 883d522f475Smrg if (screen->loc_filter) { 884d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 885d522f475Smrg screen->loc_filter = False; 886d522f475Smrg screen->locator_events = 0; 887d522f475Smrg MotionOff(screen, xw); 888d522f475Smrg } 889d522f475Smrg 890d522f475Smrg return (True); 891d522f475Smrg} 892d522f475Smrg 893d522f475Smrg/* 894d522f475Smrg * mask: 895d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 896d522f475Smrg * M4 down left down middle down right down 897d522f475Smrg * 898d522f475Smrg * Button1 (left) and Button3 (right) are swapped in the mask relative to X. 899d522f475Smrg */ 900d522f475Smrg#define ButtonState(state, mask) \ 901913cc679Smrg{ int stemp = (int) (((mask) & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8); \ 902d522f475Smrg /* swap Button1 & Button3 */ \ 903913cc679Smrg (state) = (stemp & ~(4|1)) | ((stemp & 1) ? 4 : 0) | ((stemp & 4) ? 1 : 0); \ 904d522f475Smrg} 905d522f475Smrg 906d522f475Smrgvoid 907d522f475SmrgGetLocatorPosition(XtermWidget xw) 908d522f475Smrg{ 909d522f475Smrg ANSI reply; 910956cc18dSsnj TScreen *screen = TScreenOf(xw); 911d522f475Smrg Window root, child; 912d522f475Smrg int rx, ry, x, y; 913f2e35a3aSmrg unsigned int mask = 0; 914d522f475Smrg int row = 0, col = 0; 915d522f475Smrg Bool oor = False; 916d522f475Smrg Bool ret = False; 917d522f475Smrg int state; 918d522f475Smrg 919d522f475Smrg /* 920913cc679Smrg * DECterm turns the Locator off if the position is requested while a 921913cc679Smrg * filter rectangle is active. This might be a bug, but I don't know, so 922913cc679Smrg * I'll emulate it anyways. 923d522f475Smrg */ 924d522f475Smrg if (screen->loc_filter) { 925d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 926d522f475Smrg screen->loc_filter = False; 927d522f475Smrg screen->locator_events = 0; 928d522f475Smrg MotionOff(screen, xw); 929d522f475Smrg } 930d522f475Smrg 931d522f475Smrg memset(&reply, 0, sizeof(reply)); 932d522f475Smrg reply.a_type = ANSI_CSI; 933d522f475Smrg 934913cc679Smrg if (okSendMousePos(xw) == DEC_LOCATOR) { 935d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), &root, 936d522f475Smrg &child, &rx, &ry, &x, &y, &mask); 937d522f475Smrg if (ret) { 938d522f475Smrg LocatorCoords(row, col, x, y, oor); 939d522f475Smrg } 940d522f475Smrg } 941d522f475Smrg if (ret == False || oor) { 942d522f475Smrg reply.a_nparam = 1; 943d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 944d522f475Smrg reply.a_inters = '&'; 945d522f475Smrg reply.a_final = 'w'; 946d522f475Smrg unparseseq(xw, &reply); 947d522f475Smrg 948d522f475Smrg if (screen->locator_reset) { 949d522f475Smrg MotionOff(screen, xw); 950d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 951d522f475Smrg } 952d522f475Smrg return; 953d522f475Smrg } 954d522f475Smrg 955d522f475Smrg ButtonState(state, mask); 956d522f475Smrg 957d522f475Smrg reply.a_nparam = 4; 958d522f475Smrg reply.a_param[0] = 1; /* Event - 1 = response to locator request */ 9592eaa94a1Schristos reply.a_param[1] = (ParmType) state; 9602eaa94a1Schristos reply.a_param[2] = (ParmType) row; 9612eaa94a1Schristos reply.a_param[3] = (ParmType) col; 962d522f475Smrg reply.a_inters = '&'; 963d522f475Smrg reply.a_final = 'w'; 964d522f475Smrg unparseseq(xw, &reply); 965d522f475Smrg 966d522f475Smrg if (screen->locator_reset) { 967d522f475Smrg MotionOff(screen, xw); 968d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 969d522f475Smrg } 970d522f475Smrg} 971d522f475Smrg 972d522f475Smrgvoid 973d522f475SmrgInitLocatorFilter(XtermWidget xw) 974d522f475Smrg{ 975d522f475Smrg ANSI reply; 976956cc18dSsnj TScreen *screen = TScreenOf(xw); 977d522f475Smrg Window root, child; 978d522f475Smrg int rx, ry, x, y; 979d522f475Smrg unsigned int mask; 980d522f475Smrg int row = 0, col = 0; 981d522f475Smrg Bool oor = 0; 982d522f475Smrg Bool ret; 983d522f475Smrg 984d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), 985d522f475Smrg &root, &child, &rx, &ry, &x, &y, &mask); 986d522f475Smrg if (ret) { 987d522f475Smrg LocatorCoords(row, col, x, y, oor); 988d522f475Smrg } 989d522f475Smrg if (ret == False || oor) { 990d522f475Smrg /* Locator is unavailable */ 991d522f475Smrg 992d522f475Smrg if (screen->loc_filter_top != LOC_FILTER_POS || 993d522f475Smrg screen->loc_filter_left != LOC_FILTER_POS || 994d522f475Smrg screen->loc_filter_bottom != LOC_FILTER_POS || 995d522f475Smrg screen->loc_filter_right != LOC_FILTER_POS) { 996d522f475Smrg /* 997d522f475Smrg * If any explicit coordinates were received, 998d522f475Smrg * report immediately with no coordinates. 999d522f475Smrg */ 1000d522f475Smrg memset(&reply, 0, sizeof(reply)); 1001d522f475Smrg reply.a_type = ANSI_CSI; 1002d522f475Smrg reply.a_nparam = 1; 1003d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 1004d522f475Smrg reply.a_inters = '&'; 1005d522f475Smrg reply.a_final = 'w'; 1006d522f475Smrg unparseseq(xw, &reply); 1007d522f475Smrg 1008d522f475Smrg if (screen->locator_reset) { 1009d522f475Smrg MotionOff(screen, xw); 1010d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 1011d522f475Smrg } 1012d522f475Smrg } else { 1013d522f475Smrg /* 1014d522f475Smrg * No explicit coordinates were received, and the pointer is 1015d522f475Smrg * unavailable. Report when the pointer re-enters the window. 1016d522f475Smrg */ 1017d522f475Smrg screen->loc_filter = True; 1018d522f475Smrg MotionOn(screen, xw); 1019d522f475Smrg } 1020d522f475Smrg return; 1021d522f475Smrg } 1022d522f475Smrg 1023d522f475Smrg /* 1024d522f475Smrg * Adjust rectangle coordinates: 1025d522f475Smrg * 1. Replace "LOC_FILTER_POS" with current coordinates 1026d522f475Smrg * 2. Limit coordinates to screen size 1027d522f475Smrg * 3. make sure top and left are less than bottom and right, resp. 1028d522f475Smrg */ 1029d522f475Smrg if (screen->locator_pixels) { 1030d522f475Smrg rx = OriginX(screen) * 2 + Width(screen); 1031d522f475Smrg ry = screen->border * 2 + Height(screen); 1032d522f475Smrg } else { 1033d522f475Smrg rx = screen->max_col; 1034d522f475Smrg ry = screen->max_row; 1035d522f475Smrg } 1036d522f475Smrg 1037d522f475Smrg#define Adjust( coord, def, max ) \ 1038d522f475Smrg if( (coord) == LOC_FILTER_POS ) (coord) = (def); \ 1039d522f475Smrg else if ((coord) < 1) (coord) = 1; \ 1040d522f475Smrg else if ((coord) > (max)) (coord) = (max) 1041d522f475Smrg 1042d522f475Smrg Adjust(screen->loc_filter_top, row, ry); 1043d522f475Smrg Adjust(screen->loc_filter_left, col, rx); 1044d522f475Smrg Adjust(screen->loc_filter_bottom, row, ry); 1045d522f475Smrg Adjust(screen->loc_filter_right, col, rx); 1046d522f475Smrg 1047d522f475Smrg if (screen->loc_filter_top > screen->loc_filter_bottom) { 1048d522f475Smrg ry = screen->loc_filter_top; 1049d522f475Smrg screen->loc_filter_top = screen->loc_filter_bottom; 1050d522f475Smrg screen->loc_filter_bottom = ry; 1051d522f475Smrg } 1052d522f475Smrg 1053d522f475Smrg if (screen->loc_filter_left > screen->loc_filter_right) { 1054d522f475Smrg rx = screen->loc_filter_left; 1055d522f475Smrg screen->loc_filter_left = screen->loc_filter_right; 1056d522f475Smrg screen->loc_filter_right = rx; 1057d522f475Smrg } 1058d522f475Smrg 1059d522f475Smrg if ((col < screen->loc_filter_left) || 1060d522f475Smrg (col > screen->loc_filter_right) || 1061d522f475Smrg (row < screen->loc_filter_top) || 1062d522f475Smrg (row > screen->loc_filter_bottom)) { 10632e4f8982Smrg int state; 10642e4f8982Smrg 1065d522f475Smrg /* Pointer is already outside the rectangle - report immediately */ 1066d522f475Smrg ButtonState(state, mask); 1067d522f475Smrg 1068d522f475Smrg memset(&reply, 0, sizeof(reply)); 1069d522f475Smrg reply.a_type = ANSI_CSI; 1070d522f475Smrg reply.a_nparam = 4; 1071d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 10722eaa94a1Schristos reply.a_param[1] = (ParmType) state; 10732eaa94a1Schristos reply.a_param[2] = (ParmType) row; 10742eaa94a1Schristos reply.a_param[3] = (ParmType) col; 1075d522f475Smrg reply.a_inters = '&'; 1076d522f475Smrg reply.a_final = 'w'; 1077d522f475Smrg unparseseq(xw, &reply); 1078d522f475Smrg 1079d522f475Smrg if (screen->locator_reset) { 1080d522f475Smrg MotionOff(screen, xw); 1081d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 1082d522f475Smrg } 1083d522f475Smrg return; 1084d522f475Smrg } 1085d522f475Smrg 1086d522f475Smrg /* 1087d522f475Smrg * Rectangle is set up. Allow pointer tracking 1088d522f475Smrg * to detect if the mouse leaves the rectangle. 1089d522f475Smrg */ 1090d522f475Smrg screen->loc_filter = True; 1091d522f475Smrg MotionOn(screen, xw); 1092d522f475Smrg} 1093d522f475Smrg 1094d522f475Smrgstatic void 1095894e0ac8SmrgCheckLocatorPosition(XtermWidget xw, XButtonEvent *event) 1096d522f475Smrg{ 1097d522f475Smrg ANSI reply; 1098956cc18dSsnj TScreen *screen = TScreenOf(xw); 1099d522f475Smrg int row, col; 1100d522f475Smrg Bool oor; 1101d522f475Smrg 1102492d43a5Smrg LocatorCoords(row, col, event->x, event->y, oor); 1103d522f475Smrg 1104d522f475Smrg /* 1105d522f475Smrg * Send report if the pointer left the filter rectangle, if 1106d522f475Smrg * the pointer left the window, or if the filter rectangle 1107d522f475Smrg * had no coordinates and the pointer re-entered the window. 1108d522f475Smrg */ 1109d522f475Smrg if (oor || (screen->loc_filter_top == LOC_FILTER_POS) || 1110d522f475Smrg (col < screen->loc_filter_left) || 1111d522f475Smrg (col > screen->loc_filter_right) || 1112d522f475Smrg (row < screen->loc_filter_top) || 1113d522f475Smrg (row > screen->loc_filter_bottom)) { 1114d522f475Smrg /* Filter triggered - disable it */ 1115d522f475Smrg screen->loc_filter = False; 1116d522f475Smrg MotionOff(screen, xw); 1117d522f475Smrg 1118d522f475Smrg memset(&reply, 0, sizeof(reply)); 1119d522f475Smrg reply.a_type = ANSI_CSI; 1120d522f475Smrg if (oor) { 1121d522f475Smrg reply.a_nparam = 1; 1122d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 1123d522f475Smrg } else { 11242e4f8982Smrg int state; 11252e4f8982Smrg 1126492d43a5Smrg ButtonState(state, event->state); 1127d522f475Smrg 1128d522f475Smrg reply.a_nparam = 4; 1129d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 11302eaa94a1Schristos reply.a_param[1] = (ParmType) state; 11312eaa94a1Schristos reply.a_param[2] = (ParmType) row; 11322eaa94a1Schristos reply.a_param[3] = (ParmType) col; 1133d522f475Smrg } 1134d522f475Smrg 1135d522f475Smrg reply.a_inters = '&'; 1136d522f475Smrg reply.a_final = 'w'; 1137d522f475Smrg unparseseq(xw, &reply); 1138d522f475Smrg 1139d522f475Smrg if (screen->locator_reset) { 1140d522f475Smrg MotionOff(screen, xw); 1141d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 1142d522f475Smrg } 1143d522f475Smrg } 1144d522f475Smrg} 1145d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 1146d522f475Smrg 1147d522f475Smrg#if OPT_READLINE 1148d522f475Smrgstatic int 1149913cc679SmrgisClick1_clean(XtermWidget xw, XButtonEvent *event) 1150d522f475Smrg{ 1151913cc679Smrg TScreen *screen = TScreenOf(xw); 1152d522f475Smrg int delta; 1153d522f475Smrg 1154d522f475Smrg /* Disable on Shift-Click-1, including the application-mouse modes */ 1155f2e35a3aSmrg if (OverrideButton(event) 1156f2e35a3aSmrg || (okSendMousePos(xw) != MOUSE_OFF) 1157f2e35a3aSmrg || ExtendingSelection) /* Was moved */ 1158d522f475Smrg return 0; 1159d522f475Smrg 1160d522f475Smrg if (event->type != ButtonRelease) 1161d522f475Smrg return 0; 1162d522f475Smrg 1163d522f475Smrg if (lastButtonDownTime == (Time) 0) { 1164d522f475Smrg /* first time or once in a blue moon */ 1165d522f475Smrg delta = screen->multiClickTime + 1; 1166492d43a5Smrg } else if (event->time > lastButtonDownTime) { 1167d522f475Smrg /* most of the time */ 1168492d43a5Smrg delta = (int) (event->time - lastButtonDownTime); 1169d522f475Smrg } else { 1170d522f475Smrg /* time has rolled over since lastButtonUpTime */ 1171492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->time); 1172d522f475Smrg } 1173d522f475Smrg 1174d522f475Smrg return delta <= screen->multiClickTime; 1175d522f475Smrg} 1176d522f475Smrg 1177d522f475Smrgstatic int 1178f2e35a3aSmrgisDoubleClick3(XtermWidget xw, TScreen *screen, XButtonEvent *event) 1179d522f475Smrg{ 1180d522f475Smrg int delta; 1181d522f475Smrg 1182d522f475Smrg if (event->type != ButtonRelease 1183f2e35a3aSmrg || OverrideButton(event) 1184492d43a5Smrg || event->button != Button3) { 1185d522f475Smrg lastButton3UpTime = 0; /* Disable the cached info */ 1186d522f475Smrg return 0; 1187d522f475Smrg } 1188d522f475Smrg /* Process Btn3Release. */ 1189d522f475Smrg if (lastButton3DoubleDownTime == (Time) 0) { 1190d522f475Smrg /* No previous click or once in a blue moon */ 1191d522f475Smrg delta = screen->multiClickTime + 1; 1192492d43a5Smrg } else if (event->time > lastButton3DoubleDownTime) { 1193d522f475Smrg /* most of the time */ 1194492d43a5Smrg delta = (int) (event->time - lastButton3DoubleDownTime); 1195d522f475Smrg } else { 1196d522f475Smrg /* time has rolled over since lastButton3DoubleDownTime */ 1197492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButton3DoubleDownTime) + event->time); 1198d522f475Smrg } 1199d522f475Smrg if (delta <= screen->multiClickTime) { 1200d522f475Smrg /* Double click */ 1201d522f475Smrg CELL cell; 1202d522f475Smrg 1203d522f475Smrg /* Cannot check ExtendingSelection, since mouse-3 always sets it */ 1204492d43a5Smrg PointToCELL(screen, event->y, event->x, &cell); 1205d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 1206d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the third click */ 1207d522f475Smrg return 1; 1208d522f475Smrg } 1209d522f475Smrg } 1210d522f475Smrg /* Not a double click, memorize for future check. */ 1211492d43a5Smrg lastButton3UpTime = event->time; 1212492d43a5Smrg PointToCELL(screen, event->y, event->x, &lastButton3); 1213d522f475Smrg return 0; 1214d522f475Smrg} 1215d522f475Smrg 1216d522f475Smrgstatic int 1217f2e35a3aSmrgCheckSecondPress3(XtermWidget xw, TScreen *screen, XEvent *event) 1218d522f475Smrg{ 1219d522f475Smrg int delta; 1220d522f475Smrg 1221d522f475Smrg if (event->type != ButtonPress 1222f2e35a3aSmrg || OverrideEvent(event) 1223d522f475Smrg || event->xbutton.button != Button3) { 1224d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the cached info */ 1225d522f475Smrg return 0; 1226d522f475Smrg } 1227d522f475Smrg /* Process Btn3Press. */ 1228d522f475Smrg if (lastButton3UpTime == (Time) 0) { 1229d522f475Smrg /* No previous click or once in a blue moon */ 1230d522f475Smrg delta = screen->multiClickTime + 1; 1231d522f475Smrg } else if (event->xbutton.time > lastButton3UpTime) { 1232d522f475Smrg /* most of the time */ 12332eaa94a1Schristos delta = (int) (event->xbutton.time - lastButton3UpTime); 1234d522f475Smrg } else { 1235d522f475Smrg /* time has rolled over since lastButton3UpTime */ 12362eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButton3UpTime) + event->xbutton.time); 1237d522f475Smrg } 1238d522f475Smrg if (delta <= screen->multiClickTime) { 1239d522f475Smrg CELL cell; 1240d522f475Smrg 1241d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 1242d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 1243d522f475Smrg /* A candidate for a double-click */ 1244d522f475Smrg lastButton3DoubleDownTime = event->xbutton.time; 1245d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &lastButton3); 1246d522f475Smrg return 1; 1247d522f475Smrg } 1248d522f475Smrg lastButton3UpTime = 0; /* Disable the info about the previous click */ 1249d522f475Smrg } 1250d522f475Smrg /* Either too long, or moved, disable. */ 1251d522f475Smrg lastButton3DoubleDownTime = 0; 1252d522f475Smrg return 0; 1253d522f475Smrg} 1254d522f475Smrg 1255d522f475Smrgstatic int 1256e0a2b6dfSmrgrowOnCurrentLine(TScreen *screen, 1257d522f475Smrg int line, 1258d522f475Smrg int *deltap) /* must be XButtonEvent */ 1259d522f475Smrg{ 1260956cc18dSsnj int result = 1; 1261d522f475Smrg 1262d522f475Smrg *deltap = 0; 12632e4f8982Smrg 1264956cc18dSsnj if (line != screen->cur_row) { 12652e4f8982Smrg int l1, l2; 12662e4f8982Smrg 1267f2e35a3aSmrg if (line < screen->cur_row) { 1268f2e35a3aSmrg l1 = line; 1269f2e35a3aSmrg l2 = screen->cur_row; 1270f2e35a3aSmrg } else { 1271f2e35a3aSmrg l2 = line; 1272f2e35a3aSmrg l1 = screen->cur_row; 1273f2e35a3aSmrg } 1274956cc18dSsnj l1--; 1275956cc18dSsnj while (++l1 < l2) { 1276956cc18dSsnj LineData *ld = GET_LINEDATA(screen, l1); 1277956cc18dSsnj if (!LineTstWrapped(ld)) { 1278956cc18dSsnj result = 0; 1279956cc18dSsnj break; 1280956cc18dSsnj } 1281956cc18dSsnj } 1282956cc18dSsnj if (result) { 1283956cc18dSsnj /* Everything is on one "wrapped line" now */ 1284956cc18dSsnj *deltap = line - screen->cur_row; 1285956cc18dSsnj } 1286956cc18dSsnj } 1287956cc18dSsnj return result; 1288d522f475Smrg} 1289d522f475Smrg 1290d522f475Smrgstatic int 1291894e0ac8SmrgeventRow(TScreen *screen, XEvent *event) /* must be XButtonEvent */ 1292d522f475Smrg{ 1293d522f475Smrg return (event->xbutton.y - screen->border) / FontHeight(screen); 1294d522f475Smrg} 1295d522f475Smrg 1296d522f475Smrgstatic int 1297894e0ac8SmrgeventColBetween(TScreen *screen, XEvent *event) /* must be XButtonEvent */ 1298d522f475Smrg{ 1299d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 1300d522f475Smrg return ((event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) / 2) 1301d522f475Smrg / FontWidth(screen)); 1302d522f475Smrg} 1303d522f475Smrg 1304d522f475Smrgstatic int 1305e0a2b6dfSmrgReadLineMovePoint(TScreen *screen, int col, int ldelta) 1306d522f475Smrg{ 1307d522f475Smrg Char line[6]; 1308d522f475Smrg unsigned count = 0; 1309d522f475Smrg 1310d522f475Smrg col += ldelta * MaxCols(screen) - screen->cur_col; 1311d522f475Smrg if (col == 0) 1312d522f475Smrg return 0; 1313d522f475Smrg if (screen->control_eight_bits) { 1314d522f475Smrg line[count++] = ANSI_CSI; 1315d522f475Smrg } else { 1316d522f475Smrg line[count++] = ANSI_ESC; 1317d522f475Smrg line[count++] = '['; /* XXX maybe sometimes O is better? */ 1318d522f475Smrg } 131920d2c4d2Smrg line[count] = CharOf(col > 0 ? 'C' : 'D'); 1320d522f475Smrg if (col < 0) 1321d522f475Smrg col = -col; 1322d522f475Smrg while (col--) 1323d522f475Smrg v_write(screen->respond, line, 3); 1324d522f475Smrg return 1; 1325d522f475Smrg} 1326d522f475Smrg 1327d522f475Smrgstatic int 1328e0a2b6dfSmrgReadLineDelete(TScreen *screen, CELL *cell1, CELL *cell2) 1329d522f475Smrg{ 1330d522f475Smrg int del; 1331d522f475Smrg 1332d522f475Smrg del = (cell2->col - cell1->col) + ((cell2->row - cell1->row) * MaxCols(screen)); 1333d522f475Smrg if (del <= 0) /* Just in case... */ 1334d522f475Smrg return 0; 1335d522f475Smrg while (del--) 1336492d43a5Smrg v_write(screen->respond, (const Char *) "\177", 1); 1337d522f475Smrg return 1; 1338d522f475Smrg} 1339492d43a5Smrg 1340492d43a5Smrgstatic void 1341913cc679SmrgreadlineExtend(XtermWidget xw, XEvent *event) 1342492d43a5Smrg{ 1343913cc679Smrg TScreen *screen = TScreenOf(xw); 1344492d43a5Smrg int ldelta1, ldelta2; 1345492d43a5Smrg 1346492d43a5Smrg if (IsBtnEvent(event)) { 1347492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 1348913cc679Smrg if (isClick1_clean(xw, my_event) 1349492d43a5Smrg && SCREEN_FLAG(screen, click1_moves) 1350492d43a5Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta1)) { 1351492d43a5Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta1); 1352492d43a5Smrg } 1353f2e35a3aSmrg if (isDoubleClick3(xw, screen, my_event) 1354492d43a5Smrg && SCREEN_FLAG(screen, dclick3_deletes) 1355492d43a5Smrg && rowOnCurrentLine(screen, screen->startSel.row, &ldelta1) 1356492d43a5Smrg && rowOnCurrentLine(screen, screen->endSel.row, &ldelta2)) { 1357492d43a5Smrg ReadLineMovePoint(screen, screen->endSel.col, ldelta2); 1358492d43a5Smrg ReadLineDelete(screen, &screen->startSel, &(screen->endSel)); 1359492d43a5Smrg } 1360492d43a5Smrg } 1361492d43a5Smrg} 1362d522f475Smrg#endif /* OPT_READLINE */ 1363d522f475Smrg 1364d522f475Smrg/* ^XM-G<line+' '><col+' '> */ 1365d522f475Smrgvoid 1366d522f475SmrgDiredButton(Widget w, 1367894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1368e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 1369d522f475Smrg Cardinal *num_params GCC_UNUSED) 1370d522f475Smrg{ 1371956cc18dSsnj XtermWidget xw; 1372956cc18dSsnj 1373956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1374956cc18dSsnj TScreen *screen = TScreenOf(xw); 1375d522f475Smrg 1376492d43a5Smrg if (IsBtnEvent(event) 13772eaa94a1Schristos && (event->xbutton.y >= screen->border) 13782eaa94a1Schristos && (event->xbutton.x >= OriginX(screen))) { 13792e4f8982Smrg Char Line[6]; 13802e4f8982Smrg unsigned line, col; 13812e4f8982Smrg 138220d2c4d2Smrg line = (unsigned) ((event->xbutton.y - screen->border) 138320d2c4d2Smrg / FontHeight(screen)); 138420d2c4d2Smrg col = (unsigned) ((event->xbutton.x - OriginX(screen)) 138520d2c4d2Smrg / FontWidth(screen)); 1386d522f475Smrg Line[0] = CONTROL('X'); 1387d522f475Smrg Line[1] = ANSI_ESC; 1388d522f475Smrg Line[2] = 'G'; 13892eaa94a1Schristos Line[3] = CharOf(' ' + col); 13902eaa94a1Schristos Line[4] = CharOf(' ' + line); 1391d522f475Smrg v_write(screen->respond, Line, 5); 1392d522f475Smrg } 1393d522f475Smrg } 1394d522f475Smrg} 1395d522f475Smrg 1396d522f475Smrg#if OPT_READLINE 1397d522f475Smrgvoid 1398d522f475SmrgReadLineButton(Widget w, 1399894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1400f2e35a3aSmrg String *params, /* selections */ 1401f2e35a3aSmrg Cardinal *num_params) 1402d522f475Smrg{ 1403956cc18dSsnj XtermWidget xw; 1404956cc18dSsnj 1405956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1406956cc18dSsnj TScreen *screen = TScreenOf(xw); 1407d522f475Smrg Char Line[6]; 1408d522f475Smrg int line, col, ldelta = 0; 1409d522f475Smrg 1410492d43a5Smrg if (!IsBtnEvent(event) 1411913cc679Smrg || (okSendMousePos(xw) != MOUSE_OFF) || ExtendingSelection) 1412d522f475Smrg goto finish; 1413d522f475Smrg if (event->type == ButtonRelease) { 1414d522f475Smrg int delta; 1415d522f475Smrg 1416d522f475Smrg if (lastButtonDownTime == (Time) 0) { 1417d522f475Smrg /* first time and once in a blue moon */ 1418d522f475Smrg delta = screen->multiClickTime + 1; 1419d522f475Smrg } else if (event->xbutton.time > lastButtonDownTime) { 1420d522f475Smrg /* most of the time */ 14212eaa94a1Schristos delta = (int) (event->xbutton.time - lastButtonDownTime); 1422d522f475Smrg } else { 1423d522f475Smrg /* time has rolled over since lastButtonUpTime */ 14242eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time); 1425d522f475Smrg } 1426d522f475Smrg if (delta > screen->multiClickTime) 1427d522f475Smrg goto finish; /* All this work for this... */ 1428d522f475Smrg } 1429d522f475Smrg line = (event->xbutton.y - screen->border) / FontHeight(screen); 1430956cc18dSsnj if (!rowOnCurrentLine(screen, line, &ldelta)) 1431956cc18dSsnj goto finish; 1432d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 1433d522f475Smrg col = (event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) 1434d522f475Smrg / 2) 1435d522f475Smrg / FontWidth(screen) - screen->cur_col + ldelta * MaxCols(screen); 1436d522f475Smrg if (col == 0) 1437d522f475Smrg goto finish; 1438d522f475Smrg Line[0] = ANSI_ESC; 1439d522f475Smrg /* XXX: sometimes it is better to send '['? */ 1440d522f475Smrg Line[1] = 'O'; 14412eaa94a1Schristos Line[2] = CharOf(col > 0 ? 'C' : 'D'); 1442d522f475Smrg if (col < 0) 1443d522f475Smrg col = -col; 1444d522f475Smrg while (col--) 1445d522f475Smrg v_write(screen->respond, Line, 3); 1446d522f475Smrg finish: 1447d522f475Smrg if (event->type == ButtonRelease) 1448d522f475Smrg do_select_end(xw, event, params, num_params, False); 1449d522f475Smrg } 1450d522f475Smrg} 1451d522f475Smrg#endif /* OPT_READLINE */ 1452d522f475Smrg 1453d522f475Smrg/* repeats <ESC>n or <ESC>p */ 1454d522f475Smrgvoid 1455d522f475SmrgViButton(Widget w, 1456894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1457e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 1458d522f475Smrg Cardinal *num_params GCC_UNUSED) 1459d522f475Smrg{ 1460956cc18dSsnj XtermWidget xw; 1461956cc18dSsnj 1462956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1463956cc18dSsnj TScreen *screen = TScreenOf(xw); 1464d522f475Smrg int pty = screen->respond; 1465d522f475Smrg 1466492d43a5Smrg if (IsBtnEvent(event)) { 14672e4f8982Smrg int line; 1468d522f475Smrg 1469d522f475Smrg line = screen->cur_row - 1470d522f475Smrg ((event->xbutton.y - screen->border) / FontHeight(screen)); 14712e4f8982Smrg 1472d522f475Smrg if (line != 0) { 14732e4f8982Smrg Char Line[6]; 14742e4f8982Smrg 1475d522f475Smrg Line[0] = ANSI_ESC; /* force an exit from insert-mode */ 1476d522f475Smrg v_write(pty, Line, 1); 1477d522f475Smrg 1478d522f475Smrg if (line < 0) { 1479d522f475Smrg line = -line; 1480d522f475Smrg Line[0] = CONTROL('n'); 1481d522f475Smrg } else { 1482d522f475Smrg Line[0] = CONTROL('p'); 1483d522f475Smrg } 1484d522f475Smrg while (--line >= 0) 1485d522f475Smrg v_write(pty, Line, 1); 1486d522f475Smrg } 1487d522f475Smrg } 1488d522f475Smrg } 1489d522f475Smrg} 1490d522f475Smrg 1491d522f475Smrg/* 1492d522f475Smrg * This function handles button-motion events 1493d522f475Smrg */ 1494d522f475Smrg/*ARGSUSED*/ 1495d522f475Smrgvoid 1496d522f475SmrgHandleSelectExtend(Widget w, 1497894e0ac8Smrg XEvent *event, /* must be XMotionEvent */ 1498e0a2b6dfSmrg String *params GCC_UNUSED, 1499d522f475Smrg Cardinal *num_params GCC_UNUSED) 1500d522f475Smrg{ 1501956cc18dSsnj XtermWidget xw; 1502956cc18dSsnj 1503956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1504956cc18dSsnj TScreen *screen = TScreenOf(xw); 1505d522f475Smrg CELL cell; 1506d522f475Smrg 1507f2e35a3aSmrg TRACE_EVENT("HandleSelectExtend", event, params, num_params); 15080bd37d32Smrg 1509d522f475Smrg screen->selection_time = event->xmotion.time; 1510d522f475Smrg switch (screen->eventMode) { 1511d522f475Smrg /* If not in one of the DEC mouse-reporting modes */ 1512d522f475Smrg case LEFTEXTENSION: 1513d522f475Smrg case RIGHTEXTENSION: 1514d522f475Smrg PointToCELL(screen, event->xmotion.y, event->xmotion.x, &cell); 1515d522f475Smrg ExtendExtend(xw, &cell); 1516d522f475Smrg break; 1517d522f475Smrg 1518d522f475Smrg /* If in motion reporting mode, send mouse position to 1519d522f475Smrg character process as a key sequence \E[M... */ 1520d522f475Smrg case NORMAL: 1521d522f475Smrg /* will get here if send_mouse_pos != MOUSE_OFF */ 1522913cc679Smrg if (okSendMousePos(xw) == BTN_EVENT_MOUSE 1523913cc679Smrg || okSendMousePos(xw) == ANY_EVENT_MOUSE) { 1524d522f475Smrg (void) SendMousePosition(xw, event); 1525d522f475Smrg } 1526d522f475Smrg break; 1527d522f475Smrg } 1528d522f475Smrg } 1529d522f475Smrg} 1530d522f475Smrg 1531d522f475Smrgvoid 1532d522f475SmrgHandleKeyboardSelectExtend(Widget w, 1533894e0ac8Smrg XEvent *event GCC_UNUSED, /* must be XButtonEvent */ 1534e0a2b6dfSmrg String *params GCC_UNUSED, 1535d522f475Smrg Cardinal *num_params GCC_UNUSED) 1536d522f475Smrg{ 1537956cc18dSsnj XtermWidget xw; 1538956cc18dSsnj 1539956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1540956cc18dSsnj TScreen *screen = TScreenOf(xw); 15410bd37d32Smrg 1542f2e35a3aSmrg TRACE_EVENT("HandleKeyboardSelectExtend", event, params, num_params); 1543d522f475Smrg ExtendExtend(xw, &screen->cursorp); 1544d522f475Smrg } 1545d522f475Smrg} 1546d522f475Smrg 1547d522f475Smrgstatic void 1548d522f475Smrgdo_select_end(XtermWidget xw, 1549894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1550e0a2b6dfSmrg String *params, /* selections */ 1551d522f475Smrg Cardinal *num_params, 1552d522f475Smrg Bool use_cursor_loc) 1553d522f475Smrg{ 1554956cc18dSsnj TScreen *screen = TScreenOf(xw); 1555d522f475Smrg 1556d522f475Smrg screen->selection_time = event->xbutton.time; 1557f2e35a3aSmrg 1558f2e35a3aSmrg TRACE(("do_select_end %s @%ld\n", 1559f2e35a3aSmrg visibleEventMode(screen->eventMode), 1560f2e35a3aSmrg screen->selection_time)); 1561f2e35a3aSmrg 1562d522f475Smrg switch (screen->eventMode) { 1563d522f475Smrg case NORMAL: 1564d522f475Smrg (void) SendMousePosition(xw, event); 1565d522f475Smrg break; 1566d522f475Smrg case LEFTEXTENSION: 1567d522f475Smrg case RIGHTEXTENSION: 1568d522f475Smrg EndExtend(xw, event, params, *num_params, use_cursor_loc); 1569d522f475Smrg#if OPT_READLINE 1570913cc679Smrg readlineExtend(xw, event); 1571d522f475Smrg#endif /* OPT_READLINE */ 1572d522f475Smrg break; 1573d522f475Smrg } 1574d522f475Smrg} 1575d522f475Smrg 1576d522f475Smrgvoid 1577d522f475SmrgHandleSelectEnd(Widget w, 1578894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1579e0a2b6dfSmrg String *params, /* selections */ 1580d522f475Smrg Cardinal *num_params) 1581d522f475Smrg{ 1582956cc18dSsnj XtermWidget xw; 1583956cc18dSsnj 1584956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 15850bd37d32Smrg TRACE(("HandleSelectEnd\n")); 1586956cc18dSsnj do_select_end(xw, event, params, num_params, False); 1587956cc18dSsnj } 1588d522f475Smrg} 1589d522f475Smrg 1590d522f475Smrgvoid 1591d522f475SmrgHandleKeyboardSelectEnd(Widget w, 1592894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1593e0a2b6dfSmrg String *params, /* selections */ 1594d522f475Smrg Cardinal *num_params) 1595d522f475Smrg{ 1596956cc18dSsnj XtermWidget xw; 1597956cc18dSsnj 1598956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 15990bd37d32Smrg TRACE(("HandleKeyboardSelectEnd\n")); 1600956cc18dSsnj do_select_end(xw, event, params, num_params, True); 1601956cc18dSsnj } 1602d522f475Smrg} 1603d522f475Smrg 1604f2e35a3aSmrgvoid 1605f2e35a3aSmrgHandlePointerMotion(Widget w, 1606f2e35a3aSmrg XEvent *event, 1607f2e35a3aSmrg String *params, /* selections */ 1608f2e35a3aSmrg Cardinal *num_params) 1609f2e35a3aSmrg{ 1610f2e35a3aSmrg XtermWidget xw; 1611f2e35a3aSmrg 1612f2e35a3aSmrg (void) params; 1613f2e35a3aSmrg (void) num_params; 1614f2e35a3aSmrg if ((xw = getXtermWidget(w)) != 0) { 1615f2e35a3aSmrg TRACE(("HandlePointerMotion\n")); 1616f2e35a3aSmrg if (event->type == MotionNotify) 1617f2e35a3aSmrg (void) SendMousePosition(xw, event); 1618f2e35a3aSmrg } 1619f2e35a3aSmrg} 1620f2e35a3aSmrg 1621f2e35a3aSmrgvoid 1622f2e35a3aSmrgHandlePointerButton(Widget w, 1623f2e35a3aSmrg XEvent *event, 1624f2e35a3aSmrg String *params, /* selections */ 1625f2e35a3aSmrg Cardinal *num_params) 1626f2e35a3aSmrg{ 1627f2e35a3aSmrg XtermWidget xw; 1628f2e35a3aSmrg 1629f2e35a3aSmrg (void) params; 1630f2e35a3aSmrg (void) num_params; 1631f2e35a3aSmrg if ((xw = getXtermWidget(w)) != 0) { 1632f2e35a3aSmrg TRACE(("HandlePointerButton\n")); 1633f2e35a3aSmrg if (IsBtnEvent(event)) 1634f2e35a3aSmrg (void) SendMousePosition(xw, event); 1635f2e35a3aSmrg } 1636f2e35a3aSmrg} 1637f2e35a3aSmrg 1638492d43a5Smrg/* 16396879286fSmrg * Copy the selection data to the given target(s). 1640492d43a5Smrg */ 1641492d43a5Smrgvoid 16426879286fSmrgHandleCopySelection(Widget w, 1643894e0ac8Smrg XEvent *event, 1644e0a2b6dfSmrg String *params, /* list of targets */ 16456879286fSmrg Cardinal *num_params) 1646492d43a5Smrg{ 1647492d43a5Smrg XtermWidget xw; 1648492d43a5Smrg 1649492d43a5Smrg if ((xw = getXtermWidget(w)) != 0) { 1650f2e35a3aSmrg TRACE_EVENT("HandleCopySelection", event, params, num_params); 16516879286fSmrg SelectSet(xw, event, params, *num_params); 1652492d43a5Smrg } 1653492d43a5Smrg} 1654492d43a5Smrg 1655d522f475Smrgstruct _SelectionList { 1656d522f475Smrg String *params; 1657d522f475Smrg Cardinal count; 1658d522f475Smrg Atom *targets; 1659d522f475Smrg Time time; 1660d522f475Smrg}; 1661d522f475Smrg 1662d522f475Smrgstatic unsigned 1663d522f475SmrgDECtoASCII(unsigned ch) 1664d522f475Smrg{ 1665d522f475Smrg if (xtermIsDecGraphic(ch)) { 16662eaa94a1Schristos ch = CharOf("###########+++++##-##++++|######"[ch]); 16672eaa94a1Schristos /* 01234567890123456789012345678901 */ 1668d522f475Smrg } 1669d522f475Smrg return ch; 1670d522f475Smrg} 167120d2c4d2Smrg 167220d2c4d2Smrg#if OPT_WIDE_CHARS 167320d2c4d2Smrgstatic Cardinal 1674e0a2b6dfSmrgaddXtermChar(Char **buffer, Cardinal *used, Cardinal offset, unsigned value) 167520d2c4d2Smrg{ 167620d2c4d2Smrg if (offset + 1 >= *used) { 167720d2c4d2Smrg *used = 1 + (2 * (offset + 1)); 167820d2c4d2Smrg allocXtermChars(buffer, *used); 167920d2c4d2Smrg } 168020d2c4d2Smrg (*buffer)[offset++] = (Char) value; 168120d2c4d2Smrg return offset; 168220d2c4d2Smrg} 168320d2c4d2Smrg#define AddChar(buffer, used, offset, value) \ 168420d2c4d2Smrg offset = addXtermChar(buffer, used, offset, (unsigned) value) 168520d2c4d2Smrg 1686d522f475Smrg/* 1687d522f475Smrg * Convert a UTF-8 string to Latin-1, replacing non Latin-1 characters by `#', 1688d522f475Smrg * or ASCII/Latin-1 equivalents for special cases. 1689d522f475Smrg */ 1690d522f475Smrgstatic Char * 1691e0a2b6dfSmrgUTF8toLatin1(TScreen *screen, Char *s, unsigned long len, unsigned long *result) 1692d522f475Smrg{ 1693d522f475Smrg static Char *buffer; 1694956cc18dSsnj static Cardinal used; 1695d522f475Smrg 169620d2c4d2Smrg Cardinal offset = 0; 1697d522f475Smrg 169820d2c4d2Smrg if (len != 0) { 1699d522f475Smrg PtyData data; 1700d522f475Smrg 1701d522f475Smrg fakePtyData(&data, s, s + len); 1702894e0ac8Smrg while (decodeUtf8(screen, &data)) { 1703956cc18dSsnj Bool fails = False; 1704956cc18dSsnj Bool extra = False; 1705f2e35a3aSmrg IChar value; 1706f2e35a3aSmrg skipPtyData(&data, value); 1707d522f475Smrg if (value == UCS_REPL) { 1708956cc18dSsnj fails = True; 1709d522f475Smrg } else if (value < 256) { 171020d2c4d2Smrg AddChar(&buffer, &used, offset, CharOf(value)); 1711d522f475Smrg } else { 1712f2e35a3aSmrg unsigned eqv = ucs2dec(screen, value); 1713d522f475Smrg if (xtermIsDecGraphic(eqv)) { 171420d2c4d2Smrg AddChar(&buffer, &used, offset, DECtoASCII(eqv)); 1715d522f475Smrg } else { 1716d522f475Smrg eqv = AsciiEquivs(value); 1717956cc18dSsnj if (eqv == value) { 1718956cc18dSsnj fails = True; 1719956cc18dSsnj } else { 172020d2c4d2Smrg AddChar(&buffer, &used, offset, eqv); 1721956cc18dSsnj } 1722956cc18dSsnj if (isWide((wchar_t) value)) 1723956cc18dSsnj extra = True; 1724956cc18dSsnj } 1725956cc18dSsnj } 1726956cc18dSsnj 1727956cc18dSsnj /* 1728956cc18dSsnj * If we're not able to plug in a single-byte result, insert the 1729956cc18dSsnj * defaultString (which normally is a single "#", but could be 1730956cc18dSsnj * whatever the user wants). 1731956cc18dSsnj */ 1732956cc18dSsnj if (fails) { 17332e4f8982Smrg const Char *p; 17342e4f8982Smrg 1735492d43a5Smrg for (p = (const Char *) screen->default_string; *p != '\0'; ++p) { 173620d2c4d2Smrg AddChar(&buffer, &used, offset, *p); 1737d522f475Smrg } 1738d522f475Smrg } 1739956cc18dSsnj if (extra) 174020d2c4d2Smrg AddChar(&buffer, &used, offset, ' '); 1741d522f475Smrg } 174220d2c4d2Smrg AddChar(&buffer, &used, offset, '\0'); 174320d2c4d2Smrg *result = (unsigned long) (offset - 1); 1744d522f475Smrg } else { 1745d522f475Smrg *result = 0; 1746d522f475Smrg } 1747d522f475Smrg return buffer; 1748d522f475Smrg} 174920d2c4d2Smrg 175020d2c4d2Smrgint 175120d2c4d2SmrgxtermUtf8ToTextList(XtermWidget xw, 175220d2c4d2Smrg XTextProperty * text_prop, 175320d2c4d2Smrg char ***text_list, 175420d2c4d2Smrg int *text_list_count) 175520d2c4d2Smrg{ 175620d2c4d2Smrg TScreen *screen = TScreenOf(xw); 175720d2c4d2Smrg Display *dpy = screen->display; 175820d2c4d2Smrg int rc = -1; 175920d2c4d2Smrg 176020d2c4d2Smrg if (text_prop->format == 8 176120d2c4d2Smrg && (rc = Xutf8TextPropertyToTextList(dpy, text_prop, 176220d2c4d2Smrg text_list, 176320d2c4d2Smrg text_list_count)) >= 0) { 176420d2c4d2Smrg if (*text_list != NULL && *text_list_count != 0) { 176520d2c4d2Smrg int i; 176620d2c4d2Smrg Char *data; 176720d2c4d2Smrg char **new_text_list, *tmp; 176820d2c4d2Smrg unsigned long size, new_size; 176920d2c4d2Smrg 177020d2c4d2Smrg TRACE(("xtermUtf8ToTextList size %d\n", *text_list_count)); 177120d2c4d2Smrg 177220d2c4d2Smrg /* 177320d2c4d2Smrg * XLib StringList actually uses only two pointers, one for the 177420d2c4d2Smrg * list itself, and one for the data. Pointer to the data is the 177520d2c4d2Smrg * first element of the list, the rest (if any) list elements point 177620d2c4d2Smrg * to the same memory block as the first element 177720d2c4d2Smrg */ 177820d2c4d2Smrg new_size = 0; 177920d2c4d2Smrg for (i = 0; i < *text_list_count; ++i) { 178020d2c4d2Smrg data = (Char *) (*text_list)[i]; 178120d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 178220d2c4d2Smrg (void) UTF8toLatin1(screen, data, size, &size); 178320d2c4d2Smrg new_size += size + 1; 178420d2c4d2Smrg } 1785a1f3da82Smrg new_text_list = TypeXtMallocN(char *, *text_list_count); 178620d2c4d2Smrg new_text_list[0] = tmp = XtMalloc((Cardinal) new_size); 178720d2c4d2Smrg for (i = 0; i < (*text_list_count); ++i) { 178820d2c4d2Smrg data = (Char *) (*text_list)[i]; 178920d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 17900bd37d32Smrg if ((data = UTF8toLatin1(screen, data, size, &size)) != 0) { 17910bd37d32Smrg memcpy(tmp, data, size + 1); 17920bd37d32Smrg new_text_list[i] = tmp; 17930bd37d32Smrg tmp += size + 1; 17940bd37d32Smrg } 179520d2c4d2Smrg } 179620d2c4d2Smrg XFreeStringList((*text_list)); 179720d2c4d2Smrg *text_list = new_text_list; 179820d2c4d2Smrg } else { 179920d2c4d2Smrg rc = -1; 180020d2c4d2Smrg } 180120d2c4d2Smrg } 180220d2c4d2Smrg return rc; 180320d2c4d2Smrg} 1804d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1805d522f475Smrg 1806956cc18dSsnjstatic char * 1807956cc18dSsnjparseItem(char *value, char *nextc) 1808d522f475Smrg{ 1809956cc18dSsnj char *nextp = value; 1810956cc18dSsnj while (*nextp != '\0' && *nextp != ',') { 1811956cc18dSsnj *nextp = x_toupper(*nextp); 1812956cc18dSsnj ++nextp; 1813956cc18dSsnj } 1814956cc18dSsnj *nextc = *nextp; 1815956cc18dSsnj *nextp = '\0'; 1816d522f475Smrg 1817956cc18dSsnj return nextp; 1818956cc18dSsnj} 1819d522f475Smrg 1820956cc18dSsnj/* 1821956cc18dSsnj * All of the wanted strings are unique in the first character, so we can 1822956cc18dSsnj * use simple abbreviations. 1823956cc18dSsnj */ 1824956cc18dSsnjstatic Bool 1825956cc18dSsnjsameItem(const char *actual, const char *wanted) 1826956cc18dSsnj{ 1827956cc18dSsnj Bool result = False; 1828956cc18dSsnj size_t have = strlen(actual); 1829956cc18dSsnj size_t need = strlen(wanted); 1830d522f475Smrg 1831956cc18dSsnj if (have != 0 && have <= need) { 1832956cc18dSsnj if (!strncmp(actual, wanted, have)) { 1833956cc18dSsnj TRACE(("...matched \"%s\"\n", wanted)); 1834956cc18dSsnj result = True; 1835956cc18dSsnj } 1836956cc18dSsnj } 1837956cc18dSsnj 1838956cc18dSsnj return result; 1839956cc18dSsnj} 1840956cc18dSsnj 1841956cc18dSsnj/* 1842956cc18dSsnj * Handle the eightBitSelectTypes or utf8SelectTypes resource values. 1843956cc18dSsnj */ 1844956cc18dSsnjstatic Bool 1845894e0ac8SmrgoverrideTargets(Widget w, String value, Atom **resultp) 1846956cc18dSsnj{ 1847956cc18dSsnj Bool override = False; 1848956cc18dSsnj XtermWidget xw; 1849956cc18dSsnj 1850956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1851956cc18dSsnj TScreen *screen = TScreenOf(xw); 1852956cc18dSsnj 185320d2c4d2Smrg if (!IsEmpty(value)) { 1854492d43a5Smrg char *copied = x_strdup(value); 1855956cc18dSsnj if (copied != 0) { 1856956cc18dSsnj Atom *result = 0; 1857956cc18dSsnj Cardinal count = 1; 1858956cc18dSsnj int n; 1859d522f475Smrg 1860956cc18dSsnj TRACE(("decoding SelectTypes \"%s\"\n", value)); 1861956cc18dSsnj for (n = 0; copied[n] != '\0'; ++n) { 1862956cc18dSsnj if (copied[n] == ',') 1863956cc18dSsnj ++count; 1864956cc18dSsnj } 1865a1f3da82Smrg result = TypeXtMallocN(Atom, (2 * count) + 1); 1866956cc18dSsnj if (result == NULL) { 1867956cc18dSsnj TRACE(("Couldn't allocate selection types\n")); 1868956cc18dSsnj } else { 1869956cc18dSsnj char nextc = '?'; 187020d2c4d2Smrg char *listp = (char *) copied; 1871956cc18dSsnj count = 0; 1872956cc18dSsnj do { 1873956cc18dSsnj char *nextp = parseItem(listp, &nextc); 18740bd37d32Smrg char *item = x_strtrim(listp); 18750bd37d32Smrg size_t len = (item ? strlen(item) : 0); 1876956cc18dSsnj 1877956cc18dSsnj if (len == 0) { 1878a1f3da82Smrg /* EMPTY */ ; 1879956cc18dSsnj } 1880956cc18dSsnj#if OPT_WIDE_CHARS 18810bd37d32Smrg else if (sameItem(item, "UTF8")) { 1882956cc18dSsnj result[count++] = XA_UTF8_STRING(XtDisplay(w)); 1883956cc18dSsnj } 1884956cc18dSsnj#endif 18850bd37d32Smrg else if (sameItem(item, "I18N")) { 1886956cc18dSsnj if (screen->i18nSelections) { 1887956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 1888956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1889956cc18dSsnj } 18900bd37d32Smrg } else if (sameItem(item, "TEXT")) { 1891956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 18920bd37d32Smrg } else if (sameItem(item, "COMPOUND_TEXT")) { 1893956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 18940bd37d32Smrg } else if (sameItem(item, "STRING")) { 1895956cc18dSsnj result[count++] = XA_STRING; 1896956cc18dSsnj } 1897956cc18dSsnj *nextp++ = nextc; 1898956cc18dSsnj listp = nextp; 18990bd37d32Smrg free(item); 1900956cc18dSsnj } while (nextc != '\0'); 1901956cc18dSsnj if (count) { 1902956cc18dSsnj result[count] = None; 1903956cc18dSsnj override = True; 1904956cc18dSsnj *resultp = result; 1905956cc18dSsnj } else { 1906956cc18dSsnj XtFree((char *) result); 1907956cc18dSsnj } 1908956cc18dSsnj } 19090bd37d32Smrg free(copied); 1910956cc18dSsnj } else { 1911956cc18dSsnj TRACE(("Couldn't allocate copy of selection types\n")); 1912d522f475Smrg } 1913956cc18dSsnj } 1914956cc18dSsnj } 1915956cc18dSsnj return override; 1916956cc18dSsnj} 1917956cc18dSsnj 1918956cc18dSsnj#if OPT_WIDE_CHARS 1919956cc18dSsnjstatic Atom * 1920e0a2b6dfSmrgallocUtf8Targets(Widget w, TScreen *screen) 1921956cc18dSsnj{ 1922956cc18dSsnj Atom **resultp = &(screen->selection_targets_utf8); 1923956cc18dSsnj 1924956cc18dSsnj if (*resultp == 0) { 1925956cc18dSsnj Atom *result; 1926956cc18dSsnj 1927956cc18dSsnj if (!overrideTargets(w, screen->utf8_select_types, &result)) { 1928a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1929956cc18dSsnj if (result == NULL) { 1930956cc18dSsnj TRACE(("Couldn't allocate utf-8 selection targets\n")); 1931956cc18dSsnj } else { 1932956cc18dSsnj int n = 0; 1933956cc18dSsnj 1934e39b573cSmrg if (XSupportsLocale()) { 1935e39b573cSmrg result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1936d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1937e39b573cSmrg if (screen->i18nSelections) { 1938e39b573cSmrg result[n++] = XA_TEXT(XtDisplay(w)); 1939e39b573cSmrg result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1940e39b573cSmrg } 1941d522f475Smrg#endif 1942e39b573cSmrg } 1943956cc18dSsnj result[n++] = XA_STRING; 1944956cc18dSsnj result[n] = None; 1945956cc18dSsnj } 1946d522f475Smrg } 1947956cc18dSsnj 1948956cc18dSsnj *resultp = result; 1949d522f475Smrg } 1950956cc18dSsnj 1951956cc18dSsnj return *resultp; 1952956cc18dSsnj} 1953d522f475Smrg#endif 1954d522f475Smrg 1955956cc18dSsnjstatic Atom * 1956e0a2b6dfSmrgalloc8bitTargets(Widget w, TScreen *screen) 1957956cc18dSsnj{ 1958956cc18dSsnj Atom **resultp = &(screen->selection_targets_8bit); 1959956cc18dSsnj 1960956cc18dSsnj if (*resultp == 0) { 1961956cc18dSsnj Atom *result = 0; 1962956cc18dSsnj 1963956cc18dSsnj if (!overrideTargets(w, screen->eightbit_select_types, &result)) { 1964a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1965956cc18dSsnj if (result == NULL) { 1966956cc18dSsnj TRACE(("Couldn't allocate 8bit selection targets\n")); 1967956cc18dSsnj } else { 1968956cc18dSsnj int n = 0; 1969956cc18dSsnj 1970e39b573cSmrg if (XSupportsLocale()) { 1971d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1972e39b573cSmrg result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1973956cc18dSsnj#endif 1974e39b573cSmrg if (screen->i18nSelections) { 1975e39b573cSmrg result[n++] = XA_TEXT(XtDisplay(w)); 1976e39b573cSmrg result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1977e39b573cSmrg } 1978956cc18dSsnj } 1979956cc18dSsnj result[n++] = XA_STRING; 1980956cc18dSsnj result[n] = None; 1981956cc18dSsnj } 1982956cc18dSsnj } 1983956cc18dSsnj 1984956cc18dSsnj *resultp = result; 1985956cc18dSsnj } 1986956cc18dSsnj 1987956cc18dSsnj return *resultp; 1988956cc18dSsnj} 1989956cc18dSsnj 1990956cc18dSsnjstatic Atom * 1991956cc18dSsnj_SelectionTargets(Widget w) 1992956cc18dSsnj{ 1993956cc18dSsnj Atom *result; 1994956cc18dSsnj XtermWidget xw; 1995956cc18dSsnj 1996956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) { 1997956cc18dSsnj result = NULL; 1998956cc18dSsnj } else { 19992e4f8982Smrg TScreen *screen = TScreenOf(xw); 2000956cc18dSsnj 2001956cc18dSsnj#if OPT_WIDE_CHARS 2002956cc18dSsnj if (screen->wide_chars) { 2003956cc18dSsnj result = allocUtf8Targets(w, screen); 2004956cc18dSsnj } else 2005d522f475Smrg#endif 2006956cc18dSsnj { 2007956cc18dSsnj /* not screen->wide_chars */ 2008956cc18dSsnj result = alloc8bitTargets(w, screen); 2009d522f475Smrg } 2010d522f475Smrg } 2011956cc18dSsnj 2012956cc18dSsnj return result; 2013d522f475Smrg} 2014d522f475Smrg 2015d522f475Smrg#define isSELECT(value) (!strcmp(value, "SELECT")) 2016d522f475Smrg 2017f2e35a3aSmrgstatic int 2018f2e35a3aSmrgDefaultSelection(TScreen *screen) 2019f2e35a3aSmrg{ 2020f2e35a3aSmrg return (screen->selectToClipboard ? 1 : 0); 2021f2e35a3aSmrg} 2022f2e35a3aSmrg 2023f2e35a3aSmrgstatic int 2024f2e35a3aSmrgTargetToSelection(TScreen *screen, String name) 2025f2e35a3aSmrg{ 2026f2e35a3aSmrg int result = -1; 2027f2e35a3aSmrg int cutb; 2028f2e35a3aSmrg 2029f2e35a3aSmrg if (isSELECT(name)) { 2030f2e35a3aSmrg result = DefaultSelection(screen); 2031f2e35a3aSmrg } else if (!strcmp(name, PRIMARY_NAME)) { 2032f2e35a3aSmrg result = PRIMARY_CODE; 2033f2e35a3aSmrg } else if (!strcmp(name, CLIPBOARD_NAME)) { 2034f2e35a3aSmrg result = CLIPBOARD_CODE; 2035f2e35a3aSmrg } else if (!strcmp(name, SECONDARY_NAME)) { 2036f2e35a3aSmrg result = SECONDARY_CODE; 2037f2e35a3aSmrg } else if (sscanf(name, "CUT_BUFFER%d", &cutb) == 1) { 2038f2e35a3aSmrg if (cutb >= 0 && cutb < MAX_CUT_BUFFER) { 2039f2e35a3aSmrg result = CutBufferToCode(cutb); 2040f2e35a3aSmrg } else { 2041f2e35a3aSmrg xtermWarning("unexpected cut-buffer code: %d\n", cutb); 2042f2e35a3aSmrg } 2043f2e35a3aSmrg } else { 2044f2e35a3aSmrg xtermWarning("unexpected selection target: %s\n", name); 2045f2e35a3aSmrg } 2046f2e35a3aSmrg TRACE2(("TargetToSelection(%s) ->%d\n", name, result)); 2047f2e35a3aSmrg return result; 2048f2e35a3aSmrg} 2049f2e35a3aSmrg 2050f2e35a3aSmrgvoid 2051d522f475SmrgUnmapSelections(XtermWidget xw) 2052d522f475Smrg{ 2053956cc18dSsnj TScreen *screen = TScreenOf(xw); 2054d522f475Smrg Cardinal n; 2055d522f475Smrg 2056d522f475Smrg if (screen->mappedSelect) { 2057d522f475Smrg for (n = 0; screen->mappedSelect[n] != 0; ++n) 205820d2c4d2Smrg free((void *) screen->mappedSelect[n]); 2059f2e35a3aSmrg FreeAndNull(screen->mappedSelect); 2060d522f475Smrg } 2061d522f475Smrg} 2062d522f475Smrg 2063d522f475Smrg/* 2064d522f475Smrg * xterm generally uses the primary selection. Some applications prefer 2065d522f475Smrg * (or are limited to) the clipboard. Since the translations resource is 2066d522f475Smrg * complicated, users seldom change the way it affects selection. But it 2067d522f475Smrg * is simple to remap the choice between primary and clipboard before the 2068d522f475Smrg * call to XmuInternStrings(). 2069d522f475Smrg */ 2070d522f475Smrgstatic String * 2071e0a2b6dfSmrgMapSelections(XtermWidget xw, String *params, Cardinal num_params) 2072d522f475Smrg{ 2073d522f475Smrg String *result = params; 2074d522f475Smrg 2075913cc679Smrg if (params != 0 && num_params > 0) { 2076d522f475Smrg Cardinal j; 2077d522f475Smrg Boolean map = False; 2078d522f475Smrg 2079d522f475Smrg for (j = 0; j < num_params; ++j) { 2080d522f475Smrg TRACE(("param[%d]:%s\n", j, params[j])); 2081d522f475Smrg if (isSELECT(params[j])) { 2082d522f475Smrg map = True; 2083d522f475Smrg break; 2084d522f475Smrg } 2085d522f475Smrg } 2086d522f475Smrg if (map) { 2087956cc18dSsnj TScreen *screen = TScreenOf(xw); 2088956cc18dSsnj const char *mapTo = (screen->selectToClipboard 2089f2e35a3aSmrg ? CLIPBOARD_NAME 2090f2e35a3aSmrg : PRIMARY_NAME); 2091d522f475Smrg 2092d522f475Smrg UnmapSelections(xw); 2093d522f475Smrg if ((result = TypeMallocN(String, num_params + 1)) != 0) { 2094d522f475Smrg result[num_params] = 0; 2095d522f475Smrg for (j = 0; j < num_params; ++j) { 2096d522f475Smrg result[j] = x_strdup((isSELECT(params[j]) 2097d522f475Smrg ? mapTo 2098d522f475Smrg : params[j])); 2099d522f475Smrg if (result[j] == 0) { 2100d522f475Smrg UnmapSelections(xw); 21010bd37d32Smrg while (j != 0) { 21020bd37d32Smrg free((void *) result[--j]); 21030bd37d32Smrg } 2104f2e35a3aSmrg FreeAndNull(result); 2105d522f475Smrg break; 2106d522f475Smrg } 2107d522f475Smrg } 2108956cc18dSsnj screen->mappedSelect = result; 2109d522f475Smrg } 2110d522f475Smrg } 2111d522f475Smrg } 2112d522f475Smrg return result; 2113d522f475Smrg} 2114d522f475Smrg 2115d522f475Smrg/* 2116d522f475Smrg * Lookup the cut-buffer number, which will be in the range 0-7. 2117f2e35a3aSmrg * If it is not a cut-buffer, it is a type of selection, e.g., primary. 2118d522f475Smrg */ 2119d522f475Smrgstatic int 212020d2c4d2SmrgCutBuffer(Atom code) 2121d522f475Smrg{ 2122d522f475Smrg int cutbuffer; 212320d2c4d2Smrg switch ((unsigned) code) { 2124d522f475Smrg case XA_CUT_BUFFER0: 2125d522f475Smrg cutbuffer = 0; 2126d522f475Smrg break; 2127d522f475Smrg case XA_CUT_BUFFER1: 2128d522f475Smrg cutbuffer = 1; 2129d522f475Smrg break; 2130d522f475Smrg case XA_CUT_BUFFER2: 2131d522f475Smrg cutbuffer = 2; 2132d522f475Smrg break; 2133d522f475Smrg case XA_CUT_BUFFER3: 2134d522f475Smrg cutbuffer = 3; 2135d522f475Smrg break; 2136d522f475Smrg case XA_CUT_BUFFER4: 2137d522f475Smrg cutbuffer = 4; 2138d522f475Smrg break; 2139d522f475Smrg case XA_CUT_BUFFER5: 2140d522f475Smrg cutbuffer = 5; 2141d522f475Smrg break; 2142d522f475Smrg case XA_CUT_BUFFER6: 2143d522f475Smrg cutbuffer = 6; 2144d522f475Smrg break; 2145d522f475Smrg case XA_CUT_BUFFER7: 2146d522f475Smrg cutbuffer = 7; 2147d522f475Smrg break; 2148d522f475Smrg default: 2149d522f475Smrg cutbuffer = -1; 2150d522f475Smrg break; 2151d522f475Smrg } 2152f2e35a3aSmrg TRACE2(("CutBuffer(%d) = %d\n", (int) code, cutbuffer)); 2153d522f475Smrg return cutbuffer; 2154d522f475Smrg} 2155d522f475Smrg 2156d522f475Smrg#if OPT_PASTE64 2157d522f475Smrgstatic void 2158d522f475SmrgFinishPaste64(XtermWidget xw) 2159d522f475Smrg{ 2160956cc18dSsnj TScreen *screen = TScreenOf(xw); 2161956cc18dSsnj 2162956cc18dSsnj TRACE(("FinishPaste64(%d)\n", screen->base64_paste)); 2163956cc18dSsnj if (screen->base64_paste) { 2164956cc18dSsnj screen->base64_paste = 0; 2165956cc18dSsnj unparseputc1(xw, screen->base64_final); 2166d522f475Smrg unparse_end(xw); 2167d522f475Smrg } 2168d522f475Smrg} 2169d522f475Smrg#endif 2170d522f475Smrg 2171d522f475Smrg#if !OPT_PASTE64 2172d522f475Smrgstatic 2173d522f475Smrg#endif 2174d522f475Smrgvoid 2175d522f475SmrgxtermGetSelection(Widget w, 2176d522f475Smrg Time ev_time, 2177e0a2b6dfSmrg String *params, /* selections in precedence order */ 2178d522f475Smrg Cardinal num_params, 2179894e0ac8Smrg Atom *targets) 2180d522f475Smrg{ 2181d522f475Smrg Atom selection; 2182d522f475Smrg int cutbuffer; 2183d522f475Smrg Atom target; 2184d522f475Smrg 2185956cc18dSsnj XtermWidget xw; 2186956cc18dSsnj 218720d2c4d2Smrg if (num_params == 0) 218820d2c4d2Smrg return; 2189956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 2190d522f475Smrg return; 2191d522f475Smrg 2192e0a2b6dfSmrg TRACE(("xtermGetSelection num_params %d @%ld\n", num_params, ev_time)); 2193956cc18dSsnj params = MapSelections(xw, params, num_params); 2194d522f475Smrg 2195d522f475Smrg XmuInternStrings(XtDisplay(w), params, (Cardinal) 1, &selection); 2196d522f475Smrg cutbuffer = CutBuffer(selection); 2197d522f475Smrg 2198956cc18dSsnj TRACE(("Cutbuffer: %d, target: %s\n", cutbuffer, 2199956cc18dSsnj (targets 2200956cc18dSsnj ? visibleSelectionTarget(XtDisplay(w), targets[0]) 2201956cc18dSsnj : "None"))); 2202d522f475Smrg 2203d522f475Smrg if (cutbuffer >= 0) { 2204d522f475Smrg int inbytes; 2205d522f475Smrg unsigned long nbytes; 2206d522f475Smrg int fmt8 = 8; 2207d522f475Smrg Atom type = XA_STRING; 2208d522f475Smrg char *line; 2209d522f475Smrg 2210d522f475Smrg /* 'line' is freed in SelectionReceived */ 2211d522f475Smrg line = XFetchBuffer(XtDisplay(w), &inbytes, cutbuffer); 2212d522f475Smrg nbytes = (unsigned long) inbytes; 2213d522f475Smrg 22140bd37d32Smrg if (nbytes > 0) { 2215d522f475Smrg SelectionReceived(w, NULL, &selection, &type, (XtPointer) line, 2216d522f475Smrg &nbytes, &fmt8); 22170bd37d32Smrg } else if (num_params > 1) { 2218d522f475Smrg xtermGetSelection(w, ev_time, params + 1, num_params - 1, NULL); 2219d522f475Smrg } 2220d522f475Smrg#if OPT_PASTE64 2221d522f475Smrg else { 2222956cc18dSsnj FinishPaste64(xw); 2223d522f475Smrg } 2224d522f475Smrg#endif 2225d522f475Smrg } else { 2226d522f475Smrg 2227d522f475Smrg if (targets == NULL || targets[0] == None) { 2228d522f475Smrg targets = _SelectionTargets(w); 2229d522f475Smrg } 2230d522f475Smrg 2231d522f475Smrg if (targets != 0) { 22322e4f8982Smrg struct _SelectionList *list; 22332e4f8982Smrg 2234d522f475Smrg target = targets[0]; 2235d522f475Smrg 2236d522f475Smrg if (targets[1] == None) { /* last target in list */ 2237d522f475Smrg params++; 2238d522f475Smrg num_params--; 2239d522f475Smrg targets = _SelectionTargets(w); 2240d522f475Smrg } else { 2241d522f475Smrg targets = &(targets[1]); 2242d522f475Smrg } 2243d522f475Smrg 2244d522f475Smrg if (num_params) { 2245d522f475Smrg /* 'list' is freed in SelectionReceived */ 2246a1f3da82Smrg list = TypeXtMalloc(struct _SelectionList); 2247d522f475Smrg if (list != 0) { 2248d522f475Smrg list->params = params; 2249d522f475Smrg list->count = num_params; 2250d522f475Smrg list->targets = targets; 2251d522f475Smrg list->time = ev_time; 2252d522f475Smrg } 2253d522f475Smrg } else { 2254d522f475Smrg list = NULL; 2255d522f475Smrg } 2256d522f475Smrg 2257d522f475Smrg XtGetSelectionValue(w, selection, 2258d522f475Smrg target, 2259d522f475Smrg SelectionReceived, 2260d522f475Smrg (XtPointer) list, ev_time); 2261d522f475Smrg } 2262d522f475Smrg } 2263d522f475Smrg} 2264d522f475Smrg 2265d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 2266d522f475Smrgstatic void 2267e0a2b6dfSmrgGettingSelection(Display *dpy, Atom type, Char *line, unsigned long len) 2268d522f475Smrg{ 2269d522f475Smrg Char *cp; 2270913cc679Smrg const char *name = TraceAtomName(dpy, type); 2271d522f475Smrg 227201037d57Smrg TRACE(("Getting %s (type=%ld, length=%ld)\n", name, (long int) type, len)); 2273d522f475Smrg for (cp = line; cp < line + len; cp++) { 2274956cc18dSsnj TRACE(("[%d:%lu]", (int) (cp + 1 - line), len)); 2275d522f475Smrg if (isprint(*cp)) { 2276d522f475Smrg TRACE(("%c\n", *cp)); 2277d522f475Smrg } else { 2278d522f475Smrg TRACE(("\\x%02x\n", *cp)); 2279d522f475Smrg } 2280d522f475Smrg } 2281d522f475Smrg} 2282d522f475Smrg#else 2283d522f475Smrg#define GettingSelection(dpy,type,line,len) /* nothing */ 2284d522f475Smrg#endif 2285d522f475Smrg 2286d522f475Smrg#ifdef VMS 2287d522f475Smrg# define tty_vwrite(pty,lag,l) tt_write(lag,l) 2288d522f475Smrg#else /* !( VMS ) */ 2289d522f475Smrg# define tty_vwrite(pty,lag,l) v_write(pty,lag,l) 2290d522f475Smrg#endif /* defined VMS */ 2291d522f475Smrg 2292d522f475Smrg#if OPT_PASTE64 2293d522f475Smrg/* Return base64 code character given 6-bit number */ 2294d522f475Smrgstatic const char base64_code[] = "\ 2295d522f475SmrgABCDEFGHIJKLMNOPQRSTUVWXYZ\ 2296d522f475Smrgabcdefghijklmnopqrstuvwxyz\ 2297d522f475Smrg0123456789+/"; 2298d522f475Smrgstatic void 2299e0a2b6dfSmrgbase64_flush(TScreen *screen) 2300d522f475Smrg{ 2301d522f475Smrg Char x; 230201037d57Smrg 230301037d57Smrg TRACE(("base64_flush count %d, pad %d (%d)\n", 230401037d57Smrg screen->base64_count, 230501037d57Smrg screen->base64_pad, 230601037d57Smrg screen->base64_pad & 3)); 230701037d57Smrg 2308d522f475Smrg switch (screen->base64_count) { 2309d522f475Smrg case 0: 2310d522f475Smrg break; 2311d522f475Smrg case 2: 23122eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 4]); 2313d522f475Smrg tty_vwrite(screen->respond, &x, 1); 2314d522f475Smrg break; 2315d522f475Smrg case 4: 23162eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 2]); 2317d522f475Smrg tty_vwrite(screen->respond, &x, 1); 2318d522f475Smrg break; 2319d522f475Smrg } 232001037d57Smrg if (screen->base64_pad & 3) { 2321d522f475Smrg tty_vwrite(screen->respond, 2322492d43a5Smrg (const Char *) "===", 232301037d57Smrg (unsigned) (3 - (screen->base64_pad & 3))); 232401037d57Smrg } 2325d522f475Smrg screen->base64_count = 0; 2326d522f475Smrg screen->base64_accu = 0; 2327d522f475Smrg screen->base64_pad = 0; 2328d522f475Smrg} 2329d522f475Smrg#endif /* OPT_PASTE64 */ 2330d522f475Smrg 2331e0a2b6dfSmrg/* 2332e0a2b6dfSmrg * Translate ISO-8859-1 or UTF-8 data to NRCS. 2333e0a2b6dfSmrg */ 2334d522f475Smrgstatic void 2335f2e35a3aSmrgToNational(XtermWidget xw, Char *buffer, unsigned *length) 2336e0a2b6dfSmrg{ 2337f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2338f2e35a3aSmrg DECNRCM_codes gsetL = screen->gsets[screen->curgl]; 2339f2e35a3aSmrg DECNRCM_codes gsetR = screen->gsets[screen->curgr]; 2340e0a2b6dfSmrg 2341e0a2b6dfSmrg#if OPT_WIDE_CHARS 2342e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 23432e4f8982Smrg Char *p; 2344e0a2b6dfSmrg PtyData *data = TypeXtMallocX(PtyData, *length); 2345e0a2b6dfSmrg 2346e0a2b6dfSmrg memset(data, 0, sizeof(*data)); 2347e0a2b6dfSmrg data->next = data->buffer; 2348e0a2b6dfSmrg data->last = data->buffer + *length; 2349e0a2b6dfSmrg memcpy(data->buffer, buffer, (size_t) *length); 2350e0a2b6dfSmrg p = buffer; 2351e0a2b6dfSmrg while (data->next < data->last) { 23522e4f8982Smrg unsigned chr, out, gl, gr; 23532e4f8982Smrg 2354894e0ac8Smrg if (!decodeUtf8(screen, data)) { 2355e0a2b6dfSmrg data->utf_size = 1; 2356e0a2b6dfSmrg data->utf_data = data->next[0]; 2357e0a2b6dfSmrg } 2358e0a2b6dfSmrg data->next += data->utf_size; 2359e0a2b6dfSmrg chr = data->utf_data; 2360e0a2b6dfSmrg out = chr; 2361f2e35a3aSmrg if ((gl = xtermCharSetIn(xw, chr, gsetL)) != chr) { 2362e0a2b6dfSmrg out = gl; 2363f2e35a3aSmrg } else if ((gr = xtermCharSetIn(xw, chr, gsetR)) != chr) { 2364e0a2b6dfSmrg out = gr; 2365e0a2b6dfSmrg } 2366e0a2b6dfSmrg *p++ = (Char) ((out < 256) ? out : ' '); 2367e0a2b6dfSmrg } 2368e0a2b6dfSmrg *length = (unsigned) (p - buffer); 2369e0a2b6dfSmrg free(data); 2370e0a2b6dfSmrg } else 2371e0a2b6dfSmrg#endif 2372e0a2b6dfSmrg { 23732e4f8982Smrg Char *p; 23742e4f8982Smrg 2375e0a2b6dfSmrg for (p = buffer; (int) (p - buffer) < (int) *length; ++p) { 23762e4f8982Smrg unsigned gl, gr; 23772e4f8982Smrg unsigned chr = *p; 23782e4f8982Smrg unsigned out = chr; 2379f2e35a3aSmrg if ((gl = xtermCharSetIn(xw, chr, gsetL)) != chr) { 2380e0a2b6dfSmrg out = gl; 2381f2e35a3aSmrg } else if ((gr = xtermCharSetIn(xw, chr, gsetR)) != chr) { 2382e0a2b6dfSmrg out = gr; 2383e0a2b6dfSmrg } 2384e0a2b6dfSmrg *p = (Char) out; 2385e0a2b6dfSmrg } 2386e0a2b6dfSmrg } 2387e0a2b6dfSmrg} 2388e0a2b6dfSmrg 2389e0a2b6dfSmrgstatic void 2390e0a2b6dfSmrg_qWriteSelectionData(XtermWidget xw, Char *lag, unsigned length) 2391d522f475Smrg{ 23920bd37d32Smrg TScreen *screen = TScreenOf(xw); 23930bd37d32Smrg 2394e0a2b6dfSmrg /* 2395e0a2b6dfSmrg * If we are pasting into a window which is using NRCS, we want to map 2396e0a2b6dfSmrg * the text from the normal encoding (ISO-8859-1 or UTF-8) into the coding 2397e0a2b6dfSmrg * that an application would use to write characters with NRCS. 2398e0a2b6dfSmrg * 2399e0a2b6dfSmrg * TODO: handle conversion from UTF-8, and adjust length. This can be done 2400e0a2b6dfSmrg * in the same buffer because the target is always 8-bit. 2401e0a2b6dfSmrg */ 2402e0a2b6dfSmrg if ((xw->flags & NATIONAL) && (length != 0)) { 2403f2e35a3aSmrg ToNational(xw, lag, &length); 2404e0a2b6dfSmrg } 2405d522f475Smrg#if OPT_PASTE64 2406d522f475Smrg if (screen->base64_paste) { 2407d522f475Smrg /* Send data as base64 */ 2408d522f475Smrg Char *p = lag; 2409d522f475Smrg Char buf[64]; 2410d522f475Smrg unsigned x = 0; 24110bd37d32Smrg 241201037d57Smrg TRACE(("convert to base64 %d:%s\n", length, visibleChars(p, length))); 241301037d57Smrg 24140bd37d32Smrg /* 24150bd37d32Smrg * Handle the case where the selection is from _this_ xterm, which 24160bd37d32Smrg * puts part of the reply in the buffer before the selection callback 24170bd37d32Smrg * happens. 24180bd37d32Smrg */ 24190bd37d32Smrg if (screen->base64_paste && screen->unparse_len) { 24200bd37d32Smrg unparse_end(xw); 24210bd37d32Smrg } 2422d522f475Smrg while (length--) { 2423d522f475Smrg switch (screen->base64_count) { 2424d522f475Smrg case 0: 24252eaa94a1Schristos buf[x++] = CharOf(base64_code[*p >> 2]); 24262eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0x3); 2427d522f475Smrg screen->base64_count = 2; 2428d522f475Smrg ++p; 2429d522f475Smrg break; 2430d522f475Smrg case 2: 24312eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 4) + 24322eaa94a1Schristos (*p >> 4)]); 24332eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0xF); 2434d522f475Smrg screen->base64_count = 4; 2435d522f475Smrg ++p; 2436d522f475Smrg break; 2437d522f475Smrg case 4: 24382eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 2) + 24392eaa94a1Schristos (*p >> 6)]); 24402eaa94a1Schristos buf[x++] = CharOf(base64_code[*p & 0x3F]); 2441d522f475Smrg screen->base64_accu = 0; 2442d522f475Smrg screen->base64_count = 0; 2443d522f475Smrg ++p; 2444d522f475Smrg break; 2445d522f475Smrg } 2446d522f475Smrg if (x >= 63) { 2447d522f475Smrg /* Write 63 or 64 characters */ 2448d522f475Smrg screen->base64_pad += x; 244901037d57Smrg TRACE(("writing base64 interim %s\n", visibleChars(buf, x))); 2450d522f475Smrg tty_vwrite(screen->respond, buf, x); 2451d522f475Smrg x = 0; 2452d522f475Smrg } 2453d522f475Smrg } 2454d522f475Smrg if (x != 0) { 2455d522f475Smrg screen->base64_pad += x; 245601037d57Smrg TRACE(("writing base64 finish %s\n", visibleChars(buf, x))); 2457d522f475Smrg tty_vwrite(screen->respond, buf, x); 2458d522f475Smrg } 2459d522f475Smrg } else 2460d522f475Smrg#endif /* OPT_PASTE64 */ 2461d522f475Smrg#if OPT_READLINE 2462d522f475Smrg if (SCREEN_FLAG(screen, paste_quotes)) { 2463d522f475Smrg while (length--) { 2464492d43a5Smrg tty_vwrite(screen->respond, (const Char *) "\026", 1); /* Control-V */ 2465d522f475Smrg tty_vwrite(screen->respond, lag++, 1); 2466d522f475Smrg } 2467d522f475Smrg } else 2468d522f475Smrg#endif 246901037d57Smrg { 247001037d57Smrg TRACE(("writing base64 padding %s\n", visibleChars(lag, length))); 2471d522f475Smrg tty_vwrite(screen->respond, lag, length); 247201037d57Smrg } 2473d522f475Smrg} 2474d522f475Smrg 2475d522f475Smrgstatic void 2476e0a2b6dfSmrg_WriteSelectionData(XtermWidget xw, Char *line, size_t length) 2477d522f475Smrg{ 2478d522f475Smrg /* Write data to pty a line at a time. */ 2479d522f475Smrg /* Doing this one line at a time may no longer be necessary 2480d522f475Smrg because v_write has been re-written. */ 2481d522f475Smrg 24822e4f8982Smrg#if OPT_PASTE64 24830bd37d32Smrg TScreen *screen = TScreenOf(xw); 24842e4f8982Smrg#endif 2485d522f475Smrg Char *lag, *end; 2486d522f475Smrg 2487d522f475Smrg /* in the VMS version, if tt_pasting isn't set to True then qio 2488d522f475Smrg reads aren't blocked and an infinite loop is entered, where the 2489d522f475Smrg pasted text shows up as new input, goes in again, shows up 2490d522f475Smrg again, ad nauseum. */ 2491d522f475Smrg#ifdef VMS 2492d522f475Smrg tt_pasting = True; 2493d522f475Smrg#endif 2494d522f475Smrg 2495d522f475Smrg end = &line[length]; 2496d522f475Smrg lag = line; 2497d522f475Smrg 2498d522f475Smrg#if OPT_PASTE64 2499d522f475Smrg if (screen->base64_paste) { 25000bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (end - lag)); 2501d522f475Smrg base64_flush(screen); 2502d522f475Smrg } else 2503d522f475Smrg#endif 2504d522f475Smrg { 2505d522f475Smrg if (!SCREEN_FLAG(screen, paste_literal_nl)) { 2506d522f475Smrg Char *cp; 2507d522f475Smrg for (cp = line; cp != end; cp++) { 2508d522f475Smrg if (*cp == '\n') { 2509d522f475Smrg *cp = '\r'; 25100bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (cp - lag + 1)); 2511d522f475Smrg lag = cp + 1; 2512d522f475Smrg } 2513d522f475Smrg } 2514d522f475Smrg } 2515d522f475Smrg 2516d522f475Smrg if (lag != end) { 25170bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (end - lag)); 2518d522f475Smrg } 2519d522f475Smrg } 2520d522f475Smrg#ifdef VMS 2521d522f475Smrg tt_pasting = False; 2522d522f475Smrg tt_start_read(); /* reenable reads or a character may be lost */ 2523d522f475Smrg#endif 2524d522f475Smrg} 2525d522f475Smrg 2526f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2527d522f475Smrgstatic void 2528e0a2b6dfSmrg_WriteKey(TScreen *screen, const Char *in) 2529d522f475Smrg{ 2530d522f475Smrg Char line[16]; 2531d522f475Smrg unsigned count = 0; 2532492d43a5Smrg size_t length = strlen((const char *) in); 2533d522f475Smrg 2534d522f475Smrg if (screen->control_eight_bits) { 2535d522f475Smrg line[count++] = ANSI_CSI; 2536d522f475Smrg } else { 2537d522f475Smrg line[count++] = ANSI_ESC; 2538d522f475Smrg line[count++] = '['; 2539d522f475Smrg } 2540d522f475Smrg while (length--) 2541d522f475Smrg line[count++] = *in++; 2542d522f475Smrg line[count++] = '~'; 2543d522f475Smrg tty_vwrite(screen->respond, line, count); 2544d522f475Smrg} 2545d522f475Smrg#endif /* OPT_READLINE */ 2546d522f475Smrg 25470bd37d32Smrg/* 25480bd37d32Smrg * Unless enabled by the user, strip control characters other than formatting. 25490bd37d32Smrg */ 25500bd37d32Smrgstatic size_t 25510bd37d32SmrgremoveControls(XtermWidget xw, char *value) 25520bd37d32Smrg{ 25530bd37d32Smrg TScreen *screen = TScreenOf(xw); 25540bd37d32Smrg size_t dst = 0; 25550bd37d32Smrg 25560bd37d32Smrg if (screen->allowPasteControls) { 25570bd37d32Smrg dst = strlen(value); 25580bd37d32Smrg } else { 25592e4f8982Smrg size_t src = 0; 25600bd37d32Smrg while ((value[dst] = value[src]) != '\0') { 25610bd37d32Smrg int ch = CharOf(value[src++]); 2562f2e35a3aSmrg 2563f2e35a3aSmrg#define ReplacePaste(n) \ 2564f2e35a3aSmrg if (screen->disallow_paste_controls[n]) \ 2565f2e35a3aSmrg value[dst] = ' ' 2566f2e35a3aSmrg 25670bd37d32Smrg if (ch < 32) { 2568f2e35a3aSmrg ReplacePaste(epC0); 2569f2e35a3aSmrg ReplacePaste(ch); 2570f2e35a3aSmrg ++dst; 2571f2e35a3aSmrg } else if (ch == ANSI_DEL) { 2572f2e35a3aSmrg ReplacePaste(epDEL); 2573f2e35a3aSmrg ++dst; 25740bd37d32Smrg } 25750bd37d32Smrg#if OPT_WIDE_CHARS 2576e0a2b6dfSmrg else if (screen->utf8_inparse || screen->utf8_nrc_mode) 25770bd37d32Smrg ++dst; 25780bd37d32Smrg#endif 25790bd37d32Smrg#if OPT_C1_PRINT || OPT_WIDE_CHARS 25800bd37d32Smrg else if (screen->c1_printable) 25810bd37d32Smrg ++dst; 25820bd37d32Smrg#endif 25830bd37d32Smrg else if (ch >= 128 && ch < 160) 25840bd37d32Smrg continue; 25850bd37d32Smrg else 25860bd37d32Smrg ++dst; 25870bd37d32Smrg } 25880bd37d32Smrg } 25890bd37d32Smrg return dst; 25900bd37d32Smrg} 25910bd37d32Smrg 2592f2e35a3aSmrg#if OPT_SELECTION_OPS 2593f2e35a3aSmrgstatic void 2594f2e35a3aSmrgbeginInternalSelect(XtermWidget xw) 2595f2e35a3aSmrg{ 2596f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2597f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2598f2e35a3aSmrg 2599f2e35a3aSmrg (void) mydata; 2600f2e35a3aSmrg /* override flags so that SelectionReceived only updates a buffer */ 2601f2e35a3aSmrg#if OPT_PASTE64 2602f2e35a3aSmrg mydata->base64_paste = screen->base64_paste; 2603f2e35a3aSmrg screen->base64_paste = 0; 2604f2e35a3aSmrg#endif 2605f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2606f2e35a3aSmrg mydata->paste_brackets = screen->paste_brackets; 2607f2e35a3aSmrg SCREEN_FLAG_unset(screen, paste_brackets); 2608f2e35a3aSmrg#endif 2609f2e35a3aSmrg} 2610f2e35a3aSmrg 2611f2e35a3aSmrgstatic void 2612f2e35a3aSmrgfinishInternalSelect(XtermWidget xw) 2613f2e35a3aSmrg{ 2614f2e35a3aSmrg TScreen *screen = TScreenOf(xw); 2615f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2616f2e35a3aSmrg 2617f2e35a3aSmrg (void) mydata; 2618f2e35a3aSmrg#if OPT_PASTE64 2619f2e35a3aSmrg screen->base64_paste = mydata->base64_paste; 2620f2e35a3aSmrg#endif 2621f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2622f2e35a3aSmrg screen->paste_brackets = mydata->paste_brackets; 2623f2e35a3aSmrg#endif 2624f2e35a3aSmrg} 2625f2e35a3aSmrg 2626f2e35a3aSmrg#else 2627f2e35a3aSmrg#define finishInternalSelect(xw) /* nothing */ 2628f2e35a3aSmrg#endif /* OPT_SELECTION_OPS */ 2629f2e35a3aSmrg 2630d522f475Smrg/* SelectionReceived: stuff received selection text into pty */ 2631d522f475Smrg 2632d522f475Smrg/* ARGSUSED */ 2633d522f475Smrgstatic void 2634d522f475SmrgSelectionReceived(Widget w, 2635d522f475Smrg XtPointer client_data, 2636894e0ac8Smrg Atom *selection GCC_UNUSED, 2637894e0ac8Smrg Atom *type, 2638d522f475Smrg XtPointer value, 2639d522f475Smrg unsigned long *length, 2640d522f475Smrg int *format) 2641d522f475Smrg{ 2642d522f475Smrg char **text_list = NULL; 26432e4f8982Smrg int text_list_count = 0; 2644d522f475Smrg XTextProperty text_prop; 2645d522f475Smrg TScreen *screen; 2646d522f475Smrg Display *dpy; 2647d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 2648d522f475Smrg Char *line = (Char *) value; 2649d522f475Smrg#endif 2650d522f475Smrg 2651956cc18dSsnj XtermWidget xw; 2652956cc18dSsnj 2653956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 2654d522f475Smrg return; 2655956cc18dSsnj 2656956cc18dSsnj screen = TScreenOf(xw); 2657d522f475Smrg dpy = XtDisplay(w); 2658d522f475Smrg 2659d522f475Smrg if (*type == 0 /*XT_CONVERT_FAIL */ 2660d522f475Smrg || *length == 0 266101037d57Smrg || value == NULL) { 266201037d57Smrg TRACE(("...no data to convert\n")); 2663d522f475Smrg goto fail; 266401037d57Smrg } 2665d522f475Smrg 2666d522f475Smrg text_prop.value = (unsigned char *) value; 2667d522f475Smrg text_prop.encoding = *type; 2668d522f475Smrg text_prop.format = *format; 2669d522f475Smrg text_prop.nitems = *length; 2670d522f475Smrg 267101037d57Smrg TRACE(("SelectionReceived %s %s format %d, nitems %ld\n", 2672913cc679Smrg TraceAtomName(screen->display, *selection), 2673956cc18dSsnj visibleSelectionTarget(dpy, text_prop.encoding), 2674956cc18dSsnj text_prop.format, 2675956cc18dSsnj text_prop.nitems)); 2676956cc18dSsnj 2677d522f475Smrg#if OPT_WIDE_CHARS 2678e39b573cSmrg if (XSupportsLocale() && screen->wide_chars) { 2679d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2680d522f475Smrg *type == XA_STRING || 2681d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2682d522f475Smrg GettingSelection(dpy, *type, line, *length); 2683d522f475Smrg if (Xutf8TextPropertyToTextList(dpy, &text_prop, 2684d522f475Smrg &text_list, 2685d522f475Smrg &text_list_count) < 0) { 2686e39b573cSmrg TRACE(("default Xutf8 Conversion failed\n")); 2687d522f475Smrg text_list = NULL; 2688d522f475Smrg } 2689d522f475Smrg } 2690d522f475Smrg } else 2691d522f475Smrg#endif /* OPT_WIDE_CHARS */ 2692d522f475Smrg { 2693d522f475Smrg /* Convert the selection to locale's multibyte encoding. */ 2694d522f475Smrg 2695d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2696d522f475Smrg *type == XA_STRING || 2697d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2698d522f475Smrg Status rc; 2699d522f475Smrg 2700d522f475Smrg GettingSelection(dpy, *type, line, *length); 2701d522f475Smrg 2702d522f475Smrg#if OPT_WIDE_CHARS 2703d522f475Smrg if (*type == XA_UTF8_STRING(dpy) && 2704d522f475Smrg !(screen->wide_chars || screen->c1_printable)) { 270520d2c4d2Smrg rc = xtermUtf8ToTextList(xw, &text_prop, 270620d2c4d2Smrg &text_list, &text_list_count); 2707d522f475Smrg } else 2708d522f475Smrg#endif 2709e39b573cSmrg if (*type == XA_STRING && (!XSupportsLocale() || screen->brokenSelections)) { 2710d522f475Smrg rc = XTextPropertyToStringList(&text_prop, 2711d522f475Smrg &text_list, &text_list_count); 2712d522f475Smrg } else { 2713d522f475Smrg rc = XmbTextPropertyToTextList(dpy, &text_prop, 2714d522f475Smrg &text_list, 2715d522f475Smrg &text_list_count); 2716d522f475Smrg } 2717d522f475Smrg if (rc < 0) { 2718d522f475Smrg TRACE(("Conversion failed\n")); 2719d522f475Smrg text_list = NULL; 2720d522f475Smrg } 2721d522f475Smrg } 2722d522f475Smrg } 2723d522f475Smrg 2724d522f475Smrg if (text_list != NULL && text_list_count != 0) { 2725d522f475Smrg int i; 2726d522f475Smrg 2727d522f475Smrg#if OPT_PASTE64 2728d522f475Smrg if (screen->base64_paste) { 2729a1f3da82Smrg /* EMPTY */ ; 2730d522f475Smrg } else 2731d522f475Smrg#endif 2732f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2733f2e35a3aSmrg if (SCREEN_FLAG(screen, paste_brackets) && !screen->selectToBuffer) { 2734492d43a5Smrg _WriteKey(screen, (const Char *) "200"); 2735d522f475Smrg } 2736d522f475Smrg#endif 2737d522f475Smrg for (i = 0; i < text_list_count; i++) { 27380bd37d32Smrg size_t len = removeControls(xw, text_list[i]); 273901037d57Smrg 27400bd37d32Smrg if (screen->selectToBuffer) { 274101037d57Smrg InternalSelect *mydata = &(screen->internal_select); 2742f2e35a3aSmrg if (!mydata->done) { 2743f2e35a3aSmrg size_t have = (mydata->buffer 2744f2e35a3aSmrg ? strlen(mydata->buffer) 2745f2e35a3aSmrg : 0); 2746f2e35a3aSmrg size_t need = have + len + 1; 2747f2e35a3aSmrg char *buffer = realloc(mydata->buffer, need); 2748f2e35a3aSmrg 2749f2e35a3aSmrg if (buffer != 0) { 2750f2e35a3aSmrg strcpy(buffer + have, text_list[i]); 2751f2e35a3aSmrg mydata->buffer = buffer; 2752f2e35a3aSmrg } 2753f2e35a3aSmrg TRACE(("FormatSelect %d.%d .. %d.%d %s\n", 2754f2e35a3aSmrg screen->startSel.row, 2755f2e35a3aSmrg screen->startSel.col, 2756f2e35a3aSmrg screen->endSel.row, 2757f2e35a3aSmrg screen->endSel.col, 2758f2e35a3aSmrg mydata->buffer)); 2759f2e35a3aSmrg mydata->format_select(w, mydata->format, mydata->buffer, 2760f2e35a3aSmrg &(screen->startSel), 2761f2e35a3aSmrg &(screen->endSel)); 2762f2e35a3aSmrg mydata->done = True; 27630bd37d32Smrg } 276401037d57Smrg 27650bd37d32Smrg } else { 27660bd37d32Smrg _WriteSelectionData(xw, (Char *) text_list[i], len); 27670bd37d32Smrg } 2768d522f475Smrg } 2769d522f475Smrg#if OPT_PASTE64 2770d522f475Smrg if (screen->base64_paste) { 2771956cc18dSsnj FinishPaste64(xw); 2772d522f475Smrg } else 2773d522f475Smrg#endif 2774f2e35a3aSmrg#if OPT_PASTE64 || OPT_READLINE 2775f2e35a3aSmrg if (SCREEN_FLAG(screen, paste_brackets) && !screen->selectToBuffer) { 2776492d43a5Smrg _WriteKey(screen, (const Char *) "201"); 2777d522f475Smrg } 2778d522f475Smrg#endif 2779f2e35a3aSmrg if (screen->selectToBuffer) { 2780f2e35a3aSmrg InternalSelect *mydata = &(screen->internal_select); 2781f2e35a3aSmrg finishInternalSelect(xw); 2782f2e35a3aSmrg if (mydata->done) { 2783f2e35a3aSmrg free(mydata->format); 2784f2e35a3aSmrg free(mydata->buffer); 2785f2e35a3aSmrg memset(mydata, 0, sizeof(*mydata)); 2786f2e35a3aSmrg } 2787f2e35a3aSmrg screen->selectToBuffer = False; 2788f2e35a3aSmrg } 2789d522f475Smrg XFreeStringList(text_list); 279001037d57Smrg } else { 279101037d57Smrg TRACE(("...empty text-list\n")); 2792d522f475Smrg goto fail; 279301037d57Smrg } 2794d522f475Smrg 2795d522f475Smrg XtFree((char *) client_data); 2796d522f475Smrg XtFree((char *) value); 2797d522f475Smrg 2798d522f475Smrg return; 2799d522f475Smrg 2800d522f475Smrg fail: 2801d522f475Smrg if (client_data != 0) { 2802d522f475Smrg struct _SelectionList *list = (struct _SelectionList *) client_data; 2803956cc18dSsnj 2804956cc18dSsnj TRACE(("SelectionReceived ->xtermGetSelection\n")); 2805d522f475Smrg xtermGetSelection(w, list->time, 2806d522f475Smrg list->params, list->count, list->targets); 2807d522f475Smrg XtFree((char *) client_data); 2808d522f475Smrg#if OPT_PASTE64 2809d522f475Smrg } else { 2810956cc18dSsnj FinishPaste64(xw); 2811d522f475Smrg#endif 2812d522f475Smrg } 2813d522f475Smrg return; 2814d522f475Smrg} 2815d522f475Smrg 2816d522f475Smrgvoid 2817d522f475SmrgHandleInsertSelection(Widget w, 2818894e0ac8Smrg XEvent *event, /* assumed to be XButtonEvent* */ 2819e0a2b6dfSmrg String *params, /* selections in precedence order */ 2820d522f475Smrg Cardinal *num_params) 2821d522f475Smrg{ 2822956cc18dSsnj XtermWidget xw; 2823d522f475Smrg 2824956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2825f2e35a3aSmrg TRACE_EVENT("HandleInsertSelection", event, params, num_params); 2826d522f475Smrg if (!SendMousePosition(xw, event)) { 2827d522f475Smrg#if OPT_READLINE 2828d522f475Smrg int ldelta; 2829956cc18dSsnj TScreen *screen = TScreenOf(xw); 2830492d43a5Smrg if (IsBtnEvent(event) 2831f2e35a3aSmrg && !OverrideEvent(event) 2832913cc679Smrg && (okSendMousePos(xw) == MOUSE_OFF) 2833d522f475Smrg && SCREEN_FLAG(screen, paste_moves) 2834d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta)) 2835d522f475Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta); 2836d522f475Smrg#endif /* OPT_READLINE */ 2837d522f475Smrg 2838d522f475Smrg xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL); 2839d522f475Smrg } 2840d522f475Smrg } 2841d522f475Smrg} 2842d522f475Smrg 2843d522f475Smrgstatic SelectUnit 2844956cc18dSsnjEvalSelectUnit(XtermWidget xw, 2845d522f475Smrg Time buttonDownTime, 2846d522f475Smrg SelectUnit defaultUnit, 2847d522f475Smrg unsigned int button) 2848d522f475Smrg{ 2849956cc18dSsnj TScreen *screen = TScreenOf(xw); 2850d522f475Smrg SelectUnit result; 2851d522f475Smrg int delta; 2852d522f475Smrg 2853d522f475Smrg if (button != screen->lastButton) { 285420d2c4d2Smrg delta = screen->multiClickTime + 1; 2855d522f475Smrg } else if (screen->lastButtonUpTime == (Time) 0) { 2856d522f475Smrg /* first time and once in a blue moon */ 2857d522f475Smrg delta = screen->multiClickTime + 1; 2858d522f475Smrg } else if (buttonDownTime > screen->lastButtonUpTime) { 2859d522f475Smrg /* most of the time */ 28602eaa94a1Schristos delta = (int) (buttonDownTime - screen->lastButtonUpTime); 2861d522f475Smrg } else { 2862d522f475Smrg /* time has rolled over since lastButtonUpTime */ 28632eaa94a1Schristos delta = (int) ((((Time) ~ 0) - screen->lastButtonUpTime) + buttonDownTime); 2864d522f475Smrg } 2865d522f475Smrg 2866d522f475Smrg if (delta > screen->multiClickTime) { 2867d522f475Smrg screen->numberOfClicks = 1; 2868d522f475Smrg result = defaultUnit; 2869d522f475Smrg } else { 2870d522f475Smrg result = screen->selectMap[screen->numberOfClicks % screen->maxClicks]; 2871d522f475Smrg screen->numberOfClicks += 1; 2872d522f475Smrg } 2873d522f475Smrg TRACE(("EvalSelectUnit(%d) = %d\n", screen->numberOfClicks, result)); 2874d522f475Smrg return result; 2875d522f475Smrg} 2876d522f475Smrg 2877d522f475Smrgstatic void 2878d522f475Smrgdo_select_start(XtermWidget xw, 2879894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2880e0a2b6dfSmrg CELL *cell) 2881d522f475Smrg{ 2882956cc18dSsnj TScreen *screen = TScreenOf(xw); 2883d522f475Smrg 2884d522f475Smrg if (SendMousePosition(xw, event)) 2885d522f475Smrg return; 2886956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2887d522f475Smrg event->xbutton.time, 2888d522f475Smrg Select_CHAR, 2889d522f475Smrg event->xbutton.button); 2890d522f475Smrg screen->replyToEmacs = False; 2891d522f475Smrg 2892d522f475Smrg#if OPT_READLINE 2893d522f475Smrg lastButtonDownTime = event->xbutton.time; 2894d522f475Smrg#endif 2895d522f475Smrg 2896d522f475Smrg StartSelect(xw, cell); 2897d522f475Smrg} 2898d522f475Smrg 2899d522f475Smrg/* ARGSUSED */ 2900d522f475Smrgvoid 2901d522f475SmrgHandleSelectStart(Widget w, 2902894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2903e0a2b6dfSmrg String *params GCC_UNUSED, 2904d522f475Smrg Cardinal *num_params GCC_UNUSED) 2905d522f475Smrg{ 2906956cc18dSsnj XtermWidget xw; 2907956cc18dSsnj 2908956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2909956cc18dSsnj TScreen *screen = TScreenOf(xw); 2910d522f475Smrg CELL cell; 2911d522f475Smrg 2912f2e35a3aSmrg TRACE_EVENT("HandleSelectStart", event, params, num_params); 2913d522f475Smrg screen->firstValidRow = 0; 2914d522f475Smrg screen->lastValidRow = screen->max_row; 2915d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2916d522f475Smrg 2917d522f475Smrg#if OPT_READLINE 2918d522f475Smrg ExtendingSelection = 0; 2919d522f475Smrg#endif 2920d522f475Smrg 2921d522f475Smrg do_select_start(xw, event, &cell); 2922d522f475Smrg } 2923d522f475Smrg} 2924d522f475Smrg 2925d522f475Smrg/* ARGSUSED */ 2926d522f475Smrgvoid 2927d522f475SmrgHandleKeyboardSelectStart(Widget w, 2928894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2929e0a2b6dfSmrg String *params GCC_UNUSED, 2930d522f475Smrg Cardinal *num_params GCC_UNUSED) 2931d522f475Smrg{ 2932956cc18dSsnj XtermWidget xw; 2933956cc18dSsnj 2934956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2935956cc18dSsnj TScreen *screen = TScreenOf(xw); 29360bd37d32Smrg 2937f2e35a3aSmrg TRACE_EVENT("HandleKeyboardSelectStart", event, params, num_params); 2938d522f475Smrg do_select_start(xw, event, &screen->cursorp); 2939d522f475Smrg } 2940d522f475Smrg} 2941d522f475Smrg 2942d522f475Smrgstatic void 2943894e0ac8SmrgTrackDown(XtermWidget xw, XButtonEvent *event) 2944d522f475Smrg{ 2945956cc18dSsnj TScreen *screen = TScreenOf(xw); 2946d522f475Smrg CELL cell; 2947d522f475Smrg 2948956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2949d522f475Smrg event->time, 2950d522f475Smrg Select_CHAR, 2951d522f475Smrg event->button); 2952d522f475Smrg if (screen->numberOfClicks > 1) { 2953d522f475Smrg PointToCELL(screen, event->y, event->x, &cell); 2954d522f475Smrg screen->replyToEmacs = True; 2955d522f475Smrg StartSelect(xw, &cell); 2956d522f475Smrg } else { 2957d522f475Smrg screen->waitingForTrackInfo = True; 2958492d43a5Smrg EditorButton(xw, event); 2959d522f475Smrg } 2960d522f475Smrg} 2961d522f475Smrg 2962d522f475Smrg#define boundsCheck(x) if (x < 0) \ 2963d522f475Smrg x = 0; \ 2964d522f475Smrg else if (x >= screen->max_row) \ 2965d522f475Smrg x = screen->max_row 2966d522f475Smrg 2967d522f475Smrgvoid 2968d522f475SmrgTrackMouse(XtermWidget xw, 2969d522f475Smrg int func, 2970e0a2b6dfSmrg CELL *start, 2971d522f475Smrg int firstrow, 2972d522f475Smrg int lastrow) 2973d522f475Smrg{ 2974956cc18dSsnj TScreen *screen = TScreenOf(xw); 2975d522f475Smrg 2976d522f475Smrg if (screen->waitingForTrackInfo) { /* if Timed, ignore */ 2977d522f475Smrg screen->waitingForTrackInfo = False; 2978d522f475Smrg 2979d522f475Smrg if (func != 0) { 2980d522f475Smrg CELL first = *start; 2981d522f475Smrg 2982d522f475Smrg boundsCheck(first.row); 2983d522f475Smrg boundsCheck(firstrow); 2984d522f475Smrg boundsCheck(lastrow); 2985d522f475Smrg screen->firstValidRow = firstrow; 2986d522f475Smrg screen->lastValidRow = lastrow; 2987d522f475Smrg screen->replyToEmacs = True; 2988d522f475Smrg StartSelect(xw, &first); 2989d522f475Smrg } 2990d522f475Smrg } 2991d522f475Smrg} 2992d522f475Smrg 2993d522f475Smrgstatic void 2994e0a2b6dfSmrgStartSelect(XtermWidget xw, const CELL *cell) 2995d522f475Smrg{ 2996956cc18dSsnj TScreen *screen = TScreenOf(xw); 2997d522f475Smrg 2998d522f475Smrg TRACE(("StartSelect row=%d, col=%d\n", cell->row, cell->col)); 2999d522f475Smrg if (screen->cursor_state) 3000f2e35a3aSmrg HideCursor(xw); 3001d522f475Smrg if (screen->numberOfClicks == 1) { 3002d522f475Smrg /* set start of selection */ 3003d522f475Smrg screen->rawPos = *cell; 3004d522f475Smrg } 3005d522f475Smrg /* else use old values in rawPos */ 3006d522f475Smrg screen->saveStartR = screen->startExt = screen->rawPos; 3007d522f475Smrg screen->saveEndR = screen->endExt = screen->rawPos; 3008d522f475Smrg if (Coordinate(screen, cell) < Coordinate(screen, &(screen->rawPos))) { 3009d522f475Smrg screen->eventMode = LEFTEXTENSION; 3010d522f475Smrg screen->startExt = *cell; 3011d522f475Smrg } else { 3012d522f475Smrg screen->eventMode = RIGHTEXTENSION; 3013d522f475Smrg screen->endExt = *cell; 3014d522f475Smrg } 3015f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False, True); 3016d522f475Smrg} 3017d522f475Smrg 3018d522f475Smrgstatic void 3019d522f475SmrgEndExtend(XtermWidget xw, 3020894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 3021e0a2b6dfSmrg String *params, /* selections */ 3022d522f475Smrg Cardinal num_params, 3023d522f475Smrg Bool use_cursor_loc) 3024d522f475Smrg{ 3025d522f475Smrg CELL cell; 3026956cc18dSsnj TScreen *screen = TScreenOf(xw); 3027d522f475Smrg 3028f2e35a3aSmrg TRACE_EVENT("EndExtend", event, params, &num_params); 3029d522f475Smrg if (use_cursor_loc) { 3030d522f475Smrg cell = screen->cursorp; 3031d522f475Smrg } else { 3032d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 3033d522f475Smrg } 3034d522f475Smrg ExtendExtend(xw, &cell); 30352e4f8982Smrg 3036d522f475Smrg screen->lastButtonUpTime = event->xbutton.time; 3037d522f475Smrg screen->lastButton = event->xbutton.button; 30382e4f8982Smrg 3039d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 3040d522f475Smrg if (screen->replyToEmacs) { 30412e4f8982Smrg Char line[64]; 30422e4f8982Smrg unsigned count = 0; 30432e4f8982Smrg 3044d522f475Smrg if (screen->control_eight_bits) { 3045d522f475Smrg line[count++] = ANSI_CSI; 3046d522f475Smrg } else { 3047d522f475Smrg line[count++] = ANSI_ESC; 3048d522f475Smrg line[count++] = '['; 3049d522f475Smrg } 3050d522f475Smrg if (isSameCELL(&(screen->rawPos), &(screen->startSel)) 3051d522f475Smrg && isSameCELL(&cell, &(screen->endSel))) { 3052d522f475Smrg /* Use short-form emacs select */ 30530bd37d32Smrg 30540bd37d32Smrg switch (screen->extend_coords) { 30550bd37d32Smrg case 0: 30560bd37d32Smrg case SET_EXT_MODE_MOUSE: 30570bd37d32Smrg line[count++] = 't'; 30580bd37d32Smrg break; 30590bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 3060f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 30610bd37d32Smrg line[count++] = '<'; 30620bd37d32Smrg break; 30630bd37d32Smrg } 30640bd37d32Smrg 3065492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 30660bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3067492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 30680bd37d32Smrg 30690bd37d32Smrg switch (screen->extend_coords) { 30700bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 30710bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 3072f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 30730bd37d32Smrg line[count++] = 't'; 30740bd37d32Smrg break; 30750bd37d32Smrg } 3076d522f475Smrg } else { 3077d522f475Smrg /* long-form, specify everything */ 30780bd37d32Smrg 30790bd37d32Smrg switch (screen->extend_coords) { 30800bd37d32Smrg case 0: 30810bd37d32Smrg case SET_EXT_MODE_MOUSE: 30820bd37d32Smrg line[count++] = 'T'; 30830bd37d32Smrg break; 30840bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 3085f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 30860bd37d32Smrg line[count++] = '<'; 30870bd37d32Smrg break; 30880bd37d32Smrg } 30890bd37d32Smrg 3090492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.col); 30910bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3092492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.row); 30930bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3094492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 30950bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3096492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 30970bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3098492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.col); 30990bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 3100492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.row); 31010bd37d32Smrg 31020bd37d32Smrg switch (screen->extend_coords) { 31030bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 31040bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 3105f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 31060bd37d32Smrg line[count++] = 'T'; 31070bd37d32Smrg break; 31080bd37d32Smrg } 3109d522f475Smrg } 3110d522f475Smrg v_write(screen->respond, line, count); 3111f2e35a3aSmrg UnHiliteText(xw); 3112d522f475Smrg } 3113d522f475Smrg } 3114d522f475Smrg SelectSet(xw, event, params, num_params); 3115d522f475Smrg screen->eventMode = NORMAL; 3116d522f475Smrg} 3117d522f475Smrg 3118d522f475Smrgvoid 3119d522f475SmrgHandleSelectSet(Widget w, 3120894e0ac8Smrg XEvent *event, 3121e0a2b6dfSmrg String *params, 3122d522f475Smrg Cardinal *num_params) 3123d522f475Smrg{ 3124956cc18dSsnj XtermWidget xw; 3125956cc18dSsnj 3126956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3127f2e35a3aSmrg TRACE_EVENT("HandleSelectSet", event, params, num_params); 3128956cc18dSsnj SelectSet(xw, event, params, *num_params); 3129d522f475Smrg } 3130d522f475Smrg} 3131d522f475Smrg 3132d522f475Smrg/* ARGSUSED */ 3133d522f475Smrgstatic void 3134d522f475SmrgSelectSet(XtermWidget xw, 3135894e0ac8Smrg XEvent *event GCC_UNUSED, 3136e0a2b6dfSmrg String *params, 3137d522f475Smrg Cardinal num_params) 3138d522f475Smrg{ 3139956cc18dSsnj TScreen *screen = TScreenOf(xw); 3140d522f475Smrg 3141d522f475Smrg TRACE(("SelectSet\n")); 3142d522f475Smrg /* Only do select stuff if non-null select */ 3143d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 3144f2e35a3aSmrg Cardinal n; 3145f2e35a3aSmrg for (n = 0; n < num_params; ++n) { 3146f2e35a3aSmrg SaltTextAway(xw, 3147f2e35a3aSmrg TargetToSelection(screen, params[n]), 3148f2e35a3aSmrg &(screen->startSel), &(screen->endSel)); 3149f2e35a3aSmrg } 31500bd37d32Smrg _OwnSelection(xw, params, num_params); 3151d522f475Smrg } else { 31520bd37d32Smrg ScrnDisownSelection(xw); 3153d522f475Smrg } 3154d522f475Smrg} 3155d522f475Smrg 3156d522f475Smrg#define Abs(x) ((x) < 0 ? -(x) : (x)) 3157d522f475Smrg 3158d522f475Smrg/* ARGSUSED */ 3159d522f475Smrgstatic void 3160d522f475Smrgdo_start_extend(XtermWidget xw, 3161894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3162e0a2b6dfSmrg String *params GCC_UNUSED, 3163d522f475Smrg Cardinal *num_params GCC_UNUSED, 3164d522f475Smrg Bool use_cursor_loc) 3165d522f475Smrg{ 3166956cc18dSsnj TScreen *screen = TScreenOf(xw); 3167d522f475Smrg int coord; 3168d522f475Smrg CELL cell; 3169d522f475Smrg 3170d522f475Smrg if (SendMousePosition(xw, event)) 3171d522f475Smrg return; 3172d522f475Smrg 3173d522f475Smrg screen->firstValidRow = 0; 3174d522f475Smrg screen->lastValidRow = screen->max_row; 3175d522f475Smrg#if OPT_READLINE 3176f2e35a3aSmrg if (OverrideEvent(event) 3177d522f475Smrg || event->xbutton.button != Button3 3178d522f475Smrg || !(SCREEN_FLAG(screen, dclick3_deletes))) 3179d522f475Smrg#endif 3180956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 3181d522f475Smrg event->xbutton.time, 3182d522f475Smrg screen->selectUnit, 3183d522f475Smrg event->xbutton.button); 3184d522f475Smrg screen->replyToEmacs = False; 3185d522f475Smrg 3186d522f475Smrg#if OPT_READLINE 3187f2e35a3aSmrg CheckSecondPress3(xw, screen, event); 3188d522f475Smrg#endif 3189d522f475Smrg 3190d522f475Smrg if (screen->numberOfClicks == 1 3191f2e35a3aSmrg || (SCREEN_FLAG(screen, dclick3_deletes) 3192f2e35a3aSmrg && !OverrideEvent(event))) { 3193d522f475Smrg /* Save existing selection so we can reestablish it if the guy 3194d522f475Smrg extends past the other end of the selection */ 3195d522f475Smrg screen->saveStartR = screen->startExt = screen->startRaw; 3196d522f475Smrg screen->saveEndR = screen->endExt = screen->endRaw; 3197d522f475Smrg } else { 3198d522f475Smrg /* He just needed the selection mode changed, use old values. */ 3199d522f475Smrg screen->startExt = screen->startRaw = screen->saveStartR; 3200d522f475Smrg screen->endExt = screen->endRaw = screen->saveEndR; 3201d522f475Smrg } 3202d522f475Smrg if (use_cursor_loc) { 3203d522f475Smrg cell = screen->cursorp; 3204d522f475Smrg } else { 3205d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 3206d522f475Smrg } 3207d522f475Smrg coord = Coordinate(screen, &cell); 3208d522f475Smrg 3209d522f475Smrg if (Abs(coord - Coordinate(screen, &(screen->startSel))) 3210d522f475Smrg < Abs(coord - Coordinate(screen, &(screen->endSel))) 3211d522f475Smrg || coord < Coordinate(screen, &(screen->startSel))) { 3212d522f475Smrg /* point is close to left side of selection */ 3213d522f475Smrg screen->eventMode = LEFTEXTENSION; 3214d522f475Smrg screen->startExt = cell; 3215d522f475Smrg } else { 3216d522f475Smrg /* point is close to left side of selection */ 3217d522f475Smrg screen->eventMode = RIGHTEXTENSION; 3218d522f475Smrg screen->endExt = cell; 3219d522f475Smrg } 3220f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), True, True); 3221d522f475Smrg 3222d522f475Smrg#if OPT_READLINE 3223d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 3224d522f475Smrg ExtendingSelection = 1; 3225d522f475Smrg#endif 3226d522f475Smrg} 3227d522f475Smrg 3228d522f475Smrgstatic void 3229e0a2b6dfSmrgExtendExtend(XtermWidget xw, const CELL *cell) 3230d522f475Smrg{ 3231956cc18dSsnj TScreen *screen = TScreenOf(xw); 3232d522f475Smrg int coord = Coordinate(screen, cell); 3233d522f475Smrg 3234d522f475Smrg TRACE(("ExtendExtend row=%d, col=%d\n", cell->row, cell->col)); 3235d522f475Smrg if (screen->eventMode == LEFTEXTENSION 3236d522f475Smrg && ((coord + (screen->selectUnit != Select_CHAR)) 3237d522f475Smrg > Coordinate(screen, &(screen->endSel)))) { 3238d522f475Smrg /* Whoops, he's changed his mind. Do RIGHTEXTENSION */ 3239d522f475Smrg screen->eventMode = RIGHTEXTENSION; 3240d522f475Smrg screen->startExt = screen->saveStartR; 3241d522f475Smrg } else if (screen->eventMode == RIGHTEXTENSION 3242d522f475Smrg && coord < Coordinate(screen, &(screen->startSel))) { 3243d522f475Smrg /* Whoops, he's changed his mind. Do LEFTEXTENSION */ 3244d522f475Smrg screen->eventMode = LEFTEXTENSION; 3245d522f475Smrg screen->endExt = screen->saveEndR; 3246d522f475Smrg } 3247d522f475Smrg if (screen->eventMode == LEFTEXTENSION) { 3248d522f475Smrg screen->startExt = *cell; 3249d522f475Smrg } else { 3250d522f475Smrg screen->endExt = *cell; 3251d522f475Smrg } 3252f2e35a3aSmrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False, True); 3253d522f475Smrg 3254d522f475Smrg#if OPT_READLINE 3255d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 3256d522f475Smrg ExtendingSelection = 1; 3257d522f475Smrg#endif 3258d522f475Smrg} 3259d522f475Smrg 3260d522f475Smrgvoid 3261d522f475SmrgHandleStartExtend(Widget w, 3262894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3263e0a2b6dfSmrg String *params, /* unused */ 3264d522f475Smrg Cardinal *num_params) /* unused */ 3265d522f475Smrg{ 3266956cc18dSsnj XtermWidget xw; 3267956cc18dSsnj 3268956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3269f2e35a3aSmrg TRACE_EVENT("HandleStartExtend", event, params, num_params); 3270956cc18dSsnj do_start_extend(xw, event, params, num_params, False); 3271956cc18dSsnj } 3272d522f475Smrg} 3273d522f475Smrg 3274d522f475Smrgvoid 3275d522f475SmrgHandleKeyboardStartExtend(Widget w, 3276894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 3277e0a2b6dfSmrg String *params, /* unused */ 3278d522f475Smrg Cardinal *num_params) /* unused */ 3279d522f475Smrg{ 3280956cc18dSsnj XtermWidget xw; 3281956cc18dSsnj 3282956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3283f2e35a3aSmrg TRACE_EVENT("HandleKeyboardStartExtend", event, params, num_params); 3284956cc18dSsnj do_start_extend(xw, event, params, num_params, True); 3285956cc18dSsnj } 3286d522f475Smrg} 3287d522f475Smrg 3288d522f475Smrgvoid 3289e0a2b6dfSmrgScrollSelection(TScreen *screen, int amount, Bool always) 3290d522f475Smrg{ 3291d522f475Smrg int minrow = INX2ROW(screen, -screen->savedlines); 3292d522f475Smrg int maxrow = INX2ROW(screen, screen->max_row); 3293d522f475Smrg int maxcol = screen->max_col; 3294d522f475Smrg 3295d522f475Smrg#define scroll_update_one(cell) \ 3296d522f475Smrg (cell)->row += amount; \ 3297d522f475Smrg if ((cell)->row < minrow) { \ 3298d522f475Smrg (cell)->row = minrow; \ 3299d522f475Smrg (cell)->col = 0; \ 3300d522f475Smrg } \ 3301d522f475Smrg if ((cell)->row > maxrow) { \ 3302d522f475Smrg (cell)->row = maxrow; \ 3303d522f475Smrg (cell)->col = maxcol; \ 3304d522f475Smrg } 3305d522f475Smrg 3306d522f475Smrg scroll_update_one(&(screen->startRaw)); 3307d522f475Smrg scroll_update_one(&(screen->endRaw)); 3308d522f475Smrg scroll_update_one(&(screen->startSel)); 3309d522f475Smrg scroll_update_one(&(screen->endSel)); 3310d522f475Smrg 3311d522f475Smrg scroll_update_one(&(screen->rawPos)); 3312d522f475Smrg 3313d522f475Smrg /* 3314d522f475Smrg * If we are told to scroll the selection but it lies outside the scrolling 3315d522f475Smrg * margins, then that could cause the selection to move (bad). It is not 3316d522f475Smrg * simple to fix, because this function is called both for the scrollbar 3317d522f475Smrg * actions as well as application scrolling. The 'always' flag is set in 3318d522f475Smrg * the former case. The rest of the logic handles the latter. 3319d522f475Smrg */ 3320d522f475Smrg if (ScrnHaveSelection(screen)) { 3321d522f475Smrg int adjust; 3322d522f475Smrg 3323d522f475Smrg adjust = ROW2INX(screen, screen->startH.row); 3324d522f475Smrg if (always 33250bd37d32Smrg || !ScrnHaveRowMargins(screen) 33260bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 3327d522f475Smrg scroll_update_one(&screen->startH); 3328d522f475Smrg } 3329d522f475Smrg adjust = ROW2INX(screen, screen->endH.row); 3330d522f475Smrg if (always 33310bd37d32Smrg || !ScrnHaveRowMargins(screen) 33320bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 3333d522f475Smrg scroll_update_one(&screen->endH); 3334d522f475Smrg } 3335d522f475Smrg } 3336d522f475Smrg 3337d522f475Smrg screen->startHCoord = Coordinate(screen, &screen->startH); 3338d522f475Smrg screen->endHCoord = Coordinate(screen, &screen->endH); 3339d522f475Smrg} 3340d522f475Smrg 3341d522f475Smrg/*ARGSUSED*/ 3342d522f475Smrgvoid 3343f2e35a3aSmrgResizeSelection(TScreen *screen, int rows, int cols) 3344d522f475Smrg{ 3345d522f475Smrg rows--; /* decr to get 0-max */ 3346d522f475Smrg cols--; 3347d522f475Smrg 3348d522f475Smrg if (screen->startRaw.row > rows) 3349d522f475Smrg screen->startRaw.row = rows; 3350d522f475Smrg if (screen->startSel.row > rows) 3351d522f475Smrg screen->startSel.row = rows; 3352d522f475Smrg if (screen->endRaw.row > rows) 3353d522f475Smrg screen->endRaw.row = rows; 3354d522f475Smrg if (screen->endSel.row > rows) 3355d522f475Smrg screen->endSel.row = rows; 3356d522f475Smrg if (screen->rawPos.row > rows) 3357d522f475Smrg screen->rawPos.row = rows; 3358d522f475Smrg 3359d522f475Smrg if (screen->startRaw.col > cols) 3360d522f475Smrg screen->startRaw.col = cols; 3361d522f475Smrg if (screen->startSel.col > cols) 3362d522f475Smrg screen->startSel.col = cols; 3363d522f475Smrg if (screen->endRaw.col > cols) 3364d522f475Smrg screen->endRaw.col = cols; 3365d522f475Smrg if (screen->endSel.col > cols) 3366d522f475Smrg screen->endSel.col = cols; 3367d522f475Smrg if (screen->rawPos.col > cols) 3368d522f475Smrg screen->rawPos.col = cols; 3369d522f475Smrg} 3370d522f475Smrg 3371d522f475Smrg#if OPT_WIDE_CHARS 3372f2e35a3aSmrg#define isWideCell(row, col) isWideFrg((int)XTERM_CELL(row, col)) 3373d522f475Smrg#endif 3374d522f475Smrg 3375d522f475Smrgstatic void 3376e0a2b6dfSmrgPointToCELL(TScreen *screen, 3377d522f475Smrg int y, 3378d522f475Smrg int x, 3379e0a2b6dfSmrg CELL *cell) 3380d522f475Smrg/* Convert pixel coordinates to character coordinates. 3381d522f475Smrg Rows are clipped between firstValidRow and lastValidRow. 3382d522f475Smrg Columns are clipped between to be 0 or greater, but are not clipped to some 3383d522f475Smrg maximum value. */ 3384d522f475Smrg{ 3385d522f475Smrg cell->row = (y - screen->border) / FontHeight(screen); 3386d522f475Smrg if (cell->row < screen->firstValidRow) 3387d522f475Smrg cell->row = screen->firstValidRow; 3388d522f475Smrg else if (cell->row > screen->lastValidRow) 3389d522f475Smrg cell->row = screen->lastValidRow; 3390d522f475Smrg cell->col = (x - OriginX(screen)) / FontWidth(screen); 3391d522f475Smrg if (cell->col < 0) 3392d522f475Smrg cell->col = 0; 3393d522f475Smrg else if (cell->col > MaxCols(screen)) { 3394d522f475Smrg cell->col = MaxCols(screen); 3395d522f475Smrg } 3396d522f475Smrg#if OPT_WIDE_CHARS 3397d522f475Smrg /* 3398d522f475Smrg * If we got a click on the right half of a doublewidth character, 3399d522f475Smrg * pretend it happened on the left half. 3400d522f475Smrg */ 3401d522f475Smrg if (cell->col > 0 3402d522f475Smrg && isWideCell(cell->row, cell->col - 1) 3403d522f475Smrg && (XTERM_CELL(cell->row, cell->col) == HIDDEN_CHAR)) { 3404d522f475Smrg cell->col -= 1; 3405d522f475Smrg } 3406d522f475Smrg#endif 3407d522f475Smrg} 3408d522f475Smrg 3409d522f475Smrg/* 3410d522f475Smrg * Find the last column at which text was drawn on the given row. 3411d522f475Smrg */ 3412d522f475Smrgstatic int 341301037d57SmrgLastTextCol(TScreen *screen, CLineData *ld, int row) 3414d522f475Smrg{ 341520d2c4d2Smrg int i = -1; 3416d522f475Smrg 341720d2c4d2Smrg if (ld != 0) { 341820d2c4d2Smrg if (okScrnRow(screen, row)) { 34192e4f8982Smrg const IAttr *ch; 342020d2c4d2Smrg for (i = screen->max_col, 342120d2c4d2Smrg ch = ld->attribs + i; 342220d2c4d2Smrg i >= 0 && !(*ch & CHARDRAWN); 342320d2c4d2Smrg ch--, i--) { 342420d2c4d2Smrg ; 342520d2c4d2Smrg } 3426d522f475Smrg#if OPT_DEC_CHRSET 342720d2c4d2Smrg if (CSET_DOUBLE(GetLineDblCS(ld))) { 342820d2c4d2Smrg i *= 2; 342920d2c4d2Smrg } 3430d522f475Smrg#endif 343120d2c4d2Smrg } 3432d522f475Smrg } 3433d522f475Smrg return (i); 3434d522f475Smrg} 3435d522f475Smrg 3436d522f475Smrg#if !OPT_WIDE_CHARS 3437d522f475Smrg/* 3438d522f475Smrg** double click table for cut and paste in 8 bits 3439d522f475Smrg** 3440d522f475Smrg** This table is divided in four parts : 3441d522f475Smrg** 3442d522f475Smrg** - control characters [0,0x1f] U [0x80,0x9f] 3443d522f475Smrg** - separators [0x20,0x3f] U [0xa0,0xb9] 3444d522f475Smrg** - binding characters [0x40,0x7f] U [0xc0,0xff] 3445d522f475Smrg** - exceptions 3446d522f475Smrg*/ 3447d522f475Smrg/* *INDENT-OFF* */ 3448d522f475Smrgstatic int charClass[256] = 3449d522f475Smrg{ 3450d522f475Smrg/* NUL SOH STX ETX EOT ENQ ACK BEL */ 3451d522f475Smrg 32, 1, 1, 1, 1, 1, 1, 1, 34520bd37d32Smrg/* BS HT NL VT FF CR SO SI */ 3453d522f475Smrg 1, 32, 1, 1, 1, 1, 1, 1, 3454d522f475Smrg/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 3455d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3456d522f475Smrg/* CAN EM SUB ESC FS GS RS US */ 3457d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3458d522f475Smrg/* SP ! " # $ % & ' */ 3459d522f475Smrg 32, 33, 34, 35, 36, 37, 38, 39, 3460d522f475Smrg/* ( ) * + , - . / */ 3461d522f475Smrg 40, 41, 42, 43, 44, 45, 46, 47, 3462d522f475Smrg/* 0 1 2 3 4 5 6 7 */ 3463d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3464d522f475Smrg/* 8 9 : ; < = > ? */ 3465d522f475Smrg 48, 48, 58, 59, 60, 61, 62, 63, 3466d522f475Smrg/* @ A B C D E F G */ 3467d522f475Smrg 64, 48, 48, 48, 48, 48, 48, 48, 3468d522f475Smrg/* H I J K L M N O */ 3469d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3470d522f475Smrg/* P Q R S T U V W */ 3471d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3472d522f475Smrg/* X Y Z [ \ ] ^ _ */ 3473d522f475Smrg 48, 48, 48, 91, 92, 93, 94, 48, 3474d522f475Smrg/* ` a b c d e f g */ 3475d522f475Smrg 96, 48, 48, 48, 48, 48, 48, 48, 3476d522f475Smrg/* h i j k l m n o */ 3477d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3478d522f475Smrg/* p q r s t u v w */ 3479d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3480d522f475Smrg/* x y z { | } ~ DEL */ 3481d522f475Smrg 48, 48, 48, 123, 124, 125, 126, 1, 3482d522f475Smrg/* x80 x81 x82 x83 IND NEL SSA ESA */ 3483d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3484d522f475Smrg/* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 3485d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3486d522f475Smrg/* DCS PU1 PU2 STS CCH MW SPA EPA */ 3487d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3488d522f475Smrg/* x98 x99 x9A CSI ST OSC PM APC */ 3489d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 3490d522f475Smrg/* - i c/ L ox Y- | So */ 3491d522f475Smrg 160, 161, 162, 163, 164, 165, 166, 167, 3492d522f475Smrg/* .. c0 ip << _ R0 - */ 3493d522f475Smrg 168, 169, 170, 171, 172, 173, 174, 175, 3494d522f475Smrg/* o +- 2 3 ' u q| . */ 3495d522f475Smrg 176, 177, 178, 179, 180, 181, 182, 183, 3496d522f475Smrg/* , 1 2 >> 1/4 1/2 3/4 ? */ 3497d522f475Smrg 184, 185, 186, 187, 188, 189, 190, 191, 3498d522f475Smrg/* A` A' A^ A~ A: Ao AE C, */ 3499d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3500d522f475Smrg/* E` E' E^ E: I` I' I^ I: */ 3501d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3502d522f475Smrg/* D- N~ O` O' O^ O~ O: X */ 3503d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 215, 3504d522f475Smrg/* O/ U` U' U^ U: Y' P B */ 3505d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3506d522f475Smrg/* a` a' a^ a~ a: ao ae c, */ 3507d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3508d522f475Smrg/* e` e' e^ e: i` i' i^ i: */ 3509d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 3510d522f475Smrg/* d n~ o` o' o^ o~ o: -: */ 3511d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 247, 3512d522f475Smrg/* o/ u` u' u^ u: y' P y: */ 3513d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48}; 3514d522f475Smrg/* *INDENT-ON* */ 3515d522f475Smrg 3516d522f475Smrgint 3517d522f475SmrgSetCharacterClassRange(int low, /* in range of [0..255] */ 3518d522f475Smrg int high, 3519d522f475Smrg int value) /* arbitrary */ 3520d522f475Smrg{ 3521d522f475Smrg 3522d522f475Smrg if (low < 0 || high > 255 || high < low) 3523d522f475Smrg return (-1); 3524d522f475Smrg 3525d522f475Smrg for (; low <= high; low++) 3526d522f475Smrg charClass[low] = value; 3527d522f475Smrg 3528d522f475Smrg return (0); 3529d522f475Smrg} 3530d522f475Smrg#endif 3531d522f475Smrg 3532d522f475Smrgstatic int 3533e0a2b6dfSmrgclass_of(LineData *ld, CELL *cell) 3534d522f475Smrg{ 3535d522f475Smrg CELL temp = *cell; 35360bd37d32Smrg int result = 0; 3537d522f475Smrg 3538d522f475Smrg#if OPT_DEC_CHRSET 3539956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 3540d522f475Smrg temp.col /= 2; 3541d522f475Smrg } 3542d522f475Smrg#endif 35430bd37d32Smrg if (temp.col < (int) ld->lineSize) 35440bd37d32Smrg result = CharacterClass((int) (ld->charData[temp.col])); 35450bd37d32Smrg return result; 3546d522f475Smrg} 3547956cc18dSsnj 3548956cc18dSsnj#if OPT_WIDE_CHARS 3549956cc18dSsnj#define CClassSelects(name, cclass) \ 3550956cc18dSsnj (CClassOf(name) == cclass \ 3551956cc18dSsnj || XTERM_CELL(screen->name.row, screen->name.col) == HIDDEN_CHAR) 3552d522f475Smrg#else 3553956cc18dSsnj#define CClassSelects(name, cclass) \ 3554956cc18dSsnj (class_of(ld.name, &((screen->name))) == cclass) 3555d522f475Smrg#endif 3556d522f475Smrg 3557956cc18dSsnj#define CClassOf(name) class_of(ld.name, &((screen->name))) 3558956cc18dSsnj 3559913cc679Smrg#if OPT_REPORT_CCLASS 3560913cc679Smrgstatic int 3561913cc679Smrgshow_cclass_range(int lo, int hi) 3562913cc679Smrg{ 3563913cc679Smrg int cclass = CharacterClass(lo); 3564913cc679Smrg int ident = (cclass == lo); 3565913cc679Smrg int more = 0; 3566913cc679Smrg if (ident) { 3567913cc679Smrg int ch; 3568913cc679Smrg for (ch = lo + 1; ch <= hi; ch++) { 3569913cc679Smrg if (CharacterClass(ch) != ch) { 3570913cc679Smrg ident = 0; 3571913cc679Smrg break; 3572913cc679Smrg } 3573913cc679Smrg } 3574913cc679Smrg if (ident && (hi < 255)) { 3575913cc679Smrg ch = hi + 1; 3576913cc679Smrg if (CharacterClass(ch) == ch) { 3577913cc679Smrg if (ch >= 255 || CharacterClass(ch + 1) != ch) { 3578913cc679Smrg more = 1; 3579913cc679Smrg } 3580913cc679Smrg } 3581913cc679Smrg } 3582913cc679Smrg } 3583913cc679Smrg if (!more) { 3584913cc679Smrg if (lo == hi) { 3585913cc679Smrg printf("\t%d", lo); 3586913cc679Smrg } else { 3587913cc679Smrg printf("\t%d-%d", lo, hi); 3588913cc679Smrg } 3589913cc679Smrg if (!ident) 3590913cc679Smrg printf(":%d", cclass); 3591913cc679Smrg if (hi < 255) 3592913cc679Smrg printf(", \\"); 3593913cc679Smrg printf("\n"); 3594913cc679Smrg } 3595913cc679Smrg return !more; 3596913cc679Smrg} 3597913cc679Smrg 3598913cc679Smrgvoid 3599913cc679Smrgreport_char_class(XtermWidget xw) 3600913cc679Smrg{ 3601913cc679Smrg /* simple table, to match documentation */ 3602913cc679Smrg static const char charnames[] = 3603913cc679Smrg "NUL\0" "SOH\0" "STX\0" "ETX\0" "EOT\0" "ENQ\0" "ACK\0" "BEL\0" 3604913cc679Smrg " BS\0" " HT\0" " NL\0" " VT\0" " NP\0" " CR\0" " SO\0" " SI\0" 3605913cc679Smrg "DLE\0" "DC1\0" "DC2\0" "DC3\0" "DC4\0" "NAK\0" "SYN\0" "ETB\0" 3606913cc679Smrg "CAN\0" " EM\0" "SUB\0" "ESC\0" " FS\0" " GS\0" " RS\0" " US\0" 3607913cc679Smrg " SP\0" " !\0" " \"\0" " #\0" " $\0" " %\0" " &\0" " '\0" 3608913cc679Smrg " (\0" " )\0" " *\0" " +\0" " ,\0" " -\0" " .\0" " /\0" 3609913cc679Smrg " 0\0" " 1\0" " 2\0" " 3\0" " 4\0" " 5\0" " 6\0" " 7\0" 3610913cc679Smrg " 8\0" " 9\0" " :\0" " ;\0" " <\0" " =\0" " >\0" " ?\0" 3611913cc679Smrg " @\0" " A\0" " B\0" " C\0" " D\0" " E\0" " F\0" " G\0" 3612913cc679Smrg " H\0" " I\0" " J\0" " K\0" " L\0" " M\0" " N\0" " O\0" 3613913cc679Smrg " P\0" " Q\0" " R\0" " S\0" " T\0" " U\0" " V\0" " W\0" 3614913cc679Smrg " X\0" " Y\0" " Z\0" " [\0" " \\\0" " ]\0" " ^\0" " _\0" 3615913cc679Smrg " `\0" " a\0" " b\0" " c\0" " d\0" " e\0" " f\0" " g\0" 3616913cc679Smrg " h\0" " i\0" " j\0" " k\0" " l\0" " m\0" " n\0" " o\0" 3617913cc679Smrg " p\0" " q\0" " r\0" " s\0" " t\0" " u\0" " v\0" " w\0" 3618913cc679Smrg " x\0" " y\0" " z\0" " {\0" " |\0" " }\0" " ~\0" "DEL\0" 3619913cc679Smrg "x80\0" "x81\0" "x82\0" "x83\0" "IND\0" "NEL\0" "SSA\0" "ESA\0" 3620913cc679Smrg "HTS\0" "HTJ\0" "VTS\0" "PLD\0" "PLU\0" " RI\0" "SS2\0" "SS3\0" 3621913cc679Smrg "DCS\0" "PU1\0" "PU2\0" "STS\0" "CCH\0" " MW\0" "SPA\0" "EPA\0" 3622913cc679Smrg "x98\0" "x99\0" "x9A\0" "CSI\0" " ST\0" "OSC\0" " PM\0" "APC\0" 3623913cc679Smrg " -\0" " i\0" " c/\0" " L\0" " ox\0" " Y-\0" " |\0" " So\0" 3624913cc679Smrg " ..\0" " c0\0" " ip\0" " <<\0" " _\0" " \0" " R0\0" " -\0" 3625913cc679Smrg " o\0" " +-\0" " 2\0" " 3\0" " '\0" " u\0" " q|\0" " .\0" 3626913cc679Smrg " ,\0" " 1\0" " 2\0" " >>\0" "1/4\0" "1/2\0" "3/4\0" " ?\0" 3627913cc679Smrg " A`\0" " A'\0" " A^\0" " A~\0" " A:\0" " Ao\0" " AE\0" " C,\0" 3628913cc679Smrg " E`\0" " E'\0" " E^\0" " E:\0" " I`\0" " I'\0" " I^\0" " I:\0" 3629913cc679Smrg " D-\0" " N~\0" " O`\0" " O'\0" " O^\0" " O~\0" " O:\0" " X\0" 3630913cc679Smrg " O/\0" " U`\0" " U'\0" " U^\0" " U:\0" " Y'\0" " P\0" " B\0" 3631913cc679Smrg " a`\0" " a'\0" " a^\0" " a~\0" " a:\0" " ao\0" " ae\0" " c,\0" 3632913cc679Smrg " e`\0" " e'\0" " e^\0" " e:\0" " i`\0" " i'\0" " i^\0" " i:\0" 3633913cc679Smrg " d\0" " n~\0" " o`\0" " o'\0" " o^\0" " o~\0" " o:\0" " -:\0" 3634913cc679Smrg " o/\0" " u`\0" " u'\0" " u^\0" " u:\0" " y'\0" " P\0" " y:\0"; 3635913cc679Smrg int ch, dh; 3636913cc679Smrg int class_p; 3637913cc679Smrg 3638913cc679Smrg (void) xw; 3639913cc679Smrg 3640913cc679Smrg printf("static int charClass[256] = {\n"); 3641913cc679Smrg for (ch = 0; ch < 256; ++ch) { 3642913cc679Smrg const char *s = charnames + (ch * 4); 3643913cc679Smrg if ((ch & 7) == 0) 3644913cc679Smrg printf("/*"); 3645913cc679Smrg printf(" %s ", s); 3646913cc679Smrg if (((ch + 1) & 7) == 0) { 3647913cc679Smrg printf("*/\n "); 3648913cc679Smrg for (dh = ch - 7; dh <= ch; ++dh) { 3649913cc679Smrg printf(" %3d%s", CharacterClass(dh), dh == 255 ? "};" : ","); 3650913cc679Smrg } 3651913cc679Smrg printf("\n"); 3652913cc679Smrg } 3653913cc679Smrg } 3654913cc679Smrg 3655913cc679Smrg /* print the table as if it were the charClass resource */ 3656913cc679Smrg printf("\n"); 3657913cc679Smrg printf("The table is equivalent to this \"charClass\" resource:\n"); 3658913cc679Smrg class_p = CharacterClass(dh = 0); 3659913cc679Smrg for (ch = 0; ch < 256; ++ch) { 3660913cc679Smrg int class_c = CharacterClass(ch); 3661913cc679Smrg if (class_c != class_p) { 3662913cc679Smrg if (show_cclass_range(dh, ch - 1)) { 3663913cc679Smrg dh = ch; 3664913cc679Smrg class_p = class_c; 3665913cc679Smrg } 3666913cc679Smrg } 3667913cc679Smrg } 3668913cc679Smrg if (dh < 255) { 3669913cc679Smrg show_cclass_range(dh, 255); 3670913cc679Smrg } 3671913cc679Smrg 3672913cc679Smrg if_OPT_WIDE_CHARS(TScreenOf(xw), { 3673913cc679Smrg /* if this is a wide-character configuration, print all intervals */ 3674913cc679Smrg report_wide_char_class(); 3675913cc679Smrg }); 3676913cc679Smrg} 3677913cc679Smrg#endif 3678913cc679Smrg 3679d522f475Smrg/* 3680d522f475Smrg * If the given column is past the end of text on the given row, bump to the 3681d522f475Smrg * beginning of the next line. 3682d522f475Smrg */ 3683d522f475Smrgstatic Boolean 3684e0a2b6dfSmrgokPosition(TScreen *screen, 3685e0a2b6dfSmrg LineData **ld, 3686e0a2b6dfSmrg CELL *cell) 3687d522f475Smrg{ 368820d2c4d2Smrg Boolean result = True; 368920d2c4d2Smrg 369020d2c4d2Smrg if (cell->row > screen->max_row) { 369120d2c4d2Smrg result = False; 3692f2e35a3aSmrg TRACE(("okPosition cell row %d > screen max %d\n", cell->row, screen->max_row)); 369320d2c4d2Smrg } else if (cell->col > (LastTextCol(screen, *ld, cell->row) + 1)) { 3694f2e35a3aSmrg TRACE(("okPosition cell col %d > screen max %d\n", cell->col, 3695f2e35a3aSmrg (LastTextCol(screen, *ld, cell->row) + 1))); 369620d2c4d2Smrg if (cell->row < screen->max_row) { 3697f2e35a3aSmrg TRACE(("okPosition cell row %d < screen max %d\n", cell->row, screen->max_row)); 369820d2c4d2Smrg cell->col = 0; 369920d2c4d2Smrg *ld = GET_LINEDATA(screen, ++cell->row); 370020d2c4d2Smrg result = False; 370120d2c4d2Smrg } 3702d522f475Smrg } 370320d2c4d2Smrg return result; 3704d522f475Smrg} 3705d522f475Smrg 3706d522f475Smrgstatic void 3707e0a2b6dfSmrgtrimLastLine(TScreen *screen, 3708e0a2b6dfSmrg LineData **ld, 3709e0a2b6dfSmrg CELL *last) 3710d522f475Smrg{ 371120d2c4d2Smrg if (screen->cutNewline && last->row < screen->max_row) { 3712d522f475Smrg last->col = 0; 3713956cc18dSsnj *ld = GET_LINEDATA(screen, ++last->row); 3714d522f475Smrg } else { 3715956cc18dSsnj last->col = LastTextCol(screen, *ld, last->row) + 1; 3716d522f475Smrg } 3717d522f475Smrg} 3718d522f475Smrg 3719d522f475Smrg#if OPT_SELECT_REGEX 3720d522f475Smrg/* 3721d522f475Smrg * Returns the first row of a wrapped line. 3722d522f475Smrg */ 3723d522f475Smrgstatic int 3724e0a2b6dfSmrgfirstRowOfLine(TScreen *screen, int row, Bool visible) 3725d522f475Smrg{ 3726956cc18dSsnj LineData *ld = 0; 3727d522f475Smrg int limit = visible ? 0 : -screen->savedlines; 3728d522f475Smrg 3729d522f475Smrg while (row > limit && 3730956cc18dSsnj (ld = GET_LINEDATA(screen, row - 1)) != 0 && 3731956cc18dSsnj LineTstWrapped(ld)) { 3732d522f475Smrg --row; 3733956cc18dSsnj } 3734d522f475Smrg return row; 3735d522f475Smrg} 3736d522f475Smrg 3737d522f475Smrg/* 3738d522f475Smrg * Returns the last row of a wrapped line. 3739d522f475Smrg */ 3740d522f475Smrgstatic int 3741e0a2b6dfSmrglastRowOfLine(TScreen *screen, int row) 3742d522f475Smrg{ 3743956cc18dSsnj LineData *ld; 3744956cc18dSsnj 3745d522f475Smrg while (row < screen->max_row && 3746956cc18dSsnj (ld = GET_LINEDATA(screen, row)) != 0 && 3747956cc18dSsnj LineTstWrapped(ld)) { 3748d522f475Smrg ++row; 3749956cc18dSsnj } 3750d522f475Smrg return row; 3751d522f475Smrg} 3752d522f475Smrg 3753d522f475Smrg/* 3754d522f475Smrg * Returns the number of cells on the range of rows. 3755d522f475Smrg */ 3756d522f475Smrgstatic unsigned 3757e0a2b6dfSmrglengthOfLines(TScreen *screen, int firstRow, int lastRow) 3758d522f475Smrg{ 3759d522f475Smrg unsigned length = 0; 3760d522f475Smrg int n; 3761d522f475Smrg 3762d522f475Smrg for (n = firstRow; n <= lastRow; ++n) { 3763956cc18dSsnj LineData *ld = GET_LINEDATA(screen, n); 3764956cc18dSsnj int value = LastTextCol(screen, ld, n); 3765d522f475Smrg if (value >= 0) 37662eaa94a1Schristos length += (unsigned) (value + 1); 3767d522f475Smrg } 3768d522f475Smrg return length; 3769d522f475Smrg} 3770d522f475Smrg 3771d522f475Smrg/* 3772d522f475Smrg * Make a copy of the wrapped-line which corresponds to the given row as a 3773d522f475Smrg * string of bytes. Construct an index for the columns from the beginning of 3774d522f475Smrg * the line. 3775d522f475Smrg */ 3776d522f475Smrgstatic char * 3777e0a2b6dfSmrgmake_indexed_text(TScreen *screen, int row, unsigned length, int *indexed) 3778d522f475Smrg{ 3779d522f475Smrg Char *result = 0; 378020d2c4d2Smrg size_t need = (length + 1); 3781d522f475Smrg 3782d522f475Smrg /* 3783d522f475Smrg * Get a quick upper bound to the number of bytes needed, if the whole 3784d522f475Smrg * string were UTF-8. 3785d522f475Smrg */ 3786d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3787956cc18dSsnj need *= ((screen->lineExtra + 1) * 6); 3788d522f475Smrg }); 3789d522f475Smrg 3790d522f475Smrg if ((result = TypeCallocN(Char, need + 1)) != 0) { 3791956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 3792d522f475Smrg unsigned used = 0; 3793d522f475Smrg Char *last = result; 3794d522f475Smrg 3795d522f475Smrg do { 3796d522f475Smrg int col = 0; 3797956cc18dSsnj int limit = LastTextCol(screen, ld, row); 3798d522f475Smrg 3799d522f475Smrg while (col <= limit) { 3800d522f475Smrg Char *next = last; 3801956cc18dSsnj unsigned data = ld->charData[col]; 3802d522f475Smrg 38030bd37d32Smrg assert(col < (int) ld->lineSize); 3804d522f475Smrg /* some internal points may not be drawn */ 3805d522f475Smrg if (data == 0) 3806d522f475Smrg data = ' '; 3807d522f475Smrg 3808d522f475Smrg if_WIDE_OR_NARROW(screen, { 3809d522f475Smrg next = convertToUTF8(last, data); 3810d522f475Smrg } 3811d522f475Smrg , { 3812d522f475Smrg *next++ = CharOf(data); 3813d522f475Smrg }); 3814d522f475Smrg 3815d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3816956cc18dSsnj size_t off; 3817956cc18dSsnj for_each_combData(off, ld) { 3818956cc18dSsnj data = ld->combData[off][col]; 3819956cc18dSsnj if (data == 0) 3820d522f475Smrg break; 3821d522f475Smrg next = convertToUTF8(next, data); 3822d522f475Smrg } 3823d522f475Smrg }); 3824d522f475Smrg 382520d2c4d2Smrg indexed[used] = (int) (last - result); 3826d522f475Smrg *next = 0; 3827d522f475Smrg /* TRACE(("index[%d.%d] %d:%s\n", row, used, indexed[used], last)); */ 3828d522f475Smrg last = next; 3829d522f475Smrg ++used; 3830d522f475Smrg ++col; 383120d2c4d2Smrg indexed[used] = (int) (next - result); 3832d522f475Smrg } 3833d522f475Smrg } while (used < length && 3834956cc18dSsnj LineTstWrapped(ld) && 3835956cc18dSsnj (ld = GET_LINEDATA(screen, ++row)) != 0 && 3836956cc18dSsnj row < screen->max_row); 3837d522f475Smrg } 3838d522f475Smrg /* TRACE(("result:%s\n", result)); */ 3839d522f475Smrg return (char *) result; 3840d522f475Smrg} 3841d522f475Smrg 3842d522f475Smrg/* 3843d522f475Smrg * Find the column given an offset into the character string by using the 3844d522f475Smrg * index constructed in make_indexed_text(). 3845d522f475Smrg */ 3846d522f475Smrgstatic int 3847d522f475SmrgindexToCol(int *indexed, int len, int off) 3848d522f475Smrg{ 3849d522f475Smrg int col = 0; 3850d522f475Smrg while (indexed[col] < len) { 3851d522f475Smrg if (indexed[col] >= off) 3852d522f475Smrg break; 3853d522f475Smrg ++col; 3854d522f475Smrg } 3855d522f475Smrg return col; 3856d522f475Smrg} 3857d522f475Smrg 3858d522f475Smrg/* 3859d522f475Smrg * Given a row number, and a column offset from that (which may be wrapped), 3860d522f475Smrg * set the cell to the actual row/column values. 3861d522f475Smrg */ 3862d522f475Smrgstatic void 3863e0a2b6dfSmrgcolumnToCell(TScreen *screen, int row, int col, CELL *cell) 3864d522f475Smrg{ 3865d522f475Smrg while (row < screen->max_row) { 386601037d57Smrg CLineData *ld = GET_LINEDATA(screen, row); 3867956cc18dSsnj int last = LastTextCol(screen, ld, row); 3868d522f475Smrg 3869d522f475Smrg /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */ 3870d522f475Smrg if (col <= last) { 3871d522f475Smrg break; 3872d522f475Smrg } 3873d522f475Smrg /* 3874d522f475Smrg * Stop if the current row does not wrap (does not continue the current 3875d522f475Smrg * line). 3876d522f475Smrg */ 3877956cc18dSsnj if (!LineTstWrapped(ld)) { 3878d522f475Smrg col = last + 1; 3879d522f475Smrg break; 3880d522f475Smrg } 3881d522f475Smrg col -= (last + 1); 3882d522f475Smrg ++row; 3883d522f475Smrg } 3884d522f475Smrg if (col < 0) 3885d522f475Smrg col = 0; 3886d522f475Smrg cell->row = row; 3887d522f475Smrg cell->col = col; 3888d522f475Smrg} 3889d522f475Smrg 3890d522f475Smrg/* 3891d522f475Smrg * Given a cell, find the corresponding column offset. 3892d522f475Smrg */ 3893d522f475Smrgstatic int 3894e0a2b6dfSmrgcellToColumn(TScreen *screen, CELL *cell) 3895d522f475Smrg{ 389601037d57Smrg CLineData *ld = 0; 3897d522f475Smrg int col = cell->col; 3898d522f475Smrg int row = firstRowOfLine(screen, cell->row, False); 3899d522f475Smrg while (row < cell->row) { 3900956cc18dSsnj ld = GET_LINEDATA(screen, row); 3901956cc18dSsnj col += LastTextCol(screen, ld, row++); 3902d522f475Smrg } 3903956cc18dSsnj#if OPT_DEC_CHRSET 3904956cc18dSsnj if (ld == 0) 3905956cc18dSsnj ld = GET_LINEDATA(screen, row); 3906956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3907956cc18dSsnj col /= 2; 3908956cc18dSsnj#endif 3909d522f475Smrg return col; 3910d522f475Smrg} 3911d522f475Smrg 3912d522f475Smrgstatic void 3913e0a2b6dfSmrgdo_select_regex(TScreen *screen, CELL *startc, CELL *endc) 3914d522f475Smrg{ 3915956cc18dSsnj LineData *ld = GET_LINEDATA(screen, startc->row); 3916d522f475Smrg int inx = ((screen->numberOfClicks - 1) % screen->maxClicks); 3917d522f475Smrg char *expr = screen->selectExpr[inx]; 3918d522f475Smrg regex_t preg; 3919d522f475Smrg regmatch_t match; 3920d522f475Smrg 392101037d57Smrg TRACE(("Select_REGEX[%d]:%s\n", inx, NonNull(expr))); 3922956cc18dSsnj if (okPosition(screen, &ld, startc) && expr != 0) { 3923d522f475Smrg if (regcomp(&preg, expr, REG_EXTENDED) == 0) { 3924d522f475Smrg int firstRow = firstRowOfLine(screen, startc->row, True); 3925d522f475Smrg int lastRow = lastRowOfLine(screen, firstRow); 3926d522f475Smrg unsigned size = lengthOfLines(screen, firstRow, lastRow); 3927d522f475Smrg int actual = cellToColumn(screen, startc); 39282e4f8982Smrg int *indexed; 3929d522f475Smrg 3930d522f475Smrg TRACE(("regcomp ok rows %d..%d bytes %d\n", 3931d522f475Smrg firstRow, lastRow, size)); 3932d522f475Smrg 3933d522f475Smrg if ((indexed = TypeCallocN(int, size + 1)) != 0) { 39342e4f8982Smrg char *search; 3935d522f475Smrg if ((search = make_indexed_text(screen, 3936d522f475Smrg firstRow, 3937d522f475Smrg size, 3938d522f475Smrg indexed)) != 0) { 39392eaa94a1Schristos int len = (int) strlen(search); 3940d522f475Smrg int col; 3941d522f475Smrg int best_col = -1; 3942d522f475Smrg int best_len = -1; 3943d522f475Smrg 3944913cc679Smrg startc->row = 0; 3945913cc679Smrg startc->col = 0; 3946913cc679Smrg endc->row = 0; 3947913cc679Smrg endc->col = 0; 3948913cc679Smrg 3949d522f475Smrg for (col = 0; indexed[col] < len; ++col) { 3950d522f475Smrg if (regexec(&preg, 3951d522f475Smrg search + indexed[col], 395220d2c4d2Smrg (size_t) 1, &match, 0) == 0) { 3953894e0ac8Smrg int start_inx = (int) (match.rm_so + indexed[col]); 3954894e0ac8Smrg int finis_inx = (int) (match.rm_eo + indexed[col]); 3955d522f475Smrg int start_col = indexToCol(indexed, len, start_inx); 3956d522f475Smrg int finis_col = indexToCol(indexed, len, finis_inx); 3957d522f475Smrg 3958d522f475Smrg if (start_col <= actual && 3959913cc679Smrg actual <= finis_col) { 3960d522f475Smrg int test = finis_col - start_col; 3961d522f475Smrg if (best_len < test) { 3962d522f475Smrg best_len = test; 3963d522f475Smrg best_col = start_col; 3964d522f475Smrg TRACE(("match column %d len %d\n", 3965d522f475Smrg best_col, 3966d522f475Smrg best_len)); 3967d522f475Smrg } 3968d522f475Smrg } 3969d522f475Smrg } 3970d522f475Smrg } 3971d522f475Smrg if (best_col >= 0) { 3972d522f475Smrg int best_nxt = best_col + best_len; 3973d522f475Smrg columnToCell(screen, firstRow, best_col, startc); 3974d522f475Smrg columnToCell(screen, firstRow, best_nxt, endc); 3975d522f475Smrg TRACE(("search::%s\n", search)); 3976d522f475Smrg TRACE(("indexed:%d..%d -> %d..%d\n", 3977d522f475Smrg best_col, best_nxt, 3978d522f475Smrg indexed[best_col], 3979d522f475Smrg indexed[best_nxt])); 3980d522f475Smrg TRACE(("matched:%d:%s\n", 3981d522f475Smrg indexed[best_nxt] + 1 - 3982d522f475Smrg indexed[best_col], 3983956cc18dSsnj visibleChars((Char *) (search + indexed[best_col]), 3984d522f475Smrg (unsigned) (indexed[best_nxt] + 3985d522f475Smrg 1 - 3986d522f475Smrg indexed[best_col])))); 3987d522f475Smrg } 3988d522f475Smrg free(search); 3989d522f475Smrg } 3990d522f475Smrg free(indexed); 3991956cc18dSsnj#if OPT_DEC_CHRSET 3992956cc18dSsnj if ((ld = GET_LINEDATA(screen, startc->row)) != 0) { 3993956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3994956cc18dSsnj startc->col *= 2; 3995956cc18dSsnj } 3996956cc18dSsnj if ((ld = GET_LINEDATA(screen, endc->row)) != 0) { 3997956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3998956cc18dSsnj endc->col *= 2; 3999956cc18dSsnj } 4000956cc18dSsnj#endif 4001d522f475Smrg } 4002d522f475Smrg regfree(&preg); 4003d522f475Smrg } 4004d522f475Smrg } 4005d522f475Smrg} 4006d522f475Smrg#endif /* OPT_SELECT_REGEX */ 4007d522f475Smrg 4008956cc18dSsnj#define InitRow(name) \ 4009956cc18dSsnj ld.name = GET_LINEDATA(screen, screen->name.row) 4010956cc18dSsnj 4011956cc18dSsnj#define NextRow(name) \ 4012956cc18dSsnj ld.name = GET_LINEDATA(screen, ++screen->name.row) 4013956cc18dSsnj 4014956cc18dSsnj#define PrevRow(name) \ 4015956cc18dSsnj ld.name = GET_LINEDATA(screen, --screen->name.row) 4016956cc18dSsnj 401720d2c4d2Smrg#define MoreRows(name) \ 401820d2c4d2Smrg (screen->name.row < screen->max_row) 401920d2c4d2Smrg 4020956cc18dSsnj#define isPrevWrapped(name) \ 4021956cc18dSsnj (screen->name.row > 0 \ 4022956cc18dSsnj && (ltmp = GET_LINEDATA(screen, screen->name.row - 1)) != 0 \ 4023956cc18dSsnj && LineTstWrapped(ltmp)) 4024956cc18dSsnj 4025d522f475Smrg/* 4026d522f475Smrg * sets startSel endSel 4027d522f475Smrg * ensuring that they have legal values 4028d522f475Smrg */ 4029d522f475Smrgstatic void 4030d522f475SmrgComputeSelect(XtermWidget xw, 4031e0a2b6dfSmrg CELL *startc, 4032e0a2b6dfSmrg CELL *endc, 4033f2e35a3aSmrg Bool extend, 4034f2e35a3aSmrg Bool normal) 4035d522f475Smrg{ 4036956cc18dSsnj TScreen *screen = TScreenOf(xw); 4037956cc18dSsnj 4038d522f475Smrg int cclass; 4039d522f475Smrg CELL first = *startc; 4040d522f475Smrg CELL last = *endc; 4041956cc18dSsnj Boolean ignored = False; 4042956cc18dSsnj 4043956cc18dSsnj struct { 4044956cc18dSsnj LineData *startSel; 4045956cc18dSsnj LineData *endSel; 4046956cc18dSsnj } ld; 4047956cc18dSsnj LineData *ltmp; 4048d522f475Smrg 4049d522f475Smrg TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n", 4050d522f475Smrg first.row, first.col, 4051d522f475Smrg last.row, last.col, 4052d522f475Smrg extend ? "" : "no")); 4053d522f475Smrg 4054d522f475Smrg#if OPT_WIDE_CHARS 4055d522f475Smrg if (first.col > 1 4056d522f475Smrg && isWideCell(first.row, first.col - 1) 4057d522f475Smrg && XTERM_CELL(first.row, first.col - 0) == HIDDEN_CHAR) { 405820d2c4d2Smrg TRACE(("Adjusting start. Changing downwards from %i.\n", first.col)); 4059d522f475Smrg first.col -= 1; 4060d522f475Smrg if (last.col == (first.col + 1)) 4061d522f475Smrg last.col--; 4062d522f475Smrg } 4063d522f475Smrg 4064d522f475Smrg if (last.col > 1 4065d522f475Smrg && isWideCell(last.row, last.col - 1) 4066d522f475Smrg && XTERM_CELL(last.row, last.col) == HIDDEN_CHAR) { 4067d522f475Smrg last.col += 1; 4068d522f475Smrg } 4069d522f475Smrg#endif 4070d522f475Smrg 4071d522f475Smrg if (Coordinate(screen, &first) <= Coordinate(screen, &last)) { 4072d522f475Smrg screen->startSel = screen->startRaw = first; 4073d522f475Smrg screen->endSel = screen->endRaw = last; 4074d522f475Smrg } else { /* Swap them */ 4075d522f475Smrg screen->startSel = screen->startRaw = last; 4076d522f475Smrg screen->endSel = screen->endRaw = first; 4077d522f475Smrg } 4078d522f475Smrg 4079956cc18dSsnj InitRow(startSel); 4080956cc18dSsnj InitRow(endSel); 4081956cc18dSsnj 4082d522f475Smrg switch (screen->selectUnit) { 4083d522f475Smrg case Select_CHAR: 4084956cc18dSsnj (void) okPosition(screen, &(ld.startSel), &(screen->startSel)); 4085956cc18dSsnj (void) okPosition(screen, &(ld.endSel), &(screen->endSel)); 4086d522f475Smrg break; 4087d522f475Smrg 4088d522f475Smrg case Select_WORD: 4089d522f475Smrg TRACE(("Select_WORD\n")); 4090956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 4091f2e35a3aSmrg CELL mark; 4092956cc18dSsnj cclass = CClassOf(startSel); 4093f2e35a3aSmrg TRACE(("...starting with class %d\n", cclass)); 4094d522f475Smrg do { 4095f2e35a3aSmrg mark = screen->startSel; 4096d522f475Smrg --screen->startSel.col; 4097956cc18dSsnj if (screen->startSel.col < 0 4098956cc18dSsnj && isPrevWrapped(startSel)) { 4099956cc18dSsnj PrevRow(startSel); 4100956cc18dSsnj screen->startSel.col = LastTextCol(screen, ld.startSel, screen->startSel.row); 4101d522f475Smrg } 4102d522f475Smrg } while (screen->startSel.col >= 0 4103956cc18dSsnj && CClassSelects(startSel, cclass)); 4104f2e35a3aSmrg if (normal) 4105f2e35a3aSmrg ++screen->startSel.col; 4106f2e35a3aSmrg else 4107f2e35a3aSmrg screen->startSel = mark; 4108d522f475Smrg } 4109d522f475Smrg#if OPT_WIDE_CHARS 4110f2e35a3aSmrg#define SkipHiddenCell(mark) \ 4111f2e35a3aSmrg if (mark.col && XTERM_CELL(mark.row, mark.col) == HIDDEN_CHAR) \ 4112f2e35a3aSmrg mark.col++ 4113f2e35a3aSmrg#else 4114f2e35a3aSmrg#define SkipHiddenCell(mark) /* nothing */ 4115d522f475Smrg#endif 4116f2e35a3aSmrg SkipHiddenCell(screen->startSel); 4117f2e35a3aSmrg 4118f2e35a3aSmrg if (!normal) { 4119f2e35a3aSmrg screen->endSel = screen->startSel; 4120f2e35a3aSmrg ld.endSel = ld.startSel; 4121f2e35a3aSmrg } 4122d522f475Smrg 4123956cc18dSsnj if (okPosition(screen, &(ld.endSel), &(screen->endSel))) { 41242e4f8982Smrg int length = LastTextCol(screen, ld.endSel, screen->endSel.row); 4125956cc18dSsnj cclass = CClassOf(endSel); 4126f2e35a3aSmrg TRACE(("...ending with class %d\n", cclass)); 4127d522f475Smrg do { 4128d522f475Smrg ++screen->endSel.col; 4129d522f475Smrg if (screen->endSel.col > length 4130956cc18dSsnj && LineTstWrapped(ld.endSel)) { 413120d2c4d2Smrg if (!MoreRows(endSel)) 413220d2c4d2Smrg break; 4133d522f475Smrg screen->endSel.col = 0; 4134956cc18dSsnj NextRow(endSel); 4135956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 4136d522f475Smrg } 4137d522f475Smrg } while (screen->endSel.col <= length 4138956cc18dSsnj && CClassSelects(endSel, cclass)); 4139f2e35a3aSmrg if (normal 4140f2e35a3aSmrg && screen->endSel.col > length + 1 414120d2c4d2Smrg && MoreRows(endSel)) { 4142d522f475Smrg screen->endSel.col = 0; 4143956cc18dSsnj NextRow(endSel); 4144d522f475Smrg } 4145d522f475Smrg } 4146f2e35a3aSmrg SkipHiddenCell(screen->endSel); 4147d522f475Smrg 4148d522f475Smrg screen->saveStartW = screen->startSel; 4149d522f475Smrg break; 4150d522f475Smrg 4151d522f475Smrg case Select_LINE: 4152d522f475Smrg TRACE(("Select_LINE\n")); 415320d2c4d2Smrg while (LineTstWrapped(ld.endSel) 415420d2c4d2Smrg && MoreRows(endSel)) { 4155956cc18dSsnj NextRow(endSel); 4156d522f475Smrg } 4157d522f475Smrg if (screen->cutToBeginningOfLine 4158d522f475Smrg || screen->startSel.row < screen->saveStartW.row) { 4159d522f475Smrg screen->startSel.col = 0; 4160956cc18dSsnj while (isPrevWrapped(startSel)) { 4161956cc18dSsnj PrevRow(startSel); 4162d522f475Smrg } 4163d522f475Smrg } else if (!extend) { 4164d522f475Smrg if ((first.row < screen->saveStartW.row) 4165d522f475Smrg || (isSameRow(&first, &(screen->saveStartW)) 4166d522f475Smrg && first.col < screen->saveStartW.col)) { 4167d522f475Smrg screen->startSel.col = 0; 4168956cc18dSsnj while (isPrevWrapped(startSel)) { 4169956cc18dSsnj PrevRow(startSel); 4170d522f475Smrg } 4171d522f475Smrg } else { 4172d522f475Smrg screen->startSel = screen->saveStartW; 4173d522f475Smrg } 4174d522f475Smrg } 4175956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 4176d522f475Smrg break; 4177d522f475Smrg 4178d522f475Smrg case Select_GROUP: /* paragraph */ 4179d522f475Smrg TRACE(("Select_GROUP\n")); 4180956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 4181d522f475Smrg /* scan backward for beginning of group */ 4182d522f475Smrg while (screen->startSel.row > 0 && 4183956cc18dSsnj (LastTextCol(screen, ld.startSel, screen->startSel.row - 4184956cc18dSsnj 1) > 0 || 4185956cc18dSsnj isPrevWrapped(startSel))) { 4186956cc18dSsnj PrevRow(startSel); 4187d522f475Smrg } 4188d522f475Smrg screen->startSel.col = 0; 4189d522f475Smrg /* scan forward for end of group */ 419020d2c4d2Smrg while (MoreRows(endSel) && 4191956cc18dSsnj (LastTextCol(screen, ld.endSel, screen->endSel.row + 1) > 4192956cc18dSsnj 0 || 4193956cc18dSsnj LineTstWrapped(ld.endSel))) { 4194956cc18dSsnj NextRow(endSel); 4195d522f475Smrg } 4196956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 4197d522f475Smrg } 4198d522f475Smrg break; 4199d522f475Smrg 4200d522f475Smrg case Select_PAGE: /* everything one can see */ 4201d522f475Smrg TRACE(("Select_PAGE\n")); 4202d522f475Smrg screen->startSel.row = 0; 4203d522f475Smrg screen->startSel.col = 0; 420420d2c4d2Smrg screen->endSel.row = MaxRows(screen); 4205d522f475Smrg screen->endSel.col = 0; 4206d522f475Smrg break; 4207d522f475Smrg 4208d522f475Smrg case Select_ALL: /* counts scrollback if in normal screen */ 4209d522f475Smrg TRACE(("Select_ALL\n")); 4210d522f475Smrg screen->startSel.row = -screen->savedlines; 4211d522f475Smrg screen->startSel.col = 0; 421220d2c4d2Smrg screen->endSel.row = MaxRows(screen); 4213d522f475Smrg screen->endSel.col = 0; 4214d522f475Smrg break; 4215d522f475Smrg 4216d522f475Smrg#if OPT_SELECT_REGEX 4217d522f475Smrg case Select_REGEX: 4218d522f475Smrg do_select_regex(screen, &(screen->startSel), &(screen->endSel)); 4219d522f475Smrg break; 4220d522f475Smrg#endif 4221d522f475Smrg 4222d522f475Smrg case NSELECTUNITS: /* always ignore */ 4223956cc18dSsnj ignored = True; 4224956cc18dSsnj break; 4225d522f475Smrg } 4226d522f475Smrg 4227956cc18dSsnj if (!ignored) { 4228956cc18dSsnj /* check boundaries */ 4229956cc18dSsnj ScrollSelection(screen, 0, False); 4230956cc18dSsnj TrackText(xw, &(screen->startSel), &(screen->endSel)); 4231956cc18dSsnj } 4232d522f475Smrg 4233d522f475Smrg return; 4234d522f475Smrg} 4235d522f475Smrg 4236d522f475Smrg/* Guaranteed (first.row, first.col) <= (last.row, last.col) */ 4237d522f475Smrgstatic void 4238d522f475SmrgTrackText(XtermWidget xw, 4239e0a2b6dfSmrg const CELL *firstp, 4240e0a2b6dfSmrg const CELL *lastp) 4241d522f475Smrg{ 4242956cc18dSsnj TScreen *screen = TScreenOf(xw); 4243d522f475Smrg int from, to; 4244d522f475Smrg CELL old_start, old_end; 4245d522f475Smrg CELL first = *firstp; 4246d522f475Smrg CELL last = *lastp; 4247d522f475Smrg 4248d522f475Smrg TRACE(("TrackText(first=%d,%d, last=%d,%d)\n", 4249d522f475Smrg first.row, first.col, last.row, last.col)); 4250d522f475Smrg 4251d522f475Smrg old_start = screen->startH; 4252d522f475Smrg old_end = screen->endH; 42530bd37d32Smrg TRACE(("...previous(first=%d,%d, last=%d,%d)\n", 42540bd37d32Smrg old_start.row, old_start.col, 42550bd37d32Smrg old_end.row, old_end.col)); 4256d522f475Smrg if (isSameCELL(&first, &old_start) && 42570bd37d32Smrg isSameCELL(&last, &old_end)) { 4258d522f475Smrg return; 42590bd37d32Smrg } 42600bd37d32Smrg 4261d522f475Smrg screen->startH = first; 4262d522f475Smrg screen->endH = last; 4263d522f475Smrg from = Coordinate(screen, &screen->startH); 4264d522f475Smrg to = Coordinate(screen, &screen->endH); 4265d522f475Smrg if (to <= screen->startHCoord || from > screen->endHCoord) { 4266d522f475Smrg /* No overlap whatsoever between old and new hilite */ 4267d522f475Smrg ReHiliteText(xw, &old_start, &old_end); 4268d522f475Smrg ReHiliteText(xw, &first, &last); 4269d522f475Smrg } else { 4270d522f475Smrg if (from < screen->startHCoord) { 4271d522f475Smrg /* Extend left end */ 4272d522f475Smrg ReHiliteText(xw, &first, &old_start); 4273d522f475Smrg } else if (from > screen->startHCoord) { 4274d522f475Smrg /* Shorten left end */ 4275d522f475Smrg ReHiliteText(xw, &old_start, &first); 4276d522f475Smrg } 4277d522f475Smrg if (to > screen->endHCoord) { 4278d522f475Smrg /* Extend right end */ 4279d522f475Smrg ReHiliteText(xw, &old_end, &last); 4280d522f475Smrg } else if (to < screen->endHCoord) { 4281d522f475Smrg /* Shorten right end */ 4282d522f475Smrg ReHiliteText(xw, &last, &old_end); 4283d522f475Smrg } 4284d522f475Smrg } 4285d522f475Smrg screen->startHCoord = from; 4286d522f475Smrg screen->endHCoord = to; 4287d522f475Smrg} 4288d522f475Smrg 4289f2e35a3aSmrgstatic void 4290f2e35a3aSmrgUnHiliteText(XtermWidget xw) 4291f2e35a3aSmrg{ 4292f2e35a3aSmrg TrackText(xw, &zeroCELL, &zeroCELL); 4293f2e35a3aSmrg} 4294f2e35a3aSmrg 4295d522f475Smrg/* Guaranteed that (first->row, first->col) <= (last->row, last->col) */ 4296d522f475Smrgstatic void 4297d522f475SmrgReHiliteText(XtermWidget xw, 4298e0a2b6dfSmrg CELL *firstp, 4299e0a2b6dfSmrg CELL *lastp) 4300d522f475Smrg{ 4301956cc18dSsnj TScreen *screen = TScreenOf(xw); 4302d522f475Smrg CELL first = *firstp; 4303d522f475Smrg CELL last = *lastp; 4304d522f475Smrg 4305d522f475Smrg TRACE(("ReHiliteText from %d.%d to %d.%d\n", 4306d522f475Smrg first.row, first.col, last.row, last.col)); 4307d522f475Smrg 4308d522f475Smrg if (first.row < 0) 4309d522f475Smrg first.row = first.col = 0; 4310d522f475Smrg else if (first.row > screen->max_row) 4311d522f475Smrg return; /* nothing to do, since last.row >= first.row */ 4312d522f475Smrg 4313d522f475Smrg if (last.row < 0) 4314d522f475Smrg return; /* nothing to do, since first.row <= last.row */ 4315d522f475Smrg else if (last.row > screen->max_row) { 4316d522f475Smrg last.row = screen->max_row; 4317d522f475Smrg last.col = MaxCols(screen); 4318d522f475Smrg } 4319d522f475Smrg if (isSameCELL(&first, &last)) 4320d522f475Smrg return; 4321d522f475Smrg 4322d522f475Smrg if (!isSameRow(&first, &last)) { /* do multiple rows */ 43232e4f8982Smrg int i; 4324d522f475Smrg if ((i = screen->max_col - first.col + 1) > 0) { /* first row */ 4325d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, i, True); 4326d522f475Smrg } 4327d522f475Smrg if ((i = last.row - first.row - 1) > 0) { /* middle rows */ 4328d522f475Smrg ScrnRefresh(xw, first.row + 1, 0, i, MaxCols(screen), True); 4329d522f475Smrg } 4330d522f475Smrg if (last.col > 0 && last.row <= screen->max_row) { /* last row */ 4331d522f475Smrg ScrnRefresh(xw, last.row, 0, 1, last.col, True); 4332d522f475Smrg } 4333d522f475Smrg } else { /* do single row */ 4334d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, last.col - first.col, True); 4335d522f475Smrg } 4336d522f475Smrg} 4337d522f475Smrg 4338d522f475Smrg/* 4339913cc679Smrg * Guaranteed that (cellc->row, cellc->col) <= (cell->row, cell->col), 4340913cc679Smrg * and that both points are valid 4341d522f475Smrg * (may have cell->row = screen->max_row+1, cell->col = 0). 4342d522f475Smrg */ 4343d522f475Smrgstatic void 4344d522f475SmrgSaltTextAway(XtermWidget xw, 4345f2e35a3aSmrg int which, 4346e0a2b6dfSmrg CELL *cellc, 4347e0a2b6dfSmrg CELL *cell) 4348d522f475Smrg{ 4349956cc18dSsnj TScreen *screen = TScreenOf(xw); 4350f2e35a3aSmrg SelectedCells *scp; 4351f2e35a3aSmrg int i; 4352d522f475Smrg int eol; 4353f2e35a3aSmrg int need = 0; 4354f2e35a3aSmrg size_t have = 0; 4355d522f475Smrg Char *line; 4356d522f475Smrg Char *lp; 4357d522f475Smrg CELL first = *cellc; 4358d522f475Smrg CELL last = *cell; 4359d522f475Smrg 4360f2e35a3aSmrg if (which < 0 || which >= MAX_SELECTIONS) { 4361f2e35a3aSmrg TRACE(("SaltTextAway - which selection?\n")); 4362f2e35a3aSmrg return; 4363f2e35a3aSmrg } 4364f2e35a3aSmrg scp = &(screen->selected_cells[which]); 4365f2e35a3aSmrg 4366f2e35a3aSmrg TRACE(("SaltTextAway which=%d, first=%d,%d, last=%d,%d\n", 4367f2e35a3aSmrg which, first.row, first.col, last.row, last.col)); 4368f2e35a3aSmrg 4369d522f475Smrg if (isSameRow(&first, &last) && first.col > last.col) { 43702e4f8982Smrg int tmp; 4371956cc18dSsnj EXCHANGE(first.col, last.col, tmp); 4372d522f475Smrg } 4373d522f475Smrg 4374d522f475Smrg --last.col; 4375d522f475Smrg /* first we need to know how long the string is before we can save it */ 4376d522f475Smrg 4377d522f475Smrg if (isSameRow(&last, &first)) { 4378f2e35a3aSmrg need = Length(screen, first.row, first.col, last.col); 4379d522f475Smrg } else { /* two cases, cut is on same line, cut spans multiple lines */ 4380f2e35a3aSmrg need += Length(screen, first.row, first.col, screen->max_col) + 1; 4381d522f475Smrg for (i = first.row + 1; i < last.row; i++) 4382f2e35a3aSmrg need += Length(screen, i, 0, screen->max_col) + 1; 4383d522f475Smrg if (last.col >= 0) 4384f2e35a3aSmrg need += Length(screen, last.row, 0, last.col); 4385d522f475Smrg } 4386d522f475Smrg 4387d522f475Smrg /* UTF-8 may require more space */ 4388d522f475Smrg if_OPT_WIDE_CHARS(screen, { 4389f2e35a3aSmrg if (need > 0) { 4390f2e35a3aSmrg if (screen->max_combining > 0) 4391f2e35a3aSmrg need += screen->max_combining; 4392f2e35a3aSmrg need *= 6; 4393f2e35a3aSmrg } 4394d522f475Smrg }); 4395d522f475Smrg 4396d522f475Smrg /* now get some memory to save it in */ 4397f2e35a3aSmrg if (need < 0) 4398f2e35a3aSmrg return; 4399d522f475Smrg 4400f2e35a3aSmrg if (scp->data_limit <= (unsigned) need) { 4401f2e35a3aSmrg if ((line = (Char *) malloc((size_t) need + 1)) == 0) 4402d522f475Smrg SysError(ERROR_BMALLOC2); 4403f2e35a3aSmrg free(scp->data_buffer); 4404f2e35a3aSmrg scp->data_buffer = line; 4405f2e35a3aSmrg scp->data_limit = (size_t) (need + 1); 4406d522f475Smrg } else { 4407f2e35a3aSmrg line = scp->data_buffer; 4408d522f475Smrg } 4409d522f475Smrg 4410f2e35a3aSmrg if (line == 0) 4411d522f475Smrg return; 4412d522f475Smrg 4413f2e35a3aSmrg line[need] = '\0'; /* make sure it is null terminated */ 4414d522f475Smrg lp = line; /* lp points to where to save the text */ 4415d522f475Smrg if (isSameRow(&last, &first)) { 4416d522f475Smrg lp = SaveText(screen, last.row, first.col, last.col, lp, &eol); 4417d522f475Smrg } else { 4418d522f475Smrg lp = SaveText(screen, first.row, first.col, screen->max_col, lp, &eol); 4419d522f475Smrg if (eol) 4420d522f475Smrg *lp++ = '\n'; /* put in newline at end of line */ 4421d522f475Smrg for (i = first.row + 1; i < last.row; i++) { 4422d522f475Smrg lp = SaveText(screen, i, 0, screen->max_col, lp, &eol); 4423d522f475Smrg if (eol) 4424d522f475Smrg *lp++ = '\n'; 4425d522f475Smrg } 4426d522f475Smrg if (last.col >= 0) 4427d522f475Smrg lp = SaveText(screen, last.row, 0, last.col, lp, &eol); 4428d522f475Smrg } 4429d522f475Smrg *lp = '\0'; /* make sure we have end marked */ 4430d522f475Smrg 4431f2e35a3aSmrg have = (size_t) (lp - line); 4432f2e35a3aSmrg /* 4433f2e35a3aSmrg * Scanning the buffer twice is unnecessary. Discard unwanted memory if 4434f2e35a3aSmrg * the estimate is too-far off. 4435f2e35a3aSmrg */ 4436f2e35a3aSmrg if ((have * 2) < (size_t) need) { 4437f2e35a3aSmrg Char *next; 4438f2e35a3aSmrg scp->data_limit = have + 1; 4439f2e35a3aSmrg next = realloc(line, scp->data_limit); 4440f2e35a3aSmrg if (next == NULL) { 4441f2e35a3aSmrg free(line); 4442f2e35a3aSmrg scp->data_length = 0; 4443f2e35a3aSmrg scp->data_limit = 0; 4444f2e35a3aSmrg } 4445f2e35a3aSmrg scp->data_buffer = next; 4446f2e35a3aSmrg } 4447f2e35a3aSmrg scp->data_length = have; 4448d522f475Smrg 4449f2e35a3aSmrg TRACE(("Salted TEXT:%u:%s\n", (unsigned) have, 4450f2e35a3aSmrg visibleChars(scp->data_buffer, (unsigned) have))); 4451d522f475Smrg} 4452d522f475Smrg 4453d522f475Smrg#if OPT_PASTE64 4454d522f475Smrgvoid 4455f2e35a3aSmrgClearSelectionBuffer(TScreen *screen, String selection) 4456d522f475Smrg{ 4457f2e35a3aSmrg int which = TargetToSelection(screen, selection); 4458f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[okSelectionCode(which)]); 4459f2e35a3aSmrg FreeAndNull(scp->data_buffer); 4460f2e35a3aSmrg scp->data_limit = 0; 4461f2e35a3aSmrg scp->data_length = 0; 4462d522f475Smrg screen->base64_count = 0; 4463d522f475Smrg} 4464d522f475Smrg 4465d522f475Smrgstatic void 4466f2e35a3aSmrgAppendStrToSelectionBuffer(SelectedCells * scp, Char *text, size_t len) 4467d522f475Smrg{ 4468d522f475Smrg if (len != 0) { 4469f2e35a3aSmrg size_t j = (scp->data_length + len); 4470f2e35a3aSmrg size_t k = j + (j >> 2) + 80; 4471f2e35a3aSmrg if (j + 1 >= scp->data_limit) { 4472f2e35a3aSmrg Char *line; 4473f2e35a3aSmrg if (!scp->data_length) { 4474f2e35a3aSmrg line = (Char *) malloc(k); 4475d522f475Smrg } else { 4476f2e35a3aSmrg line = (Char *) realloc(scp->data_buffer, k); 4477d522f475Smrg } 4478f2e35a3aSmrg if (line == 0) 4479f2e35a3aSmrg SysError(ERROR_BMALLOC2); 4480f2e35a3aSmrg scp->data_buffer = line; 4481f2e35a3aSmrg scp->data_limit = k; 4482d522f475Smrg } 4483f2e35a3aSmrg if (scp->data_buffer != 0) { 4484f2e35a3aSmrg memcpy(scp->data_buffer + scp->data_length, text, len); 4485f2e35a3aSmrg scp->data_length += len; 4486f2e35a3aSmrg scp->data_buffer[scp->data_length] = 0; 448720d2c4d2Smrg } 4488d522f475Smrg } 4489d522f475Smrg} 4490d522f475Smrg 4491d522f475Smrgvoid 4492f2e35a3aSmrgAppendToSelectionBuffer(TScreen *screen, unsigned c, String selection) 4493d522f475Smrg{ 4494f2e35a3aSmrg int which = TargetToSelection(screen, selection); 4495f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[okSelectionCode(which)]); 44962eaa94a1Schristos unsigned six; 4497d522f475Smrg Char ch; 4498d522f475Smrg 4499d522f475Smrg /* Decode base64 character */ 4500d522f475Smrg if (c >= 'A' && c <= 'Z') 4501d522f475Smrg six = c - 'A'; 4502d522f475Smrg else if (c >= 'a' && c <= 'z') 4503d522f475Smrg six = c - 'a' + 26; 4504d522f475Smrg else if (c >= '0' && c <= '9') 4505d522f475Smrg six = c - '0' + 52; 4506d522f475Smrg else if (c == '+') 4507d522f475Smrg six = 62; 4508d522f475Smrg else if (c == '/') 4509d522f475Smrg six = 63; 4510d522f475Smrg else 4511d522f475Smrg return; 4512d522f475Smrg 4513d522f475Smrg /* Accumulate bytes */ 4514d522f475Smrg switch (screen->base64_count) { 4515d522f475Smrg case 0: 4516d522f475Smrg screen->base64_accu = six; 4517d522f475Smrg screen->base64_count = 6; 4518d522f475Smrg break; 4519d522f475Smrg 4520d522f475Smrg case 2: 45212eaa94a1Schristos ch = CharOf((screen->base64_accu << 6) + six); 4522d522f475Smrg screen->base64_count = 0; 4523f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4524d522f475Smrg break; 4525d522f475Smrg 4526d522f475Smrg case 4: 45272eaa94a1Schristos ch = CharOf((screen->base64_accu << 4) + (six >> 2)); 4528d522f475Smrg screen->base64_accu = (six & 0x3); 4529d522f475Smrg screen->base64_count = 2; 4530f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4531d522f475Smrg break; 4532d522f475Smrg 4533d522f475Smrg case 6: 45342eaa94a1Schristos ch = CharOf((screen->base64_accu << 2) + (six >> 4)); 4535d522f475Smrg screen->base64_accu = (six & 0xF); 4536d522f475Smrg screen->base64_count = 4; 4537f2e35a3aSmrg AppendStrToSelectionBuffer(scp, &ch, (size_t) 1); 4538d522f475Smrg break; 4539d522f475Smrg } 4540d522f475Smrg} 4541d522f475Smrg 4542d522f475Smrgvoid 4543e0a2b6dfSmrgCompleteSelection(XtermWidget xw, String *args, Cardinal len) 4544d522f475Smrg{ 4545956cc18dSsnj TScreen *screen = TScreenOf(xw); 4546956cc18dSsnj 4547956cc18dSsnj screen->base64_count = 0; 4548956cc18dSsnj screen->base64_accu = 0; 4549d522f475Smrg _OwnSelection(xw, args, len); 4550d522f475Smrg} 4551d522f475Smrg#endif /* OPT_PASTE64 */ 4552d522f475Smrg 4553d522f475Smrgstatic Bool 4554d522f475Smrg_ConvertSelectionHelper(Widget w, 4555f2e35a3aSmrg SelectedCells * scp, 4556894e0ac8Smrg Atom *type, 4557d522f475Smrg XtPointer *value, 4558d522f475Smrg unsigned long *length, 4559d522f475Smrg int *format, 4560d522f475Smrg int (*conversion_function) (Display *, 4561d522f475Smrg char **, int, 4562d522f475Smrg XICCEncodingStyle, 4563d522f475Smrg XTextProperty *), 4564d522f475Smrg XICCEncodingStyle conversion_style) 4565d522f475Smrg{ 456601037d57Smrg *value = 0; 456701037d57Smrg *length = 0; 456801037d57Smrg *type = 0; 456901037d57Smrg *format = 0; 457001037d57Smrg 4571f2e35a3aSmrg if (getXtermWidget(w) != 0) { 4572d522f475Smrg Display *dpy = XtDisplay(w); 4573d522f475Smrg XTextProperty textprop; 457401037d57Smrg int out_n = 0; 457501037d57Smrg char *result = 0; 4576f2e35a3aSmrg char *the_data = (char *) scp->data_buffer; 457701037d57Smrg char *the_next; 4578f2e35a3aSmrg unsigned long remaining = scp->data_length; 457901037d57Smrg 458001037d57Smrg TRACE(("converting %ld:'%s'\n", 4581f2e35a3aSmrg (long) scp->data_length, 4582f2e35a3aSmrg visibleChars(scp->data_buffer, (unsigned) scp->data_length))); 458301037d57Smrg /* 458401037d57Smrg * For most selections, we can convert in one pass. It is possible 458501037d57Smrg * that some applications contain embedded nulls, e.g., using xterm's 458601037d57Smrg * paste64 feature. For those cases, we will build up the result in 458701037d57Smrg * parts. 458801037d57Smrg */ 4589f2e35a3aSmrg if (memchr(the_data, 0, scp->data_length) != 0) { 459001037d57Smrg TRACE(("selection contains embedded nulls\n")); 4591f2e35a3aSmrg result = calloc(scp->data_length + 1, sizeof(char)); 459201037d57Smrg } 4593d522f475Smrg 459401037d57Smrg next_try: 459501037d57Smrg memset(&textprop, 0, sizeof(textprop)); 4596d522f475Smrg if (conversion_function(dpy, &the_data, 1, 4597d522f475Smrg conversion_style, 4598d522f475Smrg &textprop) >= Success) { 459901037d57Smrg if ((result != 0) 460001037d57Smrg && (textprop.value != 0) 460101037d57Smrg && (textprop.format == 8)) { 460201037d57Smrg char *text_values = (char *) textprop.value; 460301037d57Smrg unsigned long in_n; 460401037d57Smrg 460501037d57Smrg if (out_n == 0) { 460601037d57Smrg *value = result; 460701037d57Smrg *type = textprop.encoding; 460801037d57Smrg *format = textprop.format; 460901037d57Smrg } 461001037d57Smrg for (in_n = 0; in_n < textprop.nitems; ++in_n) { 461101037d57Smrg result[out_n++] = text_values[in_n]; 461201037d57Smrg } 461301037d57Smrg *length += textprop.nitems; 461401037d57Smrg if ((the_next = memchr(the_data, 0, remaining)) != 0) { 461501037d57Smrg unsigned long this_was = (unsigned long) (the_next - the_data); 461601037d57Smrg this_was++; 461701037d57Smrg the_data += this_was; 461801037d57Smrg remaining -= this_was; 461901037d57Smrg result[out_n++] = 0; 462001037d57Smrg *length += 1; 462101037d57Smrg if (remaining) 462201037d57Smrg goto next_try; 462301037d57Smrg } 462401037d57Smrg return True; 462501037d57Smrg } else { 462601037d57Smrg free(result); 462701037d57Smrg *value = (XtPointer) textprop.value; 462801037d57Smrg *length = textprop.nitems; 462901037d57Smrg *type = textprop.encoding; 463001037d57Smrg *format = textprop.format; 463101037d57Smrg return True; 463201037d57Smrg } 4633d522f475Smrg } 463401037d57Smrg free(result); 4635d522f475Smrg } 4636d522f475Smrg return False; 4637d522f475Smrg} 4638d522f475Smrg 46392eaa94a1Schristosstatic Boolean 46402eaa94a1SchristosSaveConvertedLength(XtPointer *target, unsigned long source) 46412eaa94a1Schristos{ 46422eaa94a1Schristos Boolean result = False; 46432eaa94a1Schristos 46442eaa94a1Schristos *target = XtMalloc(4); 46452eaa94a1Schristos if (*target != 0) { 46462eaa94a1Schristos result = True; 46472eaa94a1Schristos if (sizeof(unsigned long) == 4) { 46482eaa94a1Schristos *(unsigned long *) *target = source; 46492eaa94a1Schristos } else if (sizeof(unsigned) == 4) { 465020d2c4d2Smrg *(unsigned *) *target = (unsigned) source; 46512eaa94a1Schristos } else if (sizeof(unsigned short) == 4) { 46522eaa94a1Schristos *(unsigned short *) *target = (unsigned short) source; 46532eaa94a1Schristos } else { 46542eaa94a1Schristos /* FIXME - does this depend on byte-order? */ 46552eaa94a1Schristos unsigned long temp = source; 465620d2c4d2Smrg memcpy((char *) *target, 465720d2c4d2Smrg ((char *) &temp) + sizeof(temp) - 4, 465820d2c4d2Smrg (size_t) 4); 46592eaa94a1Schristos } 46602eaa94a1Schristos } 46612eaa94a1Schristos return result; 46622eaa94a1Schristos} 46632eaa94a1Schristos 4664f2e35a3aSmrg#define keepClipboard(d,atom) ((screen->keepClipboard) && \ 4665f2e35a3aSmrg (atom == XA_CLIPBOARD(d))) 46662e4f8982Smrg 4667d522f475Smrgstatic Boolean 4668d522f475SmrgConvertSelection(Widget w, 4669894e0ac8Smrg Atom *selection, 4670894e0ac8Smrg Atom *target, 4671894e0ac8Smrg Atom *type, 4672d522f475Smrg XtPointer *value, 4673d522f475Smrg unsigned long *length, 4674d522f475Smrg int *format) 4675d522f475Smrg{ 4676d522f475Smrg Display *dpy = XtDisplay(w); 4677d522f475Smrg TScreen *screen; 4678f2e35a3aSmrg SelectedCells *scp; 4679d522f475Smrg Bool result = False; 4680d522f475Smrg 46812e4f8982Smrg Char *data; 46822e4f8982Smrg unsigned long data_length; 46832e4f8982Smrg 4684956cc18dSsnj XtermWidget xw; 4685956cc18dSsnj 4686956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 4687d522f475Smrg return False; 4688d522f475Smrg 4689956cc18dSsnj screen = TScreenOf(xw); 4690d522f475Smrg 4691f2e35a3aSmrg TRACE(("ConvertSelection %s -> %s\n", 4692f2e35a3aSmrg TraceAtomName(screen->display, *selection), 4693956cc18dSsnj visibleSelectionTarget(dpy, *target))); 4694956cc18dSsnj 4695f2e35a3aSmrg if (keepClipboard(dpy, *selection)) { 46962e4f8982Smrg TRACE(("asked for clipboard\n")); 4697f2e35a3aSmrg scp = &(screen->clipboard_data); 46982e4f8982Smrg } else { 46992e4f8982Smrg TRACE(("asked for selection\n")); 4700f2e35a3aSmrg scp = &(screen->selected_cells[AtomToSelection(dpy, *selection)]); 47012e4f8982Smrg } 47022e4f8982Smrg 4703f2e35a3aSmrg data = scp->data_buffer; 4704f2e35a3aSmrg data_length = scp->data_length; 47052e4f8982Smrg if (data == NULL) { 4706f2e35a3aSmrg TRACE(("...no selection-data\n")); 4707f2e35a3aSmrg return False; 470801037d57Smrg } 470901037d57Smrg 4710d522f475Smrg if (*target == XA_TARGETS(dpy)) { 4711d522f475Smrg Atom *targetP; 4712d522f475Smrg XPointer std_return = 0; 4713d522f475Smrg unsigned long std_length; 4714d522f475Smrg 4715d522f475Smrg if (XmuConvertStandardSelection(w, screen->selection_time, selection, 4716d522f475Smrg target, type, &std_return, 4717d522f475Smrg &std_length, format)) { 4718956cc18dSsnj Atom *my_targets = _SelectionTargets(w); 47192e4f8982Smrg Atom *allocP; 47202e4f8982Smrg Atom *std_targets; 4721956cc18dSsnj 4722956cc18dSsnj TRACE(("XmuConvertStandardSelection - success\n")); 4723a1f3da82Smrg std_targets = (Atom *) (void *) (std_return); 4724d522f475Smrg *length = std_length + 6; 4725d522f475Smrg 4726a1f3da82Smrg targetP = TypeXtMallocN(Atom, *length); 4727d522f475Smrg allocP = targetP; 4728d522f475Smrg 4729d522f475Smrg *value = (XtPointer) targetP; 4730d522f475Smrg 47310bd37d32Smrg if (my_targets != 0) { 47320bd37d32Smrg while (*my_targets != None) { 47330bd37d32Smrg *targetP++ = *my_targets++; 47340bd37d32Smrg } 4735956cc18dSsnj } 4736d522f475Smrg *targetP++ = XA_LENGTH(dpy); 4737d522f475Smrg *targetP++ = XA_LIST_LENGTH(dpy); 4738d522f475Smrg 47392eaa94a1Schristos *length = std_length + (unsigned long) (targetP - allocP); 4740d522f475Smrg 4741d522f475Smrg memcpy(targetP, std_targets, sizeof(Atom) * std_length); 4742d522f475Smrg XtFree((char *) std_targets); 4743d522f475Smrg *type = XA_ATOM; 4744d522f475Smrg *format = 32; 4745d522f475Smrg result = True; 4746956cc18dSsnj } else { 4747956cc18dSsnj TRACE(("XmuConvertStandardSelection - failed\n")); 4748d522f475Smrg } 4749d522f475Smrg } 4750d522f475Smrg#if OPT_WIDE_CHARS 4751d522f475Smrg else if (screen->wide_chars && *target == XA_STRING) { 4752d522f475Smrg result = 4753f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4754f2e35a3aSmrg type, value, length, format, 4755d522f475Smrg Xutf8TextListToTextProperty, 4756d522f475Smrg XStringStyle); 4757956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4758d522f475Smrg } else if (screen->wide_chars && *target == XA_UTF8_STRING(dpy)) { 4759d522f475Smrg result = 4760f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4761f2e35a3aSmrg type, value, length, format, 4762d522f475Smrg Xutf8TextListToTextProperty, 4763d522f475Smrg XUTF8StringStyle); 4764956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4765d522f475Smrg } else if (screen->wide_chars && *target == XA_TEXT(dpy)) { 4766d522f475Smrg result = 4767f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4768f2e35a3aSmrg type, value, length, format, 4769d522f475Smrg Xutf8TextListToTextProperty, 4770d522f475Smrg XStdICCTextStyle); 4771956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4772d522f475Smrg } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(dpy)) { 4773d522f475Smrg result = 4774f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4775f2e35a3aSmrg type, value, length, format, 4776d522f475Smrg Xutf8TextListToTextProperty, 4777d522f475Smrg XCompoundTextStyle); 4778956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4779d522f475Smrg } 4780d522f475Smrg#endif 4781d522f475Smrg 4782d522f475Smrg else if (*target == XA_STRING) { /* not wide_chars */ 4783d522f475Smrg /* We can only reach this point if the selection requestor 4784d522f475Smrg requested STRING before any of TEXT, COMPOUND_TEXT or 4785d522f475Smrg UTF8_STRING. We therefore assume that the requestor is not 4786d522f475Smrg properly internationalised, and dump raw eight-bit data 4787d522f475Smrg with no conversion into the selection. Yes, this breaks 4788d522f475Smrg the ICCCM in non-Latin-1 locales. */ 4789d522f475Smrg *type = XA_STRING; 4790f2e35a3aSmrg *value = (XtPointer) data; 4791f2e35a3aSmrg *length = data_length; 4792d522f475Smrg *format = 8; 4793d522f475Smrg result = True; 4794956cc18dSsnj TRACE(("...raw 8-bit data:%d\n", result)); 4795d522f475Smrg } else if (*target == XA_TEXT(dpy)) { /* not wide_chars */ 4796d522f475Smrg result = 4797f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4798f2e35a3aSmrg type, value, length, format, 4799d522f475Smrg XmbTextListToTextProperty, 4800d522f475Smrg XStdICCTextStyle); 4801956cc18dSsnj TRACE(("...XmbTextListToTextProperty(StdICC):%d\n", result)); 4802d522f475Smrg } else if (*target == XA_COMPOUND_TEXT(dpy)) { /* not wide_chars */ 4803d522f475Smrg result = 4804f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4805f2e35a3aSmrg type, value, length, format, 4806d522f475Smrg XmbTextListToTextProperty, 4807d522f475Smrg XCompoundTextStyle); 4808956cc18dSsnj TRACE(("...XmbTextListToTextProperty(Compound):%d\n", result)); 4809d522f475Smrg } 4810d522f475Smrg#ifdef X_HAVE_UTF8_STRING 4811d522f475Smrg else if (*target == XA_UTF8_STRING(dpy)) { /* not wide_chars */ 4812d522f475Smrg result = 4813f2e35a3aSmrg _ConvertSelectionHelper(w, scp, 4814f2e35a3aSmrg type, value, length, format, 4815d522f475Smrg XmbTextListToTextProperty, 4816d522f475Smrg XUTF8StringStyle); 4817956cc18dSsnj TRACE(("...XmbTextListToTextProperty(UTF8):%d\n", result)); 4818d522f475Smrg } 4819d522f475Smrg#endif 4820d522f475Smrg else if (*target == XA_LIST_LENGTH(dpy)) { 482120d2c4d2Smrg result = SaveConvertedLength(value, (unsigned long) 1); 4822d522f475Smrg *type = XA_INTEGER; 4823d522f475Smrg *length = 1; 4824d522f475Smrg *format = 32; 4825956cc18dSsnj TRACE(("...list of values:%d\n", result)); 4826d522f475Smrg } else if (*target == XA_LENGTH(dpy)) { 4827d522f475Smrg /* This value is wrong if we have UTF-8 text */ 4828f2e35a3aSmrg result = SaveConvertedLength(value, scp->data_length); 4829d522f475Smrg *type = XA_INTEGER; 4830d522f475Smrg *length = 1; 4831d522f475Smrg *format = 32; 4832956cc18dSsnj TRACE(("...list of values:%d\n", result)); 4833d522f475Smrg } else if (XmuConvertStandardSelection(w, 4834d522f475Smrg screen->selection_time, selection, 4835d522f475Smrg target, type, (XPointer *) value, 4836d522f475Smrg length, format)) { 4837d522f475Smrg result = True; 4838956cc18dSsnj TRACE(("...XmuConvertStandardSelection:%d\n", result)); 4839d522f475Smrg } 4840d522f475Smrg 4841d522f475Smrg /* else */ 48422eaa94a1Schristos return (Boolean) result; 4843d522f475Smrg} 4844d522f475Smrg 4845d522f475Smrgstatic void 4846894e0ac8SmrgLoseSelection(Widget w, Atom *selection) 4847d522f475Smrg{ 4848d522f475Smrg TScreen *screen; 4849d522f475Smrg Atom *atomP; 4850d522f475Smrg Cardinal i; 4851d522f475Smrg 4852956cc18dSsnj XtermWidget xw; 4853956cc18dSsnj 4854956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 4855d522f475Smrg return; 4856d522f475Smrg 4857956cc18dSsnj screen = TScreenOf(xw); 4858913cc679Smrg TRACE(("LoseSelection %s\n", TraceAtomName(screen->display, *selection))); 485901037d57Smrg 4860d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 4861d522f475Smrg i < screen->selection_count; i++, atomP++) { 4862d522f475Smrg if (*selection == *atomP) 4863d522f475Smrg *atomP = (Atom) 0; 4864d522f475Smrg if (CutBuffer(*atomP) >= 0) { 4865d522f475Smrg *atomP = (Atom) 0; 4866d522f475Smrg } 4867d522f475Smrg } 4868d522f475Smrg 4869d522f475Smrg for (i = screen->selection_count; i; i--) { 4870d522f475Smrg if (screen->selection_atoms[i - 1] != 0) 4871d522f475Smrg break; 4872d522f475Smrg } 4873d522f475Smrg screen->selection_count = i; 4874d522f475Smrg 4875d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 4876d522f475Smrg i < screen->selection_count; i++, atomP++) { 4877d522f475Smrg if (*atomP == (Atom) 0) { 4878d522f475Smrg *atomP = screen->selection_atoms[--screen->selection_count]; 4879d522f475Smrg } 4880d522f475Smrg } 4881d522f475Smrg 4882d522f475Smrg if (screen->selection_count == 0) 4883f2e35a3aSmrg UnHiliteText(xw); 4884d522f475Smrg} 4885d522f475Smrg 4886d522f475Smrg/* ARGSUSED */ 4887d522f475Smrgstatic void 4888d522f475SmrgSelectionDone(Widget w GCC_UNUSED, 4889894e0ac8Smrg Atom *selection GCC_UNUSED, 4890894e0ac8Smrg Atom *target GCC_UNUSED) 4891d522f475Smrg{ 4892d522f475Smrg /* empty proc so Intrinsics know we want to keep storage */ 489301037d57Smrg TRACE(("SelectionDone\n")); 4894d522f475Smrg} 4895d522f475Smrg 4896d522f475Smrgstatic void 4897d522f475Smrg_OwnSelection(XtermWidget xw, 4898e0a2b6dfSmrg String *selections, 4899d522f475Smrg Cardinal count) 4900d522f475Smrg{ 4901956cc18dSsnj TScreen *screen = TScreenOf(xw); 4902f2e35a3aSmrg Display *dpy = screen->display; 4903d522f475Smrg Atom *atoms = screen->selection_atoms; 4904d522f475Smrg Cardinal i; 4905d522f475Smrg Bool have_selection = False; 4906f2e35a3aSmrg SelectedCells *scp; 4907d522f475Smrg 490820d2c4d2Smrg if (count == 0) 490920d2c4d2Smrg return; 4910d522f475Smrg 4911f2e35a3aSmrg TRACE(("_OwnSelection count %d\n", count)); 4912d522f475Smrg selections = MapSelections(xw, selections, count); 4913d522f475Smrg 4914d522f475Smrg if (count > screen->sel_atoms_size) { 4915d522f475Smrg XtFree((char *) atoms); 4916a1f3da82Smrg atoms = TypeXtMallocN(Atom, count); 4917d522f475Smrg screen->selection_atoms = atoms; 4918d522f475Smrg screen->sel_atoms_size = count; 4919d522f475Smrg } 4920f2e35a3aSmrg XmuInternStrings(dpy, selections, count, atoms); 4921d522f475Smrg for (i = 0; i < count; i++) { 4922d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 4923d522f475Smrg if (cutbuffer >= 0) { 49242eaa94a1Schristos unsigned long limit = 4925f2e35a3aSmrg (unsigned long) (4 * XMaxRequestSize(dpy) - 32); 4926f2e35a3aSmrg scp = &(screen->selected_cells[CutBufferToCode(cutbuffer)]); 4927f2e35a3aSmrg if (scp->data_length > limit) { 492820d2c4d2Smrg TRACE(("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 4929f2e35a3aSmrg (unsigned long) scp->data_length, cutbuffer)); 49300bd37d32Smrg xtermWarning("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 4931f2e35a3aSmrg (unsigned long) scp->data_length, cutbuffer); 4932d522f475Smrg } else { 4933d522f475Smrg /* This used to just use the UTF-8 data, which was totally 4934894e0ac8Smrg * broken as not even the corresponding paste code in xterm 4935d522f475Smrg * understood this! So now it converts to Latin1 first. 4936d522f475Smrg * Robert Brady, 2000-09-05 4937d522f475Smrg */ 4938f2e35a3aSmrg unsigned long length = scp->data_length; 4939f2e35a3aSmrg Char *data = scp->data_buffer; 4940d522f475Smrg if_OPT_WIDE_CHARS((screen), { 4941956cc18dSsnj data = UTF8toLatin1(screen, data, length, &length); 4942d522f475Smrg }); 4943d522f475Smrg TRACE(("XStoreBuffer(%d)\n", cutbuffer)); 4944f2e35a3aSmrg XStoreBuffer(dpy, 4945d522f475Smrg (char *) data, 4946d522f475Smrg (int) length, 4947d522f475Smrg cutbuffer); 4948d522f475Smrg } 4949f2e35a3aSmrg } else { 4950f2e35a3aSmrg int which = AtomToSelection(dpy, atoms[i]); 4951f2e35a3aSmrg if (keepClipboard(dpy, atoms[i])) { 4952f2e35a3aSmrg Char *buf; 4953f2e35a3aSmrg SelectedCells *tcp = &(screen->clipboard_data); 4954f2e35a3aSmrg TRACE(("saving selection to clipboard buffer\n")); 4955f2e35a3aSmrg scp = &(screen->selected_cells[CLIPBOARD_CODE]); 4956f2e35a3aSmrg if ((buf = (Char *) malloc((size_t) scp->data_length)) == 0) 4957f2e35a3aSmrg SysError(ERROR_BMALLOC2); 49582e4f8982Smrg 4959f2e35a3aSmrg free(tcp->data_buffer); 4960f2e35a3aSmrg memcpy(buf, scp->data_buffer, scp->data_length); 4961f2e35a3aSmrg tcp->data_buffer = buf; 4962f2e35a3aSmrg tcp->data_limit = scp->data_length; 4963f2e35a3aSmrg tcp->data_length = scp->data_length; 4964f2e35a3aSmrg } 4965f2e35a3aSmrg scp = &(screen->selected_cells[which]); 4966f2e35a3aSmrg if (scp->data_length == 0) { 4967f2e35a3aSmrg TRACE(("XtDisownSelection(%s, @%ld)\n", 4968f2e35a3aSmrg TraceAtomName(screen->display, atoms[i]), 4969f2e35a3aSmrg (long) screen->selection_time)); 4970f2e35a3aSmrg XtDisownSelection((Widget) xw, 4971f2e35a3aSmrg atoms[i], 4972f2e35a3aSmrg screen->selection_time); 4973f2e35a3aSmrg } else if (!screen->replyToEmacs && atoms[i] != 0) { 4974f2e35a3aSmrg TRACE(("XtOwnSelection(%s, @%ld)\n", 4975f2e35a3aSmrg TraceAtomName(screen->display, atoms[i]), 4976f2e35a3aSmrg (long) screen->selection_time)); 4977f2e35a3aSmrg have_selection |= 4978f2e35a3aSmrg XtOwnSelection((Widget) xw, atoms[i], 4979f2e35a3aSmrg screen->selection_time, 4980f2e35a3aSmrg ConvertSelection, 4981f2e35a3aSmrg LoseSelection, 4982f2e35a3aSmrg SelectionDone); 4983f2e35a3aSmrg } 4984d522f475Smrg } 4985f2e35a3aSmrg TRACE(("... _OwnSelection used length %lu value %s\n", 4986f2e35a3aSmrg (unsigned long) scp->data_length, 4987f2e35a3aSmrg visibleChars(scp->data_buffer, 4988f2e35a3aSmrg (unsigned) scp->data_length))); 4989d522f475Smrg } 4990d522f475Smrg if (!screen->replyToEmacs) 4991d522f475Smrg screen->selection_count = count; 4992d522f475Smrg if (!have_selection) 4993f2e35a3aSmrg UnHiliteText(xw); 4994d522f475Smrg} 4995d522f475Smrg 4996d522f475Smrgstatic void 4997e0a2b6dfSmrgResetSelectionState(TScreen *screen) 4998d522f475Smrg{ 4999d522f475Smrg screen->selection_count = 0; 5000d522f475Smrg screen->startH = zeroCELL; 5001d522f475Smrg screen->endH = zeroCELL; 5002d522f475Smrg} 5003d522f475Smrg 5004d522f475Smrgvoid 5005d522f475SmrgDisownSelection(XtermWidget xw) 5006d522f475Smrg{ 5007956cc18dSsnj TScreen *screen = TScreenOf(xw); 5008d522f475Smrg Atom *atoms = screen->selection_atoms; 5009d522f475Smrg Cardinal count = screen->selection_count; 5010d522f475Smrg Cardinal i; 5011d522f475Smrg 5012d522f475Smrg TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n", 5013d522f475Smrg count, 5014d522f475Smrg screen->startH.row, 5015d522f475Smrg screen->startH.col, 5016d522f475Smrg screen->endH.row, 5017d522f475Smrg screen->endH.col)); 5018d522f475Smrg 5019d522f475Smrg for (i = 0; i < count; i++) { 5020d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 5021d522f475Smrg if (cutbuffer < 0) { 5022d522f475Smrg XtDisownSelection((Widget) xw, atoms[i], 5023d522f475Smrg screen->selection_time); 5024d522f475Smrg } 5025d522f475Smrg } 5026d522f475Smrg /* 5027d522f475Smrg * If none of the callbacks via XtDisownSelection() reset highlighting 5028d522f475Smrg * do it now. 5029d522f475Smrg */ 5030d522f475Smrg if (ScrnHaveSelection(screen)) { 5031d522f475Smrg /* save data which will be reset */ 5032d522f475Smrg CELL first = screen->startH; 5033d522f475Smrg CELL last = screen->endH; 5034d522f475Smrg 5035d522f475Smrg ResetSelectionState(screen); 5036d522f475Smrg ReHiliteText(xw, &first, &last); 5037d522f475Smrg } else { 5038d522f475Smrg ResetSelectionState(screen); 5039d522f475Smrg } 5040d522f475Smrg} 5041d522f475Smrg 5042d522f475Smrgvoid 5043d522f475SmrgUnhiliteSelection(XtermWidget xw) 5044d522f475Smrg{ 5045956cc18dSsnj TScreen *screen = TScreenOf(xw); 5046d522f475Smrg 5047d522f475Smrg if (ScrnHaveSelection(screen)) { 5048d522f475Smrg CELL first = screen->startH; 5049d522f475Smrg CELL last = screen->endH; 5050d522f475Smrg 5051d522f475Smrg screen->startH = zeroCELL; 5052d522f475Smrg screen->endH = zeroCELL; 5053d522f475Smrg ReHiliteText(xw, &first, &last); 5054d522f475Smrg } 5055d522f475Smrg} 5056d522f475Smrg 5057d522f475Smrg/* returns number of chars in line from scol to ecol out */ 5058d522f475Smrg/* ARGSUSED */ 5059d522f475Smrgstatic int 5060e0a2b6dfSmrgLength(TScreen *screen, 5061d522f475Smrg int row, 5062d522f475Smrg int scol, 5063d522f475Smrg int ecol) 5064d522f475Smrg{ 506501037d57Smrg CLineData *ld = GET_LINEDATA(screen, row); 506601037d57Smrg const int lastcol = LastTextCol(screen, ld, row); 5067d522f475Smrg 5068d522f475Smrg if (ecol > lastcol) 5069d522f475Smrg ecol = lastcol; 5070d522f475Smrg return (ecol - scol + 1); 5071d522f475Smrg} 5072d522f475Smrg 5073d522f475Smrg/* copies text into line, preallocated */ 5074d522f475Smrgstatic Char * 5075e0a2b6dfSmrgSaveText(TScreen *screen, 5076d522f475Smrg int row, 5077d522f475Smrg int scol, 5078d522f475Smrg int ecol, 5079e0a2b6dfSmrg Char *lp, /* pointer to where to put the text */ 5080d522f475Smrg int *eol) 5081d522f475Smrg{ 5082956cc18dSsnj LineData *ld; 5083d522f475Smrg int i = 0; 5084d522f475Smrg Char *result = lp; 5085d522f475Smrg#if OPT_WIDE_CHARS 50862eaa94a1Schristos unsigned previous = 0; 5087d522f475Smrg#endif 5088d522f475Smrg 5089956cc18dSsnj ld = GET_LINEDATA(screen, row); 5090d522f475Smrg i = Length(screen, row, scol, ecol); 5091d522f475Smrg ecol = scol + i; 5092d522f475Smrg#if OPT_DEC_CHRSET 5093956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 5094d522f475Smrg scol = (scol + 0) / 2; 5095d522f475Smrg ecol = (ecol + 1) / 2; 5096d522f475Smrg } 5097d522f475Smrg#endif 5098956cc18dSsnj *eol = !LineTstWrapped(ld); 5099d522f475Smrg for (i = scol; i < ecol; i++) { 51002e4f8982Smrg unsigned c; 51010bd37d32Smrg assert(i < (int) ld->lineSize); 5102956cc18dSsnj c = E2A(ld->charData[i]); 5103d522f475Smrg#if OPT_WIDE_CHARS 5104d522f475Smrg /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a 5105d522f475Smrg * wide character. 5106d522f475Smrg */ 5107894e0ac8Smrg if (c == HIDDEN_CHAR) { 5108894e0ac8Smrg if (isWide((int) previous)) { 5109894e0ac8Smrg previous = c; 5110894e0ac8Smrg /* Combining characters attached to double-width characters 5111894e0ac8Smrg are in memory attached to the HIDDEN_CHAR */ 5112894e0ac8Smrg if_OPT_WIDE_CHARS(screen, { 5113894e0ac8Smrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 5114894e0ac8Smrg size_t off; 5115894e0ac8Smrg for_each_combData(off, ld) { 51162e4f8982Smrg unsigned ch = ld->combData[off][i]; 5117894e0ac8Smrg if (ch == 0) 5118894e0ac8Smrg break; 5119894e0ac8Smrg lp = convertToUTF8(lp, ch); 5120894e0ac8Smrg } 5121d522f475Smrg } 5122894e0ac8Smrg }); 5123894e0ac8Smrg continue; 5124894e0ac8Smrg } else { 5125894e0ac8Smrg c = ' '; /* should not happen, but just in case... */ 5126894e0ac8Smrg } 5127d522f475Smrg } 5128d522f475Smrg previous = c; 5129e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 5130d522f475Smrg lp = convertToUTF8(lp, (c != 0) ? c : ' '); 5131d522f475Smrg if_OPT_WIDE_CHARS(screen, { 5132956cc18dSsnj size_t off; 5133956cc18dSsnj for_each_combData(off, ld) { 51342e4f8982Smrg unsigned ch = ld->combData[off][i]; 5135956cc18dSsnj if (ch == 0) 5136d522f475Smrg break; 5137d522f475Smrg lp = convertToUTF8(lp, ch); 5138d522f475Smrg } 5139d522f475Smrg }); 5140d522f475Smrg } else 5141d522f475Smrg#endif 5142d522f475Smrg { 5143d522f475Smrg if (c == 0) { 5144d522f475Smrg c = E2A(' '); 5145d522f475Smrg } else if (c < E2A(' ')) { 5146d522f475Smrg c = DECtoASCII(c); 5147d522f475Smrg } else if (c == 0x7f) { 5148d522f475Smrg c = 0x5f; 5149d522f475Smrg } 51502eaa94a1Schristos *lp++ = CharOf(A2E(c)); 5151d522f475Smrg } 5152d522f475Smrg if (c != E2A(' ')) 5153d522f475Smrg result = lp; 5154d522f475Smrg } 5155d522f475Smrg 5156d522f475Smrg /* 5157d522f475Smrg * If requested, trim trailing blanks from selected lines. Do not do this 5158d522f475Smrg * if the line is wrapped. 5159d522f475Smrg */ 5160d522f475Smrg if (!*eol || !screen->trim_selection) 5161d522f475Smrg result = lp; 5162d522f475Smrg 5163d522f475Smrg return (result); 5164d522f475Smrg} 5165d522f475Smrg 5166f2e35a3aSmrg/* 5167f2e35a3aSmrg * This adds together the bits: 5168f2e35a3aSmrg * shift key -> 1 5169f2e35a3aSmrg * meta key -> 2 5170f2e35a3aSmrg * control key -> 4 5171f2e35a3aSmrg */ 5172f2e35a3aSmrgstatic unsigned 5173f2e35a3aSmrgKeyState(XtermWidget xw, unsigned x) 5174f2e35a3aSmrg{ 5175f2e35a3aSmrg return ((((x) & (ShiftMask | ControlMask))) 5176f2e35a3aSmrg + (((x) & MetaMask(xw)) ? 2 : 0)); 5177f2e35a3aSmrg} 5178f2e35a3aSmrg 5179f2e35a3aSmrg/* 32 + following 8-bit word: 5180d522f475Smrg 5181d522f475Smrg 1:0 Button no: 0, 1, 2. 3=release. 5182d522f475Smrg 2 shift 5183d522f475Smrg 3 meta 5184d522f475Smrg 4 ctrl 5185d522f475Smrg 5 set for motion notify 5186f2e35a3aSmrg 6 set for wheel (and button 6 and 7) 5187f2e35a3aSmrg 7 set for buttons 8 to 11 5188d522f475Smrg*/ 5189d522f475Smrg 5190d522f475Smrg/* Position: 32 - 255. */ 5191a1f3da82Smrgstatic int 5192f2e35a3aSmrgBtnCode(XtermWidget xw, XButtonEvent *event, int button) 5193d522f475Smrg{ 5194f2e35a3aSmrg int result = (int) (32 + (KeyState(xw, event->state) << 2)); 5195d522f475Smrg 51960bd37d32Smrg if (event->type == MotionNotify) 51970bd37d32Smrg result += 32; 51980bd37d32Smrg 5199f2e35a3aSmrg if (button < 0) { 5200d522f475Smrg result += 3; 5201d522f475Smrg } else { 5202f2e35a3aSmrg result += button & 3; 5203f2e35a3aSmrg if (button & 4) 5204f2e35a3aSmrg result += 64; 5205f2e35a3aSmrg if (button & 8) 5206f2e35a3aSmrg result += 128; 5207d522f475Smrg } 52080bd37d32Smrg TRACE(("BtnCode button %d, %s state " FMT_MODIFIER_NAMES " ->%#x\n", 52090bd37d32Smrg button, 52100bd37d32Smrg visibleEventType(event->type), 52110bd37d32Smrg ARG_MODIFIER_NAMES(event->state), 52120bd37d32Smrg result)); 5213a1f3da82Smrg return result; 5214a1f3da82Smrg} 5215a1f3da82Smrg 5216a1f3da82Smrgstatic unsigned 5217913cc679SmrgEmitButtonCode(XtermWidget xw, 5218e0a2b6dfSmrg Char *line, 52190bd37d32Smrg unsigned count, 5220894e0ac8Smrg XButtonEvent *event, 52210bd37d32Smrg int button) 5222a1f3da82Smrg{ 5223913cc679Smrg TScreen *screen = TScreenOf(xw); 52240bd37d32Smrg int value; 5225a1f3da82Smrg 5226913cc679Smrg if (okSendMousePos(xw) == X10_MOUSE) { 52270bd37d32Smrg value = CharOf(' ' + button); 5228a1f3da82Smrg } else { 5229f2e35a3aSmrg value = BtnCode(xw, event, button); 52300bd37d32Smrg } 52310bd37d32Smrg 52320bd37d32Smrg switch (screen->extend_coords) { 52330bd37d32Smrg default: 52340bd37d32Smrg line[count++] = CharOf(value); 52350bd37d32Smrg break; 52360bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5237f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 52380bd37d32Smrg value -= 32; /* encoding starts at zero */ 52390bd37d32Smrg /* FALLTHRU */ 52400bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 52410bd37d32Smrg count += (unsigned) sprintf((char *) line + count, "%d", value); 52420bd37d32Smrg break; 52430bd37d32Smrg case SET_EXT_MODE_MOUSE: 52440bd37d32Smrg if (value < 128) { 52450bd37d32Smrg line[count++] = CharOf(value); 52460bd37d32Smrg } else { 52470bd37d32Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 52480bd37d32Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 52490bd37d32Smrg } 52500bd37d32Smrg break; 5251a1f3da82Smrg } 5252a1f3da82Smrg return count; 5253d522f475Smrg} 5254d522f475Smrg 52550bd37d32Smrgstatic int 52560bd37d32SmrgFirstBitN(int bits) 52570bd37d32Smrg{ 52580bd37d32Smrg int result = -1; 52590bd37d32Smrg if (bits > 0) { 52600bd37d32Smrg result = 0; 52610bd37d32Smrg while (!(bits & 1)) { 52620bd37d32Smrg bits /= 2; 52630bd37d32Smrg ++result; 52640bd37d32Smrg } 52650bd37d32Smrg } 52660bd37d32Smrg return result; 52670bd37d32Smrg} 52680bd37d32Smrg 52690bd37d32Smrg#define ButtonBit(button) ((button >= 0) ? (1 << (button)) : 0) 52700bd37d32Smrg 5271913cc679Smrg#define EMIT_BUTTON(button) EmitButtonCode(xw, line, count, event, button) 52720bd37d32Smrg 5273d522f475Smrgstatic void 5274894e0ac8SmrgEditorButton(XtermWidget xw, XButtonEvent *event) 5275d522f475Smrg{ 5276956cc18dSsnj TScreen *screen = TScreenOf(xw); 5277d522f475Smrg int pty = screen->respond; 52780bd37d32Smrg int mouse_limit = MouseLimit(screen); 52790bd37d32Smrg Char line[32]; 52800bd37d32Smrg Char final = 'M'; 5281d522f475Smrg int row, col; 5282d522f475Smrg int button; 5283d522f475Smrg unsigned count = 0; 5284d522f475Smrg Boolean changed = True; 5285d522f475Smrg 5286d522f475Smrg /* If button event, get button # adjusted for DEC compatibility */ 52872eaa94a1Schristos button = (int) (event->button - 1); 5288d522f475Smrg if (button >= 3) 5289d522f475Smrg button++; 5290d522f475Smrg 5291f2e35a3aSmrg /* Ignore buttons that cannot be encoded */ 5292f2e35a3aSmrg if (screen->send_mouse_pos == X10_MOUSE) { 5293f2e35a3aSmrg if (button > 3) 5294f2e35a3aSmrg return; 5295f2e35a3aSmrg } else if (screen->extend_coords == SET_SGR_EXT_MODE_MOUSE 5296f2e35a3aSmrg || screen->extend_coords == SET_URXVT_EXT_MODE_MOUSE 5297f2e35a3aSmrg || screen->extend_coords == SET_PIXEL_POSITION_MOUSE) { 5298f2e35a3aSmrg if (button > 15) { 5299f2e35a3aSmrg return; 5300f2e35a3aSmrg } 5301f2e35a3aSmrg } else { 5302f2e35a3aSmrg if (button > 11) { 5303f2e35a3aSmrg return; 5304f2e35a3aSmrg } 5305f2e35a3aSmrg } 5306d522f475Smrg 5307f2e35a3aSmrg if (screen->extend_coords == SET_PIXEL_POSITION_MOUSE) { 5308f2e35a3aSmrg row = event->y - OriginY(screen); 5309f2e35a3aSmrg col = event->x - OriginX(screen); 5310f2e35a3aSmrg } else { 5311f2e35a3aSmrg /* Compute character position of mouse pointer */ 5312f2e35a3aSmrg row = (event->y - screen->border) / FontHeight(screen); 5313f2e35a3aSmrg col = (event->x - OriginX(screen)) / FontWidth(screen); 5314d522f475Smrg 5315f2e35a3aSmrg /* Limit to screen dimensions */ 5316f2e35a3aSmrg if (row < 0) 5317f2e35a3aSmrg row = 0; 5318f2e35a3aSmrg else if (row > screen->max_row) 5319f2e35a3aSmrg row = screen->max_row; 5320492d43a5Smrg 5321f2e35a3aSmrg if (col < 0) 5322f2e35a3aSmrg col = 0; 5323f2e35a3aSmrg else if (col > screen->max_col) 5324f2e35a3aSmrg col = screen->max_col; 5325f2e35a3aSmrg 5326f2e35a3aSmrg if (mouse_limit > 0) { 5327f2e35a3aSmrg /* Limit to representable mouse dimensions */ 5328f2e35a3aSmrg if (row > mouse_limit) 5329f2e35a3aSmrg row = mouse_limit; 5330f2e35a3aSmrg if (col > mouse_limit) 5331f2e35a3aSmrg col = mouse_limit; 5332f2e35a3aSmrg } 53330bd37d32Smrg } 5334d522f475Smrg 5335d522f475Smrg /* Build key sequence starting with \E[M */ 5336d522f475Smrg if (screen->control_eight_bits) { 5337d522f475Smrg line[count++] = ANSI_CSI; 5338d522f475Smrg } else { 5339d522f475Smrg line[count++] = ANSI_ESC; 5340d522f475Smrg line[count++] = '['; 5341d522f475Smrg } 53420bd37d32Smrg switch (screen->extend_coords) { 53430bd37d32Smrg case 0: 53440bd37d32Smrg case SET_EXT_MODE_MOUSE: 5345d522f475Smrg#if OPT_SCO_FUNC_KEYS 53460bd37d32Smrg if (xw->keyboard.type == keyboardIsSCO) { 53470bd37d32Smrg /* 53480bd37d32Smrg * SCO function key F1 is \E[M, which would conflict with xterm's 53490bd37d32Smrg * normal kmous. 53500bd37d32Smrg */ 53510bd37d32Smrg line[count++] = '>'; 53520bd37d32Smrg } 5353d522f475Smrg#endif 53540bd37d32Smrg line[count++] = final; 53550bd37d32Smrg break; 53560bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5357f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 53580bd37d32Smrg line[count++] = '<'; 53590bd37d32Smrg break; 53600bd37d32Smrg } 5361d522f475Smrg 5362d522f475Smrg /* Add event code to key sequence */ 5363913cc679Smrg if (okSendMousePos(xw) == X10_MOUSE) { 53640bd37d32Smrg count = EMIT_BUTTON(button); 5365d522f475Smrg } else { 5366d522f475Smrg /* Button-Motion events */ 5367d522f475Smrg switch (event->type) { 5368d522f475Smrg case ButtonPress: 53690bd37d32Smrg screen->mouse_button |= ButtonBit(button); 53700bd37d32Smrg count = EMIT_BUTTON(button); 5371d522f475Smrg break; 5372d522f475Smrg case ButtonRelease: 5373d522f475Smrg /* 5374f2e35a3aSmrg * The (vertical) wheel mouse interface generates release-events 5375f2e35a3aSmrg * for buttons 4 and 5. 5376f2e35a3aSmrg * 5377f2e35a3aSmrg * The X10/X11 xterm protocol maps the release for buttons 1..3 to 5378f2e35a3aSmrg * a -1, which will be later mapped into a "0" (some button was 5379f2e35a3aSmrg * released), At this point, buttons 1..3 are encoded 0..2 (the 5380f2e35a3aSmrg * code 3 is unused). 5381f2e35a3aSmrg * 5382f2e35a3aSmrg * The SGR (extended) xterm mouse protocol keeps the button number 5383f2e35a3aSmrg * and uses a "m" to indicate button release. 5384f2e35a3aSmrg * 5385f2e35a3aSmrg * The behavior for mice with more buttons is unclear, and may be 5386f2e35a3aSmrg * revised -TD 5387d522f475Smrg */ 53880bd37d32Smrg screen->mouse_button &= ~ButtonBit(button); 5389f2e35a3aSmrg if (button < 3 || button > 5) { 53900bd37d32Smrg switch (screen->extend_coords) { 53910bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 5392f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 53930bd37d32Smrg final = 'm'; 53940bd37d32Smrg break; 53950bd37d32Smrg default: 53960bd37d32Smrg button = -1; 53970bd37d32Smrg break; 53980bd37d32Smrg } 53990bd37d32Smrg } 54000bd37d32Smrg count = EMIT_BUTTON(button); 5401d522f475Smrg break; 5402d522f475Smrg case MotionNotify: 5403d522f475Smrg /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion 5404d522f475Smrg * events only if character cell has changed. 5405d522f475Smrg */ 5406d522f475Smrg if ((row == screen->mouse_row) 5407d522f475Smrg && (col == screen->mouse_col)) { 5408d522f475Smrg changed = False; 5409d522f475Smrg } else { 54100bd37d32Smrg count = EMIT_BUTTON(FirstBitN(screen->mouse_button)); 5411d522f475Smrg } 5412d522f475Smrg break; 5413d522f475Smrg default: 5414d522f475Smrg changed = False; 5415d522f475Smrg break; 5416d522f475Smrg } 5417d522f475Smrg } 5418d522f475Smrg 5419d522f475Smrg if (changed) { 5420d522f475Smrg screen->mouse_row = row; 5421d522f475Smrg screen->mouse_col = col; 5422d522f475Smrg 5423492d43a5Smrg TRACE(("mouse at %d,%d button+mask = %#x\n", row, col, line[count - 1])); 5424d522f475Smrg 5425492d43a5Smrg /* Add pointer position to key sequence */ 54260bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 5427492d43a5Smrg count = EmitMousePosition(screen, line, count, col); 54280bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 5429492d43a5Smrg count = EmitMousePosition(screen, line, count, row); 5430d522f475Smrg 54310bd37d32Smrg switch (screen->extend_coords) { 54320bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 54330bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 5434f2e35a3aSmrg case SET_PIXEL_POSITION_MOUSE: 54350bd37d32Smrg line[count++] = final; 54360bd37d32Smrg break; 54370bd37d32Smrg } 54380bd37d32Smrg 5439d522f475Smrg /* Transmit key sequence to process running under xterm */ 5440f2e35a3aSmrg TRACE(("EditorButton -> %s\n", visibleChars(line, count))); 5441d522f475Smrg v_write(pty, line, count); 5442d522f475Smrg } 5443d522f475Smrg return; 5444d522f475Smrg} 5445d522f475Smrg 5446913cc679Smrg/* 5447913cc679Smrg * Check the current send_mouse_pos against allowed mouse-operations, returning 5448913cc679Smrg * none if it is disallowed. 5449913cc679Smrg */ 5450913cc679SmrgXtermMouseModes 5451913cc679SmrgokSendMousePos(XtermWidget xw) 5452913cc679Smrg{ 5453913cc679Smrg TScreen *screen = TScreenOf(xw); 5454f2e35a3aSmrg XtermMouseModes result = (XtermMouseModes) screen->send_mouse_pos; 5455913cc679Smrg 5456f2e35a3aSmrg switch ((int) result) { 5457913cc679Smrg case MOUSE_OFF: 5458913cc679Smrg break; 5459913cc679Smrg case X10_MOUSE: 5460913cc679Smrg if (!AllowMouseOps(xw, emX10)) 5461913cc679Smrg result = MOUSE_OFF; 5462913cc679Smrg break; 5463913cc679Smrg case VT200_MOUSE: 5464913cc679Smrg if (!AllowMouseOps(xw, emVT200Click)) 5465913cc679Smrg result = MOUSE_OFF; 5466913cc679Smrg break; 5467913cc679Smrg case VT200_HIGHLIGHT_MOUSE: 5468913cc679Smrg if (!AllowMouseOps(xw, emVT200Hilite)) 5469913cc679Smrg result = MOUSE_OFF; 5470913cc679Smrg break; 5471913cc679Smrg case BTN_EVENT_MOUSE: 5472913cc679Smrg if (!AllowMouseOps(xw, emAnyButton)) 5473913cc679Smrg result = MOUSE_OFF; 5474913cc679Smrg break; 5475913cc679Smrg case ANY_EVENT_MOUSE: 5476913cc679Smrg if (!AllowMouseOps(xw, emAnyEvent)) 5477913cc679Smrg result = MOUSE_OFF; 5478913cc679Smrg break; 5479913cc679Smrg case DEC_LOCATOR: 5480913cc679Smrg if (!AllowMouseOps(xw, emLocator)) 5481913cc679Smrg result = MOUSE_OFF; 5482913cc679Smrg break; 5483913cc679Smrg } 5484913cc679Smrg return result; 5485913cc679Smrg} 5486913cc679Smrg 5487d522f475Smrg#if OPT_FOCUS_EVENT 5488913cc679Smrg/* 5489913cc679Smrg * Check the current send_focus_pos against allowed mouse-operations, returning 5490913cc679Smrg * none if it is disallowed. 5491913cc679Smrg */ 5492913cc679Smrgstatic int 5493913cc679SmrgokSendFocusPos(XtermWidget xw) 5494d522f475Smrg{ 5495956cc18dSsnj TScreen *screen = TScreenOf(xw); 5496913cc679Smrg int result = screen->send_focus_pos; 5497913cc679Smrg 5498913cc679Smrg if (!AllowMouseOps(xw, emFocusEvent)) { 5499913cc679Smrg result = False; 5500913cc679Smrg } 5501913cc679Smrg return result; 5502913cc679Smrg} 5503d522f475Smrg 5504913cc679Smrgvoid 5505913cc679SmrgSendFocusButton(XtermWidget xw, XFocusChangeEvent *event) 5506913cc679Smrg{ 5507913cc679Smrg if (okSendFocusPos(xw)) { 5508d522f475Smrg ANSI reply; 5509d522f475Smrg 5510d522f475Smrg memset(&reply, 0, sizeof(reply)); 5511d522f475Smrg reply.a_type = ANSI_CSI; 5512d522f475Smrg 5513d522f475Smrg#if OPT_SCO_FUNC_KEYS 5514d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 5515d522f475Smrg reply.a_pintro = '>'; 5516d522f475Smrg } 5517d522f475Smrg#endif 55182eaa94a1Schristos reply.a_final = CharOf((event->type == FocusIn) ? 'I' : 'O'); 5519d522f475Smrg unparseseq(xw, &reply); 5520d522f475Smrg } 5521d522f475Smrg return; 5522d522f475Smrg} 5523d522f475Smrg#endif /* OPT_FOCUS_EVENT */ 55240bd37d32Smrg 55250bd37d32Smrg#if OPT_SELECTION_OPS 55260bd37d32Smrg/* 55270bd37d32Smrg * Get the event-time, needed to process selections. 55280bd37d32Smrg */ 55290bd37d32Smrgstatic Time 5530894e0ac8SmrggetEventTime(XEvent *event) 55310bd37d32Smrg{ 55320bd37d32Smrg Time result; 55330bd37d32Smrg 55340bd37d32Smrg if (IsBtnEvent(event)) { 55350bd37d32Smrg result = ((XButtonEvent *) event)->time; 55360bd37d32Smrg } else if (IsKeyEvent(event)) { 55370bd37d32Smrg result = ((XKeyEvent *) event)->time; 55380bd37d32Smrg } else { 55390bd37d32Smrg result = 0; 55400bd37d32Smrg } 55410bd37d32Smrg 55420bd37d32Smrg return result; 55430bd37d32Smrg} 55440bd37d32Smrg 55450bd37d32Smrg/* obtain the selection string, passing the endpoints to caller's parameters */ 554601037d57Smrgstatic void 554701037d57SmrgdoSelectionFormat(XtermWidget xw, 554801037d57Smrg Widget w, 554901037d57Smrg XEvent *event, 555001037d57Smrg String *params, 555101037d57Smrg Cardinal *num_params, 555201037d57Smrg FormatSelect format_select) 55530bd37d32Smrg{ 55540bd37d32Smrg TScreen *screen = TScreenOf(xw); 555501037d57Smrg InternalSelect *mydata = &(screen->internal_select); 555601037d57Smrg 555701037d57Smrg memset(mydata, 0, sizeof(*mydata)); 555801037d57Smrg mydata->format = x_strdup(params[0]); 555901037d57Smrg mydata->format_select = format_select; 55600bd37d32Smrg 55610bd37d32Smrg screen->selectToBuffer = True; 5562f2e35a3aSmrg beginInternalSelect(xw); 5563f2e35a3aSmrg 55640bd37d32Smrg xtermGetSelection(w, getEventTime(event), params + 1, *num_params - 1, NULL); 5565f2e35a3aSmrg 5566f2e35a3aSmrg if (screen->selectToBuffer) 5567f2e35a3aSmrg finishInternalSelect(xw); 55680bd37d32Smrg} 55690bd37d32Smrg 55700bd37d32Smrg/* obtain data from the screen, passing the endpoints to caller's parameters */ 55710bd37d32Smrgstatic char * 5572913cc679SmrggetDataFromScreen(XtermWidget xw, XEvent *event, String method, CELL *start, CELL *finish) 55730bd37d32Smrg{ 55740bd37d32Smrg TScreen *screen = TScreenOf(xw); 55750bd37d32Smrg 55760bd37d32Smrg CELL save_old_start = screen->startH; 55770bd37d32Smrg CELL save_old_end = screen->endH; 55780bd37d32Smrg 55790bd37d32Smrg CELL save_startSel = screen->startSel; 55800bd37d32Smrg CELL save_startRaw = screen->startRaw; 55810bd37d32Smrg CELL save_finishSel = screen->endSel; 55820bd37d32Smrg CELL save_finishRaw = screen->endRaw; 55830bd37d32Smrg 55840bd37d32Smrg int save_firstValidRow = screen->firstValidRow; 55850bd37d32Smrg int save_lastValidRow = screen->lastValidRow; 55860bd37d32Smrg 558701037d57Smrg const Cardinal noClick = 0; 558801037d57Smrg int save_numberOfClicks = screen->numberOfClicks; 558901037d57Smrg 55900bd37d32Smrg SelectUnit saveUnits = screen->selectUnit; 559101037d57Smrg SelectUnit saveMap = screen->selectMap[noClick]; 55920bd37d32Smrg#if OPT_SELECT_REGEX 559301037d57Smrg char *saveExpr = screen->selectExpr[noClick]; 55940bd37d32Smrg#endif 5595f2e35a3aSmrg SelectedCells *scp = &(screen->selected_cells[PRIMARY_CODE]); 5596f2e35a3aSmrg SelectedCells save_selection = *scp; 55970bd37d32Smrg 55980bd37d32Smrg char *result = 0; 55990bd37d32Smrg 56000bd37d32Smrg TRACE(("getDataFromScreen %s\n", method)); 56010bd37d32Smrg 5602f2e35a3aSmrg memset(scp, 0, sizeof(*scp)); 56030bd37d32Smrg 560401037d57Smrg screen->numberOfClicks = 1; 560501037d57Smrg lookupSelectUnit(xw, noClick, method); 560601037d57Smrg screen->selectUnit = screen->selectMap[noClick]; 56070bd37d32Smrg 56080bd37d32Smrg memset(start, 0, sizeof(*start)); 5609913cc679Smrg if (IsBtnEvent(event)) { 5610913cc679Smrg XButtonEvent *btn_event = (XButtonEvent *) event; 5611913cc679Smrg CELL cell; 5612913cc679Smrg screen->firstValidRow = 0; 5613913cc679Smrg screen->lastValidRow = screen->max_row; 5614913cc679Smrg PointToCELL(screen, btn_event->y, btn_event->x, &cell); 5615913cc679Smrg start->row = cell.row; 5616913cc679Smrg start->col = cell.col; 5617913cc679Smrg finish->row = cell.row; 5618913cc679Smrg finish->col = screen->max_col; 5619913cc679Smrg } else { 5620913cc679Smrg start->row = screen->cur_row; 5621913cc679Smrg start->col = screen->cur_col; 5622913cc679Smrg finish->row = screen->cur_row; 5623913cc679Smrg finish->col = screen->max_col; 5624913cc679Smrg } 56250bd37d32Smrg 5626f2e35a3aSmrg ComputeSelect(xw, start, finish, False, False); 5627f2e35a3aSmrg SaltTextAway(xw, 5628f2e35a3aSmrg TargetToSelection(screen, PRIMARY_NAME), 5629f2e35a3aSmrg &(screen->startSel), &(screen->endSel)); 56300bd37d32Smrg 5631f2e35a3aSmrg if (scp->data_limit && scp->data_buffer) { 5632f2e35a3aSmrg TRACE(("...getDataFromScreen selection-data %.*s\n", 5633f2e35a3aSmrg (int) scp->data_limit, 5634f2e35a3aSmrg scp->data_buffer)); 5635f2e35a3aSmrg result = malloc(scp->data_limit + 1); 56360bd37d32Smrg if (result) { 5637f2e35a3aSmrg memcpy(result, scp->data_buffer, scp->data_limit); 5638f2e35a3aSmrg result[scp->data_limit] = 0; 56390bd37d32Smrg } 5640f2e35a3aSmrg free(scp->data_buffer); 5641f2e35a3aSmrg scp->data_limit = 0; 56420bd37d32Smrg } 56430bd37d32Smrg 56440bd37d32Smrg TRACE(("...getDataFromScreen restoring previous selection\n")); 56450bd37d32Smrg 56460bd37d32Smrg screen->startSel = save_startSel; 56470bd37d32Smrg screen->startRaw = save_startRaw; 56480bd37d32Smrg screen->endSel = save_finishSel; 56490bd37d32Smrg screen->endRaw = save_finishRaw; 56500bd37d32Smrg 56510bd37d32Smrg screen->firstValidRow = save_firstValidRow; 56520bd37d32Smrg screen->lastValidRow = save_lastValidRow; 56530bd37d32Smrg 565401037d57Smrg screen->numberOfClicks = save_numberOfClicks; 56550bd37d32Smrg screen->selectUnit = saveUnits; 565601037d57Smrg screen->selectMap[noClick] = saveMap; 56570bd37d32Smrg#if OPT_SELECT_REGEX 565801037d57Smrg screen->selectExpr[noClick] = saveExpr; 56590bd37d32Smrg#endif 56600bd37d32Smrg 5661f2e35a3aSmrg screen->selected_cells[0] = save_selection; 56620bd37d32Smrg 56630bd37d32Smrg TrackText(xw, &save_old_start, &save_old_end); 56640bd37d32Smrg 56650bd37d32Smrg TRACE(("...getDataFromScreen done\n")); 56660bd37d32Smrg return result; 56670bd37d32Smrg} 56680bd37d32Smrg 56690bd37d32Smrg/* 56700bd37d32Smrg * Split-up the format before substituting data, to avoid quoting issues. 56710bd37d32Smrg * The resource mechanism has a limited ability to handle escapes. We take 56720bd37d32Smrg * the result as if it were an sh-type string and parse it into a regular 56730bd37d32Smrg * argv array. 56740bd37d32Smrg */ 56750bd37d32Smrgstatic char ** 56760bd37d32SmrgtokenizeFormat(String format) 56770bd37d32Smrg{ 56780bd37d32Smrg char **result = 0; 56790bd37d32Smrg 56800bd37d32Smrg format = x_skip_blanks(format); 56810bd37d32Smrg if (*format != '\0') { 56820bd37d32Smrg char *blob = x_strdup(format); 56832e4f8982Smrg int pass; 56840bd37d32Smrg 56850bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 56860bd37d32Smrg int used = 0; 56870bd37d32Smrg int first = 1; 56880bd37d32Smrg int escaped = 0; 56890bd37d32Smrg int squoted = 0; 56900bd37d32Smrg int dquoted = 0; 56912e4f8982Smrg int n; 5692f2e35a3aSmrg int argc = 0; 56930bd37d32Smrg 56940bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 56950bd37d32Smrg if (escaped) { 56960bd37d32Smrg blob[used++] = format[n]; 56970bd37d32Smrg escaped = 0; 56980bd37d32Smrg } else if (format[n] == '"') { 56990bd37d32Smrg if (!squoted) { 57000bd37d32Smrg if (!dquoted) 57010bd37d32Smrg blob[used++] = format[n]; 57020bd37d32Smrg dquoted = !dquoted; 57030bd37d32Smrg } 57040bd37d32Smrg } else if (format[n] == '\'') { 57050bd37d32Smrg if (!dquoted) { 57060bd37d32Smrg if (!squoted) 57070bd37d32Smrg blob[used++] = format[n]; 57080bd37d32Smrg squoted = !squoted; 57090bd37d32Smrg } 57100bd37d32Smrg } else if (format[n] == '\\') { 57110bd37d32Smrg blob[used++] = format[n]; 57120bd37d32Smrg escaped = 1; 57130bd37d32Smrg } else { 57140bd37d32Smrg if (first) { 57150bd37d32Smrg first = 0; 57160bd37d32Smrg if (pass) { 57170bd37d32Smrg result[argc] = &blob[n]; 57180bd37d32Smrg } 57190bd37d32Smrg ++argc; 57200bd37d32Smrg } 57210bd37d32Smrg if (isspace((Char) format[n])) { 57220bd37d32Smrg first = !isspace((Char) format[n + 1]); 57230bd37d32Smrg if (squoted || dquoted) { 57240bd37d32Smrg blob[used++] = format[n]; 57250bd37d32Smrg } else if (first) { 57260bd37d32Smrg blob[used++] = '\0'; 57270bd37d32Smrg } 57280bd37d32Smrg } else { 57290bd37d32Smrg blob[used++] = format[n]; 57300bd37d32Smrg } 57310bd37d32Smrg } 57320bd37d32Smrg } 57330bd37d32Smrg blob[used] = '\0'; 57340bd37d32Smrg assert(strlen(blob) <= strlen(format)); 57350bd37d32Smrg if (!pass) { 57360bd37d32Smrg result = TypeCallocN(char *, argc + 1); 57370bd37d32Smrg if (result == 0) { 57380bd37d32Smrg free(blob); 57390bd37d32Smrg break; 57400bd37d32Smrg } 57410bd37d32Smrg } 57420bd37d32Smrg } 57430bd37d32Smrg } 57440bd37d32Smrg#if OPT_TRACE 57450bd37d32Smrg if (result) { 5746f2e35a3aSmrg int n; 57470bd37d32Smrg TRACE(("tokenizeFormat %s\n", format)); 5748f2e35a3aSmrg for (n = 0; result[n]; ++n) { 5749f2e35a3aSmrg TRACE(("argv[%d] = %s\n", n, result[n])); 57500bd37d32Smrg } 57510bd37d32Smrg } 57520bd37d32Smrg#endif 57530bd37d32Smrg 57540bd37d32Smrg return result; 57550bd37d32Smrg} 57560bd37d32Smrg 57570bd37d32Smrgstatic void 5758e0a2b6dfSmrgformatVideoAttrs(XtermWidget xw, char *buffer, CELL *cell) 57590bd37d32Smrg{ 57600bd37d32Smrg TScreen *screen = TScreenOf(xw); 57610bd37d32Smrg LineData *ld = GET_LINEDATA(screen, cell->row); 57620bd37d32Smrg 57630bd37d32Smrg *buffer = '\0'; 57640bd37d32Smrg if (ld != 0 && cell->col < (int) ld->lineSize) { 5765894e0ac8Smrg IAttr attribs = ld->attribs[cell->col]; 57660bd37d32Smrg const char *delim = ""; 57670bd37d32Smrg 57680bd37d32Smrg if (attribs & INVERSE) { 57690bd37d32Smrg buffer += sprintf(buffer, "7"); 57700bd37d32Smrg delim = ";"; 57710bd37d32Smrg } 57720bd37d32Smrg if (attribs & UNDERLINE) { 57730bd37d32Smrg buffer += sprintf(buffer, "%s4", delim); 57740bd37d32Smrg delim = ";"; 57750bd37d32Smrg } 57760bd37d32Smrg if (attribs & BOLD) { 57770bd37d32Smrg buffer += sprintf(buffer, "%s1", delim); 57780bd37d32Smrg delim = ";"; 57790bd37d32Smrg } 57800bd37d32Smrg if (attribs & BLINK) { 57810bd37d32Smrg buffer += sprintf(buffer, "%s5", delim); 57820bd37d32Smrg delim = ";"; 57830bd37d32Smrg } 57840bd37d32Smrg#if OPT_ISO_COLORS 57850bd37d32Smrg if (attribs & FG_COLOR) { 5786f2e35a3aSmrg Pixel fg = extract_fg(xw, ld->color[cell->col], attribs); 57870bd37d32Smrg if (fg < 8) { 57880bd37d32Smrg fg += 30; 57890bd37d32Smrg } else if (fg < 16) { 57900bd37d32Smrg fg += 90; 57910bd37d32Smrg } else { 57920bd37d32Smrg buffer += sprintf(buffer, "%s38;5", delim); 57930bd37d32Smrg delim = ";"; 57940bd37d32Smrg } 5795f2e35a3aSmrg buffer += sprintf(buffer, "%s%lu", delim, fg); 57960bd37d32Smrg delim = ";"; 57970bd37d32Smrg } 57980bd37d32Smrg if (attribs & BG_COLOR) { 5799f2e35a3aSmrg Pixel bg = extract_bg(xw, ld->color[cell->col], attribs); 58000bd37d32Smrg if (bg < 8) { 58010bd37d32Smrg bg += 40; 58020bd37d32Smrg } else if (bg < 16) { 58030bd37d32Smrg bg += 100; 58040bd37d32Smrg } else { 58050bd37d32Smrg buffer += sprintf(buffer, "%s48;5", delim); 58060bd37d32Smrg delim = ";"; 58070bd37d32Smrg } 5808f2e35a3aSmrg (void) sprintf(buffer, "%s%lu", delim, bg); 58090bd37d32Smrg } 58100bd37d32Smrg#endif 58110bd37d32Smrg } 58120bd37d32Smrg} 58130bd37d32Smrg 58142e4f8982Smrgstatic char * 58152e4f8982SmrgformatStrlen(char *target, char *source, int freeit) 58162e4f8982Smrg{ 58172e4f8982Smrg if (source != 0) { 58182e4f8982Smrg sprintf(target, "%u", (unsigned) strlen(source)); 58192e4f8982Smrg if (freeit) { 58202e4f8982Smrg free(source); 58212e4f8982Smrg } 58222e4f8982Smrg } else { 58232e4f8982Smrg strcpy(target, "0"); 58242e4f8982Smrg } 58252e4f8982Smrg return target; 58262e4f8982Smrg} 58272e4f8982Smrg 58280bd37d32Smrg/* substitute data into format, reallocating the result */ 58290bd37d32Smrgstatic char * 58300bd37d32SmrgexpandFormat(XtermWidget xw, 58310bd37d32Smrg const char *format, 58320bd37d32Smrg char *data, 5833e0a2b6dfSmrg CELL *start, 5834e0a2b6dfSmrg CELL *finish) 58350bd37d32Smrg{ 58360bd37d32Smrg char *result = 0; 58370bd37d32Smrg if (!IsEmpty(format)) { 58380bd37d32Smrg static char empty[1]; 58390bd37d32Smrg int pass; 58400bd37d32Smrg int n; 58410bd37d32Smrg char numbers[80]; 58420bd37d32Smrg 58430bd37d32Smrg if (data == 0) 58440bd37d32Smrg data = empty; 58450bd37d32Smrg 58460bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 58470bd37d32Smrg size_t need = 0; 58480bd37d32Smrg 58490bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 58500bd37d32Smrg 58510bd37d32Smrg if (format[n] == '%') { 58522e4f8982Smrg char *value = 0; 58532e4f8982Smrg 58540bd37d32Smrg switch (format[++n]) { 58550bd37d32Smrg case '%': 58560bd37d32Smrg if (pass) { 58570bd37d32Smrg result[need] = format[n]; 58580bd37d32Smrg } 58590bd37d32Smrg ++need; 58600bd37d32Smrg break; 58610bd37d32Smrg case 'P': 58620bd37d32Smrg sprintf(numbers, "%d;%d", 58630bd37d32Smrg TScreenOf(xw)->topline + start->row + 1, 58640bd37d32Smrg start->col + 1); 58650bd37d32Smrg value = numbers; 58660bd37d32Smrg break; 58670bd37d32Smrg case 'p': 58680bd37d32Smrg sprintf(numbers, "%d;%d", 58690bd37d32Smrg TScreenOf(xw)->topline + finish->row + 1, 58700bd37d32Smrg finish->col + 1); 58710bd37d32Smrg value = numbers; 58720bd37d32Smrg break; 58732e4f8982Smrg case 'R': 58742e4f8982Smrg value = formatStrlen(numbers, x_strrtrim(data), 1); 58752e4f8982Smrg break; 58762e4f8982Smrg case 'r': 58772e4f8982Smrg value = x_strrtrim(data); 58782e4f8982Smrg break; 58790bd37d32Smrg case 'S': 58802e4f8982Smrg value = formatStrlen(numbers, data, 0); 58810bd37d32Smrg break; 58820bd37d32Smrg case 's': 58830bd37d32Smrg value = data; 58840bd37d32Smrg break; 58850bd37d32Smrg case 'T': 58862e4f8982Smrg value = formatStrlen(numbers, x_strtrim(data), 1); 58870bd37d32Smrg break; 58880bd37d32Smrg case 't': 58890bd37d32Smrg value = x_strtrim(data); 58900bd37d32Smrg break; 58910bd37d32Smrg case 'V': 58920bd37d32Smrg formatVideoAttrs(xw, numbers, start); 58930bd37d32Smrg value = numbers; 58940bd37d32Smrg break; 58950bd37d32Smrg case 'v': 58960bd37d32Smrg formatVideoAttrs(xw, numbers, finish); 58970bd37d32Smrg value = numbers; 58980bd37d32Smrg break; 58990bd37d32Smrg default: 59000bd37d32Smrg if (pass) { 59010bd37d32Smrg result[need] = format[n]; 59020bd37d32Smrg } 59030bd37d32Smrg --n; 59040bd37d32Smrg ++need; 59050bd37d32Smrg break; 59060bd37d32Smrg } 59070bd37d32Smrg if (value != 0) { 59080bd37d32Smrg if (pass) { 59090bd37d32Smrg strcpy(result + need, value); 59100bd37d32Smrg } 59110bd37d32Smrg need += strlen(value); 59120bd37d32Smrg if (value != numbers && value != data) { 59130bd37d32Smrg free(value); 59140bd37d32Smrg } 59150bd37d32Smrg } 59160bd37d32Smrg } else { 59170bd37d32Smrg if (pass) { 59180bd37d32Smrg result[need] = format[n]; 59190bd37d32Smrg } 59200bd37d32Smrg ++need; 59210bd37d32Smrg } 59220bd37d32Smrg } 59230bd37d32Smrg if (pass) { 59240bd37d32Smrg result[need] = '\0'; 59250bd37d32Smrg } else { 59260bd37d32Smrg ++need; 59270bd37d32Smrg result = malloc(need); 59280bd37d32Smrg if (result == 0) { 59290bd37d32Smrg break; 59300bd37d32Smrg } 59310bd37d32Smrg } 59320bd37d32Smrg } 59330bd37d32Smrg } 59340bd37d32Smrg TRACE(("expandFormat(%s) = %s\n", NonNull(format), NonNull(result))); 59350bd37d32Smrg return result; 59360bd37d32Smrg} 59370bd37d32Smrg 59380bd37d32Smrg/* execute the command after forking. The main process frees its data */ 59390bd37d32Smrgstatic void 59402e4f8982SmrgexecuteCommand(pid_t pid, char **argv) 59410bd37d32Smrg{ 59422e4f8982Smrg (void) pid; 59430bd37d32Smrg if (argv != 0 && argv[0] != 0) { 59442e4f8982Smrg char *child_cwd = ProcGetCWD(pid); 59452e4f8982Smrg 59460bd37d32Smrg if (fork() == 0) { 59472e4f8982Smrg if (child_cwd) { 59482e4f8982Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 59492e4f8982Smrg } 59500bd37d32Smrg execvp(argv[0], argv); 59510bd37d32Smrg exit(EXIT_FAILURE); 59520bd37d32Smrg } 5953913cc679Smrg free(child_cwd); 59540bd37d32Smrg } 59550bd37d32Smrg} 59560bd37d32Smrg 59570bd37d32Smrgstatic void 59580bd37d32SmrgfreeArgv(char *blob, char **argv) 59590bd37d32Smrg{ 59600bd37d32Smrg if (blob) { 59610bd37d32Smrg free(blob); 59620bd37d32Smrg if (argv) { 59632e4f8982Smrg int n; 59640bd37d32Smrg for (n = 0; argv[n]; ++n) 59650bd37d32Smrg free(argv[n]); 59660bd37d32Smrg free(argv); 59670bd37d32Smrg } 59680bd37d32Smrg } 59690bd37d32Smrg} 59700bd37d32Smrg 597101037d57Smrgstatic void 597201037d57SmrgreallyExecFormatted(Widget w, char *format, char *data, CELL *start, CELL *finish) 597301037d57Smrg{ 597401037d57Smrg XtermWidget xw; 597501037d57Smrg 597601037d57Smrg if ((xw = getXtermWidget(w)) != 0) { 597701037d57Smrg char **argv; 597801037d57Smrg 597901037d57Smrg if ((argv = tokenizeFormat(format)) != 0) { 59802e4f8982Smrg char *blob = argv[0]; 59812e4f8982Smrg int argc; 59822e4f8982Smrg 598301037d57Smrg for (argc = 0; argv[argc] != 0; ++argc) { 598401037d57Smrg argv[argc] = expandFormat(xw, argv[argc], data, start, finish); 598501037d57Smrg } 59862e4f8982Smrg executeCommand(TScreenOf(xw)->pid, argv); 598701037d57Smrg freeArgv(blob, argv); 598801037d57Smrg } 598901037d57Smrg } 599001037d57Smrg} 599101037d57Smrg 59920bd37d32Smrgvoid 59930bd37d32SmrgHandleExecFormatted(Widget w, 599401037d57Smrg XEvent *event, 5995e0a2b6dfSmrg String *params, /* selections */ 59960bd37d32Smrg Cardinal *num_params) 59970bd37d32Smrg{ 59980bd37d32Smrg XtermWidget xw; 59990bd37d32Smrg 6000f2e35a3aSmrg TRACE_EVENT("HandleExecFormatted", event, params, num_params); 600101037d57Smrg if ((xw = getXtermWidget(w)) != 0 && 600201037d57Smrg (*num_params > 1)) { 600301037d57Smrg doSelectionFormat(xw, w, event, params, num_params, reallyExecFormatted); 60040bd37d32Smrg } 60050bd37d32Smrg} 60060bd37d32Smrg 60070bd37d32Smrgvoid 60080bd37d32SmrgHandleExecSelectable(Widget w, 6009913cc679Smrg XEvent *event, 6010e0a2b6dfSmrg String *params, /* selections */ 60110bd37d32Smrg Cardinal *num_params) 60120bd37d32Smrg{ 60130bd37d32Smrg XtermWidget xw; 60140bd37d32Smrg 60150bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 6016f2e35a3aSmrg TRACE_EVENT("HandleExecSelectable", event, params, num_params); 60170bd37d32Smrg 60180bd37d32Smrg if (*num_params == 2) { 60190bd37d32Smrg CELL start, finish; 60200bd37d32Smrg char *data; 60210bd37d32Smrg char **argv; 60220bd37d32Smrg 6023913cc679Smrg data = getDataFromScreen(xw, event, params[1], &start, &finish); 60240bd37d32Smrg if (data != 0) { 60250bd37d32Smrg if ((argv = tokenizeFormat(params[0])) != 0) { 60262e4f8982Smrg char *blob = argv[0]; 60272e4f8982Smrg int argc; 60282e4f8982Smrg 60290bd37d32Smrg for (argc = 0; argv[argc] != 0; ++argc) { 60300bd37d32Smrg argv[argc] = expandFormat(xw, argv[argc], data, 60310bd37d32Smrg &start, &finish); 60320bd37d32Smrg } 60332e4f8982Smrg executeCommand(TScreenOf(xw)->pid, argv); 60340bd37d32Smrg freeArgv(blob, argv); 60350bd37d32Smrg } 6036894e0ac8Smrg free(data); 60370bd37d32Smrg } 60380bd37d32Smrg } 60390bd37d32Smrg } 60400bd37d32Smrg} 60410bd37d32Smrg 604201037d57Smrgstatic void 604301037d57SmrgreallyInsertFormatted(Widget w, char *format, char *data, CELL *start, CELL *finish) 604401037d57Smrg{ 604501037d57Smrg XtermWidget xw; 604601037d57Smrg 604701037d57Smrg if ((xw = getXtermWidget(w)) != 0) { 604801037d57Smrg char *exps; 604901037d57Smrg 605001037d57Smrg if ((exps = expandFormat(xw, format, data, start, finish)) != 0) { 605101037d57Smrg unparseputs(xw, exps); 605201037d57Smrg unparse_end(xw); 605301037d57Smrg free(exps); 605401037d57Smrg } 605501037d57Smrg } 605601037d57Smrg} 605701037d57Smrg 60580bd37d32Smrgvoid 60590bd37d32SmrgHandleInsertFormatted(Widget w, 606001037d57Smrg XEvent *event, 6061e0a2b6dfSmrg String *params, /* selections */ 60620bd37d32Smrg Cardinal *num_params) 60630bd37d32Smrg{ 60640bd37d32Smrg XtermWidget xw; 60650bd37d32Smrg 6066f2e35a3aSmrg TRACE_EVENT("HandleInsertFormatted", event, params, num_params); 606701037d57Smrg if ((xw = getXtermWidget(w)) != 0 && 606801037d57Smrg (*num_params > 1)) { 606901037d57Smrg doSelectionFormat(xw, w, event, params, num_params, reallyInsertFormatted); 60700bd37d32Smrg } 60710bd37d32Smrg} 60720bd37d32Smrg 60730bd37d32Smrgvoid 60740bd37d32SmrgHandleInsertSelectable(Widget w, 6075913cc679Smrg XEvent *event, 6076e0a2b6dfSmrg String *params, /* selections */ 60770bd37d32Smrg Cardinal *num_params) 60780bd37d32Smrg{ 60790bd37d32Smrg XtermWidget xw; 60800bd37d32Smrg 60810bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 6082f2e35a3aSmrg TRACE_EVENT("HandleInsertSelectable", event, params, num_params); 60830bd37d32Smrg 60840bd37d32Smrg if (*num_params == 2) { 60850bd37d32Smrg CELL start, finish; 60860bd37d32Smrg char *data; 60870bd37d32Smrg char *temp = x_strdup(params[0]); 60880bd37d32Smrg 6089913cc679Smrg data = getDataFromScreen(xw, event, params[1], &start, &finish); 60900bd37d32Smrg if (data != 0) { 60912e4f8982Smrg char *exps = expandFormat(xw, temp, data, &start, &finish); 60920bd37d32Smrg if (exps != 0) { 60930bd37d32Smrg unparseputs(xw, exps); 609401037d57Smrg unparse_end(xw); 60950bd37d32Smrg free(exps); 60960bd37d32Smrg } 60970bd37d32Smrg free(data); 60980bd37d32Smrg } 60990bd37d32Smrg free(temp); 61000bd37d32Smrg } 61010bd37d32Smrg } 61020bd37d32Smrg} 61030bd37d32Smrg#endif /* OPT_SELECTION_OPS */ 6104