button.c revision 913cc679
1913cc679Smrg/* $XTermId: button.c,v 1.524 2017/05/30 08:58:29 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4913cc679Smrg * Copyright 1999-2016,2017 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 82d522f475Smrg#ifdef HAVE_PCREPOSIX_H 83d522f475Smrg#include <pcreposix.h> 84d522f475Smrg#else /* POSIX regex.h */ 85d522f475Smrg#include <sys/types.h> 86d522f475Smrg#include <regex.h> 87d522f475Smrg#endif 88d522f475Smrg#endif 89d522f475Smrg 90d522f475Smrg#if OPT_WIDE_CHARS 91d522f475Smrg#include <ctype.h> 92d522f475Smrg#include <wcwidth.h> 93d522f475Smrg#else 94d522f475Smrg#define CharacterClass(value) \ 95913cc679Smrg charClass[(value) & ((sizeof(charClass)/sizeof(charClass[0]))-1)] 96d522f475Smrg#endif 97d522f475Smrg 98956cc18dSsnj /* 99956cc18dSsnj * We'll generally map rows to indices when doing selection. 100956cc18dSsnj * Simplify that with a macro. 101956cc18dSsnj * 102956cc18dSsnj * Note that ROW2INX() is safe to use with auto increment/decrement for 103956cc18dSsnj * the row expression since that is evaluated once. 104956cc18dSsnj */ 105956cc18dSsnj#define GET_LINEDATA(screen, row) \ 106956cc18dSsnj getLineData(screen, ROW2INX(screen, row)) 107956cc18dSsnj 108956cc18dSsnj /* 109956cc18dSsnj * We reserve shift modifier for cut/paste operations. In principle we 110956cc18dSsnj * can pass through control and meta modifiers, but in practice, the 111956cc18dSsnj * popup menu uses control, and the window manager is likely to use meta, 112956cc18dSsnj * so those events are not delivered to SendMousePosition. 113956cc18dSsnj */ 114d522f475Smrg#define OurModifiers (ShiftMask | ControlMask | Mod1Mask) 115d522f475Smrg#define AllModifiers (ShiftMask | LockMask | ControlMask | Mod1Mask | \ 116d522f475Smrg Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) 117d522f475Smrg 118492d43a5Smrg#define BtnModifiers(event) (event->state & OurModifiers) 119492d43a5Smrg#define KeyModifiers(event) (event->xbutton.state & OurModifiers) 120492d43a5Smrg 121492d43a5Smrg#define IsBtnEvent(event) ((event)->type == ButtonPress || (event)->type == ButtonRelease) 1220bd37d32Smrg#define IsKeyEvent(event) ((event)->type == KeyPress || (event)->type == KeyRelease) 123d522f475Smrg 1242eaa94a1Schristos#define KeyState(x) (((int) ((x) & (ShiftMask|ControlMask))) \ 1252eaa94a1Schristos + (((x) & Mod1Mask) ? 2 : 0)) 126d522f475Smrg /* adds together the bits: 127d522f475Smrg shift key -> 1 128d522f475Smrg meta key -> 2 129d522f475Smrg control key -> 4 */ 130d522f475Smrg 131d522f475Smrg#define Coordinate(s,c) ((c)->row * MaxCols(s) + (c)->col) 132d522f475Smrg 133d522f475Smrgstatic const CELL zeroCELL = 134d522f475Smrg{0, 0}; 135d522f475Smrg 136d522f475Smrg#if OPT_DEC_LOCATOR 137894e0ac8Smrgstatic Bool SendLocatorPosition(XtermWidget xw, XButtonEvent *event); 138894e0ac8Smrgstatic void CheckLocatorPosition(XtermWidget xw, XButtonEvent *event); 139d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 140d522f475Smrg 141d522f475Smrg/* Multi-click handling */ 142d522f475Smrg#if OPT_READLINE 143d522f475Smrgstatic Time lastButtonDownTime = 0; 144d522f475Smrgstatic int ExtendingSelection = 0; 145d522f475Smrgstatic Time lastButton3UpTime = 0; 146d522f475Smrgstatic Time lastButton3DoubleDownTime = 0; 147d522f475Smrgstatic CELL lastButton3; /* At the release time */ 148d522f475Smrg#endif /* OPT_READLINE */ 149d522f475Smrg 150e0a2b6dfSmrgstatic Char *SaveText(TScreen *screen, int row, int scol, int ecol, 151e0a2b6dfSmrg Char *lp, int *eol); 152e0a2b6dfSmrgstatic int Length(TScreen *screen, int row, int scol, int ecol); 153e0a2b6dfSmrgstatic void ComputeSelect(XtermWidget xw, CELL *startc, CELL *endc, Bool extend); 154894e0ac8Smrgstatic void EditorButton(XtermWidget xw, XButtonEvent *event); 155894e0ac8Smrgstatic void EndExtend(XtermWidget w, XEvent *event, String *params, Cardinal 156d522f475Smrg num_params, Bool use_cursor_loc); 157e0a2b6dfSmrgstatic void ExtendExtend(XtermWidget xw, const CELL *cell); 158e0a2b6dfSmrgstatic void PointToCELL(TScreen *screen, int y, int x, CELL *cell); 159e0a2b6dfSmrgstatic void ReHiliteText(XtermWidget xw, CELL *first, CELL *last); 160e0a2b6dfSmrgstatic void SaltTextAway(XtermWidget xw, CELL *cellc, CELL *cell); 161894e0ac8Smrgstatic void SelectSet(XtermWidget xw, XEvent *event, String *params, Cardinal num_params); 162d522f475Smrgstatic void SelectionReceived PROTO_XT_SEL_CB_ARGS; 163e0a2b6dfSmrgstatic void StartSelect(XtermWidget xw, const CELL *cell); 164894e0ac8Smrgstatic void TrackDown(XtermWidget xw, XButtonEvent *event); 165e0a2b6dfSmrgstatic void TrackText(XtermWidget xw, const CELL *first, const CELL *last); 166e0a2b6dfSmrgstatic void _OwnSelection(XtermWidget xw, String *selections, Cardinal count); 167894e0ac8Smrgstatic void do_select_end(XtermWidget xw, XEvent *event, String *params, 168d522f475Smrg Cardinal *num_params, Bool use_cursor_loc); 169d522f475Smrg 170492d43a5Smrg#define MOUSE_LIMIT (255 - 32) 171d522f475Smrg 172492d43a5Smrg/* Send SET_EXT_SIZE_MOUSE to enable offsets up to EXT_MOUSE_LIMIT */ 173492d43a5Smrg#define EXT_MOUSE_LIMIT (2047 - 32) 174492d43a5Smrg#define EXT_MOUSE_START (127 - 32) 175d522f475Smrg 1760bd37d32Smrgstatic int 177e0a2b6dfSmrgMouseLimit(TScreen *screen) 1780bd37d32Smrg{ 1790bd37d32Smrg int mouse_limit; 1800bd37d32Smrg 1810bd37d32Smrg switch (screen->extend_coords) { 1820bd37d32Smrg default: 1830bd37d32Smrg mouse_limit = MOUSE_LIMIT; 1840bd37d32Smrg break; 1850bd37d32Smrg case SET_EXT_MODE_MOUSE: 1860bd37d32Smrg mouse_limit = EXT_MOUSE_LIMIT; 1870bd37d32Smrg break; 1880bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 1890bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 1900bd37d32Smrg mouse_limit = -1; 1910bd37d32Smrg break; 1920bd37d32Smrg } 1930bd37d32Smrg return mouse_limit; 1940bd37d32Smrg} 1950bd37d32Smrg 196492d43a5Smrgstatic unsigned 197e0a2b6dfSmrgEmitMousePosition(TScreen *screen, Char line[], unsigned count, int value) 198492d43a5Smrg{ 1990bd37d32Smrg int mouse_limit = MouseLimit(screen); 200492d43a5Smrg 201492d43a5Smrg /* 202492d43a5Smrg * Add pointer position to key sequence 203492d43a5Smrg * 204492d43a5Smrg * In extended mode we encode large positions as two-byte UTF-8. 205492d43a5Smrg * 206492d43a5Smrg * NOTE: historically, it was possible to emit 256, which became 207492d43a5Smrg * zero by truncation to 8 bits. While this was arguably a bug, 208492d43a5Smrg * it's also somewhat useful as a past-end marker. We preserve 209492d43a5Smrg * this behavior for both normal and extended mouse modes. 210492d43a5Smrg */ 2110bd37d32Smrg switch (screen->extend_coords) { 2120bd37d32Smrg default: 2130bd37d32Smrg if (value == mouse_limit) { 2140bd37d32Smrg line[count++] = CharOf(0); 2150bd37d32Smrg } else { 2160bd37d32Smrg line[count++] = CharOf(' ' + value + 1); 2170bd37d32Smrg } 2180bd37d32Smrg break; 2190bd37d32Smrg case SET_EXT_MODE_MOUSE: 2200bd37d32Smrg if (value == mouse_limit) { 2210bd37d32Smrg line[count++] = CharOf(0); 2220bd37d32Smrg } else if (value < EXT_MOUSE_START) { 2230bd37d32Smrg line[count++] = CharOf(' ' + value + 1); 2240bd37d32Smrg } else { 2250bd37d32Smrg value += ' ' + 1; 2260bd37d32Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 2270bd37d32Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 2280bd37d32Smrg } 2290bd37d32Smrg break; 2300bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 2310bd37d32Smrg /* FALLTHRU */ 2320bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 2330bd37d32Smrg count += (unsigned) sprintf((char *) line + count, "%d", value + 1); 2340bd37d32Smrg break; 2350bd37d32Smrg } 2360bd37d32Smrg return count; 2370bd37d32Smrg} 2380bd37d32Smrg 2390bd37d32Smrgstatic unsigned 240e0a2b6dfSmrgEmitMousePositionSeparator(TScreen *screen, Char line[], unsigned count) 2410bd37d32Smrg{ 2420bd37d32Smrg switch (screen->extend_coords) { 2430bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 2440bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 2450bd37d32Smrg line[count++] = ';'; 2460bd37d32Smrg break; 247d522f475Smrg } 248492d43a5Smrg return count; 249492d43a5Smrg} 250d522f475Smrg 251492d43a5SmrgBool 252894e0ac8SmrgSendMousePosition(XtermWidget xw, XEvent *event) 253492d43a5Smrg{ 254492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 255492d43a5Smrg Bool result = False; 256d522f475Smrg 257913cc679Smrg switch (okSendMousePos(xw)) { 258492d43a5Smrg case MOUSE_OFF: 259492d43a5Smrg /* If send_mouse_pos mode isn't on, we shouldn't be here */ 260492d43a5Smrg break; 261d522f475Smrg 262d522f475Smrg case BTN_EVENT_MOUSE: 263d522f475Smrg case ANY_EVENT_MOUSE: 264492d43a5Smrg if (KeyModifiers(event) == 0 || KeyModifiers(event) == ControlMask) { 265492d43a5Smrg /* xterm extension for motion reporting. June 1998 */ 266492d43a5Smrg /* EditorButton() will distinguish between the modes */ 267492d43a5Smrg switch (event->type) { 268492d43a5Smrg case MotionNotify: 269492d43a5Smrg my_event->button = 0; 270492d43a5Smrg /* FALLTHRU */ 271492d43a5Smrg case ButtonPress: 272492d43a5Smrg /* FALLTHRU */ 273492d43a5Smrg case ButtonRelease: 274492d43a5Smrg EditorButton(xw, my_event); 275492d43a5Smrg result = True; 276492d43a5Smrg break; 2772eaa94a1Schristos } 278d522f475Smrg } 279492d43a5Smrg break; 280d522f475Smrg 281913cc679Smrg case X10_MOUSE: /* X10 compatibility sequences */ 282492d43a5Smrg if (IsBtnEvent(event)) { 283913cc679Smrg if (BtnModifiers(my_event) == 0) { 284913cc679Smrg if (my_event->type == ButtonPress) 285492d43a5Smrg EditorButton(xw, my_event); 286913cc679Smrg result = True; 287913cc679Smrg } 288913cc679Smrg } 289913cc679Smrg break; 290492d43a5Smrg 291913cc679Smrg case VT200_HIGHLIGHT_MOUSE: /* DEC vt200 hilite tracking */ 292913cc679Smrg if (IsBtnEvent(event)) { 293913cc679Smrg if (my_event->type == ButtonPress && 294913cc679Smrg BtnModifiers(my_event) == 0 && 295913cc679Smrg my_event->button == Button1) { 296913cc679Smrg TrackDown(xw, my_event); 297913cc679Smrg result = True; 298913cc679Smrg } else if (BtnModifiers(my_event) == 0 299913cc679Smrg || BtnModifiers(my_event) == ControlMask) { 300913cc679Smrg EditorButton(xw, my_event); 301913cc679Smrg result = True; 302913cc679Smrg } 303913cc679Smrg } 304913cc679Smrg break; 305492d43a5Smrg 306913cc679Smrg case VT200_MOUSE: /* DEC vt200 compatible */ 307913cc679Smrg if (IsBtnEvent(event)) { 308913cc679Smrg if (BtnModifiers(my_event) == 0 309913cc679Smrg || BtnModifiers(my_event) == ControlMask) { 310913cc679Smrg EditorButton(xw, my_event); 311913cc679Smrg result = True; 312913cc679Smrg } 313913cc679Smrg } 314913cc679Smrg break; 315913cc679Smrg 316913cc679Smrg case DEC_LOCATOR: 317913cc679Smrg if (IsBtnEvent(event)) { 318492d43a5Smrg#if OPT_DEC_LOCATOR 319913cc679Smrg result = SendLocatorPosition(xw, my_event); 320492d43a5Smrg#endif /* OPT_DEC_LOCATOR */ 321492d43a5Smrg } 322913cc679Smrg break; 323d522f475Smrg } 324492d43a5Smrg return result; 325d522f475Smrg} 326d522f475Smrg 327d522f475Smrg#if OPT_DEC_LOCATOR 328d522f475Smrg 329d522f475Smrg#define LocatorCoords( row, col, x, y, oor ) \ 330d522f475Smrg if( screen->locator_pixels ) { \ 331d522f475Smrg (oor)=False; (row) = (y)+1; (col) = (x)+1; \ 332d522f475Smrg /* Limit to screen dimensions */ \ 333d522f475Smrg if ((row) < 1) (row) = 1,(oor)=True; \ 334d522f475Smrg else if ((row) > screen->border*2+Height(screen)) \ 335d522f475Smrg (row) = screen->border*2+Height(screen),(oor)=True; \ 336d522f475Smrg if ((col) < 1) (col) = 1,(oor)=True; \ 337d522f475Smrg else if ((col) > OriginX(screen)*2+Width(screen)) \ 338d522f475Smrg (col) = OriginX(screen)*2+Width(screen),(oor)=True; \ 339d522f475Smrg } else { \ 340d522f475Smrg (oor)=False; \ 341d522f475Smrg /* Compute character position of mouse pointer */ \ 342d522f475Smrg (row) = ((y) - screen->border) / FontHeight(screen); \ 343d522f475Smrg (col) = ((x) - OriginX(screen)) / FontWidth(screen); \ 344d522f475Smrg /* Limit to screen dimensions */ \ 345d522f475Smrg if ((row) < 0) (row) = 0,(oor)=True; \ 346d522f475Smrg else if ((row) > screen->max_row) \ 347d522f475Smrg (row) = screen->max_row,(oor)=True; \ 348d522f475Smrg if ((col) < 0) (col) = 0,(oor)=True; \ 349d522f475Smrg else if ((col) > screen->max_col) \ 350d522f475Smrg (col) = screen->max_col,(oor)=True; \ 351d522f475Smrg (row)++; (col)++; \ 352d522f475Smrg } 353d522f475Smrg 354d522f475Smrgstatic Bool 355894e0ac8SmrgSendLocatorPosition(XtermWidget xw, XButtonEvent *event) 356d522f475Smrg{ 357d522f475Smrg ANSI reply; 358956cc18dSsnj TScreen *screen = TScreenOf(xw); 359d522f475Smrg int row, col; 360d522f475Smrg Bool oor; 361d522f475Smrg int button; 3622eaa94a1Schristos unsigned state; 363d522f475Smrg 364d522f475Smrg /* Make sure the event is an appropriate type */ 365492d43a5Smrg if ((!IsBtnEvent(event) && 366d522f475Smrg !screen->loc_filter) || 367492d43a5Smrg (BtnModifiers(event) != 0 && BtnModifiers(event) != ControlMask)) 368d522f475Smrg return (False); 369d522f475Smrg 370d522f475Smrg if ((event->type == ButtonPress && 371d522f475Smrg !(screen->locator_events & LOC_BTNS_DN)) || 372d522f475Smrg (event->type == ButtonRelease && 373d522f475Smrg !(screen->locator_events & LOC_BTNS_UP))) 374d522f475Smrg return (True); 375d522f475Smrg 376d522f475Smrg if (event->type == MotionNotify) { 377d522f475Smrg CheckLocatorPosition(xw, event); 378d522f475Smrg return (True); 379d522f475Smrg } 380d522f475Smrg 381d522f475Smrg /* get button # */ 382492d43a5Smrg button = (int) event->button - 1; 383d522f475Smrg 384492d43a5Smrg LocatorCoords(row, col, event->x, event->y, oor); 385d522f475Smrg 386d522f475Smrg /* 387d522f475Smrg * DECterm mouse: 388d522f475Smrg * 389d522f475Smrg * ESCAPE '[' event ; mask ; row ; column '&' 'w' 390d522f475Smrg */ 391d522f475Smrg memset(&reply, 0, sizeof(reply)); 392d522f475Smrg reply.a_type = ANSI_CSI; 393d522f475Smrg 394d522f475Smrg if (oor) { 395d522f475Smrg reply.a_nparam = 1; 396d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 397d522f475Smrg reply.a_inters = '&'; 398d522f475Smrg reply.a_final = 'w'; 399d522f475Smrg unparseseq(xw, &reply); 400d522f475Smrg 401d522f475Smrg if (screen->locator_reset) { 402d522f475Smrg MotionOff(screen, xw); 403d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 404d522f475Smrg } 405d522f475Smrg return (True); 406d522f475Smrg } 407d522f475Smrg 408d522f475Smrg /* 409d522f475Smrg * event: 410d522f475Smrg * 1 no buttons 411d522f475Smrg * 2 left button down 412d522f475Smrg * 3 left button up 413d522f475Smrg * 4 middle button down 414d522f475Smrg * 5 middle button up 415d522f475Smrg * 6 right button down 416d522f475Smrg * 7 right button up 417d522f475Smrg * 8 M4 down 418d522f475Smrg * 9 M4 up 419d522f475Smrg */ 420d522f475Smrg reply.a_nparam = 4; 421d522f475Smrg switch (event->type) { 422d522f475Smrg case ButtonPress: 4232eaa94a1Schristos reply.a_param[0] = (ParmType) (2 + (button << 1)); 424d522f475Smrg break; 425d522f475Smrg case ButtonRelease: 4262eaa94a1Schristos reply.a_param[0] = (ParmType) (3 + (button << 1)); 427d522f475Smrg break; 428d522f475Smrg default: 429d522f475Smrg return (True); 430d522f475Smrg } 431d522f475Smrg /* 432d522f475Smrg * mask: 433913cc679Smrg * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 434913cc679Smrg * M4 down left down middle down right down 435d522f475Smrg * 436d522f475Smrg * Notice that Button1 (left) and Button3 (right) are swapped in the mask. 437d522f475Smrg * Also, mask should be the state after the button press/release, 438d522f475Smrg * X provides the state not including the button press/release. 439d522f475Smrg */ 440492d43a5Smrg state = (event->state 441d522f475Smrg & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8; 4424e40088cSchristos /* update mask to "after" state */ 44320d2c4d2Smrg state ^= ((unsigned) (1 << button)); 4444e40088cSchristos /* swap Button1 & Button3 */ 445956cc18dSsnj state = ((state & (unsigned) ~(4 | 1)) 446956cc18dSsnj | ((state & 1) ? 4 : 0) 447956cc18dSsnj | ((state & 4) ? 1 : 0)); 448d522f475Smrg 4492eaa94a1Schristos reply.a_param[1] = (ParmType) state; 4502eaa94a1Schristos reply.a_param[2] = (ParmType) row; 4512eaa94a1Schristos reply.a_param[3] = (ParmType) col; 452d522f475Smrg reply.a_inters = '&'; 453d522f475Smrg reply.a_final = 'w'; 454d522f475Smrg 455d522f475Smrg unparseseq(xw, &reply); 456d522f475Smrg 457d522f475Smrg if (screen->locator_reset) { 458d522f475Smrg MotionOff(screen, xw); 459d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 460d522f475Smrg } 461d522f475Smrg 462d522f475Smrg /* 463913cc679Smrg * DECterm turns the Locator off if a button is pressed while a filter 464913cc679Smrg * rectangle is active. This might be a bug, but I don't know, so I'll 465913cc679Smrg * emulate it anyway. 466d522f475Smrg */ 467d522f475Smrg if (screen->loc_filter) { 468d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 469d522f475Smrg screen->loc_filter = False; 470d522f475Smrg screen->locator_events = 0; 471d522f475Smrg MotionOff(screen, xw); 472d522f475Smrg } 473d522f475Smrg 474d522f475Smrg return (True); 475d522f475Smrg} 476d522f475Smrg 477d522f475Smrg/* 478d522f475Smrg * mask: 479d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 480d522f475Smrg * M4 down left down middle down right down 481d522f475Smrg * 482d522f475Smrg * Button1 (left) and Button3 (right) are swapped in the mask relative to X. 483d522f475Smrg */ 484d522f475Smrg#define ButtonState(state, mask) \ 485913cc679Smrg{ int stemp = (int) (((mask) & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8); \ 486d522f475Smrg /* swap Button1 & Button3 */ \ 487913cc679Smrg (state) = (stemp & ~(4|1)) | ((stemp & 1) ? 4 : 0) | ((stemp & 4) ? 1 : 0); \ 488d522f475Smrg} 489d522f475Smrg 490d522f475Smrgvoid 491d522f475SmrgGetLocatorPosition(XtermWidget xw) 492d522f475Smrg{ 493d522f475Smrg ANSI reply; 494956cc18dSsnj TScreen *screen = TScreenOf(xw); 495d522f475Smrg Window root, child; 496d522f475Smrg int rx, ry, x, y; 497d522f475Smrg unsigned int mask; 498d522f475Smrg int row = 0, col = 0; 499d522f475Smrg Bool oor = False; 500d522f475Smrg Bool ret = False; 501d522f475Smrg int state; 502d522f475Smrg 503d522f475Smrg /* 504913cc679Smrg * DECterm turns the Locator off if the position is requested while a 505913cc679Smrg * filter rectangle is active. This might be a bug, but I don't know, so 506913cc679Smrg * I'll emulate it anyways. 507d522f475Smrg */ 508d522f475Smrg if (screen->loc_filter) { 509d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 510d522f475Smrg screen->loc_filter = False; 511d522f475Smrg screen->locator_events = 0; 512d522f475Smrg MotionOff(screen, xw); 513d522f475Smrg } 514d522f475Smrg 515d522f475Smrg memset(&reply, 0, sizeof(reply)); 516d522f475Smrg reply.a_type = ANSI_CSI; 517d522f475Smrg 518913cc679Smrg if (okSendMousePos(xw) == DEC_LOCATOR) { 519d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), &root, 520d522f475Smrg &child, &rx, &ry, &x, &y, &mask); 521d522f475Smrg if (ret) { 522d522f475Smrg LocatorCoords(row, col, x, y, oor); 523d522f475Smrg } 524d522f475Smrg } 525d522f475Smrg if (ret == False || oor) { 526d522f475Smrg reply.a_nparam = 1; 527d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 528d522f475Smrg reply.a_inters = '&'; 529d522f475Smrg reply.a_final = 'w'; 530d522f475Smrg unparseseq(xw, &reply); 531d522f475Smrg 532d522f475Smrg if (screen->locator_reset) { 533d522f475Smrg MotionOff(screen, xw); 534d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 535d522f475Smrg } 536d522f475Smrg return; 537d522f475Smrg } 538d522f475Smrg 539d522f475Smrg ButtonState(state, mask); 540d522f475Smrg 541d522f475Smrg reply.a_nparam = 4; 542d522f475Smrg reply.a_param[0] = 1; /* Event - 1 = response to locator request */ 5432eaa94a1Schristos reply.a_param[1] = (ParmType) state; 5442eaa94a1Schristos reply.a_param[2] = (ParmType) row; 5452eaa94a1Schristos reply.a_param[3] = (ParmType) col; 546d522f475Smrg reply.a_inters = '&'; 547d522f475Smrg reply.a_final = 'w'; 548d522f475Smrg unparseseq(xw, &reply); 549d522f475Smrg 550d522f475Smrg if (screen->locator_reset) { 551d522f475Smrg MotionOff(screen, xw); 552d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 553d522f475Smrg } 554d522f475Smrg} 555d522f475Smrg 556d522f475Smrgvoid 557d522f475SmrgInitLocatorFilter(XtermWidget xw) 558d522f475Smrg{ 559d522f475Smrg ANSI reply; 560956cc18dSsnj TScreen *screen = TScreenOf(xw); 561d522f475Smrg Window root, child; 562d522f475Smrg int rx, ry, x, y; 563d522f475Smrg unsigned int mask; 564d522f475Smrg int row = 0, col = 0; 565d522f475Smrg Bool oor = 0; 566d522f475Smrg Bool ret; 567d522f475Smrg 568d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), 569d522f475Smrg &root, &child, &rx, &ry, &x, &y, &mask); 570d522f475Smrg if (ret) { 571d522f475Smrg LocatorCoords(row, col, x, y, oor); 572d522f475Smrg } 573d522f475Smrg if (ret == False || oor) { 574d522f475Smrg /* Locator is unavailable */ 575d522f475Smrg 576d522f475Smrg if (screen->loc_filter_top != LOC_FILTER_POS || 577d522f475Smrg screen->loc_filter_left != LOC_FILTER_POS || 578d522f475Smrg screen->loc_filter_bottom != LOC_FILTER_POS || 579d522f475Smrg screen->loc_filter_right != LOC_FILTER_POS) { 580d522f475Smrg /* 581d522f475Smrg * If any explicit coordinates were received, 582d522f475Smrg * report immediately with no coordinates. 583d522f475Smrg */ 584d522f475Smrg memset(&reply, 0, sizeof(reply)); 585d522f475Smrg reply.a_type = ANSI_CSI; 586d522f475Smrg reply.a_nparam = 1; 587d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 588d522f475Smrg reply.a_inters = '&'; 589d522f475Smrg reply.a_final = 'w'; 590d522f475Smrg unparseseq(xw, &reply); 591d522f475Smrg 592d522f475Smrg if (screen->locator_reset) { 593d522f475Smrg MotionOff(screen, xw); 594d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 595d522f475Smrg } 596d522f475Smrg } else { 597d522f475Smrg /* 598d522f475Smrg * No explicit coordinates were received, and the pointer is 599d522f475Smrg * unavailable. Report when the pointer re-enters the window. 600d522f475Smrg */ 601d522f475Smrg screen->loc_filter = True; 602d522f475Smrg MotionOn(screen, xw); 603d522f475Smrg } 604d522f475Smrg return; 605d522f475Smrg } 606d522f475Smrg 607d522f475Smrg /* 608d522f475Smrg * Adjust rectangle coordinates: 609d522f475Smrg * 1. Replace "LOC_FILTER_POS" with current coordinates 610d522f475Smrg * 2. Limit coordinates to screen size 611d522f475Smrg * 3. make sure top and left are less than bottom and right, resp. 612d522f475Smrg */ 613d522f475Smrg if (screen->locator_pixels) { 614d522f475Smrg rx = OriginX(screen) * 2 + Width(screen); 615d522f475Smrg ry = screen->border * 2 + Height(screen); 616d522f475Smrg } else { 617d522f475Smrg rx = screen->max_col; 618d522f475Smrg ry = screen->max_row; 619d522f475Smrg } 620d522f475Smrg 621d522f475Smrg#define Adjust( coord, def, max ) \ 622d522f475Smrg if( (coord) == LOC_FILTER_POS ) (coord) = (def); \ 623d522f475Smrg else if ((coord) < 1) (coord) = 1; \ 624d522f475Smrg else if ((coord) > (max)) (coord) = (max) 625d522f475Smrg 626d522f475Smrg Adjust(screen->loc_filter_top, row, ry); 627d522f475Smrg Adjust(screen->loc_filter_left, col, rx); 628d522f475Smrg Adjust(screen->loc_filter_bottom, row, ry); 629d522f475Smrg Adjust(screen->loc_filter_right, col, rx); 630d522f475Smrg 631d522f475Smrg if (screen->loc_filter_top > screen->loc_filter_bottom) { 632d522f475Smrg ry = screen->loc_filter_top; 633d522f475Smrg screen->loc_filter_top = screen->loc_filter_bottom; 634d522f475Smrg screen->loc_filter_bottom = ry; 635d522f475Smrg } 636d522f475Smrg 637d522f475Smrg if (screen->loc_filter_left > screen->loc_filter_right) { 638d522f475Smrg rx = screen->loc_filter_left; 639d522f475Smrg screen->loc_filter_left = screen->loc_filter_right; 640d522f475Smrg screen->loc_filter_right = rx; 641d522f475Smrg } 642d522f475Smrg 643d522f475Smrg if ((col < screen->loc_filter_left) || 644d522f475Smrg (col > screen->loc_filter_right) || 645d522f475Smrg (row < screen->loc_filter_top) || 646d522f475Smrg (row > screen->loc_filter_bottom)) { 6472e4f8982Smrg int state; 6482e4f8982Smrg 649d522f475Smrg /* Pointer is already outside the rectangle - report immediately */ 650d522f475Smrg ButtonState(state, mask); 651d522f475Smrg 652d522f475Smrg memset(&reply, 0, sizeof(reply)); 653d522f475Smrg reply.a_type = ANSI_CSI; 654d522f475Smrg reply.a_nparam = 4; 655d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 6562eaa94a1Schristos reply.a_param[1] = (ParmType) state; 6572eaa94a1Schristos reply.a_param[2] = (ParmType) row; 6582eaa94a1Schristos reply.a_param[3] = (ParmType) col; 659d522f475Smrg reply.a_inters = '&'; 660d522f475Smrg reply.a_final = 'w'; 661d522f475Smrg unparseseq(xw, &reply); 662d522f475Smrg 663d522f475Smrg if (screen->locator_reset) { 664d522f475Smrg MotionOff(screen, xw); 665d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 666d522f475Smrg } 667d522f475Smrg return; 668d522f475Smrg } 669d522f475Smrg 670d522f475Smrg /* 671d522f475Smrg * Rectangle is set up. Allow pointer tracking 672d522f475Smrg * to detect if the mouse leaves the rectangle. 673d522f475Smrg */ 674d522f475Smrg screen->loc_filter = True; 675d522f475Smrg MotionOn(screen, xw); 676d522f475Smrg} 677d522f475Smrg 678d522f475Smrgstatic void 679894e0ac8SmrgCheckLocatorPosition(XtermWidget xw, XButtonEvent *event) 680d522f475Smrg{ 681d522f475Smrg ANSI reply; 682956cc18dSsnj TScreen *screen = TScreenOf(xw); 683d522f475Smrg int row, col; 684d522f475Smrg Bool oor; 685d522f475Smrg 686492d43a5Smrg LocatorCoords(row, col, event->x, event->y, oor); 687d522f475Smrg 688d522f475Smrg /* 689d522f475Smrg * Send report if the pointer left the filter rectangle, if 690d522f475Smrg * the pointer left the window, or if the filter rectangle 691d522f475Smrg * had no coordinates and the pointer re-entered the window. 692d522f475Smrg */ 693d522f475Smrg if (oor || (screen->loc_filter_top == LOC_FILTER_POS) || 694d522f475Smrg (col < screen->loc_filter_left) || 695d522f475Smrg (col > screen->loc_filter_right) || 696d522f475Smrg (row < screen->loc_filter_top) || 697d522f475Smrg (row > screen->loc_filter_bottom)) { 698d522f475Smrg /* Filter triggered - disable it */ 699d522f475Smrg screen->loc_filter = False; 700d522f475Smrg MotionOff(screen, xw); 701d522f475Smrg 702d522f475Smrg memset(&reply, 0, sizeof(reply)); 703d522f475Smrg reply.a_type = ANSI_CSI; 704d522f475Smrg if (oor) { 705d522f475Smrg reply.a_nparam = 1; 706d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 707d522f475Smrg } else { 7082e4f8982Smrg int state; 7092e4f8982Smrg 710492d43a5Smrg ButtonState(state, event->state); 711d522f475Smrg 712d522f475Smrg reply.a_nparam = 4; 713d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 7142eaa94a1Schristos reply.a_param[1] = (ParmType) state; 7152eaa94a1Schristos reply.a_param[2] = (ParmType) row; 7162eaa94a1Schristos reply.a_param[3] = (ParmType) col; 717d522f475Smrg } 718d522f475Smrg 719d522f475Smrg reply.a_inters = '&'; 720d522f475Smrg reply.a_final = 'w'; 721d522f475Smrg unparseseq(xw, &reply); 722d522f475Smrg 723d522f475Smrg if (screen->locator_reset) { 724d522f475Smrg MotionOff(screen, xw); 725d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 726d522f475Smrg } 727d522f475Smrg } 728d522f475Smrg} 729d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 730d522f475Smrg 731d522f475Smrg#if OPT_READLINE 732d522f475Smrgstatic int 733913cc679SmrgisClick1_clean(XtermWidget xw, XButtonEvent *event) 734d522f475Smrg{ 735913cc679Smrg TScreen *screen = TScreenOf(xw); 736d522f475Smrg int delta; 737d522f475Smrg 738492d43a5Smrg if (!IsBtnEvent(event) 739d522f475Smrg /* Disable on Shift-Click-1, including the application-mouse modes */ 740492d43a5Smrg || (BtnModifiers(event) & ShiftMask) 741913cc679Smrg || (okSendMousePos(xw) != MOUSE_OFF) /* Kinda duplicate... */ 742d522f475Smrg ||ExtendingSelection) /* Was moved */ 743d522f475Smrg return 0; 744d522f475Smrg 745d522f475Smrg if (event->type != ButtonRelease) 746d522f475Smrg return 0; 747d522f475Smrg 748d522f475Smrg if (lastButtonDownTime == (Time) 0) { 749d522f475Smrg /* first time or once in a blue moon */ 750d522f475Smrg delta = screen->multiClickTime + 1; 751492d43a5Smrg } else if (event->time > lastButtonDownTime) { 752d522f475Smrg /* most of the time */ 753492d43a5Smrg delta = (int) (event->time - lastButtonDownTime); 754d522f475Smrg } else { 755d522f475Smrg /* time has rolled over since lastButtonUpTime */ 756492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->time); 757d522f475Smrg } 758d522f475Smrg 759d522f475Smrg return delta <= screen->multiClickTime; 760d522f475Smrg} 761d522f475Smrg 762d522f475Smrgstatic int 763894e0ac8SmrgisDoubleClick3(TScreen *screen, XButtonEvent *event) 764d522f475Smrg{ 765d522f475Smrg int delta; 766d522f475Smrg 767d522f475Smrg if (event->type != ButtonRelease 768492d43a5Smrg || (BtnModifiers(event) & ShiftMask) 769492d43a5Smrg || event->button != Button3) { 770d522f475Smrg lastButton3UpTime = 0; /* Disable the cached info */ 771d522f475Smrg return 0; 772d522f475Smrg } 773d522f475Smrg /* Process Btn3Release. */ 774d522f475Smrg if (lastButton3DoubleDownTime == (Time) 0) { 775d522f475Smrg /* No previous click or once in a blue moon */ 776d522f475Smrg delta = screen->multiClickTime + 1; 777492d43a5Smrg } else if (event->time > lastButton3DoubleDownTime) { 778d522f475Smrg /* most of the time */ 779492d43a5Smrg delta = (int) (event->time - lastButton3DoubleDownTime); 780d522f475Smrg } else { 781d522f475Smrg /* time has rolled over since lastButton3DoubleDownTime */ 782492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButton3DoubleDownTime) + event->time); 783d522f475Smrg } 784d522f475Smrg if (delta <= screen->multiClickTime) { 785d522f475Smrg /* Double click */ 786d522f475Smrg CELL cell; 787d522f475Smrg 788d522f475Smrg /* Cannot check ExtendingSelection, since mouse-3 always sets it */ 789492d43a5Smrg PointToCELL(screen, event->y, event->x, &cell); 790d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 791d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the third click */ 792d522f475Smrg return 1; 793d522f475Smrg } 794d522f475Smrg } 795d522f475Smrg /* Not a double click, memorize for future check. */ 796492d43a5Smrg lastButton3UpTime = event->time; 797492d43a5Smrg PointToCELL(screen, event->y, event->x, &lastButton3); 798d522f475Smrg return 0; 799d522f475Smrg} 800d522f475Smrg 801d522f475Smrgstatic int 802894e0ac8SmrgCheckSecondPress3(TScreen *screen, XEvent *event) 803d522f475Smrg{ 804d522f475Smrg int delta; 805d522f475Smrg 806d522f475Smrg if (event->type != ButtonPress 807492d43a5Smrg || (KeyModifiers(event) & ShiftMask) 808d522f475Smrg || event->xbutton.button != Button3) { 809d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the cached info */ 810d522f475Smrg return 0; 811d522f475Smrg } 812d522f475Smrg /* Process Btn3Press. */ 813d522f475Smrg if (lastButton3UpTime == (Time) 0) { 814d522f475Smrg /* No previous click or once in a blue moon */ 815d522f475Smrg delta = screen->multiClickTime + 1; 816d522f475Smrg } else if (event->xbutton.time > lastButton3UpTime) { 817d522f475Smrg /* most of the time */ 8182eaa94a1Schristos delta = (int) (event->xbutton.time - lastButton3UpTime); 819d522f475Smrg } else { 820d522f475Smrg /* time has rolled over since lastButton3UpTime */ 8212eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButton3UpTime) + event->xbutton.time); 822d522f475Smrg } 823d522f475Smrg if (delta <= screen->multiClickTime) { 824d522f475Smrg CELL cell; 825d522f475Smrg 826d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 827d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 828d522f475Smrg /* A candidate for a double-click */ 829d522f475Smrg lastButton3DoubleDownTime = event->xbutton.time; 830d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &lastButton3); 831d522f475Smrg return 1; 832d522f475Smrg } 833d522f475Smrg lastButton3UpTime = 0; /* Disable the info about the previous click */ 834d522f475Smrg } 835d522f475Smrg /* Either too long, or moved, disable. */ 836d522f475Smrg lastButton3DoubleDownTime = 0; 837d522f475Smrg return 0; 838d522f475Smrg} 839d522f475Smrg 840d522f475Smrgstatic int 841e0a2b6dfSmrgrowOnCurrentLine(TScreen *screen, 842d522f475Smrg int line, 843d522f475Smrg int *deltap) /* must be XButtonEvent */ 844d522f475Smrg{ 845956cc18dSsnj int result = 1; 846d522f475Smrg 847d522f475Smrg *deltap = 0; 8482e4f8982Smrg 849956cc18dSsnj if (line != screen->cur_row) { 8502e4f8982Smrg int l1, l2; 8512e4f8982Smrg 852956cc18dSsnj if (line < screen->cur_row) 853956cc18dSsnj l1 = line, l2 = screen->cur_row; 854956cc18dSsnj else 855956cc18dSsnj l2 = line, l1 = screen->cur_row; 856956cc18dSsnj l1--; 857956cc18dSsnj while (++l1 < l2) { 858956cc18dSsnj LineData *ld = GET_LINEDATA(screen, l1); 859956cc18dSsnj if (!LineTstWrapped(ld)) { 860956cc18dSsnj result = 0; 861956cc18dSsnj break; 862956cc18dSsnj } 863956cc18dSsnj } 864956cc18dSsnj if (result) { 865956cc18dSsnj /* Everything is on one "wrapped line" now */ 866956cc18dSsnj *deltap = line - screen->cur_row; 867956cc18dSsnj } 868956cc18dSsnj } 869956cc18dSsnj return result; 870d522f475Smrg} 871d522f475Smrg 872d522f475Smrgstatic int 873894e0ac8SmrgeventRow(TScreen *screen, XEvent *event) /* must be XButtonEvent */ 874d522f475Smrg{ 875d522f475Smrg return (event->xbutton.y - screen->border) / FontHeight(screen); 876d522f475Smrg} 877d522f475Smrg 878d522f475Smrgstatic int 879894e0ac8SmrgeventColBetween(TScreen *screen, XEvent *event) /* must be XButtonEvent */ 880d522f475Smrg{ 881d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 882d522f475Smrg return ((event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) / 2) 883d522f475Smrg / FontWidth(screen)); 884d522f475Smrg} 885d522f475Smrg 886d522f475Smrgstatic int 887e0a2b6dfSmrgReadLineMovePoint(TScreen *screen, int col, int ldelta) 888d522f475Smrg{ 889d522f475Smrg Char line[6]; 890d522f475Smrg unsigned count = 0; 891d522f475Smrg 892d522f475Smrg col += ldelta * MaxCols(screen) - screen->cur_col; 893d522f475Smrg if (col == 0) 894d522f475Smrg return 0; 895d522f475Smrg if (screen->control_eight_bits) { 896d522f475Smrg line[count++] = ANSI_CSI; 897d522f475Smrg } else { 898d522f475Smrg line[count++] = ANSI_ESC; 899d522f475Smrg line[count++] = '['; /* XXX maybe sometimes O is better? */ 900d522f475Smrg } 90120d2c4d2Smrg line[count] = CharOf(col > 0 ? 'C' : 'D'); 902d522f475Smrg if (col < 0) 903d522f475Smrg col = -col; 904d522f475Smrg while (col--) 905d522f475Smrg v_write(screen->respond, line, 3); 906d522f475Smrg return 1; 907d522f475Smrg} 908d522f475Smrg 909d522f475Smrgstatic int 910e0a2b6dfSmrgReadLineDelete(TScreen *screen, CELL *cell1, CELL *cell2) 911d522f475Smrg{ 912d522f475Smrg int del; 913d522f475Smrg 914d522f475Smrg del = (cell2->col - cell1->col) + ((cell2->row - cell1->row) * MaxCols(screen)); 915d522f475Smrg if (del <= 0) /* Just in case... */ 916d522f475Smrg return 0; 917d522f475Smrg while (del--) 918492d43a5Smrg v_write(screen->respond, (const Char *) "\177", 1); 919d522f475Smrg return 1; 920d522f475Smrg} 921492d43a5Smrg 922492d43a5Smrgstatic void 923913cc679SmrgreadlineExtend(XtermWidget xw, XEvent *event) 924492d43a5Smrg{ 925913cc679Smrg TScreen *screen = TScreenOf(xw); 926492d43a5Smrg int ldelta1, ldelta2; 927492d43a5Smrg 928492d43a5Smrg if (IsBtnEvent(event)) { 929492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 930913cc679Smrg if (isClick1_clean(xw, my_event) 931492d43a5Smrg && SCREEN_FLAG(screen, click1_moves) 932492d43a5Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta1)) { 933492d43a5Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta1); 934492d43a5Smrg } 935492d43a5Smrg if (isDoubleClick3(screen, my_event) 936492d43a5Smrg && SCREEN_FLAG(screen, dclick3_deletes) 937492d43a5Smrg && rowOnCurrentLine(screen, screen->startSel.row, &ldelta1) 938492d43a5Smrg && rowOnCurrentLine(screen, screen->endSel.row, &ldelta2)) { 939492d43a5Smrg ReadLineMovePoint(screen, screen->endSel.col, ldelta2); 940492d43a5Smrg ReadLineDelete(screen, &screen->startSel, &(screen->endSel)); 941492d43a5Smrg } 942492d43a5Smrg } 943492d43a5Smrg} 944492d43a5Smrg 945d522f475Smrg#endif /* OPT_READLINE */ 946d522f475Smrg 947d522f475Smrg/* ^XM-G<line+' '><col+' '> */ 948d522f475Smrgvoid 949d522f475SmrgDiredButton(Widget w, 950894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 951e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 952d522f475Smrg Cardinal *num_params GCC_UNUSED) 953d522f475Smrg{ 954956cc18dSsnj XtermWidget xw; 955956cc18dSsnj 956956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 957956cc18dSsnj TScreen *screen = TScreenOf(xw); 958d522f475Smrg 959492d43a5Smrg if (IsBtnEvent(event) 9602eaa94a1Schristos && (event->xbutton.y >= screen->border) 9612eaa94a1Schristos && (event->xbutton.x >= OriginX(screen))) { 9622e4f8982Smrg Char Line[6]; 9632e4f8982Smrg unsigned line, col; 9642e4f8982Smrg 96520d2c4d2Smrg line = (unsigned) ((event->xbutton.y - screen->border) 96620d2c4d2Smrg / FontHeight(screen)); 96720d2c4d2Smrg col = (unsigned) ((event->xbutton.x - OriginX(screen)) 96820d2c4d2Smrg / FontWidth(screen)); 969d522f475Smrg Line[0] = CONTROL('X'); 970d522f475Smrg Line[1] = ANSI_ESC; 971d522f475Smrg Line[2] = 'G'; 9722eaa94a1Schristos Line[3] = CharOf(' ' + col); 9732eaa94a1Schristos Line[4] = CharOf(' ' + line); 974d522f475Smrg v_write(screen->respond, Line, 5); 975d522f475Smrg } 976d522f475Smrg } 977d522f475Smrg} 978d522f475Smrg 979d522f475Smrg#if OPT_READLINE 980d522f475Smrgvoid 981d522f475SmrgReadLineButton(Widget w, 982894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 983e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 984d522f475Smrg Cardinal *num_params GCC_UNUSED) 985d522f475Smrg{ 986956cc18dSsnj XtermWidget xw; 987956cc18dSsnj 988956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 989956cc18dSsnj TScreen *screen = TScreenOf(xw); 990d522f475Smrg Char Line[6]; 991d522f475Smrg int line, col, ldelta = 0; 992d522f475Smrg 993492d43a5Smrg if (!IsBtnEvent(event) 994913cc679Smrg || (okSendMousePos(xw) != MOUSE_OFF) || ExtendingSelection) 995d522f475Smrg goto finish; 996d522f475Smrg if (event->type == ButtonRelease) { 997d522f475Smrg int delta; 998d522f475Smrg 999d522f475Smrg if (lastButtonDownTime == (Time) 0) { 1000d522f475Smrg /* first time and once in a blue moon */ 1001d522f475Smrg delta = screen->multiClickTime + 1; 1002d522f475Smrg } else if (event->xbutton.time > lastButtonDownTime) { 1003d522f475Smrg /* most of the time */ 10042eaa94a1Schristos delta = (int) (event->xbutton.time - lastButtonDownTime); 1005d522f475Smrg } else { 1006d522f475Smrg /* time has rolled over since lastButtonUpTime */ 10072eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time); 1008d522f475Smrg } 1009d522f475Smrg if (delta > screen->multiClickTime) 1010d522f475Smrg goto finish; /* All this work for this... */ 1011d522f475Smrg } 1012d522f475Smrg line = (event->xbutton.y - screen->border) / FontHeight(screen); 1013956cc18dSsnj if (!rowOnCurrentLine(screen, line, &ldelta)) 1014956cc18dSsnj goto finish; 1015d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 1016d522f475Smrg col = (event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) 1017d522f475Smrg / 2) 1018d522f475Smrg / FontWidth(screen) - screen->cur_col + ldelta * MaxCols(screen); 1019d522f475Smrg if (col == 0) 1020d522f475Smrg goto finish; 1021d522f475Smrg Line[0] = ANSI_ESC; 1022d522f475Smrg /* XXX: sometimes it is better to send '['? */ 1023d522f475Smrg Line[1] = 'O'; 10242eaa94a1Schristos Line[2] = CharOf(col > 0 ? 'C' : 'D'); 1025d522f475Smrg if (col < 0) 1026d522f475Smrg col = -col; 1027d522f475Smrg while (col--) 1028d522f475Smrg v_write(screen->respond, Line, 3); 1029d522f475Smrg finish: 1030d522f475Smrg if (event->type == ButtonRelease) 1031d522f475Smrg do_select_end(xw, event, params, num_params, False); 1032d522f475Smrg } 1033d522f475Smrg} 1034d522f475Smrg#endif /* OPT_READLINE */ 1035d522f475Smrg 1036d522f475Smrg/* repeats <ESC>n or <ESC>p */ 1037d522f475Smrgvoid 1038d522f475SmrgViButton(Widget w, 1039894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1040e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 1041d522f475Smrg Cardinal *num_params GCC_UNUSED) 1042d522f475Smrg{ 1043956cc18dSsnj XtermWidget xw; 1044956cc18dSsnj 1045956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1046956cc18dSsnj TScreen *screen = TScreenOf(xw); 1047d522f475Smrg int pty = screen->respond; 1048d522f475Smrg 1049492d43a5Smrg if (IsBtnEvent(event)) { 10502e4f8982Smrg int line; 1051d522f475Smrg 1052d522f475Smrg line = screen->cur_row - 1053d522f475Smrg ((event->xbutton.y - screen->border) / FontHeight(screen)); 10542e4f8982Smrg 1055d522f475Smrg if (line != 0) { 10562e4f8982Smrg Char Line[6]; 10572e4f8982Smrg 1058d522f475Smrg Line[0] = ANSI_ESC; /* force an exit from insert-mode */ 1059d522f475Smrg v_write(pty, Line, 1); 1060d522f475Smrg 1061d522f475Smrg if (line < 0) { 1062d522f475Smrg line = -line; 1063d522f475Smrg Line[0] = CONTROL('n'); 1064d522f475Smrg } else { 1065d522f475Smrg Line[0] = CONTROL('p'); 1066d522f475Smrg } 1067d522f475Smrg while (--line >= 0) 1068d522f475Smrg v_write(pty, Line, 1); 1069d522f475Smrg } 1070d522f475Smrg } 1071d522f475Smrg } 1072d522f475Smrg} 1073d522f475Smrg 1074d522f475Smrg/* 1075d522f475Smrg * This function handles button-motion events 1076d522f475Smrg */ 1077d522f475Smrg/*ARGSUSED*/ 1078d522f475Smrgvoid 1079d522f475SmrgHandleSelectExtend(Widget w, 1080894e0ac8Smrg XEvent *event, /* must be XMotionEvent */ 1081e0a2b6dfSmrg String *params GCC_UNUSED, 1082d522f475Smrg Cardinal *num_params GCC_UNUSED) 1083d522f475Smrg{ 1084956cc18dSsnj XtermWidget xw; 1085956cc18dSsnj 1086956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1087956cc18dSsnj TScreen *screen = TScreenOf(xw); 1088d522f475Smrg CELL cell; 1089d522f475Smrg 1090e0a2b6dfSmrg TRACE(("HandleSelectExtend @%ld\n", event->xmotion.time)); 10910bd37d32Smrg 1092d522f475Smrg screen->selection_time = event->xmotion.time; 1093d522f475Smrg switch (screen->eventMode) { 1094d522f475Smrg /* If not in one of the DEC mouse-reporting modes */ 1095d522f475Smrg case LEFTEXTENSION: 1096d522f475Smrg case RIGHTEXTENSION: 1097d522f475Smrg PointToCELL(screen, event->xmotion.y, event->xmotion.x, &cell); 1098d522f475Smrg ExtendExtend(xw, &cell); 1099d522f475Smrg break; 1100d522f475Smrg 1101d522f475Smrg /* If in motion reporting mode, send mouse position to 1102d522f475Smrg character process as a key sequence \E[M... */ 1103d522f475Smrg case NORMAL: 1104d522f475Smrg /* will get here if send_mouse_pos != MOUSE_OFF */ 1105913cc679Smrg if (okSendMousePos(xw) == BTN_EVENT_MOUSE 1106913cc679Smrg || okSendMousePos(xw) == ANY_EVENT_MOUSE) { 1107d522f475Smrg (void) SendMousePosition(xw, event); 1108d522f475Smrg } 1109d522f475Smrg break; 1110d522f475Smrg } 1111d522f475Smrg } 1112d522f475Smrg} 1113d522f475Smrg 1114d522f475Smrgvoid 1115d522f475SmrgHandleKeyboardSelectExtend(Widget w, 1116894e0ac8Smrg XEvent *event GCC_UNUSED, /* must be XButtonEvent */ 1117e0a2b6dfSmrg String *params GCC_UNUSED, 1118d522f475Smrg Cardinal *num_params GCC_UNUSED) 1119d522f475Smrg{ 1120956cc18dSsnj XtermWidget xw; 1121956cc18dSsnj 1122956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1123956cc18dSsnj TScreen *screen = TScreenOf(xw); 11240bd37d32Smrg 11250bd37d32Smrg TRACE(("HandleKeyboardSelectExtend\n")); 1126d522f475Smrg ExtendExtend(xw, &screen->cursorp); 1127d522f475Smrg } 1128d522f475Smrg} 1129d522f475Smrg 1130d522f475Smrgstatic void 1131d522f475Smrgdo_select_end(XtermWidget xw, 1132894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1133e0a2b6dfSmrg String *params, /* selections */ 1134d522f475Smrg Cardinal *num_params, 1135d522f475Smrg Bool use_cursor_loc) 1136d522f475Smrg{ 1137956cc18dSsnj TScreen *screen = TScreenOf(xw); 1138d522f475Smrg 1139d522f475Smrg screen->selection_time = event->xbutton.time; 1140e0a2b6dfSmrg TRACE(("do_select_end @%ld\n", screen->selection_time)); 1141d522f475Smrg switch (screen->eventMode) { 1142d522f475Smrg case NORMAL: 1143d522f475Smrg (void) SendMousePosition(xw, event); 1144d522f475Smrg break; 1145d522f475Smrg case LEFTEXTENSION: 1146d522f475Smrg case RIGHTEXTENSION: 1147d522f475Smrg EndExtend(xw, event, params, *num_params, use_cursor_loc); 1148d522f475Smrg#if OPT_READLINE 1149913cc679Smrg readlineExtend(xw, event); 1150d522f475Smrg#endif /* OPT_READLINE */ 1151d522f475Smrg break; 1152d522f475Smrg } 1153d522f475Smrg} 1154d522f475Smrg 1155d522f475Smrgvoid 1156d522f475SmrgHandleSelectEnd(Widget w, 1157894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1158e0a2b6dfSmrg String *params, /* selections */ 1159d522f475Smrg Cardinal *num_params) 1160d522f475Smrg{ 1161956cc18dSsnj XtermWidget xw; 1162956cc18dSsnj 1163956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 11640bd37d32Smrg TRACE(("HandleSelectEnd\n")); 1165956cc18dSsnj do_select_end(xw, event, params, num_params, False); 1166956cc18dSsnj } 1167d522f475Smrg} 1168d522f475Smrg 1169d522f475Smrgvoid 1170d522f475SmrgHandleKeyboardSelectEnd(Widget w, 1171894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1172e0a2b6dfSmrg String *params, /* selections */ 1173d522f475Smrg Cardinal *num_params) 1174d522f475Smrg{ 1175956cc18dSsnj XtermWidget xw; 1176956cc18dSsnj 1177956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 11780bd37d32Smrg TRACE(("HandleKeyboardSelectEnd\n")); 1179956cc18dSsnj do_select_end(xw, event, params, num_params, True); 1180956cc18dSsnj } 1181d522f475Smrg} 1182d522f475Smrg 1183492d43a5Smrg/* 11846879286fSmrg * Copy the selection data to the given target(s). 1185492d43a5Smrg */ 1186492d43a5Smrgvoid 11876879286fSmrgHandleCopySelection(Widget w, 1188894e0ac8Smrg XEvent *event, 1189e0a2b6dfSmrg String *params, /* list of targets */ 11906879286fSmrg Cardinal *num_params) 1191492d43a5Smrg{ 1192492d43a5Smrg XtermWidget xw; 1193492d43a5Smrg 1194492d43a5Smrg if ((xw = getXtermWidget(w)) != 0) { 11950bd37d32Smrg TRACE(("HandleCopySelection\n")); 11966879286fSmrg SelectSet(xw, event, params, *num_params); 1197492d43a5Smrg } 1198492d43a5Smrg} 1199492d43a5Smrg 1200d522f475Smrgstruct _SelectionList { 1201d522f475Smrg String *params; 1202d522f475Smrg Cardinal count; 1203d522f475Smrg Atom *targets; 1204d522f475Smrg Time time; 1205d522f475Smrg}; 1206d522f475Smrg 1207d522f475Smrgstatic unsigned 1208d522f475SmrgDECtoASCII(unsigned ch) 1209d522f475Smrg{ 1210d522f475Smrg if (xtermIsDecGraphic(ch)) { 12112eaa94a1Schristos ch = CharOf("###########+++++##-##++++|######"[ch]); 12122eaa94a1Schristos /* 01234567890123456789012345678901 */ 1213d522f475Smrg } 1214d522f475Smrg return ch; 1215d522f475Smrg} 121620d2c4d2Smrg 121720d2c4d2Smrg#if OPT_WIDE_CHARS 121820d2c4d2Smrgstatic Cardinal 1219e0a2b6dfSmrgaddXtermChar(Char **buffer, Cardinal *used, Cardinal offset, unsigned value) 122020d2c4d2Smrg{ 122120d2c4d2Smrg if (offset + 1 >= *used) { 122220d2c4d2Smrg *used = 1 + (2 * (offset + 1)); 122320d2c4d2Smrg allocXtermChars(buffer, *used); 122420d2c4d2Smrg } 122520d2c4d2Smrg (*buffer)[offset++] = (Char) value; 122620d2c4d2Smrg return offset; 122720d2c4d2Smrg} 122820d2c4d2Smrg#define AddChar(buffer, used, offset, value) \ 122920d2c4d2Smrg offset = addXtermChar(buffer, used, offset, (unsigned) value) 123020d2c4d2Smrg 1231d522f475Smrg/* 1232d522f475Smrg * Convert a UTF-8 string to Latin-1, replacing non Latin-1 characters by `#', 1233d522f475Smrg * or ASCII/Latin-1 equivalents for special cases. 1234d522f475Smrg */ 1235d522f475Smrgstatic Char * 1236e0a2b6dfSmrgUTF8toLatin1(TScreen *screen, Char *s, unsigned long len, unsigned long *result) 1237d522f475Smrg{ 1238d522f475Smrg static Char *buffer; 1239956cc18dSsnj static Cardinal used; 1240d522f475Smrg 124120d2c4d2Smrg Cardinal offset = 0; 1242d522f475Smrg 124320d2c4d2Smrg if (len != 0) { 1244d522f475Smrg PtyData data; 1245d522f475Smrg 1246d522f475Smrg fakePtyData(&data, s, s + len); 1247894e0ac8Smrg while (decodeUtf8(screen, &data)) { 1248956cc18dSsnj Bool fails = False; 1249956cc18dSsnj Bool extra = False; 1250d522f475Smrg IChar value = skipPtyData(&data); 1251d522f475Smrg if (value == UCS_REPL) { 1252956cc18dSsnj fails = True; 1253d522f475Smrg } else if (value < 256) { 125420d2c4d2Smrg AddChar(&buffer, &used, offset, CharOf(value)); 1255d522f475Smrg } else { 1256d522f475Smrg unsigned eqv = ucs2dec(value); 1257d522f475Smrg if (xtermIsDecGraphic(eqv)) { 125820d2c4d2Smrg AddChar(&buffer, &used, offset, DECtoASCII(eqv)); 1259d522f475Smrg } else { 1260d522f475Smrg eqv = AsciiEquivs(value); 1261956cc18dSsnj if (eqv == value) { 1262956cc18dSsnj fails = True; 1263956cc18dSsnj } else { 126420d2c4d2Smrg AddChar(&buffer, &used, offset, eqv); 1265956cc18dSsnj } 1266956cc18dSsnj if (isWide((wchar_t) value)) 1267956cc18dSsnj extra = True; 1268956cc18dSsnj } 1269956cc18dSsnj } 1270956cc18dSsnj 1271956cc18dSsnj /* 1272956cc18dSsnj * If we're not able to plug in a single-byte result, insert the 1273956cc18dSsnj * defaultString (which normally is a single "#", but could be 1274956cc18dSsnj * whatever the user wants). 1275956cc18dSsnj */ 1276956cc18dSsnj if (fails) { 12772e4f8982Smrg const Char *p; 12782e4f8982Smrg 1279492d43a5Smrg for (p = (const Char *) screen->default_string; *p != '\0'; ++p) { 128020d2c4d2Smrg AddChar(&buffer, &used, offset, *p); 1281d522f475Smrg } 1282d522f475Smrg } 1283956cc18dSsnj if (extra) 128420d2c4d2Smrg AddChar(&buffer, &used, offset, ' '); 1285d522f475Smrg } 128620d2c4d2Smrg AddChar(&buffer, &used, offset, '\0'); 128720d2c4d2Smrg *result = (unsigned long) (offset - 1); 1288d522f475Smrg } else { 1289d522f475Smrg *result = 0; 1290d522f475Smrg } 1291d522f475Smrg return buffer; 1292d522f475Smrg} 129320d2c4d2Smrg 129420d2c4d2Smrgint 129520d2c4d2SmrgxtermUtf8ToTextList(XtermWidget xw, 129620d2c4d2Smrg XTextProperty * text_prop, 129720d2c4d2Smrg char ***text_list, 129820d2c4d2Smrg int *text_list_count) 129920d2c4d2Smrg{ 130020d2c4d2Smrg TScreen *screen = TScreenOf(xw); 130120d2c4d2Smrg Display *dpy = screen->display; 130220d2c4d2Smrg int rc = -1; 130320d2c4d2Smrg 130420d2c4d2Smrg if (text_prop->format == 8 130520d2c4d2Smrg && (rc = Xutf8TextPropertyToTextList(dpy, text_prop, 130620d2c4d2Smrg text_list, 130720d2c4d2Smrg text_list_count)) >= 0) { 130820d2c4d2Smrg if (*text_list != NULL && *text_list_count != 0) { 130920d2c4d2Smrg int i; 131020d2c4d2Smrg Char *data; 131120d2c4d2Smrg char **new_text_list, *tmp; 131220d2c4d2Smrg unsigned long size, new_size; 131320d2c4d2Smrg 131420d2c4d2Smrg TRACE(("xtermUtf8ToTextList size %d\n", *text_list_count)); 131520d2c4d2Smrg 131620d2c4d2Smrg /* 131720d2c4d2Smrg * XLib StringList actually uses only two pointers, one for the 131820d2c4d2Smrg * list itself, and one for the data. Pointer to the data is the 131920d2c4d2Smrg * first element of the list, the rest (if any) list elements point 132020d2c4d2Smrg * to the same memory block as the first element 132120d2c4d2Smrg */ 132220d2c4d2Smrg new_size = 0; 132320d2c4d2Smrg for (i = 0; i < *text_list_count; ++i) { 132420d2c4d2Smrg data = (Char *) (*text_list)[i]; 132520d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 132620d2c4d2Smrg (void) UTF8toLatin1(screen, data, size, &size); 132720d2c4d2Smrg new_size += size + 1; 132820d2c4d2Smrg } 1329a1f3da82Smrg new_text_list = TypeXtMallocN(char *, *text_list_count); 133020d2c4d2Smrg new_text_list[0] = tmp = XtMalloc((Cardinal) new_size); 133120d2c4d2Smrg for (i = 0; i < (*text_list_count); ++i) { 133220d2c4d2Smrg data = (Char *) (*text_list)[i]; 133320d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 13340bd37d32Smrg if ((data = UTF8toLatin1(screen, data, size, &size)) != 0) { 13350bd37d32Smrg memcpy(tmp, data, size + 1); 13360bd37d32Smrg new_text_list[i] = tmp; 13370bd37d32Smrg tmp += size + 1; 13380bd37d32Smrg } 133920d2c4d2Smrg } 134020d2c4d2Smrg XFreeStringList((*text_list)); 134120d2c4d2Smrg *text_list = new_text_list; 134220d2c4d2Smrg } else { 134320d2c4d2Smrg rc = -1; 134420d2c4d2Smrg } 134520d2c4d2Smrg } 134620d2c4d2Smrg return rc; 134720d2c4d2Smrg} 1348d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1349d522f475Smrg 1350956cc18dSsnjstatic char * 1351956cc18dSsnjparseItem(char *value, char *nextc) 1352d522f475Smrg{ 1353956cc18dSsnj char *nextp = value; 1354956cc18dSsnj while (*nextp != '\0' && *nextp != ',') { 1355956cc18dSsnj *nextp = x_toupper(*nextp); 1356956cc18dSsnj ++nextp; 1357956cc18dSsnj } 1358956cc18dSsnj *nextc = *nextp; 1359956cc18dSsnj *nextp = '\0'; 1360d522f475Smrg 1361956cc18dSsnj return nextp; 1362956cc18dSsnj} 1363d522f475Smrg 1364956cc18dSsnj/* 1365956cc18dSsnj * All of the wanted strings are unique in the first character, so we can 1366956cc18dSsnj * use simple abbreviations. 1367956cc18dSsnj */ 1368956cc18dSsnjstatic Bool 1369956cc18dSsnjsameItem(const char *actual, const char *wanted) 1370956cc18dSsnj{ 1371956cc18dSsnj Bool result = False; 1372956cc18dSsnj size_t have = strlen(actual); 1373956cc18dSsnj size_t need = strlen(wanted); 1374d522f475Smrg 1375956cc18dSsnj if (have != 0 && have <= need) { 1376956cc18dSsnj if (!strncmp(actual, wanted, have)) { 1377956cc18dSsnj TRACE(("...matched \"%s\"\n", wanted)); 1378956cc18dSsnj result = True; 1379956cc18dSsnj } 1380956cc18dSsnj } 1381956cc18dSsnj 1382956cc18dSsnj return result; 1383956cc18dSsnj} 1384956cc18dSsnj 1385956cc18dSsnj/* 1386956cc18dSsnj * Handle the eightBitSelectTypes or utf8SelectTypes resource values. 1387956cc18dSsnj */ 1388956cc18dSsnjstatic Bool 1389894e0ac8SmrgoverrideTargets(Widget w, String value, Atom **resultp) 1390956cc18dSsnj{ 1391956cc18dSsnj Bool override = False; 1392956cc18dSsnj XtermWidget xw; 1393956cc18dSsnj 1394956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1395956cc18dSsnj TScreen *screen = TScreenOf(xw); 1396956cc18dSsnj 139720d2c4d2Smrg if (!IsEmpty(value)) { 1398492d43a5Smrg char *copied = x_strdup(value); 1399956cc18dSsnj if (copied != 0) { 1400956cc18dSsnj Atom *result = 0; 1401956cc18dSsnj Cardinal count = 1; 1402956cc18dSsnj int n; 1403d522f475Smrg 1404956cc18dSsnj TRACE(("decoding SelectTypes \"%s\"\n", value)); 1405956cc18dSsnj for (n = 0; copied[n] != '\0'; ++n) { 1406956cc18dSsnj if (copied[n] == ',') 1407956cc18dSsnj ++count; 1408956cc18dSsnj } 1409a1f3da82Smrg result = TypeXtMallocN(Atom, (2 * count) + 1); 1410956cc18dSsnj if (result == NULL) { 1411956cc18dSsnj TRACE(("Couldn't allocate selection types\n")); 1412956cc18dSsnj } else { 1413956cc18dSsnj char nextc = '?'; 141420d2c4d2Smrg char *listp = (char *) copied; 1415956cc18dSsnj count = 0; 1416956cc18dSsnj do { 1417956cc18dSsnj char *nextp = parseItem(listp, &nextc); 14180bd37d32Smrg char *item = x_strtrim(listp); 14190bd37d32Smrg size_t len = (item ? strlen(item) : 0); 1420956cc18dSsnj 1421956cc18dSsnj if (len == 0) { 1422a1f3da82Smrg /* EMPTY */ ; 1423956cc18dSsnj } 1424956cc18dSsnj#if OPT_WIDE_CHARS 14250bd37d32Smrg else if (sameItem(item, "UTF8")) { 1426956cc18dSsnj result[count++] = XA_UTF8_STRING(XtDisplay(w)); 1427956cc18dSsnj } 1428956cc18dSsnj#endif 14290bd37d32Smrg else if (sameItem(item, "I18N")) { 1430956cc18dSsnj if (screen->i18nSelections) { 1431956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 1432956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1433956cc18dSsnj } 14340bd37d32Smrg } else if (sameItem(item, "TEXT")) { 1435956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 14360bd37d32Smrg } else if (sameItem(item, "COMPOUND_TEXT")) { 1437956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 14380bd37d32Smrg } else if (sameItem(item, "STRING")) { 1439956cc18dSsnj result[count++] = XA_STRING; 1440956cc18dSsnj } 1441956cc18dSsnj *nextp++ = nextc; 1442956cc18dSsnj listp = nextp; 14430bd37d32Smrg free(item); 1444956cc18dSsnj } while (nextc != '\0'); 1445956cc18dSsnj if (count) { 1446956cc18dSsnj result[count] = None; 1447956cc18dSsnj override = True; 1448956cc18dSsnj *resultp = result; 1449956cc18dSsnj } else { 1450956cc18dSsnj XtFree((char *) result); 1451956cc18dSsnj } 1452956cc18dSsnj } 14530bd37d32Smrg free(copied); 1454956cc18dSsnj } else { 1455956cc18dSsnj TRACE(("Couldn't allocate copy of selection types\n")); 1456d522f475Smrg } 1457956cc18dSsnj } 1458956cc18dSsnj } 1459956cc18dSsnj return override; 1460956cc18dSsnj} 1461956cc18dSsnj 1462956cc18dSsnj#if OPT_WIDE_CHARS 1463956cc18dSsnjstatic Atom * 1464e0a2b6dfSmrgallocUtf8Targets(Widget w, TScreen *screen) 1465956cc18dSsnj{ 1466956cc18dSsnj Atom **resultp = &(screen->selection_targets_utf8); 1467956cc18dSsnj 1468956cc18dSsnj if (*resultp == 0) { 1469956cc18dSsnj Atom *result; 1470956cc18dSsnj 1471956cc18dSsnj if (!overrideTargets(w, screen->utf8_select_types, &result)) { 1472a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1473956cc18dSsnj if (result == NULL) { 1474956cc18dSsnj TRACE(("Couldn't allocate utf-8 selection targets\n")); 1475956cc18dSsnj } else { 1476956cc18dSsnj int n = 0; 1477956cc18dSsnj 1478e39b573cSmrg if (XSupportsLocale()) { 1479e39b573cSmrg result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1480d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1481e39b573cSmrg if (screen->i18nSelections) { 1482e39b573cSmrg result[n++] = XA_TEXT(XtDisplay(w)); 1483e39b573cSmrg result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1484e39b573cSmrg } 1485d522f475Smrg#endif 1486e39b573cSmrg } 1487956cc18dSsnj result[n++] = XA_STRING; 1488956cc18dSsnj result[n] = None; 1489956cc18dSsnj } 1490d522f475Smrg } 1491956cc18dSsnj 1492956cc18dSsnj *resultp = result; 1493d522f475Smrg } 1494956cc18dSsnj 1495956cc18dSsnj return *resultp; 1496956cc18dSsnj} 1497d522f475Smrg#endif 1498d522f475Smrg 1499956cc18dSsnjstatic Atom * 1500e0a2b6dfSmrgalloc8bitTargets(Widget w, TScreen *screen) 1501956cc18dSsnj{ 1502956cc18dSsnj Atom **resultp = &(screen->selection_targets_8bit); 1503956cc18dSsnj 1504956cc18dSsnj if (*resultp == 0) { 1505956cc18dSsnj Atom *result = 0; 1506956cc18dSsnj 1507956cc18dSsnj if (!overrideTargets(w, screen->eightbit_select_types, &result)) { 1508a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1509956cc18dSsnj if (result == NULL) { 1510956cc18dSsnj TRACE(("Couldn't allocate 8bit selection targets\n")); 1511956cc18dSsnj } else { 1512956cc18dSsnj int n = 0; 1513956cc18dSsnj 1514e39b573cSmrg if (XSupportsLocale()) { 1515d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1516e39b573cSmrg result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1517956cc18dSsnj#endif 1518e39b573cSmrg if (screen->i18nSelections) { 1519e39b573cSmrg result[n++] = XA_TEXT(XtDisplay(w)); 1520e39b573cSmrg result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1521e39b573cSmrg } 1522956cc18dSsnj } 1523956cc18dSsnj result[n++] = XA_STRING; 1524956cc18dSsnj result[n] = None; 1525956cc18dSsnj } 1526956cc18dSsnj } 1527956cc18dSsnj 1528956cc18dSsnj *resultp = result; 1529956cc18dSsnj } 1530956cc18dSsnj 1531956cc18dSsnj return *resultp; 1532956cc18dSsnj} 1533956cc18dSsnj 1534956cc18dSsnjstatic Atom * 1535956cc18dSsnj_SelectionTargets(Widget w) 1536956cc18dSsnj{ 1537956cc18dSsnj Atom *result; 1538956cc18dSsnj XtermWidget xw; 1539956cc18dSsnj 1540956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) { 1541956cc18dSsnj result = NULL; 1542956cc18dSsnj } else { 15432e4f8982Smrg TScreen *screen = TScreenOf(xw); 1544956cc18dSsnj 1545956cc18dSsnj#if OPT_WIDE_CHARS 1546956cc18dSsnj if (screen->wide_chars) { 1547956cc18dSsnj result = allocUtf8Targets(w, screen); 1548956cc18dSsnj } else 1549d522f475Smrg#endif 1550956cc18dSsnj { 1551956cc18dSsnj /* not screen->wide_chars */ 1552956cc18dSsnj result = alloc8bitTargets(w, screen); 1553d522f475Smrg } 1554d522f475Smrg } 1555956cc18dSsnj 1556956cc18dSsnj return result; 1557d522f475Smrg} 1558d522f475Smrg 1559d522f475Smrg#define isSELECT(value) (!strcmp(value, "SELECT")) 1560d522f475Smrg 1561d522f475Smrgstatic void 1562d522f475SmrgUnmapSelections(XtermWidget xw) 1563d522f475Smrg{ 1564956cc18dSsnj TScreen *screen = TScreenOf(xw); 1565d522f475Smrg Cardinal n; 1566d522f475Smrg 1567d522f475Smrg if (screen->mappedSelect) { 1568d522f475Smrg for (n = 0; screen->mappedSelect[n] != 0; ++n) 156920d2c4d2Smrg free((void *) screen->mappedSelect[n]); 1570d522f475Smrg free(screen->mappedSelect); 1571d522f475Smrg screen->mappedSelect = 0; 1572d522f475Smrg } 1573d522f475Smrg} 1574d522f475Smrg 1575d522f475Smrg/* 1576d522f475Smrg * xterm generally uses the primary selection. Some applications prefer 1577d522f475Smrg * (or are limited to) the clipboard. Since the translations resource is 1578d522f475Smrg * complicated, users seldom change the way it affects selection. But it 1579d522f475Smrg * is simple to remap the choice between primary and clipboard before the 1580d522f475Smrg * call to XmuInternStrings(). 1581d522f475Smrg */ 1582d522f475Smrgstatic String * 1583e0a2b6dfSmrgMapSelections(XtermWidget xw, String *params, Cardinal num_params) 1584d522f475Smrg{ 1585d522f475Smrg String *result = params; 1586d522f475Smrg 1587913cc679Smrg if (params != 0 && num_params > 0) { 1588d522f475Smrg Cardinal j; 1589d522f475Smrg Boolean map = False; 1590d522f475Smrg 1591d522f475Smrg for (j = 0; j < num_params; ++j) { 1592d522f475Smrg TRACE(("param[%d]:%s\n", j, params[j])); 1593d522f475Smrg if (isSELECT(params[j])) { 1594d522f475Smrg map = True; 1595d522f475Smrg break; 1596d522f475Smrg } 1597d522f475Smrg } 1598d522f475Smrg if (map) { 1599956cc18dSsnj TScreen *screen = TScreenOf(xw); 1600956cc18dSsnj const char *mapTo = (screen->selectToClipboard 1601d522f475Smrg ? "CLIPBOARD" 1602d522f475Smrg : "PRIMARY"); 1603d522f475Smrg 1604d522f475Smrg UnmapSelections(xw); 1605d522f475Smrg if ((result = TypeMallocN(String, num_params + 1)) != 0) { 1606d522f475Smrg result[num_params] = 0; 1607d522f475Smrg for (j = 0; j < num_params; ++j) { 1608d522f475Smrg result[j] = x_strdup((isSELECT(params[j]) 1609d522f475Smrg ? mapTo 1610d522f475Smrg : params[j])); 1611d522f475Smrg if (result[j] == 0) { 1612d522f475Smrg UnmapSelections(xw); 16130bd37d32Smrg while (j != 0) { 16140bd37d32Smrg free((void *) result[--j]); 16150bd37d32Smrg } 16160bd37d32Smrg free(result); 1617d522f475Smrg result = 0; 1618d522f475Smrg break; 1619d522f475Smrg } 1620d522f475Smrg } 1621956cc18dSsnj screen->mappedSelect = result; 1622d522f475Smrg } 1623d522f475Smrg } 1624d522f475Smrg } 1625d522f475Smrg return result; 1626d522f475Smrg} 1627d522f475Smrg 1628d522f475Smrg/* 1629d522f475Smrg * Lookup the cut-buffer number, which will be in the range 0-7. 1630d522f475Smrg * If it is not a cut-buffer, it is the primary selection (-1). 1631d522f475Smrg */ 1632d522f475Smrgstatic int 163320d2c4d2SmrgCutBuffer(Atom code) 1634d522f475Smrg{ 1635d522f475Smrg int cutbuffer; 163620d2c4d2Smrg switch ((unsigned) code) { 1637d522f475Smrg case XA_CUT_BUFFER0: 1638d522f475Smrg cutbuffer = 0; 1639d522f475Smrg break; 1640d522f475Smrg case XA_CUT_BUFFER1: 1641d522f475Smrg cutbuffer = 1; 1642d522f475Smrg break; 1643d522f475Smrg case XA_CUT_BUFFER2: 1644d522f475Smrg cutbuffer = 2; 1645d522f475Smrg break; 1646d522f475Smrg case XA_CUT_BUFFER3: 1647d522f475Smrg cutbuffer = 3; 1648d522f475Smrg break; 1649d522f475Smrg case XA_CUT_BUFFER4: 1650d522f475Smrg cutbuffer = 4; 1651d522f475Smrg break; 1652d522f475Smrg case XA_CUT_BUFFER5: 1653d522f475Smrg cutbuffer = 5; 1654d522f475Smrg break; 1655d522f475Smrg case XA_CUT_BUFFER6: 1656d522f475Smrg cutbuffer = 6; 1657d522f475Smrg break; 1658d522f475Smrg case XA_CUT_BUFFER7: 1659d522f475Smrg cutbuffer = 7; 1660d522f475Smrg break; 1661d522f475Smrg default: 1662d522f475Smrg cutbuffer = -1; 1663d522f475Smrg break; 1664d522f475Smrg } 16650bd37d32Smrg TRACE(("CutBuffer(%d) = %d\n", (int) code, cutbuffer)); 1666d522f475Smrg return cutbuffer; 1667d522f475Smrg} 1668d522f475Smrg 1669d522f475Smrg#if OPT_PASTE64 1670d522f475Smrgstatic void 1671d522f475SmrgFinishPaste64(XtermWidget xw) 1672d522f475Smrg{ 1673956cc18dSsnj TScreen *screen = TScreenOf(xw); 1674956cc18dSsnj 1675956cc18dSsnj TRACE(("FinishPaste64(%d)\n", screen->base64_paste)); 1676956cc18dSsnj if (screen->base64_paste) { 1677956cc18dSsnj screen->base64_paste = 0; 1678956cc18dSsnj unparseputc1(xw, screen->base64_final); 1679d522f475Smrg unparse_end(xw); 1680d522f475Smrg } 1681d522f475Smrg} 1682d522f475Smrg#endif 1683d522f475Smrg 1684d522f475Smrg#if !OPT_PASTE64 1685d522f475Smrgstatic 1686d522f475Smrg#endif 1687d522f475Smrgvoid 1688d522f475SmrgxtermGetSelection(Widget w, 1689d522f475Smrg Time ev_time, 1690e0a2b6dfSmrg String *params, /* selections in precedence order */ 1691d522f475Smrg Cardinal num_params, 1692894e0ac8Smrg Atom *targets) 1693d522f475Smrg{ 1694d522f475Smrg Atom selection; 1695d522f475Smrg int cutbuffer; 1696d522f475Smrg Atom target; 1697d522f475Smrg 1698956cc18dSsnj XtermWidget xw; 1699956cc18dSsnj 170020d2c4d2Smrg if (num_params == 0) 170120d2c4d2Smrg return; 1702956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 1703d522f475Smrg return; 1704d522f475Smrg 1705e0a2b6dfSmrg TRACE(("xtermGetSelection num_params %d @%ld\n", num_params, ev_time)); 1706956cc18dSsnj params = MapSelections(xw, params, num_params); 1707d522f475Smrg 1708d522f475Smrg XmuInternStrings(XtDisplay(w), params, (Cardinal) 1, &selection); 1709d522f475Smrg cutbuffer = CutBuffer(selection); 1710d522f475Smrg 1711956cc18dSsnj TRACE(("Cutbuffer: %d, target: %s\n", cutbuffer, 1712956cc18dSsnj (targets 1713956cc18dSsnj ? visibleSelectionTarget(XtDisplay(w), targets[0]) 1714956cc18dSsnj : "None"))); 1715d522f475Smrg 1716d522f475Smrg if (cutbuffer >= 0) { 1717d522f475Smrg int inbytes; 1718d522f475Smrg unsigned long nbytes; 1719d522f475Smrg int fmt8 = 8; 1720d522f475Smrg Atom type = XA_STRING; 1721d522f475Smrg char *line; 1722d522f475Smrg 1723d522f475Smrg /* 'line' is freed in SelectionReceived */ 1724d522f475Smrg line = XFetchBuffer(XtDisplay(w), &inbytes, cutbuffer); 1725d522f475Smrg nbytes = (unsigned long) inbytes; 1726d522f475Smrg 17270bd37d32Smrg if (nbytes > 0) { 1728d522f475Smrg SelectionReceived(w, NULL, &selection, &type, (XtPointer) line, 1729d522f475Smrg &nbytes, &fmt8); 17300bd37d32Smrg } else if (num_params > 1) { 1731d522f475Smrg xtermGetSelection(w, ev_time, params + 1, num_params - 1, NULL); 1732d522f475Smrg } 1733d522f475Smrg#if OPT_PASTE64 1734d522f475Smrg else { 1735956cc18dSsnj FinishPaste64(xw); 1736d522f475Smrg } 1737d522f475Smrg#endif 1738d522f475Smrg } else { 1739d522f475Smrg 1740d522f475Smrg if (targets == NULL || targets[0] == None) { 1741d522f475Smrg targets = _SelectionTargets(w); 1742d522f475Smrg } 1743d522f475Smrg 1744d522f475Smrg if (targets != 0) { 17452e4f8982Smrg struct _SelectionList *list; 17462e4f8982Smrg 1747d522f475Smrg target = targets[0]; 1748d522f475Smrg 1749d522f475Smrg if (targets[1] == None) { /* last target in list */ 1750d522f475Smrg params++; 1751d522f475Smrg num_params--; 1752d522f475Smrg targets = _SelectionTargets(w); 1753d522f475Smrg } else { 1754d522f475Smrg targets = &(targets[1]); 1755d522f475Smrg } 1756d522f475Smrg 1757d522f475Smrg if (num_params) { 1758d522f475Smrg /* 'list' is freed in SelectionReceived */ 1759a1f3da82Smrg list = TypeXtMalloc(struct _SelectionList); 1760d522f475Smrg if (list != 0) { 1761d522f475Smrg list->params = params; 1762d522f475Smrg list->count = num_params; 1763d522f475Smrg list->targets = targets; 1764d522f475Smrg list->time = ev_time; 1765d522f475Smrg } 1766d522f475Smrg } else { 1767d522f475Smrg list = NULL; 1768d522f475Smrg } 1769d522f475Smrg 1770d522f475Smrg XtGetSelectionValue(w, selection, 1771d522f475Smrg target, 1772d522f475Smrg SelectionReceived, 1773d522f475Smrg (XtPointer) list, ev_time); 1774d522f475Smrg } 1775d522f475Smrg } 1776d522f475Smrg} 1777d522f475Smrg 1778d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 1779d522f475Smrgstatic void 1780e0a2b6dfSmrgGettingSelection(Display *dpy, Atom type, Char *line, unsigned long len) 1781d522f475Smrg{ 1782d522f475Smrg Char *cp; 1783913cc679Smrg const char *name = TraceAtomName(dpy, type); 1784d522f475Smrg 178501037d57Smrg TRACE(("Getting %s (type=%ld, length=%ld)\n", name, (long int) type, len)); 1786d522f475Smrg for (cp = line; cp < line + len; cp++) { 1787956cc18dSsnj TRACE(("[%d:%lu]", (int) (cp + 1 - line), len)); 1788d522f475Smrg if (isprint(*cp)) { 1789d522f475Smrg TRACE(("%c\n", *cp)); 1790d522f475Smrg } else { 1791d522f475Smrg TRACE(("\\x%02x\n", *cp)); 1792d522f475Smrg } 1793d522f475Smrg } 1794d522f475Smrg} 1795d522f475Smrg#else 1796d522f475Smrg#define GettingSelection(dpy,type,line,len) /* nothing */ 1797d522f475Smrg#endif 1798d522f475Smrg 1799d522f475Smrg#ifdef VMS 1800d522f475Smrg# define tty_vwrite(pty,lag,l) tt_write(lag,l) 1801d522f475Smrg#else /* !( VMS ) */ 1802d522f475Smrg# define tty_vwrite(pty,lag,l) v_write(pty,lag,l) 1803d522f475Smrg#endif /* defined VMS */ 1804d522f475Smrg 1805d522f475Smrg#if OPT_PASTE64 1806d522f475Smrg/* Return base64 code character given 6-bit number */ 1807d522f475Smrgstatic const char base64_code[] = "\ 1808d522f475SmrgABCDEFGHIJKLMNOPQRSTUVWXYZ\ 1809d522f475Smrgabcdefghijklmnopqrstuvwxyz\ 1810d522f475Smrg0123456789+/"; 1811d522f475Smrgstatic void 1812e0a2b6dfSmrgbase64_flush(TScreen *screen) 1813d522f475Smrg{ 1814d522f475Smrg Char x; 181501037d57Smrg 181601037d57Smrg TRACE(("base64_flush count %d, pad %d (%d)\n", 181701037d57Smrg screen->base64_count, 181801037d57Smrg screen->base64_pad, 181901037d57Smrg screen->base64_pad & 3)); 182001037d57Smrg 1821d522f475Smrg switch (screen->base64_count) { 1822d522f475Smrg case 0: 1823d522f475Smrg break; 1824d522f475Smrg case 2: 18252eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 4]); 1826d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1827d522f475Smrg break; 1828d522f475Smrg case 4: 18292eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 2]); 1830d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1831d522f475Smrg break; 1832d522f475Smrg } 183301037d57Smrg if (screen->base64_pad & 3) { 1834d522f475Smrg tty_vwrite(screen->respond, 1835492d43a5Smrg (const Char *) "===", 183601037d57Smrg (unsigned) (3 - (screen->base64_pad & 3))); 183701037d57Smrg } 1838d522f475Smrg screen->base64_count = 0; 1839d522f475Smrg screen->base64_accu = 0; 1840d522f475Smrg screen->base64_pad = 0; 1841d522f475Smrg} 1842d522f475Smrg#endif /* OPT_PASTE64 */ 1843d522f475Smrg 1844e0a2b6dfSmrg/* 1845e0a2b6dfSmrg * Translate ISO-8859-1 or UTF-8 data to NRCS. 1846e0a2b6dfSmrg */ 1847d522f475Smrgstatic void 1848e0a2b6dfSmrgToNational(TScreen *screen, Char *buffer, unsigned *length) 1849e0a2b6dfSmrg{ 1850e0a2b6dfSmrg int gsetL = screen->gsets[screen->curgl]; 1851e0a2b6dfSmrg int gsetR = screen->gsets[screen->curgr]; 1852e0a2b6dfSmrg 1853e0a2b6dfSmrg#if OPT_WIDE_CHARS 1854e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 18552e4f8982Smrg Char *p; 1856e0a2b6dfSmrg PtyData *data = TypeXtMallocX(PtyData, *length); 1857e0a2b6dfSmrg 1858e0a2b6dfSmrg memset(data, 0, sizeof(*data)); 1859e0a2b6dfSmrg data->next = data->buffer; 1860e0a2b6dfSmrg data->last = data->buffer + *length; 1861e0a2b6dfSmrg memcpy(data->buffer, buffer, (size_t) *length); 1862e0a2b6dfSmrg p = buffer; 1863e0a2b6dfSmrg while (data->next < data->last) { 18642e4f8982Smrg unsigned chr, out, gl, gr; 18652e4f8982Smrg 1866894e0ac8Smrg if (!decodeUtf8(screen, data)) { 1867e0a2b6dfSmrg data->utf_size = 1; 1868e0a2b6dfSmrg data->utf_data = data->next[0]; 1869e0a2b6dfSmrg } 1870e0a2b6dfSmrg data->next += data->utf_size; 1871e0a2b6dfSmrg chr = data->utf_data; 1872e0a2b6dfSmrg out = chr; 1873e0a2b6dfSmrg if ((gl = xtermCharSetIn(screen, chr, gsetL)) != chr) { 1874e0a2b6dfSmrg out = gl; 1875e0a2b6dfSmrg } else if ((gr = xtermCharSetIn(screen, chr, gsetR)) != chr) { 1876e0a2b6dfSmrg out = gr; 1877e0a2b6dfSmrg } 1878e0a2b6dfSmrg *p++ = (Char) ((out < 256) ? out : ' '); 1879e0a2b6dfSmrg } 1880e0a2b6dfSmrg *length = (unsigned) (p - buffer); 1881e0a2b6dfSmrg free(data); 1882e0a2b6dfSmrg } else 1883e0a2b6dfSmrg#endif 1884e0a2b6dfSmrg { 18852e4f8982Smrg Char *p; 18862e4f8982Smrg 1887e0a2b6dfSmrg for (p = buffer; (int) (p - buffer) < (int) *length; ++p) { 18882e4f8982Smrg unsigned gl, gr; 18892e4f8982Smrg unsigned chr = *p; 18902e4f8982Smrg unsigned out = chr; 1891e0a2b6dfSmrg if ((gl = xtermCharSetIn(screen, chr, gsetL)) != chr) { 1892e0a2b6dfSmrg out = gl; 1893e0a2b6dfSmrg } else if ((gr = xtermCharSetIn(screen, chr, gsetR)) != chr) { 1894e0a2b6dfSmrg out = gr; 1895e0a2b6dfSmrg } 1896e0a2b6dfSmrg *p = (Char) out; 1897e0a2b6dfSmrg } 1898e0a2b6dfSmrg } 1899e0a2b6dfSmrg} 1900e0a2b6dfSmrg 1901e0a2b6dfSmrgstatic void 1902e0a2b6dfSmrg_qWriteSelectionData(XtermWidget xw, Char *lag, unsigned length) 1903d522f475Smrg{ 19040bd37d32Smrg TScreen *screen = TScreenOf(xw); 19050bd37d32Smrg 1906e0a2b6dfSmrg /* 1907e0a2b6dfSmrg * If we are pasting into a window which is using NRCS, we want to map 1908e0a2b6dfSmrg * the text from the normal encoding (ISO-8859-1 or UTF-8) into the coding 1909e0a2b6dfSmrg * that an application would use to write characters with NRCS. 1910e0a2b6dfSmrg * 1911e0a2b6dfSmrg * TODO: handle conversion from UTF-8, and adjust length. This can be done 1912e0a2b6dfSmrg * in the same buffer because the target is always 8-bit. 1913e0a2b6dfSmrg */ 1914e0a2b6dfSmrg if ((xw->flags & NATIONAL) && (length != 0)) { 1915e0a2b6dfSmrg ToNational(screen, lag, &length); 1916e0a2b6dfSmrg } 1917d522f475Smrg#if OPT_PASTE64 1918d522f475Smrg if (screen->base64_paste) { 1919d522f475Smrg /* Send data as base64 */ 1920d522f475Smrg Char *p = lag; 1921d522f475Smrg Char buf[64]; 1922d522f475Smrg unsigned x = 0; 19230bd37d32Smrg 192401037d57Smrg TRACE(("convert to base64 %d:%s\n", length, visibleChars(p, length))); 192501037d57Smrg 19260bd37d32Smrg /* 19270bd37d32Smrg * Handle the case where the selection is from _this_ xterm, which 19280bd37d32Smrg * puts part of the reply in the buffer before the selection callback 19290bd37d32Smrg * happens. 19300bd37d32Smrg */ 19310bd37d32Smrg if (screen->base64_paste && screen->unparse_len) { 19320bd37d32Smrg unparse_end(xw); 19330bd37d32Smrg } 1934d522f475Smrg while (length--) { 1935d522f475Smrg switch (screen->base64_count) { 1936d522f475Smrg case 0: 19372eaa94a1Schristos buf[x++] = CharOf(base64_code[*p >> 2]); 19382eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0x3); 1939d522f475Smrg screen->base64_count = 2; 1940d522f475Smrg ++p; 1941d522f475Smrg break; 1942d522f475Smrg case 2: 19432eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 4) + 19442eaa94a1Schristos (*p >> 4)]); 19452eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0xF); 1946d522f475Smrg screen->base64_count = 4; 1947d522f475Smrg ++p; 1948d522f475Smrg break; 1949d522f475Smrg case 4: 19502eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 2) + 19512eaa94a1Schristos (*p >> 6)]); 19522eaa94a1Schristos buf[x++] = CharOf(base64_code[*p & 0x3F]); 1953d522f475Smrg screen->base64_accu = 0; 1954d522f475Smrg screen->base64_count = 0; 1955d522f475Smrg ++p; 1956d522f475Smrg break; 1957d522f475Smrg } 1958d522f475Smrg if (x >= 63) { 1959d522f475Smrg /* Write 63 or 64 characters */ 1960d522f475Smrg screen->base64_pad += x; 196101037d57Smrg TRACE(("writing base64 interim %s\n", visibleChars(buf, x))); 1962d522f475Smrg tty_vwrite(screen->respond, buf, x); 1963d522f475Smrg x = 0; 1964d522f475Smrg } 1965d522f475Smrg } 1966d522f475Smrg if (x != 0) { 1967d522f475Smrg screen->base64_pad += x; 196801037d57Smrg TRACE(("writing base64 finish %s\n", visibleChars(buf, x))); 1969d522f475Smrg tty_vwrite(screen->respond, buf, x); 1970d522f475Smrg } 1971d522f475Smrg } else 1972d522f475Smrg#endif /* OPT_PASTE64 */ 1973d522f475Smrg#if OPT_READLINE 1974d522f475Smrg if (SCREEN_FLAG(screen, paste_quotes)) { 1975d522f475Smrg while (length--) { 1976492d43a5Smrg tty_vwrite(screen->respond, (const Char *) "\026", 1); /* Control-V */ 1977d522f475Smrg tty_vwrite(screen->respond, lag++, 1); 1978d522f475Smrg } 1979d522f475Smrg } else 1980d522f475Smrg#endif 198101037d57Smrg { 198201037d57Smrg TRACE(("writing base64 padding %s\n", visibleChars(lag, length))); 1983d522f475Smrg tty_vwrite(screen->respond, lag, length); 198401037d57Smrg } 1985d522f475Smrg} 1986d522f475Smrg 1987d522f475Smrgstatic void 1988e0a2b6dfSmrg_WriteSelectionData(XtermWidget xw, Char *line, size_t length) 1989d522f475Smrg{ 1990d522f475Smrg /* Write data to pty a line at a time. */ 1991d522f475Smrg /* Doing this one line at a time may no longer be necessary 1992d522f475Smrg because v_write has been re-written. */ 1993d522f475Smrg 19942e4f8982Smrg#if OPT_PASTE64 19950bd37d32Smrg TScreen *screen = TScreenOf(xw); 19962e4f8982Smrg#endif 1997d522f475Smrg Char *lag, *end; 1998d522f475Smrg 1999d522f475Smrg /* in the VMS version, if tt_pasting isn't set to True then qio 2000d522f475Smrg reads aren't blocked and an infinite loop is entered, where the 2001d522f475Smrg pasted text shows up as new input, goes in again, shows up 2002d522f475Smrg again, ad nauseum. */ 2003d522f475Smrg#ifdef VMS 2004d522f475Smrg tt_pasting = True; 2005d522f475Smrg#endif 2006d522f475Smrg 2007d522f475Smrg end = &line[length]; 2008d522f475Smrg lag = line; 2009d522f475Smrg 2010d522f475Smrg#if OPT_PASTE64 2011d522f475Smrg if (screen->base64_paste) { 20120bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (end - lag)); 2013d522f475Smrg base64_flush(screen); 2014d522f475Smrg } else 2015d522f475Smrg#endif 2016d522f475Smrg { 2017d522f475Smrg if (!SCREEN_FLAG(screen, paste_literal_nl)) { 2018d522f475Smrg Char *cp; 2019d522f475Smrg for (cp = line; cp != end; cp++) { 2020d522f475Smrg if (*cp == '\n') { 2021d522f475Smrg *cp = '\r'; 20220bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (cp - lag + 1)); 2023d522f475Smrg lag = cp + 1; 2024d522f475Smrg } 2025d522f475Smrg } 2026d522f475Smrg } 2027d522f475Smrg 2028d522f475Smrg if (lag != end) { 20290bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (end - lag)); 2030d522f475Smrg } 2031d522f475Smrg } 2032d522f475Smrg#ifdef VMS 2033d522f475Smrg tt_pasting = False; 2034d522f475Smrg tt_start_read(); /* reenable reads or a character may be lost */ 2035d522f475Smrg#endif 2036d522f475Smrg} 2037d522f475Smrg 2038d522f475Smrg#if OPT_READLINE 2039d522f475Smrgstatic void 2040e0a2b6dfSmrg_WriteKey(TScreen *screen, const Char *in) 2041d522f475Smrg{ 2042d522f475Smrg Char line[16]; 2043d522f475Smrg unsigned count = 0; 2044492d43a5Smrg size_t length = strlen((const char *) in); 2045d522f475Smrg 2046d522f475Smrg if (screen->control_eight_bits) { 2047d522f475Smrg line[count++] = ANSI_CSI; 2048d522f475Smrg } else { 2049d522f475Smrg line[count++] = ANSI_ESC; 2050d522f475Smrg line[count++] = '['; 2051d522f475Smrg } 2052d522f475Smrg while (length--) 2053d522f475Smrg line[count++] = *in++; 2054d522f475Smrg line[count++] = '~'; 2055d522f475Smrg tty_vwrite(screen->respond, line, count); 2056d522f475Smrg} 2057d522f475Smrg#endif /* OPT_READLINE */ 2058d522f475Smrg 20590bd37d32Smrg/* 20600bd37d32Smrg * Unless enabled by the user, strip control characters other than formatting. 20610bd37d32Smrg */ 20620bd37d32Smrgstatic size_t 20630bd37d32SmrgremoveControls(XtermWidget xw, char *value) 20640bd37d32Smrg{ 20650bd37d32Smrg TScreen *screen = TScreenOf(xw); 20660bd37d32Smrg size_t dst = 0; 20670bd37d32Smrg 20680bd37d32Smrg if (screen->allowPasteControls) { 20690bd37d32Smrg dst = strlen(value); 20700bd37d32Smrg } else { 20712e4f8982Smrg size_t src = 0; 20720bd37d32Smrg while ((value[dst] = value[src]) != '\0') { 20730bd37d32Smrg int ch = CharOf(value[src++]); 20740bd37d32Smrg if (ch < 32) { 20750bd37d32Smrg switch (ch) { 20760bd37d32Smrg case '\b': 20770bd37d32Smrg case '\t': 20780bd37d32Smrg case '\n': 20790bd37d32Smrg case '\r': 20800bd37d32Smrg ++dst; 20810bd37d32Smrg break; 20820bd37d32Smrg default: 20830bd37d32Smrg continue; 20840bd37d32Smrg } 20850bd37d32Smrg } 20860bd37d32Smrg#if OPT_WIDE_CHARS 2087e0a2b6dfSmrg else if (screen->utf8_inparse || screen->utf8_nrc_mode) 20880bd37d32Smrg ++dst; 20890bd37d32Smrg#endif 20900bd37d32Smrg#if OPT_C1_PRINT || OPT_WIDE_CHARS 20910bd37d32Smrg else if (screen->c1_printable) 20920bd37d32Smrg ++dst; 20930bd37d32Smrg#endif 20940bd37d32Smrg else if (ch >= 128 && ch < 160) 20950bd37d32Smrg continue; 20960bd37d32Smrg else 20970bd37d32Smrg ++dst; 20980bd37d32Smrg } 20990bd37d32Smrg } 21000bd37d32Smrg return dst; 21010bd37d32Smrg} 21020bd37d32Smrg 2103d522f475Smrg/* SelectionReceived: stuff received selection text into pty */ 2104d522f475Smrg 2105d522f475Smrg/* ARGSUSED */ 2106d522f475Smrgstatic void 2107d522f475SmrgSelectionReceived(Widget w, 2108d522f475Smrg XtPointer client_data, 2109894e0ac8Smrg Atom *selection GCC_UNUSED, 2110894e0ac8Smrg Atom *type, 2111d522f475Smrg XtPointer value, 2112d522f475Smrg unsigned long *length, 2113d522f475Smrg int *format) 2114d522f475Smrg{ 2115d522f475Smrg char **text_list = NULL; 21162e4f8982Smrg int text_list_count = 0; 2117d522f475Smrg XTextProperty text_prop; 2118d522f475Smrg TScreen *screen; 2119d522f475Smrg Display *dpy; 2120d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 2121d522f475Smrg Char *line = (Char *) value; 2122d522f475Smrg#endif 2123d522f475Smrg 2124956cc18dSsnj XtermWidget xw; 2125956cc18dSsnj 2126956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 2127d522f475Smrg return; 2128956cc18dSsnj 2129956cc18dSsnj screen = TScreenOf(xw); 2130d522f475Smrg dpy = XtDisplay(w); 2131d522f475Smrg 2132d522f475Smrg if (*type == 0 /*XT_CONVERT_FAIL */ 2133d522f475Smrg || *length == 0 213401037d57Smrg || value == NULL) { 213501037d57Smrg TRACE(("...no data to convert\n")); 2136d522f475Smrg goto fail; 213701037d57Smrg } 2138d522f475Smrg 2139d522f475Smrg text_prop.value = (unsigned char *) value; 2140d522f475Smrg text_prop.encoding = *type; 2141d522f475Smrg text_prop.format = *format; 2142d522f475Smrg text_prop.nitems = *length; 2143d522f475Smrg 214401037d57Smrg TRACE(("SelectionReceived %s %s format %d, nitems %ld\n", 2145913cc679Smrg TraceAtomName(screen->display, *selection), 2146956cc18dSsnj visibleSelectionTarget(dpy, text_prop.encoding), 2147956cc18dSsnj text_prop.format, 2148956cc18dSsnj text_prop.nitems)); 2149956cc18dSsnj 2150d522f475Smrg#if OPT_WIDE_CHARS 2151e39b573cSmrg if (XSupportsLocale() && screen->wide_chars) { 2152d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2153d522f475Smrg *type == XA_STRING || 2154d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2155d522f475Smrg GettingSelection(dpy, *type, line, *length); 2156d522f475Smrg if (Xutf8TextPropertyToTextList(dpy, &text_prop, 2157d522f475Smrg &text_list, 2158d522f475Smrg &text_list_count) < 0) { 2159e39b573cSmrg TRACE(("default Xutf8 Conversion failed\n")); 2160d522f475Smrg text_list = NULL; 2161d522f475Smrg } 2162d522f475Smrg } 2163d522f475Smrg } else 2164d522f475Smrg#endif /* OPT_WIDE_CHARS */ 2165d522f475Smrg { 2166d522f475Smrg /* Convert the selection to locale's multibyte encoding. */ 2167d522f475Smrg 2168d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2169d522f475Smrg *type == XA_STRING || 2170d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2171d522f475Smrg Status rc; 2172d522f475Smrg 2173d522f475Smrg GettingSelection(dpy, *type, line, *length); 2174d522f475Smrg 2175d522f475Smrg#if OPT_WIDE_CHARS 2176d522f475Smrg if (*type == XA_UTF8_STRING(dpy) && 2177d522f475Smrg !(screen->wide_chars || screen->c1_printable)) { 217820d2c4d2Smrg rc = xtermUtf8ToTextList(xw, &text_prop, 217920d2c4d2Smrg &text_list, &text_list_count); 2180d522f475Smrg } else 2181d522f475Smrg#endif 2182e39b573cSmrg if (*type == XA_STRING && (!XSupportsLocale() || screen->brokenSelections)) { 2183d522f475Smrg rc = XTextPropertyToStringList(&text_prop, 2184d522f475Smrg &text_list, &text_list_count); 2185d522f475Smrg } else { 2186d522f475Smrg rc = XmbTextPropertyToTextList(dpy, &text_prop, 2187d522f475Smrg &text_list, 2188d522f475Smrg &text_list_count); 2189d522f475Smrg } 2190d522f475Smrg if (rc < 0) { 2191d522f475Smrg TRACE(("Conversion failed\n")); 2192d522f475Smrg text_list = NULL; 2193d522f475Smrg } 2194d522f475Smrg } 2195d522f475Smrg } 2196d522f475Smrg 2197d522f475Smrg if (text_list != NULL && text_list_count != 0) { 2198d522f475Smrg int i; 2199d522f475Smrg 2200d522f475Smrg#if OPT_PASTE64 2201d522f475Smrg if (screen->base64_paste) { 2202a1f3da82Smrg /* EMPTY */ ; 2203d522f475Smrg } else 2204d522f475Smrg#endif 2205d522f475Smrg#if OPT_READLINE 2206d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 2207492d43a5Smrg _WriteKey(screen, (const Char *) "200"); 2208d522f475Smrg } 2209d522f475Smrg#endif 2210d522f475Smrg for (i = 0; i < text_list_count; i++) { 22110bd37d32Smrg size_t len = removeControls(xw, text_list[i]); 221201037d57Smrg 22130bd37d32Smrg if (screen->selectToBuffer) { 221401037d57Smrg InternalSelect *mydata = &(screen->internal_select); 221501037d57Smrg size_t have = (mydata->buffer 221601037d57Smrg ? strlen(mydata->buffer) 22170bd37d32Smrg : 0); 22180bd37d32Smrg size_t need = have + len + 1; 221901037d57Smrg char *buffer = realloc(mydata->buffer, need); 222001037d57Smrg 222101037d57Smrg screen->selectToBuffer = False; 222201037d57Smrg#if OPT_PASTE64 222301037d57Smrg screen->base64_paste = mydata->base64_paste; 222401037d57Smrg#endif 222501037d57Smrg#if OPT_READLINE 222601037d57Smrg screen->paste_brackets = mydata->paste_brackets; 222701037d57Smrg#endif 22280bd37d32Smrg if (buffer != 0) { 22290bd37d32Smrg strcpy(buffer + have, text_list[i]); 223001037d57Smrg mydata->buffer = buffer; 22310bd37d32Smrg } 223201037d57Smrg TRACE(("FormatSelect %d.%d .. %d.%d %s\n", 223301037d57Smrg screen->startSel.row, 223401037d57Smrg screen->startSel.col, 223501037d57Smrg screen->endSel.row, 223601037d57Smrg screen->endSel.col, 223701037d57Smrg mydata->buffer)); 223801037d57Smrg mydata->format_select(w, mydata->format, mydata->buffer, 223901037d57Smrg &(screen->startSel), 224001037d57Smrg &(screen->endSel)); 224101037d57Smrg 224201037d57Smrg free(mydata->format); 224301037d57Smrg free(mydata->buffer); 224401037d57Smrg memset(mydata, 0, sizeof(*mydata)); 22450bd37d32Smrg } else { 22460bd37d32Smrg _WriteSelectionData(xw, (Char *) text_list[i], len); 22470bd37d32Smrg } 2248d522f475Smrg } 2249d522f475Smrg#if OPT_PASTE64 2250d522f475Smrg if (screen->base64_paste) { 2251956cc18dSsnj FinishPaste64(xw); 2252d522f475Smrg } else 2253d522f475Smrg#endif 2254d522f475Smrg#if OPT_READLINE 2255d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 2256492d43a5Smrg _WriteKey(screen, (const Char *) "201"); 2257d522f475Smrg } 2258d522f475Smrg#endif 2259d522f475Smrg XFreeStringList(text_list); 226001037d57Smrg } else { 226101037d57Smrg TRACE(("...empty text-list\n")); 2262d522f475Smrg goto fail; 226301037d57Smrg } 2264d522f475Smrg 2265d522f475Smrg XtFree((char *) client_data); 2266d522f475Smrg XtFree((char *) value); 2267d522f475Smrg 2268d522f475Smrg return; 2269d522f475Smrg 2270d522f475Smrg fail: 2271d522f475Smrg if (client_data != 0) { 2272d522f475Smrg struct _SelectionList *list = (struct _SelectionList *) client_data; 2273956cc18dSsnj 2274956cc18dSsnj TRACE(("SelectionReceived ->xtermGetSelection\n")); 2275d522f475Smrg xtermGetSelection(w, list->time, 2276d522f475Smrg list->params, list->count, list->targets); 2277d522f475Smrg XtFree((char *) client_data); 2278d522f475Smrg#if OPT_PASTE64 2279d522f475Smrg } else { 2280956cc18dSsnj FinishPaste64(xw); 2281d522f475Smrg#endif 2282d522f475Smrg } 2283d522f475Smrg return; 2284d522f475Smrg} 2285d522f475Smrg 2286d522f475Smrgvoid 2287d522f475SmrgHandleInsertSelection(Widget w, 2288894e0ac8Smrg XEvent *event, /* assumed to be XButtonEvent* */ 2289e0a2b6dfSmrg String *params, /* selections in precedence order */ 2290d522f475Smrg Cardinal *num_params) 2291d522f475Smrg{ 2292956cc18dSsnj XtermWidget xw; 2293d522f475Smrg 2294956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 22950bd37d32Smrg TRACE(("HandleInsertSelection\n")); 2296d522f475Smrg if (!SendMousePosition(xw, event)) { 2297d522f475Smrg#if OPT_READLINE 2298d522f475Smrg int ldelta; 2299956cc18dSsnj TScreen *screen = TScreenOf(xw); 2300492d43a5Smrg if (IsBtnEvent(event) 2301d522f475Smrg /* Disable on Shift-mouse, including the application-mouse modes */ 2302492d43a5Smrg && !(KeyModifiers(event) & ShiftMask) 2303913cc679Smrg && (okSendMousePos(xw) == MOUSE_OFF) 2304d522f475Smrg && SCREEN_FLAG(screen, paste_moves) 2305d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta)) 2306d522f475Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta); 2307d522f475Smrg#endif /* OPT_READLINE */ 2308d522f475Smrg 2309d522f475Smrg xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL); 2310d522f475Smrg } 2311d522f475Smrg } 2312d522f475Smrg} 2313d522f475Smrg 2314d522f475Smrgstatic SelectUnit 2315956cc18dSsnjEvalSelectUnit(XtermWidget xw, 2316d522f475Smrg Time buttonDownTime, 2317d522f475Smrg SelectUnit defaultUnit, 2318d522f475Smrg unsigned int button) 2319d522f475Smrg{ 2320956cc18dSsnj TScreen *screen = TScreenOf(xw); 2321d522f475Smrg SelectUnit result; 2322d522f475Smrg int delta; 2323d522f475Smrg 2324d522f475Smrg if (button != screen->lastButton) { 232520d2c4d2Smrg delta = screen->multiClickTime + 1; 2326d522f475Smrg } else if (screen->lastButtonUpTime == (Time) 0) { 2327d522f475Smrg /* first time and once in a blue moon */ 2328d522f475Smrg delta = screen->multiClickTime + 1; 2329d522f475Smrg } else if (buttonDownTime > screen->lastButtonUpTime) { 2330d522f475Smrg /* most of the time */ 23312eaa94a1Schristos delta = (int) (buttonDownTime - screen->lastButtonUpTime); 2332d522f475Smrg } else { 2333d522f475Smrg /* time has rolled over since lastButtonUpTime */ 23342eaa94a1Schristos delta = (int) ((((Time) ~ 0) - screen->lastButtonUpTime) + buttonDownTime); 2335d522f475Smrg } 2336d522f475Smrg 2337d522f475Smrg if (delta > screen->multiClickTime) { 2338d522f475Smrg screen->numberOfClicks = 1; 2339d522f475Smrg result = defaultUnit; 2340d522f475Smrg } else { 2341d522f475Smrg result = screen->selectMap[screen->numberOfClicks % screen->maxClicks]; 2342d522f475Smrg screen->numberOfClicks += 1; 2343d522f475Smrg } 2344d522f475Smrg TRACE(("EvalSelectUnit(%d) = %d\n", screen->numberOfClicks, result)); 2345d522f475Smrg return result; 2346d522f475Smrg} 2347d522f475Smrg 2348d522f475Smrgstatic void 2349d522f475Smrgdo_select_start(XtermWidget xw, 2350894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2351e0a2b6dfSmrg CELL *cell) 2352d522f475Smrg{ 2353956cc18dSsnj TScreen *screen = TScreenOf(xw); 2354d522f475Smrg 2355d522f475Smrg if (SendMousePosition(xw, event)) 2356d522f475Smrg return; 2357956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2358d522f475Smrg event->xbutton.time, 2359d522f475Smrg Select_CHAR, 2360d522f475Smrg event->xbutton.button); 2361d522f475Smrg screen->replyToEmacs = False; 2362d522f475Smrg 2363d522f475Smrg#if OPT_READLINE 2364d522f475Smrg lastButtonDownTime = event->xbutton.time; 2365d522f475Smrg#endif 2366d522f475Smrg 2367d522f475Smrg StartSelect(xw, cell); 2368d522f475Smrg} 2369d522f475Smrg 2370d522f475Smrg/* ARGSUSED */ 2371d522f475Smrgvoid 2372d522f475SmrgHandleSelectStart(Widget w, 2373894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2374e0a2b6dfSmrg String *params GCC_UNUSED, 2375d522f475Smrg Cardinal *num_params GCC_UNUSED) 2376d522f475Smrg{ 2377956cc18dSsnj XtermWidget xw; 2378956cc18dSsnj 2379956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2380956cc18dSsnj TScreen *screen = TScreenOf(xw); 2381d522f475Smrg CELL cell; 2382d522f475Smrg 23830bd37d32Smrg TRACE(("HandleSelectStart\n")); 2384d522f475Smrg screen->firstValidRow = 0; 2385d522f475Smrg screen->lastValidRow = screen->max_row; 2386d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2387d522f475Smrg 2388d522f475Smrg#if OPT_READLINE 2389d522f475Smrg ExtendingSelection = 0; 2390d522f475Smrg#endif 2391d522f475Smrg 2392d522f475Smrg do_select_start(xw, event, &cell); 2393d522f475Smrg } 2394d522f475Smrg} 2395d522f475Smrg 2396d522f475Smrg/* ARGSUSED */ 2397d522f475Smrgvoid 2398d522f475SmrgHandleKeyboardSelectStart(Widget w, 2399894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2400e0a2b6dfSmrg String *params GCC_UNUSED, 2401d522f475Smrg Cardinal *num_params GCC_UNUSED) 2402d522f475Smrg{ 2403956cc18dSsnj XtermWidget xw; 2404956cc18dSsnj 2405956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2406956cc18dSsnj TScreen *screen = TScreenOf(xw); 24070bd37d32Smrg 24080bd37d32Smrg TRACE(("HandleKeyboardSelectStart\n")); 2409d522f475Smrg do_select_start(xw, event, &screen->cursorp); 2410d522f475Smrg } 2411d522f475Smrg} 2412d522f475Smrg 2413d522f475Smrgstatic void 2414894e0ac8SmrgTrackDown(XtermWidget xw, XButtonEvent *event) 2415d522f475Smrg{ 2416956cc18dSsnj TScreen *screen = TScreenOf(xw); 2417d522f475Smrg CELL cell; 2418d522f475Smrg 2419956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2420d522f475Smrg event->time, 2421d522f475Smrg Select_CHAR, 2422d522f475Smrg event->button); 2423d522f475Smrg if (screen->numberOfClicks > 1) { 2424d522f475Smrg PointToCELL(screen, event->y, event->x, &cell); 2425d522f475Smrg screen->replyToEmacs = True; 2426d522f475Smrg StartSelect(xw, &cell); 2427d522f475Smrg } else { 2428d522f475Smrg screen->waitingForTrackInfo = True; 2429492d43a5Smrg EditorButton(xw, event); 2430d522f475Smrg } 2431d522f475Smrg} 2432d522f475Smrg 2433d522f475Smrg#define boundsCheck(x) if (x < 0) \ 2434d522f475Smrg x = 0; \ 2435d522f475Smrg else if (x >= screen->max_row) \ 2436d522f475Smrg x = screen->max_row 2437d522f475Smrg 2438d522f475Smrgvoid 2439d522f475SmrgTrackMouse(XtermWidget xw, 2440d522f475Smrg int func, 2441e0a2b6dfSmrg CELL *start, 2442d522f475Smrg int firstrow, 2443d522f475Smrg int lastrow) 2444d522f475Smrg{ 2445956cc18dSsnj TScreen *screen = TScreenOf(xw); 2446d522f475Smrg 2447d522f475Smrg if (screen->waitingForTrackInfo) { /* if Timed, ignore */ 2448d522f475Smrg screen->waitingForTrackInfo = False; 2449d522f475Smrg 2450d522f475Smrg if (func != 0) { 2451d522f475Smrg CELL first = *start; 2452d522f475Smrg 2453d522f475Smrg boundsCheck(first.row); 2454d522f475Smrg boundsCheck(firstrow); 2455d522f475Smrg boundsCheck(lastrow); 2456d522f475Smrg screen->firstValidRow = firstrow; 2457d522f475Smrg screen->lastValidRow = lastrow; 2458d522f475Smrg screen->replyToEmacs = True; 2459d522f475Smrg StartSelect(xw, &first); 2460d522f475Smrg } 2461d522f475Smrg } 2462d522f475Smrg} 2463d522f475Smrg 2464d522f475Smrgstatic void 2465e0a2b6dfSmrgStartSelect(XtermWidget xw, const CELL *cell) 2466d522f475Smrg{ 2467956cc18dSsnj TScreen *screen = TScreenOf(xw); 2468d522f475Smrg 2469d522f475Smrg TRACE(("StartSelect row=%d, col=%d\n", cell->row, cell->col)); 2470d522f475Smrg if (screen->cursor_state) 2471d522f475Smrg HideCursor(); 2472d522f475Smrg if (screen->numberOfClicks == 1) { 2473d522f475Smrg /* set start of selection */ 2474d522f475Smrg screen->rawPos = *cell; 2475d522f475Smrg } 2476d522f475Smrg /* else use old values in rawPos */ 2477d522f475Smrg screen->saveStartR = screen->startExt = screen->rawPos; 2478d522f475Smrg screen->saveEndR = screen->endExt = screen->rawPos; 2479d522f475Smrg if (Coordinate(screen, cell) < Coordinate(screen, &(screen->rawPos))) { 2480d522f475Smrg screen->eventMode = LEFTEXTENSION; 2481d522f475Smrg screen->startExt = *cell; 2482d522f475Smrg } else { 2483d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2484d522f475Smrg screen->endExt = *cell; 2485d522f475Smrg } 2486d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 2487d522f475Smrg} 2488d522f475Smrg 2489d522f475Smrgstatic void 2490d522f475SmrgEndExtend(XtermWidget xw, 2491894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 2492e0a2b6dfSmrg String *params, /* selections */ 2493d522f475Smrg Cardinal num_params, 2494d522f475Smrg Bool use_cursor_loc) 2495d522f475Smrg{ 2496d522f475Smrg CELL cell; 2497956cc18dSsnj TScreen *screen = TScreenOf(xw); 2498d522f475Smrg 2499d522f475Smrg if (use_cursor_loc) { 2500d522f475Smrg cell = screen->cursorp; 2501d522f475Smrg } else { 2502d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2503d522f475Smrg } 2504d522f475Smrg ExtendExtend(xw, &cell); 25052e4f8982Smrg 2506d522f475Smrg screen->lastButtonUpTime = event->xbutton.time; 2507d522f475Smrg screen->lastButton = event->xbutton.button; 25082e4f8982Smrg 2509d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 2510d522f475Smrg if (screen->replyToEmacs) { 25112e4f8982Smrg Char line[64]; 25122e4f8982Smrg unsigned count = 0; 25132e4f8982Smrg 2514d522f475Smrg if (screen->control_eight_bits) { 2515d522f475Smrg line[count++] = ANSI_CSI; 2516d522f475Smrg } else { 2517d522f475Smrg line[count++] = ANSI_ESC; 2518d522f475Smrg line[count++] = '['; 2519d522f475Smrg } 2520d522f475Smrg if (isSameCELL(&(screen->rawPos), &(screen->startSel)) 2521d522f475Smrg && isSameCELL(&cell, &(screen->endSel))) { 2522d522f475Smrg /* Use short-form emacs select */ 25230bd37d32Smrg 25240bd37d32Smrg switch (screen->extend_coords) { 25250bd37d32Smrg case 0: 25260bd37d32Smrg case SET_EXT_MODE_MOUSE: 25270bd37d32Smrg line[count++] = 't'; 25280bd37d32Smrg break; 25290bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 25300bd37d32Smrg line[count++] = '<'; 25310bd37d32Smrg break; 25320bd37d32Smrg } 25330bd37d32Smrg 2534492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 25350bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2536492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 25370bd37d32Smrg 25380bd37d32Smrg switch (screen->extend_coords) { 25390bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 25400bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 25410bd37d32Smrg line[count++] = 't'; 25420bd37d32Smrg break; 25430bd37d32Smrg } 2544d522f475Smrg } else { 2545d522f475Smrg /* long-form, specify everything */ 25460bd37d32Smrg 25470bd37d32Smrg switch (screen->extend_coords) { 25480bd37d32Smrg case 0: 25490bd37d32Smrg case SET_EXT_MODE_MOUSE: 25500bd37d32Smrg line[count++] = 'T'; 25510bd37d32Smrg break; 25520bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 25530bd37d32Smrg line[count++] = '<'; 25540bd37d32Smrg break; 25550bd37d32Smrg } 25560bd37d32Smrg 2557492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.col); 25580bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2559492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.row); 25600bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2561492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 25620bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2563492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 25640bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2565492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.col); 25660bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2567492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.row); 25680bd37d32Smrg 25690bd37d32Smrg switch (screen->extend_coords) { 25700bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 25710bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 25720bd37d32Smrg line[count++] = 'T'; 25730bd37d32Smrg break; 25740bd37d32Smrg } 2575d522f475Smrg } 2576d522f475Smrg v_write(screen->respond, line, count); 2577d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 2578d522f475Smrg } 2579d522f475Smrg } 2580d522f475Smrg SelectSet(xw, event, params, num_params); 2581d522f475Smrg screen->eventMode = NORMAL; 2582d522f475Smrg} 2583d522f475Smrg 2584d522f475Smrgvoid 2585d522f475SmrgHandleSelectSet(Widget w, 2586894e0ac8Smrg XEvent *event, 2587e0a2b6dfSmrg String *params, 2588d522f475Smrg Cardinal *num_params) 2589d522f475Smrg{ 2590956cc18dSsnj XtermWidget xw; 2591956cc18dSsnj 2592956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 25930bd37d32Smrg TRACE(("HandleSelectSet\n")); 2594956cc18dSsnj SelectSet(xw, event, params, *num_params); 2595d522f475Smrg } 2596d522f475Smrg} 2597d522f475Smrg 2598d522f475Smrg/* ARGSUSED */ 2599d522f475Smrgstatic void 2600d522f475SmrgSelectSet(XtermWidget xw, 2601894e0ac8Smrg XEvent *event GCC_UNUSED, 2602e0a2b6dfSmrg String *params, 2603d522f475Smrg Cardinal num_params) 2604d522f475Smrg{ 2605956cc18dSsnj TScreen *screen = TScreenOf(xw); 2606d522f475Smrg 2607d522f475Smrg TRACE(("SelectSet\n")); 2608d522f475Smrg /* Only do select stuff if non-null select */ 2609d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 26100bd37d32Smrg SaltTextAway(xw, &(screen->startSel), &(screen->endSel)); 26110bd37d32Smrg _OwnSelection(xw, params, num_params); 2612d522f475Smrg } else { 26130bd37d32Smrg ScrnDisownSelection(xw); 2614d522f475Smrg } 2615d522f475Smrg} 2616d522f475Smrg 2617d522f475Smrg#define Abs(x) ((x) < 0 ? -(x) : (x)) 2618d522f475Smrg 2619d522f475Smrg/* ARGSUSED */ 2620d522f475Smrgstatic void 2621d522f475Smrgdo_start_extend(XtermWidget xw, 2622894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2623e0a2b6dfSmrg String *params GCC_UNUSED, 2624d522f475Smrg Cardinal *num_params GCC_UNUSED, 2625d522f475Smrg Bool use_cursor_loc) 2626d522f475Smrg{ 2627956cc18dSsnj TScreen *screen = TScreenOf(xw); 2628d522f475Smrg int coord; 2629d522f475Smrg CELL cell; 2630d522f475Smrg 2631d522f475Smrg if (SendMousePosition(xw, event)) 2632d522f475Smrg return; 2633d522f475Smrg 2634d522f475Smrg screen->firstValidRow = 0; 2635d522f475Smrg screen->lastValidRow = screen->max_row; 2636d522f475Smrg#if OPT_READLINE 2637492d43a5Smrg if ((KeyModifiers(event) & ShiftMask) 2638d522f475Smrg || event->xbutton.button != Button3 2639d522f475Smrg || !(SCREEN_FLAG(screen, dclick3_deletes))) 2640d522f475Smrg#endif 2641956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2642d522f475Smrg event->xbutton.time, 2643d522f475Smrg screen->selectUnit, 2644d522f475Smrg event->xbutton.button); 2645d522f475Smrg screen->replyToEmacs = False; 2646d522f475Smrg 2647d522f475Smrg#if OPT_READLINE 2648d522f475Smrg CheckSecondPress3(screen, event); 2649d522f475Smrg#endif 2650d522f475Smrg 2651d522f475Smrg if (screen->numberOfClicks == 1 2652d522f475Smrg || (SCREEN_FLAG(screen, dclick3_deletes) /* Dclick special */ 2653492d43a5Smrg &&!(KeyModifiers(event) & ShiftMask))) { 2654d522f475Smrg /* Save existing selection so we can reestablish it if the guy 2655d522f475Smrg extends past the other end of the selection */ 2656d522f475Smrg screen->saveStartR = screen->startExt = screen->startRaw; 2657d522f475Smrg screen->saveEndR = screen->endExt = screen->endRaw; 2658d522f475Smrg } else { 2659d522f475Smrg /* He just needed the selection mode changed, use old values. */ 2660d522f475Smrg screen->startExt = screen->startRaw = screen->saveStartR; 2661d522f475Smrg screen->endExt = screen->endRaw = screen->saveEndR; 2662d522f475Smrg } 2663d522f475Smrg if (use_cursor_loc) { 2664d522f475Smrg cell = screen->cursorp; 2665d522f475Smrg } else { 2666d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2667d522f475Smrg } 2668d522f475Smrg coord = Coordinate(screen, &cell); 2669d522f475Smrg 2670d522f475Smrg if (Abs(coord - Coordinate(screen, &(screen->startSel))) 2671d522f475Smrg < Abs(coord - Coordinate(screen, &(screen->endSel))) 2672d522f475Smrg || coord < Coordinate(screen, &(screen->startSel))) { 2673d522f475Smrg /* point is close to left side of selection */ 2674d522f475Smrg screen->eventMode = LEFTEXTENSION; 2675d522f475Smrg screen->startExt = cell; 2676d522f475Smrg } else { 2677d522f475Smrg /* point is close to left side of selection */ 2678d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2679d522f475Smrg screen->endExt = cell; 2680d522f475Smrg } 2681d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), True); 2682d522f475Smrg 2683d522f475Smrg#if OPT_READLINE 2684d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2685d522f475Smrg ExtendingSelection = 1; 2686d522f475Smrg#endif 2687d522f475Smrg} 2688d522f475Smrg 2689d522f475Smrgstatic void 2690e0a2b6dfSmrgExtendExtend(XtermWidget xw, const CELL *cell) 2691d522f475Smrg{ 2692956cc18dSsnj TScreen *screen = TScreenOf(xw); 2693d522f475Smrg int coord = Coordinate(screen, cell); 2694d522f475Smrg 2695d522f475Smrg TRACE(("ExtendExtend row=%d, col=%d\n", cell->row, cell->col)); 2696d522f475Smrg if (screen->eventMode == LEFTEXTENSION 2697d522f475Smrg && ((coord + (screen->selectUnit != Select_CHAR)) 2698d522f475Smrg > Coordinate(screen, &(screen->endSel)))) { 2699d522f475Smrg /* Whoops, he's changed his mind. Do RIGHTEXTENSION */ 2700d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2701d522f475Smrg screen->startExt = screen->saveStartR; 2702d522f475Smrg } else if (screen->eventMode == RIGHTEXTENSION 2703d522f475Smrg && coord < Coordinate(screen, &(screen->startSel))) { 2704d522f475Smrg /* Whoops, he's changed his mind. Do LEFTEXTENSION */ 2705d522f475Smrg screen->eventMode = LEFTEXTENSION; 2706d522f475Smrg screen->endExt = screen->saveEndR; 2707d522f475Smrg } 2708d522f475Smrg if (screen->eventMode == LEFTEXTENSION) { 2709d522f475Smrg screen->startExt = *cell; 2710d522f475Smrg } else { 2711d522f475Smrg screen->endExt = *cell; 2712d522f475Smrg } 2713d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 2714d522f475Smrg 2715d522f475Smrg#if OPT_READLINE 2716d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2717d522f475Smrg ExtendingSelection = 1; 2718d522f475Smrg#endif 2719d522f475Smrg} 2720d522f475Smrg 2721d522f475Smrgvoid 2722d522f475SmrgHandleStartExtend(Widget w, 2723894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2724e0a2b6dfSmrg String *params, /* unused */ 2725d522f475Smrg Cardinal *num_params) /* unused */ 2726d522f475Smrg{ 2727956cc18dSsnj XtermWidget xw; 2728956cc18dSsnj 2729956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 27300bd37d32Smrg TRACE(("HandleStartExtend\n")); 2731956cc18dSsnj do_start_extend(xw, event, params, num_params, False); 2732956cc18dSsnj } 2733d522f475Smrg} 2734d522f475Smrg 2735d522f475Smrgvoid 2736d522f475SmrgHandleKeyboardStartExtend(Widget w, 2737894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2738e0a2b6dfSmrg String *params, /* unused */ 2739d522f475Smrg Cardinal *num_params) /* unused */ 2740d522f475Smrg{ 2741956cc18dSsnj XtermWidget xw; 2742956cc18dSsnj 2743956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 27440bd37d32Smrg TRACE(("HandleKeyboardStartExtend\n")); 2745956cc18dSsnj do_start_extend(xw, event, params, num_params, True); 2746956cc18dSsnj } 2747d522f475Smrg} 2748d522f475Smrg 2749d522f475Smrgvoid 2750e0a2b6dfSmrgScrollSelection(TScreen *screen, int amount, Bool always) 2751d522f475Smrg{ 2752d522f475Smrg int minrow = INX2ROW(screen, -screen->savedlines); 2753d522f475Smrg int maxrow = INX2ROW(screen, screen->max_row); 2754d522f475Smrg int maxcol = screen->max_col; 2755d522f475Smrg 2756d522f475Smrg#define scroll_update_one(cell) \ 2757d522f475Smrg (cell)->row += amount; \ 2758d522f475Smrg if ((cell)->row < minrow) { \ 2759d522f475Smrg (cell)->row = minrow; \ 2760d522f475Smrg (cell)->col = 0; \ 2761d522f475Smrg } \ 2762d522f475Smrg if ((cell)->row > maxrow) { \ 2763d522f475Smrg (cell)->row = maxrow; \ 2764d522f475Smrg (cell)->col = maxcol; \ 2765d522f475Smrg } 2766d522f475Smrg 2767d522f475Smrg scroll_update_one(&(screen->startRaw)); 2768d522f475Smrg scroll_update_one(&(screen->endRaw)); 2769d522f475Smrg scroll_update_one(&(screen->startSel)); 2770d522f475Smrg scroll_update_one(&(screen->endSel)); 2771d522f475Smrg 2772d522f475Smrg scroll_update_one(&(screen->rawPos)); 2773d522f475Smrg 2774d522f475Smrg /* 2775d522f475Smrg * If we are told to scroll the selection but it lies outside the scrolling 2776d522f475Smrg * margins, then that could cause the selection to move (bad). It is not 2777d522f475Smrg * simple to fix, because this function is called both for the scrollbar 2778d522f475Smrg * actions as well as application scrolling. The 'always' flag is set in 2779d522f475Smrg * the former case. The rest of the logic handles the latter. 2780d522f475Smrg */ 2781d522f475Smrg if (ScrnHaveSelection(screen)) { 2782d522f475Smrg int adjust; 2783d522f475Smrg 2784d522f475Smrg adjust = ROW2INX(screen, screen->startH.row); 2785d522f475Smrg if (always 27860bd37d32Smrg || !ScrnHaveRowMargins(screen) 27870bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 2788d522f475Smrg scroll_update_one(&screen->startH); 2789d522f475Smrg } 2790d522f475Smrg adjust = ROW2INX(screen, screen->endH.row); 2791d522f475Smrg if (always 27920bd37d32Smrg || !ScrnHaveRowMargins(screen) 27930bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 2794d522f475Smrg scroll_update_one(&screen->endH); 2795d522f475Smrg } 2796d522f475Smrg } 2797d522f475Smrg 2798d522f475Smrg screen->startHCoord = Coordinate(screen, &screen->startH); 2799d522f475Smrg screen->endHCoord = Coordinate(screen, &screen->endH); 2800d522f475Smrg} 2801d522f475Smrg 2802d522f475Smrg/*ARGSUSED*/ 2803d522f475Smrgvoid 2804e0a2b6dfSmrgResizeSelection(TScreen *screen GCC_UNUSED, int rows, int cols) 2805d522f475Smrg{ 2806d522f475Smrg rows--; /* decr to get 0-max */ 2807d522f475Smrg cols--; 2808d522f475Smrg 2809d522f475Smrg if (screen->startRaw.row > rows) 2810d522f475Smrg screen->startRaw.row = rows; 2811d522f475Smrg if (screen->startSel.row > rows) 2812d522f475Smrg screen->startSel.row = rows; 2813d522f475Smrg if (screen->endRaw.row > rows) 2814d522f475Smrg screen->endRaw.row = rows; 2815d522f475Smrg if (screen->endSel.row > rows) 2816d522f475Smrg screen->endSel.row = rows; 2817d522f475Smrg if (screen->rawPos.row > rows) 2818d522f475Smrg screen->rawPos.row = rows; 2819d522f475Smrg 2820d522f475Smrg if (screen->startRaw.col > cols) 2821d522f475Smrg screen->startRaw.col = cols; 2822d522f475Smrg if (screen->startSel.col > cols) 2823d522f475Smrg screen->startSel.col = cols; 2824d522f475Smrg if (screen->endRaw.col > cols) 2825d522f475Smrg screen->endRaw.col = cols; 2826d522f475Smrg if (screen->endSel.col > cols) 2827d522f475Smrg screen->endSel.col = cols; 2828d522f475Smrg if (screen->rawPos.col > cols) 2829d522f475Smrg screen->rawPos.col = cols; 2830d522f475Smrg} 2831d522f475Smrg 2832d522f475Smrg#if OPT_WIDE_CHARS 2833d522f475SmrgBool 2834d522f475Smrgiswide(int i) 2835d522f475Smrg{ 283620d2c4d2Smrg return (i == HIDDEN_CHAR) || (WideCells(i) == 2); 2837d522f475Smrg} 2838d522f475Smrg 2839d522f475Smrg#define isWideCell(row, col) iswide((int)XTERM_CELL(row, col)) 2840d522f475Smrg#endif 2841d522f475Smrg 2842d522f475Smrgstatic void 2843e0a2b6dfSmrgPointToCELL(TScreen *screen, 2844d522f475Smrg int y, 2845d522f475Smrg int x, 2846e0a2b6dfSmrg CELL *cell) 2847d522f475Smrg/* Convert pixel coordinates to character coordinates. 2848d522f475Smrg Rows are clipped between firstValidRow and lastValidRow. 2849d522f475Smrg Columns are clipped between to be 0 or greater, but are not clipped to some 2850d522f475Smrg maximum value. */ 2851d522f475Smrg{ 2852d522f475Smrg cell->row = (y - screen->border) / FontHeight(screen); 2853d522f475Smrg if (cell->row < screen->firstValidRow) 2854d522f475Smrg cell->row = screen->firstValidRow; 2855d522f475Smrg else if (cell->row > screen->lastValidRow) 2856d522f475Smrg cell->row = screen->lastValidRow; 2857d522f475Smrg cell->col = (x - OriginX(screen)) / FontWidth(screen); 2858d522f475Smrg if (cell->col < 0) 2859d522f475Smrg cell->col = 0; 2860d522f475Smrg else if (cell->col > MaxCols(screen)) { 2861d522f475Smrg cell->col = MaxCols(screen); 2862d522f475Smrg } 2863d522f475Smrg#if OPT_WIDE_CHARS 2864d522f475Smrg /* 2865d522f475Smrg * If we got a click on the right half of a doublewidth character, 2866d522f475Smrg * pretend it happened on the left half. 2867d522f475Smrg */ 2868d522f475Smrg if (cell->col > 0 2869d522f475Smrg && isWideCell(cell->row, cell->col - 1) 2870d522f475Smrg && (XTERM_CELL(cell->row, cell->col) == HIDDEN_CHAR)) { 2871d522f475Smrg cell->col -= 1; 2872d522f475Smrg } 2873d522f475Smrg#endif 2874d522f475Smrg} 2875d522f475Smrg 2876d522f475Smrg/* 2877d522f475Smrg * Find the last column at which text was drawn on the given row. 2878d522f475Smrg */ 2879d522f475Smrgstatic int 288001037d57SmrgLastTextCol(TScreen *screen, CLineData *ld, int row) 2881d522f475Smrg{ 288220d2c4d2Smrg int i = -1; 2883d522f475Smrg 288420d2c4d2Smrg if (ld != 0) { 288520d2c4d2Smrg if (okScrnRow(screen, row)) { 28862e4f8982Smrg const IAttr *ch; 288720d2c4d2Smrg for (i = screen->max_col, 288820d2c4d2Smrg ch = ld->attribs + i; 288920d2c4d2Smrg i >= 0 && !(*ch & CHARDRAWN); 289020d2c4d2Smrg ch--, i--) { 289120d2c4d2Smrg ; 289220d2c4d2Smrg } 2893d522f475Smrg#if OPT_DEC_CHRSET 289420d2c4d2Smrg if (CSET_DOUBLE(GetLineDblCS(ld))) { 289520d2c4d2Smrg i *= 2; 289620d2c4d2Smrg } 2897d522f475Smrg#endif 289820d2c4d2Smrg } 2899d522f475Smrg } 2900d522f475Smrg return (i); 2901d522f475Smrg} 2902d522f475Smrg 2903d522f475Smrg#if !OPT_WIDE_CHARS 2904d522f475Smrg/* 2905d522f475Smrg** double click table for cut and paste in 8 bits 2906d522f475Smrg** 2907d522f475Smrg** This table is divided in four parts : 2908d522f475Smrg** 2909d522f475Smrg** - control characters [0,0x1f] U [0x80,0x9f] 2910d522f475Smrg** - separators [0x20,0x3f] U [0xa0,0xb9] 2911d522f475Smrg** - binding characters [0x40,0x7f] U [0xc0,0xff] 2912d522f475Smrg** - exceptions 2913d522f475Smrg*/ 2914d522f475Smrg/* *INDENT-OFF* */ 2915d522f475Smrgstatic int charClass[256] = 2916d522f475Smrg{ 2917d522f475Smrg/* NUL SOH STX ETX EOT ENQ ACK BEL */ 2918d522f475Smrg 32, 1, 1, 1, 1, 1, 1, 1, 29190bd37d32Smrg/* BS HT NL VT FF CR SO SI */ 2920d522f475Smrg 1, 32, 1, 1, 1, 1, 1, 1, 2921d522f475Smrg/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 2922d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2923d522f475Smrg/* CAN EM SUB ESC FS GS RS US */ 2924d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2925d522f475Smrg/* SP ! " # $ % & ' */ 2926d522f475Smrg 32, 33, 34, 35, 36, 37, 38, 39, 2927d522f475Smrg/* ( ) * + , - . / */ 2928d522f475Smrg 40, 41, 42, 43, 44, 45, 46, 47, 2929d522f475Smrg/* 0 1 2 3 4 5 6 7 */ 2930d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2931d522f475Smrg/* 8 9 : ; < = > ? */ 2932d522f475Smrg 48, 48, 58, 59, 60, 61, 62, 63, 2933d522f475Smrg/* @ A B C D E F G */ 2934d522f475Smrg 64, 48, 48, 48, 48, 48, 48, 48, 2935d522f475Smrg/* H I J K L M N O */ 2936d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2937d522f475Smrg/* P Q R S T U V W */ 2938d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2939d522f475Smrg/* X Y Z [ \ ] ^ _ */ 2940d522f475Smrg 48, 48, 48, 91, 92, 93, 94, 48, 2941d522f475Smrg/* ` a b c d e f g */ 2942d522f475Smrg 96, 48, 48, 48, 48, 48, 48, 48, 2943d522f475Smrg/* h i j k l m n o */ 2944d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2945d522f475Smrg/* p q r s t u v w */ 2946d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2947d522f475Smrg/* x y z { | } ~ DEL */ 2948d522f475Smrg 48, 48, 48, 123, 124, 125, 126, 1, 2949d522f475Smrg/* x80 x81 x82 x83 IND NEL SSA ESA */ 2950d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2951d522f475Smrg/* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 2952d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2953d522f475Smrg/* DCS PU1 PU2 STS CCH MW SPA EPA */ 2954d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2955d522f475Smrg/* x98 x99 x9A CSI ST OSC PM APC */ 2956d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2957d522f475Smrg/* - i c/ L ox Y- | So */ 2958d522f475Smrg 160, 161, 162, 163, 164, 165, 166, 167, 2959d522f475Smrg/* .. c0 ip << _ R0 - */ 2960d522f475Smrg 168, 169, 170, 171, 172, 173, 174, 175, 2961d522f475Smrg/* o +- 2 3 ' u q| . */ 2962d522f475Smrg 176, 177, 178, 179, 180, 181, 182, 183, 2963d522f475Smrg/* , 1 2 >> 1/4 1/2 3/4 ? */ 2964d522f475Smrg 184, 185, 186, 187, 188, 189, 190, 191, 2965d522f475Smrg/* A` A' A^ A~ A: Ao AE C, */ 2966d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2967d522f475Smrg/* E` E' E^ E: I` I' I^ I: */ 2968d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2969d522f475Smrg/* D- N~ O` O' O^ O~ O: X */ 2970d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 215, 2971d522f475Smrg/* O/ U` U' U^ U: Y' P B */ 2972d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2973d522f475Smrg/* a` a' a^ a~ a: ao ae c, */ 2974d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2975d522f475Smrg/* e` e' e^ e: i` i' i^ i: */ 2976d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2977d522f475Smrg/* d n~ o` o' o^ o~ o: -: */ 2978d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 247, 2979d522f475Smrg/* o/ u` u' u^ u: y' P y: */ 2980d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48}; 2981d522f475Smrg/* *INDENT-ON* */ 2982d522f475Smrg 2983d522f475Smrgint 2984d522f475SmrgSetCharacterClassRange(int low, /* in range of [0..255] */ 2985d522f475Smrg int high, 2986d522f475Smrg int value) /* arbitrary */ 2987d522f475Smrg{ 2988d522f475Smrg 2989d522f475Smrg if (low < 0 || high > 255 || high < low) 2990d522f475Smrg return (-1); 2991d522f475Smrg 2992d522f475Smrg for (; low <= high; low++) 2993d522f475Smrg charClass[low] = value; 2994d522f475Smrg 2995d522f475Smrg return (0); 2996d522f475Smrg} 2997d522f475Smrg#endif 2998d522f475Smrg 2999d522f475Smrgstatic int 3000e0a2b6dfSmrgclass_of(LineData *ld, CELL *cell) 3001d522f475Smrg{ 3002d522f475Smrg CELL temp = *cell; 30030bd37d32Smrg int result = 0; 3004d522f475Smrg 3005d522f475Smrg#if OPT_DEC_CHRSET 3006956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 3007d522f475Smrg temp.col /= 2; 3008d522f475Smrg } 3009d522f475Smrg#endif 30100bd37d32Smrg if (temp.col < (int) ld->lineSize) 30110bd37d32Smrg result = CharacterClass((int) (ld->charData[temp.col])); 30120bd37d32Smrg return result; 3013d522f475Smrg} 3014956cc18dSsnj 3015956cc18dSsnj#if OPT_WIDE_CHARS 3016956cc18dSsnj#define CClassSelects(name, cclass) \ 3017956cc18dSsnj (CClassOf(name) == cclass \ 3018956cc18dSsnj || XTERM_CELL(screen->name.row, screen->name.col) == HIDDEN_CHAR) 3019d522f475Smrg#else 3020956cc18dSsnj#define CClassSelects(name, cclass) \ 3021956cc18dSsnj (class_of(ld.name, &((screen->name))) == cclass) 3022d522f475Smrg#endif 3023d522f475Smrg 3024956cc18dSsnj#define CClassOf(name) class_of(ld.name, &((screen->name))) 3025956cc18dSsnj 3026913cc679Smrg#if OPT_REPORT_CCLASS 3027913cc679Smrgstatic int 3028913cc679Smrgshow_cclass_range(int lo, int hi) 3029913cc679Smrg{ 3030913cc679Smrg int cclass = CharacterClass(lo); 3031913cc679Smrg int ident = (cclass == lo); 3032913cc679Smrg int more = 0; 3033913cc679Smrg if (ident) { 3034913cc679Smrg int ch; 3035913cc679Smrg for (ch = lo + 1; ch <= hi; ch++) { 3036913cc679Smrg if (CharacterClass(ch) != ch) { 3037913cc679Smrg ident = 0; 3038913cc679Smrg break; 3039913cc679Smrg } 3040913cc679Smrg } 3041913cc679Smrg if (ident && (hi < 255)) { 3042913cc679Smrg ch = hi + 1; 3043913cc679Smrg if (CharacterClass(ch) == ch) { 3044913cc679Smrg if (ch >= 255 || CharacterClass(ch + 1) != ch) { 3045913cc679Smrg more = 1; 3046913cc679Smrg } 3047913cc679Smrg } 3048913cc679Smrg } 3049913cc679Smrg } 3050913cc679Smrg if (!more) { 3051913cc679Smrg if (lo == hi) { 3052913cc679Smrg printf("\t%d", lo); 3053913cc679Smrg } else { 3054913cc679Smrg printf("\t%d-%d", lo, hi); 3055913cc679Smrg } 3056913cc679Smrg if (!ident) 3057913cc679Smrg printf(":%d", cclass); 3058913cc679Smrg if (hi < 255) 3059913cc679Smrg printf(", \\"); 3060913cc679Smrg printf("\n"); 3061913cc679Smrg } 3062913cc679Smrg return !more; 3063913cc679Smrg} 3064913cc679Smrg 3065913cc679Smrgvoid 3066913cc679Smrgreport_char_class(XtermWidget xw) 3067913cc679Smrg{ 3068913cc679Smrg /* simple table, to match documentation */ 3069913cc679Smrg static const char charnames[] = 3070913cc679Smrg "NUL\0" "SOH\0" "STX\0" "ETX\0" "EOT\0" "ENQ\0" "ACK\0" "BEL\0" 3071913cc679Smrg " BS\0" " HT\0" " NL\0" " VT\0" " NP\0" " CR\0" " SO\0" " SI\0" 3072913cc679Smrg "DLE\0" "DC1\0" "DC2\0" "DC3\0" "DC4\0" "NAK\0" "SYN\0" "ETB\0" 3073913cc679Smrg "CAN\0" " EM\0" "SUB\0" "ESC\0" " FS\0" " GS\0" " RS\0" " US\0" 3074913cc679Smrg " SP\0" " !\0" " \"\0" " #\0" " $\0" " %\0" " &\0" " '\0" 3075913cc679Smrg " (\0" " )\0" " *\0" " +\0" " ,\0" " -\0" " .\0" " /\0" 3076913cc679Smrg " 0\0" " 1\0" " 2\0" " 3\0" " 4\0" " 5\0" " 6\0" " 7\0" 3077913cc679Smrg " 8\0" " 9\0" " :\0" " ;\0" " <\0" " =\0" " >\0" " ?\0" 3078913cc679Smrg " @\0" " A\0" " B\0" " C\0" " D\0" " E\0" " F\0" " G\0" 3079913cc679Smrg " H\0" " I\0" " J\0" " K\0" " L\0" " M\0" " N\0" " O\0" 3080913cc679Smrg " P\0" " Q\0" " R\0" " S\0" " T\0" " U\0" " V\0" " W\0" 3081913cc679Smrg " X\0" " Y\0" " Z\0" " [\0" " \\\0" " ]\0" " ^\0" " _\0" 3082913cc679Smrg " `\0" " a\0" " b\0" " c\0" " d\0" " e\0" " f\0" " g\0" 3083913cc679Smrg " h\0" " i\0" " j\0" " k\0" " l\0" " m\0" " n\0" " o\0" 3084913cc679Smrg " p\0" " q\0" " r\0" " s\0" " t\0" " u\0" " v\0" " w\0" 3085913cc679Smrg " x\0" " y\0" " z\0" " {\0" " |\0" " }\0" " ~\0" "DEL\0" 3086913cc679Smrg "x80\0" "x81\0" "x82\0" "x83\0" "IND\0" "NEL\0" "SSA\0" "ESA\0" 3087913cc679Smrg "HTS\0" "HTJ\0" "VTS\0" "PLD\0" "PLU\0" " RI\0" "SS2\0" "SS3\0" 3088913cc679Smrg "DCS\0" "PU1\0" "PU2\0" "STS\0" "CCH\0" " MW\0" "SPA\0" "EPA\0" 3089913cc679Smrg "x98\0" "x99\0" "x9A\0" "CSI\0" " ST\0" "OSC\0" " PM\0" "APC\0" 3090913cc679Smrg " -\0" " i\0" " c/\0" " L\0" " ox\0" " Y-\0" " |\0" " So\0" 3091913cc679Smrg " ..\0" " c0\0" " ip\0" " <<\0" " _\0" " \0" " R0\0" " -\0" 3092913cc679Smrg " o\0" " +-\0" " 2\0" " 3\0" " '\0" " u\0" " q|\0" " .\0" 3093913cc679Smrg " ,\0" " 1\0" " 2\0" " >>\0" "1/4\0" "1/2\0" "3/4\0" " ?\0" 3094913cc679Smrg " A`\0" " A'\0" " A^\0" " A~\0" " A:\0" " Ao\0" " AE\0" " C,\0" 3095913cc679Smrg " E`\0" " E'\0" " E^\0" " E:\0" " I`\0" " I'\0" " I^\0" " I:\0" 3096913cc679Smrg " D-\0" " N~\0" " O`\0" " O'\0" " O^\0" " O~\0" " O:\0" " X\0" 3097913cc679Smrg " O/\0" " U`\0" " U'\0" " U^\0" " U:\0" " Y'\0" " P\0" " B\0" 3098913cc679Smrg " a`\0" " a'\0" " a^\0" " a~\0" " a:\0" " ao\0" " ae\0" " c,\0" 3099913cc679Smrg " e`\0" " e'\0" " e^\0" " e:\0" " i`\0" " i'\0" " i^\0" " i:\0" 3100913cc679Smrg " d\0" " n~\0" " o`\0" " o'\0" " o^\0" " o~\0" " o:\0" " -:\0" 3101913cc679Smrg " o/\0" " u`\0" " u'\0" " u^\0" " u:\0" " y'\0" " P\0" " y:\0"; 3102913cc679Smrg int ch, dh; 3103913cc679Smrg int class_p; 3104913cc679Smrg 3105913cc679Smrg (void) xw; 3106913cc679Smrg 3107913cc679Smrg printf("static int charClass[256] = {\n"); 3108913cc679Smrg for (ch = 0; ch < 256; ++ch) { 3109913cc679Smrg const char *s = charnames + (ch * 4); 3110913cc679Smrg if ((ch & 7) == 0) 3111913cc679Smrg printf("/*"); 3112913cc679Smrg printf(" %s ", s); 3113913cc679Smrg if (((ch + 1) & 7) == 0) { 3114913cc679Smrg printf("*/\n "); 3115913cc679Smrg for (dh = ch - 7; dh <= ch; ++dh) { 3116913cc679Smrg printf(" %3d%s", CharacterClass(dh), dh == 255 ? "};" : ","); 3117913cc679Smrg } 3118913cc679Smrg printf("\n"); 3119913cc679Smrg } 3120913cc679Smrg } 3121913cc679Smrg 3122913cc679Smrg /* print the table as if it were the charClass resource */ 3123913cc679Smrg printf("\n"); 3124913cc679Smrg printf("The table is equivalent to this \"charClass\" resource:\n"); 3125913cc679Smrg class_p = CharacterClass(dh = 0); 3126913cc679Smrg for (ch = 0; ch < 256; ++ch) { 3127913cc679Smrg int class_c = CharacterClass(ch); 3128913cc679Smrg if (class_c != class_p) { 3129913cc679Smrg if (show_cclass_range(dh, ch - 1)) { 3130913cc679Smrg dh = ch; 3131913cc679Smrg class_p = class_c; 3132913cc679Smrg } 3133913cc679Smrg } 3134913cc679Smrg } 3135913cc679Smrg if (dh < 255) { 3136913cc679Smrg show_cclass_range(dh, 255); 3137913cc679Smrg } 3138913cc679Smrg 3139913cc679Smrg if_OPT_WIDE_CHARS(TScreenOf(xw), { 3140913cc679Smrg /* if this is a wide-character configuration, print all intervals */ 3141913cc679Smrg report_wide_char_class(); 3142913cc679Smrg }); 3143913cc679Smrg} 3144913cc679Smrg#endif 3145913cc679Smrg 3146d522f475Smrg/* 3147d522f475Smrg * If the given column is past the end of text on the given row, bump to the 3148d522f475Smrg * beginning of the next line. 3149d522f475Smrg */ 3150d522f475Smrgstatic Boolean 3151e0a2b6dfSmrgokPosition(TScreen *screen, 3152e0a2b6dfSmrg LineData **ld, 3153e0a2b6dfSmrg CELL *cell) 3154d522f475Smrg{ 315520d2c4d2Smrg Boolean result = True; 315620d2c4d2Smrg 315720d2c4d2Smrg if (cell->row > screen->max_row) { 315820d2c4d2Smrg result = False; 315920d2c4d2Smrg } else if (cell->col > (LastTextCol(screen, *ld, cell->row) + 1)) { 316020d2c4d2Smrg if (cell->row < screen->max_row) { 316120d2c4d2Smrg cell->col = 0; 316220d2c4d2Smrg *ld = GET_LINEDATA(screen, ++cell->row); 316320d2c4d2Smrg result = False; 316420d2c4d2Smrg } 3165d522f475Smrg } 316620d2c4d2Smrg return result; 3167d522f475Smrg} 3168d522f475Smrg 3169d522f475Smrgstatic void 3170e0a2b6dfSmrgtrimLastLine(TScreen *screen, 3171e0a2b6dfSmrg LineData **ld, 3172e0a2b6dfSmrg CELL *last) 3173d522f475Smrg{ 317420d2c4d2Smrg if (screen->cutNewline && last->row < screen->max_row) { 3175d522f475Smrg last->col = 0; 3176956cc18dSsnj *ld = GET_LINEDATA(screen, ++last->row); 3177d522f475Smrg } else { 3178956cc18dSsnj last->col = LastTextCol(screen, *ld, last->row) + 1; 3179d522f475Smrg } 3180d522f475Smrg} 3181d522f475Smrg 3182d522f475Smrg#if OPT_SELECT_REGEX 3183d522f475Smrg/* 3184d522f475Smrg * Returns the first row of a wrapped line. 3185d522f475Smrg */ 3186d522f475Smrgstatic int 3187e0a2b6dfSmrgfirstRowOfLine(TScreen *screen, int row, Bool visible) 3188d522f475Smrg{ 3189956cc18dSsnj LineData *ld = 0; 3190d522f475Smrg int limit = visible ? 0 : -screen->savedlines; 3191d522f475Smrg 3192d522f475Smrg while (row > limit && 3193956cc18dSsnj (ld = GET_LINEDATA(screen, row - 1)) != 0 && 3194956cc18dSsnj LineTstWrapped(ld)) { 3195d522f475Smrg --row; 3196956cc18dSsnj } 3197d522f475Smrg return row; 3198d522f475Smrg} 3199d522f475Smrg 3200d522f475Smrg/* 3201d522f475Smrg * Returns the last row of a wrapped line. 3202d522f475Smrg */ 3203d522f475Smrgstatic int 3204e0a2b6dfSmrglastRowOfLine(TScreen *screen, int row) 3205d522f475Smrg{ 3206956cc18dSsnj LineData *ld; 3207956cc18dSsnj 3208d522f475Smrg while (row < screen->max_row && 3209956cc18dSsnj (ld = GET_LINEDATA(screen, row)) != 0 && 3210956cc18dSsnj LineTstWrapped(ld)) { 3211d522f475Smrg ++row; 3212956cc18dSsnj } 3213d522f475Smrg return row; 3214d522f475Smrg} 3215d522f475Smrg 3216d522f475Smrg/* 3217d522f475Smrg * Returns the number of cells on the range of rows. 3218d522f475Smrg */ 3219d522f475Smrgstatic unsigned 3220e0a2b6dfSmrglengthOfLines(TScreen *screen, int firstRow, int lastRow) 3221d522f475Smrg{ 3222d522f475Smrg unsigned length = 0; 3223d522f475Smrg int n; 3224d522f475Smrg 3225d522f475Smrg for (n = firstRow; n <= lastRow; ++n) { 3226956cc18dSsnj LineData *ld = GET_LINEDATA(screen, n); 3227956cc18dSsnj int value = LastTextCol(screen, ld, n); 3228d522f475Smrg if (value >= 0) 32292eaa94a1Schristos length += (unsigned) (value + 1); 3230d522f475Smrg } 3231d522f475Smrg return length; 3232d522f475Smrg} 3233d522f475Smrg 3234d522f475Smrg/* 3235d522f475Smrg * Make a copy of the wrapped-line which corresponds to the given row as a 3236d522f475Smrg * string of bytes. Construct an index for the columns from the beginning of 3237d522f475Smrg * the line. 3238d522f475Smrg */ 3239d522f475Smrgstatic char * 3240e0a2b6dfSmrgmake_indexed_text(TScreen *screen, int row, unsigned length, int *indexed) 3241d522f475Smrg{ 3242d522f475Smrg Char *result = 0; 324320d2c4d2Smrg size_t need = (length + 1); 3244d522f475Smrg 3245d522f475Smrg /* 3246d522f475Smrg * Get a quick upper bound to the number of bytes needed, if the whole 3247d522f475Smrg * string were UTF-8. 3248d522f475Smrg */ 3249d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3250956cc18dSsnj need *= ((screen->lineExtra + 1) * 6); 3251d522f475Smrg }); 3252d522f475Smrg 3253d522f475Smrg if ((result = TypeCallocN(Char, need + 1)) != 0) { 3254956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 3255d522f475Smrg unsigned used = 0; 3256d522f475Smrg Char *last = result; 3257d522f475Smrg 3258d522f475Smrg do { 3259d522f475Smrg int col = 0; 3260956cc18dSsnj int limit = LastTextCol(screen, ld, row); 3261d522f475Smrg 3262d522f475Smrg while (col <= limit) { 3263d522f475Smrg Char *next = last; 3264956cc18dSsnj unsigned data = ld->charData[col]; 3265d522f475Smrg 32660bd37d32Smrg assert(col < (int) ld->lineSize); 3267d522f475Smrg /* some internal points may not be drawn */ 3268d522f475Smrg if (data == 0) 3269d522f475Smrg data = ' '; 3270d522f475Smrg 3271d522f475Smrg if_WIDE_OR_NARROW(screen, { 3272d522f475Smrg next = convertToUTF8(last, data); 3273d522f475Smrg } 3274d522f475Smrg , { 3275d522f475Smrg *next++ = CharOf(data); 3276d522f475Smrg }); 3277d522f475Smrg 3278d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3279956cc18dSsnj size_t off; 3280956cc18dSsnj for_each_combData(off, ld) { 3281956cc18dSsnj data = ld->combData[off][col]; 3282956cc18dSsnj if (data == 0) 3283d522f475Smrg break; 3284d522f475Smrg next = convertToUTF8(next, data); 3285d522f475Smrg } 3286d522f475Smrg }); 3287d522f475Smrg 328820d2c4d2Smrg indexed[used] = (int) (last - result); 3289d522f475Smrg *next = 0; 3290d522f475Smrg /* TRACE(("index[%d.%d] %d:%s\n", row, used, indexed[used], last)); */ 3291d522f475Smrg last = next; 3292d522f475Smrg ++used; 3293d522f475Smrg ++col; 329420d2c4d2Smrg indexed[used] = (int) (next - result); 3295d522f475Smrg } 3296d522f475Smrg } while (used < length && 3297956cc18dSsnj LineTstWrapped(ld) && 3298956cc18dSsnj (ld = GET_LINEDATA(screen, ++row)) != 0 && 3299956cc18dSsnj row < screen->max_row); 3300d522f475Smrg } 3301d522f475Smrg /* TRACE(("result:%s\n", result)); */ 3302d522f475Smrg return (char *) result; 3303d522f475Smrg} 3304d522f475Smrg 3305d522f475Smrg/* 3306d522f475Smrg * Find the column given an offset into the character string by using the 3307d522f475Smrg * index constructed in make_indexed_text(). 3308d522f475Smrg */ 3309d522f475Smrgstatic int 3310d522f475SmrgindexToCol(int *indexed, int len, int off) 3311d522f475Smrg{ 3312d522f475Smrg int col = 0; 3313d522f475Smrg while (indexed[col] < len) { 3314d522f475Smrg if (indexed[col] >= off) 3315d522f475Smrg break; 3316d522f475Smrg ++col; 3317d522f475Smrg } 3318d522f475Smrg return col; 3319d522f475Smrg} 3320d522f475Smrg 3321d522f475Smrg/* 3322d522f475Smrg * Given a row number, and a column offset from that (which may be wrapped), 3323d522f475Smrg * set the cell to the actual row/column values. 3324d522f475Smrg */ 3325d522f475Smrgstatic void 3326e0a2b6dfSmrgcolumnToCell(TScreen *screen, int row, int col, CELL *cell) 3327d522f475Smrg{ 3328d522f475Smrg while (row < screen->max_row) { 332901037d57Smrg CLineData *ld = GET_LINEDATA(screen, row); 3330956cc18dSsnj int last = LastTextCol(screen, ld, row); 3331d522f475Smrg 3332d522f475Smrg /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */ 3333d522f475Smrg if (col <= last) { 3334d522f475Smrg break; 3335d522f475Smrg } 3336d522f475Smrg /* 3337d522f475Smrg * Stop if the current row does not wrap (does not continue the current 3338d522f475Smrg * line). 3339d522f475Smrg */ 3340956cc18dSsnj if (!LineTstWrapped(ld)) { 3341d522f475Smrg col = last + 1; 3342d522f475Smrg break; 3343d522f475Smrg } 3344d522f475Smrg col -= (last + 1); 3345d522f475Smrg ++row; 3346d522f475Smrg } 3347d522f475Smrg if (col < 0) 3348d522f475Smrg col = 0; 3349d522f475Smrg cell->row = row; 3350d522f475Smrg cell->col = col; 3351d522f475Smrg} 3352d522f475Smrg 3353d522f475Smrg/* 3354d522f475Smrg * Given a cell, find the corresponding column offset. 3355d522f475Smrg */ 3356d522f475Smrgstatic int 3357e0a2b6dfSmrgcellToColumn(TScreen *screen, CELL *cell) 3358d522f475Smrg{ 335901037d57Smrg CLineData *ld = 0; 3360d522f475Smrg int col = cell->col; 3361d522f475Smrg int row = firstRowOfLine(screen, cell->row, False); 3362d522f475Smrg while (row < cell->row) { 3363956cc18dSsnj ld = GET_LINEDATA(screen, row); 3364956cc18dSsnj col += LastTextCol(screen, ld, row++); 3365d522f475Smrg } 3366956cc18dSsnj#if OPT_DEC_CHRSET 3367956cc18dSsnj if (ld == 0) 3368956cc18dSsnj ld = GET_LINEDATA(screen, row); 3369956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3370956cc18dSsnj col /= 2; 3371956cc18dSsnj#endif 3372d522f475Smrg return col; 3373d522f475Smrg} 3374d522f475Smrg 3375d522f475Smrgstatic void 3376e0a2b6dfSmrgdo_select_regex(TScreen *screen, CELL *startc, CELL *endc) 3377d522f475Smrg{ 3378956cc18dSsnj LineData *ld = GET_LINEDATA(screen, startc->row); 3379d522f475Smrg int inx = ((screen->numberOfClicks - 1) % screen->maxClicks); 3380d522f475Smrg char *expr = screen->selectExpr[inx]; 3381d522f475Smrg regex_t preg; 3382d522f475Smrg regmatch_t match; 3383d522f475Smrg 338401037d57Smrg TRACE(("Select_REGEX[%d]:%s\n", inx, NonNull(expr))); 3385956cc18dSsnj if (okPosition(screen, &ld, startc) && expr != 0) { 3386d522f475Smrg if (regcomp(&preg, expr, REG_EXTENDED) == 0) { 3387d522f475Smrg int firstRow = firstRowOfLine(screen, startc->row, True); 3388d522f475Smrg int lastRow = lastRowOfLine(screen, firstRow); 3389d522f475Smrg unsigned size = lengthOfLines(screen, firstRow, lastRow); 3390d522f475Smrg int actual = cellToColumn(screen, startc); 33912e4f8982Smrg int *indexed; 3392d522f475Smrg 3393d522f475Smrg TRACE(("regcomp ok rows %d..%d bytes %d\n", 3394d522f475Smrg firstRow, lastRow, size)); 3395d522f475Smrg 3396d522f475Smrg if ((indexed = TypeCallocN(int, size + 1)) != 0) { 33972e4f8982Smrg char *search; 3398d522f475Smrg if ((search = make_indexed_text(screen, 3399d522f475Smrg firstRow, 3400d522f475Smrg size, 3401d522f475Smrg indexed)) != 0) { 34022eaa94a1Schristos int len = (int) strlen(search); 3403d522f475Smrg int col; 3404d522f475Smrg int best_col = -1; 3405d522f475Smrg int best_len = -1; 3406d522f475Smrg 3407913cc679Smrg startc->row = 0; 3408913cc679Smrg startc->col = 0; 3409913cc679Smrg endc->row = 0; 3410913cc679Smrg endc->col = 0; 3411913cc679Smrg 3412d522f475Smrg for (col = 0; indexed[col] < len; ++col) { 3413d522f475Smrg if (regexec(&preg, 3414d522f475Smrg search + indexed[col], 341520d2c4d2Smrg (size_t) 1, &match, 0) == 0) { 3416894e0ac8Smrg int start_inx = (int) (match.rm_so + indexed[col]); 3417894e0ac8Smrg int finis_inx = (int) (match.rm_eo + indexed[col]); 3418d522f475Smrg int start_col = indexToCol(indexed, len, start_inx); 3419d522f475Smrg int finis_col = indexToCol(indexed, len, finis_inx); 3420d522f475Smrg 3421d522f475Smrg if (start_col <= actual && 3422913cc679Smrg actual <= finis_col) { 3423d522f475Smrg int test = finis_col - start_col; 3424d522f475Smrg if (best_len < test) { 3425d522f475Smrg best_len = test; 3426d522f475Smrg best_col = start_col; 3427d522f475Smrg TRACE(("match column %d len %d\n", 3428d522f475Smrg best_col, 3429d522f475Smrg best_len)); 3430d522f475Smrg } 3431d522f475Smrg } 3432d522f475Smrg } 3433d522f475Smrg } 3434d522f475Smrg if (best_col >= 0) { 3435d522f475Smrg int best_nxt = best_col + best_len; 3436d522f475Smrg columnToCell(screen, firstRow, best_col, startc); 3437d522f475Smrg columnToCell(screen, firstRow, best_nxt, endc); 3438d522f475Smrg TRACE(("search::%s\n", search)); 3439d522f475Smrg TRACE(("indexed:%d..%d -> %d..%d\n", 3440d522f475Smrg best_col, best_nxt, 3441d522f475Smrg indexed[best_col], 3442d522f475Smrg indexed[best_nxt])); 3443d522f475Smrg TRACE(("matched:%d:%s\n", 3444d522f475Smrg indexed[best_nxt] + 1 - 3445d522f475Smrg indexed[best_col], 3446956cc18dSsnj visibleChars((Char *) (search + indexed[best_col]), 3447d522f475Smrg (unsigned) (indexed[best_nxt] + 3448d522f475Smrg 1 - 3449d522f475Smrg indexed[best_col])))); 3450d522f475Smrg } 3451d522f475Smrg free(search); 3452d522f475Smrg } 3453d522f475Smrg free(indexed); 3454956cc18dSsnj#if OPT_DEC_CHRSET 3455956cc18dSsnj if ((ld = GET_LINEDATA(screen, startc->row)) != 0) { 3456956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3457956cc18dSsnj startc->col *= 2; 3458956cc18dSsnj } 3459956cc18dSsnj if ((ld = GET_LINEDATA(screen, endc->row)) != 0) { 3460956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3461956cc18dSsnj endc->col *= 2; 3462956cc18dSsnj } 3463956cc18dSsnj#endif 3464d522f475Smrg } 3465d522f475Smrg regfree(&preg); 3466d522f475Smrg } 3467d522f475Smrg } 3468d522f475Smrg} 3469d522f475Smrg#endif /* OPT_SELECT_REGEX */ 3470d522f475Smrg 3471956cc18dSsnj#define InitRow(name) \ 3472956cc18dSsnj ld.name = GET_LINEDATA(screen, screen->name.row) 3473956cc18dSsnj 3474956cc18dSsnj#define NextRow(name) \ 3475956cc18dSsnj ld.name = GET_LINEDATA(screen, ++screen->name.row) 3476956cc18dSsnj 3477956cc18dSsnj#define PrevRow(name) \ 3478956cc18dSsnj ld.name = GET_LINEDATA(screen, --screen->name.row) 3479956cc18dSsnj 348020d2c4d2Smrg#define MoreRows(name) \ 348120d2c4d2Smrg (screen->name.row < screen->max_row) 348220d2c4d2Smrg 3483956cc18dSsnj#define isPrevWrapped(name) \ 3484956cc18dSsnj (screen->name.row > 0 \ 3485956cc18dSsnj && (ltmp = GET_LINEDATA(screen, screen->name.row - 1)) != 0 \ 3486956cc18dSsnj && LineTstWrapped(ltmp)) 3487956cc18dSsnj 3488d522f475Smrg/* 3489d522f475Smrg * sets startSel endSel 3490d522f475Smrg * ensuring that they have legal values 3491d522f475Smrg */ 3492d522f475Smrgstatic void 3493d522f475SmrgComputeSelect(XtermWidget xw, 3494e0a2b6dfSmrg CELL *startc, 3495e0a2b6dfSmrg CELL *endc, 3496d522f475Smrg Bool extend) 3497d522f475Smrg{ 3498956cc18dSsnj TScreen *screen = TScreenOf(xw); 3499956cc18dSsnj 3500d522f475Smrg int cclass; 3501d522f475Smrg CELL first = *startc; 3502d522f475Smrg CELL last = *endc; 3503956cc18dSsnj Boolean ignored = False; 3504956cc18dSsnj 3505956cc18dSsnj struct { 3506956cc18dSsnj LineData *startSel; 3507956cc18dSsnj LineData *endSel; 3508956cc18dSsnj } ld; 3509956cc18dSsnj LineData *ltmp; 3510d522f475Smrg 3511d522f475Smrg TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n", 3512d522f475Smrg first.row, first.col, 3513d522f475Smrg last.row, last.col, 3514d522f475Smrg extend ? "" : "no")); 3515d522f475Smrg 3516d522f475Smrg#if OPT_WIDE_CHARS 3517d522f475Smrg if (first.col > 1 3518d522f475Smrg && isWideCell(first.row, first.col - 1) 3519d522f475Smrg && XTERM_CELL(first.row, first.col - 0) == HIDDEN_CHAR) { 352020d2c4d2Smrg TRACE(("Adjusting start. Changing downwards from %i.\n", first.col)); 3521d522f475Smrg first.col -= 1; 3522d522f475Smrg if (last.col == (first.col + 1)) 3523d522f475Smrg last.col--; 3524d522f475Smrg } 3525d522f475Smrg 3526d522f475Smrg if (last.col > 1 3527d522f475Smrg && isWideCell(last.row, last.col - 1) 3528d522f475Smrg && XTERM_CELL(last.row, last.col) == HIDDEN_CHAR) { 3529d522f475Smrg last.col += 1; 3530d522f475Smrg } 3531d522f475Smrg#endif 3532d522f475Smrg 3533d522f475Smrg if (Coordinate(screen, &first) <= Coordinate(screen, &last)) { 3534d522f475Smrg screen->startSel = screen->startRaw = first; 3535d522f475Smrg screen->endSel = screen->endRaw = last; 3536d522f475Smrg } else { /* Swap them */ 3537d522f475Smrg screen->startSel = screen->startRaw = last; 3538d522f475Smrg screen->endSel = screen->endRaw = first; 3539d522f475Smrg } 3540d522f475Smrg 3541956cc18dSsnj InitRow(startSel); 3542956cc18dSsnj InitRow(endSel); 3543956cc18dSsnj 3544d522f475Smrg switch (screen->selectUnit) { 3545d522f475Smrg case Select_CHAR: 3546956cc18dSsnj (void) okPosition(screen, &(ld.startSel), &(screen->startSel)); 3547956cc18dSsnj (void) okPosition(screen, &(ld.endSel), &(screen->endSel)); 3548d522f475Smrg break; 3549d522f475Smrg 3550d522f475Smrg case Select_WORD: 3551d522f475Smrg TRACE(("Select_WORD\n")); 3552956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 3553956cc18dSsnj cclass = CClassOf(startSel); 3554d522f475Smrg do { 3555d522f475Smrg --screen->startSel.col; 3556956cc18dSsnj if (screen->startSel.col < 0 3557956cc18dSsnj && isPrevWrapped(startSel)) { 3558956cc18dSsnj PrevRow(startSel); 3559956cc18dSsnj screen->startSel.col = LastTextCol(screen, ld.startSel, screen->startSel.row); 3560d522f475Smrg } 3561d522f475Smrg } while (screen->startSel.col >= 0 3562956cc18dSsnj && CClassSelects(startSel, cclass)); 3563d522f475Smrg ++screen->startSel.col; 3564d522f475Smrg } 3565d522f475Smrg#if OPT_WIDE_CHARS 3566d522f475Smrg if (screen->startSel.col 3567d522f475Smrg && XTERM_CELL(screen->startSel.row, 3568d522f475Smrg screen->startSel.col) == HIDDEN_CHAR) 3569d522f475Smrg screen->startSel.col++; 3570d522f475Smrg#endif 3571d522f475Smrg 3572956cc18dSsnj if (okPosition(screen, &(ld.endSel), &(screen->endSel))) { 35732e4f8982Smrg int length = LastTextCol(screen, ld.endSel, screen->endSel.row); 3574956cc18dSsnj cclass = CClassOf(endSel); 3575d522f475Smrg do { 3576d522f475Smrg ++screen->endSel.col; 3577d522f475Smrg if (screen->endSel.col > length 3578956cc18dSsnj && LineTstWrapped(ld.endSel)) { 357920d2c4d2Smrg if (!MoreRows(endSel)) 358020d2c4d2Smrg break; 3581d522f475Smrg screen->endSel.col = 0; 3582956cc18dSsnj NextRow(endSel); 3583956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 3584d522f475Smrg } 3585d522f475Smrg } while (screen->endSel.col <= length 3586956cc18dSsnj && CClassSelects(endSel, cclass)); 3587d522f475Smrg /* Word-select selects if pointing to any char in "word", 3588d522f475Smrg * especially note that it includes the last character in a word. 3589d522f475Smrg * So we do no --endSel.col and do special eol handling. 3590d522f475Smrg */ 359120d2c4d2Smrg if (screen->endSel.col > length + 1 359220d2c4d2Smrg && MoreRows(endSel)) { 3593d522f475Smrg screen->endSel.col = 0; 3594956cc18dSsnj NextRow(endSel); 3595d522f475Smrg } 3596d522f475Smrg } 3597d522f475Smrg#if OPT_WIDE_CHARS 3598d522f475Smrg if (screen->endSel.col 3599d522f475Smrg && XTERM_CELL(screen->endSel.row, 3600d522f475Smrg screen->endSel.col) == HIDDEN_CHAR) 3601d522f475Smrg screen->endSel.col++; 3602d522f475Smrg#endif 3603d522f475Smrg 3604d522f475Smrg screen->saveStartW = screen->startSel; 3605d522f475Smrg break; 3606d522f475Smrg 3607d522f475Smrg case Select_LINE: 3608d522f475Smrg TRACE(("Select_LINE\n")); 360920d2c4d2Smrg while (LineTstWrapped(ld.endSel) 361020d2c4d2Smrg && MoreRows(endSel)) { 3611956cc18dSsnj NextRow(endSel); 3612d522f475Smrg } 3613d522f475Smrg if (screen->cutToBeginningOfLine 3614d522f475Smrg || screen->startSel.row < screen->saveStartW.row) { 3615d522f475Smrg screen->startSel.col = 0; 3616956cc18dSsnj while (isPrevWrapped(startSel)) { 3617956cc18dSsnj PrevRow(startSel); 3618d522f475Smrg } 3619d522f475Smrg } else if (!extend) { 3620d522f475Smrg if ((first.row < screen->saveStartW.row) 3621d522f475Smrg || (isSameRow(&first, &(screen->saveStartW)) 3622d522f475Smrg && first.col < screen->saveStartW.col)) { 3623d522f475Smrg screen->startSel.col = 0; 3624956cc18dSsnj while (isPrevWrapped(startSel)) { 3625956cc18dSsnj PrevRow(startSel); 3626d522f475Smrg } 3627d522f475Smrg } else { 3628d522f475Smrg screen->startSel = screen->saveStartW; 3629d522f475Smrg } 3630d522f475Smrg } 3631956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 3632d522f475Smrg break; 3633d522f475Smrg 3634d522f475Smrg case Select_GROUP: /* paragraph */ 3635d522f475Smrg TRACE(("Select_GROUP\n")); 3636956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 3637d522f475Smrg /* scan backward for beginning of group */ 3638d522f475Smrg while (screen->startSel.row > 0 && 3639956cc18dSsnj (LastTextCol(screen, ld.startSel, screen->startSel.row - 3640956cc18dSsnj 1) > 0 || 3641956cc18dSsnj isPrevWrapped(startSel))) { 3642956cc18dSsnj PrevRow(startSel); 3643d522f475Smrg } 3644d522f475Smrg screen->startSel.col = 0; 3645d522f475Smrg /* scan forward for end of group */ 364620d2c4d2Smrg while (MoreRows(endSel) && 3647956cc18dSsnj (LastTextCol(screen, ld.endSel, screen->endSel.row + 1) > 3648956cc18dSsnj 0 || 3649956cc18dSsnj LineTstWrapped(ld.endSel))) { 3650956cc18dSsnj NextRow(endSel); 3651d522f475Smrg } 3652956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 3653d522f475Smrg } 3654d522f475Smrg break; 3655d522f475Smrg 3656d522f475Smrg case Select_PAGE: /* everything one can see */ 3657d522f475Smrg TRACE(("Select_PAGE\n")); 3658d522f475Smrg screen->startSel.row = 0; 3659d522f475Smrg screen->startSel.col = 0; 366020d2c4d2Smrg screen->endSel.row = MaxRows(screen); 3661d522f475Smrg screen->endSel.col = 0; 3662d522f475Smrg break; 3663d522f475Smrg 3664d522f475Smrg case Select_ALL: /* counts scrollback if in normal screen */ 3665d522f475Smrg TRACE(("Select_ALL\n")); 3666d522f475Smrg screen->startSel.row = -screen->savedlines; 3667d522f475Smrg screen->startSel.col = 0; 366820d2c4d2Smrg screen->endSel.row = MaxRows(screen); 3669d522f475Smrg screen->endSel.col = 0; 3670d522f475Smrg break; 3671d522f475Smrg 3672d522f475Smrg#if OPT_SELECT_REGEX 3673d522f475Smrg case Select_REGEX: 3674d522f475Smrg do_select_regex(screen, &(screen->startSel), &(screen->endSel)); 3675d522f475Smrg break; 3676d522f475Smrg#endif 3677d522f475Smrg 3678d522f475Smrg case NSELECTUNITS: /* always ignore */ 3679956cc18dSsnj ignored = True; 3680956cc18dSsnj break; 3681d522f475Smrg } 3682d522f475Smrg 3683956cc18dSsnj if (!ignored) { 3684956cc18dSsnj /* check boundaries */ 3685956cc18dSsnj ScrollSelection(screen, 0, False); 3686956cc18dSsnj TrackText(xw, &(screen->startSel), &(screen->endSel)); 3687956cc18dSsnj } 3688d522f475Smrg 3689d522f475Smrg return; 3690d522f475Smrg} 3691d522f475Smrg 3692d522f475Smrg/* Guaranteed (first.row, first.col) <= (last.row, last.col) */ 3693d522f475Smrgstatic void 3694d522f475SmrgTrackText(XtermWidget xw, 3695e0a2b6dfSmrg const CELL *firstp, 3696e0a2b6dfSmrg const CELL *lastp) 3697d522f475Smrg{ 3698956cc18dSsnj TScreen *screen = TScreenOf(xw); 3699d522f475Smrg int from, to; 3700d522f475Smrg CELL old_start, old_end; 3701d522f475Smrg CELL first = *firstp; 3702d522f475Smrg CELL last = *lastp; 3703d522f475Smrg 3704d522f475Smrg TRACE(("TrackText(first=%d,%d, last=%d,%d)\n", 3705d522f475Smrg first.row, first.col, last.row, last.col)); 3706d522f475Smrg 3707d522f475Smrg old_start = screen->startH; 3708d522f475Smrg old_end = screen->endH; 37090bd37d32Smrg TRACE(("...previous(first=%d,%d, last=%d,%d)\n", 37100bd37d32Smrg old_start.row, old_start.col, 37110bd37d32Smrg old_end.row, old_end.col)); 3712d522f475Smrg if (isSameCELL(&first, &old_start) && 37130bd37d32Smrg isSameCELL(&last, &old_end)) { 3714d522f475Smrg return; 37150bd37d32Smrg } 37160bd37d32Smrg 3717d522f475Smrg screen->startH = first; 3718d522f475Smrg screen->endH = last; 3719d522f475Smrg from = Coordinate(screen, &screen->startH); 3720d522f475Smrg to = Coordinate(screen, &screen->endH); 3721d522f475Smrg if (to <= screen->startHCoord || from > screen->endHCoord) { 3722d522f475Smrg /* No overlap whatsoever between old and new hilite */ 3723d522f475Smrg ReHiliteText(xw, &old_start, &old_end); 3724d522f475Smrg ReHiliteText(xw, &first, &last); 3725d522f475Smrg } else { 3726d522f475Smrg if (from < screen->startHCoord) { 3727d522f475Smrg /* Extend left end */ 3728d522f475Smrg ReHiliteText(xw, &first, &old_start); 3729d522f475Smrg } else if (from > screen->startHCoord) { 3730d522f475Smrg /* Shorten left end */ 3731d522f475Smrg ReHiliteText(xw, &old_start, &first); 3732d522f475Smrg } 3733d522f475Smrg if (to > screen->endHCoord) { 3734d522f475Smrg /* Extend right end */ 3735d522f475Smrg ReHiliteText(xw, &old_end, &last); 3736d522f475Smrg } else if (to < screen->endHCoord) { 3737d522f475Smrg /* Shorten right end */ 3738d522f475Smrg ReHiliteText(xw, &last, &old_end); 3739d522f475Smrg } 3740d522f475Smrg } 3741d522f475Smrg screen->startHCoord = from; 3742d522f475Smrg screen->endHCoord = to; 3743d522f475Smrg} 3744d522f475Smrg 3745d522f475Smrg/* Guaranteed that (first->row, first->col) <= (last->row, last->col) */ 3746d522f475Smrgstatic void 3747d522f475SmrgReHiliteText(XtermWidget xw, 3748e0a2b6dfSmrg CELL *firstp, 3749e0a2b6dfSmrg CELL *lastp) 3750d522f475Smrg{ 3751956cc18dSsnj TScreen *screen = TScreenOf(xw); 3752d522f475Smrg CELL first = *firstp; 3753d522f475Smrg CELL last = *lastp; 3754d522f475Smrg 3755d522f475Smrg TRACE(("ReHiliteText from %d.%d to %d.%d\n", 3756d522f475Smrg first.row, first.col, last.row, last.col)); 3757d522f475Smrg 3758d522f475Smrg if (first.row < 0) 3759d522f475Smrg first.row = first.col = 0; 3760d522f475Smrg else if (first.row > screen->max_row) 3761d522f475Smrg return; /* nothing to do, since last.row >= first.row */ 3762d522f475Smrg 3763d522f475Smrg if (last.row < 0) 3764d522f475Smrg return; /* nothing to do, since first.row <= last.row */ 3765d522f475Smrg else if (last.row > screen->max_row) { 3766d522f475Smrg last.row = screen->max_row; 3767d522f475Smrg last.col = MaxCols(screen); 3768d522f475Smrg } 3769d522f475Smrg if (isSameCELL(&first, &last)) 3770d522f475Smrg return; 3771d522f475Smrg 3772d522f475Smrg if (!isSameRow(&first, &last)) { /* do multiple rows */ 37732e4f8982Smrg int i; 3774d522f475Smrg if ((i = screen->max_col - first.col + 1) > 0) { /* first row */ 3775d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, i, True); 3776d522f475Smrg } 3777d522f475Smrg if ((i = last.row - first.row - 1) > 0) { /* middle rows */ 3778d522f475Smrg ScrnRefresh(xw, first.row + 1, 0, i, MaxCols(screen), True); 3779d522f475Smrg } 3780d522f475Smrg if (last.col > 0 && last.row <= screen->max_row) { /* last row */ 3781d522f475Smrg ScrnRefresh(xw, last.row, 0, 1, last.col, True); 3782d522f475Smrg } 3783d522f475Smrg } else { /* do single row */ 3784d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, last.col - first.col, True); 3785d522f475Smrg } 3786d522f475Smrg} 3787d522f475Smrg 3788d522f475Smrg/* 3789913cc679Smrg * Guaranteed that (cellc->row, cellc->col) <= (cell->row, cell->col), 3790913cc679Smrg * and that both points are valid 3791d522f475Smrg * (may have cell->row = screen->max_row+1, cell->col = 0). 3792d522f475Smrg */ 3793d522f475Smrgstatic void 3794d522f475SmrgSaltTextAway(XtermWidget xw, 3795e0a2b6dfSmrg CELL *cellc, 3796e0a2b6dfSmrg CELL *cell) 3797d522f475Smrg{ 3798956cc18dSsnj TScreen *screen = TScreenOf(xw); 3799d522f475Smrg int i, j = 0; 3800d522f475Smrg int eol; 3801d522f475Smrg Char *line; 3802d522f475Smrg Char *lp; 3803d522f475Smrg CELL first = *cellc; 3804d522f475Smrg CELL last = *cell; 3805d522f475Smrg 3806d522f475Smrg if (isSameRow(&first, &last) && first.col > last.col) { 38072e4f8982Smrg int tmp; 3808956cc18dSsnj EXCHANGE(first.col, last.col, tmp); 3809d522f475Smrg } 3810d522f475Smrg 3811d522f475Smrg --last.col; 3812d522f475Smrg /* first we need to know how long the string is before we can save it */ 3813d522f475Smrg 3814d522f475Smrg if (isSameRow(&last, &first)) { 3815d522f475Smrg j = Length(screen, first.row, first.col, last.col); 3816d522f475Smrg } else { /* two cases, cut is on same line, cut spans multiple lines */ 3817d522f475Smrg j += Length(screen, first.row, first.col, screen->max_col) + 1; 3818d522f475Smrg for (i = first.row + 1; i < last.row; i++) 3819d522f475Smrg j += Length(screen, i, 0, screen->max_col) + 1; 3820d522f475Smrg if (last.col >= 0) 3821d522f475Smrg j += Length(screen, last.row, 0, last.col); 3822d522f475Smrg } 3823d522f475Smrg 3824d522f475Smrg /* UTF-8 may require more space */ 3825d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3826d522f475Smrg j *= 4; 3827d522f475Smrg }); 3828d522f475Smrg 3829d522f475Smrg /* now get some memory to save it in */ 3830d522f475Smrg 3831d522f475Smrg if (screen->selection_size <= j) { 383220d2c4d2Smrg if ((line = (Char *) malloc((size_t) j + 1)) == 0) 3833d522f475Smrg SysError(ERROR_BMALLOC2); 3834d522f475Smrg XtFree((char *) screen->selection_data); 3835d522f475Smrg screen->selection_data = line; 3836d522f475Smrg screen->selection_size = j + 1; 3837d522f475Smrg } else { 3838d522f475Smrg line = screen->selection_data; 3839d522f475Smrg } 3840d522f475Smrg 3841d522f475Smrg if ((line == 0) 3842d522f475Smrg || (j < 0)) 3843d522f475Smrg return; 3844d522f475Smrg 3845d522f475Smrg line[j] = '\0'; /* make sure it is null terminated */ 3846d522f475Smrg lp = line; /* lp points to where to save the text */ 3847d522f475Smrg if (isSameRow(&last, &first)) { 3848d522f475Smrg lp = SaveText(screen, last.row, first.col, last.col, lp, &eol); 3849d522f475Smrg } else { 3850d522f475Smrg lp = SaveText(screen, first.row, first.col, screen->max_col, lp, &eol); 3851d522f475Smrg if (eol) 3852d522f475Smrg *lp++ = '\n'; /* put in newline at end of line */ 3853d522f475Smrg for (i = first.row + 1; i < last.row; i++) { 3854d522f475Smrg lp = SaveText(screen, i, 0, screen->max_col, lp, &eol); 3855d522f475Smrg if (eol) 3856d522f475Smrg *lp++ = '\n'; 3857d522f475Smrg } 3858d522f475Smrg if (last.col >= 0) 3859d522f475Smrg lp = SaveText(screen, last.row, 0, last.col, lp, &eol); 3860d522f475Smrg } 3861d522f475Smrg *lp = '\0'; /* make sure we have end marked */ 3862d522f475Smrg 3863956cc18dSsnj TRACE(("Salted TEXT:%d:%s\n", (int) (lp - line), 3864956cc18dSsnj visibleChars(line, (unsigned) (lp - line)))); 3865d522f475Smrg 38662eaa94a1Schristos screen->selection_length = (unsigned long) (lp - line); 3867d522f475Smrg} 3868d522f475Smrg 3869d522f475Smrg#if OPT_PASTE64 3870d522f475Smrgvoid 3871e0a2b6dfSmrgClearSelectionBuffer(TScreen *screen) 3872d522f475Smrg{ 3873d522f475Smrg screen->selection_length = 0; 3874d522f475Smrg screen->base64_count = 0; 3875d522f475Smrg} 3876d522f475Smrg 3877d522f475Smrgstatic void 3878e0a2b6dfSmrgAppendStrToSelectionBuffer(TScreen *screen, Char *text, size_t len) 3879d522f475Smrg{ 3880d522f475Smrg if (len != 0) { 38812eaa94a1Schristos int j = (int) (screen->selection_length + len); /* New length */ 3882d522f475Smrg int k = j + (j >> 2) + 80; /* New size if we grow buffer: grow by ~50% */ 3883d522f475Smrg if (j + 1 >= screen->selection_size) { 3884d522f475Smrg if (!screen->selection_length) { 3885d522f475Smrg /* New buffer */ 3886d522f475Smrg Char *line; 388720d2c4d2Smrg if ((line = (Char *) malloc((size_t) k)) == 0) 3888d522f475Smrg SysError(ERROR_BMALLOC2); 3889d522f475Smrg XtFree((char *) screen->selection_data); 3890d522f475Smrg screen->selection_data = line; 3891d522f475Smrg } else { 3892d522f475Smrg /* Realloc buffer */ 3893d522f475Smrg screen->selection_data = (Char *) 3894d522f475Smrg realloc(screen->selection_data, 389520d2c4d2Smrg (size_t) k); 3896d522f475Smrg if (screen->selection_data == 0) 3897d522f475Smrg SysError(ERROR_BMALLOC2); 3898d522f475Smrg } 3899d522f475Smrg screen->selection_size = k; 3900d522f475Smrg } 390120d2c4d2Smrg if (screen->selection_data != 0) { 390220d2c4d2Smrg memcpy(screen->selection_data + screen->selection_length, text, len); 390320d2c4d2Smrg screen->selection_length += len; 390420d2c4d2Smrg screen->selection_data[screen->selection_length] = 0; 390520d2c4d2Smrg } 3906d522f475Smrg } 3907d522f475Smrg} 3908d522f475Smrg 3909d522f475Smrgvoid 3910e0a2b6dfSmrgAppendToSelectionBuffer(TScreen *screen, unsigned c) 3911d522f475Smrg{ 39122eaa94a1Schristos unsigned six; 3913d522f475Smrg Char ch; 3914d522f475Smrg 3915d522f475Smrg /* Decode base64 character */ 3916d522f475Smrg if (c >= 'A' && c <= 'Z') 3917d522f475Smrg six = c - 'A'; 3918d522f475Smrg else if (c >= 'a' && c <= 'z') 3919d522f475Smrg six = c - 'a' + 26; 3920d522f475Smrg else if (c >= '0' && c <= '9') 3921d522f475Smrg six = c - '0' + 52; 3922d522f475Smrg else if (c == '+') 3923d522f475Smrg six = 62; 3924d522f475Smrg else if (c == '/') 3925d522f475Smrg six = 63; 3926d522f475Smrg else 3927d522f475Smrg return; 3928d522f475Smrg 3929d522f475Smrg /* Accumulate bytes */ 3930d522f475Smrg switch (screen->base64_count) { 3931d522f475Smrg case 0: 3932d522f475Smrg screen->base64_accu = six; 3933d522f475Smrg screen->base64_count = 6; 3934d522f475Smrg break; 3935d522f475Smrg 3936d522f475Smrg case 2: 39372eaa94a1Schristos ch = CharOf((screen->base64_accu << 6) + six); 3938d522f475Smrg screen->base64_count = 0; 393920d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3940d522f475Smrg break; 3941d522f475Smrg 3942d522f475Smrg case 4: 39432eaa94a1Schristos ch = CharOf((screen->base64_accu << 4) + (six >> 2)); 3944d522f475Smrg screen->base64_accu = (six & 0x3); 3945d522f475Smrg screen->base64_count = 2; 394620d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3947d522f475Smrg break; 3948d522f475Smrg 3949d522f475Smrg case 6: 39502eaa94a1Schristos ch = CharOf((screen->base64_accu << 2) + (six >> 4)); 3951d522f475Smrg screen->base64_accu = (six & 0xF); 3952d522f475Smrg screen->base64_count = 4; 395320d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3954d522f475Smrg break; 3955d522f475Smrg } 3956d522f475Smrg} 3957d522f475Smrg 3958d522f475Smrgvoid 3959e0a2b6dfSmrgCompleteSelection(XtermWidget xw, String *args, Cardinal len) 3960d522f475Smrg{ 3961956cc18dSsnj TScreen *screen = TScreenOf(xw); 3962956cc18dSsnj 3963956cc18dSsnj screen->base64_count = 0; 3964956cc18dSsnj screen->base64_accu = 0; 3965d522f475Smrg _OwnSelection(xw, args, len); 3966d522f475Smrg} 3967d522f475Smrg#endif /* OPT_PASTE64 */ 3968d522f475Smrg 3969d522f475Smrgstatic Bool 3970d522f475Smrg_ConvertSelectionHelper(Widget w, 3971894e0ac8Smrg Atom *type, 3972d522f475Smrg XtPointer *value, 3973d522f475Smrg unsigned long *length, 39742e4f8982Smrg Char *data, 39752e4f8982Smrg unsigned long remaining, 3976d522f475Smrg int *format, 3977d522f475Smrg int (*conversion_function) (Display *, 3978d522f475Smrg char **, int, 3979d522f475Smrg XICCEncodingStyle, 3980d522f475Smrg XTextProperty *), 3981d522f475Smrg XICCEncodingStyle conversion_style) 3982d522f475Smrg{ 3983956cc18dSsnj XtermWidget xw; 3984956cc18dSsnj 398501037d57Smrg *value = 0; 398601037d57Smrg *length = 0; 398701037d57Smrg *type = 0; 398801037d57Smrg *format = 0; 398901037d57Smrg 3990956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3991956cc18dSsnj TScreen *screen = TScreenOf(xw); 3992d522f475Smrg Display *dpy = XtDisplay(w); 3993d522f475Smrg XTextProperty textprop; 399401037d57Smrg int out_n = 0; 399501037d57Smrg char *result = 0; 39962e4f8982Smrg char *the_data = (char *) data; 399701037d57Smrg char *the_next; 399801037d57Smrg 399901037d57Smrg TRACE(("converting %ld:'%s'\n", 400001037d57Smrg (long) screen->selection_length, 400101037d57Smrg visibleChars(screen->selection_data, (unsigned) screen->selection_length))); 400201037d57Smrg /* 400301037d57Smrg * For most selections, we can convert in one pass. It is possible 400401037d57Smrg * that some applications contain embedded nulls, e.g., using xterm's 400501037d57Smrg * paste64 feature. For those cases, we will build up the result in 400601037d57Smrg * parts. 400701037d57Smrg */ 400801037d57Smrg if (memchr(the_data, 0, screen->selection_length) != 0) { 400901037d57Smrg TRACE(("selection contains embedded nulls\n")); 401001037d57Smrg result = calloc(screen->selection_length + 1, sizeof(char)); 401101037d57Smrg } 4012d522f475Smrg 401301037d57Smrg next_try: 401401037d57Smrg memset(&textprop, 0, sizeof(textprop)); 4015d522f475Smrg if (conversion_function(dpy, &the_data, 1, 4016d522f475Smrg conversion_style, 4017d522f475Smrg &textprop) >= Success) { 401801037d57Smrg if ((result != 0) 401901037d57Smrg && (textprop.value != 0) 402001037d57Smrg && (textprop.format == 8)) { 402101037d57Smrg char *text_values = (char *) textprop.value; 402201037d57Smrg unsigned long in_n; 402301037d57Smrg 402401037d57Smrg if (out_n == 0) { 402501037d57Smrg *value = result; 402601037d57Smrg *type = textprop.encoding; 402701037d57Smrg *format = textprop.format; 402801037d57Smrg } 402901037d57Smrg for (in_n = 0; in_n < textprop.nitems; ++in_n) { 403001037d57Smrg result[out_n++] = text_values[in_n]; 403101037d57Smrg } 403201037d57Smrg *length += textprop.nitems; 403301037d57Smrg if ((the_next = memchr(the_data, 0, remaining)) != 0) { 403401037d57Smrg unsigned long this_was = (unsigned long) (the_next - the_data); 403501037d57Smrg this_was++; 403601037d57Smrg the_data += this_was; 403701037d57Smrg remaining -= this_was; 403801037d57Smrg result[out_n++] = 0; 403901037d57Smrg *length += 1; 404001037d57Smrg if (remaining) 404101037d57Smrg goto next_try; 404201037d57Smrg } 404301037d57Smrg return True; 404401037d57Smrg } else { 404501037d57Smrg free(result); 404601037d57Smrg *value = (XtPointer) textprop.value; 404701037d57Smrg *length = textprop.nitems; 404801037d57Smrg *type = textprop.encoding; 404901037d57Smrg *format = textprop.format; 405001037d57Smrg return True; 405101037d57Smrg } 4052d522f475Smrg } 405301037d57Smrg free(result); 4054d522f475Smrg } 4055d522f475Smrg return False; 4056d522f475Smrg} 4057d522f475Smrg 40582eaa94a1Schristosstatic Boolean 40592eaa94a1SchristosSaveConvertedLength(XtPointer *target, unsigned long source) 40602eaa94a1Schristos{ 40612eaa94a1Schristos Boolean result = False; 40622eaa94a1Schristos 40632eaa94a1Schristos *target = XtMalloc(4); 40642eaa94a1Schristos if (*target != 0) { 40652eaa94a1Schristos result = True; 40662eaa94a1Schristos if (sizeof(unsigned long) == 4) { 40672eaa94a1Schristos *(unsigned long *) *target = source; 40682eaa94a1Schristos } else if (sizeof(unsigned) == 4) { 406920d2c4d2Smrg *(unsigned *) *target = (unsigned) source; 40702eaa94a1Schristos } else if (sizeof(unsigned short) == 4) { 40712eaa94a1Schristos *(unsigned short *) *target = (unsigned short) source; 40722eaa94a1Schristos } else { 40732eaa94a1Schristos /* FIXME - does this depend on byte-order? */ 40742eaa94a1Schristos unsigned long temp = source; 407520d2c4d2Smrg memcpy((char *) *target, 407620d2c4d2Smrg ((char *) &temp) + sizeof(temp) - 4, 407720d2c4d2Smrg (size_t) 4); 40782eaa94a1Schristos } 40792eaa94a1Schristos } 40802eaa94a1Schristos return result; 40812eaa94a1Schristos} 40822eaa94a1Schristos 40832e4f8982Smrg#define keepClipboard(atom) ((screen->keepClipboard) && \ 40842e4f8982Smrg (atom == XInternAtom(screen->display, "CLIPBOARD", False))) 40852e4f8982Smrg 4086d522f475Smrgstatic Boolean 4087d522f475SmrgConvertSelection(Widget w, 4088894e0ac8Smrg Atom *selection, 4089894e0ac8Smrg Atom *target, 4090894e0ac8Smrg Atom *type, 4091d522f475Smrg XtPointer *value, 4092d522f475Smrg unsigned long *length, 4093d522f475Smrg int *format) 4094d522f475Smrg{ 4095d522f475Smrg Display *dpy = XtDisplay(w); 4096d522f475Smrg TScreen *screen; 4097d522f475Smrg Bool result = False; 4098d522f475Smrg 40992e4f8982Smrg Char *data; 41002e4f8982Smrg unsigned long data_length; 41012e4f8982Smrg 4102956cc18dSsnj XtermWidget xw; 4103956cc18dSsnj 4104956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 4105d522f475Smrg return False; 4106d522f475Smrg 4107956cc18dSsnj screen = TScreenOf(xw); 4108d522f475Smrg 4109956cc18dSsnj TRACE(("ConvertSelection %s\n", 4110956cc18dSsnj visibleSelectionTarget(dpy, *target))); 4111956cc18dSsnj 41122e4f8982Smrg if (keepClipboard(*selection)) { 41132e4f8982Smrg TRACE(("asked for clipboard\n")); 41142e4f8982Smrg data = screen->clipboard_data; 41152e4f8982Smrg data_length = screen->clipboard_size; 41162e4f8982Smrg } else { 41172e4f8982Smrg TRACE(("asked for selection\n")); 41182e4f8982Smrg data = screen->selection_data; 41192e4f8982Smrg data_length = screen->selection_length; 41202e4f8982Smrg } 41212e4f8982Smrg 41222e4f8982Smrg if (data == NULL) { 412301037d57Smrg TRACE(("...FIXME: no selection_data\n")); 412401037d57Smrg return False; /* can this happen? */ 412501037d57Smrg } 412601037d57Smrg 4127d522f475Smrg if (*target == XA_TARGETS(dpy)) { 4128d522f475Smrg Atom *targetP; 4129d522f475Smrg XPointer std_return = 0; 4130d522f475Smrg unsigned long std_length; 4131d522f475Smrg 4132d522f475Smrg if (XmuConvertStandardSelection(w, screen->selection_time, selection, 4133d522f475Smrg target, type, &std_return, 4134d522f475Smrg &std_length, format)) { 4135956cc18dSsnj Atom *my_targets = _SelectionTargets(w); 41362e4f8982Smrg Atom *allocP; 41372e4f8982Smrg Atom *std_targets; 4138956cc18dSsnj 4139956cc18dSsnj TRACE(("XmuConvertStandardSelection - success\n")); 4140a1f3da82Smrg std_targets = (Atom *) (void *) (std_return); 4141d522f475Smrg *length = std_length + 6; 4142d522f475Smrg 4143a1f3da82Smrg targetP = TypeXtMallocN(Atom, *length); 4144d522f475Smrg allocP = targetP; 4145d522f475Smrg 4146d522f475Smrg *value = (XtPointer) targetP; 4147d522f475Smrg 41480bd37d32Smrg if (my_targets != 0) { 41490bd37d32Smrg while (*my_targets != None) { 41500bd37d32Smrg *targetP++ = *my_targets++; 41510bd37d32Smrg } 4152956cc18dSsnj } 4153d522f475Smrg *targetP++ = XA_LENGTH(dpy); 4154d522f475Smrg *targetP++ = XA_LIST_LENGTH(dpy); 4155d522f475Smrg 41562eaa94a1Schristos *length = std_length + (unsigned long) (targetP - allocP); 4157d522f475Smrg 4158d522f475Smrg memcpy(targetP, std_targets, sizeof(Atom) * std_length); 4159d522f475Smrg XtFree((char *) std_targets); 4160d522f475Smrg *type = XA_ATOM; 4161d522f475Smrg *format = 32; 4162d522f475Smrg result = True; 4163956cc18dSsnj } else { 4164956cc18dSsnj TRACE(("XmuConvertStandardSelection - failed\n")); 4165d522f475Smrg } 4166d522f475Smrg } 4167d522f475Smrg#if OPT_WIDE_CHARS 4168d522f475Smrg else if (screen->wide_chars && *target == XA_STRING) { 4169d522f475Smrg result = 4170d522f475Smrg _ConvertSelectionHelper(w, 41712e4f8982Smrg type, value, length, data, 41722e4f8982Smrg data_length, format, 4173d522f475Smrg Xutf8TextListToTextProperty, 4174d522f475Smrg XStringStyle); 4175956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4176d522f475Smrg } else if (screen->wide_chars && *target == XA_UTF8_STRING(dpy)) { 4177d522f475Smrg result = 4178d522f475Smrg _ConvertSelectionHelper(w, 41792e4f8982Smrg type, value, length, data, 41802e4f8982Smrg data_length, format, 4181d522f475Smrg Xutf8TextListToTextProperty, 4182d522f475Smrg XUTF8StringStyle); 4183956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4184d522f475Smrg } else if (screen->wide_chars && *target == XA_TEXT(dpy)) { 4185d522f475Smrg result = 4186d522f475Smrg _ConvertSelectionHelper(w, 41872e4f8982Smrg type, value, length, data, 41882e4f8982Smrg data_length, format, 4189d522f475Smrg Xutf8TextListToTextProperty, 4190d522f475Smrg XStdICCTextStyle); 4191956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4192d522f475Smrg } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(dpy)) { 4193d522f475Smrg result = 4194d522f475Smrg _ConvertSelectionHelper(w, 41952e4f8982Smrg type, value, length, data, 41962e4f8982Smrg data_length, format, 4197d522f475Smrg Xutf8TextListToTextProperty, 4198d522f475Smrg XCompoundTextStyle); 4199956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 4200d522f475Smrg } 4201d522f475Smrg#endif 4202d522f475Smrg 4203d522f475Smrg else if (*target == XA_STRING) { /* not wide_chars */ 4204d522f475Smrg /* We can only reach this point if the selection requestor 4205d522f475Smrg requested STRING before any of TEXT, COMPOUND_TEXT or 4206d522f475Smrg UTF8_STRING. We therefore assume that the requestor is not 4207d522f475Smrg properly internationalised, and dump raw eight-bit data 4208d522f475Smrg with no conversion into the selection. Yes, this breaks 4209d522f475Smrg the ICCCM in non-Latin-1 locales. */ 4210d522f475Smrg *type = XA_STRING; 4211d522f475Smrg *value = (XtPointer) screen->selection_data; 4212d522f475Smrg *length = screen->selection_length; 4213d522f475Smrg *format = 8; 4214d522f475Smrg result = True; 4215956cc18dSsnj TRACE(("...raw 8-bit data:%d\n", result)); 4216d522f475Smrg } else if (*target == XA_TEXT(dpy)) { /* not wide_chars */ 4217d522f475Smrg result = 4218d522f475Smrg _ConvertSelectionHelper(w, 42192e4f8982Smrg type, value, length, data, 42202e4f8982Smrg data_length, format, 4221d522f475Smrg XmbTextListToTextProperty, 4222d522f475Smrg XStdICCTextStyle); 4223956cc18dSsnj TRACE(("...XmbTextListToTextProperty(StdICC):%d\n", result)); 4224d522f475Smrg } else if (*target == XA_COMPOUND_TEXT(dpy)) { /* not wide_chars */ 4225d522f475Smrg result = 4226d522f475Smrg _ConvertSelectionHelper(w, 42272e4f8982Smrg type, value, length, data, 42282e4f8982Smrg data_length, format, 4229d522f475Smrg XmbTextListToTextProperty, 4230d522f475Smrg XCompoundTextStyle); 4231956cc18dSsnj TRACE(("...XmbTextListToTextProperty(Compound):%d\n", result)); 4232d522f475Smrg } 4233d522f475Smrg#ifdef X_HAVE_UTF8_STRING 4234d522f475Smrg else if (*target == XA_UTF8_STRING(dpy)) { /* not wide_chars */ 4235d522f475Smrg result = 4236d522f475Smrg _ConvertSelectionHelper(w, 42372e4f8982Smrg type, value, length, data, 42382e4f8982Smrg data_length, format, 4239d522f475Smrg XmbTextListToTextProperty, 4240d522f475Smrg XUTF8StringStyle); 4241956cc18dSsnj TRACE(("...XmbTextListToTextProperty(UTF8):%d\n", result)); 4242d522f475Smrg } 4243d522f475Smrg#endif 4244d522f475Smrg else if (*target == XA_LIST_LENGTH(dpy)) { 424520d2c4d2Smrg result = SaveConvertedLength(value, (unsigned long) 1); 4246d522f475Smrg *type = XA_INTEGER; 4247d522f475Smrg *length = 1; 4248d522f475Smrg *format = 32; 4249956cc18dSsnj TRACE(("...list of values:%d\n", result)); 4250d522f475Smrg } else if (*target == XA_LENGTH(dpy)) { 4251d522f475Smrg /* This value is wrong if we have UTF-8 text */ 42522eaa94a1Schristos result = SaveConvertedLength(value, screen->selection_length); 4253d522f475Smrg *type = XA_INTEGER; 4254d522f475Smrg *length = 1; 4255d522f475Smrg *format = 32; 4256956cc18dSsnj TRACE(("...list of values:%d\n", result)); 4257d522f475Smrg } else if (XmuConvertStandardSelection(w, 4258d522f475Smrg screen->selection_time, selection, 4259d522f475Smrg target, type, (XPointer *) value, 4260d522f475Smrg length, format)) { 4261d522f475Smrg result = True; 4262956cc18dSsnj TRACE(("...XmuConvertStandardSelection:%d\n", result)); 4263d522f475Smrg } 4264d522f475Smrg 4265d522f475Smrg /* else */ 42662eaa94a1Schristos return (Boolean) result; 4267d522f475Smrg} 4268d522f475Smrg 4269d522f475Smrgstatic void 4270894e0ac8SmrgLoseSelection(Widget w, Atom *selection) 4271d522f475Smrg{ 4272d522f475Smrg TScreen *screen; 4273d522f475Smrg Atom *atomP; 4274d522f475Smrg Cardinal i; 4275d522f475Smrg 4276956cc18dSsnj XtermWidget xw; 4277956cc18dSsnj 4278956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 4279d522f475Smrg return; 4280d522f475Smrg 4281956cc18dSsnj screen = TScreenOf(xw); 4282913cc679Smrg TRACE(("LoseSelection %s\n", TraceAtomName(screen->display, *selection))); 428301037d57Smrg 4284d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 4285d522f475Smrg i < screen->selection_count; i++, atomP++) { 4286d522f475Smrg if (*selection == *atomP) 4287d522f475Smrg *atomP = (Atom) 0; 4288d522f475Smrg if (CutBuffer(*atomP) >= 0) { 4289d522f475Smrg *atomP = (Atom) 0; 4290d522f475Smrg } 4291d522f475Smrg } 4292d522f475Smrg 4293d522f475Smrg for (i = screen->selection_count; i; i--) { 4294d522f475Smrg if (screen->selection_atoms[i - 1] != 0) 4295d522f475Smrg break; 4296d522f475Smrg } 4297d522f475Smrg screen->selection_count = i; 4298d522f475Smrg 4299d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 4300d522f475Smrg i < screen->selection_count; i++, atomP++) { 4301d522f475Smrg if (*atomP == (Atom) 0) { 4302d522f475Smrg *atomP = screen->selection_atoms[--screen->selection_count]; 4303d522f475Smrg } 4304d522f475Smrg } 4305d522f475Smrg 4306d522f475Smrg if (screen->selection_count == 0) 4307956cc18dSsnj TrackText(xw, &zeroCELL, &zeroCELL); 4308d522f475Smrg} 4309d522f475Smrg 4310d522f475Smrg/* ARGSUSED */ 4311d522f475Smrgstatic void 4312d522f475SmrgSelectionDone(Widget w GCC_UNUSED, 4313894e0ac8Smrg Atom *selection GCC_UNUSED, 4314894e0ac8Smrg Atom *target GCC_UNUSED) 4315d522f475Smrg{ 4316d522f475Smrg /* empty proc so Intrinsics know we want to keep storage */ 431701037d57Smrg TRACE(("SelectionDone\n")); 4318d522f475Smrg} 4319d522f475Smrg 4320d522f475Smrgstatic void 4321d522f475Smrg_OwnSelection(XtermWidget xw, 4322e0a2b6dfSmrg String *selections, 4323d522f475Smrg Cardinal count) 4324d522f475Smrg{ 4325956cc18dSsnj TScreen *screen = TScreenOf(xw); 4326d522f475Smrg Atom *atoms = screen->selection_atoms; 4327d522f475Smrg Cardinal i; 4328d522f475Smrg Bool have_selection = False; 4329d522f475Smrg 433020d2c4d2Smrg if (count == 0) 433120d2c4d2Smrg return; 4332d522f475Smrg 433301037d57Smrg TRACE(("_OwnSelection count %d, length %ld value %s\n", count, 433401037d57Smrg screen->selection_length, 433501037d57Smrg visibleChars(screen->selection_data, (unsigned) screen->selection_length))); 4336d522f475Smrg selections = MapSelections(xw, selections, count); 4337d522f475Smrg 4338d522f475Smrg if (count > screen->sel_atoms_size) { 4339d522f475Smrg XtFree((char *) atoms); 4340a1f3da82Smrg atoms = TypeXtMallocN(Atom, count); 4341d522f475Smrg screen->selection_atoms = atoms; 4342d522f475Smrg screen->sel_atoms_size = count; 4343d522f475Smrg } 4344d522f475Smrg XmuInternStrings(XtDisplay((Widget) xw), selections, count, atoms); 4345d522f475Smrg for (i = 0; i < count; i++) { 4346d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 4347d522f475Smrg if (cutbuffer >= 0) { 43482eaa94a1Schristos unsigned long limit = 43492eaa94a1Schristos (unsigned long) (4 * XMaxRequestSize(XtDisplay((Widget) xw)) - 32); 43502eaa94a1Schristos if (screen->selection_length > limit) { 435120d2c4d2Smrg TRACE(("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 435220d2c4d2Smrg screen->selection_length, cutbuffer)); 43530bd37d32Smrg xtermWarning("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 43540bd37d32Smrg screen->selection_length, cutbuffer); 4355d522f475Smrg } else { 4356d522f475Smrg /* This used to just use the UTF-8 data, which was totally 4357894e0ac8Smrg * broken as not even the corresponding paste code in xterm 4358d522f475Smrg * understood this! So now it converts to Latin1 first. 4359d522f475Smrg * Robert Brady, 2000-09-05 4360d522f475Smrg */ 4361d522f475Smrg unsigned long length = screen->selection_length; 4362d522f475Smrg Char *data = screen->selection_data; 4363d522f475Smrg if_OPT_WIDE_CHARS((screen), { 4364956cc18dSsnj data = UTF8toLatin1(screen, data, length, &length); 4365d522f475Smrg }); 4366d522f475Smrg TRACE(("XStoreBuffer(%d)\n", cutbuffer)); 4367d522f475Smrg XStoreBuffer(XtDisplay((Widget) xw), 4368d522f475Smrg (char *) data, 4369d522f475Smrg (int) length, 4370d522f475Smrg cutbuffer); 4371d522f475Smrg } 43722e4f8982Smrg } else if (keepClipboard(atoms[i])) { 43732e4f8982Smrg Char *buf; 43742e4f8982Smrg TRACE(("saving selection to clipboard buffer\n")); 43752e4f8982Smrg if ((buf = (Char *) malloc((size_t) screen->selection_length)) 43762e4f8982Smrg == 0) 43772e4f8982Smrg SysError(ERROR_BMALLOC2); 43782e4f8982Smrg 43792e4f8982Smrg XtFree((char *) screen->clipboard_data); 43802e4f8982Smrg memcpy(buf, screen->selection_data, screen->selection_length); 43812e4f8982Smrg screen->clipboard_data = buf; 43822e4f8982Smrg screen->clipboard_size = screen->selection_length; 438301037d57Smrg } else if (screen->selection_length == 0) { 438401037d57Smrg XtDisownSelection((Widget) xw, atoms[i], screen->selection_time); 4385d522f475Smrg } else if (!screen->replyToEmacs) { 4386d522f475Smrg have_selection |= 4387d522f475Smrg XtOwnSelection((Widget) xw, atoms[i], 4388d522f475Smrg screen->selection_time, 4389d522f475Smrg ConvertSelection, LoseSelection, SelectionDone); 4390d522f475Smrg } 4391d522f475Smrg } 4392d522f475Smrg if (!screen->replyToEmacs) 4393d522f475Smrg screen->selection_count = count; 4394d522f475Smrg if (!have_selection) 4395d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 4396d522f475Smrg} 4397d522f475Smrg 4398d522f475Smrgstatic void 4399e0a2b6dfSmrgResetSelectionState(TScreen *screen) 4400d522f475Smrg{ 4401d522f475Smrg screen->selection_count = 0; 4402d522f475Smrg screen->startH = zeroCELL; 4403d522f475Smrg screen->endH = zeroCELL; 4404d522f475Smrg} 4405d522f475Smrg 4406d522f475Smrgvoid 4407d522f475SmrgDisownSelection(XtermWidget xw) 4408d522f475Smrg{ 4409956cc18dSsnj TScreen *screen = TScreenOf(xw); 4410d522f475Smrg Atom *atoms = screen->selection_atoms; 4411d522f475Smrg Cardinal count = screen->selection_count; 4412d522f475Smrg Cardinal i; 4413d522f475Smrg 4414d522f475Smrg TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n", 4415d522f475Smrg count, 4416d522f475Smrg screen->startH.row, 4417d522f475Smrg screen->startH.col, 4418d522f475Smrg screen->endH.row, 4419d522f475Smrg screen->endH.col)); 4420d522f475Smrg 4421d522f475Smrg for (i = 0; i < count; i++) { 4422d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 4423d522f475Smrg if (cutbuffer < 0) { 4424d522f475Smrg XtDisownSelection((Widget) xw, atoms[i], 4425d522f475Smrg screen->selection_time); 4426d522f475Smrg } 4427d522f475Smrg } 4428d522f475Smrg /* 4429d522f475Smrg * If none of the callbacks via XtDisownSelection() reset highlighting 4430d522f475Smrg * do it now. 4431d522f475Smrg */ 4432d522f475Smrg if (ScrnHaveSelection(screen)) { 4433d522f475Smrg /* save data which will be reset */ 4434d522f475Smrg CELL first = screen->startH; 4435d522f475Smrg CELL last = screen->endH; 4436d522f475Smrg 4437d522f475Smrg ResetSelectionState(screen); 4438d522f475Smrg ReHiliteText(xw, &first, &last); 4439d522f475Smrg } else { 4440d522f475Smrg ResetSelectionState(screen); 4441d522f475Smrg } 4442d522f475Smrg} 4443d522f475Smrg 4444d522f475Smrgvoid 4445d522f475SmrgUnhiliteSelection(XtermWidget xw) 4446d522f475Smrg{ 4447956cc18dSsnj TScreen *screen = TScreenOf(xw); 4448d522f475Smrg 4449d522f475Smrg if (ScrnHaveSelection(screen)) { 4450d522f475Smrg CELL first = screen->startH; 4451d522f475Smrg CELL last = screen->endH; 4452d522f475Smrg 4453d522f475Smrg screen->startH = zeroCELL; 4454d522f475Smrg screen->endH = zeroCELL; 4455d522f475Smrg ReHiliteText(xw, &first, &last); 4456d522f475Smrg } 4457d522f475Smrg} 4458d522f475Smrg 4459d522f475Smrg/* returns number of chars in line from scol to ecol out */ 4460d522f475Smrg/* ARGSUSED */ 4461d522f475Smrgstatic int 4462e0a2b6dfSmrgLength(TScreen *screen, 4463d522f475Smrg int row, 4464d522f475Smrg int scol, 4465d522f475Smrg int ecol) 4466d522f475Smrg{ 446701037d57Smrg CLineData *ld = GET_LINEDATA(screen, row); 446801037d57Smrg const int lastcol = LastTextCol(screen, ld, row); 4469d522f475Smrg 4470d522f475Smrg if (ecol > lastcol) 4471d522f475Smrg ecol = lastcol; 4472d522f475Smrg return (ecol - scol + 1); 4473d522f475Smrg} 4474d522f475Smrg 4475d522f475Smrg/* copies text into line, preallocated */ 4476d522f475Smrgstatic Char * 4477e0a2b6dfSmrgSaveText(TScreen *screen, 4478d522f475Smrg int row, 4479d522f475Smrg int scol, 4480d522f475Smrg int ecol, 4481e0a2b6dfSmrg Char *lp, /* pointer to where to put the text */ 4482d522f475Smrg int *eol) 4483d522f475Smrg{ 4484956cc18dSsnj LineData *ld; 4485d522f475Smrg int i = 0; 4486d522f475Smrg Char *result = lp; 4487d522f475Smrg#if OPT_WIDE_CHARS 44882eaa94a1Schristos unsigned previous = 0; 4489d522f475Smrg#endif 4490d522f475Smrg 4491956cc18dSsnj ld = GET_LINEDATA(screen, row); 4492d522f475Smrg i = Length(screen, row, scol, ecol); 4493d522f475Smrg ecol = scol + i; 4494d522f475Smrg#if OPT_DEC_CHRSET 4495956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 4496d522f475Smrg scol = (scol + 0) / 2; 4497d522f475Smrg ecol = (ecol + 1) / 2; 4498d522f475Smrg } 4499d522f475Smrg#endif 4500956cc18dSsnj *eol = !LineTstWrapped(ld); 4501d522f475Smrg for (i = scol; i < ecol; i++) { 45022e4f8982Smrg unsigned c; 45030bd37d32Smrg assert(i < (int) ld->lineSize); 4504956cc18dSsnj c = E2A(ld->charData[i]); 4505d522f475Smrg#if OPT_WIDE_CHARS 4506d522f475Smrg /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a 4507d522f475Smrg * wide character. 4508d522f475Smrg */ 4509894e0ac8Smrg if (c == HIDDEN_CHAR) { 4510894e0ac8Smrg if (isWide((int) previous)) { 4511894e0ac8Smrg previous = c; 4512894e0ac8Smrg /* Combining characters attached to double-width characters 4513894e0ac8Smrg are in memory attached to the HIDDEN_CHAR */ 4514894e0ac8Smrg if_OPT_WIDE_CHARS(screen, { 4515894e0ac8Smrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 4516894e0ac8Smrg size_t off; 4517894e0ac8Smrg for_each_combData(off, ld) { 45182e4f8982Smrg unsigned ch = ld->combData[off][i]; 4519894e0ac8Smrg if (ch == 0) 4520894e0ac8Smrg break; 4521894e0ac8Smrg lp = convertToUTF8(lp, ch); 4522894e0ac8Smrg } 4523d522f475Smrg } 4524894e0ac8Smrg }); 4525894e0ac8Smrg continue; 4526894e0ac8Smrg } else { 4527894e0ac8Smrg c = ' '; /* should not happen, but just in case... */ 4528894e0ac8Smrg } 4529d522f475Smrg } 4530d522f475Smrg previous = c; 4531e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 4532d522f475Smrg lp = convertToUTF8(lp, (c != 0) ? c : ' '); 4533d522f475Smrg if_OPT_WIDE_CHARS(screen, { 4534956cc18dSsnj size_t off; 4535956cc18dSsnj for_each_combData(off, ld) { 45362e4f8982Smrg unsigned ch = ld->combData[off][i]; 4537956cc18dSsnj if (ch == 0) 4538d522f475Smrg break; 4539d522f475Smrg lp = convertToUTF8(lp, ch); 4540d522f475Smrg } 4541d522f475Smrg }); 4542d522f475Smrg } else 4543d522f475Smrg#endif 4544d522f475Smrg { 4545d522f475Smrg if (c == 0) { 4546d522f475Smrg c = E2A(' '); 4547d522f475Smrg } else if (c < E2A(' ')) { 4548d522f475Smrg c = DECtoASCII(c); 4549d522f475Smrg } else if (c == 0x7f) { 4550d522f475Smrg c = 0x5f; 4551d522f475Smrg } 45522eaa94a1Schristos *lp++ = CharOf(A2E(c)); 4553d522f475Smrg } 4554d522f475Smrg if (c != E2A(' ')) 4555d522f475Smrg result = lp; 4556d522f475Smrg } 4557d522f475Smrg 4558d522f475Smrg /* 4559d522f475Smrg * If requested, trim trailing blanks from selected lines. Do not do this 4560d522f475Smrg * if the line is wrapped. 4561d522f475Smrg */ 4562d522f475Smrg if (!*eol || !screen->trim_selection) 4563d522f475Smrg result = lp; 4564d522f475Smrg 4565d522f475Smrg return (result); 4566d522f475Smrg} 4567d522f475Smrg 4568d522f475Smrg/* 32 + following 7-bit word: 4569d522f475Smrg 4570d522f475Smrg 1:0 Button no: 0, 1, 2. 3=release. 4571d522f475Smrg 2 shift 4572d522f475Smrg 3 meta 4573d522f475Smrg 4 ctrl 4574d522f475Smrg 5 set for motion notify 4575d522f475Smrg 6 set for wheel 4576d522f475Smrg*/ 4577d522f475Smrg 4578d522f475Smrg/* Position: 32 - 255. */ 4579a1f3da82Smrgstatic int 4580894e0ac8SmrgBtnCode(XButtonEvent *event, int button) 4581d522f475Smrg{ 45822eaa94a1Schristos int result = (int) (32 + (KeyState(event->state) << 2)); 4583d522f475Smrg 45840bd37d32Smrg if (event->type == MotionNotify) 45850bd37d32Smrg result += 32; 45860bd37d32Smrg 4587d522f475Smrg if (button < 0 || button > 5) { 4588d522f475Smrg result += 3; 4589d522f475Smrg } else { 4590d522f475Smrg if (button > 3) 4591d522f475Smrg result += (64 - 4); 4592d522f475Smrg result += button; 4593d522f475Smrg } 45940bd37d32Smrg TRACE(("BtnCode button %d, %s state " FMT_MODIFIER_NAMES " ->%#x\n", 45950bd37d32Smrg button, 45960bd37d32Smrg visibleEventType(event->type), 45970bd37d32Smrg ARG_MODIFIER_NAMES(event->state), 45980bd37d32Smrg result)); 4599a1f3da82Smrg return result; 4600a1f3da82Smrg} 4601a1f3da82Smrg 4602a1f3da82Smrgstatic unsigned 4603913cc679SmrgEmitButtonCode(XtermWidget xw, 4604e0a2b6dfSmrg Char *line, 46050bd37d32Smrg unsigned count, 4606894e0ac8Smrg XButtonEvent *event, 46070bd37d32Smrg int button) 4608a1f3da82Smrg{ 4609913cc679Smrg TScreen *screen = TScreenOf(xw); 46100bd37d32Smrg int value; 4611a1f3da82Smrg 4612913cc679Smrg if (okSendMousePos(xw) == X10_MOUSE) { 46130bd37d32Smrg value = CharOf(' ' + button); 4614a1f3da82Smrg } else { 46150bd37d32Smrg value = BtnCode(event, button); 46160bd37d32Smrg } 46170bd37d32Smrg 46180bd37d32Smrg switch (screen->extend_coords) { 46190bd37d32Smrg default: 46200bd37d32Smrg line[count++] = CharOf(value); 46210bd37d32Smrg break; 46220bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 46230bd37d32Smrg value -= 32; /* encoding starts at zero */ 46240bd37d32Smrg /* FALLTHRU */ 46250bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 46260bd37d32Smrg count += (unsigned) sprintf((char *) line + count, "%d", value); 46270bd37d32Smrg break; 46280bd37d32Smrg case SET_EXT_MODE_MOUSE: 46290bd37d32Smrg if (value < 128) { 46300bd37d32Smrg line[count++] = CharOf(value); 46310bd37d32Smrg } else { 46320bd37d32Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 46330bd37d32Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 46340bd37d32Smrg } 46350bd37d32Smrg break; 4636a1f3da82Smrg } 4637a1f3da82Smrg return count; 4638d522f475Smrg} 4639d522f475Smrg 46400bd37d32Smrgstatic int 46410bd37d32SmrgFirstBitN(int bits) 46420bd37d32Smrg{ 46430bd37d32Smrg int result = -1; 46440bd37d32Smrg if (bits > 0) { 46450bd37d32Smrg result = 0; 46460bd37d32Smrg while (!(bits & 1)) { 46470bd37d32Smrg bits /= 2; 46480bd37d32Smrg ++result; 46490bd37d32Smrg } 46500bd37d32Smrg } 46510bd37d32Smrg return result; 46520bd37d32Smrg} 46530bd37d32Smrg 46540bd37d32Smrg#define ButtonBit(button) ((button >= 0) ? (1 << (button)) : 0) 46550bd37d32Smrg 4656913cc679Smrg#define EMIT_BUTTON(button) EmitButtonCode(xw, line, count, event, button) 46570bd37d32Smrg 4658d522f475Smrgstatic void 4659894e0ac8SmrgEditorButton(XtermWidget xw, XButtonEvent *event) 4660d522f475Smrg{ 4661956cc18dSsnj TScreen *screen = TScreenOf(xw); 4662d522f475Smrg int pty = screen->respond; 46630bd37d32Smrg int mouse_limit = MouseLimit(screen); 46640bd37d32Smrg Char line[32]; 46650bd37d32Smrg Char final = 'M'; 4666d522f475Smrg int row, col; 4667d522f475Smrg int button; 4668d522f475Smrg unsigned count = 0; 4669d522f475Smrg Boolean changed = True; 4670d522f475Smrg 4671d522f475Smrg /* If button event, get button # adjusted for DEC compatibility */ 46722eaa94a1Schristos button = (int) (event->button - 1); 4673d522f475Smrg if (button >= 3) 4674d522f475Smrg button++; 4675d522f475Smrg 4676d522f475Smrg /* Compute character position of mouse pointer */ 4677d522f475Smrg row = (event->y - screen->border) / FontHeight(screen); 4678d522f475Smrg col = (event->x - OriginX(screen)) / FontWidth(screen); 4679d522f475Smrg 4680d522f475Smrg /* Limit to screen dimensions */ 4681d522f475Smrg if (row < 0) 4682d522f475Smrg row = 0; 4683d522f475Smrg else if (row > screen->max_row) 4684d522f475Smrg row = screen->max_row; 4685d522f475Smrg 4686d522f475Smrg if (col < 0) 4687d522f475Smrg col = 0; 4688d522f475Smrg else if (col > screen->max_col) 4689d522f475Smrg col = screen->max_col; 4690492d43a5Smrg 46910bd37d32Smrg if (mouse_limit > 0) { 46920bd37d32Smrg /* Limit to representable mouse dimensions */ 46930bd37d32Smrg if (row > mouse_limit) 46940bd37d32Smrg row = mouse_limit; 46950bd37d32Smrg if (col > mouse_limit) 46960bd37d32Smrg col = mouse_limit; 46970bd37d32Smrg } 4698d522f475Smrg 4699d522f475Smrg /* Build key sequence starting with \E[M */ 4700d522f475Smrg if (screen->control_eight_bits) { 4701d522f475Smrg line[count++] = ANSI_CSI; 4702d522f475Smrg } else { 4703d522f475Smrg line[count++] = ANSI_ESC; 4704d522f475Smrg line[count++] = '['; 4705d522f475Smrg } 47060bd37d32Smrg switch (screen->extend_coords) { 47070bd37d32Smrg case 0: 47080bd37d32Smrg case SET_EXT_MODE_MOUSE: 4709d522f475Smrg#if OPT_SCO_FUNC_KEYS 47100bd37d32Smrg if (xw->keyboard.type == keyboardIsSCO) { 47110bd37d32Smrg /* 47120bd37d32Smrg * SCO function key F1 is \E[M, which would conflict with xterm's 47130bd37d32Smrg * normal kmous. 47140bd37d32Smrg */ 47150bd37d32Smrg line[count++] = '>'; 47160bd37d32Smrg } 4717d522f475Smrg#endif 47180bd37d32Smrg line[count++] = final; 47190bd37d32Smrg break; 47200bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 47210bd37d32Smrg line[count++] = '<'; 47220bd37d32Smrg break; 47230bd37d32Smrg } 4724d522f475Smrg 4725d522f475Smrg /* Add event code to key sequence */ 4726913cc679Smrg if (okSendMousePos(xw) == X10_MOUSE) { 47270bd37d32Smrg count = EMIT_BUTTON(button); 4728d522f475Smrg } else { 4729d522f475Smrg /* Button-Motion events */ 4730d522f475Smrg switch (event->type) { 4731d522f475Smrg case ButtonPress: 47320bd37d32Smrg screen->mouse_button |= ButtonBit(button); 47330bd37d32Smrg count = EMIT_BUTTON(button); 4734d522f475Smrg break; 4735d522f475Smrg case ButtonRelease: 4736d522f475Smrg /* 4737d522f475Smrg * Wheel mouse interface generates release-events for buttons 4738d522f475Smrg * 4 and 5, coded here as 3 and 4 respectively. We change the 47390bd37d32Smrg * release for buttons 1..3 to a -1, which will be later mapped 47400bd37d32Smrg * into a "0" (some button was released). 4741d522f475Smrg */ 47420bd37d32Smrg screen->mouse_button &= ~ButtonBit(button); 47430bd37d32Smrg if (button < 3) { 47440bd37d32Smrg switch (screen->extend_coords) { 47450bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 47460bd37d32Smrg final = 'm'; 47470bd37d32Smrg break; 47480bd37d32Smrg default: 47490bd37d32Smrg button = -1; 47500bd37d32Smrg break; 47510bd37d32Smrg } 47520bd37d32Smrg } 47530bd37d32Smrg count = EMIT_BUTTON(button); 4754d522f475Smrg break; 4755d522f475Smrg case MotionNotify: 4756d522f475Smrg /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion 4757d522f475Smrg * events only if character cell has changed. 4758d522f475Smrg */ 4759d522f475Smrg if ((row == screen->mouse_row) 4760d522f475Smrg && (col == screen->mouse_col)) { 4761d522f475Smrg changed = False; 4762d522f475Smrg } else { 47630bd37d32Smrg count = EMIT_BUTTON(FirstBitN(screen->mouse_button)); 4764d522f475Smrg } 4765d522f475Smrg break; 4766d522f475Smrg default: 4767d522f475Smrg changed = False; 4768d522f475Smrg break; 4769d522f475Smrg } 4770d522f475Smrg } 4771d522f475Smrg 4772d522f475Smrg if (changed) { 4773d522f475Smrg screen->mouse_row = row; 4774d522f475Smrg screen->mouse_col = col; 4775d522f475Smrg 4776492d43a5Smrg TRACE(("mouse at %d,%d button+mask = %#x\n", row, col, line[count - 1])); 4777d522f475Smrg 4778492d43a5Smrg /* Add pointer position to key sequence */ 47790bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 4780492d43a5Smrg count = EmitMousePosition(screen, line, count, col); 47810bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 4782492d43a5Smrg count = EmitMousePosition(screen, line, count, row); 4783d522f475Smrg 47840bd37d32Smrg switch (screen->extend_coords) { 47850bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 47860bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 47870bd37d32Smrg line[count++] = final; 47880bd37d32Smrg break; 47890bd37d32Smrg } 47900bd37d32Smrg 4791d522f475Smrg /* Transmit key sequence to process running under xterm */ 4792d522f475Smrg v_write(pty, line, count); 4793d522f475Smrg } 4794d522f475Smrg return; 4795d522f475Smrg} 4796d522f475Smrg 4797913cc679Smrg/* 4798913cc679Smrg * Check the current send_mouse_pos against allowed mouse-operations, returning 4799913cc679Smrg * none if it is disallowed. 4800913cc679Smrg */ 4801913cc679SmrgXtermMouseModes 4802913cc679SmrgokSendMousePos(XtermWidget xw) 4803913cc679Smrg{ 4804913cc679Smrg TScreen *screen = TScreenOf(xw); 4805913cc679Smrg XtermMouseModes result = screen->send_mouse_pos; 4806913cc679Smrg 4807913cc679Smrg switch (result) { 4808913cc679Smrg case MOUSE_OFF: 4809913cc679Smrg break; 4810913cc679Smrg case X10_MOUSE: 4811913cc679Smrg if (!AllowMouseOps(xw, emX10)) 4812913cc679Smrg result = MOUSE_OFF; 4813913cc679Smrg break; 4814913cc679Smrg case VT200_MOUSE: 4815913cc679Smrg if (!AllowMouseOps(xw, emVT200Click)) 4816913cc679Smrg result = MOUSE_OFF; 4817913cc679Smrg break; 4818913cc679Smrg case VT200_HIGHLIGHT_MOUSE: 4819913cc679Smrg if (!AllowMouseOps(xw, emVT200Hilite)) 4820913cc679Smrg result = MOUSE_OFF; 4821913cc679Smrg break; 4822913cc679Smrg case BTN_EVENT_MOUSE: 4823913cc679Smrg if (!AllowMouseOps(xw, emAnyButton)) 4824913cc679Smrg result = MOUSE_OFF; 4825913cc679Smrg break; 4826913cc679Smrg case ANY_EVENT_MOUSE: 4827913cc679Smrg if (!AllowMouseOps(xw, emAnyEvent)) 4828913cc679Smrg result = MOUSE_OFF; 4829913cc679Smrg break; 4830913cc679Smrg case DEC_LOCATOR: 4831913cc679Smrg if (!AllowMouseOps(xw, emLocator)) 4832913cc679Smrg result = MOUSE_OFF; 4833913cc679Smrg break; 4834913cc679Smrg } 4835913cc679Smrg return result; 4836913cc679Smrg} 4837913cc679Smrg 4838d522f475Smrg#if OPT_FOCUS_EVENT 4839913cc679Smrg/* 4840913cc679Smrg * Check the current send_focus_pos against allowed mouse-operations, returning 4841913cc679Smrg * none if it is disallowed. 4842913cc679Smrg */ 4843913cc679Smrgstatic int 4844913cc679SmrgokSendFocusPos(XtermWidget xw) 4845d522f475Smrg{ 4846956cc18dSsnj TScreen *screen = TScreenOf(xw); 4847913cc679Smrg int result = screen->send_focus_pos; 4848913cc679Smrg 4849913cc679Smrg if (!AllowMouseOps(xw, emFocusEvent)) { 4850913cc679Smrg result = False; 4851913cc679Smrg } 4852913cc679Smrg return result; 4853913cc679Smrg} 4854d522f475Smrg 4855913cc679Smrgvoid 4856913cc679SmrgSendFocusButton(XtermWidget xw, XFocusChangeEvent *event) 4857913cc679Smrg{ 4858913cc679Smrg if (okSendFocusPos(xw)) { 4859d522f475Smrg ANSI reply; 4860d522f475Smrg 4861d522f475Smrg memset(&reply, 0, sizeof(reply)); 4862d522f475Smrg reply.a_type = ANSI_CSI; 4863d522f475Smrg 4864d522f475Smrg#if OPT_SCO_FUNC_KEYS 4865d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 4866d522f475Smrg reply.a_pintro = '>'; 4867d522f475Smrg } 4868d522f475Smrg#endif 48692eaa94a1Schristos reply.a_final = CharOf((event->type == FocusIn) ? 'I' : 'O'); 4870d522f475Smrg unparseseq(xw, &reply); 4871d522f475Smrg } 4872d522f475Smrg return; 4873d522f475Smrg} 4874d522f475Smrg#endif /* OPT_FOCUS_EVENT */ 48750bd37d32Smrg 48760bd37d32Smrg#if OPT_SELECTION_OPS 48770bd37d32Smrg/* 48780bd37d32Smrg * Get the event-time, needed to process selections. 48790bd37d32Smrg */ 48800bd37d32Smrgstatic Time 4881894e0ac8SmrggetEventTime(XEvent *event) 48820bd37d32Smrg{ 48830bd37d32Smrg Time result; 48840bd37d32Smrg 48850bd37d32Smrg if (IsBtnEvent(event)) { 48860bd37d32Smrg result = ((XButtonEvent *) event)->time; 48870bd37d32Smrg } else if (IsKeyEvent(event)) { 48880bd37d32Smrg result = ((XKeyEvent *) event)->time; 48890bd37d32Smrg } else { 48900bd37d32Smrg result = 0; 48910bd37d32Smrg } 48920bd37d32Smrg 48930bd37d32Smrg return result; 48940bd37d32Smrg} 48950bd37d32Smrg 48960bd37d32Smrg/* obtain the selection string, passing the endpoints to caller's parameters */ 489701037d57Smrgstatic void 489801037d57SmrgdoSelectionFormat(XtermWidget xw, 489901037d57Smrg Widget w, 490001037d57Smrg XEvent *event, 490101037d57Smrg String *params, 490201037d57Smrg Cardinal *num_params, 490301037d57Smrg FormatSelect format_select) 49040bd37d32Smrg{ 49050bd37d32Smrg TScreen *screen = TScreenOf(xw); 490601037d57Smrg InternalSelect *mydata = &(screen->internal_select); 490701037d57Smrg 490801037d57Smrg memset(mydata, 0, sizeof(*mydata)); 490901037d57Smrg mydata->format = x_strdup(params[0]); 491001037d57Smrg mydata->format_select = format_select; 49110bd37d32Smrg 49120bd37d32Smrg /* override flags so that SelectionReceived only updates a buffer */ 49130bd37d32Smrg#if OPT_PASTE64 491401037d57Smrg mydata->base64_paste = screen->base64_paste; 49150bd37d32Smrg screen->base64_paste = 0; 49160bd37d32Smrg#endif 49170bd37d32Smrg#if OPT_READLINE 491801037d57Smrg mydata->paste_brackets = screen->paste_brackets; 49190bd37d32Smrg SCREEN_FLAG_unset(screen, paste_brackets); 49200bd37d32Smrg#endif 49210bd37d32Smrg 49220bd37d32Smrg screen->selectToBuffer = True; 49230bd37d32Smrg xtermGetSelection(w, getEventTime(event), params + 1, *num_params - 1, NULL); 49240bd37d32Smrg} 49250bd37d32Smrg 49260bd37d32Smrg/* obtain data from the screen, passing the endpoints to caller's parameters */ 49270bd37d32Smrgstatic char * 4928913cc679SmrggetDataFromScreen(XtermWidget xw, XEvent *event, String method, CELL *start, CELL *finish) 49290bd37d32Smrg{ 49300bd37d32Smrg TScreen *screen = TScreenOf(xw); 49310bd37d32Smrg 49320bd37d32Smrg CELL save_old_start = screen->startH; 49330bd37d32Smrg CELL save_old_end = screen->endH; 49340bd37d32Smrg 49350bd37d32Smrg CELL save_startSel = screen->startSel; 49360bd37d32Smrg CELL save_startRaw = screen->startRaw; 49370bd37d32Smrg CELL save_finishSel = screen->endSel; 49380bd37d32Smrg CELL save_finishRaw = screen->endRaw; 49390bd37d32Smrg 49400bd37d32Smrg int save_firstValidRow = screen->firstValidRow; 49410bd37d32Smrg int save_lastValidRow = screen->lastValidRow; 49420bd37d32Smrg 494301037d57Smrg const Cardinal noClick = 0; 494401037d57Smrg int save_numberOfClicks = screen->numberOfClicks; 494501037d57Smrg 49460bd37d32Smrg SelectUnit saveUnits = screen->selectUnit; 494701037d57Smrg SelectUnit saveMap = screen->selectMap[noClick]; 49480bd37d32Smrg#if OPT_SELECT_REGEX 494901037d57Smrg char *saveExpr = screen->selectExpr[noClick]; 49500bd37d32Smrg#endif 49510bd37d32Smrg 49520bd37d32Smrg Char *save_selection_data = screen->selection_data; 49530bd37d32Smrg int save_selection_size = screen->selection_size; 49540bd37d32Smrg unsigned long save_selection_length = screen->selection_length; 49550bd37d32Smrg 49560bd37d32Smrg char *result = 0; 49570bd37d32Smrg 49580bd37d32Smrg TRACE(("getDataFromScreen %s\n", method)); 49590bd37d32Smrg 49600bd37d32Smrg screen->selection_data = 0; 49610bd37d32Smrg screen->selection_size = 0; 49620bd37d32Smrg screen->selection_length = 0; 49630bd37d32Smrg 496401037d57Smrg screen->numberOfClicks = 1; 496501037d57Smrg lookupSelectUnit(xw, noClick, method); 496601037d57Smrg screen->selectUnit = screen->selectMap[noClick]; 49670bd37d32Smrg 49680bd37d32Smrg memset(start, 0, sizeof(*start)); 4969913cc679Smrg if (IsBtnEvent(event)) { 4970913cc679Smrg XButtonEvent *btn_event = (XButtonEvent *) event; 4971913cc679Smrg CELL cell; 4972913cc679Smrg screen->firstValidRow = 0; 4973913cc679Smrg screen->lastValidRow = screen->max_row; 4974913cc679Smrg PointToCELL(screen, btn_event->y, btn_event->x, &cell); 4975913cc679Smrg start->row = cell.row; 4976913cc679Smrg start->col = cell.col; 4977913cc679Smrg finish->row = cell.row; 4978913cc679Smrg finish->col = screen->max_col; 4979913cc679Smrg } else { 4980913cc679Smrg start->row = screen->cur_row; 4981913cc679Smrg start->col = screen->cur_col; 4982913cc679Smrg finish->row = screen->cur_row; 4983913cc679Smrg finish->col = screen->max_col; 4984913cc679Smrg } 49850bd37d32Smrg 49860bd37d32Smrg ComputeSelect(xw, start, finish, False); 49870bd37d32Smrg SaltTextAway(xw, &(screen->startSel), &(screen->endSel)); 49880bd37d32Smrg 49890bd37d32Smrg if (screen->selection_length && screen->selection_data) { 49900bd37d32Smrg TRACE(("...getDataFromScreen selection_data %.*s\n", 49910bd37d32Smrg (int) screen->selection_length, 49920bd37d32Smrg screen->selection_data)); 49930bd37d32Smrg result = malloc(screen->selection_length + 1); 49940bd37d32Smrg if (result) { 49950bd37d32Smrg memcpy(result, screen->selection_data, screen->selection_length); 49960bd37d32Smrg result[screen->selection_length] = 0; 49970bd37d32Smrg } 49980bd37d32Smrg free(screen->selection_data); 49990bd37d32Smrg } 50000bd37d32Smrg 50010bd37d32Smrg TRACE(("...getDataFromScreen restoring previous selection\n")); 50020bd37d32Smrg 50030bd37d32Smrg screen->startSel = save_startSel; 50040bd37d32Smrg screen->startRaw = save_startRaw; 50050bd37d32Smrg screen->endSel = save_finishSel; 50060bd37d32Smrg screen->endRaw = save_finishRaw; 50070bd37d32Smrg 50080bd37d32Smrg screen->firstValidRow = save_firstValidRow; 50090bd37d32Smrg screen->lastValidRow = save_lastValidRow; 50100bd37d32Smrg 501101037d57Smrg screen->numberOfClicks = save_numberOfClicks; 50120bd37d32Smrg screen->selectUnit = saveUnits; 501301037d57Smrg screen->selectMap[noClick] = saveMap; 50140bd37d32Smrg#if OPT_SELECT_REGEX 501501037d57Smrg screen->selectExpr[noClick] = saveExpr; 50160bd37d32Smrg#endif 50170bd37d32Smrg 50180bd37d32Smrg screen->selection_data = save_selection_data; 50190bd37d32Smrg screen->selection_size = save_selection_size; 50200bd37d32Smrg screen->selection_length = save_selection_length; 50210bd37d32Smrg 50220bd37d32Smrg TrackText(xw, &save_old_start, &save_old_end); 50230bd37d32Smrg 50240bd37d32Smrg TRACE(("...getDataFromScreen done\n")); 50250bd37d32Smrg return result; 50260bd37d32Smrg} 50270bd37d32Smrg 50280bd37d32Smrg/* 50290bd37d32Smrg * Split-up the format before substituting data, to avoid quoting issues. 50300bd37d32Smrg * The resource mechanism has a limited ability to handle escapes. We take 50310bd37d32Smrg * the result as if it were an sh-type string and parse it into a regular 50320bd37d32Smrg * argv array. 50330bd37d32Smrg */ 50340bd37d32Smrgstatic char ** 50350bd37d32SmrgtokenizeFormat(String format) 50360bd37d32Smrg{ 50370bd37d32Smrg char **result = 0; 50380bd37d32Smrg int argc; 50390bd37d32Smrg 50400bd37d32Smrg format = x_skip_blanks(format); 50410bd37d32Smrg if (*format != '\0') { 50420bd37d32Smrg char *blob = x_strdup(format); 50432e4f8982Smrg int pass; 50440bd37d32Smrg 50450bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 50460bd37d32Smrg int used = 0; 50470bd37d32Smrg int first = 1; 50480bd37d32Smrg int escaped = 0; 50490bd37d32Smrg int squoted = 0; 50500bd37d32Smrg int dquoted = 0; 50512e4f8982Smrg int n; 50520bd37d32Smrg 50530bd37d32Smrg argc = 0; 50540bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 50550bd37d32Smrg if (escaped) { 50560bd37d32Smrg blob[used++] = format[n]; 50570bd37d32Smrg escaped = 0; 50580bd37d32Smrg } else if (format[n] == '"') { 50590bd37d32Smrg if (!squoted) { 50600bd37d32Smrg if (!dquoted) 50610bd37d32Smrg blob[used++] = format[n]; 50620bd37d32Smrg dquoted = !dquoted; 50630bd37d32Smrg } 50640bd37d32Smrg } else if (format[n] == '\'') { 50650bd37d32Smrg if (!dquoted) { 50660bd37d32Smrg if (!squoted) 50670bd37d32Smrg blob[used++] = format[n]; 50680bd37d32Smrg squoted = !squoted; 50690bd37d32Smrg } 50700bd37d32Smrg } else if (format[n] == '\\') { 50710bd37d32Smrg blob[used++] = format[n]; 50720bd37d32Smrg escaped = 1; 50730bd37d32Smrg } else { 50740bd37d32Smrg if (first) { 50750bd37d32Smrg first = 0; 50760bd37d32Smrg if (pass) { 50770bd37d32Smrg result[argc] = &blob[n]; 50780bd37d32Smrg } 50790bd37d32Smrg ++argc; 50800bd37d32Smrg } 50810bd37d32Smrg if (isspace((Char) format[n])) { 50820bd37d32Smrg first = !isspace((Char) format[n + 1]); 50830bd37d32Smrg if (squoted || dquoted) { 50840bd37d32Smrg blob[used++] = format[n]; 50850bd37d32Smrg } else if (first) { 50860bd37d32Smrg blob[used++] = '\0'; 50870bd37d32Smrg } 50880bd37d32Smrg } else { 50890bd37d32Smrg blob[used++] = format[n]; 50900bd37d32Smrg } 50910bd37d32Smrg } 50920bd37d32Smrg } 50930bd37d32Smrg blob[used] = '\0'; 50940bd37d32Smrg assert(strlen(blob) <= strlen(format)); 50950bd37d32Smrg if (!pass) { 50960bd37d32Smrg result = TypeCallocN(char *, argc + 1); 50970bd37d32Smrg if (result == 0) { 50980bd37d32Smrg free(blob); 50990bd37d32Smrg break; 51000bd37d32Smrg } 51010bd37d32Smrg } 51020bd37d32Smrg } 51030bd37d32Smrg } 51040bd37d32Smrg#if OPT_TRACE 51050bd37d32Smrg if (result) { 51060bd37d32Smrg TRACE(("tokenizeFormat %s\n", format)); 51070bd37d32Smrg for (argc = 0; result[argc]; ++argc) { 51080bd37d32Smrg TRACE(("argv[%d] = %s\n", argc, result[argc])); 51090bd37d32Smrg } 51100bd37d32Smrg } 51110bd37d32Smrg#endif 51120bd37d32Smrg 51130bd37d32Smrg return result; 51140bd37d32Smrg} 51150bd37d32Smrg 51160bd37d32Smrgstatic void 5117e0a2b6dfSmrgformatVideoAttrs(XtermWidget xw, char *buffer, CELL *cell) 51180bd37d32Smrg{ 51190bd37d32Smrg TScreen *screen = TScreenOf(xw); 51200bd37d32Smrg LineData *ld = GET_LINEDATA(screen, cell->row); 51210bd37d32Smrg 51220bd37d32Smrg *buffer = '\0'; 51230bd37d32Smrg if (ld != 0 && cell->col < (int) ld->lineSize) { 5124894e0ac8Smrg IAttr attribs = ld->attribs[cell->col]; 51250bd37d32Smrg const char *delim = ""; 51260bd37d32Smrg 51270bd37d32Smrg if (attribs & INVERSE) { 51280bd37d32Smrg buffer += sprintf(buffer, "7"); 51290bd37d32Smrg delim = ";"; 51300bd37d32Smrg } 51310bd37d32Smrg if (attribs & UNDERLINE) { 51320bd37d32Smrg buffer += sprintf(buffer, "%s4", delim); 51330bd37d32Smrg delim = ";"; 51340bd37d32Smrg } 51350bd37d32Smrg if (attribs & BOLD) { 51360bd37d32Smrg buffer += sprintf(buffer, "%s1", delim); 51370bd37d32Smrg delim = ";"; 51380bd37d32Smrg } 51390bd37d32Smrg if (attribs & BLINK) { 51400bd37d32Smrg buffer += sprintf(buffer, "%s5", delim); 51410bd37d32Smrg delim = ";"; 51420bd37d32Smrg } 51430bd37d32Smrg#if OPT_ISO_COLORS 51440bd37d32Smrg if (attribs & FG_COLOR) { 51450bd37d32Smrg unsigned fg = extract_fg(xw, ld->color[cell->col], attribs); 51460bd37d32Smrg if (fg < 8) { 51470bd37d32Smrg fg += 30; 51480bd37d32Smrg } else if (fg < 16) { 51490bd37d32Smrg fg += 90; 51500bd37d32Smrg } else { 51510bd37d32Smrg buffer += sprintf(buffer, "%s38;5", delim); 51520bd37d32Smrg delim = ";"; 51530bd37d32Smrg } 51540bd37d32Smrg buffer += sprintf(buffer, "%s%u", delim, fg); 51550bd37d32Smrg delim = ";"; 51560bd37d32Smrg } 51570bd37d32Smrg if (attribs & BG_COLOR) { 51580bd37d32Smrg unsigned bg = extract_bg(xw, ld->color[cell->col], attribs); 51590bd37d32Smrg if (bg < 8) { 51600bd37d32Smrg bg += 40; 51610bd37d32Smrg } else if (bg < 16) { 51620bd37d32Smrg bg += 100; 51630bd37d32Smrg } else { 51640bd37d32Smrg buffer += sprintf(buffer, "%s48;5", delim); 51650bd37d32Smrg delim = ";"; 51660bd37d32Smrg } 51670bd37d32Smrg (void) sprintf(buffer, "%s%u", delim, bg); 51680bd37d32Smrg } 51690bd37d32Smrg#endif 51700bd37d32Smrg } 51710bd37d32Smrg} 51720bd37d32Smrg 51732e4f8982Smrgstatic char * 51742e4f8982SmrgformatStrlen(char *target, char *source, int freeit) 51752e4f8982Smrg{ 51762e4f8982Smrg if (source != 0) { 51772e4f8982Smrg sprintf(target, "%u", (unsigned) strlen(source)); 51782e4f8982Smrg if (freeit) { 51792e4f8982Smrg free(source); 51802e4f8982Smrg } 51812e4f8982Smrg } else { 51822e4f8982Smrg strcpy(target, "0"); 51832e4f8982Smrg } 51842e4f8982Smrg return target; 51852e4f8982Smrg} 51862e4f8982Smrg 51870bd37d32Smrg/* substitute data into format, reallocating the result */ 51880bd37d32Smrgstatic char * 51890bd37d32SmrgexpandFormat(XtermWidget xw, 51900bd37d32Smrg const char *format, 51910bd37d32Smrg char *data, 5192e0a2b6dfSmrg CELL *start, 5193e0a2b6dfSmrg CELL *finish) 51940bd37d32Smrg{ 51950bd37d32Smrg char *result = 0; 51960bd37d32Smrg if (!IsEmpty(format)) { 51970bd37d32Smrg static char empty[1]; 51980bd37d32Smrg int pass; 51990bd37d32Smrg int n; 52000bd37d32Smrg char numbers[80]; 52010bd37d32Smrg 52020bd37d32Smrg if (data == 0) 52030bd37d32Smrg data = empty; 52040bd37d32Smrg 52050bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 52060bd37d32Smrg size_t need = 0; 52070bd37d32Smrg 52080bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 52090bd37d32Smrg 52100bd37d32Smrg if (format[n] == '%') { 52112e4f8982Smrg char *value = 0; 52122e4f8982Smrg 52130bd37d32Smrg switch (format[++n]) { 52140bd37d32Smrg case '%': 52150bd37d32Smrg if (pass) { 52160bd37d32Smrg result[need] = format[n]; 52170bd37d32Smrg } 52180bd37d32Smrg ++need; 52190bd37d32Smrg break; 52200bd37d32Smrg case 'P': 52210bd37d32Smrg sprintf(numbers, "%d;%d", 52220bd37d32Smrg TScreenOf(xw)->topline + start->row + 1, 52230bd37d32Smrg start->col + 1); 52240bd37d32Smrg value = numbers; 52250bd37d32Smrg break; 52260bd37d32Smrg case 'p': 52270bd37d32Smrg sprintf(numbers, "%d;%d", 52280bd37d32Smrg TScreenOf(xw)->topline + finish->row + 1, 52290bd37d32Smrg finish->col + 1); 52300bd37d32Smrg value = numbers; 52310bd37d32Smrg break; 52322e4f8982Smrg case 'R': 52332e4f8982Smrg value = formatStrlen(numbers, x_strrtrim(data), 1); 52342e4f8982Smrg break; 52352e4f8982Smrg case 'r': 52362e4f8982Smrg value = x_strrtrim(data); 52372e4f8982Smrg break; 52380bd37d32Smrg case 'S': 52392e4f8982Smrg value = formatStrlen(numbers, data, 0); 52400bd37d32Smrg break; 52410bd37d32Smrg case 's': 52420bd37d32Smrg value = data; 52430bd37d32Smrg break; 52440bd37d32Smrg case 'T': 52452e4f8982Smrg value = formatStrlen(numbers, x_strtrim(data), 1); 52460bd37d32Smrg break; 52470bd37d32Smrg case 't': 52480bd37d32Smrg value = x_strtrim(data); 52490bd37d32Smrg break; 52500bd37d32Smrg case 'V': 52510bd37d32Smrg formatVideoAttrs(xw, numbers, start); 52520bd37d32Smrg value = numbers; 52530bd37d32Smrg break; 52540bd37d32Smrg case 'v': 52550bd37d32Smrg formatVideoAttrs(xw, numbers, finish); 52560bd37d32Smrg value = numbers; 52570bd37d32Smrg break; 52580bd37d32Smrg default: 52590bd37d32Smrg if (pass) { 52600bd37d32Smrg result[need] = format[n]; 52610bd37d32Smrg } 52620bd37d32Smrg --n; 52630bd37d32Smrg ++need; 52640bd37d32Smrg break; 52650bd37d32Smrg } 52660bd37d32Smrg if (value != 0) { 52670bd37d32Smrg if (pass) { 52680bd37d32Smrg strcpy(result + need, value); 52690bd37d32Smrg } 52700bd37d32Smrg need += strlen(value); 52710bd37d32Smrg if (value != numbers && value != data) { 52720bd37d32Smrg free(value); 52730bd37d32Smrg } 52740bd37d32Smrg } 52750bd37d32Smrg } else { 52760bd37d32Smrg if (pass) { 52770bd37d32Smrg result[need] = format[n]; 52780bd37d32Smrg } 52790bd37d32Smrg ++need; 52800bd37d32Smrg } 52810bd37d32Smrg } 52820bd37d32Smrg if (pass) { 52830bd37d32Smrg result[need] = '\0'; 52840bd37d32Smrg } else { 52850bd37d32Smrg ++need; 52860bd37d32Smrg result = malloc(need); 52870bd37d32Smrg if (result == 0) { 52880bd37d32Smrg break; 52890bd37d32Smrg } 52900bd37d32Smrg } 52910bd37d32Smrg } 52920bd37d32Smrg } 52930bd37d32Smrg TRACE(("expandFormat(%s) = %s\n", NonNull(format), NonNull(result))); 52940bd37d32Smrg return result; 52950bd37d32Smrg} 52960bd37d32Smrg 52970bd37d32Smrg/* execute the command after forking. The main process frees its data */ 52980bd37d32Smrgstatic void 52992e4f8982SmrgexecuteCommand(pid_t pid, char **argv) 53000bd37d32Smrg{ 53012e4f8982Smrg (void) pid; 53020bd37d32Smrg if (argv != 0 && argv[0] != 0) { 53032e4f8982Smrg char *child_cwd = ProcGetCWD(pid); 53042e4f8982Smrg 53050bd37d32Smrg if (fork() == 0) { 53062e4f8982Smrg if (child_cwd) { 53072e4f8982Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 53082e4f8982Smrg } 53090bd37d32Smrg execvp(argv[0], argv); 53100bd37d32Smrg exit(EXIT_FAILURE); 53110bd37d32Smrg } 5312913cc679Smrg free(child_cwd); 53130bd37d32Smrg } 53140bd37d32Smrg} 53150bd37d32Smrg 53160bd37d32Smrgstatic void 53170bd37d32SmrgfreeArgv(char *blob, char **argv) 53180bd37d32Smrg{ 53190bd37d32Smrg if (blob) { 53200bd37d32Smrg free(blob); 53210bd37d32Smrg if (argv) { 53222e4f8982Smrg int n; 53230bd37d32Smrg for (n = 0; argv[n]; ++n) 53240bd37d32Smrg free(argv[n]); 53250bd37d32Smrg free(argv); 53260bd37d32Smrg } 53270bd37d32Smrg } 53280bd37d32Smrg} 53290bd37d32Smrg 533001037d57Smrgstatic void 533101037d57SmrgreallyExecFormatted(Widget w, char *format, char *data, CELL *start, CELL *finish) 533201037d57Smrg{ 533301037d57Smrg XtermWidget xw; 533401037d57Smrg 533501037d57Smrg if ((xw = getXtermWidget(w)) != 0) { 533601037d57Smrg char **argv; 533701037d57Smrg 533801037d57Smrg if ((argv = tokenizeFormat(format)) != 0) { 53392e4f8982Smrg char *blob = argv[0]; 53402e4f8982Smrg int argc; 53412e4f8982Smrg 534201037d57Smrg for (argc = 0; argv[argc] != 0; ++argc) { 534301037d57Smrg argv[argc] = expandFormat(xw, argv[argc], data, start, finish); 534401037d57Smrg } 53452e4f8982Smrg executeCommand(TScreenOf(xw)->pid, argv); 534601037d57Smrg freeArgv(blob, argv); 534701037d57Smrg } 534801037d57Smrg } 534901037d57Smrg} 535001037d57Smrg 53510bd37d32Smrgvoid 53520bd37d32SmrgHandleExecFormatted(Widget w, 535301037d57Smrg XEvent *event, 5354e0a2b6dfSmrg String *params, /* selections */ 53550bd37d32Smrg Cardinal *num_params) 53560bd37d32Smrg{ 53570bd37d32Smrg XtermWidget xw; 53580bd37d32Smrg 535901037d57Smrg TRACE(("HandleExecFormatted(%d)\n", *num_params)); 536001037d57Smrg if ((xw = getXtermWidget(w)) != 0 && 536101037d57Smrg (*num_params > 1)) { 536201037d57Smrg doSelectionFormat(xw, w, event, params, num_params, reallyExecFormatted); 53630bd37d32Smrg } 53640bd37d32Smrg} 53650bd37d32Smrg 53660bd37d32Smrgvoid 53670bd37d32SmrgHandleExecSelectable(Widget w, 5368913cc679Smrg XEvent *event, 5369e0a2b6dfSmrg String *params, /* selections */ 53700bd37d32Smrg Cardinal *num_params) 53710bd37d32Smrg{ 53720bd37d32Smrg XtermWidget xw; 53730bd37d32Smrg 53740bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 53750bd37d32Smrg TRACE(("HandleExecSelectable(%d)\n", *num_params)); 53760bd37d32Smrg 53770bd37d32Smrg if (*num_params == 2) { 53780bd37d32Smrg CELL start, finish; 53790bd37d32Smrg char *data; 53800bd37d32Smrg char **argv; 53810bd37d32Smrg 5382913cc679Smrg data = getDataFromScreen(xw, event, params[1], &start, &finish); 53830bd37d32Smrg if (data != 0) { 53840bd37d32Smrg if ((argv = tokenizeFormat(params[0])) != 0) { 53852e4f8982Smrg char *blob = argv[0]; 53862e4f8982Smrg int argc; 53872e4f8982Smrg 53880bd37d32Smrg for (argc = 0; argv[argc] != 0; ++argc) { 53890bd37d32Smrg argv[argc] = expandFormat(xw, argv[argc], data, 53900bd37d32Smrg &start, &finish); 53910bd37d32Smrg } 53922e4f8982Smrg executeCommand(TScreenOf(xw)->pid, argv); 53930bd37d32Smrg freeArgv(blob, argv); 53940bd37d32Smrg } 5395894e0ac8Smrg free(data); 53960bd37d32Smrg } 53970bd37d32Smrg } 53980bd37d32Smrg } 53990bd37d32Smrg} 54000bd37d32Smrg 540101037d57Smrgstatic void 540201037d57SmrgreallyInsertFormatted(Widget w, char *format, char *data, CELL *start, CELL *finish) 540301037d57Smrg{ 540401037d57Smrg XtermWidget xw; 540501037d57Smrg 540601037d57Smrg if ((xw = getXtermWidget(w)) != 0) { 540701037d57Smrg char *exps; 540801037d57Smrg 540901037d57Smrg if ((exps = expandFormat(xw, format, data, start, finish)) != 0) { 541001037d57Smrg unparseputs(xw, exps); 541101037d57Smrg unparse_end(xw); 541201037d57Smrg free(exps); 541301037d57Smrg } 541401037d57Smrg } 541501037d57Smrg} 541601037d57Smrg 54170bd37d32Smrgvoid 54180bd37d32SmrgHandleInsertFormatted(Widget w, 541901037d57Smrg XEvent *event, 5420e0a2b6dfSmrg String *params, /* selections */ 54210bd37d32Smrg Cardinal *num_params) 54220bd37d32Smrg{ 54230bd37d32Smrg XtermWidget xw; 54240bd37d32Smrg 542501037d57Smrg TRACE(("HandleInsertFormatted(%d)\n", *num_params)); 542601037d57Smrg if ((xw = getXtermWidget(w)) != 0 && 542701037d57Smrg (*num_params > 1)) { 542801037d57Smrg doSelectionFormat(xw, w, event, params, num_params, reallyInsertFormatted); 54290bd37d32Smrg } 54300bd37d32Smrg} 54310bd37d32Smrg 54320bd37d32Smrgvoid 54330bd37d32SmrgHandleInsertSelectable(Widget w, 5434913cc679Smrg XEvent *event, 5435e0a2b6dfSmrg String *params, /* selections */ 54360bd37d32Smrg Cardinal *num_params) 54370bd37d32Smrg{ 54380bd37d32Smrg XtermWidget xw; 54390bd37d32Smrg 54400bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 54410bd37d32Smrg TRACE(("HandleInsertSelectable(%d)\n", *num_params)); 54420bd37d32Smrg 54430bd37d32Smrg if (*num_params == 2) { 54440bd37d32Smrg CELL start, finish; 54450bd37d32Smrg char *data; 54460bd37d32Smrg char *temp = x_strdup(params[0]); 54470bd37d32Smrg 5448913cc679Smrg data = getDataFromScreen(xw, event, params[1], &start, &finish); 54490bd37d32Smrg if (data != 0) { 54502e4f8982Smrg char *exps = expandFormat(xw, temp, data, &start, &finish); 54510bd37d32Smrg if (exps != 0) { 54520bd37d32Smrg unparseputs(xw, exps); 545301037d57Smrg unparse_end(xw); 54540bd37d32Smrg free(exps); 54550bd37d32Smrg } 54560bd37d32Smrg free(data); 54570bd37d32Smrg } 54580bd37d32Smrg free(temp); 54590bd37d32Smrg } 54600bd37d32Smrg } 54610bd37d32Smrg} 54620bd37d32Smrg#endif /* OPT_SELECTION_OPS */ 5463