button.c revision 894e0ac8
1894e0ac8Smrg/* $XTermId: button.c,v 1.473 2014/05/26 17:12:51 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4894e0ac8Smrg * Copyright 1999-2013,2014 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) \ 95d522f475Smrg 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 TScreen *screen = TScreenOf(xw); 255492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 256492d43a5Smrg Bool result = False; 257d522f475Smrg 258d522f475Smrg switch (screen->send_mouse_pos) { 259492d43a5Smrg case MOUSE_OFF: 260492d43a5Smrg /* If send_mouse_pos mode isn't on, we shouldn't be here */ 261492d43a5Smrg break; 262d522f475Smrg 263d522f475Smrg case BTN_EVENT_MOUSE: 264d522f475Smrg case ANY_EVENT_MOUSE: 265492d43a5Smrg if (KeyModifiers(event) == 0 || KeyModifiers(event) == ControlMask) { 266492d43a5Smrg /* xterm extension for motion reporting. June 1998 */ 267492d43a5Smrg /* EditorButton() will distinguish between the modes */ 268492d43a5Smrg switch (event->type) { 269492d43a5Smrg case MotionNotify: 270492d43a5Smrg my_event->button = 0; 271492d43a5Smrg /* FALLTHRU */ 272492d43a5Smrg case ButtonPress: 273492d43a5Smrg /* FALLTHRU */ 274492d43a5Smrg case ButtonRelease: 275492d43a5Smrg EditorButton(xw, my_event); 276492d43a5Smrg result = True; 277492d43a5Smrg break; 2782eaa94a1Schristos } 279d522f475Smrg } 280492d43a5Smrg break; 281d522f475Smrg 282d522f475Smrg default: 283492d43a5Smrg /* Make sure the event is an appropriate type */ 284492d43a5Smrg if (IsBtnEvent(event)) { 285492d43a5Smrg switch (screen->send_mouse_pos) { 286492d43a5Smrg case X10_MOUSE: /* X10 compatibility sequences */ 287492d43a5Smrg 288492d43a5Smrg if (BtnModifiers(my_event) == 0) { 289492d43a5Smrg if (my_event->type == ButtonPress) 290492d43a5Smrg EditorButton(xw, my_event); 291492d43a5Smrg result = True; 292492d43a5Smrg } 293492d43a5Smrg break; 294492d43a5Smrg 295492d43a5Smrg case VT200_HIGHLIGHT_MOUSE: /* DEC vt200 hilite tracking */ 296492d43a5Smrg if (my_event->type == ButtonPress && 297492d43a5Smrg BtnModifiers(my_event) == 0 && 298492d43a5Smrg my_event->button == Button1) { 299492d43a5Smrg TrackDown(xw, my_event); 300492d43a5Smrg result = True; 301492d43a5Smrg } else if (BtnModifiers(my_event) == 0 302492d43a5Smrg || BtnModifiers(my_event) == ControlMask) { 303492d43a5Smrg EditorButton(xw, my_event); 304492d43a5Smrg result = True; 305492d43a5Smrg } 306492d43a5Smrg break; 307492d43a5Smrg 308492d43a5Smrg case VT200_MOUSE: /* DEC vt200 compatible */ 309492d43a5Smrg if (BtnModifiers(my_event) == 0 310492d43a5Smrg || BtnModifiers(my_event) == ControlMask) { 311492d43a5Smrg EditorButton(xw, my_event); 312492d43a5Smrg result = True; 313492d43a5Smrg } 314492d43a5Smrg break; 315492d43a5Smrg 316492d43a5Smrg#if OPT_DEC_LOCATOR 317492d43a5Smrg case DEC_LOCATOR: 318492d43a5Smrg result = SendLocatorPosition(xw, my_event); 319492d43a5Smrg break; 320492d43a5Smrg#endif /* OPT_DEC_LOCATOR */ 321492d43a5Smrg } 322492d43a5Smrg } 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: 433d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 434d522f475Smrg * 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 /* 463d522f475Smrg * DECterm turns the Locator off if a button is pressed while a filter rectangle 464d522f475Smrg * is active. This might be a bug, but I don't know, so I'll emulate it anyways. 465d522f475Smrg */ 466d522f475Smrg if (screen->loc_filter) { 467d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 468d522f475Smrg screen->loc_filter = False; 469d522f475Smrg screen->locator_events = 0; 470d522f475Smrg MotionOff(screen, xw); 471d522f475Smrg } 472d522f475Smrg 473d522f475Smrg return (True); 474d522f475Smrg} 475d522f475Smrg 476d522f475Smrg/* 477d522f475Smrg * mask: 478d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 479d522f475Smrg * M4 down left down middle down right down 480d522f475Smrg * 481d522f475Smrg * Button1 (left) and Button3 (right) are swapped in the mask relative to X. 482d522f475Smrg */ 483d522f475Smrg#define ButtonState(state, mask) \ 4842eaa94a1Schristos{ (state) = (int) (((mask) & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8); \ 485d522f475Smrg /* swap Button1 & Button3 */ \ 486d522f475Smrg (state) = ((state) & ~(4|1)) | (((state)&1)?4:0) | (((state)&4)?1:0); \ 487d522f475Smrg} 488d522f475Smrg 489d522f475Smrgvoid 490d522f475SmrgGetLocatorPosition(XtermWidget xw) 491d522f475Smrg{ 492d522f475Smrg ANSI reply; 493956cc18dSsnj TScreen *screen = TScreenOf(xw); 494d522f475Smrg Window root, child; 495d522f475Smrg int rx, ry, x, y; 496d522f475Smrg unsigned int mask; 497d522f475Smrg int row = 0, col = 0; 498d522f475Smrg Bool oor = False; 499d522f475Smrg Bool ret = False; 500d522f475Smrg int state; 501d522f475Smrg 502d522f475Smrg /* 503d522f475Smrg * DECterm turns the Locator off if the position is requested while a filter rectangle 504d522f475Smrg * is active. This might be a bug, but I don't know, so I'll emulate it anyways. 505d522f475Smrg */ 506d522f475Smrg if (screen->loc_filter) { 507d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 508d522f475Smrg screen->loc_filter = False; 509d522f475Smrg screen->locator_events = 0; 510d522f475Smrg MotionOff(screen, xw); 511d522f475Smrg } 512d522f475Smrg 513d522f475Smrg memset(&reply, 0, sizeof(reply)); 514d522f475Smrg reply.a_type = ANSI_CSI; 515d522f475Smrg 516d522f475Smrg if (screen->send_mouse_pos == DEC_LOCATOR) { 517d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), &root, 518d522f475Smrg &child, &rx, &ry, &x, &y, &mask); 519d522f475Smrg if (ret) { 520d522f475Smrg LocatorCoords(row, col, x, y, oor); 521d522f475Smrg } 522d522f475Smrg } 523d522f475Smrg if (ret == False || oor) { 524d522f475Smrg reply.a_nparam = 1; 525d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 526d522f475Smrg reply.a_inters = '&'; 527d522f475Smrg reply.a_final = 'w'; 528d522f475Smrg unparseseq(xw, &reply); 529d522f475Smrg 530d522f475Smrg if (screen->locator_reset) { 531d522f475Smrg MotionOff(screen, xw); 532d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 533d522f475Smrg } 534d522f475Smrg return; 535d522f475Smrg } 536d522f475Smrg 537d522f475Smrg ButtonState(state, mask); 538d522f475Smrg 539d522f475Smrg reply.a_nparam = 4; 540d522f475Smrg reply.a_param[0] = 1; /* Event - 1 = response to locator request */ 5412eaa94a1Schristos reply.a_param[1] = (ParmType) state; 5422eaa94a1Schristos reply.a_param[2] = (ParmType) row; 5432eaa94a1Schristos reply.a_param[3] = (ParmType) col; 544d522f475Smrg reply.a_inters = '&'; 545d522f475Smrg reply.a_final = 'w'; 546d522f475Smrg unparseseq(xw, &reply); 547d522f475Smrg 548d522f475Smrg if (screen->locator_reset) { 549d522f475Smrg MotionOff(screen, xw); 550d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 551d522f475Smrg } 552d522f475Smrg} 553d522f475Smrg 554d522f475Smrgvoid 555d522f475SmrgInitLocatorFilter(XtermWidget xw) 556d522f475Smrg{ 557d522f475Smrg ANSI reply; 558956cc18dSsnj TScreen *screen = TScreenOf(xw); 559d522f475Smrg Window root, child; 560d522f475Smrg int rx, ry, x, y; 561d522f475Smrg unsigned int mask; 562d522f475Smrg int row = 0, col = 0; 563d522f475Smrg Bool oor = 0; 564d522f475Smrg Bool ret; 565d522f475Smrg int state; 566d522f475Smrg 567d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), 568d522f475Smrg &root, &child, &rx, &ry, &x, &y, &mask); 569d522f475Smrg if (ret) { 570d522f475Smrg LocatorCoords(row, col, x, y, oor); 571d522f475Smrg } 572d522f475Smrg if (ret == False || oor) { 573d522f475Smrg /* Locator is unavailable */ 574d522f475Smrg 575d522f475Smrg if (screen->loc_filter_top != LOC_FILTER_POS || 576d522f475Smrg screen->loc_filter_left != LOC_FILTER_POS || 577d522f475Smrg screen->loc_filter_bottom != LOC_FILTER_POS || 578d522f475Smrg screen->loc_filter_right != LOC_FILTER_POS) { 579d522f475Smrg /* 580d522f475Smrg * If any explicit coordinates were received, 581d522f475Smrg * report immediately with no coordinates. 582d522f475Smrg */ 583d522f475Smrg memset(&reply, 0, sizeof(reply)); 584d522f475Smrg reply.a_type = ANSI_CSI; 585d522f475Smrg reply.a_nparam = 1; 586d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 587d522f475Smrg reply.a_inters = '&'; 588d522f475Smrg reply.a_final = 'w'; 589d522f475Smrg unparseseq(xw, &reply); 590d522f475Smrg 591d522f475Smrg if (screen->locator_reset) { 592d522f475Smrg MotionOff(screen, xw); 593d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 594d522f475Smrg } 595d522f475Smrg } else { 596d522f475Smrg /* 597d522f475Smrg * No explicit coordinates were received, and the pointer is 598d522f475Smrg * unavailable. Report when the pointer re-enters the window. 599d522f475Smrg */ 600d522f475Smrg screen->loc_filter = True; 601d522f475Smrg MotionOn(screen, xw); 602d522f475Smrg } 603d522f475Smrg return; 604d522f475Smrg } 605d522f475Smrg 606d522f475Smrg /* 607d522f475Smrg * Adjust rectangle coordinates: 608d522f475Smrg * 1. Replace "LOC_FILTER_POS" with current coordinates 609d522f475Smrg * 2. Limit coordinates to screen size 610d522f475Smrg * 3. make sure top and left are less than bottom and right, resp. 611d522f475Smrg */ 612d522f475Smrg if (screen->locator_pixels) { 613d522f475Smrg rx = OriginX(screen) * 2 + Width(screen); 614d522f475Smrg ry = screen->border * 2 + Height(screen); 615d522f475Smrg } else { 616d522f475Smrg rx = screen->max_col; 617d522f475Smrg ry = screen->max_row; 618d522f475Smrg } 619d522f475Smrg 620d522f475Smrg#define Adjust( coord, def, max ) \ 621d522f475Smrg if( (coord) == LOC_FILTER_POS ) (coord) = (def); \ 622d522f475Smrg else if ((coord) < 1) (coord) = 1; \ 623d522f475Smrg else if ((coord) > (max)) (coord) = (max) 624d522f475Smrg 625d522f475Smrg Adjust(screen->loc_filter_top, row, ry); 626d522f475Smrg Adjust(screen->loc_filter_left, col, rx); 627d522f475Smrg Adjust(screen->loc_filter_bottom, row, ry); 628d522f475Smrg Adjust(screen->loc_filter_right, col, rx); 629d522f475Smrg 630d522f475Smrg if (screen->loc_filter_top > screen->loc_filter_bottom) { 631d522f475Smrg ry = screen->loc_filter_top; 632d522f475Smrg screen->loc_filter_top = screen->loc_filter_bottom; 633d522f475Smrg screen->loc_filter_bottom = ry; 634d522f475Smrg } 635d522f475Smrg 636d522f475Smrg if (screen->loc_filter_left > screen->loc_filter_right) { 637d522f475Smrg rx = screen->loc_filter_left; 638d522f475Smrg screen->loc_filter_left = screen->loc_filter_right; 639d522f475Smrg screen->loc_filter_right = rx; 640d522f475Smrg } 641d522f475Smrg 642d522f475Smrg if ((col < screen->loc_filter_left) || 643d522f475Smrg (col > screen->loc_filter_right) || 644d522f475Smrg (row < screen->loc_filter_top) || 645d522f475Smrg (row > screen->loc_filter_bottom)) { 646d522f475Smrg /* Pointer is already outside the rectangle - report immediately */ 647d522f475Smrg ButtonState(state, mask); 648d522f475Smrg 649d522f475Smrg memset(&reply, 0, sizeof(reply)); 650d522f475Smrg reply.a_type = ANSI_CSI; 651d522f475Smrg reply.a_nparam = 4; 652d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 6532eaa94a1Schristos reply.a_param[1] = (ParmType) state; 6542eaa94a1Schristos reply.a_param[2] = (ParmType) row; 6552eaa94a1Schristos reply.a_param[3] = (ParmType) col; 656d522f475Smrg reply.a_inters = '&'; 657d522f475Smrg reply.a_final = 'w'; 658d522f475Smrg unparseseq(xw, &reply); 659d522f475Smrg 660d522f475Smrg if (screen->locator_reset) { 661d522f475Smrg MotionOff(screen, xw); 662d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 663d522f475Smrg } 664d522f475Smrg return; 665d522f475Smrg } 666d522f475Smrg 667d522f475Smrg /* 668d522f475Smrg * Rectangle is set up. Allow pointer tracking 669d522f475Smrg * to detect if the mouse leaves the rectangle. 670d522f475Smrg */ 671d522f475Smrg screen->loc_filter = True; 672d522f475Smrg MotionOn(screen, xw); 673d522f475Smrg} 674d522f475Smrg 675d522f475Smrgstatic void 676894e0ac8SmrgCheckLocatorPosition(XtermWidget xw, XButtonEvent *event) 677d522f475Smrg{ 678d522f475Smrg ANSI reply; 679956cc18dSsnj TScreen *screen = TScreenOf(xw); 680d522f475Smrg int row, col; 681d522f475Smrg Bool oor; 682d522f475Smrg int state; 683d522f475Smrg 684492d43a5Smrg LocatorCoords(row, col, event->x, event->y, oor); 685d522f475Smrg 686d522f475Smrg /* 687d522f475Smrg * Send report if the pointer left the filter rectangle, if 688d522f475Smrg * the pointer left the window, or if the filter rectangle 689d522f475Smrg * had no coordinates and the pointer re-entered the window. 690d522f475Smrg */ 691d522f475Smrg if (oor || (screen->loc_filter_top == LOC_FILTER_POS) || 692d522f475Smrg (col < screen->loc_filter_left) || 693d522f475Smrg (col > screen->loc_filter_right) || 694d522f475Smrg (row < screen->loc_filter_top) || 695d522f475Smrg (row > screen->loc_filter_bottom)) { 696d522f475Smrg /* Filter triggered - disable it */ 697d522f475Smrg screen->loc_filter = False; 698d522f475Smrg MotionOff(screen, xw); 699d522f475Smrg 700d522f475Smrg memset(&reply, 0, sizeof(reply)); 701d522f475Smrg reply.a_type = ANSI_CSI; 702d522f475Smrg if (oor) { 703d522f475Smrg reply.a_nparam = 1; 704d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 705d522f475Smrg } else { 706492d43a5Smrg ButtonState(state, event->state); 707d522f475Smrg 708d522f475Smrg reply.a_nparam = 4; 709d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 7102eaa94a1Schristos reply.a_param[1] = (ParmType) state; 7112eaa94a1Schristos reply.a_param[2] = (ParmType) row; 7122eaa94a1Schristos reply.a_param[3] = (ParmType) col; 713d522f475Smrg } 714d522f475Smrg 715d522f475Smrg reply.a_inters = '&'; 716d522f475Smrg reply.a_final = 'w'; 717d522f475Smrg unparseseq(xw, &reply); 718d522f475Smrg 719d522f475Smrg if (screen->locator_reset) { 720d522f475Smrg MotionOff(screen, xw); 721d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 722d522f475Smrg } 723d522f475Smrg } 724d522f475Smrg} 725d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 726d522f475Smrg 727d522f475Smrg#if OPT_READLINE 728d522f475Smrgstatic int 729894e0ac8SmrgisClick1_clean(TScreen *screen, XButtonEvent *event) 730d522f475Smrg{ 731d522f475Smrg int delta; 732d522f475Smrg 733492d43a5Smrg if (!IsBtnEvent(event) 734d522f475Smrg /* Disable on Shift-Click-1, including the application-mouse modes */ 735492d43a5Smrg || (BtnModifiers(event) & ShiftMask) 736d522f475Smrg || (screen->send_mouse_pos != MOUSE_OFF) /* Kinda duplicate... */ 737d522f475Smrg ||ExtendingSelection) /* Was moved */ 738d522f475Smrg return 0; 739d522f475Smrg 740d522f475Smrg if (event->type != ButtonRelease) 741d522f475Smrg return 0; 742d522f475Smrg 743d522f475Smrg if (lastButtonDownTime == (Time) 0) { 744d522f475Smrg /* first time or once in a blue moon */ 745d522f475Smrg delta = screen->multiClickTime + 1; 746492d43a5Smrg } else if (event->time > lastButtonDownTime) { 747d522f475Smrg /* most of the time */ 748492d43a5Smrg delta = (int) (event->time - lastButtonDownTime); 749d522f475Smrg } else { 750d522f475Smrg /* time has rolled over since lastButtonUpTime */ 751492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->time); 752d522f475Smrg } 753d522f475Smrg 754d522f475Smrg return delta <= screen->multiClickTime; 755d522f475Smrg} 756d522f475Smrg 757d522f475Smrgstatic int 758894e0ac8SmrgisDoubleClick3(TScreen *screen, XButtonEvent *event) 759d522f475Smrg{ 760d522f475Smrg int delta; 761d522f475Smrg 762d522f475Smrg if (event->type != ButtonRelease 763492d43a5Smrg || (BtnModifiers(event) & ShiftMask) 764492d43a5Smrg || event->button != Button3) { 765d522f475Smrg lastButton3UpTime = 0; /* Disable the cached info */ 766d522f475Smrg return 0; 767d522f475Smrg } 768d522f475Smrg /* Process Btn3Release. */ 769d522f475Smrg if (lastButton3DoubleDownTime == (Time) 0) { 770d522f475Smrg /* No previous click or once in a blue moon */ 771d522f475Smrg delta = screen->multiClickTime + 1; 772492d43a5Smrg } else if (event->time > lastButton3DoubleDownTime) { 773d522f475Smrg /* most of the time */ 774492d43a5Smrg delta = (int) (event->time - lastButton3DoubleDownTime); 775d522f475Smrg } else { 776d522f475Smrg /* time has rolled over since lastButton3DoubleDownTime */ 777492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButton3DoubleDownTime) + event->time); 778d522f475Smrg } 779d522f475Smrg if (delta <= screen->multiClickTime) { 780d522f475Smrg /* Double click */ 781d522f475Smrg CELL cell; 782d522f475Smrg 783d522f475Smrg /* Cannot check ExtendingSelection, since mouse-3 always sets it */ 784492d43a5Smrg PointToCELL(screen, event->y, event->x, &cell); 785d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 786d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the third click */ 787d522f475Smrg return 1; 788d522f475Smrg } 789d522f475Smrg } 790d522f475Smrg /* Not a double click, memorize for future check. */ 791492d43a5Smrg lastButton3UpTime = event->time; 792492d43a5Smrg PointToCELL(screen, event->y, event->x, &lastButton3); 793d522f475Smrg return 0; 794d522f475Smrg} 795d522f475Smrg 796d522f475Smrgstatic int 797894e0ac8SmrgCheckSecondPress3(TScreen *screen, XEvent *event) 798d522f475Smrg{ 799d522f475Smrg int delta; 800d522f475Smrg 801d522f475Smrg if (event->type != ButtonPress 802492d43a5Smrg || (KeyModifiers(event) & ShiftMask) 803d522f475Smrg || event->xbutton.button != Button3) { 804d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the cached info */ 805d522f475Smrg return 0; 806d522f475Smrg } 807d522f475Smrg /* Process Btn3Press. */ 808d522f475Smrg if (lastButton3UpTime == (Time) 0) { 809d522f475Smrg /* No previous click or once in a blue moon */ 810d522f475Smrg delta = screen->multiClickTime + 1; 811d522f475Smrg } else if (event->xbutton.time > lastButton3UpTime) { 812d522f475Smrg /* most of the time */ 8132eaa94a1Schristos delta = (int) (event->xbutton.time - lastButton3UpTime); 814d522f475Smrg } else { 815d522f475Smrg /* time has rolled over since lastButton3UpTime */ 8162eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButton3UpTime) + event->xbutton.time); 817d522f475Smrg } 818d522f475Smrg if (delta <= screen->multiClickTime) { 819d522f475Smrg CELL cell; 820d522f475Smrg 821d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 822d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 823d522f475Smrg /* A candidate for a double-click */ 824d522f475Smrg lastButton3DoubleDownTime = event->xbutton.time; 825d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &lastButton3); 826d522f475Smrg return 1; 827d522f475Smrg } 828d522f475Smrg lastButton3UpTime = 0; /* Disable the info about the previous click */ 829d522f475Smrg } 830d522f475Smrg /* Either too long, or moved, disable. */ 831d522f475Smrg lastButton3DoubleDownTime = 0; 832d522f475Smrg return 0; 833d522f475Smrg} 834d522f475Smrg 835d522f475Smrgstatic int 836e0a2b6dfSmrgrowOnCurrentLine(TScreen *screen, 837d522f475Smrg int line, 838d522f475Smrg int *deltap) /* must be XButtonEvent */ 839d522f475Smrg{ 840956cc18dSsnj int result = 1; 841d522f475Smrg int l1, l2; 842d522f475Smrg 843d522f475Smrg *deltap = 0; 844956cc18dSsnj if (line != screen->cur_row) { 845956cc18dSsnj if (line < screen->cur_row) 846956cc18dSsnj l1 = line, l2 = screen->cur_row; 847956cc18dSsnj else 848956cc18dSsnj l2 = line, l1 = screen->cur_row; 849956cc18dSsnj l1--; 850956cc18dSsnj while (++l1 < l2) { 851956cc18dSsnj LineData *ld = GET_LINEDATA(screen, l1); 852956cc18dSsnj if (!LineTstWrapped(ld)) { 853956cc18dSsnj result = 0; 854956cc18dSsnj break; 855956cc18dSsnj } 856956cc18dSsnj } 857956cc18dSsnj if (result) { 858956cc18dSsnj /* Everything is on one "wrapped line" now */ 859956cc18dSsnj *deltap = line - screen->cur_row; 860956cc18dSsnj } 861956cc18dSsnj } 862956cc18dSsnj return result; 863d522f475Smrg} 864d522f475Smrg 865d522f475Smrgstatic int 866894e0ac8SmrgeventRow(TScreen *screen, XEvent *event) /* must be XButtonEvent */ 867d522f475Smrg{ 868d522f475Smrg return (event->xbutton.y - screen->border) / FontHeight(screen); 869d522f475Smrg} 870d522f475Smrg 871d522f475Smrgstatic int 872894e0ac8SmrgeventColBetween(TScreen *screen, XEvent *event) /* must be XButtonEvent */ 873d522f475Smrg{ 874d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 875d522f475Smrg return ((event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) / 2) 876d522f475Smrg / FontWidth(screen)); 877d522f475Smrg} 878d522f475Smrg 879d522f475Smrgstatic int 880e0a2b6dfSmrgReadLineMovePoint(TScreen *screen, int col, int ldelta) 881d522f475Smrg{ 882d522f475Smrg Char line[6]; 883d522f475Smrg unsigned count = 0; 884d522f475Smrg 885d522f475Smrg col += ldelta * MaxCols(screen) - screen->cur_col; 886d522f475Smrg if (col == 0) 887d522f475Smrg return 0; 888d522f475Smrg if (screen->control_eight_bits) { 889d522f475Smrg line[count++] = ANSI_CSI; 890d522f475Smrg } else { 891d522f475Smrg line[count++] = ANSI_ESC; 892d522f475Smrg line[count++] = '['; /* XXX maybe sometimes O is better? */ 893d522f475Smrg } 89420d2c4d2Smrg line[count] = CharOf(col > 0 ? 'C' : 'D'); 895d522f475Smrg if (col < 0) 896d522f475Smrg col = -col; 897d522f475Smrg while (col--) 898d522f475Smrg v_write(screen->respond, line, 3); 899d522f475Smrg return 1; 900d522f475Smrg} 901d522f475Smrg 902d522f475Smrgstatic int 903e0a2b6dfSmrgReadLineDelete(TScreen *screen, CELL *cell1, CELL *cell2) 904d522f475Smrg{ 905d522f475Smrg int del; 906d522f475Smrg 907d522f475Smrg del = (cell2->col - cell1->col) + ((cell2->row - cell1->row) * MaxCols(screen)); 908d522f475Smrg if (del <= 0) /* Just in case... */ 909d522f475Smrg return 0; 910d522f475Smrg while (del--) 911492d43a5Smrg v_write(screen->respond, (const Char *) "\177", 1); 912d522f475Smrg return 1; 913d522f475Smrg} 914492d43a5Smrg 915492d43a5Smrgstatic void 916894e0ac8SmrgreadlineExtend(TScreen *screen, XEvent *event) 917492d43a5Smrg{ 918492d43a5Smrg int ldelta1, ldelta2; 919492d43a5Smrg 920492d43a5Smrg if (IsBtnEvent(event)) { 921492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 922492d43a5Smrg if (isClick1_clean(screen, my_event) 923492d43a5Smrg && SCREEN_FLAG(screen, click1_moves) 924492d43a5Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta1)) { 925492d43a5Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta1); 926492d43a5Smrg } 927492d43a5Smrg if (isDoubleClick3(screen, my_event) 928492d43a5Smrg && SCREEN_FLAG(screen, dclick3_deletes) 929492d43a5Smrg && rowOnCurrentLine(screen, screen->startSel.row, &ldelta1) 930492d43a5Smrg && rowOnCurrentLine(screen, screen->endSel.row, &ldelta2)) { 931492d43a5Smrg ReadLineMovePoint(screen, screen->endSel.col, ldelta2); 932492d43a5Smrg ReadLineDelete(screen, &screen->startSel, &(screen->endSel)); 933492d43a5Smrg } 934492d43a5Smrg } 935492d43a5Smrg} 936492d43a5Smrg 937d522f475Smrg#endif /* OPT_READLINE */ 938d522f475Smrg 939d522f475Smrg/* ^XM-G<line+' '><col+' '> */ 940d522f475Smrgvoid 941d522f475SmrgDiredButton(Widget w, 942894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 943e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 944d522f475Smrg Cardinal *num_params GCC_UNUSED) 945d522f475Smrg{ 946956cc18dSsnj XtermWidget xw; 947956cc18dSsnj 948956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 949956cc18dSsnj TScreen *screen = TScreenOf(xw); 950d522f475Smrg Char Line[6]; 951d522f475Smrg unsigned line, col; 952d522f475Smrg 953492d43a5Smrg if (IsBtnEvent(event) 9542eaa94a1Schristos && (event->xbutton.y >= screen->border) 9552eaa94a1Schristos && (event->xbutton.x >= OriginX(screen))) { 95620d2c4d2Smrg line = (unsigned) ((event->xbutton.y - screen->border) 95720d2c4d2Smrg / FontHeight(screen)); 95820d2c4d2Smrg col = (unsigned) ((event->xbutton.x - OriginX(screen)) 95920d2c4d2Smrg / FontWidth(screen)); 960d522f475Smrg Line[0] = CONTROL('X'); 961d522f475Smrg Line[1] = ANSI_ESC; 962d522f475Smrg Line[2] = 'G'; 9632eaa94a1Schristos Line[3] = CharOf(' ' + col); 9642eaa94a1Schristos Line[4] = CharOf(' ' + line); 965d522f475Smrg v_write(screen->respond, Line, 5); 966d522f475Smrg } 967d522f475Smrg } 968d522f475Smrg} 969d522f475Smrg 970d522f475Smrg#if OPT_READLINE 971d522f475Smrgvoid 972d522f475SmrgReadLineButton(Widget w, 973894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 974e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 975d522f475Smrg Cardinal *num_params GCC_UNUSED) 976d522f475Smrg{ 977956cc18dSsnj XtermWidget xw; 978956cc18dSsnj 979956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 980956cc18dSsnj TScreen *screen = TScreenOf(xw); 981d522f475Smrg Char Line[6]; 982d522f475Smrg int line, col, ldelta = 0; 983d522f475Smrg 984492d43a5Smrg if (!IsBtnEvent(event) 985d522f475Smrg || (screen->send_mouse_pos != MOUSE_OFF) || ExtendingSelection) 986d522f475Smrg goto finish; 987d522f475Smrg if (event->type == ButtonRelease) { 988d522f475Smrg int delta; 989d522f475Smrg 990d522f475Smrg if (lastButtonDownTime == (Time) 0) { 991d522f475Smrg /* first time and once in a blue moon */ 992d522f475Smrg delta = screen->multiClickTime + 1; 993d522f475Smrg } else if (event->xbutton.time > lastButtonDownTime) { 994d522f475Smrg /* most of the time */ 9952eaa94a1Schristos delta = (int) (event->xbutton.time - lastButtonDownTime); 996d522f475Smrg } else { 997d522f475Smrg /* time has rolled over since lastButtonUpTime */ 9982eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time); 999d522f475Smrg } 1000d522f475Smrg if (delta > screen->multiClickTime) 1001d522f475Smrg goto finish; /* All this work for this... */ 1002d522f475Smrg } 1003d522f475Smrg line = (event->xbutton.y - screen->border) / FontHeight(screen); 1004956cc18dSsnj if (!rowOnCurrentLine(screen, line, &ldelta)) 1005956cc18dSsnj goto finish; 1006d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 1007d522f475Smrg col = (event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) 1008d522f475Smrg / 2) 1009d522f475Smrg / FontWidth(screen) - screen->cur_col + ldelta * MaxCols(screen); 1010d522f475Smrg if (col == 0) 1011d522f475Smrg goto finish; 1012d522f475Smrg Line[0] = ANSI_ESC; 1013d522f475Smrg /* XXX: sometimes it is better to send '['? */ 1014d522f475Smrg Line[1] = 'O'; 10152eaa94a1Schristos Line[2] = CharOf(col > 0 ? 'C' : 'D'); 1016d522f475Smrg if (col < 0) 1017d522f475Smrg col = -col; 1018d522f475Smrg while (col--) 1019d522f475Smrg v_write(screen->respond, Line, 3); 1020d522f475Smrg finish: 1021d522f475Smrg if (event->type == ButtonRelease) 1022d522f475Smrg do_select_end(xw, event, params, num_params, False); 1023d522f475Smrg } 1024d522f475Smrg} 1025d522f475Smrg#endif /* OPT_READLINE */ 1026d522f475Smrg 1027d522f475Smrg/* repeats <ESC>n or <ESC>p */ 1028d522f475Smrgvoid 1029d522f475SmrgViButton(Widget w, 1030894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1031e0a2b6dfSmrg String *params GCC_UNUSED, /* selections */ 1032d522f475Smrg Cardinal *num_params GCC_UNUSED) 1033d522f475Smrg{ 1034956cc18dSsnj XtermWidget xw; 1035956cc18dSsnj 1036956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1037956cc18dSsnj TScreen *screen = TScreenOf(xw); 1038d522f475Smrg int pty = screen->respond; 1039d522f475Smrg Char Line[6]; 1040d522f475Smrg int line; 1041d522f475Smrg 1042492d43a5Smrg if (IsBtnEvent(event)) { 1043d522f475Smrg 1044d522f475Smrg line = screen->cur_row - 1045d522f475Smrg ((event->xbutton.y - screen->border) / FontHeight(screen)); 1046d522f475Smrg if (line != 0) { 1047d522f475Smrg Line[0] = ANSI_ESC; /* force an exit from insert-mode */ 1048d522f475Smrg v_write(pty, Line, 1); 1049d522f475Smrg 1050d522f475Smrg if (line < 0) { 1051d522f475Smrg line = -line; 1052d522f475Smrg Line[0] = CONTROL('n'); 1053d522f475Smrg } else { 1054d522f475Smrg Line[0] = CONTROL('p'); 1055d522f475Smrg } 1056d522f475Smrg while (--line >= 0) 1057d522f475Smrg v_write(pty, Line, 1); 1058d522f475Smrg } 1059d522f475Smrg } 1060d522f475Smrg } 1061d522f475Smrg} 1062d522f475Smrg 1063d522f475Smrg/* 1064d522f475Smrg * This function handles button-motion events 1065d522f475Smrg */ 1066d522f475Smrg/*ARGSUSED*/ 1067d522f475Smrgvoid 1068d522f475SmrgHandleSelectExtend(Widget w, 1069894e0ac8Smrg XEvent *event, /* must be XMotionEvent */ 1070e0a2b6dfSmrg String *params GCC_UNUSED, 1071d522f475Smrg Cardinal *num_params GCC_UNUSED) 1072d522f475Smrg{ 1073956cc18dSsnj XtermWidget xw; 1074956cc18dSsnj 1075956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1076956cc18dSsnj TScreen *screen = TScreenOf(xw); 1077d522f475Smrg CELL cell; 1078d522f475Smrg 1079e0a2b6dfSmrg TRACE(("HandleSelectExtend @%ld\n", event->xmotion.time)); 10800bd37d32Smrg 1081d522f475Smrg screen->selection_time = event->xmotion.time; 1082d522f475Smrg switch (screen->eventMode) { 1083d522f475Smrg /* If not in one of the DEC mouse-reporting modes */ 1084d522f475Smrg case LEFTEXTENSION: 1085d522f475Smrg case RIGHTEXTENSION: 1086d522f475Smrg PointToCELL(screen, event->xmotion.y, event->xmotion.x, &cell); 1087d522f475Smrg ExtendExtend(xw, &cell); 1088d522f475Smrg break; 1089d522f475Smrg 1090d522f475Smrg /* If in motion reporting mode, send mouse position to 1091d522f475Smrg character process as a key sequence \E[M... */ 1092d522f475Smrg case NORMAL: 1093d522f475Smrg /* will get here if send_mouse_pos != MOUSE_OFF */ 1094d522f475Smrg if (screen->send_mouse_pos == BTN_EVENT_MOUSE 1095d522f475Smrg || screen->send_mouse_pos == ANY_EVENT_MOUSE) { 1096d522f475Smrg (void) SendMousePosition(xw, event); 1097d522f475Smrg } 1098d522f475Smrg break; 1099d522f475Smrg } 1100d522f475Smrg } 1101d522f475Smrg} 1102d522f475Smrg 1103d522f475Smrgvoid 1104d522f475SmrgHandleKeyboardSelectExtend(Widget w, 1105894e0ac8Smrg XEvent *event GCC_UNUSED, /* must be XButtonEvent */ 1106e0a2b6dfSmrg String *params GCC_UNUSED, 1107d522f475Smrg Cardinal *num_params GCC_UNUSED) 1108d522f475Smrg{ 1109956cc18dSsnj XtermWidget xw; 1110956cc18dSsnj 1111956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1112956cc18dSsnj TScreen *screen = TScreenOf(xw); 11130bd37d32Smrg 11140bd37d32Smrg TRACE(("HandleKeyboardSelectExtend\n")); 1115d522f475Smrg ExtendExtend(xw, &screen->cursorp); 1116d522f475Smrg } 1117d522f475Smrg} 1118d522f475Smrg 1119d522f475Smrgstatic void 1120d522f475Smrgdo_select_end(XtermWidget xw, 1121894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1122e0a2b6dfSmrg String *params, /* selections */ 1123d522f475Smrg Cardinal *num_params, 1124d522f475Smrg Bool use_cursor_loc) 1125d522f475Smrg{ 1126956cc18dSsnj TScreen *screen = TScreenOf(xw); 1127d522f475Smrg 1128d522f475Smrg screen->selection_time = event->xbutton.time; 1129e0a2b6dfSmrg TRACE(("do_select_end @%ld\n", screen->selection_time)); 1130d522f475Smrg switch (screen->eventMode) { 1131d522f475Smrg case NORMAL: 1132d522f475Smrg (void) SendMousePosition(xw, event); 1133d522f475Smrg break; 1134d522f475Smrg case LEFTEXTENSION: 1135d522f475Smrg case RIGHTEXTENSION: 1136d522f475Smrg EndExtend(xw, event, params, *num_params, use_cursor_loc); 1137d522f475Smrg#if OPT_READLINE 1138492d43a5Smrg readlineExtend(screen, event); 1139d522f475Smrg#endif /* OPT_READLINE */ 1140d522f475Smrg break; 1141d522f475Smrg } 1142d522f475Smrg} 1143d522f475Smrg 1144d522f475Smrgvoid 1145d522f475SmrgHandleSelectEnd(Widget w, 1146894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1147e0a2b6dfSmrg String *params, /* selections */ 1148d522f475Smrg Cardinal *num_params) 1149d522f475Smrg{ 1150956cc18dSsnj XtermWidget xw; 1151956cc18dSsnj 1152956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 11530bd37d32Smrg TRACE(("HandleSelectEnd\n")); 1154956cc18dSsnj do_select_end(xw, event, params, num_params, False); 1155956cc18dSsnj } 1156d522f475Smrg} 1157d522f475Smrg 1158d522f475Smrgvoid 1159d522f475SmrgHandleKeyboardSelectEnd(Widget w, 1160894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 1161e0a2b6dfSmrg String *params, /* selections */ 1162d522f475Smrg Cardinal *num_params) 1163d522f475Smrg{ 1164956cc18dSsnj XtermWidget xw; 1165956cc18dSsnj 1166956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 11670bd37d32Smrg TRACE(("HandleKeyboardSelectEnd\n")); 1168956cc18dSsnj do_select_end(xw, event, params, num_params, True); 1169956cc18dSsnj } 1170d522f475Smrg} 1171d522f475Smrg 1172492d43a5Smrg/* 11736879286fSmrg * Copy the selection data to the given target(s). 1174492d43a5Smrg */ 1175492d43a5Smrgvoid 11766879286fSmrgHandleCopySelection(Widget w, 1177894e0ac8Smrg XEvent *event, 1178e0a2b6dfSmrg String *params, /* list of targets */ 11796879286fSmrg Cardinal *num_params) 1180492d43a5Smrg{ 1181492d43a5Smrg XtermWidget xw; 1182492d43a5Smrg 1183492d43a5Smrg if ((xw = getXtermWidget(w)) != 0) { 11840bd37d32Smrg TRACE(("HandleCopySelection\n")); 11856879286fSmrg SelectSet(xw, event, params, *num_params); 1186492d43a5Smrg } 1187492d43a5Smrg} 1188492d43a5Smrg 1189d522f475Smrgstruct _SelectionList { 1190d522f475Smrg String *params; 1191d522f475Smrg Cardinal count; 1192d522f475Smrg Atom *targets; 1193d522f475Smrg Time time; 1194d522f475Smrg}; 1195d522f475Smrg 1196d522f475Smrgstatic unsigned 1197d522f475SmrgDECtoASCII(unsigned ch) 1198d522f475Smrg{ 1199d522f475Smrg if (xtermIsDecGraphic(ch)) { 12002eaa94a1Schristos ch = CharOf("###########+++++##-##++++|######"[ch]); 12012eaa94a1Schristos /* 01234567890123456789012345678901 */ 1202d522f475Smrg } 1203d522f475Smrg return ch; 1204d522f475Smrg} 120520d2c4d2Smrg 120620d2c4d2Smrg#if OPT_WIDE_CHARS 120720d2c4d2Smrgstatic Cardinal 1208e0a2b6dfSmrgaddXtermChar(Char **buffer, Cardinal *used, Cardinal offset, unsigned value) 120920d2c4d2Smrg{ 121020d2c4d2Smrg if (offset + 1 >= *used) { 121120d2c4d2Smrg *used = 1 + (2 * (offset + 1)); 121220d2c4d2Smrg allocXtermChars(buffer, *used); 121320d2c4d2Smrg } 121420d2c4d2Smrg (*buffer)[offset++] = (Char) value; 121520d2c4d2Smrg return offset; 121620d2c4d2Smrg} 121720d2c4d2Smrg#define AddChar(buffer, used, offset, value) \ 121820d2c4d2Smrg offset = addXtermChar(buffer, used, offset, (unsigned) value) 121920d2c4d2Smrg 1220d522f475Smrg/* 1221d522f475Smrg * Convert a UTF-8 string to Latin-1, replacing non Latin-1 characters by `#', 1222d522f475Smrg * or ASCII/Latin-1 equivalents for special cases. 1223d522f475Smrg */ 1224d522f475Smrgstatic Char * 1225e0a2b6dfSmrgUTF8toLatin1(TScreen *screen, Char *s, unsigned long len, unsigned long *result) 1226d522f475Smrg{ 1227d522f475Smrg static Char *buffer; 1228956cc18dSsnj static Cardinal used; 1229d522f475Smrg 123020d2c4d2Smrg Cardinal offset = 0; 1231d522f475Smrg 1232492d43a5Smrg const Char *p; 1233d522f475Smrg 123420d2c4d2Smrg if (len != 0) { 1235d522f475Smrg PtyData data; 1236d522f475Smrg 1237d522f475Smrg fakePtyData(&data, s, s + len); 1238894e0ac8Smrg while (decodeUtf8(screen, &data)) { 1239956cc18dSsnj Bool fails = False; 1240956cc18dSsnj Bool extra = False; 1241d522f475Smrg IChar value = skipPtyData(&data); 1242d522f475Smrg if (value == UCS_REPL) { 1243956cc18dSsnj fails = True; 1244d522f475Smrg } else if (value < 256) { 124520d2c4d2Smrg AddChar(&buffer, &used, offset, CharOf(value)); 1246d522f475Smrg } else { 1247d522f475Smrg unsigned eqv = ucs2dec(value); 1248d522f475Smrg if (xtermIsDecGraphic(eqv)) { 124920d2c4d2Smrg AddChar(&buffer, &used, offset, DECtoASCII(eqv)); 1250d522f475Smrg } else { 1251d522f475Smrg eqv = AsciiEquivs(value); 1252956cc18dSsnj if (eqv == value) { 1253956cc18dSsnj fails = True; 1254956cc18dSsnj } else { 125520d2c4d2Smrg AddChar(&buffer, &used, offset, eqv); 1256956cc18dSsnj } 1257956cc18dSsnj if (isWide((wchar_t) value)) 1258956cc18dSsnj extra = True; 1259956cc18dSsnj } 1260956cc18dSsnj } 1261956cc18dSsnj 1262956cc18dSsnj /* 1263956cc18dSsnj * If we're not able to plug in a single-byte result, insert the 1264956cc18dSsnj * defaultString (which normally is a single "#", but could be 1265956cc18dSsnj * whatever the user wants). 1266956cc18dSsnj */ 1267956cc18dSsnj if (fails) { 1268492d43a5Smrg for (p = (const Char *) screen->default_string; *p != '\0'; ++p) { 126920d2c4d2Smrg AddChar(&buffer, &used, offset, *p); 1270d522f475Smrg } 1271d522f475Smrg } 1272956cc18dSsnj if (extra) 127320d2c4d2Smrg AddChar(&buffer, &used, offset, ' '); 1274d522f475Smrg } 127520d2c4d2Smrg AddChar(&buffer, &used, offset, '\0'); 127620d2c4d2Smrg *result = (unsigned long) (offset - 1); 1277d522f475Smrg } else { 1278d522f475Smrg *result = 0; 1279d522f475Smrg } 1280d522f475Smrg return buffer; 1281d522f475Smrg} 128220d2c4d2Smrg 128320d2c4d2Smrgint 128420d2c4d2SmrgxtermUtf8ToTextList(XtermWidget xw, 128520d2c4d2Smrg XTextProperty * text_prop, 128620d2c4d2Smrg char ***text_list, 128720d2c4d2Smrg int *text_list_count) 128820d2c4d2Smrg{ 128920d2c4d2Smrg TScreen *screen = TScreenOf(xw); 129020d2c4d2Smrg Display *dpy = screen->display; 129120d2c4d2Smrg int rc = -1; 129220d2c4d2Smrg 129320d2c4d2Smrg if (text_prop->format == 8 129420d2c4d2Smrg && (rc = Xutf8TextPropertyToTextList(dpy, text_prop, 129520d2c4d2Smrg text_list, 129620d2c4d2Smrg text_list_count)) >= 0) { 129720d2c4d2Smrg if (*text_list != NULL && *text_list_count != 0) { 129820d2c4d2Smrg int i; 129920d2c4d2Smrg Char *data; 130020d2c4d2Smrg char **new_text_list, *tmp; 130120d2c4d2Smrg unsigned long size, new_size; 130220d2c4d2Smrg 130320d2c4d2Smrg TRACE(("xtermUtf8ToTextList size %d\n", *text_list_count)); 130420d2c4d2Smrg 130520d2c4d2Smrg /* 130620d2c4d2Smrg * XLib StringList actually uses only two pointers, one for the 130720d2c4d2Smrg * list itself, and one for the data. Pointer to the data is the 130820d2c4d2Smrg * first element of the list, the rest (if any) list elements point 130920d2c4d2Smrg * to the same memory block as the first element 131020d2c4d2Smrg */ 131120d2c4d2Smrg new_size = 0; 131220d2c4d2Smrg for (i = 0; i < *text_list_count; ++i) { 131320d2c4d2Smrg data = (Char *) (*text_list)[i]; 131420d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 131520d2c4d2Smrg (void) UTF8toLatin1(screen, data, size, &size); 131620d2c4d2Smrg new_size += size + 1; 131720d2c4d2Smrg } 1318a1f3da82Smrg new_text_list = TypeXtMallocN(char *, *text_list_count); 131920d2c4d2Smrg new_text_list[0] = tmp = XtMalloc((Cardinal) new_size); 132020d2c4d2Smrg for (i = 0; i < (*text_list_count); ++i) { 132120d2c4d2Smrg data = (Char *) (*text_list)[i]; 132220d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 13230bd37d32Smrg if ((data = UTF8toLatin1(screen, data, size, &size)) != 0) { 13240bd37d32Smrg memcpy(tmp, data, size + 1); 13250bd37d32Smrg new_text_list[i] = tmp; 13260bd37d32Smrg tmp += size + 1; 13270bd37d32Smrg } 132820d2c4d2Smrg } 132920d2c4d2Smrg XFreeStringList((*text_list)); 133020d2c4d2Smrg *text_list = new_text_list; 133120d2c4d2Smrg } else { 133220d2c4d2Smrg rc = -1; 133320d2c4d2Smrg } 133420d2c4d2Smrg } 133520d2c4d2Smrg return rc; 133620d2c4d2Smrg} 1337d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1338d522f475Smrg 1339956cc18dSsnjstatic char * 1340956cc18dSsnjparseItem(char *value, char *nextc) 1341d522f475Smrg{ 1342956cc18dSsnj char *nextp = value; 1343956cc18dSsnj while (*nextp != '\0' && *nextp != ',') { 1344956cc18dSsnj *nextp = x_toupper(*nextp); 1345956cc18dSsnj ++nextp; 1346956cc18dSsnj } 1347956cc18dSsnj *nextc = *nextp; 1348956cc18dSsnj *nextp = '\0'; 1349d522f475Smrg 1350956cc18dSsnj return nextp; 1351956cc18dSsnj} 1352d522f475Smrg 1353956cc18dSsnj/* 1354956cc18dSsnj * All of the wanted strings are unique in the first character, so we can 1355956cc18dSsnj * use simple abbreviations. 1356956cc18dSsnj */ 1357956cc18dSsnjstatic Bool 1358956cc18dSsnjsameItem(const char *actual, const char *wanted) 1359956cc18dSsnj{ 1360956cc18dSsnj Bool result = False; 1361956cc18dSsnj size_t have = strlen(actual); 1362956cc18dSsnj size_t need = strlen(wanted); 1363d522f475Smrg 1364956cc18dSsnj if (have != 0 && have <= need) { 1365956cc18dSsnj if (!strncmp(actual, wanted, have)) { 1366956cc18dSsnj TRACE(("...matched \"%s\"\n", wanted)); 1367956cc18dSsnj result = True; 1368956cc18dSsnj } 1369956cc18dSsnj } 1370956cc18dSsnj 1371956cc18dSsnj return result; 1372956cc18dSsnj} 1373956cc18dSsnj 1374956cc18dSsnj/* 1375956cc18dSsnj * Handle the eightBitSelectTypes or utf8SelectTypes resource values. 1376956cc18dSsnj */ 1377956cc18dSsnjstatic Bool 1378894e0ac8SmrgoverrideTargets(Widget w, String value, Atom **resultp) 1379956cc18dSsnj{ 1380956cc18dSsnj Bool override = False; 1381956cc18dSsnj XtermWidget xw; 1382956cc18dSsnj 1383956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1384956cc18dSsnj TScreen *screen = TScreenOf(xw); 1385956cc18dSsnj 138620d2c4d2Smrg if (!IsEmpty(value)) { 1387492d43a5Smrg char *copied = x_strdup(value); 1388956cc18dSsnj if (copied != 0) { 1389956cc18dSsnj Atom *result = 0; 1390956cc18dSsnj Cardinal count = 1; 1391956cc18dSsnj int n; 1392d522f475Smrg 1393956cc18dSsnj TRACE(("decoding SelectTypes \"%s\"\n", value)); 1394956cc18dSsnj for (n = 0; copied[n] != '\0'; ++n) { 1395956cc18dSsnj if (copied[n] == ',') 1396956cc18dSsnj ++count; 1397956cc18dSsnj } 1398a1f3da82Smrg result = TypeXtMallocN(Atom, (2 * count) + 1); 1399956cc18dSsnj if (result == NULL) { 1400956cc18dSsnj TRACE(("Couldn't allocate selection types\n")); 1401956cc18dSsnj } else { 1402956cc18dSsnj char nextc = '?'; 140320d2c4d2Smrg char *listp = (char *) copied; 1404956cc18dSsnj count = 0; 1405956cc18dSsnj do { 1406956cc18dSsnj char *nextp = parseItem(listp, &nextc); 14070bd37d32Smrg char *item = x_strtrim(listp); 14080bd37d32Smrg size_t len = (item ? strlen(item) : 0); 1409956cc18dSsnj 1410956cc18dSsnj if (len == 0) { 1411a1f3da82Smrg /* EMPTY */ ; 1412956cc18dSsnj } 1413956cc18dSsnj#if OPT_WIDE_CHARS 14140bd37d32Smrg else if (sameItem(item, "UTF8")) { 1415956cc18dSsnj result[count++] = XA_UTF8_STRING(XtDisplay(w)); 1416956cc18dSsnj } 1417956cc18dSsnj#endif 14180bd37d32Smrg else if (sameItem(item, "I18N")) { 1419956cc18dSsnj if (screen->i18nSelections) { 1420956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 1421956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1422956cc18dSsnj } 14230bd37d32Smrg } else if (sameItem(item, "TEXT")) { 1424956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 14250bd37d32Smrg } else if (sameItem(item, "COMPOUND_TEXT")) { 1426956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 14270bd37d32Smrg } else if (sameItem(item, "STRING")) { 1428956cc18dSsnj result[count++] = XA_STRING; 1429956cc18dSsnj } 1430956cc18dSsnj *nextp++ = nextc; 1431956cc18dSsnj listp = nextp; 14320bd37d32Smrg free(item); 1433956cc18dSsnj } while (nextc != '\0'); 1434956cc18dSsnj if (count) { 1435956cc18dSsnj result[count] = None; 1436956cc18dSsnj override = True; 1437956cc18dSsnj *resultp = result; 1438956cc18dSsnj } else { 1439956cc18dSsnj XtFree((char *) result); 1440956cc18dSsnj } 1441956cc18dSsnj } 14420bd37d32Smrg free(copied); 1443956cc18dSsnj } else { 1444956cc18dSsnj TRACE(("Couldn't allocate copy of selection types\n")); 1445d522f475Smrg } 1446956cc18dSsnj } 1447956cc18dSsnj } 1448956cc18dSsnj return override; 1449956cc18dSsnj} 1450956cc18dSsnj 1451956cc18dSsnj#if OPT_WIDE_CHARS 1452956cc18dSsnjstatic Atom * 1453e0a2b6dfSmrgallocUtf8Targets(Widget w, TScreen *screen) 1454956cc18dSsnj{ 1455956cc18dSsnj Atom **resultp = &(screen->selection_targets_utf8); 1456956cc18dSsnj 1457956cc18dSsnj if (*resultp == 0) { 1458956cc18dSsnj Atom *result; 1459956cc18dSsnj 1460956cc18dSsnj if (!overrideTargets(w, screen->utf8_select_types, &result)) { 1461a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1462956cc18dSsnj if (result == NULL) { 1463956cc18dSsnj TRACE(("Couldn't allocate utf-8 selection targets\n")); 1464956cc18dSsnj } else { 1465956cc18dSsnj int n = 0; 1466956cc18dSsnj 1467e39b573cSmrg if (XSupportsLocale()) { 1468e39b573cSmrg result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1469d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1470e39b573cSmrg if (screen->i18nSelections) { 1471e39b573cSmrg result[n++] = XA_TEXT(XtDisplay(w)); 1472e39b573cSmrg result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1473e39b573cSmrg } 1474d522f475Smrg#endif 1475e39b573cSmrg } 1476956cc18dSsnj result[n++] = XA_STRING; 1477956cc18dSsnj result[n] = None; 1478956cc18dSsnj } 1479d522f475Smrg } 1480956cc18dSsnj 1481956cc18dSsnj *resultp = result; 1482d522f475Smrg } 1483956cc18dSsnj 1484956cc18dSsnj return *resultp; 1485956cc18dSsnj} 1486d522f475Smrg#endif 1487d522f475Smrg 1488956cc18dSsnjstatic Atom * 1489e0a2b6dfSmrgalloc8bitTargets(Widget w, TScreen *screen) 1490956cc18dSsnj{ 1491956cc18dSsnj Atom **resultp = &(screen->selection_targets_8bit); 1492956cc18dSsnj 1493956cc18dSsnj if (*resultp == 0) { 1494956cc18dSsnj Atom *result = 0; 1495956cc18dSsnj 1496956cc18dSsnj if (!overrideTargets(w, screen->eightbit_select_types, &result)) { 1497a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1498956cc18dSsnj if (result == NULL) { 1499956cc18dSsnj TRACE(("Couldn't allocate 8bit selection targets\n")); 1500956cc18dSsnj } else { 1501956cc18dSsnj int n = 0; 1502956cc18dSsnj 1503e39b573cSmrg if (XSupportsLocale()) { 1504d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1505e39b573cSmrg result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1506956cc18dSsnj#endif 1507e39b573cSmrg if (screen->i18nSelections) { 1508e39b573cSmrg result[n++] = XA_TEXT(XtDisplay(w)); 1509e39b573cSmrg result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1510e39b573cSmrg } 1511956cc18dSsnj } 1512956cc18dSsnj result[n++] = XA_STRING; 1513956cc18dSsnj result[n] = None; 1514956cc18dSsnj } 1515956cc18dSsnj } 1516956cc18dSsnj 1517956cc18dSsnj *resultp = result; 1518956cc18dSsnj } 1519956cc18dSsnj 1520956cc18dSsnj return *resultp; 1521956cc18dSsnj} 1522956cc18dSsnj 1523956cc18dSsnjstatic Atom * 1524956cc18dSsnj_SelectionTargets(Widget w) 1525956cc18dSsnj{ 1526956cc18dSsnj Atom *result; 1527956cc18dSsnj TScreen *screen; 1528956cc18dSsnj XtermWidget xw; 1529956cc18dSsnj 1530956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) { 1531956cc18dSsnj result = NULL; 1532956cc18dSsnj } else { 1533956cc18dSsnj screen = TScreenOf(xw); 1534956cc18dSsnj 1535956cc18dSsnj#if OPT_WIDE_CHARS 1536956cc18dSsnj if (screen->wide_chars) { 1537956cc18dSsnj result = allocUtf8Targets(w, screen); 1538956cc18dSsnj } else 1539d522f475Smrg#endif 1540956cc18dSsnj { 1541956cc18dSsnj /* not screen->wide_chars */ 1542956cc18dSsnj result = alloc8bitTargets(w, screen); 1543d522f475Smrg } 1544d522f475Smrg } 1545956cc18dSsnj 1546956cc18dSsnj return result; 1547d522f475Smrg} 1548d522f475Smrg 1549d522f475Smrg#define isSELECT(value) (!strcmp(value, "SELECT")) 1550d522f475Smrg 1551d522f475Smrgstatic void 1552d522f475SmrgUnmapSelections(XtermWidget xw) 1553d522f475Smrg{ 1554956cc18dSsnj TScreen *screen = TScreenOf(xw); 1555d522f475Smrg Cardinal n; 1556d522f475Smrg 1557d522f475Smrg if (screen->mappedSelect) { 1558d522f475Smrg for (n = 0; screen->mappedSelect[n] != 0; ++n) 155920d2c4d2Smrg free((void *) screen->mappedSelect[n]); 1560d522f475Smrg free(screen->mappedSelect); 1561d522f475Smrg screen->mappedSelect = 0; 1562d522f475Smrg } 1563d522f475Smrg} 1564d522f475Smrg 1565d522f475Smrg/* 1566d522f475Smrg * xterm generally uses the primary selection. Some applications prefer 1567d522f475Smrg * (or are limited to) the clipboard. Since the translations resource is 1568d522f475Smrg * complicated, users seldom change the way it affects selection. But it 1569d522f475Smrg * is simple to remap the choice between primary and clipboard before the 1570d522f475Smrg * call to XmuInternStrings(). 1571d522f475Smrg */ 1572d522f475Smrgstatic String * 1573e0a2b6dfSmrgMapSelections(XtermWidget xw, String *params, Cardinal num_params) 1574d522f475Smrg{ 1575d522f475Smrg String *result = params; 1576d522f475Smrg 1577d522f475Smrg if (num_params > 0) { 1578d522f475Smrg Cardinal j; 1579d522f475Smrg Boolean map = False; 1580d522f475Smrg 1581d522f475Smrg for (j = 0; j < num_params; ++j) { 1582d522f475Smrg TRACE(("param[%d]:%s\n", j, params[j])); 1583d522f475Smrg if (isSELECT(params[j])) { 1584d522f475Smrg map = True; 1585d522f475Smrg break; 1586d522f475Smrg } 1587d522f475Smrg } 1588d522f475Smrg if (map) { 1589956cc18dSsnj TScreen *screen = TScreenOf(xw); 1590956cc18dSsnj const char *mapTo = (screen->selectToClipboard 1591d522f475Smrg ? "CLIPBOARD" 1592d522f475Smrg : "PRIMARY"); 1593d522f475Smrg 1594d522f475Smrg UnmapSelections(xw); 1595d522f475Smrg if ((result = TypeMallocN(String, num_params + 1)) != 0) { 1596d522f475Smrg result[num_params] = 0; 1597d522f475Smrg for (j = 0; j < num_params; ++j) { 1598d522f475Smrg result[j] = x_strdup((isSELECT(params[j]) 1599d522f475Smrg ? mapTo 1600d522f475Smrg : params[j])); 1601d522f475Smrg if (result[j] == 0) { 1602d522f475Smrg UnmapSelections(xw); 16030bd37d32Smrg while (j != 0) { 16040bd37d32Smrg free((void *) result[--j]); 16050bd37d32Smrg } 16060bd37d32Smrg free(result); 1607d522f475Smrg result = 0; 1608d522f475Smrg break; 1609d522f475Smrg } 1610d522f475Smrg } 1611956cc18dSsnj screen->mappedSelect = result; 1612d522f475Smrg } 1613d522f475Smrg } 1614d522f475Smrg } 1615d522f475Smrg return result; 1616d522f475Smrg} 1617d522f475Smrg 1618d522f475Smrg/* 1619d522f475Smrg * Lookup the cut-buffer number, which will be in the range 0-7. 1620d522f475Smrg * If it is not a cut-buffer, it is the primary selection (-1). 1621d522f475Smrg */ 1622d522f475Smrgstatic int 162320d2c4d2SmrgCutBuffer(Atom code) 1624d522f475Smrg{ 1625d522f475Smrg int cutbuffer; 162620d2c4d2Smrg switch ((unsigned) code) { 1627d522f475Smrg case XA_CUT_BUFFER0: 1628d522f475Smrg cutbuffer = 0; 1629d522f475Smrg break; 1630d522f475Smrg case XA_CUT_BUFFER1: 1631d522f475Smrg cutbuffer = 1; 1632d522f475Smrg break; 1633d522f475Smrg case XA_CUT_BUFFER2: 1634d522f475Smrg cutbuffer = 2; 1635d522f475Smrg break; 1636d522f475Smrg case XA_CUT_BUFFER3: 1637d522f475Smrg cutbuffer = 3; 1638d522f475Smrg break; 1639d522f475Smrg case XA_CUT_BUFFER4: 1640d522f475Smrg cutbuffer = 4; 1641d522f475Smrg break; 1642d522f475Smrg case XA_CUT_BUFFER5: 1643d522f475Smrg cutbuffer = 5; 1644d522f475Smrg break; 1645d522f475Smrg case XA_CUT_BUFFER6: 1646d522f475Smrg cutbuffer = 6; 1647d522f475Smrg break; 1648d522f475Smrg case XA_CUT_BUFFER7: 1649d522f475Smrg cutbuffer = 7; 1650d522f475Smrg break; 1651d522f475Smrg default: 1652d522f475Smrg cutbuffer = -1; 1653d522f475Smrg break; 1654d522f475Smrg } 16550bd37d32Smrg TRACE(("CutBuffer(%d) = %d\n", (int) code, cutbuffer)); 1656d522f475Smrg return cutbuffer; 1657d522f475Smrg} 1658d522f475Smrg 1659d522f475Smrg#if OPT_PASTE64 1660d522f475Smrgstatic void 1661d522f475SmrgFinishPaste64(XtermWidget xw) 1662d522f475Smrg{ 1663956cc18dSsnj TScreen *screen = TScreenOf(xw); 1664956cc18dSsnj 1665956cc18dSsnj TRACE(("FinishPaste64(%d)\n", screen->base64_paste)); 1666956cc18dSsnj if (screen->base64_paste) { 1667956cc18dSsnj screen->base64_paste = 0; 1668956cc18dSsnj unparseputc1(xw, screen->base64_final); 1669d522f475Smrg unparse_end(xw); 1670d522f475Smrg } 1671d522f475Smrg} 1672d522f475Smrg#endif 1673d522f475Smrg 1674d522f475Smrg#if !OPT_PASTE64 1675d522f475Smrgstatic 1676d522f475Smrg#endif 1677d522f475Smrgvoid 1678d522f475SmrgxtermGetSelection(Widget w, 1679d522f475Smrg Time ev_time, 1680e0a2b6dfSmrg String *params, /* selections in precedence order */ 1681d522f475Smrg Cardinal num_params, 1682894e0ac8Smrg Atom *targets) 1683d522f475Smrg{ 1684d522f475Smrg Atom selection; 1685d522f475Smrg int cutbuffer; 1686d522f475Smrg Atom target; 1687d522f475Smrg 1688956cc18dSsnj XtermWidget xw; 1689956cc18dSsnj 169020d2c4d2Smrg if (num_params == 0) 169120d2c4d2Smrg return; 1692956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 1693d522f475Smrg return; 1694d522f475Smrg 1695e0a2b6dfSmrg TRACE(("xtermGetSelection num_params %d @%ld\n", num_params, ev_time)); 1696956cc18dSsnj params = MapSelections(xw, params, num_params); 1697d522f475Smrg 1698d522f475Smrg XmuInternStrings(XtDisplay(w), params, (Cardinal) 1, &selection); 1699d522f475Smrg cutbuffer = CutBuffer(selection); 1700d522f475Smrg 1701956cc18dSsnj TRACE(("Cutbuffer: %d, target: %s\n", cutbuffer, 1702956cc18dSsnj (targets 1703956cc18dSsnj ? visibleSelectionTarget(XtDisplay(w), targets[0]) 1704956cc18dSsnj : "None"))); 1705d522f475Smrg 1706d522f475Smrg if (cutbuffer >= 0) { 1707d522f475Smrg int inbytes; 1708d522f475Smrg unsigned long nbytes; 1709d522f475Smrg int fmt8 = 8; 1710d522f475Smrg Atom type = XA_STRING; 1711d522f475Smrg char *line; 1712d522f475Smrg 1713d522f475Smrg /* 'line' is freed in SelectionReceived */ 1714d522f475Smrg line = XFetchBuffer(XtDisplay(w), &inbytes, cutbuffer); 1715d522f475Smrg nbytes = (unsigned long) inbytes; 1716d522f475Smrg 17170bd37d32Smrg if (nbytes > 0) { 1718d522f475Smrg SelectionReceived(w, NULL, &selection, &type, (XtPointer) line, 1719d522f475Smrg &nbytes, &fmt8); 17200bd37d32Smrg } else if (num_params > 1) { 1721d522f475Smrg xtermGetSelection(w, ev_time, params + 1, num_params - 1, NULL); 1722d522f475Smrg } 1723d522f475Smrg#if OPT_PASTE64 1724d522f475Smrg else { 1725956cc18dSsnj FinishPaste64(xw); 1726d522f475Smrg } 1727d522f475Smrg#endif 1728d522f475Smrg } else { 1729d522f475Smrg struct _SelectionList *list; 1730d522f475Smrg 1731d522f475Smrg if (targets == NULL || targets[0] == None) { 1732d522f475Smrg targets = _SelectionTargets(w); 1733d522f475Smrg } 1734d522f475Smrg 1735d522f475Smrg if (targets != 0) { 1736d522f475Smrg target = targets[0]; 1737d522f475Smrg 1738d522f475Smrg if (targets[1] == None) { /* last target in list */ 1739d522f475Smrg params++; 1740d522f475Smrg num_params--; 1741d522f475Smrg targets = _SelectionTargets(w); 1742d522f475Smrg } else { 1743d522f475Smrg targets = &(targets[1]); 1744d522f475Smrg } 1745d522f475Smrg 1746d522f475Smrg if (num_params) { 1747d522f475Smrg /* 'list' is freed in SelectionReceived */ 1748a1f3da82Smrg list = TypeXtMalloc(struct _SelectionList); 1749d522f475Smrg if (list != 0) { 1750d522f475Smrg list->params = params; 1751d522f475Smrg list->count = num_params; 1752d522f475Smrg list->targets = targets; 1753d522f475Smrg list->time = ev_time; 1754d522f475Smrg } 1755d522f475Smrg } else { 1756d522f475Smrg list = NULL; 1757d522f475Smrg } 1758d522f475Smrg 1759d522f475Smrg XtGetSelectionValue(w, selection, 1760d522f475Smrg target, 1761d522f475Smrg SelectionReceived, 1762d522f475Smrg (XtPointer) list, ev_time); 1763d522f475Smrg } 1764d522f475Smrg } 1765d522f475Smrg} 1766d522f475Smrg 1767d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 1768d522f475Smrgstatic void 1769e0a2b6dfSmrgGettingSelection(Display *dpy, Atom type, Char *line, unsigned long len) 1770d522f475Smrg{ 1771d522f475Smrg Char *cp; 1772d522f475Smrg char *name; 1773d522f475Smrg 1774d522f475Smrg name = XGetAtomName(dpy, type); 1775d522f475Smrg 1776d522f475Smrg TRACE(("Getting %s (%ld)\n", name, (long int) type)); 1777d522f475Smrg for (cp = line; cp < line + len; cp++) { 1778956cc18dSsnj TRACE(("[%d:%lu]", (int) (cp + 1 - line), len)); 1779d522f475Smrg if (isprint(*cp)) { 1780d522f475Smrg TRACE(("%c\n", *cp)); 1781d522f475Smrg } else { 1782d522f475Smrg TRACE(("\\x%02x\n", *cp)); 1783d522f475Smrg } 1784d522f475Smrg } 1785d522f475Smrg} 1786d522f475Smrg#else 1787d522f475Smrg#define GettingSelection(dpy,type,line,len) /* nothing */ 1788d522f475Smrg#endif 1789d522f475Smrg 1790d522f475Smrg#ifdef VMS 1791d522f475Smrg# define tty_vwrite(pty,lag,l) tt_write(lag,l) 1792d522f475Smrg#else /* !( VMS ) */ 1793d522f475Smrg# define tty_vwrite(pty,lag,l) v_write(pty,lag,l) 1794d522f475Smrg#endif /* defined VMS */ 1795d522f475Smrg 1796d522f475Smrg#if OPT_PASTE64 1797d522f475Smrg/* Return base64 code character given 6-bit number */ 1798d522f475Smrgstatic const char base64_code[] = "\ 1799d522f475SmrgABCDEFGHIJKLMNOPQRSTUVWXYZ\ 1800d522f475Smrgabcdefghijklmnopqrstuvwxyz\ 1801d522f475Smrg0123456789+/"; 1802d522f475Smrgstatic void 1803e0a2b6dfSmrgbase64_flush(TScreen *screen) 1804d522f475Smrg{ 1805d522f475Smrg Char x; 1806d522f475Smrg switch (screen->base64_count) { 1807d522f475Smrg case 0: 1808d522f475Smrg break; 1809d522f475Smrg case 2: 18102eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 4]); 1811d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1812d522f475Smrg break; 1813d522f475Smrg case 4: 18142eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 2]); 1815d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1816d522f475Smrg break; 1817d522f475Smrg } 1818d522f475Smrg if (screen->base64_pad & 3) 1819d522f475Smrg tty_vwrite(screen->respond, 1820492d43a5Smrg (const Char *) "===", 1821d522f475Smrg (unsigned) (4 - (screen->base64_pad & 3))); 1822d522f475Smrg screen->base64_count = 0; 1823d522f475Smrg screen->base64_accu = 0; 1824d522f475Smrg screen->base64_pad = 0; 1825d522f475Smrg} 1826d522f475Smrg#endif /* OPT_PASTE64 */ 1827d522f475Smrg 1828e0a2b6dfSmrg/* 1829e0a2b6dfSmrg * Translate ISO-8859-1 or UTF-8 data to NRCS. 1830e0a2b6dfSmrg */ 1831d522f475Smrgstatic void 1832e0a2b6dfSmrgToNational(TScreen *screen, Char *buffer, unsigned *length) 1833e0a2b6dfSmrg{ 1834e0a2b6dfSmrg int gsetL = screen->gsets[screen->curgl]; 1835e0a2b6dfSmrg int gsetR = screen->gsets[screen->curgr]; 1836e0a2b6dfSmrg unsigned chr, out, gl, gr; 1837e0a2b6dfSmrg Char *p; 1838e0a2b6dfSmrg 1839e0a2b6dfSmrg#if OPT_WIDE_CHARS 1840e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 1841e0a2b6dfSmrg PtyData *data = TypeXtMallocX(PtyData, *length); 1842e0a2b6dfSmrg 1843e0a2b6dfSmrg memset(data, 0, sizeof(*data)); 1844e0a2b6dfSmrg data->next = data->buffer; 1845e0a2b6dfSmrg data->last = data->buffer + *length; 1846e0a2b6dfSmrg memcpy(data->buffer, buffer, (size_t) *length); 1847e0a2b6dfSmrg p = buffer; 1848e0a2b6dfSmrg while (data->next < data->last) { 1849894e0ac8Smrg if (!decodeUtf8(screen, data)) { 1850e0a2b6dfSmrg data->utf_size = 1; 1851e0a2b6dfSmrg data->utf_data = data->next[0]; 1852e0a2b6dfSmrg } 1853e0a2b6dfSmrg data->next += data->utf_size; 1854e0a2b6dfSmrg chr = data->utf_data; 1855e0a2b6dfSmrg out = chr; 1856e0a2b6dfSmrg if ((gl = xtermCharSetIn(screen, chr, gsetL)) != chr) { 1857e0a2b6dfSmrg out = gl; 1858e0a2b6dfSmrg } else if ((gr = xtermCharSetIn(screen, chr, gsetR)) != chr) { 1859e0a2b6dfSmrg out = gr; 1860e0a2b6dfSmrg } 1861e0a2b6dfSmrg *p++ = (Char) ((out < 256) ? out : ' '); 1862e0a2b6dfSmrg } 1863e0a2b6dfSmrg *length = (unsigned) (p - buffer); 1864e0a2b6dfSmrg free(data); 1865e0a2b6dfSmrg } else 1866e0a2b6dfSmrg#endif 1867e0a2b6dfSmrg { 1868e0a2b6dfSmrg for (p = buffer; (int) (p - buffer) < (int) *length; ++p) { 1869e0a2b6dfSmrg chr = *p; 1870e0a2b6dfSmrg out = chr; 1871e0a2b6dfSmrg if ((gl = xtermCharSetIn(screen, chr, gsetL)) != chr) { 1872e0a2b6dfSmrg out = gl; 1873e0a2b6dfSmrg } else if ((gr = xtermCharSetIn(screen, chr, gsetR)) != chr) { 1874e0a2b6dfSmrg out = gr; 1875e0a2b6dfSmrg } 1876e0a2b6dfSmrg *p = (Char) out; 1877e0a2b6dfSmrg } 1878e0a2b6dfSmrg } 1879e0a2b6dfSmrg} 1880e0a2b6dfSmrg 1881e0a2b6dfSmrgstatic void 1882e0a2b6dfSmrg_qWriteSelectionData(XtermWidget xw, Char *lag, unsigned length) 1883d522f475Smrg{ 18840bd37d32Smrg TScreen *screen = TScreenOf(xw); 18850bd37d32Smrg 1886e0a2b6dfSmrg /* 1887e0a2b6dfSmrg * If we are pasting into a window which is using NRCS, we want to map 1888e0a2b6dfSmrg * the text from the normal encoding (ISO-8859-1 or UTF-8) into the coding 1889e0a2b6dfSmrg * that an application would use to write characters with NRCS. 1890e0a2b6dfSmrg * 1891e0a2b6dfSmrg * TODO: handle conversion from UTF-8, and adjust length. This can be done 1892e0a2b6dfSmrg * in the same buffer because the target is always 8-bit. 1893e0a2b6dfSmrg */ 1894e0a2b6dfSmrg if ((xw->flags & NATIONAL) && (length != 0)) { 1895e0a2b6dfSmrg ToNational(screen, lag, &length); 1896e0a2b6dfSmrg } 1897d522f475Smrg#if OPT_PASTE64 1898d522f475Smrg if (screen->base64_paste) { 1899d522f475Smrg /* Send data as base64 */ 1900d522f475Smrg Char *p = lag; 1901d522f475Smrg Char buf[64]; 1902d522f475Smrg unsigned x = 0; 19030bd37d32Smrg 19040bd37d32Smrg /* 19050bd37d32Smrg * Handle the case where the selection is from _this_ xterm, which 19060bd37d32Smrg * puts part of the reply in the buffer before the selection callback 19070bd37d32Smrg * happens. 19080bd37d32Smrg */ 19090bd37d32Smrg if (screen->base64_paste && screen->unparse_len) { 19100bd37d32Smrg unparse_end(xw); 19110bd37d32Smrg } 1912d522f475Smrg while (length--) { 1913d522f475Smrg switch (screen->base64_count) { 1914d522f475Smrg case 0: 19152eaa94a1Schristos buf[x++] = CharOf(base64_code[*p >> 2]); 19162eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0x3); 1917d522f475Smrg screen->base64_count = 2; 1918d522f475Smrg ++p; 1919d522f475Smrg break; 1920d522f475Smrg case 2: 19212eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 4) + 19222eaa94a1Schristos (*p >> 4)]); 19232eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0xF); 1924d522f475Smrg screen->base64_count = 4; 1925d522f475Smrg ++p; 1926d522f475Smrg break; 1927d522f475Smrg case 4: 19282eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 2) + 19292eaa94a1Schristos (*p >> 6)]); 19302eaa94a1Schristos buf[x++] = CharOf(base64_code[*p & 0x3F]); 1931d522f475Smrg screen->base64_accu = 0; 1932d522f475Smrg screen->base64_count = 0; 1933d522f475Smrg ++p; 1934d522f475Smrg break; 1935d522f475Smrg } 1936d522f475Smrg if (x >= 63) { 1937d522f475Smrg /* Write 63 or 64 characters */ 1938d522f475Smrg screen->base64_pad += x; 1939d522f475Smrg tty_vwrite(screen->respond, buf, x); 1940d522f475Smrg x = 0; 1941d522f475Smrg } 1942d522f475Smrg } 1943d522f475Smrg if (x != 0) { 1944d522f475Smrg screen->base64_pad += x; 1945d522f475Smrg tty_vwrite(screen->respond, buf, x); 1946d522f475Smrg } 1947d522f475Smrg } else 1948d522f475Smrg#endif /* OPT_PASTE64 */ 1949d522f475Smrg#if OPT_READLINE 1950d522f475Smrg if (SCREEN_FLAG(screen, paste_quotes)) { 1951d522f475Smrg while (length--) { 1952492d43a5Smrg tty_vwrite(screen->respond, (const Char *) "\026", 1); /* Control-V */ 1953d522f475Smrg tty_vwrite(screen->respond, lag++, 1); 1954d522f475Smrg } 1955d522f475Smrg } else 1956d522f475Smrg#endif 1957d522f475Smrg tty_vwrite(screen->respond, lag, length); 1958d522f475Smrg} 1959d522f475Smrg 1960d522f475Smrgstatic void 1961e0a2b6dfSmrg_WriteSelectionData(XtermWidget xw, Char *line, size_t length) 1962d522f475Smrg{ 1963d522f475Smrg /* Write data to pty a line at a time. */ 1964d522f475Smrg /* Doing this one line at a time may no longer be necessary 1965d522f475Smrg because v_write has been re-written. */ 1966d522f475Smrg 19670bd37d32Smrg TScreen *screen = TScreenOf(xw); 1968d522f475Smrg Char *lag, *end; 1969d522f475Smrg 1970d522f475Smrg /* in the VMS version, if tt_pasting isn't set to True then qio 1971d522f475Smrg reads aren't blocked and an infinite loop is entered, where the 1972d522f475Smrg pasted text shows up as new input, goes in again, shows up 1973d522f475Smrg again, ad nauseum. */ 1974d522f475Smrg#ifdef VMS 1975d522f475Smrg tt_pasting = True; 1976d522f475Smrg#endif 1977d522f475Smrg 1978d522f475Smrg end = &line[length]; 1979d522f475Smrg lag = line; 1980d522f475Smrg 1981d522f475Smrg#if OPT_PASTE64 1982d522f475Smrg if (screen->base64_paste) { 19830bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (end - lag)); 1984d522f475Smrg base64_flush(screen); 1985d522f475Smrg } else 1986d522f475Smrg#endif 1987d522f475Smrg { 1988d522f475Smrg if (!SCREEN_FLAG(screen, paste_literal_nl)) { 1989d522f475Smrg Char *cp; 1990d522f475Smrg for (cp = line; cp != end; cp++) { 1991d522f475Smrg if (*cp == '\n') { 1992d522f475Smrg *cp = '\r'; 19930bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (cp - lag + 1)); 1994d522f475Smrg lag = cp + 1; 1995d522f475Smrg } 1996d522f475Smrg } 1997d522f475Smrg } 1998d522f475Smrg 1999d522f475Smrg if (lag != end) { 20000bd37d32Smrg _qWriteSelectionData(xw, lag, (unsigned) (end - lag)); 2001d522f475Smrg } 2002d522f475Smrg } 2003d522f475Smrg#ifdef VMS 2004d522f475Smrg tt_pasting = False; 2005d522f475Smrg tt_start_read(); /* reenable reads or a character may be lost */ 2006d522f475Smrg#endif 2007d522f475Smrg} 2008d522f475Smrg 2009d522f475Smrg#if OPT_READLINE 2010d522f475Smrgstatic void 2011e0a2b6dfSmrg_WriteKey(TScreen *screen, const Char *in) 2012d522f475Smrg{ 2013d522f475Smrg Char line[16]; 2014d522f475Smrg unsigned count = 0; 2015492d43a5Smrg size_t length = strlen((const char *) in); 2016d522f475Smrg 2017d522f475Smrg if (screen->control_eight_bits) { 2018d522f475Smrg line[count++] = ANSI_CSI; 2019d522f475Smrg } else { 2020d522f475Smrg line[count++] = ANSI_ESC; 2021d522f475Smrg line[count++] = '['; 2022d522f475Smrg } 2023d522f475Smrg while (length--) 2024d522f475Smrg line[count++] = *in++; 2025d522f475Smrg line[count++] = '~'; 2026d522f475Smrg tty_vwrite(screen->respond, line, count); 2027d522f475Smrg} 2028d522f475Smrg#endif /* OPT_READLINE */ 2029d522f475Smrg 20300bd37d32Smrg/* 20310bd37d32Smrg * Unless enabled by the user, strip control characters other than formatting. 20320bd37d32Smrg */ 20330bd37d32Smrgstatic size_t 20340bd37d32SmrgremoveControls(XtermWidget xw, char *value) 20350bd37d32Smrg{ 20360bd37d32Smrg TScreen *screen = TScreenOf(xw); 20370bd37d32Smrg size_t dst = 0; 20380bd37d32Smrg size_t src = 0; 20390bd37d32Smrg 20400bd37d32Smrg if (screen->allowPasteControls) { 20410bd37d32Smrg dst = strlen(value); 20420bd37d32Smrg } else { 20430bd37d32Smrg while ((value[dst] = value[src]) != '\0') { 20440bd37d32Smrg int ch = CharOf(value[src++]); 20450bd37d32Smrg if (ch < 32) { 20460bd37d32Smrg switch (ch) { 20470bd37d32Smrg case '\b': 20480bd37d32Smrg case '\t': 20490bd37d32Smrg case '\n': 20500bd37d32Smrg case '\r': 20510bd37d32Smrg ++dst; 20520bd37d32Smrg break; 20530bd37d32Smrg default: 20540bd37d32Smrg continue; 20550bd37d32Smrg } 20560bd37d32Smrg } 20570bd37d32Smrg#if OPT_WIDE_CHARS 2058e0a2b6dfSmrg else if (screen->utf8_inparse || screen->utf8_nrc_mode) 20590bd37d32Smrg ++dst; 20600bd37d32Smrg#endif 20610bd37d32Smrg#if OPT_C1_PRINT || OPT_WIDE_CHARS 20620bd37d32Smrg else if (screen->c1_printable) 20630bd37d32Smrg ++dst; 20640bd37d32Smrg#endif 20650bd37d32Smrg else if (ch >= 128 && ch < 160) 20660bd37d32Smrg continue; 20670bd37d32Smrg else 20680bd37d32Smrg ++dst; 20690bd37d32Smrg } 20700bd37d32Smrg } 20710bd37d32Smrg return dst; 20720bd37d32Smrg} 20730bd37d32Smrg 2074d522f475Smrg/* SelectionReceived: stuff received selection text into pty */ 2075d522f475Smrg 2076d522f475Smrg/* ARGSUSED */ 2077d522f475Smrgstatic void 2078d522f475SmrgSelectionReceived(Widget w, 2079d522f475Smrg XtPointer client_data, 2080894e0ac8Smrg Atom *selection GCC_UNUSED, 2081894e0ac8Smrg Atom *type, 2082d522f475Smrg XtPointer value, 2083d522f475Smrg unsigned long *length, 2084d522f475Smrg int *format) 2085d522f475Smrg{ 2086d522f475Smrg char **text_list = NULL; 2087d522f475Smrg int text_list_count; 2088d522f475Smrg XTextProperty text_prop; 2089d522f475Smrg TScreen *screen; 2090d522f475Smrg Display *dpy; 2091d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 2092d522f475Smrg Char *line = (Char *) value; 2093d522f475Smrg#endif 2094d522f475Smrg 2095956cc18dSsnj XtermWidget xw; 2096956cc18dSsnj 2097956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 2098d522f475Smrg return; 2099956cc18dSsnj 2100956cc18dSsnj screen = TScreenOf(xw); 2101d522f475Smrg dpy = XtDisplay(w); 2102d522f475Smrg 2103d522f475Smrg if (*type == 0 /*XT_CONVERT_FAIL */ 2104d522f475Smrg || *length == 0 2105d522f475Smrg || value == NULL) 2106d522f475Smrg goto fail; 2107d522f475Smrg 2108d522f475Smrg text_prop.value = (unsigned char *) value; 2109d522f475Smrg text_prop.encoding = *type; 2110d522f475Smrg text_prop.format = *format; 2111d522f475Smrg text_prop.nitems = *length; 2112d522f475Smrg 2113956cc18dSsnj TRACE(("SelectionReceived %s format %d, nitems %ld\n", 2114956cc18dSsnj visibleSelectionTarget(dpy, text_prop.encoding), 2115956cc18dSsnj text_prop.format, 2116956cc18dSsnj text_prop.nitems)); 2117956cc18dSsnj 2118d522f475Smrg#if OPT_WIDE_CHARS 2119e39b573cSmrg if (XSupportsLocale() && screen->wide_chars) { 2120d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2121d522f475Smrg *type == XA_STRING || 2122d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2123d522f475Smrg GettingSelection(dpy, *type, line, *length); 2124d522f475Smrg if (Xutf8TextPropertyToTextList(dpy, &text_prop, 2125d522f475Smrg &text_list, 2126d522f475Smrg &text_list_count) < 0) { 2127e39b573cSmrg TRACE(("default Xutf8 Conversion failed\n")); 2128d522f475Smrg text_list = NULL; 2129d522f475Smrg } 2130d522f475Smrg } 2131d522f475Smrg } else 2132d522f475Smrg#endif /* OPT_WIDE_CHARS */ 2133d522f475Smrg { 2134d522f475Smrg /* Convert the selection to locale's multibyte encoding. */ 2135d522f475Smrg 2136d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 2137d522f475Smrg *type == XA_STRING || 2138d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 2139d522f475Smrg Status rc; 2140d522f475Smrg 2141d522f475Smrg GettingSelection(dpy, *type, line, *length); 2142d522f475Smrg 2143d522f475Smrg#if OPT_WIDE_CHARS 2144d522f475Smrg if (*type == XA_UTF8_STRING(dpy) && 2145d522f475Smrg !(screen->wide_chars || screen->c1_printable)) { 214620d2c4d2Smrg rc = xtermUtf8ToTextList(xw, &text_prop, 214720d2c4d2Smrg &text_list, &text_list_count); 2148d522f475Smrg } else 2149d522f475Smrg#endif 2150e39b573cSmrg if (*type == XA_STRING && (!XSupportsLocale() || screen->brokenSelections)) { 2151d522f475Smrg rc = XTextPropertyToStringList(&text_prop, 2152d522f475Smrg &text_list, &text_list_count); 2153d522f475Smrg } else { 2154d522f475Smrg rc = XmbTextPropertyToTextList(dpy, &text_prop, 2155d522f475Smrg &text_list, 2156d522f475Smrg &text_list_count); 2157d522f475Smrg } 2158d522f475Smrg if (rc < 0) { 2159d522f475Smrg TRACE(("Conversion failed\n")); 2160d522f475Smrg text_list = NULL; 2161d522f475Smrg } 2162d522f475Smrg } 2163d522f475Smrg } 2164d522f475Smrg 2165d522f475Smrg if (text_list != NULL && text_list_count != 0) { 2166d522f475Smrg int i; 2167d522f475Smrg 2168d522f475Smrg#if OPT_PASTE64 2169d522f475Smrg if (screen->base64_paste) { 2170a1f3da82Smrg /* EMPTY */ ; 2171d522f475Smrg } else 2172d522f475Smrg#endif 2173d522f475Smrg#if OPT_READLINE 2174d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 2175492d43a5Smrg _WriteKey(screen, (const Char *) "200"); 2176d522f475Smrg } 2177d522f475Smrg#endif 2178d522f475Smrg for (i = 0; i < text_list_count; i++) { 21790bd37d32Smrg size_t len = removeControls(xw, text_list[i]); 21800bd37d32Smrg if (screen->selectToBuffer) { 21810bd37d32Smrg size_t have = (screen->internal_select 21820bd37d32Smrg ? strlen(screen->internal_select) 21830bd37d32Smrg : 0); 21840bd37d32Smrg size_t need = have + len + 1; 21850bd37d32Smrg char *buffer = realloc(screen->internal_select, need); 21860bd37d32Smrg if (buffer != 0) { 21870bd37d32Smrg strcpy(buffer + have, text_list[i]); 21880bd37d32Smrg screen->internal_select = buffer; 21890bd37d32Smrg } 21900bd37d32Smrg } else { 21910bd37d32Smrg _WriteSelectionData(xw, (Char *) text_list[i], len); 21920bd37d32Smrg } 2193d522f475Smrg } 2194d522f475Smrg#if OPT_PASTE64 2195d522f475Smrg if (screen->base64_paste) { 2196956cc18dSsnj FinishPaste64(xw); 2197d522f475Smrg } else 2198d522f475Smrg#endif 2199d522f475Smrg#if OPT_READLINE 2200d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 2201492d43a5Smrg _WriteKey(screen, (const Char *) "201"); 2202d522f475Smrg } 2203d522f475Smrg#endif 2204d522f475Smrg XFreeStringList(text_list); 2205d522f475Smrg } else 2206d522f475Smrg goto fail; 2207d522f475Smrg 2208d522f475Smrg XtFree((char *) client_data); 2209d522f475Smrg XtFree((char *) value); 2210d522f475Smrg 2211d522f475Smrg return; 2212d522f475Smrg 2213d522f475Smrg fail: 2214d522f475Smrg if (client_data != 0) { 2215d522f475Smrg struct _SelectionList *list = (struct _SelectionList *) client_data; 2216956cc18dSsnj 2217956cc18dSsnj TRACE(("SelectionReceived ->xtermGetSelection\n")); 2218d522f475Smrg xtermGetSelection(w, list->time, 2219d522f475Smrg list->params, list->count, list->targets); 2220d522f475Smrg XtFree((char *) client_data); 2221d522f475Smrg#if OPT_PASTE64 2222d522f475Smrg } else { 2223956cc18dSsnj FinishPaste64(xw); 2224d522f475Smrg#endif 2225d522f475Smrg } 2226d522f475Smrg return; 2227d522f475Smrg} 2228d522f475Smrg 2229d522f475Smrgvoid 2230d522f475SmrgHandleInsertSelection(Widget w, 2231894e0ac8Smrg XEvent *event, /* assumed to be XButtonEvent* */ 2232e0a2b6dfSmrg String *params, /* selections in precedence order */ 2233d522f475Smrg Cardinal *num_params) 2234d522f475Smrg{ 2235956cc18dSsnj XtermWidget xw; 2236d522f475Smrg 2237956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 22380bd37d32Smrg TRACE(("HandleInsertSelection\n")); 2239d522f475Smrg if (!SendMousePosition(xw, event)) { 2240d522f475Smrg#if OPT_READLINE 2241d522f475Smrg int ldelta; 2242956cc18dSsnj TScreen *screen = TScreenOf(xw); 2243492d43a5Smrg if (IsBtnEvent(event) 2244d522f475Smrg /* Disable on Shift-mouse, including the application-mouse modes */ 2245492d43a5Smrg && !(KeyModifiers(event) & ShiftMask) 2246d522f475Smrg && (screen->send_mouse_pos == MOUSE_OFF) 2247d522f475Smrg && SCREEN_FLAG(screen, paste_moves) 2248d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta)) 2249d522f475Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta); 2250d522f475Smrg#endif /* OPT_READLINE */ 2251d522f475Smrg 2252d522f475Smrg xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL); 2253d522f475Smrg } 2254d522f475Smrg } 2255d522f475Smrg} 2256d522f475Smrg 2257d522f475Smrgstatic SelectUnit 2258956cc18dSsnjEvalSelectUnit(XtermWidget xw, 2259d522f475Smrg Time buttonDownTime, 2260d522f475Smrg SelectUnit defaultUnit, 2261d522f475Smrg unsigned int button) 2262d522f475Smrg{ 2263956cc18dSsnj TScreen *screen = TScreenOf(xw); 2264d522f475Smrg SelectUnit result; 2265d522f475Smrg int delta; 2266d522f475Smrg 2267d522f475Smrg if (button != screen->lastButton) { 226820d2c4d2Smrg delta = screen->multiClickTime + 1; 2269d522f475Smrg } else if (screen->lastButtonUpTime == (Time) 0) { 2270d522f475Smrg /* first time and once in a blue moon */ 2271d522f475Smrg delta = screen->multiClickTime + 1; 2272d522f475Smrg } else if (buttonDownTime > screen->lastButtonUpTime) { 2273d522f475Smrg /* most of the time */ 22742eaa94a1Schristos delta = (int) (buttonDownTime - screen->lastButtonUpTime); 2275d522f475Smrg } else { 2276d522f475Smrg /* time has rolled over since lastButtonUpTime */ 22772eaa94a1Schristos delta = (int) ((((Time) ~ 0) - screen->lastButtonUpTime) + buttonDownTime); 2278d522f475Smrg } 2279d522f475Smrg 2280d522f475Smrg if (delta > screen->multiClickTime) { 2281d522f475Smrg screen->numberOfClicks = 1; 2282d522f475Smrg result = defaultUnit; 2283d522f475Smrg } else { 2284d522f475Smrg result = screen->selectMap[screen->numberOfClicks % screen->maxClicks]; 2285d522f475Smrg screen->numberOfClicks += 1; 2286d522f475Smrg } 2287d522f475Smrg TRACE(("EvalSelectUnit(%d) = %d\n", screen->numberOfClicks, result)); 2288d522f475Smrg return result; 2289d522f475Smrg} 2290d522f475Smrg 2291d522f475Smrgstatic void 2292d522f475Smrgdo_select_start(XtermWidget xw, 2293894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2294e0a2b6dfSmrg CELL *cell) 2295d522f475Smrg{ 2296956cc18dSsnj TScreen *screen = TScreenOf(xw); 2297d522f475Smrg 2298d522f475Smrg if (SendMousePosition(xw, event)) 2299d522f475Smrg return; 2300956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2301d522f475Smrg event->xbutton.time, 2302d522f475Smrg Select_CHAR, 2303d522f475Smrg event->xbutton.button); 2304d522f475Smrg screen->replyToEmacs = False; 2305d522f475Smrg 2306d522f475Smrg#if OPT_READLINE 2307d522f475Smrg lastButtonDownTime = event->xbutton.time; 2308d522f475Smrg#endif 2309d522f475Smrg 2310d522f475Smrg StartSelect(xw, cell); 2311d522f475Smrg} 2312d522f475Smrg 2313d522f475Smrg/* ARGSUSED */ 2314d522f475Smrgvoid 2315d522f475SmrgHandleSelectStart(Widget w, 2316894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2317e0a2b6dfSmrg String *params GCC_UNUSED, 2318d522f475Smrg Cardinal *num_params GCC_UNUSED) 2319d522f475Smrg{ 2320956cc18dSsnj XtermWidget xw; 2321956cc18dSsnj 2322956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2323956cc18dSsnj TScreen *screen = TScreenOf(xw); 2324d522f475Smrg CELL cell; 2325d522f475Smrg 23260bd37d32Smrg TRACE(("HandleSelectStart\n")); 2327d522f475Smrg screen->firstValidRow = 0; 2328d522f475Smrg screen->lastValidRow = screen->max_row; 2329d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2330d522f475Smrg 2331d522f475Smrg#if OPT_READLINE 2332d522f475Smrg ExtendingSelection = 0; 2333d522f475Smrg#endif 2334d522f475Smrg 2335d522f475Smrg do_select_start(xw, event, &cell); 2336d522f475Smrg } 2337d522f475Smrg} 2338d522f475Smrg 2339d522f475Smrg/* ARGSUSED */ 2340d522f475Smrgvoid 2341d522f475SmrgHandleKeyboardSelectStart(Widget w, 2342894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2343e0a2b6dfSmrg String *params GCC_UNUSED, 2344d522f475Smrg Cardinal *num_params GCC_UNUSED) 2345d522f475Smrg{ 2346956cc18dSsnj XtermWidget xw; 2347956cc18dSsnj 2348956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2349956cc18dSsnj TScreen *screen = TScreenOf(xw); 23500bd37d32Smrg 23510bd37d32Smrg TRACE(("HandleKeyboardSelectStart\n")); 2352d522f475Smrg do_select_start(xw, event, &screen->cursorp); 2353d522f475Smrg } 2354d522f475Smrg} 2355d522f475Smrg 2356d522f475Smrgstatic void 2357894e0ac8SmrgTrackDown(XtermWidget xw, XButtonEvent *event) 2358d522f475Smrg{ 2359956cc18dSsnj TScreen *screen = TScreenOf(xw); 2360d522f475Smrg CELL cell; 2361d522f475Smrg 2362956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2363d522f475Smrg event->time, 2364d522f475Smrg Select_CHAR, 2365d522f475Smrg event->button); 2366d522f475Smrg if (screen->numberOfClicks > 1) { 2367d522f475Smrg PointToCELL(screen, event->y, event->x, &cell); 2368d522f475Smrg screen->replyToEmacs = True; 2369d522f475Smrg StartSelect(xw, &cell); 2370d522f475Smrg } else { 2371d522f475Smrg screen->waitingForTrackInfo = True; 2372492d43a5Smrg EditorButton(xw, event); 2373d522f475Smrg } 2374d522f475Smrg} 2375d522f475Smrg 2376d522f475Smrg#define boundsCheck(x) if (x < 0) \ 2377d522f475Smrg x = 0; \ 2378d522f475Smrg else if (x >= screen->max_row) \ 2379d522f475Smrg x = screen->max_row 2380d522f475Smrg 2381d522f475Smrgvoid 2382d522f475SmrgTrackMouse(XtermWidget xw, 2383d522f475Smrg int func, 2384e0a2b6dfSmrg CELL *start, 2385d522f475Smrg int firstrow, 2386d522f475Smrg int lastrow) 2387d522f475Smrg{ 2388956cc18dSsnj TScreen *screen = TScreenOf(xw); 2389d522f475Smrg 2390d522f475Smrg if (screen->waitingForTrackInfo) { /* if Timed, ignore */ 2391d522f475Smrg screen->waitingForTrackInfo = False; 2392d522f475Smrg 2393d522f475Smrg if (func != 0) { 2394d522f475Smrg CELL first = *start; 2395d522f475Smrg 2396d522f475Smrg boundsCheck(first.row); 2397d522f475Smrg boundsCheck(firstrow); 2398d522f475Smrg boundsCheck(lastrow); 2399d522f475Smrg screen->firstValidRow = firstrow; 2400d522f475Smrg screen->lastValidRow = lastrow; 2401d522f475Smrg screen->replyToEmacs = True; 2402d522f475Smrg StartSelect(xw, &first); 2403d522f475Smrg } 2404d522f475Smrg } 2405d522f475Smrg} 2406d522f475Smrg 2407d522f475Smrgstatic void 2408e0a2b6dfSmrgStartSelect(XtermWidget xw, const CELL *cell) 2409d522f475Smrg{ 2410956cc18dSsnj TScreen *screen = TScreenOf(xw); 2411d522f475Smrg 2412d522f475Smrg TRACE(("StartSelect row=%d, col=%d\n", cell->row, cell->col)); 2413d522f475Smrg if (screen->cursor_state) 2414d522f475Smrg HideCursor(); 2415d522f475Smrg if (screen->numberOfClicks == 1) { 2416d522f475Smrg /* set start of selection */ 2417d522f475Smrg screen->rawPos = *cell; 2418d522f475Smrg } 2419d522f475Smrg /* else use old values in rawPos */ 2420d522f475Smrg screen->saveStartR = screen->startExt = screen->rawPos; 2421d522f475Smrg screen->saveEndR = screen->endExt = screen->rawPos; 2422d522f475Smrg if (Coordinate(screen, cell) < Coordinate(screen, &(screen->rawPos))) { 2423d522f475Smrg screen->eventMode = LEFTEXTENSION; 2424d522f475Smrg screen->startExt = *cell; 2425d522f475Smrg } else { 2426d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2427d522f475Smrg screen->endExt = *cell; 2428d522f475Smrg } 2429d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 2430d522f475Smrg} 2431d522f475Smrg 2432d522f475Smrgstatic void 2433d522f475SmrgEndExtend(XtermWidget xw, 2434894e0ac8Smrg XEvent *event, /* must be XButtonEvent */ 2435e0a2b6dfSmrg String *params, /* selections */ 2436d522f475Smrg Cardinal num_params, 2437d522f475Smrg Bool use_cursor_loc) 2438d522f475Smrg{ 2439d522f475Smrg CELL cell; 2440d522f475Smrg unsigned count; 2441956cc18dSsnj TScreen *screen = TScreenOf(xw); 24420bd37d32Smrg Char line[64]; 2443d522f475Smrg 2444d522f475Smrg if (use_cursor_loc) { 2445d522f475Smrg cell = screen->cursorp; 2446d522f475Smrg } else { 2447d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2448d522f475Smrg } 2449d522f475Smrg ExtendExtend(xw, &cell); 2450d522f475Smrg screen->lastButtonUpTime = event->xbutton.time; 2451d522f475Smrg screen->lastButton = event->xbutton.button; 2452d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 2453d522f475Smrg if (screen->replyToEmacs) { 2454d522f475Smrg count = 0; 2455d522f475Smrg if (screen->control_eight_bits) { 2456d522f475Smrg line[count++] = ANSI_CSI; 2457d522f475Smrg } else { 2458d522f475Smrg line[count++] = ANSI_ESC; 2459d522f475Smrg line[count++] = '['; 2460d522f475Smrg } 2461d522f475Smrg if (isSameCELL(&(screen->rawPos), &(screen->startSel)) 2462d522f475Smrg && isSameCELL(&cell, &(screen->endSel))) { 2463d522f475Smrg /* Use short-form emacs select */ 24640bd37d32Smrg 24650bd37d32Smrg switch (screen->extend_coords) { 24660bd37d32Smrg case 0: 24670bd37d32Smrg case SET_EXT_MODE_MOUSE: 24680bd37d32Smrg line[count++] = 't'; 24690bd37d32Smrg break; 24700bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 24710bd37d32Smrg line[count++] = '<'; 24720bd37d32Smrg break; 24730bd37d32Smrg } 24740bd37d32Smrg 2475492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 24760bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2477492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 24780bd37d32Smrg 24790bd37d32Smrg switch (screen->extend_coords) { 24800bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 24810bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 24820bd37d32Smrg line[count++] = 't'; 24830bd37d32Smrg break; 24840bd37d32Smrg } 2485d522f475Smrg } else { 2486d522f475Smrg /* long-form, specify everything */ 24870bd37d32Smrg 24880bd37d32Smrg switch (screen->extend_coords) { 24890bd37d32Smrg case 0: 24900bd37d32Smrg case SET_EXT_MODE_MOUSE: 24910bd37d32Smrg line[count++] = 'T'; 24920bd37d32Smrg break; 24930bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 24940bd37d32Smrg line[count++] = '<'; 24950bd37d32Smrg break; 24960bd37d32Smrg } 24970bd37d32Smrg 2498492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.col); 24990bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2500492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.row); 25010bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2502492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 25030bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2504492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 25050bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2506492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.col); 25070bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 2508492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.row); 25090bd37d32Smrg 25100bd37d32Smrg switch (screen->extend_coords) { 25110bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 25120bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 25130bd37d32Smrg line[count++] = 'T'; 25140bd37d32Smrg break; 25150bd37d32Smrg } 2516d522f475Smrg } 2517d522f475Smrg v_write(screen->respond, line, count); 2518d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 2519d522f475Smrg } 2520d522f475Smrg } 2521d522f475Smrg SelectSet(xw, event, params, num_params); 2522d522f475Smrg screen->eventMode = NORMAL; 2523d522f475Smrg} 2524d522f475Smrg 2525d522f475Smrgvoid 2526d522f475SmrgHandleSelectSet(Widget w, 2527894e0ac8Smrg XEvent *event, 2528e0a2b6dfSmrg String *params, 2529d522f475Smrg Cardinal *num_params) 2530d522f475Smrg{ 2531956cc18dSsnj XtermWidget xw; 2532956cc18dSsnj 2533956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 25340bd37d32Smrg TRACE(("HandleSelectSet\n")); 2535956cc18dSsnj SelectSet(xw, event, params, *num_params); 2536d522f475Smrg } 2537d522f475Smrg} 2538d522f475Smrg 2539d522f475Smrg/* ARGSUSED */ 2540d522f475Smrgstatic void 2541d522f475SmrgSelectSet(XtermWidget xw, 2542894e0ac8Smrg XEvent *event GCC_UNUSED, 2543e0a2b6dfSmrg String *params, 2544d522f475Smrg Cardinal num_params) 2545d522f475Smrg{ 2546956cc18dSsnj TScreen *screen = TScreenOf(xw); 2547d522f475Smrg 2548d522f475Smrg TRACE(("SelectSet\n")); 2549d522f475Smrg /* Only do select stuff if non-null select */ 2550d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 25510bd37d32Smrg SaltTextAway(xw, &(screen->startSel), &(screen->endSel)); 25520bd37d32Smrg _OwnSelection(xw, params, num_params); 2553d522f475Smrg } else { 25540bd37d32Smrg ScrnDisownSelection(xw); 2555d522f475Smrg } 2556d522f475Smrg} 2557d522f475Smrg 2558d522f475Smrg#define Abs(x) ((x) < 0 ? -(x) : (x)) 2559d522f475Smrg 2560d522f475Smrg/* ARGSUSED */ 2561d522f475Smrgstatic void 2562d522f475Smrgdo_start_extend(XtermWidget xw, 2563894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2564e0a2b6dfSmrg String *params GCC_UNUSED, 2565d522f475Smrg Cardinal *num_params GCC_UNUSED, 2566d522f475Smrg Bool use_cursor_loc) 2567d522f475Smrg{ 2568956cc18dSsnj TScreen *screen = TScreenOf(xw); 2569d522f475Smrg int coord; 2570d522f475Smrg CELL cell; 2571d522f475Smrg 2572d522f475Smrg if (SendMousePosition(xw, event)) 2573d522f475Smrg return; 2574d522f475Smrg 2575d522f475Smrg screen->firstValidRow = 0; 2576d522f475Smrg screen->lastValidRow = screen->max_row; 2577d522f475Smrg#if OPT_READLINE 2578492d43a5Smrg if ((KeyModifiers(event) & ShiftMask) 2579d522f475Smrg || event->xbutton.button != Button3 2580d522f475Smrg || !(SCREEN_FLAG(screen, dclick3_deletes))) 2581d522f475Smrg#endif 2582956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2583d522f475Smrg event->xbutton.time, 2584d522f475Smrg screen->selectUnit, 2585d522f475Smrg event->xbutton.button); 2586d522f475Smrg screen->replyToEmacs = False; 2587d522f475Smrg 2588d522f475Smrg#if OPT_READLINE 2589d522f475Smrg CheckSecondPress3(screen, event); 2590d522f475Smrg#endif 2591d522f475Smrg 2592d522f475Smrg if (screen->numberOfClicks == 1 2593d522f475Smrg || (SCREEN_FLAG(screen, dclick3_deletes) /* Dclick special */ 2594492d43a5Smrg &&!(KeyModifiers(event) & ShiftMask))) { 2595d522f475Smrg /* Save existing selection so we can reestablish it if the guy 2596d522f475Smrg extends past the other end of the selection */ 2597d522f475Smrg screen->saveStartR = screen->startExt = screen->startRaw; 2598d522f475Smrg screen->saveEndR = screen->endExt = screen->endRaw; 2599d522f475Smrg } else { 2600d522f475Smrg /* He just needed the selection mode changed, use old values. */ 2601d522f475Smrg screen->startExt = screen->startRaw = screen->saveStartR; 2602d522f475Smrg screen->endExt = screen->endRaw = screen->saveEndR; 2603d522f475Smrg } 2604d522f475Smrg if (use_cursor_loc) { 2605d522f475Smrg cell = screen->cursorp; 2606d522f475Smrg } else { 2607d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2608d522f475Smrg } 2609d522f475Smrg coord = Coordinate(screen, &cell); 2610d522f475Smrg 2611d522f475Smrg if (Abs(coord - Coordinate(screen, &(screen->startSel))) 2612d522f475Smrg < Abs(coord - Coordinate(screen, &(screen->endSel))) 2613d522f475Smrg || coord < Coordinate(screen, &(screen->startSel))) { 2614d522f475Smrg /* point is close to left side of selection */ 2615d522f475Smrg screen->eventMode = LEFTEXTENSION; 2616d522f475Smrg screen->startExt = cell; 2617d522f475Smrg } else { 2618d522f475Smrg /* point is close to left side of selection */ 2619d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2620d522f475Smrg screen->endExt = cell; 2621d522f475Smrg } 2622d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), True); 2623d522f475Smrg 2624d522f475Smrg#if OPT_READLINE 2625d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2626d522f475Smrg ExtendingSelection = 1; 2627d522f475Smrg#endif 2628d522f475Smrg} 2629d522f475Smrg 2630d522f475Smrgstatic void 2631e0a2b6dfSmrgExtendExtend(XtermWidget xw, const CELL *cell) 2632d522f475Smrg{ 2633956cc18dSsnj TScreen *screen = TScreenOf(xw); 2634d522f475Smrg int coord = Coordinate(screen, cell); 2635d522f475Smrg 2636d522f475Smrg TRACE(("ExtendExtend row=%d, col=%d\n", cell->row, cell->col)); 2637d522f475Smrg if (screen->eventMode == LEFTEXTENSION 2638d522f475Smrg && ((coord + (screen->selectUnit != Select_CHAR)) 2639d522f475Smrg > Coordinate(screen, &(screen->endSel)))) { 2640d522f475Smrg /* Whoops, he's changed his mind. Do RIGHTEXTENSION */ 2641d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2642d522f475Smrg screen->startExt = screen->saveStartR; 2643d522f475Smrg } else if (screen->eventMode == RIGHTEXTENSION 2644d522f475Smrg && coord < Coordinate(screen, &(screen->startSel))) { 2645d522f475Smrg /* Whoops, he's changed his mind. Do LEFTEXTENSION */ 2646d522f475Smrg screen->eventMode = LEFTEXTENSION; 2647d522f475Smrg screen->endExt = screen->saveEndR; 2648d522f475Smrg } 2649d522f475Smrg if (screen->eventMode == LEFTEXTENSION) { 2650d522f475Smrg screen->startExt = *cell; 2651d522f475Smrg } else { 2652d522f475Smrg screen->endExt = *cell; 2653d522f475Smrg } 2654d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 2655d522f475Smrg 2656d522f475Smrg#if OPT_READLINE 2657d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2658d522f475Smrg ExtendingSelection = 1; 2659d522f475Smrg#endif 2660d522f475Smrg} 2661d522f475Smrg 2662d522f475Smrgvoid 2663d522f475SmrgHandleStartExtend(Widget w, 2664894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2665e0a2b6dfSmrg String *params, /* unused */ 2666d522f475Smrg Cardinal *num_params) /* unused */ 2667d522f475Smrg{ 2668956cc18dSsnj XtermWidget xw; 2669956cc18dSsnj 2670956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 26710bd37d32Smrg TRACE(("HandleStartExtend\n")); 2672956cc18dSsnj do_start_extend(xw, event, params, num_params, False); 2673956cc18dSsnj } 2674d522f475Smrg} 2675d522f475Smrg 2676d522f475Smrgvoid 2677d522f475SmrgHandleKeyboardStartExtend(Widget w, 2678894e0ac8Smrg XEvent *event, /* must be XButtonEvent* */ 2679e0a2b6dfSmrg String *params, /* unused */ 2680d522f475Smrg Cardinal *num_params) /* unused */ 2681d522f475Smrg{ 2682956cc18dSsnj XtermWidget xw; 2683956cc18dSsnj 2684956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 26850bd37d32Smrg TRACE(("HandleKeyboardStartExtend\n")); 2686956cc18dSsnj do_start_extend(xw, event, params, num_params, True); 2687956cc18dSsnj } 2688d522f475Smrg} 2689d522f475Smrg 2690d522f475Smrgvoid 2691e0a2b6dfSmrgScrollSelection(TScreen *screen, int amount, Bool always) 2692d522f475Smrg{ 2693d522f475Smrg int minrow = INX2ROW(screen, -screen->savedlines); 2694d522f475Smrg int maxrow = INX2ROW(screen, screen->max_row); 2695d522f475Smrg int maxcol = screen->max_col; 2696d522f475Smrg 2697d522f475Smrg#define scroll_update_one(cell) \ 2698d522f475Smrg (cell)->row += amount; \ 2699d522f475Smrg if ((cell)->row < minrow) { \ 2700d522f475Smrg (cell)->row = minrow; \ 2701d522f475Smrg (cell)->col = 0; \ 2702d522f475Smrg } \ 2703d522f475Smrg if ((cell)->row > maxrow) { \ 2704d522f475Smrg (cell)->row = maxrow; \ 2705d522f475Smrg (cell)->col = maxcol; \ 2706d522f475Smrg } 2707d522f475Smrg 2708d522f475Smrg scroll_update_one(&(screen->startRaw)); 2709d522f475Smrg scroll_update_one(&(screen->endRaw)); 2710d522f475Smrg scroll_update_one(&(screen->startSel)); 2711d522f475Smrg scroll_update_one(&(screen->endSel)); 2712d522f475Smrg 2713d522f475Smrg scroll_update_one(&(screen->rawPos)); 2714d522f475Smrg 2715d522f475Smrg /* 2716d522f475Smrg * If we are told to scroll the selection but it lies outside the scrolling 2717d522f475Smrg * margins, then that could cause the selection to move (bad). It is not 2718d522f475Smrg * simple to fix, because this function is called both for the scrollbar 2719d522f475Smrg * actions as well as application scrolling. The 'always' flag is set in 2720d522f475Smrg * the former case. The rest of the logic handles the latter. 2721d522f475Smrg */ 2722d522f475Smrg if (ScrnHaveSelection(screen)) { 2723d522f475Smrg int adjust; 2724d522f475Smrg 2725d522f475Smrg adjust = ROW2INX(screen, screen->startH.row); 2726d522f475Smrg if (always 27270bd37d32Smrg || !ScrnHaveRowMargins(screen) 27280bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 2729d522f475Smrg scroll_update_one(&screen->startH); 2730d522f475Smrg } 2731d522f475Smrg adjust = ROW2INX(screen, screen->endH.row); 2732d522f475Smrg if (always 27330bd37d32Smrg || !ScrnHaveRowMargins(screen) 27340bd37d32Smrg || ScrnIsRowInMargins(screen, adjust)) { 2735d522f475Smrg scroll_update_one(&screen->endH); 2736d522f475Smrg } 2737d522f475Smrg } 2738d522f475Smrg 2739d522f475Smrg screen->startHCoord = Coordinate(screen, &screen->startH); 2740d522f475Smrg screen->endHCoord = Coordinate(screen, &screen->endH); 2741d522f475Smrg} 2742d522f475Smrg 2743d522f475Smrg/*ARGSUSED*/ 2744d522f475Smrgvoid 2745e0a2b6dfSmrgResizeSelection(TScreen *screen GCC_UNUSED, int rows, int cols) 2746d522f475Smrg{ 2747d522f475Smrg rows--; /* decr to get 0-max */ 2748d522f475Smrg cols--; 2749d522f475Smrg 2750d522f475Smrg if (screen->startRaw.row > rows) 2751d522f475Smrg screen->startRaw.row = rows; 2752d522f475Smrg if (screen->startSel.row > rows) 2753d522f475Smrg screen->startSel.row = rows; 2754d522f475Smrg if (screen->endRaw.row > rows) 2755d522f475Smrg screen->endRaw.row = rows; 2756d522f475Smrg if (screen->endSel.row > rows) 2757d522f475Smrg screen->endSel.row = rows; 2758d522f475Smrg if (screen->rawPos.row > rows) 2759d522f475Smrg screen->rawPos.row = rows; 2760d522f475Smrg 2761d522f475Smrg if (screen->startRaw.col > cols) 2762d522f475Smrg screen->startRaw.col = cols; 2763d522f475Smrg if (screen->startSel.col > cols) 2764d522f475Smrg screen->startSel.col = cols; 2765d522f475Smrg if (screen->endRaw.col > cols) 2766d522f475Smrg screen->endRaw.col = cols; 2767d522f475Smrg if (screen->endSel.col > cols) 2768d522f475Smrg screen->endSel.col = cols; 2769d522f475Smrg if (screen->rawPos.col > cols) 2770d522f475Smrg screen->rawPos.col = cols; 2771d522f475Smrg} 2772d522f475Smrg 2773d522f475Smrg#if OPT_WIDE_CHARS 2774d522f475SmrgBool 2775d522f475Smrgiswide(int i) 2776d522f475Smrg{ 277720d2c4d2Smrg return (i == HIDDEN_CHAR) || (WideCells(i) == 2); 2778d522f475Smrg} 2779d522f475Smrg 2780d522f475Smrg#define isWideCell(row, col) iswide((int)XTERM_CELL(row, col)) 2781d522f475Smrg#endif 2782d522f475Smrg 2783d522f475Smrgstatic void 2784e0a2b6dfSmrgPointToCELL(TScreen *screen, 2785d522f475Smrg int y, 2786d522f475Smrg int x, 2787e0a2b6dfSmrg CELL *cell) 2788d522f475Smrg/* Convert pixel coordinates to character coordinates. 2789d522f475Smrg Rows are clipped between firstValidRow and lastValidRow. 2790d522f475Smrg Columns are clipped between to be 0 or greater, but are not clipped to some 2791d522f475Smrg maximum value. */ 2792d522f475Smrg{ 2793d522f475Smrg cell->row = (y - screen->border) / FontHeight(screen); 2794d522f475Smrg if (cell->row < screen->firstValidRow) 2795d522f475Smrg cell->row = screen->firstValidRow; 2796d522f475Smrg else if (cell->row > screen->lastValidRow) 2797d522f475Smrg cell->row = screen->lastValidRow; 2798d522f475Smrg cell->col = (x - OriginX(screen)) / FontWidth(screen); 2799d522f475Smrg if (cell->col < 0) 2800d522f475Smrg cell->col = 0; 2801d522f475Smrg else if (cell->col > MaxCols(screen)) { 2802d522f475Smrg cell->col = MaxCols(screen); 2803d522f475Smrg } 2804d522f475Smrg#if OPT_WIDE_CHARS 2805d522f475Smrg /* 2806d522f475Smrg * If we got a click on the right half of a doublewidth character, 2807d522f475Smrg * pretend it happened on the left half. 2808d522f475Smrg */ 2809d522f475Smrg if (cell->col > 0 2810d522f475Smrg && isWideCell(cell->row, cell->col - 1) 2811d522f475Smrg && (XTERM_CELL(cell->row, cell->col) == HIDDEN_CHAR)) { 2812d522f475Smrg cell->col -= 1; 2813d522f475Smrg } 2814d522f475Smrg#endif 2815d522f475Smrg} 2816d522f475Smrg 2817d522f475Smrg/* 2818d522f475Smrg * Find the last column at which text was drawn on the given row. 2819d522f475Smrg */ 2820d522f475Smrgstatic int 2821e0a2b6dfSmrgLastTextCol(TScreen *screen, LineData *ld, int row) 2822d522f475Smrg{ 282320d2c4d2Smrg int i = -1; 2824894e0ac8Smrg IAttr *ch; 2825d522f475Smrg 282620d2c4d2Smrg if (ld != 0) { 282720d2c4d2Smrg if (okScrnRow(screen, row)) { 282820d2c4d2Smrg for (i = screen->max_col, 282920d2c4d2Smrg ch = ld->attribs + i; 283020d2c4d2Smrg i >= 0 && !(*ch & CHARDRAWN); 283120d2c4d2Smrg ch--, i--) { 283220d2c4d2Smrg ; 283320d2c4d2Smrg } 2834d522f475Smrg#if OPT_DEC_CHRSET 283520d2c4d2Smrg if (CSET_DOUBLE(GetLineDblCS(ld))) { 283620d2c4d2Smrg i *= 2; 283720d2c4d2Smrg } 2838d522f475Smrg#endif 283920d2c4d2Smrg } 2840d522f475Smrg } 2841d522f475Smrg return (i); 2842d522f475Smrg} 2843d522f475Smrg 2844d522f475Smrg#if !OPT_WIDE_CHARS 2845d522f475Smrg/* 2846d522f475Smrg** double click table for cut and paste in 8 bits 2847d522f475Smrg** 2848d522f475Smrg** This table is divided in four parts : 2849d522f475Smrg** 2850d522f475Smrg** - control characters [0,0x1f] U [0x80,0x9f] 2851d522f475Smrg** - separators [0x20,0x3f] U [0xa0,0xb9] 2852d522f475Smrg** - binding characters [0x40,0x7f] U [0xc0,0xff] 2853d522f475Smrg** - exceptions 2854d522f475Smrg*/ 2855d522f475Smrg/* *INDENT-OFF* */ 2856d522f475Smrgstatic int charClass[256] = 2857d522f475Smrg{ 2858d522f475Smrg/* NUL SOH STX ETX EOT ENQ ACK BEL */ 2859d522f475Smrg 32, 1, 1, 1, 1, 1, 1, 1, 28600bd37d32Smrg/* BS HT NL VT FF CR SO SI */ 2861d522f475Smrg 1, 32, 1, 1, 1, 1, 1, 1, 2862d522f475Smrg/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 2863d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2864d522f475Smrg/* CAN EM SUB ESC FS GS RS US */ 2865d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2866d522f475Smrg/* SP ! " # $ % & ' */ 2867d522f475Smrg 32, 33, 34, 35, 36, 37, 38, 39, 2868d522f475Smrg/* ( ) * + , - . / */ 2869d522f475Smrg 40, 41, 42, 43, 44, 45, 46, 47, 2870d522f475Smrg/* 0 1 2 3 4 5 6 7 */ 2871d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2872d522f475Smrg/* 8 9 : ; < = > ? */ 2873d522f475Smrg 48, 48, 58, 59, 60, 61, 62, 63, 2874d522f475Smrg/* @ A B C D E F G */ 2875d522f475Smrg 64, 48, 48, 48, 48, 48, 48, 48, 2876d522f475Smrg/* H I J K L M N O */ 2877d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2878d522f475Smrg/* P Q R S T U V W */ 2879d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2880d522f475Smrg/* X Y Z [ \ ] ^ _ */ 2881d522f475Smrg 48, 48, 48, 91, 92, 93, 94, 48, 2882d522f475Smrg/* ` a b c d e f g */ 2883d522f475Smrg 96, 48, 48, 48, 48, 48, 48, 48, 2884d522f475Smrg/* h i j k l m n o */ 2885d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2886d522f475Smrg/* p q r s t u v w */ 2887d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2888d522f475Smrg/* x y z { | } ~ DEL */ 2889d522f475Smrg 48, 48, 48, 123, 124, 125, 126, 1, 2890d522f475Smrg/* x80 x81 x82 x83 IND NEL SSA ESA */ 2891d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2892d522f475Smrg/* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 2893d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2894d522f475Smrg/* DCS PU1 PU2 STS CCH MW SPA EPA */ 2895d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2896d522f475Smrg/* x98 x99 x9A CSI ST OSC PM APC */ 2897d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2898d522f475Smrg/* - i c/ L ox Y- | So */ 2899d522f475Smrg 160, 161, 162, 163, 164, 165, 166, 167, 2900d522f475Smrg/* .. c0 ip << _ R0 - */ 2901d522f475Smrg 168, 169, 170, 171, 172, 173, 174, 175, 2902d522f475Smrg/* o +- 2 3 ' u q| . */ 2903d522f475Smrg 176, 177, 178, 179, 180, 181, 182, 183, 2904d522f475Smrg/* , 1 2 >> 1/4 1/2 3/4 ? */ 2905d522f475Smrg 184, 185, 186, 187, 188, 189, 190, 191, 2906d522f475Smrg/* A` A' A^ A~ A: Ao AE C, */ 2907d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2908d522f475Smrg/* E` E' E^ E: I` I' I^ I: */ 2909d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2910d522f475Smrg/* D- N~ O` O' O^ O~ O: X */ 2911d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 215, 2912d522f475Smrg/* O/ U` U' U^ U: Y' P B */ 2913d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2914d522f475Smrg/* a` a' a^ a~ a: ao ae c, */ 2915d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2916d522f475Smrg/* e` e' e^ e: i` i' i^ i: */ 2917d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2918d522f475Smrg/* d n~ o` o' o^ o~ o: -: */ 2919d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 247, 2920d522f475Smrg/* o/ u` u' u^ u: y' P y: */ 2921d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48}; 2922d522f475Smrg/* *INDENT-ON* */ 2923d522f475Smrg 2924d522f475Smrgint 2925d522f475SmrgSetCharacterClassRange(int low, /* in range of [0..255] */ 2926d522f475Smrg int high, 2927d522f475Smrg int value) /* arbitrary */ 2928d522f475Smrg{ 2929d522f475Smrg 2930d522f475Smrg if (low < 0 || high > 255 || high < low) 2931d522f475Smrg return (-1); 2932d522f475Smrg 2933d522f475Smrg for (; low <= high; low++) 2934d522f475Smrg charClass[low] = value; 2935d522f475Smrg 2936d522f475Smrg return (0); 2937d522f475Smrg} 2938d522f475Smrg#endif 2939d522f475Smrg 2940d522f475Smrgstatic int 2941e0a2b6dfSmrgclass_of(LineData *ld, CELL *cell) 2942d522f475Smrg{ 2943d522f475Smrg CELL temp = *cell; 29440bd37d32Smrg int result = 0; 2945d522f475Smrg 2946d522f475Smrg#if OPT_DEC_CHRSET 2947956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 2948d522f475Smrg temp.col /= 2; 2949d522f475Smrg } 2950d522f475Smrg#endif 29510bd37d32Smrg if (temp.col < (int) ld->lineSize) 29520bd37d32Smrg result = CharacterClass((int) (ld->charData[temp.col])); 29530bd37d32Smrg return result; 2954d522f475Smrg} 2955956cc18dSsnj 2956956cc18dSsnj#if OPT_WIDE_CHARS 2957956cc18dSsnj#define CClassSelects(name, cclass) \ 2958956cc18dSsnj (CClassOf(name) == cclass \ 2959956cc18dSsnj || XTERM_CELL(screen->name.row, screen->name.col) == HIDDEN_CHAR) 2960d522f475Smrg#else 2961956cc18dSsnj#define CClassSelects(name, cclass) \ 2962956cc18dSsnj (class_of(ld.name, &((screen->name))) == cclass) 2963d522f475Smrg#endif 2964d522f475Smrg 2965956cc18dSsnj#define CClassOf(name) class_of(ld.name, &((screen->name))) 2966956cc18dSsnj 2967d522f475Smrg/* 2968d522f475Smrg * If the given column is past the end of text on the given row, bump to the 2969d522f475Smrg * beginning of the next line. 2970d522f475Smrg */ 2971d522f475Smrgstatic Boolean 2972e0a2b6dfSmrgokPosition(TScreen *screen, 2973e0a2b6dfSmrg LineData **ld, 2974e0a2b6dfSmrg CELL *cell) 2975d522f475Smrg{ 297620d2c4d2Smrg Boolean result = True; 297720d2c4d2Smrg 297820d2c4d2Smrg if (cell->row > screen->max_row) { 297920d2c4d2Smrg result = False; 298020d2c4d2Smrg } else if (cell->col > (LastTextCol(screen, *ld, cell->row) + 1)) { 298120d2c4d2Smrg if (cell->row < screen->max_row) { 298220d2c4d2Smrg cell->col = 0; 298320d2c4d2Smrg *ld = GET_LINEDATA(screen, ++cell->row); 298420d2c4d2Smrg result = False; 298520d2c4d2Smrg } 2986d522f475Smrg } 298720d2c4d2Smrg return result; 2988d522f475Smrg} 2989d522f475Smrg 2990d522f475Smrgstatic void 2991e0a2b6dfSmrgtrimLastLine(TScreen *screen, 2992e0a2b6dfSmrg LineData **ld, 2993e0a2b6dfSmrg CELL *last) 2994d522f475Smrg{ 299520d2c4d2Smrg if (screen->cutNewline && last->row < screen->max_row) { 2996d522f475Smrg last->col = 0; 2997956cc18dSsnj *ld = GET_LINEDATA(screen, ++last->row); 2998d522f475Smrg } else { 2999956cc18dSsnj last->col = LastTextCol(screen, *ld, last->row) + 1; 3000d522f475Smrg } 3001d522f475Smrg} 3002d522f475Smrg 3003d522f475Smrg#if OPT_SELECT_REGEX 3004d522f475Smrg/* 3005d522f475Smrg * Returns the first row of a wrapped line. 3006d522f475Smrg */ 3007d522f475Smrgstatic int 3008e0a2b6dfSmrgfirstRowOfLine(TScreen *screen, int row, Bool visible) 3009d522f475Smrg{ 3010956cc18dSsnj LineData *ld = 0; 3011d522f475Smrg int limit = visible ? 0 : -screen->savedlines; 3012d522f475Smrg 3013d522f475Smrg while (row > limit && 3014956cc18dSsnj (ld = GET_LINEDATA(screen, row - 1)) != 0 && 3015956cc18dSsnj LineTstWrapped(ld)) { 3016d522f475Smrg --row; 3017956cc18dSsnj } 3018d522f475Smrg return row; 3019d522f475Smrg} 3020d522f475Smrg 3021d522f475Smrg/* 3022d522f475Smrg * Returns the last row of a wrapped line. 3023d522f475Smrg */ 3024d522f475Smrgstatic int 3025e0a2b6dfSmrglastRowOfLine(TScreen *screen, int row) 3026d522f475Smrg{ 3027956cc18dSsnj LineData *ld; 3028956cc18dSsnj 3029d522f475Smrg while (row < screen->max_row && 3030956cc18dSsnj (ld = GET_LINEDATA(screen, row)) != 0 && 3031956cc18dSsnj LineTstWrapped(ld)) { 3032d522f475Smrg ++row; 3033956cc18dSsnj } 3034d522f475Smrg return row; 3035d522f475Smrg} 3036d522f475Smrg 3037d522f475Smrg/* 3038d522f475Smrg * Returns the number of cells on the range of rows. 3039d522f475Smrg */ 3040d522f475Smrgstatic unsigned 3041e0a2b6dfSmrglengthOfLines(TScreen *screen, int firstRow, int lastRow) 3042d522f475Smrg{ 3043d522f475Smrg unsigned length = 0; 3044d522f475Smrg int n; 3045d522f475Smrg 3046d522f475Smrg for (n = firstRow; n <= lastRow; ++n) { 3047956cc18dSsnj LineData *ld = GET_LINEDATA(screen, n); 3048956cc18dSsnj int value = LastTextCol(screen, ld, n); 3049d522f475Smrg if (value >= 0) 30502eaa94a1Schristos length += (unsigned) (value + 1); 3051d522f475Smrg } 3052d522f475Smrg return length; 3053d522f475Smrg} 3054d522f475Smrg 3055d522f475Smrg/* 3056d522f475Smrg * Make a copy of the wrapped-line which corresponds to the given row as a 3057d522f475Smrg * string of bytes. Construct an index for the columns from the beginning of 3058d522f475Smrg * the line. 3059d522f475Smrg */ 3060d522f475Smrgstatic char * 3061e0a2b6dfSmrgmake_indexed_text(TScreen *screen, int row, unsigned length, int *indexed) 3062d522f475Smrg{ 3063d522f475Smrg Char *result = 0; 306420d2c4d2Smrg size_t need = (length + 1); 3065d522f475Smrg 3066d522f475Smrg /* 3067d522f475Smrg * Get a quick upper bound to the number of bytes needed, if the whole 3068d522f475Smrg * string were UTF-8. 3069d522f475Smrg */ 3070d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3071956cc18dSsnj need *= ((screen->lineExtra + 1) * 6); 3072d522f475Smrg }); 3073d522f475Smrg 3074d522f475Smrg if ((result = TypeCallocN(Char, need + 1)) != 0) { 3075956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 3076d522f475Smrg unsigned used = 0; 3077d522f475Smrg Char *last = result; 3078d522f475Smrg 3079d522f475Smrg do { 3080d522f475Smrg int col = 0; 3081956cc18dSsnj int limit = LastTextCol(screen, ld, row); 3082d522f475Smrg 3083d522f475Smrg while (col <= limit) { 3084d522f475Smrg Char *next = last; 3085956cc18dSsnj unsigned data = ld->charData[col]; 3086d522f475Smrg 30870bd37d32Smrg assert(col < (int) ld->lineSize); 3088d522f475Smrg /* some internal points may not be drawn */ 3089d522f475Smrg if (data == 0) 3090d522f475Smrg data = ' '; 3091d522f475Smrg 3092d522f475Smrg if_WIDE_OR_NARROW(screen, { 3093d522f475Smrg next = convertToUTF8(last, data); 3094d522f475Smrg } 3095d522f475Smrg , { 3096d522f475Smrg *next++ = CharOf(data); 3097d522f475Smrg }); 3098d522f475Smrg 3099d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3100956cc18dSsnj size_t off; 3101956cc18dSsnj for_each_combData(off, ld) { 3102956cc18dSsnj data = ld->combData[off][col]; 3103956cc18dSsnj if (data == 0) 3104d522f475Smrg break; 3105d522f475Smrg next = convertToUTF8(next, data); 3106d522f475Smrg } 3107d522f475Smrg }); 3108d522f475Smrg 310920d2c4d2Smrg indexed[used] = (int) (last - result); 3110d522f475Smrg *next = 0; 3111d522f475Smrg /* TRACE(("index[%d.%d] %d:%s\n", row, used, indexed[used], last)); */ 3112d522f475Smrg last = next; 3113d522f475Smrg ++used; 3114d522f475Smrg ++col; 311520d2c4d2Smrg indexed[used] = (int) (next - result); 3116d522f475Smrg } 3117d522f475Smrg } while (used < length && 3118956cc18dSsnj LineTstWrapped(ld) && 3119956cc18dSsnj (ld = GET_LINEDATA(screen, ++row)) != 0 && 3120956cc18dSsnj row < screen->max_row); 3121d522f475Smrg } 3122d522f475Smrg /* TRACE(("result:%s\n", result)); */ 3123d522f475Smrg return (char *) result; 3124d522f475Smrg} 3125d522f475Smrg 3126d522f475Smrg/* 3127d522f475Smrg * Find the column given an offset into the character string by using the 3128d522f475Smrg * index constructed in make_indexed_text(). 3129d522f475Smrg */ 3130d522f475Smrgstatic int 3131d522f475SmrgindexToCol(int *indexed, int len, int off) 3132d522f475Smrg{ 3133d522f475Smrg int col = 0; 3134d522f475Smrg while (indexed[col] < len) { 3135d522f475Smrg if (indexed[col] >= off) 3136d522f475Smrg break; 3137d522f475Smrg ++col; 3138d522f475Smrg } 3139d522f475Smrg return col; 3140d522f475Smrg} 3141d522f475Smrg 3142d522f475Smrg/* 3143d522f475Smrg * Given a row number, and a column offset from that (which may be wrapped), 3144d522f475Smrg * set the cell to the actual row/column values. 3145d522f475Smrg */ 3146d522f475Smrgstatic void 3147e0a2b6dfSmrgcolumnToCell(TScreen *screen, int row, int col, CELL *cell) 3148d522f475Smrg{ 3149d522f475Smrg while (row < screen->max_row) { 3150956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 3151956cc18dSsnj int last = LastTextCol(screen, ld, row); 3152d522f475Smrg 3153d522f475Smrg /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */ 3154d522f475Smrg if (col <= last) { 3155d522f475Smrg break; 3156d522f475Smrg } 3157d522f475Smrg /* 3158d522f475Smrg * Stop if the current row does not wrap (does not continue the current 3159d522f475Smrg * line). 3160d522f475Smrg */ 3161956cc18dSsnj if (!LineTstWrapped(ld)) { 3162d522f475Smrg col = last + 1; 3163d522f475Smrg break; 3164d522f475Smrg } 3165d522f475Smrg col -= (last + 1); 3166d522f475Smrg ++row; 3167d522f475Smrg } 3168d522f475Smrg if (col < 0) 3169d522f475Smrg col = 0; 3170d522f475Smrg cell->row = row; 3171d522f475Smrg cell->col = col; 3172d522f475Smrg} 3173d522f475Smrg 3174d522f475Smrg/* 3175d522f475Smrg * Given a cell, find the corresponding column offset. 3176d522f475Smrg */ 3177d522f475Smrgstatic int 3178e0a2b6dfSmrgcellToColumn(TScreen *screen, CELL *cell) 3179d522f475Smrg{ 3180956cc18dSsnj LineData *ld = 0; 3181d522f475Smrg int col = cell->col; 3182d522f475Smrg int row = firstRowOfLine(screen, cell->row, False); 3183d522f475Smrg while (row < cell->row) { 3184956cc18dSsnj ld = GET_LINEDATA(screen, row); 3185956cc18dSsnj col += LastTextCol(screen, ld, row++); 3186d522f475Smrg } 3187956cc18dSsnj#if OPT_DEC_CHRSET 3188956cc18dSsnj if (ld == 0) 3189956cc18dSsnj ld = GET_LINEDATA(screen, row); 3190956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3191956cc18dSsnj col /= 2; 3192956cc18dSsnj#endif 3193d522f475Smrg return col; 3194d522f475Smrg} 3195d522f475Smrg 3196d522f475Smrgstatic void 3197e0a2b6dfSmrgdo_select_regex(TScreen *screen, CELL *startc, CELL *endc) 3198d522f475Smrg{ 3199956cc18dSsnj LineData *ld = GET_LINEDATA(screen, startc->row); 3200d522f475Smrg int inx = ((screen->numberOfClicks - 1) % screen->maxClicks); 3201d522f475Smrg char *expr = screen->selectExpr[inx]; 3202d522f475Smrg regex_t preg; 3203d522f475Smrg regmatch_t match; 3204d522f475Smrg char *search; 3205d522f475Smrg int *indexed; 3206d522f475Smrg 3207d522f475Smrg TRACE(("Select_REGEX:%s\n", NonNull(expr))); 3208956cc18dSsnj if (okPosition(screen, &ld, startc) && expr != 0) { 3209d522f475Smrg if (regcomp(&preg, expr, REG_EXTENDED) == 0) { 3210d522f475Smrg int firstRow = firstRowOfLine(screen, startc->row, True); 3211d522f475Smrg int lastRow = lastRowOfLine(screen, firstRow); 3212d522f475Smrg unsigned size = lengthOfLines(screen, firstRow, lastRow); 3213d522f475Smrg int actual = cellToColumn(screen, startc); 3214d522f475Smrg 3215d522f475Smrg TRACE(("regcomp ok rows %d..%d bytes %d\n", 3216d522f475Smrg firstRow, lastRow, size)); 3217d522f475Smrg 3218d522f475Smrg if ((indexed = TypeCallocN(int, size + 1)) != 0) { 3219d522f475Smrg if ((search = make_indexed_text(screen, 3220d522f475Smrg firstRow, 3221d522f475Smrg size, 3222d522f475Smrg indexed)) != 0) { 32232eaa94a1Schristos int len = (int) strlen(search); 3224d522f475Smrg int col; 3225d522f475Smrg int best_col = -1; 3226d522f475Smrg int best_len = -1; 3227d522f475Smrg 3228d522f475Smrg for (col = 0; indexed[col] < len; ++col) { 3229d522f475Smrg if (regexec(&preg, 3230d522f475Smrg search + indexed[col], 323120d2c4d2Smrg (size_t) 1, &match, 0) == 0) { 3232894e0ac8Smrg int start_inx = (int) (match.rm_so + indexed[col]); 3233894e0ac8Smrg int finis_inx = (int) (match.rm_eo + indexed[col]); 3234d522f475Smrg int start_col = indexToCol(indexed, len, start_inx); 3235d522f475Smrg int finis_col = indexToCol(indexed, len, finis_inx); 3236d522f475Smrg 3237d522f475Smrg if (start_col <= actual && 3238d522f475Smrg actual < finis_col) { 3239d522f475Smrg int test = finis_col - start_col; 3240d522f475Smrg if (best_len < test) { 3241d522f475Smrg best_len = test; 3242d522f475Smrg best_col = start_col; 3243d522f475Smrg TRACE(("match column %d len %d\n", 3244d522f475Smrg best_col, 3245d522f475Smrg best_len)); 3246d522f475Smrg } 3247d522f475Smrg } 3248d522f475Smrg } 3249d522f475Smrg } 3250d522f475Smrg if (best_col >= 0) { 3251d522f475Smrg int best_nxt = best_col + best_len; 3252d522f475Smrg columnToCell(screen, firstRow, best_col, startc); 3253d522f475Smrg columnToCell(screen, firstRow, best_nxt, endc); 3254d522f475Smrg TRACE(("search::%s\n", search)); 3255d522f475Smrg TRACE(("indexed:%d..%d -> %d..%d\n", 3256d522f475Smrg best_col, best_nxt, 3257d522f475Smrg indexed[best_col], 3258d522f475Smrg indexed[best_nxt])); 3259d522f475Smrg TRACE(("matched:%d:%s\n", 3260d522f475Smrg indexed[best_nxt] + 1 - 3261d522f475Smrg indexed[best_col], 3262956cc18dSsnj visibleChars((Char *) (search + indexed[best_col]), 3263d522f475Smrg (unsigned) (indexed[best_nxt] + 3264d522f475Smrg 1 - 3265d522f475Smrg indexed[best_col])))); 3266d522f475Smrg } 3267d522f475Smrg free(search); 3268d522f475Smrg } 3269d522f475Smrg free(indexed); 3270956cc18dSsnj#if OPT_DEC_CHRSET 3271956cc18dSsnj if ((ld = GET_LINEDATA(screen, startc->row)) != 0) { 3272956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3273956cc18dSsnj startc->col *= 2; 3274956cc18dSsnj } 3275956cc18dSsnj if ((ld = GET_LINEDATA(screen, endc->row)) != 0) { 3276956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3277956cc18dSsnj endc->col *= 2; 3278956cc18dSsnj } 3279956cc18dSsnj#endif 3280d522f475Smrg } 3281d522f475Smrg regfree(&preg); 3282d522f475Smrg } 3283d522f475Smrg } 3284d522f475Smrg} 3285d522f475Smrg#endif /* OPT_SELECT_REGEX */ 3286d522f475Smrg 3287956cc18dSsnj#define InitRow(name) \ 3288956cc18dSsnj ld.name = GET_LINEDATA(screen, screen->name.row) 3289956cc18dSsnj 3290956cc18dSsnj#define NextRow(name) \ 3291956cc18dSsnj ld.name = GET_LINEDATA(screen, ++screen->name.row) 3292956cc18dSsnj 3293956cc18dSsnj#define PrevRow(name) \ 3294956cc18dSsnj ld.name = GET_LINEDATA(screen, --screen->name.row) 3295956cc18dSsnj 329620d2c4d2Smrg#define MoreRows(name) \ 329720d2c4d2Smrg (screen->name.row < screen->max_row) 329820d2c4d2Smrg 3299956cc18dSsnj#define isPrevWrapped(name) \ 3300956cc18dSsnj (screen->name.row > 0 \ 3301956cc18dSsnj && (ltmp = GET_LINEDATA(screen, screen->name.row - 1)) != 0 \ 3302956cc18dSsnj && LineTstWrapped(ltmp)) 3303956cc18dSsnj 3304d522f475Smrg/* 3305d522f475Smrg * sets startSel endSel 3306d522f475Smrg * ensuring that they have legal values 3307d522f475Smrg */ 3308d522f475Smrgstatic void 3309d522f475SmrgComputeSelect(XtermWidget xw, 3310e0a2b6dfSmrg CELL *startc, 3311e0a2b6dfSmrg CELL *endc, 3312d522f475Smrg Bool extend) 3313d522f475Smrg{ 3314956cc18dSsnj TScreen *screen = TScreenOf(xw); 3315956cc18dSsnj 3316d522f475Smrg int length; 3317d522f475Smrg int cclass; 3318d522f475Smrg CELL first = *startc; 3319d522f475Smrg CELL last = *endc; 3320956cc18dSsnj Boolean ignored = False; 3321956cc18dSsnj 3322956cc18dSsnj struct { 3323956cc18dSsnj LineData *startSel; 3324956cc18dSsnj LineData *endSel; 3325956cc18dSsnj } ld; 3326956cc18dSsnj LineData *ltmp; 3327d522f475Smrg 3328d522f475Smrg TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n", 3329d522f475Smrg first.row, first.col, 3330d522f475Smrg last.row, last.col, 3331d522f475Smrg extend ? "" : "no")); 3332d522f475Smrg 3333d522f475Smrg#if OPT_WIDE_CHARS 3334d522f475Smrg if (first.col > 1 3335d522f475Smrg && isWideCell(first.row, first.col - 1) 3336d522f475Smrg && XTERM_CELL(first.row, first.col - 0) == HIDDEN_CHAR) { 333720d2c4d2Smrg TRACE(("Adjusting start. Changing downwards from %i.\n", first.col)); 3338d522f475Smrg first.col -= 1; 3339d522f475Smrg if (last.col == (first.col + 1)) 3340d522f475Smrg last.col--; 3341d522f475Smrg } 3342d522f475Smrg 3343d522f475Smrg if (last.col > 1 3344d522f475Smrg && isWideCell(last.row, last.col - 1) 3345d522f475Smrg && XTERM_CELL(last.row, last.col) == HIDDEN_CHAR) { 3346d522f475Smrg last.col += 1; 3347d522f475Smrg } 3348d522f475Smrg#endif 3349d522f475Smrg 3350d522f475Smrg if (Coordinate(screen, &first) <= Coordinate(screen, &last)) { 3351d522f475Smrg screen->startSel = screen->startRaw = first; 3352d522f475Smrg screen->endSel = screen->endRaw = last; 3353d522f475Smrg } else { /* Swap them */ 3354d522f475Smrg screen->startSel = screen->startRaw = last; 3355d522f475Smrg screen->endSel = screen->endRaw = first; 3356d522f475Smrg } 3357d522f475Smrg 3358956cc18dSsnj InitRow(startSel); 3359956cc18dSsnj InitRow(endSel); 3360956cc18dSsnj 3361d522f475Smrg switch (screen->selectUnit) { 3362d522f475Smrg case Select_CHAR: 3363956cc18dSsnj (void) okPosition(screen, &(ld.startSel), &(screen->startSel)); 3364956cc18dSsnj (void) okPosition(screen, &(ld.endSel), &(screen->endSel)); 3365d522f475Smrg break; 3366d522f475Smrg 3367d522f475Smrg case Select_WORD: 3368d522f475Smrg TRACE(("Select_WORD\n")); 3369956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 3370956cc18dSsnj cclass = CClassOf(startSel); 3371d522f475Smrg do { 3372d522f475Smrg --screen->startSel.col; 3373956cc18dSsnj if (screen->startSel.col < 0 3374956cc18dSsnj && isPrevWrapped(startSel)) { 3375956cc18dSsnj PrevRow(startSel); 3376956cc18dSsnj screen->startSel.col = LastTextCol(screen, ld.startSel, screen->startSel.row); 3377d522f475Smrg } 3378d522f475Smrg } while (screen->startSel.col >= 0 3379956cc18dSsnj && CClassSelects(startSel, cclass)); 3380d522f475Smrg ++screen->startSel.col; 3381d522f475Smrg } 3382d522f475Smrg#if OPT_WIDE_CHARS 3383d522f475Smrg if (screen->startSel.col 3384d522f475Smrg && XTERM_CELL(screen->startSel.row, 3385d522f475Smrg screen->startSel.col) == HIDDEN_CHAR) 3386d522f475Smrg screen->startSel.col++; 3387d522f475Smrg#endif 3388d522f475Smrg 3389956cc18dSsnj if (okPosition(screen, &(ld.endSel), &(screen->endSel))) { 3390956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 3391956cc18dSsnj cclass = CClassOf(endSel); 3392d522f475Smrg do { 3393d522f475Smrg ++screen->endSel.col; 3394d522f475Smrg if (screen->endSel.col > length 3395956cc18dSsnj && LineTstWrapped(ld.endSel)) { 339620d2c4d2Smrg if (!MoreRows(endSel)) 339720d2c4d2Smrg break; 3398d522f475Smrg screen->endSel.col = 0; 3399956cc18dSsnj NextRow(endSel); 3400956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 3401d522f475Smrg } 3402d522f475Smrg } while (screen->endSel.col <= length 3403956cc18dSsnj && CClassSelects(endSel, cclass)); 3404d522f475Smrg /* Word-select selects if pointing to any char in "word", 3405d522f475Smrg * especially note that it includes the last character in a word. 3406d522f475Smrg * So we do no --endSel.col and do special eol handling. 3407d522f475Smrg */ 340820d2c4d2Smrg if (screen->endSel.col > length + 1 340920d2c4d2Smrg && MoreRows(endSel)) { 3410d522f475Smrg screen->endSel.col = 0; 3411956cc18dSsnj NextRow(endSel); 3412d522f475Smrg } 3413d522f475Smrg } 3414d522f475Smrg#if OPT_WIDE_CHARS 3415d522f475Smrg if (screen->endSel.col 3416d522f475Smrg && XTERM_CELL(screen->endSel.row, 3417d522f475Smrg screen->endSel.col) == HIDDEN_CHAR) 3418d522f475Smrg screen->endSel.col++; 3419d522f475Smrg#endif 3420d522f475Smrg 3421d522f475Smrg screen->saveStartW = screen->startSel; 3422d522f475Smrg break; 3423d522f475Smrg 3424d522f475Smrg case Select_LINE: 3425d522f475Smrg TRACE(("Select_LINE\n")); 342620d2c4d2Smrg while (LineTstWrapped(ld.endSel) 342720d2c4d2Smrg && MoreRows(endSel)) { 3428956cc18dSsnj NextRow(endSel); 3429d522f475Smrg } 3430d522f475Smrg if (screen->cutToBeginningOfLine 3431d522f475Smrg || screen->startSel.row < screen->saveStartW.row) { 3432d522f475Smrg screen->startSel.col = 0; 3433956cc18dSsnj while (isPrevWrapped(startSel)) { 3434956cc18dSsnj PrevRow(startSel); 3435d522f475Smrg } 3436d522f475Smrg } else if (!extend) { 3437d522f475Smrg if ((first.row < screen->saveStartW.row) 3438d522f475Smrg || (isSameRow(&first, &(screen->saveStartW)) 3439d522f475Smrg && first.col < screen->saveStartW.col)) { 3440d522f475Smrg screen->startSel.col = 0; 3441956cc18dSsnj while (isPrevWrapped(startSel)) { 3442956cc18dSsnj PrevRow(startSel); 3443d522f475Smrg } 3444d522f475Smrg } else { 3445d522f475Smrg screen->startSel = screen->saveStartW; 3446d522f475Smrg } 3447d522f475Smrg } 3448956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 3449d522f475Smrg break; 3450d522f475Smrg 3451d522f475Smrg case Select_GROUP: /* paragraph */ 3452d522f475Smrg TRACE(("Select_GROUP\n")); 3453956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 3454d522f475Smrg /* scan backward for beginning of group */ 3455d522f475Smrg while (screen->startSel.row > 0 && 3456956cc18dSsnj (LastTextCol(screen, ld.startSel, screen->startSel.row - 3457956cc18dSsnj 1) > 0 || 3458956cc18dSsnj isPrevWrapped(startSel))) { 3459956cc18dSsnj PrevRow(startSel); 3460d522f475Smrg } 3461d522f475Smrg screen->startSel.col = 0; 3462d522f475Smrg /* scan forward for end of group */ 346320d2c4d2Smrg while (MoreRows(endSel) && 3464956cc18dSsnj (LastTextCol(screen, ld.endSel, screen->endSel.row + 1) > 3465956cc18dSsnj 0 || 3466956cc18dSsnj LineTstWrapped(ld.endSel))) { 3467956cc18dSsnj NextRow(endSel); 3468d522f475Smrg } 3469956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 3470d522f475Smrg } 3471d522f475Smrg break; 3472d522f475Smrg 3473d522f475Smrg case Select_PAGE: /* everything one can see */ 3474d522f475Smrg TRACE(("Select_PAGE\n")); 3475d522f475Smrg screen->startSel.row = 0; 3476d522f475Smrg screen->startSel.col = 0; 347720d2c4d2Smrg screen->endSel.row = MaxRows(screen); 3478d522f475Smrg screen->endSel.col = 0; 3479d522f475Smrg break; 3480d522f475Smrg 3481d522f475Smrg case Select_ALL: /* counts scrollback if in normal screen */ 3482d522f475Smrg TRACE(("Select_ALL\n")); 3483d522f475Smrg screen->startSel.row = -screen->savedlines; 3484d522f475Smrg screen->startSel.col = 0; 348520d2c4d2Smrg screen->endSel.row = MaxRows(screen); 3486d522f475Smrg screen->endSel.col = 0; 3487d522f475Smrg break; 3488d522f475Smrg 3489d522f475Smrg#if OPT_SELECT_REGEX 3490d522f475Smrg case Select_REGEX: 3491d522f475Smrg do_select_regex(screen, &(screen->startSel), &(screen->endSel)); 3492d522f475Smrg break; 3493d522f475Smrg#endif 3494d522f475Smrg 3495d522f475Smrg case NSELECTUNITS: /* always ignore */ 3496956cc18dSsnj ignored = True; 3497956cc18dSsnj break; 3498d522f475Smrg } 3499d522f475Smrg 3500956cc18dSsnj if (!ignored) { 3501956cc18dSsnj /* check boundaries */ 3502956cc18dSsnj ScrollSelection(screen, 0, False); 3503956cc18dSsnj TrackText(xw, &(screen->startSel), &(screen->endSel)); 3504956cc18dSsnj } 3505d522f475Smrg 3506d522f475Smrg return; 3507d522f475Smrg} 3508d522f475Smrg 3509d522f475Smrg/* Guaranteed (first.row, first.col) <= (last.row, last.col) */ 3510d522f475Smrgstatic void 3511d522f475SmrgTrackText(XtermWidget xw, 3512e0a2b6dfSmrg const CELL *firstp, 3513e0a2b6dfSmrg const CELL *lastp) 3514d522f475Smrg{ 3515956cc18dSsnj TScreen *screen = TScreenOf(xw); 3516d522f475Smrg int from, to; 3517d522f475Smrg CELL old_start, old_end; 3518d522f475Smrg CELL first = *firstp; 3519d522f475Smrg CELL last = *lastp; 3520d522f475Smrg 3521d522f475Smrg TRACE(("TrackText(first=%d,%d, last=%d,%d)\n", 3522d522f475Smrg first.row, first.col, last.row, last.col)); 3523d522f475Smrg 3524d522f475Smrg old_start = screen->startH; 3525d522f475Smrg old_end = screen->endH; 35260bd37d32Smrg TRACE(("...previous(first=%d,%d, last=%d,%d)\n", 35270bd37d32Smrg old_start.row, old_start.col, 35280bd37d32Smrg old_end.row, old_end.col)); 3529d522f475Smrg if (isSameCELL(&first, &old_start) && 35300bd37d32Smrg isSameCELL(&last, &old_end)) { 3531d522f475Smrg return; 35320bd37d32Smrg } 35330bd37d32Smrg 3534d522f475Smrg screen->startH = first; 3535d522f475Smrg screen->endH = last; 3536d522f475Smrg from = Coordinate(screen, &screen->startH); 3537d522f475Smrg to = Coordinate(screen, &screen->endH); 3538d522f475Smrg if (to <= screen->startHCoord || from > screen->endHCoord) { 3539d522f475Smrg /* No overlap whatsoever between old and new hilite */ 3540d522f475Smrg ReHiliteText(xw, &old_start, &old_end); 3541d522f475Smrg ReHiliteText(xw, &first, &last); 3542d522f475Smrg } else { 3543d522f475Smrg if (from < screen->startHCoord) { 3544d522f475Smrg /* Extend left end */ 3545d522f475Smrg ReHiliteText(xw, &first, &old_start); 3546d522f475Smrg } else if (from > screen->startHCoord) { 3547d522f475Smrg /* Shorten left end */ 3548d522f475Smrg ReHiliteText(xw, &old_start, &first); 3549d522f475Smrg } 3550d522f475Smrg if (to > screen->endHCoord) { 3551d522f475Smrg /* Extend right end */ 3552d522f475Smrg ReHiliteText(xw, &old_end, &last); 3553d522f475Smrg } else if (to < screen->endHCoord) { 3554d522f475Smrg /* Shorten right end */ 3555d522f475Smrg ReHiliteText(xw, &last, &old_end); 3556d522f475Smrg } 3557d522f475Smrg } 3558d522f475Smrg screen->startHCoord = from; 3559d522f475Smrg screen->endHCoord = to; 3560d522f475Smrg} 3561d522f475Smrg 3562d522f475Smrg/* Guaranteed that (first->row, first->col) <= (last->row, last->col) */ 3563d522f475Smrgstatic void 3564d522f475SmrgReHiliteText(XtermWidget xw, 3565e0a2b6dfSmrg CELL *firstp, 3566e0a2b6dfSmrg CELL *lastp) 3567d522f475Smrg{ 3568956cc18dSsnj TScreen *screen = TScreenOf(xw); 3569d522f475Smrg int i; 3570d522f475Smrg CELL first = *firstp; 3571d522f475Smrg CELL last = *lastp; 3572d522f475Smrg 3573d522f475Smrg TRACE(("ReHiliteText from %d.%d to %d.%d\n", 3574d522f475Smrg first.row, first.col, last.row, last.col)); 3575d522f475Smrg 3576d522f475Smrg if (first.row < 0) 3577d522f475Smrg first.row = first.col = 0; 3578d522f475Smrg else if (first.row > screen->max_row) 3579d522f475Smrg return; /* nothing to do, since last.row >= first.row */ 3580d522f475Smrg 3581d522f475Smrg if (last.row < 0) 3582d522f475Smrg return; /* nothing to do, since first.row <= last.row */ 3583d522f475Smrg else if (last.row > screen->max_row) { 3584d522f475Smrg last.row = screen->max_row; 3585d522f475Smrg last.col = MaxCols(screen); 3586d522f475Smrg } 3587d522f475Smrg if (isSameCELL(&first, &last)) 3588d522f475Smrg return; 3589d522f475Smrg 3590d522f475Smrg if (!isSameRow(&first, &last)) { /* do multiple rows */ 3591d522f475Smrg if ((i = screen->max_col - first.col + 1) > 0) { /* first row */ 3592d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, i, True); 3593d522f475Smrg } 3594d522f475Smrg if ((i = last.row - first.row - 1) > 0) { /* middle rows */ 3595d522f475Smrg ScrnRefresh(xw, first.row + 1, 0, i, MaxCols(screen), True); 3596d522f475Smrg } 3597d522f475Smrg if (last.col > 0 && last.row <= screen->max_row) { /* last row */ 3598d522f475Smrg ScrnRefresh(xw, last.row, 0, 1, last.col, True); 3599d522f475Smrg } 3600d522f475Smrg } else { /* do single row */ 3601d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, last.col - first.col, True); 3602d522f475Smrg } 3603d522f475Smrg} 3604d522f475Smrg 3605d522f475Smrg/* 3606d522f475Smrg * Guaranteed that (cellc->row, cellc->col) <= (cell->row, cell->col), and that both points are valid 3607d522f475Smrg * (may have cell->row = screen->max_row+1, cell->col = 0). 3608d522f475Smrg */ 3609d522f475Smrgstatic void 3610d522f475SmrgSaltTextAway(XtermWidget xw, 3611e0a2b6dfSmrg CELL *cellc, 3612e0a2b6dfSmrg CELL *cell) 3613d522f475Smrg{ 3614956cc18dSsnj TScreen *screen = TScreenOf(xw); 3615d522f475Smrg int i, j = 0; 3616d522f475Smrg int eol; 3617956cc18dSsnj int tmp; 3618d522f475Smrg Char *line; 3619d522f475Smrg Char *lp; 3620d522f475Smrg CELL first = *cellc; 3621d522f475Smrg CELL last = *cell; 3622d522f475Smrg 3623d522f475Smrg if (isSameRow(&first, &last) && first.col > last.col) { 3624956cc18dSsnj EXCHANGE(first.col, last.col, tmp); 3625d522f475Smrg } 3626d522f475Smrg 3627d522f475Smrg --last.col; 3628d522f475Smrg /* first we need to know how long the string is before we can save it */ 3629d522f475Smrg 3630d522f475Smrg if (isSameRow(&last, &first)) { 3631d522f475Smrg j = Length(screen, first.row, first.col, last.col); 3632d522f475Smrg } else { /* two cases, cut is on same line, cut spans multiple lines */ 3633d522f475Smrg j += Length(screen, first.row, first.col, screen->max_col) + 1; 3634d522f475Smrg for (i = first.row + 1; i < last.row; i++) 3635d522f475Smrg j += Length(screen, i, 0, screen->max_col) + 1; 3636d522f475Smrg if (last.col >= 0) 3637d522f475Smrg j += Length(screen, last.row, 0, last.col); 3638d522f475Smrg } 3639d522f475Smrg 3640d522f475Smrg /* UTF-8 may require more space */ 3641d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3642d522f475Smrg j *= 4; 3643d522f475Smrg }); 3644d522f475Smrg 3645d522f475Smrg /* now get some memory to save it in */ 3646d522f475Smrg 3647d522f475Smrg if (screen->selection_size <= j) { 364820d2c4d2Smrg if ((line = (Char *) malloc((size_t) j + 1)) == 0) 3649d522f475Smrg SysError(ERROR_BMALLOC2); 3650d522f475Smrg XtFree((char *) screen->selection_data); 3651d522f475Smrg screen->selection_data = line; 3652d522f475Smrg screen->selection_size = j + 1; 3653d522f475Smrg } else { 3654d522f475Smrg line = screen->selection_data; 3655d522f475Smrg } 3656d522f475Smrg 3657d522f475Smrg if ((line == 0) 3658d522f475Smrg || (j < 0)) 3659d522f475Smrg return; 3660d522f475Smrg 3661d522f475Smrg line[j] = '\0'; /* make sure it is null terminated */ 3662d522f475Smrg lp = line; /* lp points to where to save the text */ 3663d522f475Smrg if (isSameRow(&last, &first)) { 3664d522f475Smrg lp = SaveText(screen, last.row, first.col, last.col, lp, &eol); 3665d522f475Smrg } else { 3666d522f475Smrg lp = SaveText(screen, first.row, first.col, screen->max_col, lp, &eol); 3667d522f475Smrg if (eol) 3668d522f475Smrg *lp++ = '\n'; /* put in newline at end of line */ 3669d522f475Smrg for (i = first.row + 1; i < last.row; i++) { 3670d522f475Smrg lp = SaveText(screen, i, 0, screen->max_col, lp, &eol); 3671d522f475Smrg if (eol) 3672d522f475Smrg *lp++ = '\n'; 3673d522f475Smrg } 3674d522f475Smrg if (last.col >= 0) 3675d522f475Smrg lp = SaveText(screen, last.row, 0, last.col, lp, &eol); 3676d522f475Smrg } 3677d522f475Smrg *lp = '\0'; /* make sure we have end marked */ 3678d522f475Smrg 3679956cc18dSsnj TRACE(("Salted TEXT:%d:%s\n", (int) (lp - line), 3680956cc18dSsnj visibleChars(line, (unsigned) (lp - line)))); 3681d522f475Smrg 36822eaa94a1Schristos screen->selection_length = (unsigned long) (lp - line); 3683d522f475Smrg} 3684d522f475Smrg 3685d522f475Smrg#if OPT_PASTE64 3686d522f475Smrgvoid 3687e0a2b6dfSmrgClearSelectionBuffer(TScreen *screen) 3688d522f475Smrg{ 3689d522f475Smrg screen->selection_length = 0; 3690d522f475Smrg screen->base64_count = 0; 3691d522f475Smrg} 3692d522f475Smrg 3693d522f475Smrgstatic void 3694e0a2b6dfSmrgAppendStrToSelectionBuffer(TScreen *screen, Char *text, size_t len) 3695d522f475Smrg{ 3696d522f475Smrg if (len != 0) { 36972eaa94a1Schristos int j = (int) (screen->selection_length + len); /* New length */ 3698d522f475Smrg int k = j + (j >> 2) + 80; /* New size if we grow buffer: grow by ~50% */ 3699d522f475Smrg if (j + 1 >= screen->selection_size) { 3700d522f475Smrg if (!screen->selection_length) { 3701d522f475Smrg /* New buffer */ 3702d522f475Smrg Char *line; 370320d2c4d2Smrg if ((line = (Char *) malloc((size_t) k)) == 0) 3704d522f475Smrg SysError(ERROR_BMALLOC2); 3705d522f475Smrg XtFree((char *) screen->selection_data); 3706d522f475Smrg screen->selection_data = line; 3707d522f475Smrg } else { 3708d522f475Smrg /* Realloc buffer */ 3709d522f475Smrg screen->selection_data = (Char *) 3710d522f475Smrg realloc(screen->selection_data, 371120d2c4d2Smrg (size_t) k); 3712d522f475Smrg if (screen->selection_data == 0) 3713d522f475Smrg SysError(ERROR_BMALLOC2); 3714d522f475Smrg } 3715d522f475Smrg screen->selection_size = k; 3716d522f475Smrg } 371720d2c4d2Smrg if (screen->selection_data != 0) { 371820d2c4d2Smrg memcpy(screen->selection_data + screen->selection_length, text, len); 371920d2c4d2Smrg screen->selection_length += len; 372020d2c4d2Smrg screen->selection_data[screen->selection_length] = 0; 372120d2c4d2Smrg } 3722d522f475Smrg } 3723d522f475Smrg} 3724d522f475Smrg 3725d522f475Smrgvoid 3726e0a2b6dfSmrgAppendToSelectionBuffer(TScreen *screen, unsigned c) 3727d522f475Smrg{ 37282eaa94a1Schristos unsigned six; 3729d522f475Smrg Char ch; 3730d522f475Smrg 3731d522f475Smrg /* Decode base64 character */ 3732d522f475Smrg if (c >= 'A' && c <= 'Z') 3733d522f475Smrg six = c - 'A'; 3734d522f475Smrg else if (c >= 'a' && c <= 'z') 3735d522f475Smrg six = c - 'a' + 26; 3736d522f475Smrg else if (c >= '0' && c <= '9') 3737d522f475Smrg six = c - '0' + 52; 3738d522f475Smrg else if (c == '+') 3739d522f475Smrg six = 62; 3740d522f475Smrg else if (c == '/') 3741d522f475Smrg six = 63; 3742d522f475Smrg else 3743d522f475Smrg return; 3744d522f475Smrg 3745d522f475Smrg /* Accumulate bytes */ 3746d522f475Smrg switch (screen->base64_count) { 3747d522f475Smrg case 0: 3748d522f475Smrg screen->base64_accu = six; 3749d522f475Smrg screen->base64_count = 6; 3750d522f475Smrg break; 3751d522f475Smrg 3752d522f475Smrg case 2: 37532eaa94a1Schristos ch = CharOf((screen->base64_accu << 6) + six); 3754d522f475Smrg screen->base64_count = 0; 375520d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3756d522f475Smrg break; 3757d522f475Smrg 3758d522f475Smrg case 4: 37592eaa94a1Schristos ch = CharOf((screen->base64_accu << 4) + (six >> 2)); 3760d522f475Smrg screen->base64_accu = (six & 0x3); 3761d522f475Smrg screen->base64_count = 2; 376220d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3763d522f475Smrg break; 3764d522f475Smrg 3765d522f475Smrg case 6: 37662eaa94a1Schristos ch = CharOf((screen->base64_accu << 2) + (six >> 4)); 3767d522f475Smrg screen->base64_accu = (six & 0xF); 3768d522f475Smrg screen->base64_count = 4; 376920d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3770d522f475Smrg break; 3771d522f475Smrg } 3772d522f475Smrg} 3773d522f475Smrg 3774d522f475Smrgvoid 3775e0a2b6dfSmrgCompleteSelection(XtermWidget xw, String *args, Cardinal len) 3776d522f475Smrg{ 3777956cc18dSsnj TScreen *screen = TScreenOf(xw); 3778956cc18dSsnj 3779956cc18dSsnj screen->base64_count = 0; 3780956cc18dSsnj screen->base64_accu = 0; 3781d522f475Smrg _OwnSelection(xw, args, len); 3782d522f475Smrg} 3783d522f475Smrg#endif /* OPT_PASTE64 */ 3784d522f475Smrg 3785d522f475Smrgstatic Bool 3786d522f475Smrg_ConvertSelectionHelper(Widget w, 3787894e0ac8Smrg Atom *type, 3788d522f475Smrg XtPointer *value, 3789d522f475Smrg unsigned long *length, 3790d522f475Smrg int *format, 3791d522f475Smrg int (*conversion_function) (Display *, 3792d522f475Smrg char **, int, 3793d522f475Smrg XICCEncodingStyle, 3794d522f475Smrg XTextProperty *), 3795d522f475Smrg XICCEncodingStyle conversion_style) 3796d522f475Smrg{ 3797956cc18dSsnj XtermWidget xw; 3798956cc18dSsnj 3799956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3800956cc18dSsnj TScreen *screen = TScreenOf(xw); 3801d522f475Smrg Display *dpy = XtDisplay(w); 3802d522f475Smrg XTextProperty textprop; 3803d522f475Smrg char *the_data = (char *) screen->selection_data; 3804d522f475Smrg 3805d522f475Smrg if (conversion_function(dpy, &the_data, 1, 3806d522f475Smrg conversion_style, 3807d522f475Smrg &textprop) >= Success) { 3808d522f475Smrg *value = (XtPointer) textprop.value; 3809d522f475Smrg *length = textprop.nitems; 3810d522f475Smrg *type = textprop.encoding; 3811d522f475Smrg *format = textprop.format; 3812d522f475Smrg return True; 3813d522f475Smrg } 3814d522f475Smrg } 3815d522f475Smrg return False; 3816d522f475Smrg} 3817d522f475Smrg 38182eaa94a1Schristosstatic Boolean 38192eaa94a1SchristosSaveConvertedLength(XtPointer *target, unsigned long source) 38202eaa94a1Schristos{ 38212eaa94a1Schristos Boolean result = False; 38222eaa94a1Schristos 38232eaa94a1Schristos *target = XtMalloc(4); 38242eaa94a1Schristos if (*target != 0) { 38252eaa94a1Schristos result = True; 38262eaa94a1Schristos if (sizeof(unsigned long) == 4) { 38272eaa94a1Schristos *(unsigned long *) *target = source; 38282eaa94a1Schristos } else if (sizeof(unsigned) == 4) { 382920d2c4d2Smrg *(unsigned *) *target = (unsigned) source; 38302eaa94a1Schristos } else if (sizeof(unsigned short) == 4) { 38312eaa94a1Schristos *(unsigned short *) *target = (unsigned short) source; 38322eaa94a1Schristos } else { 38332eaa94a1Schristos /* FIXME - does this depend on byte-order? */ 38342eaa94a1Schristos unsigned long temp = source; 383520d2c4d2Smrg memcpy((char *) *target, 383620d2c4d2Smrg ((char *) &temp) + sizeof(temp) - 4, 383720d2c4d2Smrg (size_t) 4); 38382eaa94a1Schristos } 38392eaa94a1Schristos } 38402eaa94a1Schristos return result; 38412eaa94a1Schristos} 38422eaa94a1Schristos 3843d522f475Smrgstatic Boolean 3844d522f475SmrgConvertSelection(Widget w, 3845894e0ac8Smrg Atom *selection, 3846894e0ac8Smrg Atom *target, 3847894e0ac8Smrg Atom *type, 3848d522f475Smrg XtPointer *value, 3849d522f475Smrg unsigned long *length, 3850d522f475Smrg int *format) 3851d522f475Smrg{ 3852d522f475Smrg Display *dpy = XtDisplay(w); 3853d522f475Smrg TScreen *screen; 3854d522f475Smrg Bool result = False; 3855d522f475Smrg 3856956cc18dSsnj XtermWidget xw; 3857956cc18dSsnj 3858956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 3859d522f475Smrg return False; 3860d522f475Smrg 3861956cc18dSsnj screen = TScreenOf(xw); 3862d522f475Smrg 3863d522f475Smrg if (screen->selection_data == NULL) 3864d522f475Smrg return False; /* can this happen? */ 3865d522f475Smrg 3866956cc18dSsnj TRACE(("ConvertSelection %s\n", 3867956cc18dSsnj visibleSelectionTarget(dpy, *target))); 3868956cc18dSsnj 3869d522f475Smrg if (*target == XA_TARGETS(dpy)) { 3870d522f475Smrg Atom *allocP; 3871d522f475Smrg Atom *targetP; 3872d522f475Smrg Atom *std_targets; 3873d522f475Smrg XPointer std_return = 0; 3874d522f475Smrg unsigned long std_length; 3875d522f475Smrg 3876d522f475Smrg if (XmuConvertStandardSelection(w, screen->selection_time, selection, 3877d522f475Smrg target, type, &std_return, 3878d522f475Smrg &std_length, format)) { 3879956cc18dSsnj Atom *my_targets = _SelectionTargets(w); 3880956cc18dSsnj 3881956cc18dSsnj TRACE(("XmuConvertStandardSelection - success\n")); 3882a1f3da82Smrg std_targets = (Atom *) (void *) (std_return); 3883d522f475Smrg *length = std_length + 6; 3884d522f475Smrg 3885a1f3da82Smrg targetP = TypeXtMallocN(Atom, *length); 3886d522f475Smrg allocP = targetP; 3887d522f475Smrg 3888d522f475Smrg *value = (XtPointer) targetP; 3889d522f475Smrg 38900bd37d32Smrg if (my_targets != 0) { 38910bd37d32Smrg while (*my_targets != None) { 38920bd37d32Smrg *targetP++ = *my_targets++; 38930bd37d32Smrg } 3894956cc18dSsnj } 3895d522f475Smrg *targetP++ = XA_LENGTH(dpy); 3896d522f475Smrg *targetP++ = XA_LIST_LENGTH(dpy); 3897d522f475Smrg 38982eaa94a1Schristos *length = std_length + (unsigned long) (targetP - allocP); 3899d522f475Smrg 3900d522f475Smrg memcpy(targetP, std_targets, sizeof(Atom) * std_length); 3901d522f475Smrg XtFree((char *) std_targets); 3902d522f475Smrg *type = XA_ATOM; 3903d522f475Smrg *format = 32; 3904d522f475Smrg result = True; 3905956cc18dSsnj } else { 3906956cc18dSsnj TRACE(("XmuConvertStandardSelection - failed\n")); 3907d522f475Smrg } 3908d522f475Smrg } 3909d522f475Smrg#if OPT_WIDE_CHARS 3910d522f475Smrg else if (screen->wide_chars && *target == XA_STRING) { 3911d522f475Smrg result = 3912d522f475Smrg _ConvertSelectionHelper(w, 3913d522f475Smrg type, value, length, format, 3914d522f475Smrg Xutf8TextListToTextProperty, 3915d522f475Smrg XStringStyle); 3916956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3917d522f475Smrg } else if (screen->wide_chars && *target == XA_UTF8_STRING(dpy)) { 3918d522f475Smrg result = 3919d522f475Smrg _ConvertSelectionHelper(w, 3920d522f475Smrg type, value, length, format, 3921d522f475Smrg Xutf8TextListToTextProperty, 3922d522f475Smrg XUTF8StringStyle); 3923956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3924d522f475Smrg } else if (screen->wide_chars && *target == XA_TEXT(dpy)) { 3925d522f475Smrg result = 3926d522f475Smrg _ConvertSelectionHelper(w, 3927d522f475Smrg type, value, length, format, 3928d522f475Smrg Xutf8TextListToTextProperty, 3929d522f475Smrg XStdICCTextStyle); 3930956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3931d522f475Smrg } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(dpy)) { 3932d522f475Smrg result = 3933d522f475Smrg _ConvertSelectionHelper(w, 3934d522f475Smrg type, value, length, format, 3935d522f475Smrg Xutf8TextListToTextProperty, 3936d522f475Smrg XCompoundTextStyle); 3937956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3938d522f475Smrg } 3939d522f475Smrg#endif 3940d522f475Smrg 3941d522f475Smrg else if (*target == XA_STRING) { /* not wide_chars */ 3942d522f475Smrg /* We can only reach this point if the selection requestor 3943d522f475Smrg requested STRING before any of TEXT, COMPOUND_TEXT or 3944d522f475Smrg UTF8_STRING. We therefore assume that the requestor is not 3945d522f475Smrg properly internationalised, and dump raw eight-bit data 3946d522f475Smrg with no conversion into the selection. Yes, this breaks 3947d522f475Smrg the ICCCM in non-Latin-1 locales. */ 3948d522f475Smrg *type = XA_STRING; 3949d522f475Smrg *value = (XtPointer) screen->selection_data; 3950d522f475Smrg *length = screen->selection_length; 3951d522f475Smrg *format = 8; 3952d522f475Smrg result = True; 3953956cc18dSsnj TRACE(("...raw 8-bit data:%d\n", result)); 3954d522f475Smrg } else if (*target == XA_TEXT(dpy)) { /* not wide_chars */ 3955d522f475Smrg result = 3956d522f475Smrg _ConvertSelectionHelper(w, 3957d522f475Smrg type, value, length, format, 3958d522f475Smrg XmbTextListToTextProperty, 3959d522f475Smrg XStdICCTextStyle); 3960956cc18dSsnj TRACE(("...XmbTextListToTextProperty(StdICC):%d\n", result)); 3961d522f475Smrg } else if (*target == XA_COMPOUND_TEXT(dpy)) { /* not wide_chars */ 3962d522f475Smrg result = 3963d522f475Smrg _ConvertSelectionHelper(w, 3964d522f475Smrg type, value, length, format, 3965d522f475Smrg XmbTextListToTextProperty, 3966d522f475Smrg XCompoundTextStyle); 3967956cc18dSsnj TRACE(("...XmbTextListToTextProperty(Compound):%d\n", result)); 3968d522f475Smrg } 3969d522f475Smrg#ifdef X_HAVE_UTF8_STRING 3970d522f475Smrg else if (*target == XA_UTF8_STRING(dpy)) { /* not wide_chars */ 3971d522f475Smrg result = 3972d522f475Smrg _ConvertSelectionHelper(w, 3973d522f475Smrg type, value, length, format, 3974d522f475Smrg XmbTextListToTextProperty, 3975d522f475Smrg XUTF8StringStyle); 3976956cc18dSsnj TRACE(("...XmbTextListToTextProperty(UTF8):%d\n", result)); 3977d522f475Smrg } 3978d522f475Smrg#endif 3979d522f475Smrg else if (*target == XA_LIST_LENGTH(dpy)) { 398020d2c4d2Smrg result = SaveConvertedLength(value, (unsigned long) 1); 3981d522f475Smrg *type = XA_INTEGER; 3982d522f475Smrg *length = 1; 3983d522f475Smrg *format = 32; 3984956cc18dSsnj TRACE(("...list of values:%d\n", result)); 3985d522f475Smrg } else if (*target == XA_LENGTH(dpy)) { 3986d522f475Smrg /* This value is wrong if we have UTF-8 text */ 39872eaa94a1Schristos result = SaveConvertedLength(value, screen->selection_length); 3988d522f475Smrg *type = XA_INTEGER; 3989d522f475Smrg *length = 1; 3990d522f475Smrg *format = 32; 3991956cc18dSsnj TRACE(("...list of values:%d\n", result)); 3992d522f475Smrg } else if (XmuConvertStandardSelection(w, 3993d522f475Smrg screen->selection_time, selection, 3994d522f475Smrg target, type, (XPointer *) value, 3995d522f475Smrg length, format)) { 3996d522f475Smrg result = True; 3997956cc18dSsnj TRACE(("...XmuConvertStandardSelection:%d\n", result)); 3998d522f475Smrg } 3999d522f475Smrg 4000d522f475Smrg /* else */ 40012eaa94a1Schristos return (Boolean) result; 4002d522f475Smrg} 4003d522f475Smrg 4004d522f475Smrgstatic void 4005894e0ac8SmrgLoseSelection(Widget w, Atom *selection) 4006d522f475Smrg{ 4007d522f475Smrg TScreen *screen; 4008d522f475Smrg Atom *atomP; 4009d522f475Smrg Cardinal i; 4010d522f475Smrg 4011956cc18dSsnj XtermWidget xw; 4012956cc18dSsnj 4013956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 4014d522f475Smrg return; 4015d522f475Smrg 4016956cc18dSsnj screen = TScreenOf(xw); 4017d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 4018d522f475Smrg i < screen->selection_count; i++, atomP++) { 4019d522f475Smrg if (*selection == *atomP) 4020d522f475Smrg *atomP = (Atom) 0; 4021d522f475Smrg if (CutBuffer(*atomP) >= 0) { 4022d522f475Smrg *atomP = (Atom) 0; 4023d522f475Smrg } 4024d522f475Smrg } 4025d522f475Smrg 4026d522f475Smrg for (i = screen->selection_count; i; i--) { 4027d522f475Smrg if (screen->selection_atoms[i - 1] != 0) 4028d522f475Smrg break; 4029d522f475Smrg } 4030d522f475Smrg screen->selection_count = i; 4031d522f475Smrg 4032d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 4033d522f475Smrg i < screen->selection_count; i++, atomP++) { 4034d522f475Smrg if (*atomP == (Atom) 0) { 4035d522f475Smrg *atomP = screen->selection_atoms[--screen->selection_count]; 4036d522f475Smrg } 4037d522f475Smrg } 4038d522f475Smrg 4039d522f475Smrg if (screen->selection_count == 0) 4040956cc18dSsnj TrackText(xw, &zeroCELL, &zeroCELL); 4041d522f475Smrg} 4042d522f475Smrg 4043d522f475Smrg/* ARGSUSED */ 4044d522f475Smrgstatic void 4045d522f475SmrgSelectionDone(Widget w GCC_UNUSED, 4046894e0ac8Smrg Atom *selection GCC_UNUSED, 4047894e0ac8Smrg Atom *target GCC_UNUSED) 4048d522f475Smrg{ 4049d522f475Smrg /* empty proc so Intrinsics know we want to keep storage */ 4050d522f475Smrg} 4051d522f475Smrg 4052d522f475Smrgstatic void 4053d522f475Smrg_OwnSelection(XtermWidget xw, 4054e0a2b6dfSmrg String *selections, 4055d522f475Smrg Cardinal count) 4056d522f475Smrg{ 4057956cc18dSsnj TScreen *screen = TScreenOf(xw); 4058d522f475Smrg Atom *atoms = screen->selection_atoms; 4059d522f475Smrg Cardinal i; 4060d522f475Smrg Bool have_selection = False; 4061d522f475Smrg 406220d2c4d2Smrg if (count == 0) 406320d2c4d2Smrg return; 40642eaa94a1Schristos if (screen->selection_length == 0) 4065d522f475Smrg return; 4066d522f475Smrg 4067956cc18dSsnj TRACE(("_OwnSelection count %d\n", count)); 4068d522f475Smrg selections = MapSelections(xw, selections, count); 4069d522f475Smrg 4070d522f475Smrg if (count > screen->sel_atoms_size) { 4071d522f475Smrg XtFree((char *) atoms); 4072a1f3da82Smrg atoms = TypeXtMallocN(Atom, count); 4073d522f475Smrg screen->selection_atoms = atoms; 4074d522f475Smrg screen->sel_atoms_size = count; 4075d522f475Smrg } 4076d522f475Smrg XmuInternStrings(XtDisplay((Widget) xw), selections, count, atoms); 4077d522f475Smrg for (i = 0; i < count; i++) { 4078d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 4079d522f475Smrg if (cutbuffer >= 0) { 40802eaa94a1Schristos unsigned long limit = 40812eaa94a1Schristos (unsigned long) (4 * XMaxRequestSize(XtDisplay((Widget) xw)) - 32); 40822eaa94a1Schristos if (screen->selection_length > limit) { 408320d2c4d2Smrg TRACE(("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 408420d2c4d2Smrg screen->selection_length, cutbuffer)); 40850bd37d32Smrg xtermWarning("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 40860bd37d32Smrg screen->selection_length, cutbuffer); 4087d522f475Smrg } else { 4088d522f475Smrg /* This used to just use the UTF-8 data, which was totally 4089894e0ac8Smrg * broken as not even the corresponding paste code in xterm 4090d522f475Smrg * understood this! So now it converts to Latin1 first. 4091d522f475Smrg * Robert Brady, 2000-09-05 4092d522f475Smrg */ 4093d522f475Smrg unsigned long length = screen->selection_length; 4094d522f475Smrg Char *data = screen->selection_data; 4095d522f475Smrg if_OPT_WIDE_CHARS((screen), { 4096956cc18dSsnj data = UTF8toLatin1(screen, data, length, &length); 4097d522f475Smrg }); 4098d522f475Smrg TRACE(("XStoreBuffer(%d)\n", cutbuffer)); 4099d522f475Smrg XStoreBuffer(XtDisplay((Widget) xw), 4100d522f475Smrg (char *) data, 4101d522f475Smrg (int) length, 4102d522f475Smrg cutbuffer); 4103d522f475Smrg } 4104d522f475Smrg } else if (!screen->replyToEmacs) { 4105d522f475Smrg have_selection |= 4106d522f475Smrg XtOwnSelection((Widget) xw, atoms[i], 4107d522f475Smrg screen->selection_time, 4108d522f475Smrg ConvertSelection, LoseSelection, SelectionDone); 4109d522f475Smrg } 4110d522f475Smrg } 4111d522f475Smrg if (!screen->replyToEmacs) 4112d522f475Smrg screen->selection_count = count; 4113d522f475Smrg if (!have_selection) 4114d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 4115d522f475Smrg} 4116d522f475Smrg 4117d522f475Smrgstatic void 4118e0a2b6dfSmrgResetSelectionState(TScreen *screen) 4119d522f475Smrg{ 4120d522f475Smrg screen->selection_count = 0; 4121d522f475Smrg screen->startH = zeroCELL; 4122d522f475Smrg screen->endH = zeroCELL; 4123d522f475Smrg} 4124d522f475Smrg 4125d522f475Smrgvoid 4126d522f475SmrgDisownSelection(XtermWidget xw) 4127d522f475Smrg{ 4128956cc18dSsnj TScreen *screen = TScreenOf(xw); 4129d522f475Smrg Atom *atoms = screen->selection_atoms; 4130d522f475Smrg Cardinal count = screen->selection_count; 4131d522f475Smrg Cardinal i; 4132d522f475Smrg 4133d522f475Smrg TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n", 4134d522f475Smrg count, 4135d522f475Smrg screen->startH.row, 4136d522f475Smrg screen->startH.col, 4137d522f475Smrg screen->endH.row, 4138d522f475Smrg screen->endH.col)); 4139d522f475Smrg 4140d522f475Smrg for (i = 0; i < count; i++) { 4141d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 4142d522f475Smrg if (cutbuffer < 0) { 4143d522f475Smrg XtDisownSelection((Widget) xw, atoms[i], 4144d522f475Smrg screen->selection_time); 4145d522f475Smrg } 4146d522f475Smrg } 4147d522f475Smrg /* 4148d522f475Smrg * If none of the callbacks via XtDisownSelection() reset highlighting 4149d522f475Smrg * do it now. 4150d522f475Smrg */ 4151d522f475Smrg if (ScrnHaveSelection(screen)) { 4152d522f475Smrg /* save data which will be reset */ 4153d522f475Smrg CELL first = screen->startH; 4154d522f475Smrg CELL last = screen->endH; 4155d522f475Smrg 4156d522f475Smrg ResetSelectionState(screen); 4157d522f475Smrg ReHiliteText(xw, &first, &last); 4158d522f475Smrg } else { 4159d522f475Smrg ResetSelectionState(screen); 4160d522f475Smrg } 4161d522f475Smrg} 4162d522f475Smrg 4163d522f475Smrgvoid 4164d522f475SmrgUnhiliteSelection(XtermWidget xw) 4165d522f475Smrg{ 4166956cc18dSsnj TScreen *screen = TScreenOf(xw); 4167d522f475Smrg 4168d522f475Smrg if (ScrnHaveSelection(screen)) { 4169d522f475Smrg CELL first = screen->startH; 4170d522f475Smrg CELL last = screen->endH; 4171d522f475Smrg 4172d522f475Smrg screen->startH = zeroCELL; 4173d522f475Smrg screen->endH = zeroCELL; 4174d522f475Smrg ReHiliteText(xw, &first, &last); 4175d522f475Smrg } 4176d522f475Smrg} 4177d522f475Smrg 4178d522f475Smrg/* returns number of chars in line from scol to ecol out */ 4179d522f475Smrg/* ARGSUSED */ 4180d522f475Smrgstatic int 4181e0a2b6dfSmrgLength(TScreen *screen, 4182d522f475Smrg int row, 4183d522f475Smrg int scol, 4184d522f475Smrg int ecol) 4185d522f475Smrg{ 4186956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 4187956cc18dSsnj int lastcol = LastTextCol(screen, ld, row); 4188d522f475Smrg 4189d522f475Smrg if (ecol > lastcol) 4190d522f475Smrg ecol = lastcol; 4191d522f475Smrg return (ecol - scol + 1); 4192d522f475Smrg} 4193d522f475Smrg 4194d522f475Smrg/* copies text into line, preallocated */ 4195d522f475Smrgstatic Char * 4196e0a2b6dfSmrgSaveText(TScreen *screen, 4197d522f475Smrg int row, 4198d522f475Smrg int scol, 4199d522f475Smrg int ecol, 4200e0a2b6dfSmrg Char *lp, /* pointer to where to put the text */ 4201d522f475Smrg int *eol) 4202d522f475Smrg{ 4203956cc18dSsnj LineData *ld; 4204d522f475Smrg int i = 0; 4205d522f475Smrg unsigned c; 4206d522f475Smrg Char *result = lp; 4207d522f475Smrg#if OPT_WIDE_CHARS 42082eaa94a1Schristos unsigned previous = 0; 4209d522f475Smrg#endif 4210d522f475Smrg 4211956cc18dSsnj ld = GET_LINEDATA(screen, row); 4212d522f475Smrg i = Length(screen, row, scol, ecol); 4213d522f475Smrg ecol = scol + i; 4214d522f475Smrg#if OPT_DEC_CHRSET 4215956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 4216d522f475Smrg scol = (scol + 0) / 2; 4217d522f475Smrg ecol = (ecol + 1) / 2; 4218d522f475Smrg } 4219d522f475Smrg#endif 4220956cc18dSsnj *eol = !LineTstWrapped(ld); 4221d522f475Smrg for (i = scol; i < ecol; i++) { 42220bd37d32Smrg assert(i < (int) ld->lineSize); 4223956cc18dSsnj c = E2A(ld->charData[i]); 4224d522f475Smrg#if OPT_WIDE_CHARS 4225d522f475Smrg /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a 4226d522f475Smrg * wide character. 4227d522f475Smrg */ 4228894e0ac8Smrg if (c == HIDDEN_CHAR) { 4229894e0ac8Smrg if (isWide((int) previous)) { 4230894e0ac8Smrg previous = c; 4231894e0ac8Smrg /* Combining characters attached to double-width characters 4232894e0ac8Smrg are in memory attached to the HIDDEN_CHAR */ 4233894e0ac8Smrg if_OPT_WIDE_CHARS(screen, { 4234894e0ac8Smrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 4235894e0ac8Smrg unsigned ch; 4236894e0ac8Smrg size_t off; 4237894e0ac8Smrg for_each_combData(off, ld) { 4238894e0ac8Smrg ch = ld->combData[off][i]; 4239894e0ac8Smrg if (ch == 0) 4240894e0ac8Smrg break; 4241894e0ac8Smrg lp = convertToUTF8(lp, ch); 4242894e0ac8Smrg } 4243d522f475Smrg } 4244894e0ac8Smrg }); 4245894e0ac8Smrg continue; 4246894e0ac8Smrg } else { 4247894e0ac8Smrg c = ' '; /* should not happen, but just in case... */ 4248894e0ac8Smrg } 4249d522f475Smrg } 4250d522f475Smrg previous = c; 4251e0a2b6dfSmrg if ((screen->utf8_nrc_mode | screen->utf8_mode) != uFalse) { 4252d522f475Smrg lp = convertToUTF8(lp, (c != 0) ? c : ' '); 4253d522f475Smrg if_OPT_WIDE_CHARS(screen, { 4254d522f475Smrg unsigned ch; 4255956cc18dSsnj size_t off; 4256956cc18dSsnj for_each_combData(off, ld) { 4257956cc18dSsnj ch = ld->combData[off][i]; 4258956cc18dSsnj if (ch == 0) 4259d522f475Smrg break; 4260d522f475Smrg lp = convertToUTF8(lp, ch); 4261d522f475Smrg } 4262d522f475Smrg }); 4263d522f475Smrg } else 4264d522f475Smrg#endif 4265d522f475Smrg { 4266d522f475Smrg if (c == 0) { 4267d522f475Smrg c = E2A(' '); 4268d522f475Smrg } else if (c < E2A(' ')) { 4269d522f475Smrg c = DECtoASCII(c); 4270d522f475Smrg } else if (c == 0x7f) { 4271d522f475Smrg c = 0x5f; 4272d522f475Smrg } 42732eaa94a1Schristos *lp++ = CharOf(A2E(c)); 4274d522f475Smrg } 4275d522f475Smrg if (c != E2A(' ')) 4276d522f475Smrg result = lp; 4277d522f475Smrg } 4278d522f475Smrg 4279d522f475Smrg /* 4280d522f475Smrg * If requested, trim trailing blanks from selected lines. Do not do this 4281d522f475Smrg * if the line is wrapped. 4282d522f475Smrg */ 4283d522f475Smrg if (!*eol || !screen->trim_selection) 4284d522f475Smrg result = lp; 4285d522f475Smrg 4286d522f475Smrg return (result); 4287d522f475Smrg} 4288d522f475Smrg 4289d522f475Smrg/* 32 + following 7-bit word: 4290d522f475Smrg 4291d522f475Smrg 1:0 Button no: 0, 1, 2. 3=release. 4292d522f475Smrg 2 shift 4293d522f475Smrg 3 meta 4294d522f475Smrg 4 ctrl 4295d522f475Smrg 5 set for motion notify 4296d522f475Smrg 6 set for wheel 4297d522f475Smrg*/ 4298d522f475Smrg 4299d522f475Smrg/* Position: 32 - 255. */ 4300a1f3da82Smrgstatic int 4301894e0ac8SmrgBtnCode(XButtonEvent *event, int button) 4302d522f475Smrg{ 43032eaa94a1Schristos int result = (int) (32 + (KeyState(event->state) << 2)); 4304d522f475Smrg 43050bd37d32Smrg if (event->type == MotionNotify) 43060bd37d32Smrg result += 32; 43070bd37d32Smrg 4308d522f475Smrg if (button < 0 || button > 5) { 4309d522f475Smrg result += 3; 4310d522f475Smrg } else { 4311d522f475Smrg if (button > 3) 4312d522f475Smrg result += (64 - 4); 4313d522f475Smrg result += button; 4314d522f475Smrg } 43150bd37d32Smrg TRACE(("BtnCode button %d, %s state " FMT_MODIFIER_NAMES " ->%#x\n", 43160bd37d32Smrg button, 43170bd37d32Smrg visibleEventType(event->type), 43180bd37d32Smrg ARG_MODIFIER_NAMES(event->state), 43190bd37d32Smrg result)); 4320a1f3da82Smrg return result; 4321a1f3da82Smrg} 4322a1f3da82Smrg 4323a1f3da82Smrgstatic unsigned 4324e0a2b6dfSmrgEmitButtonCode(TScreen *screen, 4325e0a2b6dfSmrg Char *line, 43260bd37d32Smrg unsigned count, 4327894e0ac8Smrg XButtonEvent *event, 43280bd37d32Smrg int button) 4329a1f3da82Smrg{ 43300bd37d32Smrg int value; 4331a1f3da82Smrg 43320bd37d32Smrg if (screen->send_mouse_pos == X10_MOUSE) { 43330bd37d32Smrg value = CharOf(' ' + button); 4334a1f3da82Smrg } else { 43350bd37d32Smrg value = BtnCode(event, button); 43360bd37d32Smrg } 43370bd37d32Smrg 43380bd37d32Smrg switch (screen->extend_coords) { 43390bd37d32Smrg default: 43400bd37d32Smrg line[count++] = CharOf(value); 43410bd37d32Smrg break; 43420bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 43430bd37d32Smrg value -= 32; /* encoding starts at zero */ 43440bd37d32Smrg /* FALLTHRU */ 43450bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 43460bd37d32Smrg count += (unsigned) sprintf((char *) line + count, "%d", value); 43470bd37d32Smrg break; 43480bd37d32Smrg case SET_EXT_MODE_MOUSE: 43490bd37d32Smrg if (value < 128) { 43500bd37d32Smrg line[count++] = CharOf(value); 43510bd37d32Smrg } else { 43520bd37d32Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 43530bd37d32Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 43540bd37d32Smrg } 43550bd37d32Smrg break; 4356a1f3da82Smrg } 4357a1f3da82Smrg return count; 4358d522f475Smrg} 4359d522f475Smrg 43600bd37d32Smrgstatic int 43610bd37d32SmrgFirstBitN(int bits) 43620bd37d32Smrg{ 43630bd37d32Smrg int result = -1; 43640bd37d32Smrg if (bits > 0) { 43650bd37d32Smrg result = 0; 43660bd37d32Smrg while (!(bits & 1)) { 43670bd37d32Smrg bits /= 2; 43680bd37d32Smrg ++result; 43690bd37d32Smrg } 43700bd37d32Smrg } 43710bd37d32Smrg return result; 43720bd37d32Smrg} 43730bd37d32Smrg 43740bd37d32Smrg#define ButtonBit(button) ((button >= 0) ? (1 << (button)) : 0) 43750bd37d32Smrg 43760bd37d32Smrg#define EMIT_BUTTON(button) EmitButtonCode(screen, line, count, event, button) 43770bd37d32Smrg 4378d522f475Smrgstatic void 4379894e0ac8SmrgEditorButton(XtermWidget xw, XButtonEvent *event) 4380d522f475Smrg{ 4381956cc18dSsnj TScreen *screen = TScreenOf(xw); 4382d522f475Smrg int pty = screen->respond; 43830bd37d32Smrg int mouse_limit = MouseLimit(screen); 43840bd37d32Smrg Char line[32]; 43850bd37d32Smrg Char final = 'M'; 4386d522f475Smrg int row, col; 4387d522f475Smrg int button; 4388d522f475Smrg unsigned count = 0; 4389d522f475Smrg Boolean changed = True; 4390d522f475Smrg 4391d522f475Smrg /* If button event, get button # adjusted for DEC compatibility */ 43922eaa94a1Schristos button = (int) (event->button - 1); 4393d522f475Smrg if (button >= 3) 4394d522f475Smrg button++; 4395d522f475Smrg 4396d522f475Smrg /* Compute character position of mouse pointer */ 4397d522f475Smrg row = (event->y - screen->border) / FontHeight(screen); 4398d522f475Smrg col = (event->x - OriginX(screen)) / FontWidth(screen); 4399d522f475Smrg 4400d522f475Smrg /* Limit to screen dimensions */ 4401d522f475Smrg if (row < 0) 4402d522f475Smrg row = 0; 4403d522f475Smrg else if (row > screen->max_row) 4404d522f475Smrg row = screen->max_row; 4405d522f475Smrg 4406d522f475Smrg if (col < 0) 4407d522f475Smrg col = 0; 4408d522f475Smrg else if (col > screen->max_col) 4409d522f475Smrg col = screen->max_col; 4410492d43a5Smrg 44110bd37d32Smrg if (mouse_limit > 0) { 44120bd37d32Smrg /* Limit to representable mouse dimensions */ 44130bd37d32Smrg if (row > mouse_limit) 44140bd37d32Smrg row = mouse_limit; 44150bd37d32Smrg if (col > mouse_limit) 44160bd37d32Smrg col = mouse_limit; 44170bd37d32Smrg } 4418d522f475Smrg 4419d522f475Smrg /* Build key sequence starting with \E[M */ 4420d522f475Smrg if (screen->control_eight_bits) { 4421d522f475Smrg line[count++] = ANSI_CSI; 4422d522f475Smrg } else { 4423d522f475Smrg line[count++] = ANSI_ESC; 4424d522f475Smrg line[count++] = '['; 4425d522f475Smrg } 44260bd37d32Smrg switch (screen->extend_coords) { 44270bd37d32Smrg case 0: 44280bd37d32Smrg case SET_EXT_MODE_MOUSE: 4429d522f475Smrg#if OPT_SCO_FUNC_KEYS 44300bd37d32Smrg if (xw->keyboard.type == keyboardIsSCO) { 44310bd37d32Smrg /* 44320bd37d32Smrg * SCO function key F1 is \E[M, which would conflict with xterm's 44330bd37d32Smrg * normal kmous. 44340bd37d32Smrg */ 44350bd37d32Smrg line[count++] = '>'; 44360bd37d32Smrg } 4437d522f475Smrg#endif 44380bd37d32Smrg line[count++] = final; 44390bd37d32Smrg break; 44400bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 44410bd37d32Smrg line[count++] = '<'; 44420bd37d32Smrg break; 44430bd37d32Smrg } 4444d522f475Smrg 4445d522f475Smrg /* Add event code to key sequence */ 4446d522f475Smrg if (screen->send_mouse_pos == X10_MOUSE) { 44470bd37d32Smrg count = EMIT_BUTTON(button); 4448d522f475Smrg } else { 4449d522f475Smrg /* Button-Motion events */ 4450d522f475Smrg switch (event->type) { 4451d522f475Smrg case ButtonPress: 44520bd37d32Smrg screen->mouse_button |= ButtonBit(button); 44530bd37d32Smrg count = EMIT_BUTTON(button); 4454d522f475Smrg break; 4455d522f475Smrg case ButtonRelease: 4456d522f475Smrg /* 4457d522f475Smrg * Wheel mouse interface generates release-events for buttons 4458d522f475Smrg * 4 and 5, coded here as 3 and 4 respectively. We change the 44590bd37d32Smrg * release for buttons 1..3 to a -1, which will be later mapped 44600bd37d32Smrg * into a "0" (some button was released). 4461d522f475Smrg */ 44620bd37d32Smrg screen->mouse_button &= ~ButtonBit(button); 44630bd37d32Smrg if (button < 3) { 44640bd37d32Smrg switch (screen->extend_coords) { 44650bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 44660bd37d32Smrg final = 'm'; 44670bd37d32Smrg break; 44680bd37d32Smrg default: 44690bd37d32Smrg button = -1; 44700bd37d32Smrg break; 44710bd37d32Smrg } 44720bd37d32Smrg } 44730bd37d32Smrg count = EMIT_BUTTON(button); 4474d522f475Smrg break; 4475d522f475Smrg case MotionNotify: 4476d522f475Smrg /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion 4477d522f475Smrg * events only if character cell has changed. 4478d522f475Smrg */ 4479d522f475Smrg if ((row == screen->mouse_row) 4480d522f475Smrg && (col == screen->mouse_col)) { 4481d522f475Smrg changed = False; 4482d522f475Smrg } else { 44830bd37d32Smrg count = EMIT_BUTTON(FirstBitN(screen->mouse_button)); 4484d522f475Smrg } 4485d522f475Smrg break; 4486d522f475Smrg default: 4487d522f475Smrg changed = False; 4488d522f475Smrg break; 4489d522f475Smrg } 4490d522f475Smrg } 4491d522f475Smrg 4492d522f475Smrg if (changed) { 4493d522f475Smrg screen->mouse_row = row; 4494d522f475Smrg screen->mouse_col = col; 4495d522f475Smrg 4496492d43a5Smrg TRACE(("mouse at %d,%d button+mask = %#x\n", row, col, line[count - 1])); 4497d522f475Smrg 4498492d43a5Smrg /* Add pointer position to key sequence */ 44990bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 4500492d43a5Smrg count = EmitMousePosition(screen, line, count, col); 45010bd37d32Smrg count = EmitMousePositionSeparator(screen, line, count); 4502492d43a5Smrg count = EmitMousePosition(screen, line, count, row); 4503d522f475Smrg 45040bd37d32Smrg switch (screen->extend_coords) { 45050bd37d32Smrg case SET_SGR_EXT_MODE_MOUSE: 45060bd37d32Smrg case SET_URXVT_EXT_MODE_MOUSE: 45070bd37d32Smrg line[count++] = final; 45080bd37d32Smrg break; 45090bd37d32Smrg } 45100bd37d32Smrg 4511d522f475Smrg /* Transmit key sequence to process running under xterm */ 4512d522f475Smrg v_write(pty, line, count); 4513d522f475Smrg } 4514d522f475Smrg return; 4515d522f475Smrg} 4516d522f475Smrg 4517d522f475Smrg#if OPT_FOCUS_EVENT 4518d522f475Smrgvoid 4519894e0ac8SmrgSendFocusButton(XtermWidget xw, XFocusChangeEvent *event) 4520d522f475Smrg{ 4521956cc18dSsnj TScreen *screen = TScreenOf(xw); 4522d522f475Smrg 4523d522f475Smrg if (screen->send_focus_pos) { 4524d522f475Smrg ANSI reply; 4525d522f475Smrg 4526d522f475Smrg memset(&reply, 0, sizeof(reply)); 4527d522f475Smrg reply.a_type = ANSI_CSI; 4528d522f475Smrg 4529d522f475Smrg#if OPT_SCO_FUNC_KEYS 4530d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 4531d522f475Smrg reply.a_pintro = '>'; 4532d522f475Smrg } 4533d522f475Smrg#endif 45342eaa94a1Schristos reply.a_final = CharOf((event->type == FocusIn) ? 'I' : 'O'); 4535d522f475Smrg unparseseq(xw, &reply); 4536d522f475Smrg } 4537d522f475Smrg return; 4538d522f475Smrg} 4539d522f475Smrg#endif /* OPT_FOCUS_EVENT */ 45400bd37d32Smrg 45410bd37d32Smrg#if OPT_SELECTION_OPS 45420bd37d32Smrg/* 45430bd37d32Smrg * Get the event-time, needed to process selections. 45440bd37d32Smrg */ 45450bd37d32Smrgstatic Time 4546894e0ac8SmrggetEventTime(XEvent *event) 45470bd37d32Smrg{ 45480bd37d32Smrg Time result; 45490bd37d32Smrg 45500bd37d32Smrg if (IsBtnEvent(event)) { 45510bd37d32Smrg result = ((XButtonEvent *) event)->time; 45520bd37d32Smrg } else if (IsKeyEvent(event)) { 45530bd37d32Smrg result = ((XKeyEvent *) event)->time; 45540bd37d32Smrg } else { 45550bd37d32Smrg result = 0; 45560bd37d32Smrg } 45570bd37d32Smrg 45580bd37d32Smrg return result; 45590bd37d32Smrg} 45600bd37d32Smrg 45610bd37d32Smrg/* obtain the selection string, passing the endpoints to caller's parameters */ 45620bd37d32Smrgstatic char * 45630bd37d32SmrggetSelectionString(XtermWidget xw, 45640bd37d32Smrg Widget w, 4565894e0ac8Smrg XEvent *event, 4566e0a2b6dfSmrg String *params, 45670bd37d32Smrg Cardinal *num_params, 4568e0a2b6dfSmrg CELL *start, CELL *finish) 45690bd37d32Smrg{ 45700bd37d32Smrg TScreen *screen = TScreenOf(xw); 45710bd37d32Smrg#if OPT_PASTE64 45720bd37d32Smrg int base64_paste = (int) screen->base64_paste; 45730bd37d32Smrg#endif 45740bd37d32Smrg#if OPT_READLINE 45750bd37d32Smrg int paste_brackets = (int) SCREEN_FLAG(screen, paste_brackets); 45760bd37d32Smrg#endif 45770bd37d32Smrg 45780bd37d32Smrg /* override flags so that SelectionReceived only updates a buffer */ 45790bd37d32Smrg#if OPT_PASTE64 45800bd37d32Smrg screen->base64_paste = 0; 45810bd37d32Smrg#endif 45820bd37d32Smrg#if OPT_READLINE 45830bd37d32Smrg SCREEN_FLAG_unset(screen, paste_brackets); 45840bd37d32Smrg#endif 45850bd37d32Smrg 45860bd37d32Smrg screen->selectToBuffer = True; 45870bd37d32Smrg screen->internal_select = 0; 45880bd37d32Smrg xtermGetSelection(w, getEventTime(event), params + 1, *num_params - 1, NULL); 45890bd37d32Smrg screen->selectToBuffer = False; 45900bd37d32Smrg 45910bd37d32Smrg if (screen->internal_select != 0) { 45920bd37d32Smrg TRACE(("getSelectionString %d:%s\n", 45930bd37d32Smrg (int) strlen(screen->internal_select), 45940bd37d32Smrg screen->internal_select)); 45950bd37d32Smrg *start = screen->startSel; 45960bd37d32Smrg *finish = screen->endSel; 45970bd37d32Smrg } else { 45980bd37d32Smrg memset(start, 0, sizeof(*start)); 45990bd37d32Smrg memset(finish, 0, sizeof(*finish)); 46000bd37d32Smrg } 46010bd37d32Smrg#if OPT_PASTE64 46020bd37d32Smrg screen->base64_paste = (Cardinal) base64_paste; 46030bd37d32Smrg#endif 46040bd37d32Smrg#if OPT_READLINE 46050bd37d32Smrg if (paste_brackets) 46060bd37d32Smrg SCREEN_FLAG_set(screen, paste_brackets); 46070bd37d32Smrg#endif 46080bd37d32Smrg return screen->internal_select; 46090bd37d32Smrg} 46100bd37d32Smrg 46110bd37d32Smrg/* obtain data from the screen, passing the endpoints to caller's parameters */ 46120bd37d32Smrgstatic char * 4613e0a2b6dfSmrggetDataFromScreen(XtermWidget xw, String method, CELL *start, CELL *finish) 46140bd37d32Smrg{ 46150bd37d32Smrg TScreen *screen = TScreenOf(xw); 46160bd37d32Smrg 46170bd37d32Smrg CELL save_old_start = screen->startH; 46180bd37d32Smrg CELL save_old_end = screen->endH; 46190bd37d32Smrg 46200bd37d32Smrg CELL save_startSel = screen->startSel; 46210bd37d32Smrg CELL save_startRaw = screen->startRaw; 46220bd37d32Smrg CELL save_finishSel = screen->endSel; 46230bd37d32Smrg CELL save_finishRaw = screen->endRaw; 46240bd37d32Smrg 46250bd37d32Smrg int save_firstValidRow = screen->firstValidRow; 46260bd37d32Smrg int save_lastValidRow = screen->lastValidRow; 46270bd37d32Smrg 46280bd37d32Smrg SelectUnit saveUnits = screen->selectUnit; 46290bd37d32Smrg SelectUnit saveMap = screen->selectMap[0]; 46300bd37d32Smrg#if OPT_SELECT_REGEX 46310bd37d32Smrg char *saveExpr = screen->selectExpr[0]; 46320bd37d32Smrg#endif 46330bd37d32Smrg 46340bd37d32Smrg Char *save_selection_data = screen->selection_data; 46350bd37d32Smrg int save_selection_size = screen->selection_size; 46360bd37d32Smrg unsigned long save_selection_length = screen->selection_length; 46370bd37d32Smrg 46380bd37d32Smrg char *result = 0; 46390bd37d32Smrg 46400bd37d32Smrg TRACE(("getDataFromScreen %s\n", method)); 46410bd37d32Smrg 46420bd37d32Smrg screen->selection_data = 0; 46430bd37d32Smrg screen->selection_size = 0; 46440bd37d32Smrg screen->selection_length = 0; 46450bd37d32Smrg 46460bd37d32Smrg lookupSelectUnit(xw, 0, method); 46470bd37d32Smrg screen->selectUnit = screen->selectMap[0]; 46480bd37d32Smrg 46490bd37d32Smrg memset(start, 0, sizeof(*start)); 46500bd37d32Smrg start->row = screen->cur_row; 46510bd37d32Smrg start->col = screen->cur_col; 46520bd37d32Smrg *finish = *start; 46530bd37d32Smrg 46540bd37d32Smrg ComputeSelect(xw, start, finish, False); 46550bd37d32Smrg SaltTextAway(xw, &(screen->startSel), &(screen->endSel)); 46560bd37d32Smrg 46570bd37d32Smrg if (screen->selection_length && screen->selection_data) { 46580bd37d32Smrg TRACE(("...getDataFromScreen selection_data %.*s\n", 46590bd37d32Smrg (int) screen->selection_length, 46600bd37d32Smrg screen->selection_data)); 46610bd37d32Smrg result = malloc(screen->selection_length + 1); 46620bd37d32Smrg if (result) { 46630bd37d32Smrg memcpy(result, screen->selection_data, screen->selection_length); 46640bd37d32Smrg result[screen->selection_length] = 0; 46650bd37d32Smrg } 46660bd37d32Smrg free(screen->selection_data); 46670bd37d32Smrg } 46680bd37d32Smrg 46690bd37d32Smrg TRACE(("...getDataFromScreen restoring previous selection\n")); 46700bd37d32Smrg 46710bd37d32Smrg screen->startSel = save_startSel; 46720bd37d32Smrg screen->startRaw = save_startRaw; 46730bd37d32Smrg screen->endSel = save_finishSel; 46740bd37d32Smrg screen->endRaw = save_finishRaw; 46750bd37d32Smrg 46760bd37d32Smrg screen->firstValidRow = save_firstValidRow; 46770bd37d32Smrg screen->lastValidRow = save_lastValidRow; 46780bd37d32Smrg 46790bd37d32Smrg screen->selectUnit = saveUnits; 46800bd37d32Smrg screen->selectMap[0] = saveMap; 46810bd37d32Smrg#if OPT_SELECT_REGEX 46820bd37d32Smrg screen->selectExpr[0] = saveExpr; 46830bd37d32Smrg#endif 46840bd37d32Smrg 46850bd37d32Smrg screen->selection_data = save_selection_data; 46860bd37d32Smrg screen->selection_size = save_selection_size; 46870bd37d32Smrg screen->selection_length = save_selection_length; 46880bd37d32Smrg 46890bd37d32Smrg TrackText(xw, &save_old_start, &save_old_end); 46900bd37d32Smrg 46910bd37d32Smrg TRACE(("...getDataFromScreen done\n")); 46920bd37d32Smrg return result; 46930bd37d32Smrg} 46940bd37d32Smrg 46950bd37d32Smrg/* 46960bd37d32Smrg * Split-up the format before substituting data, to avoid quoting issues. 46970bd37d32Smrg * The resource mechanism has a limited ability to handle escapes. We take 46980bd37d32Smrg * the result as if it were an sh-type string and parse it into a regular 46990bd37d32Smrg * argv array. 47000bd37d32Smrg */ 47010bd37d32Smrgstatic char ** 47020bd37d32SmrgtokenizeFormat(String format) 47030bd37d32Smrg{ 47040bd37d32Smrg char **result = 0; 47050bd37d32Smrg int pass; 47060bd37d32Smrg int argc; 47070bd37d32Smrg int n; 47080bd37d32Smrg 47090bd37d32Smrg format = x_skip_blanks(format); 47100bd37d32Smrg if (*format != '\0') { 47110bd37d32Smrg char *blob = x_strdup(format); 47120bd37d32Smrg 47130bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 47140bd37d32Smrg int used = 0; 47150bd37d32Smrg int first = 1; 47160bd37d32Smrg int escaped = 0; 47170bd37d32Smrg int squoted = 0; 47180bd37d32Smrg int dquoted = 0; 47190bd37d32Smrg 47200bd37d32Smrg argc = 0; 47210bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 47220bd37d32Smrg if (escaped) { 47230bd37d32Smrg blob[used++] = format[n]; 47240bd37d32Smrg escaped = 0; 47250bd37d32Smrg } else if (format[n] == '"') { 47260bd37d32Smrg if (!squoted) { 47270bd37d32Smrg if (!dquoted) 47280bd37d32Smrg blob[used++] = format[n]; 47290bd37d32Smrg dquoted = !dquoted; 47300bd37d32Smrg } 47310bd37d32Smrg } else if (format[n] == '\'') { 47320bd37d32Smrg if (!dquoted) { 47330bd37d32Smrg if (!squoted) 47340bd37d32Smrg blob[used++] = format[n]; 47350bd37d32Smrg squoted = !squoted; 47360bd37d32Smrg } 47370bd37d32Smrg } else if (format[n] == '\\') { 47380bd37d32Smrg blob[used++] = format[n]; 47390bd37d32Smrg escaped = 1; 47400bd37d32Smrg } else { 47410bd37d32Smrg if (first) { 47420bd37d32Smrg first = 0; 47430bd37d32Smrg if (pass) { 47440bd37d32Smrg result[argc] = &blob[n]; 47450bd37d32Smrg } 47460bd37d32Smrg ++argc; 47470bd37d32Smrg } 47480bd37d32Smrg if (isspace((Char) format[n])) { 47490bd37d32Smrg first = !isspace((Char) format[n + 1]); 47500bd37d32Smrg if (squoted || dquoted) { 47510bd37d32Smrg blob[used++] = format[n]; 47520bd37d32Smrg } else if (first) { 47530bd37d32Smrg blob[used++] = '\0'; 47540bd37d32Smrg } 47550bd37d32Smrg } else { 47560bd37d32Smrg blob[used++] = format[n]; 47570bd37d32Smrg } 47580bd37d32Smrg } 47590bd37d32Smrg } 47600bd37d32Smrg blob[used] = '\0'; 47610bd37d32Smrg assert(strlen(blob) <= strlen(format)); 47620bd37d32Smrg if (!pass) { 47630bd37d32Smrg result = TypeCallocN(char *, argc + 1); 47640bd37d32Smrg if (result == 0) { 47650bd37d32Smrg free(blob); 47660bd37d32Smrg break; 47670bd37d32Smrg } 47680bd37d32Smrg } 47690bd37d32Smrg } 47700bd37d32Smrg } 47710bd37d32Smrg#if OPT_TRACE 47720bd37d32Smrg if (result) { 47730bd37d32Smrg TRACE(("tokenizeFormat %s\n", format)); 47740bd37d32Smrg for (argc = 0; result[argc]; ++argc) { 47750bd37d32Smrg TRACE(("argv[%d] = %s\n", argc, result[argc])); 47760bd37d32Smrg } 47770bd37d32Smrg } 47780bd37d32Smrg#endif 47790bd37d32Smrg 47800bd37d32Smrg return result; 47810bd37d32Smrg} 47820bd37d32Smrg 47830bd37d32Smrgstatic void 4784e0a2b6dfSmrgformatVideoAttrs(XtermWidget xw, char *buffer, CELL *cell) 47850bd37d32Smrg{ 47860bd37d32Smrg TScreen *screen = TScreenOf(xw); 47870bd37d32Smrg LineData *ld = GET_LINEDATA(screen, cell->row); 47880bd37d32Smrg 47890bd37d32Smrg *buffer = '\0'; 47900bd37d32Smrg if (ld != 0 && cell->col < (int) ld->lineSize) { 4791894e0ac8Smrg IAttr attribs = ld->attribs[cell->col]; 47920bd37d32Smrg const char *delim = ""; 47930bd37d32Smrg 47940bd37d32Smrg if (attribs & INVERSE) { 47950bd37d32Smrg buffer += sprintf(buffer, "7"); 47960bd37d32Smrg delim = ";"; 47970bd37d32Smrg } 47980bd37d32Smrg if (attribs & UNDERLINE) { 47990bd37d32Smrg buffer += sprintf(buffer, "%s4", delim); 48000bd37d32Smrg delim = ";"; 48010bd37d32Smrg } 48020bd37d32Smrg if (attribs & BOLD) { 48030bd37d32Smrg buffer += sprintf(buffer, "%s1", delim); 48040bd37d32Smrg delim = ";"; 48050bd37d32Smrg } 48060bd37d32Smrg if (attribs & BLINK) { 48070bd37d32Smrg buffer += sprintf(buffer, "%s5", delim); 48080bd37d32Smrg delim = ";"; 48090bd37d32Smrg } 48100bd37d32Smrg#if OPT_ISO_COLORS 48110bd37d32Smrg if (attribs & FG_COLOR) { 48120bd37d32Smrg unsigned fg = extract_fg(xw, ld->color[cell->col], attribs); 48130bd37d32Smrg if (fg < 8) { 48140bd37d32Smrg fg += 30; 48150bd37d32Smrg } else if (fg < 16) { 48160bd37d32Smrg fg += 90; 48170bd37d32Smrg } else { 48180bd37d32Smrg buffer += sprintf(buffer, "%s38;5", delim); 48190bd37d32Smrg delim = ";"; 48200bd37d32Smrg } 48210bd37d32Smrg buffer += sprintf(buffer, "%s%u", delim, fg); 48220bd37d32Smrg delim = ";"; 48230bd37d32Smrg } 48240bd37d32Smrg if (attribs & BG_COLOR) { 48250bd37d32Smrg unsigned bg = extract_bg(xw, ld->color[cell->col], attribs); 48260bd37d32Smrg if (bg < 8) { 48270bd37d32Smrg bg += 40; 48280bd37d32Smrg } else if (bg < 16) { 48290bd37d32Smrg bg += 100; 48300bd37d32Smrg } else { 48310bd37d32Smrg buffer += sprintf(buffer, "%s48;5", delim); 48320bd37d32Smrg delim = ";"; 48330bd37d32Smrg } 48340bd37d32Smrg (void) sprintf(buffer, "%s%u", delim, bg); 48350bd37d32Smrg } 48360bd37d32Smrg#endif 48370bd37d32Smrg } 48380bd37d32Smrg} 48390bd37d32Smrg 48400bd37d32Smrg/* substitute data into format, reallocating the result */ 48410bd37d32Smrgstatic char * 48420bd37d32SmrgexpandFormat(XtermWidget xw, 48430bd37d32Smrg const char *format, 48440bd37d32Smrg char *data, 4845e0a2b6dfSmrg CELL *start, 4846e0a2b6dfSmrg CELL *finish) 48470bd37d32Smrg{ 48480bd37d32Smrg char *result = 0; 48490bd37d32Smrg if (!IsEmpty(format)) { 48500bd37d32Smrg static char empty[1]; 48510bd37d32Smrg int pass; 48520bd37d32Smrg int n; 48530bd37d32Smrg char numbers[80]; 48540bd37d32Smrg 48550bd37d32Smrg if (data == 0) 48560bd37d32Smrg data = empty; 48570bd37d32Smrg 48580bd37d32Smrg for (pass = 0; pass < 2; ++pass) { 48590bd37d32Smrg size_t need = 0; 48600bd37d32Smrg 48610bd37d32Smrg for (n = 0; format[n] != '\0'; ++n) { 48620bd37d32Smrg char *value = 0; 48630bd37d32Smrg 48640bd37d32Smrg if (format[n] == '%') { 48650bd37d32Smrg switch (format[++n]) { 48660bd37d32Smrg case '%': 48670bd37d32Smrg if (pass) { 48680bd37d32Smrg result[need] = format[n]; 48690bd37d32Smrg } 48700bd37d32Smrg ++need; 48710bd37d32Smrg break; 48720bd37d32Smrg case 'P': 48730bd37d32Smrg sprintf(numbers, "%d;%d", 48740bd37d32Smrg TScreenOf(xw)->topline + start->row + 1, 48750bd37d32Smrg start->col + 1); 48760bd37d32Smrg value = numbers; 48770bd37d32Smrg break; 48780bd37d32Smrg case 'p': 48790bd37d32Smrg sprintf(numbers, "%d;%d", 48800bd37d32Smrg TScreenOf(xw)->topline + finish->row + 1, 48810bd37d32Smrg finish->col + 1); 48820bd37d32Smrg value = numbers; 48830bd37d32Smrg break; 48840bd37d32Smrg case 'S': 48850bd37d32Smrg sprintf(numbers, "%u", (unsigned) strlen(data)); 48860bd37d32Smrg value = numbers; 48870bd37d32Smrg break; 48880bd37d32Smrg case 's': 48890bd37d32Smrg value = data; 48900bd37d32Smrg break; 48910bd37d32Smrg case 'T': 48920bd37d32Smrg if ((value = x_strtrim(data)) != 0) { 48930bd37d32Smrg sprintf(numbers, "%u", (unsigned) strlen(value)); 48940bd37d32Smrg free(value); 48950bd37d32Smrg } else { 48960bd37d32Smrg strcpy(numbers, "0"); 48970bd37d32Smrg } 48980bd37d32Smrg value = numbers; 48990bd37d32Smrg break; 49000bd37d32Smrg case 't': 49010bd37d32Smrg value = x_strtrim(data); 49020bd37d32Smrg break; 49030bd37d32Smrg case 'V': 49040bd37d32Smrg formatVideoAttrs(xw, numbers, start); 49050bd37d32Smrg value = numbers; 49060bd37d32Smrg break; 49070bd37d32Smrg case 'v': 49080bd37d32Smrg formatVideoAttrs(xw, numbers, finish); 49090bd37d32Smrg value = numbers; 49100bd37d32Smrg break; 49110bd37d32Smrg default: 49120bd37d32Smrg if (pass) { 49130bd37d32Smrg result[need] = format[n]; 49140bd37d32Smrg } 49150bd37d32Smrg --n; 49160bd37d32Smrg ++need; 49170bd37d32Smrg break; 49180bd37d32Smrg } 49190bd37d32Smrg if (value != 0) { 49200bd37d32Smrg if (pass) { 49210bd37d32Smrg strcpy(result + need, value); 49220bd37d32Smrg } 49230bd37d32Smrg need += strlen(value); 49240bd37d32Smrg if (value != numbers && value != data) { 49250bd37d32Smrg free(value); 49260bd37d32Smrg } 49270bd37d32Smrg } 49280bd37d32Smrg } else { 49290bd37d32Smrg if (pass) { 49300bd37d32Smrg result[need] = format[n]; 49310bd37d32Smrg } 49320bd37d32Smrg ++need; 49330bd37d32Smrg } 49340bd37d32Smrg } 49350bd37d32Smrg if (pass) { 49360bd37d32Smrg result[need] = '\0'; 49370bd37d32Smrg } else { 49380bd37d32Smrg ++need; 49390bd37d32Smrg result = malloc(need); 49400bd37d32Smrg if (result == 0) { 49410bd37d32Smrg break; 49420bd37d32Smrg } 49430bd37d32Smrg } 49440bd37d32Smrg } 49450bd37d32Smrg } 49460bd37d32Smrg TRACE(("expandFormat(%s) = %s\n", NonNull(format), NonNull(result))); 49470bd37d32Smrg return result; 49480bd37d32Smrg} 49490bd37d32Smrg 49500bd37d32Smrg/* execute the command after forking. The main process frees its data */ 49510bd37d32Smrgstatic void 49520bd37d32SmrgexecuteCommand(char **argv) 49530bd37d32Smrg{ 49540bd37d32Smrg if (argv != 0 && argv[0] != 0) { 49550bd37d32Smrg if (fork() == 0) { 49560bd37d32Smrg execvp(argv[0], argv); 49570bd37d32Smrg exit(EXIT_FAILURE); 49580bd37d32Smrg } 49590bd37d32Smrg } 49600bd37d32Smrg} 49610bd37d32Smrg 49620bd37d32Smrgstatic void 49630bd37d32SmrgfreeArgv(char *blob, char **argv) 49640bd37d32Smrg{ 49650bd37d32Smrg int n; 49660bd37d32Smrg 49670bd37d32Smrg if (blob) { 49680bd37d32Smrg free(blob); 49690bd37d32Smrg if (argv) { 49700bd37d32Smrg for (n = 0; argv[n]; ++n) 49710bd37d32Smrg free(argv[n]); 49720bd37d32Smrg free(argv); 49730bd37d32Smrg } 49740bd37d32Smrg } 49750bd37d32Smrg} 49760bd37d32Smrg 49770bd37d32Smrgvoid 49780bd37d32SmrgHandleExecFormatted(Widget w, 4979894e0ac8Smrg XEvent *event GCC_UNUSED, 4980e0a2b6dfSmrg String *params, /* selections */ 49810bd37d32Smrg Cardinal *num_params) 49820bd37d32Smrg{ 49830bd37d32Smrg XtermWidget xw; 49840bd37d32Smrg 49850bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 49860bd37d32Smrg TRACE(("HandleExecFormatted(%d)\n", *num_params)); 49870bd37d32Smrg 49880bd37d32Smrg if (*num_params > 1) { 49890bd37d32Smrg CELL start, finish; 49900bd37d32Smrg char *data; 49910bd37d32Smrg char **argv; 49920bd37d32Smrg char *blob; 49930bd37d32Smrg int argc; 49940bd37d32Smrg 49950bd37d32Smrg data = getSelectionString(xw, w, event, params, num_params, 49960bd37d32Smrg &start, &finish); 49970bd37d32Smrg if ((argv = tokenizeFormat(params[0])) != 0) { 49980bd37d32Smrg blob = argv[0]; 49990bd37d32Smrg for (argc = 0; argv[argc] != 0; ++argc) { 50000bd37d32Smrg argv[argc] = expandFormat(xw, argv[argc], data, &start, &finish); 50010bd37d32Smrg } 50020bd37d32Smrg executeCommand(argv); 50030bd37d32Smrg freeArgv(blob, argv); 50040bd37d32Smrg } 50050bd37d32Smrg } 50060bd37d32Smrg } 50070bd37d32Smrg} 50080bd37d32Smrg 50090bd37d32Smrgvoid 50100bd37d32SmrgHandleExecSelectable(Widget w, 5011894e0ac8Smrg XEvent *event GCC_UNUSED, 5012e0a2b6dfSmrg String *params, /* selections */ 50130bd37d32Smrg Cardinal *num_params) 50140bd37d32Smrg{ 50150bd37d32Smrg XtermWidget xw; 50160bd37d32Smrg 50170bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 50180bd37d32Smrg TRACE(("HandleExecSelectable(%d)\n", *num_params)); 50190bd37d32Smrg 50200bd37d32Smrg if (*num_params == 2) { 50210bd37d32Smrg CELL start, finish; 50220bd37d32Smrg char *data; 50230bd37d32Smrg char **argv; 50240bd37d32Smrg char *blob; 50250bd37d32Smrg int argc; 50260bd37d32Smrg 50270bd37d32Smrg data = getDataFromScreen(xw, params[1], &start, &finish); 50280bd37d32Smrg if (data != 0) { 50290bd37d32Smrg if ((argv = tokenizeFormat(params[0])) != 0) { 50300bd37d32Smrg blob = argv[0]; 50310bd37d32Smrg for (argc = 0; argv[argc] != 0; ++argc) { 50320bd37d32Smrg argv[argc] = expandFormat(xw, argv[argc], data, 50330bd37d32Smrg &start, &finish); 50340bd37d32Smrg } 50350bd37d32Smrg executeCommand(argv); 50360bd37d32Smrg freeArgv(blob, argv); 50370bd37d32Smrg } 5038894e0ac8Smrg free(data); 50390bd37d32Smrg } 50400bd37d32Smrg } 50410bd37d32Smrg } 50420bd37d32Smrg} 50430bd37d32Smrg 50440bd37d32Smrgvoid 50450bd37d32SmrgHandleInsertFormatted(Widget w, 5046894e0ac8Smrg XEvent *event GCC_UNUSED, 5047e0a2b6dfSmrg String *params, /* selections */ 50480bd37d32Smrg Cardinal *num_params) 50490bd37d32Smrg{ 50500bd37d32Smrg XtermWidget xw; 50510bd37d32Smrg 50520bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 50530bd37d32Smrg TRACE(("HandleInsertFormatted(%d)\n", *num_params)); 50540bd37d32Smrg 50550bd37d32Smrg if (*num_params > 1) { 50560bd37d32Smrg CELL start, finish; 50570bd37d32Smrg char *data; 50580bd37d32Smrg char *temp = x_strdup(params[0]); 50590bd37d32Smrg char *exps; 50600bd37d32Smrg 50610bd37d32Smrg data = getSelectionString(xw, w, event, params, num_params, 50620bd37d32Smrg &start, &finish); 50630bd37d32Smrg if ((exps = expandFormat(xw, temp, data, &start, &finish)) != 0) { 50640bd37d32Smrg unparseputs(xw, exps); 50650bd37d32Smrg free(exps); 50660bd37d32Smrg } 50670bd37d32Smrg free(data); 50680bd37d32Smrg free(temp); 50690bd37d32Smrg } 50700bd37d32Smrg } 50710bd37d32Smrg} 50720bd37d32Smrg 50730bd37d32Smrgvoid 50740bd37d32SmrgHandleInsertSelectable(Widget w, 5075894e0ac8Smrg XEvent *event GCC_UNUSED, 5076e0a2b6dfSmrg String *params, /* selections */ 50770bd37d32Smrg Cardinal *num_params) 50780bd37d32Smrg{ 50790bd37d32Smrg XtermWidget xw; 50800bd37d32Smrg 50810bd37d32Smrg if ((xw = getXtermWidget(w)) != 0) { 50820bd37d32Smrg TRACE(("HandleInsertSelectable(%d)\n", *num_params)); 50830bd37d32Smrg 50840bd37d32Smrg if (*num_params == 2) { 50850bd37d32Smrg CELL start, finish; 50860bd37d32Smrg char *data; 50870bd37d32Smrg char *temp = x_strdup(params[0]); 50880bd37d32Smrg char *exps; 50890bd37d32Smrg 50900bd37d32Smrg data = getDataFromScreen(xw, params[1], &start, &finish); 50910bd37d32Smrg if (data != 0) { 50920bd37d32Smrg exps = expandFormat(xw, temp, data, &start, &finish); 50930bd37d32Smrg if (exps != 0) { 50940bd37d32Smrg unparseputs(xw, exps); 50950bd37d32Smrg free(exps); 50960bd37d32Smrg } 50970bd37d32Smrg free(data); 50980bd37d32Smrg } 50990bd37d32Smrg free(temp); 51000bd37d32Smrg } 51010bd37d32Smrg } 51020bd37d32Smrg} 51030bd37d32Smrg#endif /* OPT_SELECTION_OPS */ 5104