button.c revision a1f3da82
1a1f3da82Smrg/* $XTermId: button.c,v 1.397 2011/02/13 20:09:31 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4a1f3da82Smrg * Copyright 1999-2010,2011 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> 6520d2c4d2Smrg#include <assert.h> 66d522f475Smrg 67d522f475Smrg#include <X11/Xatom.h> 68d522f475Smrg#include <X11/Xmu/Atoms.h> 69d522f475Smrg#include <X11/Xmu/StdSel.h> 70d522f475Smrg 71d522f475Smrg#include <xutf8.h> 72d522f475Smrg#include <fontutils.h> 73d522f475Smrg 74d522f475Smrg#include <data.h> 75d522f475Smrg#include <error.h> 76d522f475Smrg#include <menu.h> 77d522f475Smrg#include <xcharmouse.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) 122d522f475Smrg 1232eaa94a1Schristos#define KeyState(x) (((int) ((x) & (ShiftMask|ControlMask))) \ 1242eaa94a1Schristos + (((x) & Mod1Mask) ? 2 : 0)) 125d522f475Smrg /* adds together the bits: 126d522f475Smrg shift key -> 1 127d522f475Smrg meta key -> 2 128d522f475Smrg control key -> 4 */ 129d522f475Smrg 130d522f475Smrg#define Coordinate(s,c) ((c)->row * MaxCols(s) + (c)->col) 131d522f475Smrg 132d522f475Smrgstatic const CELL zeroCELL = 133d522f475Smrg{0, 0}; 134d522f475Smrg 135d522f475Smrg#if OPT_DEC_LOCATOR 136492d43a5Smrgstatic Bool SendLocatorPosition(XtermWidget xw, XButtonEvent * event); 137492d43a5Smrgstatic void CheckLocatorPosition(XtermWidget xw, XButtonEvent * event); 138d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 139d522f475Smrg 140d522f475Smrg/* Multi-click handling */ 141d522f475Smrg#if OPT_READLINE 142d522f475Smrgstatic Time lastButtonDownTime = 0; 143d522f475Smrgstatic int ExtendingSelection = 0; 144d522f475Smrgstatic Time lastButton3UpTime = 0; 145d522f475Smrgstatic Time lastButton3DoubleDownTime = 0; 146d522f475Smrgstatic CELL lastButton3; /* At the release time */ 147d522f475Smrg#endif /* OPT_READLINE */ 148d522f475Smrg 149d522f475Smrgstatic Char *SaveText(TScreen * screen, int row, int scol, int ecol, 150d522f475Smrg Char * lp, int *eol); 151d522f475Smrgstatic int Length(TScreen * screen, int row, int scol, int ecol); 152d522f475Smrgstatic void ComputeSelect(XtermWidget xw, CELL * startc, CELL * endc, Bool extend); 153d522f475Smrgstatic void EditorButton(XtermWidget xw, XButtonEvent * event); 154d522f475Smrgstatic void EndExtend(XtermWidget w, XEvent * event, String * params, Cardinal 155d522f475Smrg num_params, Bool use_cursor_loc); 156d522f475Smrgstatic void ExtendExtend(XtermWidget xw, const CELL * cell); 157d522f475Smrgstatic void PointToCELL(TScreen * screen, int y, int x, CELL * cell); 158d522f475Smrgstatic void ReHiliteText(XtermWidget xw, CELL * first, CELL * last); 159d522f475Smrgstatic void SaltTextAway(XtermWidget xw, CELL * cellc, CELL * cell, 160d522f475Smrg String * params, Cardinal num_params); 161d522f475Smrgstatic void SelectSet(XtermWidget xw, XEvent * event, String * params, Cardinal num_params); 162d522f475Smrgstatic void SelectionReceived PROTO_XT_SEL_CB_ARGS; 163d522f475Smrgstatic void StartSelect(XtermWidget xw, const CELL * cell); 164d522f475Smrgstatic void TrackDown(XtermWidget xw, XButtonEvent * event); 165d522f475Smrgstatic void TrackText(XtermWidget xw, const CELL * first, const CELL * last); 166d522f475Smrgstatic void _OwnSelection(XtermWidget xw, String * selections, Cardinal count); 167d522f475Smrgstatic 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 176492d43a5Smrgstatic unsigned 177492d43a5SmrgEmitMousePosition(TScreen * screen, Char line[], unsigned count, int value) 178492d43a5Smrg{ 179492d43a5Smrg int mouse_limit = (screen->ext_mode_mouse 180492d43a5Smrg ? EXT_MOUSE_LIMIT 181492d43a5Smrg : MOUSE_LIMIT); 182492d43a5Smrg 183492d43a5Smrg /* 184492d43a5Smrg * Add pointer position to key sequence 185492d43a5Smrg * 186492d43a5Smrg * In extended mode we encode large positions as two-byte UTF-8. 187492d43a5Smrg * 188492d43a5Smrg * NOTE: historically, it was possible to emit 256, which became 189492d43a5Smrg * zero by truncation to 8 bits. While this was arguably a bug, 190492d43a5Smrg * it's also somewhat useful as a past-end marker. We preserve 191492d43a5Smrg * this behavior for both normal and extended mouse modes. 192492d43a5Smrg */ 193492d43a5Smrg if (value == mouse_limit) { 194492d43a5Smrg line[count++] = CharOf(0); 195492d43a5Smrg } else if (!screen->ext_mode_mouse || value < EXT_MOUSE_START) { 196492d43a5Smrg line[count++] = CharOf(' ' + value + 1); 197492d43a5Smrg } else { 198492d43a5Smrg value += ' ' + 1; 199492d43a5Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 200492d43a5Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 201d522f475Smrg } 202492d43a5Smrg return count; 203492d43a5Smrg} 204d522f475Smrg 205492d43a5SmrgBool 206492d43a5SmrgSendMousePosition(XtermWidget xw, XEvent * event) 207492d43a5Smrg{ 208492d43a5Smrg TScreen *screen = TScreenOf(xw); 209492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 210492d43a5Smrg Bool result = False; 211d522f475Smrg 212d522f475Smrg switch (screen->send_mouse_pos) { 213492d43a5Smrg case MOUSE_OFF: 214492d43a5Smrg /* If send_mouse_pos mode isn't on, we shouldn't be here */ 215492d43a5Smrg break; 216d522f475Smrg 217d522f475Smrg case BTN_EVENT_MOUSE: 218d522f475Smrg case ANY_EVENT_MOUSE: 219492d43a5Smrg if (KeyModifiers(event) == 0 || KeyModifiers(event) == ControlMask) { 220492d43a5Smrg /* xterm extension for motion reporting. June 1998 */ 221492d43a5Smrg /* EditorButton() will distinguish between the modes */ 222492d43a5Smrg switch (event->type) { 223492d43a5Smrg case MotionNotify: 224492d43a5Smrg my_event->button = 0; 225492d43a5Smrg /* FALLTHRU */ 226492d43a5Smrg case ButtonPress: 227492d43a5Smrg /* FALLTHRU */ 228492d43a5Smrg case ButtonRelease: 229492d43a5Smrg EditorButton(xw, my_event); 230492d43a5Smrg result = True; 231492d43a5Smrg break; 2322eaa94a1Schristos } 233d522f475Smrg } 234492d43a5Smrg break; 235d522f475Smrg 236d522f475Smrg default: 237492d43a5Smrg /* Make sure the event is an appropriate type */ 238492d43a5Smrg if (IsBtnEvent(event)) { 239492d43a5Smrg switch (screen->send_mouse_pos) { 240492d43a5Smrg case X10_MOUSE: /* X10 compatibility sequences */ 241492d43a5Smrg 242492d43a5Smrg if (BtnModifiers(my_event) == 0) { 243492d43a5Smrg if (my_event->type == ButtonPress) 244492d43a5Smrg EditorButton(xw, my_event); 245492d43a5Smrg result = True; 246492d43a5Smrg } 247492d43a5Smrg break; 248492d43a5Smrg 249492d43a5Smrg case VT200_HIGHLIGHT_MOUSE: /* DEC vt200 hilite tracking */ 250492d43a5Smrg if (my_event->type == ButtonPress && 251492d43a5Smrg BtnModifiers(my_event) == 0 && 252492d43a5Smrg my_event->button == Button1) { 253492d43a5Smrg TrackDown(xw, my_event); 254492d43a5Smrg result = True; 255492d43a5Smrg } else if (BtnModifiers(my_event) == 0 256492d43a5Smrg || BtnModifiers(my_event) == ControlMask) { 257492d43a5Smrg EditorButton(xw, my_event); 258492d43a5Smrg result = True; 259492d43a5Smrg } 260492d43a5Smrg break; 261492d43a5Smrg 262492d43a5Smrg case VT200_MOUSE: /* DEC vt200 compatible */ 263492d43a5Smrg if (BtnModifiers(my_event) == 0 264492d43a5Smrg || BtnModifiers(my_event) == ControlMask) { 265492d43a5Smrg EditorButton(xw, my_event); 266492d43a5Smrg result = True; 267492d43a5Smrg } 268492d43a5Smrg break; 269492d43a5Smrg 270492d43a5Smrg#if OPT_DEC_LOCATOR 271492d43a5Smrg case DEC_LOCATOR: 272492d43a5Smrg result = SendLocatorPosition(xw, my_event); 273492d43a5Smrg break; 274492d43a5Smrg#endif /* OPT_DEC_LOCATOR */ 275492d43a5Smrg } 276492d43a5Smrg } 277d522f475Smrg } 278492d43a5Smrg return result; 279d522f475Smrg} 280d522f475Smrg 281d522f475Smrg#if OPT_DEC_LOCATOR 282d522f475Smrg 283d522f475Smrg#define LocatorCoords( row, col, x, y, oor ) \ 284d522f475Smrg if( screen->locator_pixels ) { \ 285d522f475Smrg (oor)=False; (row) = (y)+1; (col) = (x)+1; \ 286d522f475Smrg /* Limit to screen dimensions */ \ 287d522f475Smrg if ((row) < 1) (row) = 1,(oor)=True; \ 288d522f475Smrg else if ((row) > screen->border*2+Height(screen)) \ 289d522f475Smrg (row) = screen->border*2+Height(screen),(oor)=True; \ 290d522f475Smrg if ((col) < 1) (col) = 1,(oor)=True; \ 291d522f475Smrg else if ((col) > OriginX(screen)*2+Width(screen)) \ 292d522f475Smrg (col) = OriginX(screen)*2+Width(screen),(oor)=True; \ 293d522f475Smrg } else { \ 294d522f475Smrg (oor)=False; \ 295d522f475Smrg /* Compute character position of mouse pointer */ \ 296d522f475Smrg (row) = ((y) - screen->border) / FontHeight(screen); \ 297d522f475Smrg (col) = ((x) - OriginX(screen)) / FontWidth(screen); \ 298d522f475Smrg /* Limit to screen dimensions */ \ 299d522f475Smrg if ((row) < 0) (row) = 0,(oor)=True; \ 300d522f475Smrg else if ((row) > screen->max_row) \ 301d522f475Smrg (row) = screen->max_row,(oor)=True; \ 302d522f475Smrg if ((col) < 0) (col) = 0,(oor)=True; \ 303d522f475Smrg else if ((col) > screen->max_col) \ 304d522f475Smrg (col) = screen->max_col,(oor)=True; \ 305d522f475Smrg (row)++; (col)++; \ 306d522f475Smrg } 307d522f475Smrg 308d522f475Smrgstatic Bool 309492d43a5SmrgSendLocatorPosition(XtermWidget xw, XButtonEvent * event) 310d522f475Smrg{ 311d522f475Smrg ANSI reply; 312956cc18dSsnj TScreen *screen = TScreenOf(xw); 313d522f475Smrg int row, col; 314d522f475Smrg Bool oor; 315d522f475Smrg int button; 3162eaa94a1Schristos unsigned state; 317d522f475Smrg 318d522f475Smrg /* Make sure the event is an appropriate type */ 319492d43a5Smrg if ((!IsBtnEvent(event) && 320d522f475Smrg !screen->loc_filter) || 321492d43a5Smrg (BtnModifiers(event) != 0 && BtnModifiers(event) != ControlMask)) 322d522f475Smrg return (False); 323d522f475Smrg 324d522f475Smrg if ((event->type == ButtonPress && 325d522f475Smrg !(screen->locator_events & LOC_BTNS_DN)) || 326d522f475Smrg (event->type == ButtonRelease && 327d522f475Smrg !(screen->locator_events & LOC_BTNS_UP))) 328d522f475Smrg return (True); 329d522f475Smrg 330d522f475Smrg if (event->type == MotionNotify) { 331d522f475Smrg CheckLocatorPosition(xw, event); 332d522f475Smrg return (True); 333d522f475Smrg } 334d522f475Smrg 335d522f475Smrg /* get button # */ 336492d43a5Smrg button = (int) event->button - 1; 337d522f475Smrg 338492d43a5Smrg LocatorCoords(row, col, event->x, event->y, oor); 339d522f475Smrg 340d522f475Smrg /* 341d522f475Smrg * DECterm mouse: 342d522f475Smrg * 343d522f475Smrg * ESCAPE '[' event ; mask ; row ; column '&' 'w' 344d522f475Smrg */ 345d522f475Smrg memset(&reply, 0, sizeof(reply)); 346d522f475Smrg reply.a_type = ANSI_CSI; 347d522f475Smrg 348d522f475Smrg if (oor) { 349d522f475Smrg reply.a_nparam = 1; 350d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 351d522f475Smrg reply.a_inters = '&'; 352d522f475Smrg reply.a_final = 'w'; 353d522f475Smrg unparseseq(xw, &reply); 354d522f475Smrg 355d522f475Smrg if (screen->locator_reset) { 356d522f475Smrg MotionOff(screen, xw); 357d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 358d522f475Smrg } 359d522f475Smrg return (True); 360d522f475Smrg } 361d522f475Smrg 362d522f475Smrg /* 363d522f475Smrg * event: 364d522f475Smrg * 1 no buttons 365d522f475Smrg * 2 left button down 366d522f475Smrg * 3 left button up 367d522f475Smrg * 4 middle button down 368d522f475Smrg * 5 middle button up 369d522f475Smrg * 6 right button down 370d522f475Smrg * 7 right button up 371d522f475Smrg * 8 M4 down 372d522f475Smrg * 9 M4 up 373d522f475Smrg */ 374d522f475Smrg reply.a_nparam = 4; 375d522f475Smrg switch (event->type) { 376d522f475Smrg case ButtonPress: 3772eaa94a1Schristos reply.a_param[0] = (ParmType) (2 + (button << 1)); 378d522f475Smrg break; 379d522f475Smrg case ButtonRelease: 3802eaa94a1Schristos reply.a_param[0] = (ParmType) (3 + (button << 1)); 381d522f475Smrg break; 382d522f475Smrg default: 383d522f475Smrg return (True); 384d522f475Smrg } 385d522f475Smrg /* 386d522f475Smrg * mask: 387d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 388d522f475Smrg * M4 down left down middle down right down 389d522f475Smrg * 390d522f475Smrg * Notice that Button1 (left) and Button3 (right) are swapped in the mask. 391d522f475Smrg * Also, mask should be the state after the button press/release, 392d522f475Smrg * X provides the state not including the button press/release. 393d522f475Smrg */ 394492d43a5Smrg state = (event->state 395d522f475Smrg & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8; 3964e40088cSchristos /* update mask to "after" state */ 39720d2c4d2Smrg state ^= ((unsigned) (1 << button)); 3984e40088cSchristos /* swap Button1 & Button3 */ 399956cc18dSsnj state = ((state & (unsigned) ~(4 | 1)) 400956cc18dSsnj | ((state & 1) ? 4 : 0) 401956cc18dSsnj | ((state & 4) ? 1 : 0)); 402d522f475Smrg 4032eaa94a1Schristos reply.a_param[1] = (ParmType) state; 4042eaa94a1Schristos reply.a_param[2] = (ParmType) row; 4052eaa94a1Schristos reply.a_param[3] = (ParmType) col; 406d522f475Smrg reply.a_inters = '&'; 407d522f475Smrg reply.a_final = 'w'; 408d522f475Smrg 409d522f475Smrg unparseseq(xw, &reply); 410d522f475Smrg 411d522f475Smrg if (screen->locator_reset) { 412d522f475Smrg MotionOff(screen, xw); 413d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 414d522f475Smrg } 415d522f475Smrg 416d522f475Smrg /* 417d522f475Smrg * DECterm turns the Locator off if a button is pressed while a filter rectangle 418d522f475Smrg * is active. This might be a bug, but I don't know, so I'll emulate it anyways. 419d522f475Smrg */ 420d522f475Smrg if (screen->loc_filter) { 421d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 422d522f475Smrg screen->loc_filter = False; 423d522f475Smrg screen->locator_events = 0; 424d522f475Smrg MotionOff(screen, xw); 425d522f475Smrg } 426d522f475Smrg 427d522f475Smrg return (True); 428d522f475Smrg} 429d522f475Smrg 430d522f475Smrg/* 431d522f475Smrg * mask: 432d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 433d522f475Smrg * M4 down left down middle down right down 434d522f475Smrg * 435d522f475Smrg * Button1 (left) and Button3 (right) are swapped in the mask relative to X. 436d522f475Smrg */ 437d522f475Smrg#define ButtonState(state, mask) \ 4382eaa94a1Schristos{ (state) = (int) (((mask) & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8); \ 439d522f475Smrg /* swap Button1 & Button3 */ \ 440d522f475Smrg (state) = ((state) & ~(4|1)) | (((state)&1)?4:0) | (((state)&4)?1:0); \ 441d522f475Smrg} 442d522f475Smrg 443d522f475Smrgvoid 444d522f475SmrgGetLocatorPosition(XtermWidget xw) 445d522f475Smrg{ 446d522f475Smrg ANSI reply; 447956cc18dSsnj TScreen *screen = TScreenOf(xw); 448d522f475Smrg Window root, child; 449d522f475Smrg int rx, ry, x, y; 450d522f475Smrg unsigned int mask; 451d522f475Smrg int row = 0, col = 0; 452d522f475Smrg Bool oor = False; 453d522f475Smrg Bool ret = False; 454d522f475Smrg int state; 455d522f475Smrg 456d522f475Smrg /* 457d522f475Smrg * DECterm turns the Locator off if the position is requested while a filter rectangle 458d522f475Smrg * is active. This might be a bug, but I don't know, so I'll emulate it anyways. 459d522f475Smrg */ 460d522f475Smrg if (screen->loc_filter) { 461d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 462d522f475Smrg screen->loc_filter = False; 463d522f475Smrg screen->locator_events = 0; 464d522f475Smrg MotionOff(screen, xw); 465d522f475Smrg } 466d522f475Smrg 467d522f475Smrg memset(&reply, 0, sizeof(reply)); 468d522f475Smrg reply.a_type = ANSI_CSI; 469d522f475Smrg 470d522f475Smrg if (screen->send_mouse_pos == DEC_LOCATOR) { 471d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), &root, 472d522f475Smrg &child, &rx, &ry, &x, &y, &mask); 473d522f475Smrg if (ret) { 474d522f475Smrg LocatorCoords(row, col, x, y, oor); 475d522f475Smrg } 476d522f475Smrg } 477d522f475Smrg if (ret == False || oor) { 478d522f475Smrg reply.a_nparam = 1; 479d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 480d522f475Smrg reply.a_inters = '&'; 481d522f475Smrg reply.a_final = 'w'; 482d522f475Smrg unparseseq(xw, &reply); 483d522f475Smrg 484d522f475Smrg if (screen->locator_reset) { 485d522f475Smrg MotionOff(screen, xw); 486d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 487d522f475Smrg } 488d522f475Smrg return; 489d522f475Smrg } 490d522f475Smrg 491d522f475Smrg ButtonState(state, mask); 492d522f475Smrg 493d522f475Smrg reply.a_nparam = 4; 494d522f475Smrg reply.a_param[0] = 1; /* Event - 1 = response to locator request */ 4952eaa94a1Schristos reply.a_param[1] = (ParmType) state; 4962eaa94a1Schristos reply.a_param[2] = (ParmType) row; 4972eaa94a1Schristos reply.a_param[3] = (ParmType) col; 498d522f475Smrg reply.a_inters = '&'; 499d522f475Smrg reply.a_final = 'w'; 500d522f475Smrg unparseseq(xw, &reply); 501d522f475Smrg 502d522f475Smrg if (screen->locator_reset) { 503d522f475Smrg MotionOff(screen, xw); 504d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 505d522f475Smrg } 506d522f475Smrg} 507d522f475Smrg 508d522f475Smrgvoid 509d522f475SmrgInitLocatorFilter(XtermWidget xw) 510d522f475Smrg{ 511d522f475Smrg ANSI reply; 512956cc18dSsnj TScreen *screen = TScreenOf(xw); 513d522f475Smrg Window root, child; 514d522f475Smrg int rx, ry, x, y; 515d522f475Smrg unsigned int mask; 516d522f475Smrg int row = 0, col = 0; 517d522f475Smrg Bool oor = 0; 518d522f475Smrg Bool ret; 519d522f475Smrg int state; 520d522f475Smrg 521d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), 522d522f475Smrg &root, &child, &rx, &ry, &x, &y, &mask); 523d522f475Smrg if (ret) { 524d522f475Smrg LocatorCoords(row, col, x, y, oor); 525d522f475Smrg } 526d522f475Smrg if (ret == False || oor) { 527d522f475Smrg /* Locator is unavailable */ 528d522f475Smrg 529d522f475Smrg if (screen->loc_filter_top != LOC_FILTER_POS || 530d522f475Smrg screen->loc_filter_left != LOC_FILTER_POS || 531d522f475Smrg screen->loc_filter_bottom != LOC_FILTER_POS || 532d522f475Smrg screen->loc_filter_right != LOC_FILTER_POS) { 533d522f475Smrg /* 534d522f475Smrg * If any explicit coordinates were received, 535d522f475Smrg * report immediately with no coordinates. 536d522f475Smrg */ 537d522f475Smrg memset(&reply, 0, sizeof(reply)); 538d522f475Smrg reply.a_type = ANSI_CSI; 539d522f475Smrg reply.a_nparam = 1; 540d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 541d522f475Smrg reply.a_inters = '&'; 542d522f475Smrg reply.a_final = 'w'; 543d522f475Smrg unparseseq(xw, &reply); 544d522f475Smrg 545d522f475Smrg if (screen->locator_reset) { 546d522f475Smrg MotionOff(screen, xw); 547d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 548d522f475Smrg } 549d522f475Smrg } else { 550d522f475Smrg /* 551d522f475Smrg * No explicit coordinates were received, and the pointer is 552d522f475Smrg * unavailable. Report when the pointer re-enters the window. 553d522f475Smrg */ 554d522f475Smrg screen->loc_filter = True; 555d522f475Smrg MotionOn(screen, xw); 556d522f475Smrg } 557d522f475Smrg return; 558d522f475Smrg } 559d522f475Smrg 560d522f475Smrg /* 561d522f475Smrg * Adjust rectangle coordinates: 562d522f475Smrg * 1. Replace "LOC_FILTER_POS" with current coordinates 563d522f475Smrg * 2. Limit coordinates to screen size 564d522f475Smrg * 3. make sure top and left are less than bottom and right, resp. 565d522f475Smrg */ 566d522f475Smrg if (screen->locator_pixels) { 567d522f475Smrg rx = OriginX(screen) * 2 + Width(screen); 568d522f475Smrg ry = screen->border * 2 + Height(screen); 569d522f475Smrg } else { 570d522f475Smrg rx = screen->max_col; 571d522f475Smrg ry = screen->max_row; 572d522f475Smrg } 573d522f475Smrg 574d522f475Smrg#define Adjust( coord, def, max ) \ 575d522f475Smrg if( (coord) == LOC_FILTER_POS ) (coord) = (def); \ 576d522f475Smrg else if ((coord) < 1) (coord) = 1; \ 577d522f475Smrg else if ((coord) > (max)) (coord) = (max) 578d522f475Smrg 579d522f475Smrg Adjust(screen->loc_filter_top, row, ry); 580d522f475Smrg Adjust(screen->loc_filter_left, col, rx); 581d522f475Smrg Adjust(screen->loc_filter_bottom, row, ry); 582d522f475Smrg Adjust(screen->loc_filter_right, col, rx); 583d522f475Smrg 584d522f475Smrg if (screen->loc_filter_top > screen->loc_filter_bottom) { 585d522f475Smrg ry = screen->loc_filter_top; 586d522f475Smrg screen->loc_filter_top = screen->loc_filter_bottom; 587d522f475Smrg screen->loc_filter_bottom = ry; 588d522f475Smrg } 589d522f475Smrg 590d522f475Smrg if (screen->loc_filter_left > screen->loc_filter_right) { 591d522f475Smrg rx = screen->loc_filter_left; 592d522f475Smrg screen->loc_filter_left = screen->loc_filter_right; 593d522f475Smrg screen->loc_filter_right = rx; 594d522f475Smrg } 595d522f475Smrg 596d522f475Smrg if ((col < screen->loc_filter_left) || 597d522f475Smrg (col > screen->loc_filter_right) || 598d522f475Smrg (row < screen->loc_filter_top) || 599d522f475Smrg (row > screen->loc_filter_bottom)) { 600d522f475Smrg /* Pointer is already outside the rectangle - report immediately */ 601d522f475Smrg ButtonState(state, mask); 602d522f475Smrg 603d522f475Smrg memset(&reply, 0, sizeof(reply)); 604d522f475Smrg reply.a_type = ANSI_CSI; 605d522f475Smrg reply.a_nparam = 4; 606d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 6072eaa94a1Schristos reply.a_param[1] = (ParmType) state; 6082eaa94a1Schristos reply.a_param[2] = (ParmType) row; 6092eaa94a1Schristos reply.a_param[3] = (ParmType) col; 610d522f475Smrg reply.a_inters = '&'; 611d522f475Smrg reply.a_final = 'w'; 612d522f475Smrg unparseseq(xw, &reply); 613d522f475Smrg 614d522f475Smrg if (screen->locator_reset) { 615d522f475Smrg MotionOff(screen, xw); 616d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 617d522f475Smrg } 618d522f475Smrg return; 619d522f475Smrg } 620d522f475Smrg 621d522f475Smrg /* 622d522f475Smrg * Rectangle is set up. Allow pointer tracking 623d522f475Smrg * to detect if the mouse leaves the rectangle. 624d522f475Smrg */ 625d522f475Smrg screen->loc_filter = True; 626d522f475Smrg MotionOn(screen, xw); 627d522f475Smrg} 628d522f475Smrg 629d522f475Smrgstatic void 630492d43a5SmrgCheckLocatorPosition(XtermWidget xw, XButtonEvent * event) 631d522f475Smrg{ 632d522f475Smrg ANSI reply; 633956cc18dSsnj TScreen *screen = TScreenOf(xw); 634d522f475Smrg int row, col; 635d522f475Smrg Bool oor; 636d522f475Smrg int state; 637d522f475Smrg 638492d43a5Smrg LocatorCoords(row, col, event->x, event->y, oor); 639d522f475Smrg 640d522f475Smrg /* 641d522f475Smrg * Send report if the pointer left the filter rectangle, if 642d522f475Smrg * the pointer left the window, or if the filter rectangle 643d522f475Smrg * had no coordinates and the pointer re-entered the window. 644d522f475Smrg */ 645d522f475Smrg if (oor || (screen->loc_filter_top == LOC_FILTER_POS) || 646d522f475Smrg (col < screen->loc_filter_left) || 647d522f475Smrg (col > screen->loc_filter_right) || 648d522f475Smrg (row < screen->loc_filter_top) || 649d522f475Smrg (row > screen->loc_filter_bottom)) { 650d522f475Smrg /* Filter triggered - disable it */ 651d522f475Smrg screen->loc_filter = False; 652d522f475Smrg MotionOff(screen, xw); 653d522f475Smrg 654d522f475Smrg memset(&reply, 0, sizeof(reply)); 655d522f475Smrg reply.a_type = ANSI_CSI; 656d522f475Smrg if (oor) { 657d522f475Smrg reply.a_nparam = 1; 658d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 659d522f475Smrg } else { 660492d43a5Smrg ButtonState(state, event->state); 661d522f475Smrg 662d522f475Smrg reply.a_nparam = 4; 663d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 6642eaa94a1Schristos reply.a_param[1] = (ParmType) state; 6652eaa94a1Schristos reply.a_param[2] = (ParmType) row; 6662eaa94a1Schristos reply.a_param[3] = (ParmType) col; 667d522f475Smrg } 668d522f475Smrg 669d522f475Smrg reply.a_inters = '&'; 670d522f475Smrg reply.a_final = 'w'; 671d522f475Smrg unparseseq(xw, &reply); 672d522f475Smrg 673d522f475Smrg if (screen->locator_reset) { 674d522f475Smrg MotionOff(screen, xw); 675d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 676d522f475Smrg } 677d522f475Smrg } 678d522f475Smrg} 679d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 680d522f475Smrg 681d522f475Smrg#if OPT_READLINE 682d522f475Smrgstatic int 683492d43a5SmrgisClick1_clean(TScreen * screen, XButtonEvent * event) 684d522f475Smrg{ 685d522f475Smrg int delta; 686d522f475Smrg 687492d43a5Smrg if (!IsBtnEvent(event) 688d522f475Smrg /* Disable on Shift-Click-1, including the application-mouse modes */ 689492d43a5Smrg || (BtnModifiers(event) & ShiftMask) 690d522f475Smrg || (screen->send_mouse_pos != MOUSE_OFF) /* Kinda duplicate... */ 691d522f475Smrg ||ExtendingSelection) /* Was moved */ 692d522f475Smrg return 0; 693d522f475Smrg 694d522f475Smrg if (event->type != ButtonRelease) 695d522f475Smrg return 0; 696d522f475Smrg 697d522f475Smrg if (lastButtonDownTime == (Time) 0) { 698d522f475Smrg /* first time or once in a blue moon */ 699d522f475Smrg delta = screen->multiClickTime + 1; 700492d43a5Smrg } else if (event->time > lastButtonDownTime) { 701d522f475Smrg /* most of the time */ 702492d43a5Smrg delta = (int) (event->time - lastButtonDownTime); 703d522f475Smrg } else { 704d522f475Smrg /* time has rolled over since lastButtonUpTime */ 705492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->time); 706d522f475Smrg } 707d522f475Smrg 708d522f475Smrg return delta <= screen->multiClickTime; 709d522f475Smrg} 710d522f475Smrg 711d522f475Smrgstatic int 712492d43a5SmrgisDoubleClick3(TScreen * screen, XButtonEvent * event) 713d522f475Smrg{ 714d522f475Smrg int delta; 715d522f475Smrg 716d522f475Smrg if (event->type != ButtonRelease 717492d43a5Smrg || (BtnModifiers(event) & ShiftMask) 718492d43a5Smrg || event->button != Button3) { 719d522f475Smrg lastButton3UpTime = 0; /* Disable the cached info */ 720d522f475Smrg return 0; 721d522f475Smrg } 722d522f475Smrg /* Process Btn3Release. */ 723d522f475Smrg if (lastButton3DoubleDownTime == (Time) 0) { 724d522f475Smrg /* No previous click or once in a blue moon */ 725d522f475Smrg delta = screen->multiClickTime + 1; 726492d43a5Smrg } else if (event->time > lastButton3DoubleDownTime) { 727d522f475Smrg /* most of the time */ 728492d43a5Smrg delta = (int) (event->time - lastButton3DoubleDownTime); 729d522f475Smrg } else { 730d522f475Smrg /* time has rolled over since lastButton3DoubleDownTime */ 731492d43a5Smrg delta = (int) ((((Time) ~ 0) - lastButton3DoubleDownTime) + event->time); 732d522f475Smrg } 733d522f475Smrg if (delta <= screen->multiClickTime) { 734d522f475Smrg /* Double click */ 735d522f475Smrg CELL cell; 736d522f475Smrg 737d522f475Smrg /* Cannot check ExtendingSelection, since mouse-3 always sets it */ 738492d43a5Smrg PointToCELL(screen, event->y, event->x, &cell); 739d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 740d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the third click */ 741d522f475Smrg return 1; 742d522f475Smrg } 743d522f475Smrg } 744d522f475Smrg /* Not a double click, memorize for future check. */ 745492d43a5Smrg lastButton3UpTime = event->time; 746492d43a5Smrg PointToCELL(screen, event->y, event->x, &lastButton3); 747d522f475Smrg return 0; 748d522f475Smrg} 749d522f475Smrg 750d522f475Smrgstatic int 751d522f475SmrgCheckSecondPress3(TScreen * screen, XEvent * event) 752d522f475Smrg{ 753d522f475Smrg int delta; 754d522f475Smrg 755d522f475Smrg if (event->type != ButtonPress 756492d43a5Smrg || (KeyModifiers(event) & ShiftMask) 757d522f475Smrg || event->xbutton.button != Button3) { 758d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the cached info */ 759d522f475Smrg return 0; 760d522f475Smrg } 761d522f475Smrg /* Process Btn3Press. */ 762d522f475Smrg if (lastButton3UpTime == (Time) 0) { 763d522f475Smrg /* No previous click or once in a blue moon */ 764d522f475Smrg delta = screen->multiClickTime + 1; 765d522f475Smrg } else if (event->xbutton.time > lastButton3UpTime) { 766d522f475Smrg /* most of the time */ 7672eaa94a1Schristos delta = (int) (event->xbutton.time - lastButton3UpTime); 768d522f475Smrg } else { 769d522f475Smrg /* time has rolled over since lastButton3UpTime */ 7702eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButton3UpTime) + event->xbutton.time); 771d522f475Smrg } 772d522f475Smrg if (delta <= screen->multiClickTime) { 773d522f475Smrg CELL cell; 774d522f475Smrg 775d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 776d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 777d522f475Smrg /* A candidate for a double-click */ 778d522f475Smrg lastButton3DoubleDownTime = event->xbutton.time; 779d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &lastButton3); 780d522f475Smrg return 1; 781d522f475Smrg } 782d522f475Smrg lastButton3UpTime = 0; /* Disable the info about the previous click */ 783d522f475Smrg } 784d522f475Smrg /* Either too long, or moved, disable. */ 785d522f475Smrg lastButton3DoubleDownTime = 0; 786d522f475Smrg return 0; 787d522f475Smrg} 788d522f475Smrg 789d522f475Smrgstatic int 790d522f475SmrgrowOnCurrentLine(TScreen * screen, 791d522f475Smrg int line, 792d522f475Smrg int *deltap) /* must be XButtonEvent */ 793d522f475Smrg{ 794956cc18dSsnj int result = 1; 795d522f475Smrg int l1, l2; 796d522f475Smrg 797d522f475Smrg *deltap = 0; 798956cc18dSsnj if (line != screen->cur_row) { 799956cc18dSsnj if (line < screen->cur_row) 800956cc18dSsnj l1 = line, l2 = screen->cur_row; 801956cc18dSsnj else 802956cc18dSsnj l2 = line, l1 = screen->cur_row; 803956cc18dSsnj l1--; 804956cc18dSsnj while (++l1 < l2) { 805956cc18dSsnj LineData *ld = GET_LINEDATA(screen, l1); 806956cc18dSsnj if (!LineTstWrapped(ld)) { 807956cc18dSsnj result = 0; 808956cc18dSsnj break; 809956cc18dSsnj } 810956cc18dSsnj } 811956cc18dSsnj if (result) { 812956cc18dSsnj /* Everything is on one "wrapped line" now */ 813956cc18dSsnj *deltap = line - screen->cur_row; 814956cc18dSsnj } 815956cc18dSsnj } 816956cc18dSsnj return result; 817d522f475Smrg} 818d522f475Smrg 819d522f475Smrgstatic int 820d522f475SmrgeventRow(TScreen * screen, XEvent * event) /* must be XButtonEvent */ 821d522f475Smrg{ 822d522f475Smrg return (event->xbutton.y - screen->border) / FontHeight(screen); 823d522f475Smrg} 824d522f475Smrg 825d522f475Smrgstatic int 826d522f475SmrgeventColBetween(TScreen * screen, XEvent * event) /* must be XButtonEvent */ 827d522f475Smrg{ 828d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 829d522f475Smrg return ((event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) / 2) 830d522f475Smrg / FontWidth(screen)); 831d522f475Smrg} 832d522f475Smrg 833d522f475Smrgstatic int 834d522f475SmrgReadLineMovePoint(TScreen * screen, int col, int ldelta) 835d522f475Smrg{ 836d522f475Smrg Char line[6]; 837d522f475Smrg unsigned count = 0; 838d522f475Smrg 839d522f475Smrg col += ldelta * MaxCols(screen) - screen->cur_col; 840d522f475Smrg if (col == 0) 841d522f475Smrg return 0; 842d522f475Smrg if (screen->control_eight_bits) { 843d522f475Smrg line[count++] = ANSI_CSI; 844d522f475Smrg } else { 845d522f475Smrg line[count++] = ANSI_ESC; 846d522f475Smrg line[count++] = '['; /* XXX maybe sometimes O is better? */ 847d522f475Smrg } 84820d2c4d2Smrg line[count] = CharOf(col > 0 ? 'C' : 'D'); 849d522f475Smrg if (col < 0) 850d522f475Smrg col = -col; 851d522f475Smrg while (col--) 852d522f475Smrg v_write(screen->respond, line, 3); 853d522f475Smrg return 1; 854d522f475Smrg} 855d522f475Smrg 856d522f475Smrgstatic int 857d522f475SmrgReadLineDelete(TScreen * screen, CELL * cell1, CELL * cell2) 858d522f475Smrg{ 859d522f475Smrg int del; 860d522f475Smrg 861d522f475Smrg del = (cell2->col - cell1->col) + ((cell2->row - cell1->row) * MaxCols(screen)); 862d522f475Smrg if (del <= 0) /* Just in case... */ 863d522f475Smrg return 0; 864d522f475Smrg while (del--) 865492d43a5Smrg v_write(screen->respond, (const Char *) "\177", 1); 866d522f475Smrg return 1; 867d522f475Smrg} 868492d43a5Smrg 869492d43a5Smrgstatic void 870492d43a5SmrgreadlineExtend(TScreen * screen, XEvent * event) 871492d43a5Smrg{ 872492d43a5Smrg int ldelta1, ldelta2; 873492d43a5Smrg 874492d43a5Smrg if (IsBtnEvent(event)) { 875492d43a5Smrg XButtonEvent *my_event = (XButtonEvent *) event; 876492d43a5Smrg if (isClick1_clean(screen, my_event) 877492d43a5Smrg && SCREEN_FLAG(screen, click1_moves) 878492d43a5Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta1)) { 879492d43a5Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta1); 880492d43a5Smrg } 881492d43a5Smrg if (isDoubleClick3(screen, my_event) 882492d43a5Smrg && SCREEN_FLAG(screen, dclick3_deletes) 883492d43a5Smrg && rowOnCurrentLine(screen, screen->startSel.row, &ldelta1) 884492d43a5Smrg && rowOnCurrentLine(screen, screen->endSel.row, &ldelta2)) { 885492d43a5Smrg ReadLineMovePoint(screen, screen->endSel.col, ldelta2); 886492d43a5Smrg ReadLineDelete(screen, &screen->startSel, &(screen->endSel)); 887492d43a5Smrg } 888492d43a5Smrg } 889492d43a5Smrg} 890492d43a5Smrg 891d522f475Smrg#endif /* OPT_READLINE */ 892d522f475Smrg 893d522f475Smrg/* ^XM-G<line+' '><col+' '> */ 894d522f475Smrgvoid 895d522f475SmrgDiredButton(Widget w, 896d522f475Smrg XEvent * event, /* must be XButtonEvent */ 897d522f475Smrg String * params GCC_UNUSED, /* selections */ 898d522f475Smrg Cardinal *num_params GCC_UNUSED) 899d522f475Smrg{ 900956cc18dSsnj XtermWidget xw; 901956cc18dSsnj 902956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 903956cc18dSsnj TScreen *screen = TScreenOf(xw); 904d522f475Smrg Char Line[6]; 905d522f475Smrg unsigned line, col; 906d522f475Smrg 907492d43a5Smrg if (IsBtnEvent(event) 9082eaa94a1Schristos && (event->xbutton.y >= screen->border) 9092eaa94a1Schristos && (event->xbutton.x >= OriginX(screen))) { 91020d2c4d2Smrg line = (unsigned) ((event->xbutton.y - screen->border) 91120d2c4d2Smrg / FontHeight(screen)); 91220d2c4d2Smrg col = (unsigned) ((event->xbutton.x - OriginX(screen)) 91320d2c4d2Smrg / FontWidth(screen)); 914d522f475Smrg Line[0] = CONTROL('X'); 915d522f475Smrg Line[1] = ANSI_ESC; 916d522f475Smrg Line[2] = 'G'; 9172eaa94a1Schristos Line[3] = CharOf(' ' + col); 9182eaa94a1Schristos Line[4] = CharOf(' ' + line); 919d522f475Smrg v_write(screen->respond, Line, 5); 920d522f475Smrg } 921d522f475Smrg } 922d522f475Smrg} 923d522f475Smrg 924d522f475Smrg#if OPT_READLINE 925d522f475Smrgvoid 926d522f475SmrgReadLineButton(Widget w, 927d522f475Smrg XEvent * event, /* must be XButtonEvent */ 928d522f475Smrg String * params GCC_UNUSED, /* selections */ 929d522f475Smrg Cardinal *num_params GCC_UNUSED) 930d522f475Smrg{ 931956cc18dSsnj XtermWidget xw; 932956cc18dSsnj 933956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 934956cc18dSsnj TScreen *screen = TScreenOf(xw); 935d522f475Smrg Char Line[6]; 936d522f475Smrg int line, col, ldelta = 0; 937d522f475Smrg 938492d43a5Smrg if (!IsBtnEvent(event) 939d522f475Smrg || (screen->send_mouse_pos != MOUSE_OFF) || ExtendingSelection) 940d522f475Smrg goto finish; 941d522f475Smrg if (event->type == ButtonRelease) { 942d522f475Smrg int delta; 943d522f475Smrg 944d522f475Smrg if (lastButtonDownTime == (Time) 0) { 945d522f475Smrg /* first time and once in a blue moon */ 946d522f475Smrg delta = screen->multiClickTime + 1; 947d522f475Smrg } else if (event->xbutton.time > lastButtonDownTime) { 948d522f475Smrg /* most of the time */ 9492eaa94a1Schristos delta = (int) (event->xbutton.time - lastButtonDownTime); 950d522f475Smrg } else { 951d522f475Smrg /* time has rolled over since lastButtonUpTime */ 9522eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time); 953d522f475Smrg } 954d522f475Smrg if (delta > screen->multiClickTime) 955d522f475Smrg goto finish; /* All this work for this... */ 956d522f475Smrg } 957d522f475Smrg line = (event->xbutton.y - screen->border) / FontHeight(screen); 958956cc18dSsnj if (!rowOnCurrentLine(screen, line, &ldelta)) 959956cc18dSsnj goto finish; 960d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 961d522f475Smrg col = (event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) 962d522f475Smrg / 2) 963d522f475Smrg / FontWidth(screen) - screen->cur_col + ldelta * MaxCols(screen); 964d522f475Smrg if (col == 0) 965d522f475Smrg goto finish; 966d522f475Smrg Line[0] = ANSI_ESC; 967d522f475Smrg /* XXX: sometimes it is better to send '['? */ 968d522f475Smrg Line[1] = 'O'; 9692eaa94a1Schristos Line[2] = CharOf(col > 0 ? 'C' : 'D'); 970d522f475Smrg if (col < 0) 971d522f475Smrg col = -col; 972d522f475Smrg while (col--) 973d522f475Smrg v_write(screen->respond, Line, 3); 974d522f475Smrg finish: 975d522f475Smrg if (event->type == ButtonRelease) 976d522f475Smrg do_select_end(xw, event, params, num_params, False); 977d522f475Smrg } 978d522f475Smrg} 979d522f475Smrg#endif /* OPT_READLINE */ 980d522f475Smrg 981d522f475Smrg/* repeats <ESC>n or <ESC>p */ 982d522f475Smrgvoid 983d522f475SmrgViButton(Widget w, 984d522f475Smrg XEvent * event, /* must be XButtonEvent */ 985d522f475Smrg String * params GCC_UNUSED, /* selections */ 986d522f475Smrg Cardinal *num_params GCC_UNUSED) 987d522f475Smrg{ 988956cc18dSsnj XtermWidget xw; 989956cc18dSsnj 990956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 991956cc18dSsnj TScreen *screen = TScreenOf(xw); 992d522f475Smrg int pty = screen->respond; 993d522f475Smrg Char Line[6]; 994d522f475Smrg int line; 995d522f475Smrg 996492d43a5Smrg if (IsBtnEvent(event)) { 997d522f475Smrg 998d522f475Smrg line = screen->cur_row - 999d522f475Smrg ((event->xbutton.y - screen->border) / FontHeight(screen)); 1000d522f475Smrg if (line != 0) { 1001d522f475Smrg Line[0] = ANSI_ESC; /* force an exit from insert-mode */ 1002d522f475Smrg v_write(pty, Line, 1); 1003d522f475Smrg 1004d522f475Smrg if (line < 0) { 1005d522f475Smrg line = -line; 1006d522f475Smrg Line[0] = CONTROL('n'); 1007d522f475Smrg } else { 1008d522f475Smrg Line[0] = CONTROL('p'); 1009d522f475Smrg } 1010d522f475Smrg while (--line >= 0) 1011d522f475Smrg v_write(pty, Line, 1); 1012d522f475Smrg } 1013d522f475Smrg } 1014d522f475Smrg } 1015d522f475Smrg} 1016d522f475Smrg 1017d522f475Smrg/* 1018d522f475Smrg * This function handles button-motion events 1019d522f475Smrg */ 1020d522f475Smrg/*ARGSUSED*/ 1021d522f475Smrgvoid 1022d522f475SmrgHandleSelectExtend(Widget w, 1023d522f475Smrg XEvent * event, /* must be XMotionEvent */ 1024d522f475Smrg String * params GCC_UNUSED, 1025d522f475Smrg Cardinal *num_params GCC_UNUSED) 1026d522f475Smrg{ 1027956cc18dSsnj XtermWidget xw; 1028956cc18dSsnj 1029956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1030956cc18dSsnj TScreen *screen = TScreenOf(xw); 1031d522f475Smrg CELL cell; 1032d522f475Smrg 1033d522f475Smrg screen->selection_time = event->xmotion.time; 1034d522f475Smrg switch (screen->eventMode) { 1035d522f475Smrg /* If not in one of the DEC mouse-reporting modes */ 1036d522f475Smrg case LEFTEXTENSION: 1037d522f475Smrg case RIGHTEXTENSION: 1038d522f475Smrg PointToCELL(screen, event->xmotion.y, event->xmotion.x, &cell); 1039d522f475Smrg ExtendExtend(xw, &cell); 1040d522f475Smrg break; 1041d522f475Smrg 1042d522f475Smrg /* If in motion reporting mode, send mouse position to 1043d522f475Smrg character process as a key sequence \E[M... */ 1044d522f475Smrg case NORMAL: 1045d522f475Smrg /* will get here if send_mouse_pos != MOUSE_OFF */ 1046d522f475Smrg if (screen->send_mouse_pos == BTN_EVENT_MOUSE 1047d522f475Smrg || screen->send_mouse_pos == ANY_EVENT_MOUSE) { 1048d522f475Smrg (void) SendMousePosition(xw, event); 1049d522f475Smrg } 1050d522f475Smrg break; 1051d522f475Smrg } 1052d522f475Smrg } 1053d522f475Smrg} 1054d522f475Smrg 1055d522f475Smrgvoid 1056d522f475SmrgHandleKeyboardSelectExtend(Widget w, 1057d522f475Smrg XEvent * event GCC_UNUSED, /* must be XButtonEvent */ 1058d522f475Smrg String * params GCC_UNUSED, 1059d522f475Smrg Cardinal *num_params GCC_UNUSED) 1060d522f475Smrg{ 1061956cc18dSsnj XtermWidget xw; 1062956cc18dSsnj 1063956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1064956cc18dSsnj TScreen *screen = TScreenOf(xw); 1065d522f475Smrg ExtendExtend(xw, &screen->cursorp); 1066d522f475Smrg } 1067d522f475Smrg} 1068d522f475Smrg 1069d522f475Smrgstatic void 1070d522f475Smrgdo_select_end(XtermWidget xw, 1071d522f475Smrg XEvent * event, /* must be XButtonEvent */ 1072d522f475Smrg String * params, /* selections */ 1073d522f475Smrg Cardinal *num_params, 1074d522f475Smrg Bool use_cursor_loc) 1075d522f475Smrg{ 1076956cc18dSsnj TScreen *screen = TScreenOf(xw); 1077d522f475Smrg 1078d522f475Smrg screen->selection_time = event->xbutton.time; 1079d522f475Smrg switch (screen->eventMode) { 1080d522f475Smrg case NORMAL: 1081d522f475Smrg (void) SendMousePosition(xw, event); 1082d522f475Smrg break; 1083d522f475Smrg case LEFTEXTENSION: 1084d522f475Smrg case RIGHTEXTENSION: 1085d522f475Smrg EndExtend(xw, event, params, *num_params, use_cursor_loc); 1086d522f475Smrg#if OPT_READLINE 1087492d43a5Smrg readlineExtend(screen, event); 1088d522f475Smrg#endif /* OPT_READLINE */ 1089d522f475Smrg break; 1090d522f475Smrg } 1091d522f475Smrg} 1092d522f475Smrg 1093d522f475Smrgvoid 1094d522f475SmrgHandleSelectEnd(Widget w, 1095d522f475Smrg XEvent * event, /* must be XButtonEvent */ 1096d522f475Smrg String * params, /* selections */ 1097d522f475Smrg Cardinal *num_params) 1098d522f475Smrg{ 1099956cc18dSsnj XtermWidget xw; 1100956cc18dSsnj 1101956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1102956cc18dSsnj do_select_end(xw, event, params, num_params, False); 1103956cc18dSsnj } 1104d522f475Smrg} 1105d522f475Smrg 1106d522f475Smrgvoid 1107d522f475SmrgHandleKeyboardSelectEnd(Widget w, 1108d522f475Smrg XEvent * event, /* must be XButtonEvent */ 1109d522f475Smrg String * params, /* selections */ 1110d522f475Smrg Cardinal *num_params) 1111d522f475Smrg{ 1112956cc18dSsnj XtermWidget xw; 1113956cc18dSsnj 1114956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1115956cc18dSsnj do_select_end(xw, event, params, num_params, True); 1116956cc18dSsnj } 1117d522f475Smrg} 1118d522f475Smrg 1119492d43a5Smrg/* 11206879286fSmrg * Copy the selection data to the given target(s). 1121492d43a5Smrg */ 1122492d43a5Smrgvoid 11236879286fSmrgHandleCopySelection(Widget w, 11246879286fSmrg XEvent * event, 11256879286fSmrg String * params, /* list of targets */ 11266879286fSmrg Cardinal *num_params) 1127492d43a5Smrg{ 1128492d43a5Smrg XtermWidget xw; 1129492d43a5Smrg 1130492d43a5Smrg if ((xw = getXtermWidget(w)) != 0) { 11316879286fSmrg SelectSet(xw, event, params, *num_params); 1132492d43a5Smrg } 1133492d43a5Smrg} 1134492d43a5Smrg 1135d522f475Smrgstruct _SelectionList { 1136d522f475Smrg String *params; 1137d522f475Smrg Cardinal count; 1138d522f475Smrg Atom *targets; 1139d522f475Smrg Time time; 1140d522f475Smrg}; 1141d522f475Smrg 1142d522f475Smrgstatic unsigned 1143d522f475SmrgDECtoASCII(unsigned ch) 1144d522f475Smrg{ 1145d522f475Smrg if (xtermIsDecGraphic(ch)) { 11462eaa94a1Schristos ch = CharOf("###########+++++##-##++++|######"[ch]); 11472eaa94a1Schristos /* 01234567890123456789012345678901 */ 1148d522f475Smrg } 1149d522f475Smrg return ch; 1150d522f475Smrg} 115120d2c4d2Smrg 115220d2c4d2Smrg#if OPT_WIDE_CHARS 115320d2c4d2Smrgstatic Cardinal 115420d2c4d2SmrgaddXtermChar(Char ** buffer, Cardinal *used, Cardinal offset, unsigned value) 115520d2c4d2Smrg{ 115620d2c4d2Smrg if (offset + 1 >= *used) { 115720d2c4d2Smrg *used = 1 + (2 * (offset + 1)); 115820d2c4d2Smrg allocXtermChars(buffer, *used); 115920d2c4d2Smrg } 116020d2c4d2Smrg (*buffer)[offset++] = (Char) value; 116120d2c4d2Smrg return offset; 116220d2c4d2Smrg} 116320d2c4d2Smrg#define AddChar(buffer, used, offset, value) \ 116420d2c4d2Smrg offset = addXtermChar(buffer, used, offset, (unsigned) value) 116520d2c4d2Smrg 1166d522f475Smrg/* 1167d522f475Smrg * Convert a UTF-8 string to Latin-1, replacing non Latin-1 characters by `#', 1168d522f475Smrg * or ASCII/Latin-1 equivalents for special cases. 1169d522f475Smrg */ 1170d522f475Smrgstatic Char * 117120d2c4d2SmrgUTF8toLatin1(TScreen * screen, Char * s, unsigned long len, unsigned long *result) 1172d522f475Smrg{ 1173d522f475Smrg static Char *buffer; 1174956cc18dSsnj static Cardinal used; 1175d522f475Smrg 117620d2c4d2Smrg Cardinal offset = 0; 1177d522f475Smrg 1178492d43a5Smrg const Char *p; 1179d522f475Smrg 118020d2c4d2Smrg if (len != 0) { 1181d522f475Smrg PtyData data; 1182d522f475Smrg 1183d522f475Smrg fakePtyData(&data, s, s + len); 1184d522f475Smrg while (decodeUtf8(&data)) { 1185956cc18dSsnj Bool fails = False; 1186956cc18dSsnj Bool extra = False; 1187d522f475Smrg IChar value = skipPtyData(&data); 1188d522f475Smrg if (value == UCS_REPL) { 1189956cc18dSsnj fails = True; 1190d522f475Smrg } else if (value < 256) { 119120d2c4d2Smrg AddChar(&buffer, &used, offset, CharOf(value)); 1192d522f475Smrg } else { 1193d522f475Smrg unsigned eqv = ucs2dec(value); 1194d522f475Smrg if (xtermIsDecGraphic(eqv)) { 119520d2c4d2Smrg AddChar(&buffer, &used, offset, DECtoASCII(eqv)); 1196d522f475Smrg } else { 1197d522f475Smrg eqv = AsciiEquivs(value); 1198956cc18dSsnj if (eqv == value) { 1199956cc18dSsnj fails = True; 1200956cc18dSsnj } else { 120120d2c4d2Smrg AddChar(&buffer, &used, offset, eqv); 1202956cc18dSsnj } 1203956cc18dSsnj if (isWide((wchar_t) value)) 1204956cc18dSsnj extra = True; 1205956cc18dSsnj } 1206956cc18dSsnj } 1207956cc18dSsnj 1208956cc18dSsnj /* 1209956cc18dSsnj * If we're not able to plug in a single-byte result, insert the 1210956cc18dSsnj * defaultString (which normally is a single "#", but could be 1211956cc18dSsnj * whatever the user wants). 1212956cc18dSsnj */ 1213956cc18dSsnj if (fails) { 1214492d43a5Smrg for (p = (const Char *) screen->default_string; *p != '\0'; ++p) { 121520d2c4d2Smrg AddChar(&buffer, &used, offset, *p); 1216d522f475Smrg } 1217d522f475Smrg } 1218956cc18dSsnj if (extra) 121920d2c4d2Smrg AddChar(&buffer, &used, offset, ' '); 1220d522f475Smrg } 122120d2c4d2Smrg AddChar(&buffer, &used, offset, '\0'); 122220d2c4d2Smrg *result = (unsigned long) (offset - 1); 1223d522f475Smrg } else { 1224d522f475Smrg *result = 0; 1225d522f475Smrg } 1226d522f475Smrg return buffer; 1227d522f475Smrg} 122820d2c4d2Smrg 122920d2c4d2Smrgint 123020d2c4d2SmrgxtermUtf8ToTextList(XtermWidget xw, 123120d2c4d2Smrg XTextProperty * text_prop, 123220d2c4d2Smrg char ***text_list, 123320d2c4d2Smrg int *text_list_count) 123420d2c4d2Smrg{ 123520d2c4d2Smrg TScreen *screen = TScreenOf(xw); 123620d2c4d2Smrg Display *dpy = screen->display; 123720d2c4d2Smrg int rc = -1; 123820d2c4d2Smrg 123920d2c4d2Smrg if (text_prop->format == 8 124020d2c4d2Smrg && (rc = Xutf8TextPropertyToTextList(dpy, text_prop, 124120d2c4d2Smrg text_list, 124220d2c4d2Smrg text_list_count)) >= 0) { 124320d2c4d2Smrg if (*text_list != NULL && *text_list_count != 0) { 124420d2c4d2Smrg int i; 124520d2c4d2Smrg Char *data; 124620d2c4d2Smrg char **new_text_list, *tmp; 124720d2c4d2Smrg unsigned long size, new_size; 124820d2c4d2Smrg 124920d2c4d2Smrg TRACE(("xtermUtf8ToTextList size %d\n", *text_list_count)); 125020d2c4d2Smrg 125120d2c4d2Smrg /* 125220d2c4d2Smrg * XLib StringList actually uses only two pointers, one for the 125320d2c4d2Smrg * list itself, and one for the data. Pointer to the data is the 125420d2c4d2Smrg * first element of the list, the rest (if any) list elements point 125520d2c4d2Smrg * to the same memory block as the first element 125620d2c4d2Smrg */ 125720d2c4d2Smrg new_size = 0; 125820d2c4d2Smrg for (i = 0; i < *text_list_count; ++i) { 125920d2c4d2Smrg data = (Char *) (*text_list)[i]; 126020d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 126120d2c4d2Smrg (void) UTF8toLatin1(screen, data, size, &size); 126220d2c4d2Smrg new_size += size + 1; 126320d2c4d2Smrg } 1264a1f3da82Smrg new_text_list = TypeXtMallocN(char *, *text_list_count); 126520d2c4d2Smrg new_text_list[0] = tmp = XtMalloc((Cardinal) new_size); 126620d2c4d2Smrg for (i = 0; i < (*text_list_count); ++i) { 126720d2c4d2Smrg data = (Char *) (*text_list)[i]; 126820d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 126920d2c4d2Smrg data = UTF8toLatin1(screen, data, size, &size); 127020d2c4d2Smrg memcpy(tmp, data, size + 1); 127120d2c4d2Smrg new_text_list[i] = tmp; 127220d2c4d2Smrg tmp += size + 1; 127320d2c4d2Smrg } 127420d2c4d2Smrg XFreeStringList((*text_list)); 127520d2c4d2Smrg *text_list = new_text_list; 127620d2c4d2Smrg } else { 127720d2c4d2Smrg rc = -1; 127820d2c4d2Smrg } 127920d2c4d2Smrg } 128020d2c4d2Smrg return rc; 128120d2c4d2Smrg} 1282d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1283d522f475Smrg 1284956cc18dSsnjstatic char * 1285956cc18dSsnjparseItem(char *value, char *nextc) 1286d522f475Smrg{ 1287956cc18dSsnj char *nextp = value; 1288956cc18dSsnj while (*nextp != '\0' && *nextp != ',') { 1289956cc18dSsnj *nextp = x_toupper(*nextp); 1290956cc18dSsnj ++nextp; 1291956cc18dSsnj } 1292956cc18dSsnj *nextc = *nextp; 1293956cc18dSsnj *nextp = '\0'; 1294956cc18dSsnj x_strtrim(value); 1295d522f475Smrg 1296956cc18dSsnj return nextp; 1297956cc18dSsnj} 1298d522f475Smrg 1299956cc18dSsnj/* 1300956cc18dSsnj * All of the wanted strings are unique in the first character, so we can 1301956cc18dSsnj * use simple abbreviations. 1302956cc18dSsnj */ 1303956cc18dSsnjstatic Bool 1304956cc18dSsnjsameItem(const char *actual, const char *wanted) 1305956cc18dSsnj{ 1306956cc18dSsnj Bool result = False; 1307956cc18dSsnj size_t have = strlen(actual); 1308956cc18dSsnj size_t need = strlen(wanted); 1309d522f475Smrg 1310956cc18dSsnj if (have != 0 && have <= need) { 1311956cc18dSsnj if (!strncmp(actual, wanted, have)) { 1312956cc18dSsnj TRACE(("...matched \"%s\"\n", wanted)); 1313956cc18dSsnj result = True; 1314956cc18dSsnj } 1315956cc18dSsnj } 1316956cc18dSsnj 1317956cc18dSsnj return result; 1318956cc18dSsnj} 1319956cc18dSsnj 1320956cc18dSsnj/* 1321956cc18dSsnj * Handle the eightBitSelectTypes or utf8SelectTypes resource values. 1322956cc18dSsnj */ 1323956cc18dSsnjstatic Bool 1324956cc18dSsnjoverrideTargets(Widget w, String value, Atom ** resultp) 1325956cc18dSsnj{ 1326956cc18dSsnj Bool override = False; 1327956cc18dSsnj XtermWidget xw; 1328956cc18dSsnj 1329956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1330956cc18dSsnj TScreen *screen = TScreenOf(xw); 1331956cc18dSsnj 133220d2c4d2Smrg if (!IsEmpty(value)) { 1333492d43a5Smrg char *copied = x_strdup(value); 1334956cc18dSsnj if (copied != 0) { 1335956cc18dSsnj Atom *result = 0; 1336956cc18dSsnj Cardinal count = 1; 1337956cc18dSsnj int n; 1338d522f475Smrg 1339956cc18dSsnj TRACE(("decoding SelectTypes \"%s\"\n", value)); 1340956cc18dSsnj for (n = 0; copied[n] != '\0'; ++n) { 1341956cc18dSsnj if (copied[n] == ',') 1342956cc18dSsnj ++count; 1343956cc18dSsnj } 1344a1f3da82Smrg result = TypeXtMallocN(Atom, (2 * count) + 1); 1345956cc18dSsnj if (result == NULL) { 1346956cc18dSsnj TRACE(("Couldn't allocate selection types\n")); 1347956cc18dSsnj } else { 1348956cc18dSsnj char nextc = '?'; 134920d2c4d2Smrg char *listp = (char *) copied; 1350956cc18dSsnj count = 0; 1351956cc18dSsnj do { 1352956cc18dSsnj char *nextp = parseItem(listp, &nextc); 1353956cc18dSsnj size_t len = strlen(listp); 1354956cc18dSsnj 1355956cc18dSsnj if (len == 0) { 1356a1f3da82Smrg /* EMPTY */ ; 1357956cc18dSsnj } 1358956cc18dSsnj#if OPT_WIDE_CHARS 1359956cc18dSsnj else if (sameItem(listp, "UTF8")) { 1360956cc18dSsnj result[count++] = XA_UTF8_STRING(XtDisplay(w)); 1361956cc18dSsnj } 1362956cc18dSsnj#endif 1363956cc18dSsnj else if (sameItem(listp, "I18N")) { 1364956cc18dSsnj if (screen->i18nSelections) { 1365956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 1366956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1367956cc18dSsnj } 1368956cc18dSsnj } else if (sameItem(listp, "TEXT")) { 1369956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 1370956cc18dSsnj } else if (sameItem(listp, "COMPOUND_TEXT")) { 1371956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1372956cc18dSsnj } else if (sameItem(listp, "STRING")) { 1373956cc18dSsnj result[count++] = XA_STRING; 1374956cc18dSsnj } 1375956cc18dSsnj *nextp++ = nextc; 1376956cc18dSsnj listp = nextp; 1377956cc18dSsnj } while (nextc != '\0'); 1378956cc18dSsnj if (count) { 1379956cc18dSsnj result[count] = None; 1380956cc18dSsnj override = True; 1381956cc18dSsnj *resultp = result; 1382956cc18dSsnj } else { 1383956cc18dSsnj XtFree((char *) result); 1384956cc18dSsnj } 1385956cc18dSsnj } 1386956cc18dSsnj } else { 1387956cc18dSsnj TRACE(("Couldn't allocate copy of selection types\n")); 1388d522f475Smrg } 1389956cc18dSsnj } 1390956cc18dSsnj } 1391956cc18dSsnj return override; 1392956cc18dSsnj} 1393956cc18dSsnj 1394956cc18dSsnj#if OPT_WIDE_CHARS 1395956cc18dSsnjstatic Atom * 1396956cc18dSsnjallocUtf8Targets(Widget w, TScreen * screen) 1397956cc18dSsnj{ 1398956cc18dSsnj Atom **resultp = &(screen->selection_targets_utf8); 1399956cc18dSsnj 1400956cc18dSsnj if (*resultp == 0) { 1401956cc18dSsnj Atom *result; 1402956cc18dSsnj 1403956cc18dSsnj if (!overrideTargets(w, screen->utf8_select_types, &result)) { 1404a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1405956cc18dSsnj if (result == NULL) { 1406956cc18dSsnj TRACE(("Couldn't allocate utf-8 selection targets\n")); 1407956cc18dSsnj } else { 1408956cc18dSsnj int n = 0; 1409956cc18dSsnj 1410956cc18dSsnj result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1411d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1412956cc18dSsnj if (screen->i18nSelections) { 1413956cc18dSsnj result[n++] = XA_TEXT(XtDisplay(w)); 1414956cc18dSsnj result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1415956cc18dSsnj } 1416d522f475Smrg#endif 1417956cc18dSsnj result[n++] = XA_STRING; 1418956cc18dSsnj result[n] = None; 1419956cc18dSsnj } 1420d522f475Smrg } 1421956cc18dSsnj 1422956cc18dSsnj *resultp = result; 1423d522f475Smrg } 1424956cc18dSsnj 1425956cc18dSsnj return *resultp; 1426956cc18dSsnj} 1427d522f475Smrg#endif 1428d522f475Smrg 1429956cc18dSsnjstatic Atom * 1430956cc18dSsnjalloc8bitTargets(Widget w, TScreen * screen) 1431956cc18dSsnj{ 1432956cc18dSsnj Atom **resultp = &(screen->selection_targets_8bit); 1433956cc18dSsnj 1434956cc18dSsnj if (*resultp == 0) { 1435956cc18dSsnj Atom *result = 0; 1436956cc18dSsnj 1437956cc18dSsnj if (!overrideTargets(w, screen->eightbit_select_types, &result)) { 1438a1f3da82Smrg result = TypeXtMallocN(Atom, 5); 1439956cc18dSsnj if (result == NULL) { 1440956cc18dSsnj TRACE(("Couldn't allocate 8bit selection targets\n")); 1441956cc18dSsnj } else { 1442956cc18dSsnj int n = 0; 1443956cc18dSsnj 1444d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1445956cc18dSsnj result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1446956cc18dSsnj#endif 1447956cc18dSsnj if (screen->i18nSelections) { 1448956cc18dSsnj result[n++] = XA_TEXT(XtDisplay(w)); 1449956cc18dSsnj result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1450956cc18dSsnj } 1451956cc18dSsnj result[n++] = XA_STRING; 1452956cc18dSsnj result[n] = None; 1453956cc18dSsnj } 1454956cc18dSsnj } 1455956cc18dSsnj 1456956cc18dSsnj *resultp = result; 1457956cc18dSsnj } 1458956cc18dSsnj 1459956cc18dSsnj return *resultp; 1460956cc18dSsnj} 1461956cc18dSsnj 1462956cc18dSsnjstatic Atom * 1463956cc18dSsnj_SelectionTargets(Widget w) 1464956cc18dSsnj{ 1465956cc18dSsnj Atom *result; 1466956cc18dSsnj TScreen *screen; 1467956cc18dSsnj XtermWidget xw; 1468956cc18dSsnj 1469956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) { 1470956cc18dSsnj result = NULL; 1471956cc18dSsnj } else { 1472956cc18dSsnj screen = TScreenOf(xw); 1473956cc18dSsnj 1474956cc18dSsnj#if OPT_WIDE_CHARS 1475956cc18dSsnj if (screen->wide_chars) { 1476956cc18dSsnj result = allocUtf8Targets(w, screen); 1477956cc18dSsnj } else 1478d522f475Smrg#endif 1479956cc18dSsnj { 1480956cc18dSsnj /* not screen->wide_chars */ 1481956cc18dSsnj result = alloc8bitTargets(w, screen); 1482d522f475Smrg } 1483d522f475Smrg } 1484956cc18dSsnj 1485956cc18dSsnj return result; 1486d522f475Smrg} 1487d522f475Smrg 1488d522f475Smrg#define isSELECT(value) (!strcmp(value, "SELECT")) 1489d522f475Smrg 1490d522f475Smrgstatic void 1491d522f475SmrgUnmapSelections(XtermWidget xw) 1492d522f475Smrg{ 1493956cc18dSsnj TScreen *screen = TScreenOf(xw); 1494d522f475Smrg Cardinal n; 1495d522f475Smrg 1496d522f475Smrg if (screen->mappedSelect) { 1497d522f475Smrg for (n = 0; screen->mappedSelect[n] != 0; ++n) 149820d2c4d2Smrg free((void *) screen->mappedSelect[n]); 1499d522f475Smrg free(screen->mappedSelect); 1500d522f475Smrg screen->mappedSelect = 0; 1501d522f475Smrg } 1502d522f475Smrg} 1503d522f475Smrg 1504d522f475Smrg/* 1505d522f475Smrg * xterm generally uses the primary selection. Some applications prefer 1506d522f475Smrg * (or are limited to) the clipboard. Since the translations resource is 1507d522f475Smrg * complicated, users seldom change the way it affects selection. But it 1508d522f475Smrg * is simple to remap the choice between primary and clipboard before the 1509d522f475Smrg * call to XmuInternStrings(). 1510d522f475Smrg */ 1511d522f475Smrgstatic String * 1512d522f475SmrgMapSelections(XtermWidget xw, String * params, Cardinal num_params) 1513d522f475Smrg{ 1514d522f475Smrg String *result = params; 1515d522f475Smrg 1516d522f475Smrg if (num_params > 0) { 1517d522f475Smrg Cardinal j; 1518d522f475Smrg Boolean map = False; 1519d522f475Smrg 1520d522f475Smrg for (j = 0; j < num_params; ++j) { 1521d522f475Smrg TRACE(("param[%d]:%s\n", j, params[j])); 1522d522f475Smrg if (isSELECT(params[j])) { 1523d522f475Smrg map = True; 1524d522f475Smrg break; 1525d522f475Smrg } 1526d522f475Smrg } 1527d522f475Smrg if (map) { 1528956cc18dSsnj TScreen *screen = TScreenOf(xw); 1529956cc18dSsnj const char *mapTo = (screen->selectToClipboard 1530d522f475Smrg ? "CLIPBOARD" 1531d522f475Smrg : "PRIMARY"); 1532d522f475Smrg 1533d522f475Smrg UnmapSelections(xw); 1534d522f475Smrg if ((result = TypeMallocN(String, num_params + 1)) != 0) { 1535d522f475Smrg result[num_params] = 0; 1536d522f475Smrg for (j = 0; j < num_params; ++j) { 1537d522f475Smrg result[j] = x_strdup((isSELECT(params[j]) 1538d522f475Smrg ? mapTo 1539d522f475Smrg : params[j])); 1540d522f475Smrg if (result[j] == 0) { 1541d522f475Smrg UnmapSelections(xw); 1542d522f475Smrg result = 0; 1543d522f475Smrg break; 1544d522f475Smrg } 1545d522f475Smrg } 1546956cc18dSsnj screen->mappedSelect = result; 1547d522f475Smrg } 1548d522f475Smrg } 1549d522f475Smrg } 1550d522f475Smrg return result; 1551d522f475Smrg} 1552d522f475Smrg 1553d522f475Smrg/* 1554d522f475Smrg * Lookup the cut-buffer number, which will be in the range 0-7. 1555d522f475Smrg * If it is not a cut-buffer, it is the primary selection (-1). 1556d522f475Smrg */ 1557d522f475Smrgstatic int 155820d2c4d2SmrgCutBuffer(Atom code) 1559d522f475Smrg{ 1560d522f475Smrg int cutbuffer; 156120d2c4d2Smrg switch ((unsigned) code) { 1562d522f475Smrg case XA_CUT_BUFFER0: 1563d522f475Smrg cutbuffer = 0; 1564d522f475Smrg break; 1565d522f475Smrg case XA_CUT_BUFFER1: 1566d522f475Smrg cutbuffer = 1; 1567d522f475Smrg break; 1568d522f475Smrg case XA_CUT_BUFFER2: 1569d522f475Smrg cutbuffer = 2; 1570d522f475Smrg break; 1571d522f475Smrg case XA_CUT_BUFFER3: 1572d522f475Smrg cutbuffer = 3; 1573d522f475Smrg break; 1574d522f475Smrg case XA_CUT_BUFFER4: 1575d522f475Smrg cutbuffer = 4; 1576d522f475Smrg break; 1577d522f475Smrg case XA_CUT_BUFFER5: 1578d522f475Smrg cutbuffer = 5; 1579d522f475Smrg break; 1580d522f475Smrg case XA_CUT_BUFFER6: 1581d522f475Smrg cutbuffer = 6; 1582d522f475Smrg break; 1583d522f475Smrg case XA_CUT_BUFFER7: 1584d522f475Smrg cutbuffer = 7; 1585d522f475Smrg break; 1586d522f475Smrg default: 1587d522f475Smrg cutbuffer = -1; 1588d522f475Smrg break; 1589d522f475Smrg } 1590d522f475Smrg return cutbuffer; 1591d522f475Smrg} 1592d522f475Smrg 1593d522f475Smrg#if OPT_PASTE64 1594d522f475Smrgstatic void 1595d522f475SmrgFinishPaste64(XtermWidget xw) 1596d522f475Smrg{ 1597956cc18dSsnj TScreen *screen = TScreenOf(xw); 1598956cc18dSsnj 1599956cc18dSsnj TRACE(("FinishPaste64(%d)\n", screen->base64_paste)); 1600956cc18dSsnj if (screen->base64_paste) { 1601956cc18dSsnj screen->base64_paste = 0; 1602956cc18dSsnj unparseputc1(xw, screen->base64_final); 1603d522f475Smrg unparse_end(xw); 1604d522f475Smrg } 1605d522f475Smrg} 1606d522f475Smrg#endif 1607d522f475Smrg 1608d522f475Smrg#if !OPT_PASTE64 1609d522f475Smrgstatic 1610d522f475Smrg#endif 1611d522f475Smrgvoid 1612d522f475SmrgxtermGetSelection(Widget w, 1613d522f475Smrg Time ev_time, 1614d522f475Smrg String * params, /* selections in precedence order */ 1615d522f475Smrg Cardinal num_params, 1616d522f475Smrg Atom * targets) 1617d522f475Smrg{ 1618d522f475Smrg Atom selection; 1619d522f475Smrg int cutbuffer; 1620d522f475Smrg Atom target; 1621d522f475Smrg 1622956cc18dSsnj XtermWidget xw; 1623956cc18dSsnj 162420d2c4d2Smrg if (num_params == 0) 162520d2c4d2Smrg return; 1626956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 1627d522f475Smrg return; 1628d522f475Smrg 1629956cc18dSsnj TRACE(("xtermGetSelection num_params %d\n", num_params)); 1630956cc18dSsnj params = MapSelections(xw, params, num_params); 1631d522f475Smrg 1632d522f475Smrg XmuInternStrings(XtDisplay(w), params, (Cardinal) 1, &selection); 1633d522f475Smrg cutbuffer = CutBuffer(selection); 1634d522f475Smrg 1635956cc18dSsnj TRACE(("Cutbuffer: %d, target: %s\n", cutbuffer, 1636956cc18dSsnj (targets 1637956cc18dSsnj ? visibleSelectionTarget(XtDisplay(w), targets[0]) 1638956cc18dSsnj : "None"))); 1639d522f475Smrg 1640d522f475Smrg if (cutbuffer >= 0) { 1641d522f475Smrg int inbytes; 1642d522f475Smrg unsigned long nbytes; 1643d522f475Smrg int fmt8 = 8; 1644d522f475Smrg Atom type = XA_STRING; 1645d522f475Smrg char *line; 1646d522f475Smrg 1647d522f475Smrg /* 'line' is freed in SelectionReceived */ 1648d522f475Smrg line = XFetchBuffer(XtDisplay(w), &inbytes, cutbuffer); 1649d522f475Smrg nbytes = (unsigned long) inbytes; 1650d522f475Smrg 1651d522f475Smrg if (nbytes > 0) 1652d522f475Smrg SelectionReceived(w, NULL, &selection, &type, (XtPointer) line, 1653d522f475Smrg &nbytes, &fmt8); 1654d522f475Smrg else if (num_params > 1) { 1655d522f475Smrg xtermGetSelection(w, ev_time, params + 1, num_params - 1, NULL); 1656d522f475Smrg } 1657d522f475Smrg#if OPT_PASTE64 1658d522f475Smrg else { 1659956cc18dSsnj FinishPaste64(xw); 1660d522f475Smrg } 1661d522f475Smrg#endif 1662d522f475Smrg return; 1663d522f475Smrg } else { 1664d522f475Smrg struct _SelectionList *list; 1665d522f475Smrg 1666d522f475Smrg if (targets == NULL || targets[0] == None) { 1667d522f475Smrg targets = _SelectionTargets(w); 1668d522f475Smrg } 1669d522f475Smrg 1670d522f475Smrg if (targets != 0) { 1671d522f475Smrg target = targets[0]; 1672d522f475Smrg 1673d522f475Smrg if (targets[1] == None) { /* last target in list */ 1674d522f475Smrg params++; 1675d522f475Smrg num_params--; 1676d522f475Smrg targets = _SelectionTargets(w); 1677d522f475Smrg } else { 1678d522f475Smrg targets = &(targets[1]); 1679d522f475Smrg } 1680d522f475Smrg 1681d522f475Smrg if (num_params) { 1682d522f475Smrg /* 'list' is freed in SelectionReceived */ 1683a1f3da82Smrg list = TypeXtMalloc(struct _SelectionList); 1684d522f475Smrg if (list != 0) { 1685d522f475Smrg list->params = params; 1686d522f475Smrg list->count = num_params; 1687d522f475Smrg list->targets = targets; 1688d522f475Smrg list->time = ev_time; 1689d522f475Smrg } 1690d522f475Smrg } else { 1691d522f475Smrg list = NULL; 1692d522f475Smrg } 1693d522f475Smrg 1694d522f475Smrg XtGetSelectionValue(w, selection, 1695d522f475Smrg target, 1696d522f475Smrg SelectionReceived, 1697d522f475Smrg (XtPointer) list, ev_time); 1698d522f475Smrg } 1699d522f475Smrg } 1700d522f475Smrg} 1701d522f475Smrg 1702d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 1703d522f475Smrgstatic void 1704d522f475SmrgGettingSelection(Display * dpy, Atom type, Char * line, unsigned long len) 1705d522f475Smrg{ 1706d522f475Smrg Char *cp; 1707d522f475Smrg char *name; 1708d522f475Smrg 1709d522f475Smrg name = XGetAtomName(dpy, type); 1710d522f475Smrg 1711d522f475Smrg TRACE(("Getting %s (%ld)\n", name, (long int) type)); 1712d522f475Smrg for (cp = line; cp < line + len; cp++) { 1713956cc18dSsnj TRACE(("[%d:%lu]", (int) (cp + 1 - line), len)); 1714d522f475Smrg if (isprint(*cp)) { 1715d522f475Smrg TRACE(("%c\n", *cp)); 1716d522f475Smrg } else { 1717d522f475Smrg TRACE(("\\x%02x\n", *cp)); 1718d522f475Smrg } 1719d522f475Smrg } 1720d522f475Smrg} 1721d522f475Smrg#else 1722d522f475Smrg#define GettingSelection(dpy,type,line,len) /* nothing */ 1723d522f475Smrg#endif 1724d522f475Smrg 1725d522f475Smrg#ifdef VMS 1726d522f475Smrg# define tty_vwrite(pty,lag,l) tt_write(lag,l) 1727d522f475Smrg#else /* !( VMS ) */ 1728d522f475Smrg# define tty_vwrite(pty,lag,l) v_write(pty,lag,l) 1729d522f475Smrg#endif /* defined VMS */ 1730d522f475Smrg 1731d522f475Smrg#if OPT_PASTE64 1732d522f475Smrg/* Return base64 code character given 6-bit number */ 1733d522f475Smrgstatic const char base64_code[] = "\ 1734d522f475SmrgABCDEFGHIJKLMNOPQRSTUVWXYZ\ 1735d522f475Smrgabcdefghijklmnopqrstuvwxyz\ 1736d522f475Smrg0123456789+/"; 1737d522f475Smrgstatic void 1738d522f475Smrgbase64_flush(TScreen * screen) 1739d522f475Smrg{ 1740d522f475Smrg Char x; 1741d522f475Smrg switch (screen->base64_count) { 1742d522f475Smrg case 0: 1743d522f475Smrg break; 1744d522f475Smrg case 2: 17452eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 4]); 1746d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1747d522f475Smrg break; 1748d522f475Smrg case 4: 17492eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 2]); 1750d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1751d522f475Smrg break; 1752d522f475Smrg } 1753d522f475Smrg if (screen->base64_pad & 3) 1754d522f475Smrg tty_vwrite(screen->respond, 1755492d43a5Smrg (const Char *) "===", 1756d522f475Smrg (unsigned) (4 - (screen->base64_pad & 3))); 1757d522f475Smrg screen->base64_count = 0; 1758d522f475Smrg screen->base64_accu = 0; 1759d522f475Smrg screen->base64_pad = 0; 1760d522f475Smrg} 1761d522f475Smrg#endif /* OPT_PASTE64 */ 1762d522f475Smrg 1763d522f475Smrgstatic void 1764d522f475Smrg_qWriteSelectionData(TScreen * screen, Char * lag, unsigned length) 1765d522f475Smrg{ 1766d522f475Smrg#if OPT_PASTE64 1767d522f475Smrg if (screen->base64_paste) { 1768d522f475Smrg /* Send data as base64 */ 1769d522f475Smrg Char *p = lag; 1770d522f475Smrg Char buf[64]; 1771d522f475Smrg unsigned x = 0; 1772d522f475Smrg while (length--) { 1773d522f475Smrg switch (screen->base64_count) { 1774d522f475Smrg case 0: 17752eaa94a1Schristos buf[x++] = CharOf(base64_code[*p >> 2]); 17762eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0x3); 1777d522f475Smrg screen->base64_count = 2; 1778d522f475Smrg ++p; 1779d522f475Smrg break; 1780d522f475Smrg case 2: 17812eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 4) + 17822eaa94a1Schristos (*p >> 4)]); 17832eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0xF); 1784d522f475Smrg screen->base64_count = 4; 1785d522f475Smrg ++p; 1786d522f475Smrg break; 1787d522f475Smrg case 4: 17882eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 2) + 17892eaa94a1Schristos (*p >> 6)]); 17902eaa94a1Schristos buf[x++] = CharOf(base64_code[*p & 0x3F]); 1791d522f475Smrg screen->base64_accu = 0; 1792d522f475Smrg screen->base64_count = 0; 1793d522f475Smrg ++p; 1794d522f475Smrg break; 1795d522f475Smrg } 1796d522f475Smrg if (x >= 63) { 1797d522f475Smrg /* Write 63 or 64 characters */ 1798d522f475Smrg screen->base64_pad += x; 1799d522f475Smrg tty_vwrite(screen->respond, buf, x); 1800d522f475Smrg x = 0; 1801d522f475Smrg } 1802d522f475Smrg } 1803d522f475Smrg if (x != 0) { 1804d522f475Smrg screen->base64_pad += x; 1805d522f475Smrg tty_vwrite(screen->respond, buf, x); 1806d522f475Smrg } 1807d522f475Smrg } else 1808d522f475Smrg#endif /* OPT_PASTE64 */ 1809d522f475Smrg#if OPT_READLINE 1810d522f475Smrg if (SCREEN_FLAG(screen, paste_quotes)) { 1811d522f475Smrg while (length--) { 1812492d43a5Smrg tty_vwrite(screen->respond, (const Char *) "\026", 1); /* Control-V */ 1813d522f475Smrg tty_vwrite(screen->respond, lag++, 1); 1814d522f475Smrg } 1815d522f475Smrg } else 1816d522f475Smrg#endif 1817d522f475Smrg tty_vwrite(screen->respond, lag, length); 1818d522f475Smrg} 1819d522f475Smrg 1820d522f475Smrgstatic void 182120d2c4d2Smrg_WriteSelectionData(TScreen * screen, Char * line, size_t length) 1822d522f475Smrg{ 1823d522f475Smrg /* Write data to pty a line at a time. */ 1824d522f475Smrg /* Doing this one line at a time may no longer be necessary 1825d522f475Smrg because v_write has been re-written. */ 1826d522f475Smrg 1827d522f475Smrg Char *lag, *end; 1828d522f475Smrg 1829d522f475Smrg /* in the VMS version, if tt_pasting isn't set to True then qio 1830d522f475Smrg reads aren't blocked and an infinite loop is entered, where the 1831d522f475Smrg pasted text shows up as new input, goes in again, shows up 1832d522f475Smrg again, ad nauseum. */ 1833d522f475Smrg#ifdef VMS 1834d522f475Smrg tt_pasting = True; 1835d522f475Smrg#endif 1836d522f475Smrg 1837d522f475Smrg end = &line[length]; 1838d522f475Smrg lag = line; 1839d522f475Smrg 1840d522f475Smrg#if OPT_PASTE64 1841d522f475Smrg if (screen->base64_paste) { 1842d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (end - lag)); 1843d522f475Smrg base64_flush(screen); 1844d522f475Smrg } else 1845d522f475Smrg#endif 1846d522f475Smrg { 1847d522f475Smrg if (!SCREEN_FLAG(screen, paste_literal_nl)) { 1848d522f475Smrg Char *cp; 1849d522f475Smrg for (cp = line; cp != end; cp++) { 1850d522f475Smrg if (*cp == '\n') { 1851d522f475Smrg *cp = '\r'; 1852d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (cp - lag + 1)); 1853d522f475Smrg lag = cp + 1; 1854d522f475Smrg } 1855d522f475Smrg } 1856d522f475Smrg } 1857d522f475Smrg 1858d522f475Smrg if (lag != end) { 1859d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (end - lag)); 1860d522f475Smrg } 1861d522f475Smrg } 1862d522f475Smrg#ifdef VMS 1863d522f475Smrg tt_pasting = False; 1864d522f475Smrg tt_start_read(); /* reenable reads or a character may be lost */ 1865d522f475Smrg#endif 1866d522f475Smrg} 1867d522f475Smrg 1868d522f475Smrg#if OPT_READLINE 1869d522f475Smrgstatic void 1870492d43a5Smrg_WriteKey(TScreen * screen, const Char * in) 1871d522f475Smrg{ 1872d522f475Smrg Char line[16]; 1873d522f475Smrg unsigned count = 0; 1874492d43a5Smrg size_t length = strlen((const char *) in); 1875d522f475Smrg 1876d522f475Smrg if (screen->control_eight_bits) { 1877d522f475Smrg line[count++] = ANSI_CSI; 1878d522f475Smrg } else { 1879d522f475Smrg line[count++] = ANSI_ESC; 1880d522f475Smrg line[count++] = '['; 1881d522f475Smrg } 1882d522f475Smrg while (length--) 1883d522f475Smrg line[count++] = *in++; 1884d522f475Smrg line[count++] = '~'; 1885d522f475Smrg tty_vwrite(screen->respond, line, count); 1886d522f475Smrg} 1887d522f475Smrg#endif /* OPT_READLINE */ 1888d522f475Smrg 1889d522f475Smrg/* SelectionReceived: stuff received selection text into pty */ 1890d522f475Smrg 1891d522f475Smrg/* ARGSUSED */ 1892d522f475Smrgstatic void 1893d522f475SmrgSelectionReceived(Widget w, 1894d522f475Smrg XtPointer client_data, 1895d522f475Smrg Atom * selection GCC_UNUSED, 1896d522f475Smrg Atom * type, 1897d522f475Smrg XtPointer value, 1898d522f475Smrg unsigned long *length, 1899d522f475Smrg int *format) 1900d522f475Smrg{ 1901d522f475Smrg char **text_list = NULL; 1902d522f475Smrg int text_list_count; 1903d522f475Smrg XTextProperty text_prop; 1904d522f475Smrg TScreen *screen; 1905d522f475Smrg Display *dpy; 1906d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 1907d522f475Smrg Char *line = (Char *) value; 1908d522f475Smrg#endif 1909d522f475Smrg 1910956cc18dSsnj XtermWidget xw; 1911956cc18dSsnj 1912956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 1913d522f475Smrg return; 1914956cc18dSsnj 1915956cc18dSsnj screen = TScreenOf(xw); 1916d522f475Smrg dpy = XtDisplay(w); 1917d522f475Smrg 1918d522f475Smrg if (*type == 0 /*XT_CONVERT_FAIL */ 1919d522f475Smrg || *length == 0 1920d522f475Smrg || value == NULL) 1921d522f475Smrg goto fail; 1922d522f475Smrg 1923d522f475Smrg text_prop.value = (unsigned char *) value; 1924d522f475Smrg text_prop.encoding = *type; 1925d522f475Smrg text_prop.format = *format; 1926d522f475Smrg text_prop.nitems = *length; 1927d522f475Smrg 1928956cc18dSsnj TRACE(("SelectionReceived %s format %d, nitems %ld\n", 1929956cc18dSsnj visibleSelectionTarget(dpy, text_prop.encoding), 1930956cc18dSsnj text_prop.format, 1931956cc18dSsnj text_prop.nitems)); 1932956cc18dSsnj 1933d522f475Smrg#if OPT_WIDE_CHARS 1934d522f475Smrg if (screen->wide_chars) { 1935d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 1936d522f475Smrg *type == XA_STRING || 1937d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 1938d522f475Smrg GettingSelection(dpy, *type, line, *length); 1939d522f475Smrg if (Xutf8TextPropertyToTextList(dpy, &text_prop, 1940d522f475Smrg &text_list, 1941d522f475Smrg &text_list_count) < 0) { 1942d522f475Smrg TRACE(("Conversion failed\n")); 1943d522f475Smrg text_list = NULL; 1944d522f475Smrg } 1945d522f475Smrg } 1946d522f475Smrg } else 1947d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1948d522f475Smrg { 1949d522f475Smrg /* Convert the selection to locale's multibyte encoding. */ 1950d522f475Smrg 1951d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 1952d522f475Smrg *type == XA_STRING || 1953d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 1954d522f475Smrg Status rc; 1955d522f475Smrg 1956d522f475Smrg GettingSelection(dpy, *type, line, *length); 1957d522f475Smrg 1958d522f475Smrg#if OPT_WIDE_CHARS 1959d522f475Smrg if (*type == XA_UTF8_STRING(dpy) && 1960d522f475Smrg !(screen->wide_chars || screen->c1_printable)) { 196120d2c4d2Smrg rc = xtermUtf8ToTextList(xw, &text_prop, 196220d2c4d2Smrg &text_list, &text_list_count); 1963d522f475Smrg } else 1964d522f475Smrg#endif 1965d522f475Smrg if (*type == XA_STRING && screen->brokenSelections) { 1966d522f475Smrg rc = XTextPropertyToStringList(&text_prop, 1967d522f475Smrg &text_list, &text_list_count); 1968d522f475Smrg } else { 1969d522f475Smrg rc = XmbTextPropertyToTextList(dpy, &text_prop, 1970d522f475Smrg &text_list, 1971d522f475Smrg &text_list_count); 1972d522f475Smrg } 1973d522f475Smrg if (rc < 0) { 1974d522f475Smrg TRACE(("Conversion failed\n")); 1975d522f475Smrg text_list = NULL; 1976d522f475Smrg } 1977d522f475Smrg } 1978d522f475Smrg } 1979d522f475Smrg 1980d522f475Smrg if (text_list != NULL && text_list_count != 0) { 1981d522f475Smrg int i; 1982d522f475Smrg 1983d522f475Smrg#if OPT_PASTE64 1984d522f475Smrg if (screen->base64_paste) { 1985a1f3da82Smrg /* EMPTY */ ; 1986d522f475Smrg } else 1987d522f475Smrg#endif 1988d522f475Smrg#if OPT_READLINE 1989d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 1990492d43a5Smrg _WriteKey(screen, (const Char *) "200"); 1991d522f475Smrg } 1992d522f475Smrg#endif 1993d522f475Smrg for (i = 0; i < text_list_count; i++) { 199420d2c4d2Smrg size_t len = strlen(text_list[i]); 1995d522f475Smrg _WriteSelectionData(screen, (Char *) text_list[i], len); 1996d522f475Smrg } 1997d522f475Smrg#if OPT_PASTE64 1998d522f475Smrg if (screen->base64_paste) { 1999956cc18dSsnj FinishPaste64(xw); 2000d522f475Smrg } else 2001d522f475Smrg#endif 2002d522f475Smrg#if OPT_READLINE 2003d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 2004492d43a5Smrg _WriteKey(screen, (const Char *) "201"); 2005d522f475Smrg } 2006d522f475Smrg#endif 2007d522f475Smrg XFreeStringList(text_list); 2008d522f475Smrg } else 2009d522f475Smrg goto fail; 2010d522f475Smrg 2011d522f475Smrg XtFree((char *) client_data); 2012d522f475Smrg XtFree((char *) value); 2013d522f475Smrg 2014d522f475Smrg return; 2015d522f475Smrg 2016d522f475Smrg fail: 2017d522f475Smrg if (client_data != 0) { 2018d522f475Smrg struct _SelectionList *list = (struct _SelectionList *) client_data; 2019956cc18dSsnj 2020956cc18dSsnj TRACE(("SelectionReceived ->xtermGetSelection\n")); 2021d522f475Smrg xtermGetSelection(w, list->time, 2022d522f475Smrg list->params, list->count, list->targets); 2023d522f475Smrg XtFree((char *) client_data); 2024d522f475Smrg#if OPT_PASTE64 2025d522f475Smrg } else { 2026956cc18dSsnj FinishPaste64(xw); 2027d522f475Smrg#endif 2028d522f475Smrg } 2029d522f475Smrg return; 2030d522f475Smrg} 2031d522f475Smrg 2032d522f475Smrgvoid 2033d522f475SmrgHandleInsertSelection(Widget w, 2034d522f475Smrg XEvent * event, /* assumed to be XButtonEvent* */ 2035d522f475Smrg String * params, /* selections in precedence order */ 2036d522f475Smrg Cardinal *num_params) 2037d522f475Smrg{ 2038956cc18dSsnj XtermWidget xw; 2039d522f475Smrg 2040956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2041d522f475Smrg if (!SendMousePosition(xw, event)) { 2042d522f475Smrg#if OPT_READLINE 2043d522f475Smrg int ldelta; 2044956cc18dSsnj TScreen *screen = TScreenOf(xw); 2045492d43a5Smrg if (IsBtnEvent(event) 2046d522f475Smrg /* Disable on Shift-mouse, including the application-mouse modes */ 2047492d43a5Smrg && !(KeyModifiers(event) & ShiftMask) 2048d522f475Smrg && (screen->send_mouse_pos == MOUSE_OFF) 2049d522f475Smrg && SCREEN_FLAG(screen, paste_moves) 2050d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta)) 2051d522f475Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta); 2052d522f475Smrg#endif /* OPT_READLINE */ 2053d522f475Smrg 2054d522f475Smrg xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL); 2055d522f475Smrg } 2056d522f475Smrg } 2057d522f475Smrg} 2058d522f475Smrg 2059d522f475Smrgstatic SelectUnit 2060956cc18dSsnjEvalSelectUnit(XtermWidget xw, 2061d522f475Smrg Time buttonDownTime, 2062d522f475Smrg SelectUnit defaultUnit, 2063d522f475Smrg unsigned int button) 2064d522f475Smrg{ 2065956cc18dSsnj TScreen *screen = TScreenOf(xw); 2066d522f475Smrg SelectUnit result; 2067d522f475Smrg int delta; 2068d522f475Smrg 2069d522f475Smrg if (button != screen->lastButton) { 207020d2c4d2Smrg delta = screen->multiClickTime + 1; 2071d522f475Smrg } else if (screen->lastButtonUpTime == (Time) 0) { 2072d522f475Smrg /* first time and once in a blue moon */ 2073d522f475Smrg delta = screen->multiClickTime + 1; 2074d522f475Smrg } else if (buttonDownTime > screen->lastButtonUpTime) { 2075d522f475Smrg /* most of the time */ 20762eaa94a1Schristos delta = (int) (buttonDownTime - screen->lastButtonUpTime); 2077d522f475Smrg } else { 2078d522f475Smrg /* time has rolled over since lastButtonUpTime */ 20792eaa94a1Schristos delta = (int) ((((Time) ~ 0) - screen->lastButtonUpTime) + buttonDownTime); 2080d522f475Smrg } 2081d522f475Smrg 2082d522f475Smrg if (delta > screen->multiClickTime) { 2083d522f475Smrg screen->numberOfClicks = 1; 2084d522f475Smrg result = defaultUnit; 2085d522f475Smrg } else { 2086d522f475Smrg result = screen->selectMap[screen->numberOfClicks % screen->maxClicks]; 2087d522f475Smrg screen->numberOfClicks += 1; 2088d522f475Smrg } 2089d522f475Smrg TRACE(("EvalSelectUnit(%d) = %d\n", screen->numberOfClicks, result)); 2090d522f475Smrg return result; 2091d522f475Smrg} 2092d522f475Smrg 2093d522f475Smrgstatic void 2094d522f475Smrgdo_select_start(XtermWidget xw, 2095d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2096d522f475Smrg CELL * cell) 2097d522f475Smrg{ 2098956cc18dSsnj TScreen *screen = TScreenOf(xw); 2099d522f475Smrg 2100d522f475Smrg if (SendMousePosition(xw, event)) 2101d522f475Smrg return; 2102956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2103d522f475Smrg event->xbutton.time, 2104d522f475Smrg Select_CHAR, 2105d522f475Smrg event->xbutton.button); 2106d522f475Smrg screen->replyToEmacs = False; 2107d522f475Smrg 2108d522f475Smrg#if OPT_READLINE 2109d522f475Smrg lastButtonDownTime = event->xbutton.time; 2110d522f475Smrg#endif 2111d522f475Smrg 2112d522f475Smrg StartSelect(xw, cell); 2113d522f475Smrg} 2114d522f475Smrg 2115d522f475Smrg/* ARGSUSED */ 2116d522f475Smrgvoid 2117d522f475SmrgHandleSelectStart(Widget w, 2118d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2119d522f475Smrg String * params GCC_UNUSED, 2120d522f475Smrg Cardinal *num_params GCC_UNUSED) 2121d522f475Smrg{ 2122956cc18dSsnj XtermWidget xw; 2123956cc18dSsnj 2124956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2125956cc18dSsnj TScreen *screen = TScreenOf(xw); 2126d522f475Smrg CELL cell; 2127d522f475Smrg 2128d522f475Smrg screen->firstValidRow = 0; 2129d522f475Smrg screen->lastValidRow = screen->max_row; 2130d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2131d522f475Smrg 2132d522f475Smrg#if OPT_READLINE 2133d522f475Smrg ExtendingSelection = 0; 2134d522f475Smrg#endif 2135d522f475Smrg 2136d522f475Smrg do_select_start(xw, event, &cell); 2137d522f475Smrg } 2138d522f475Smrg} 2139d522f475Smrg 2140d522f475Smrg/* ARGSUSED */ 2141d522f475Smrgvoid 2142d522f475SmrgHandleKeyboardSelectStart(Widget w, 2143d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2144d522f475Smrg String * params GCC_UNUSED, 2145d522f475Smrg Cardinal *num_params GCC_UNUSED) 2146d522f475Smrg{ 2147956cc18dSsnj XtermWidget xw; 2148956cc18dSsnj 2149956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2150956cc18dSsnj TScreen *screen = TScreenOf(xw); 2151d522f475Smrg do_select_start(xw, event, &screen->cursorp); 2152d522f475Smrg } 2153d522f475Smrg} 2154d522f475Smrg 2155d522f475Smrgstatic void 2156d522f475SmrgTrackDown(XtermWidget xw, XButtonEvent * event) 2157d522f475Smrg{ 2158956cc18dSsnj TScreen *screen = TScreenOf(xw); 2159d522f475Smrg CELL cell; 2160d522f475Smrg 2161956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2162d522f475Smrg event->time, 2163d522f475Smrg Select_CHAR, 2164d522f475Smrg event->button); 2165d522f475Smrg if (screen->numberOfClicks > 1) { 2166d522f475Smrg PointToCELL(screen, event->y, event->x, &cell); 2167d522f475Smrg screen->replyToEmacs = True; 2168d522f475Smrg StartSelect(xw, &cell); 2169d522f475Smrg } else { 2170d522f475Smrg screen->waitingForTrackInfo = True; 2171492d43a5Smrg EditorButton(xw, event); 2172d522f475Smrg } 2173d522f475Smrg} 2174d522f475Smrg 2175d522f475Smrg#define boundsCheck(x) if (x < 0) \ 2176d522f475Smrg x = 0; \ 2177d522f475Smrg else if (x >= screen->max_row) \ 2178d522f475Smrg x = screen->max_row 2179d522f475Smrg 2180d522f475Smrgvoid 2181d522f475SmrgTrackMouse(XtermWidget xw, 2182d522f475Smrg int func, 2183d522f475Smrg CELL * start, 2184d522f475Smrg int firstrow, 2185d522f475Smrg int lastrow) 2186d522f475Smrg{ 2187956cc18dSsnj TScreen *screen = TScreenOf(xw); 2188d522f475Smrg 2189d522f475Smrg if (screen->waitingForTrackInfo) { /* if Timed, ignore */ 2190d522f475Smrg screen->waitingForTrackInfo = False; 2191d522f475Smrg 2192d522f475Smrg if (func != 0) { 2193d522f475Smrg CELL first = *start; 2194d522f475Smrg 2195d522f475Smrg boundsCheck(first.row); 2196d522f475Smrg boundsCheck(firstrow); 2197d522f475Smrg boundsCheck(lastrow); 2198d522f475Smrg screen->firstValidRow = firstrow; 2199d522f475Smrg screen->lastValidRow = lastrow; 2200d522f475Smrg screen->replyToEmacs = True; 2201d522f475Smrg StartSelect(xw, &first); 2202d522f475Smrg } 2203d522f475Smrg } 2204d522f475Smrg} 2205d522f475Smrg 2206d522f475Smrgstatic void 2207d522f475SmrgStartSelect(XtermWidget xw, const CELL * cell) 2208d522f475Smrg{ 2209956cc18dSsnj TScreen *screen = TScreenOf(xw); 2210d522f475Smrg 2211d522f475Smrg TRACE(("StartSelect row=%d, col=%d\n", cell->row, cell->col)); 2212d522f475Smrg if (screen->cursor_state) 2213d522f475Smrg HideCursor(); 2214d522f475Smrg if (screen->numberOfClicks == 1) { 2215d522f475Smrg /* set start of selection */ 2216d522f475Smrg screen->rawPos = *cell; 2217d522f475Smrg } 2218d522f475Smrg /* else use old values in rawPos */ 2219d522f475Smrg screen->saveStartR = screen->startExt = screen->rawPos; 2220d522f475Smrg screen->saveEndR = screen->endExt = screen->rawPos; 2221d522f475Smrg if (Coordinate(screen, cell) < Coordinate(screen, &(screen->rawPos))) { 2222d522f475Smrg screen->eventMode = LEFTEXTENSION; 2223d522f475Smrg screen->startExt = *cell; 2224d522f475Smrg } else { 2225d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2226d522f475Smrg screen->endExt = *cell; 2227d522f475Smrg } 2228d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 2229d522f475Smrg} 2230d522f475Smrg 2231d522f475Smrgstatic void 2232d522f475SmrgEndExtend(XtermWidget xw, 2233d522f475Smrg XEvent * event, /* must be XButtonEvent */ 2234d522f475Smrg String * params, /* selections */ 2235d522f475Smrg Cardinal num_params, 2236d522f475Smrg Bool use_cursor_loc) 2237d522f475Smrg{ 2238d522f475Smrg CELL cell; 2239d522f475Smrg unsigned count; 2240956cc18dSsnj TScreen *screen = TScreenOf(xw); 2241492d43a5Smrg Char line[20]; 2242d522f475Smrg 2243d522f475Smrg if (use_cursor_loc) { 2244d522f475Smrg cell = screen->cursorp; 2245d522f475Smrg } else { 2246d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2247d522f475Smrg } 2248d522f475Smrg ExtendExtend(xw, &cell); 2249d522f475Smrg screen->lastButtonUpTime = event->xbutton.time; 2250d522f475Smrg screen->lastButton = event->xbutton.button; 2251d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 2252d522f475Smrg if (screen->replyToEmacs) { 2253d522f475Smrg count = 0; 2254d522f475Smrg if (screen->control_eight_bits) { 2255d522f475Smrg line[count++] = ANSI_CSI; 2256d522f475Smrg } else { 2257d522f475Smrg line[count++] = ANSI_ESC; 2258d522f475Smrg line[count++] = '['; 2259d522f475Smrg } 2260d522f475Smrg if (isSameCELL(&(screen->rawPos), &(screen->startSel)) 2261d522f475Smrg && isSameCELL(&cell, &(screen->endSel))) { 2262d522f475Smrg /* Use short-form emacs select */ 2263d522f475Smrg line[count++] = 't'; 2264492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 2265492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 2266d522f475Smrg } else { 2267d522f475Smrg /* long-form, specify everything */ 2268d522f475Smrg line[count++] = 'T'; 2269492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.col); 2270492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.row); 2271492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 2272492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 2273492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.col); 2274492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.row); 2275d522f475Smrg } 2276d522f475Smrg v_write(screen->respond, line, count); 2277d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 2278d522f475Smrg } 2279d522f475Smrg } 2280d522f475Smrg SelectSet(xw, event, params, num_params); 2281d522f475Smrg screen->eventMode = NORMAL; 2282d522f475Smrg} 2283d522f475Smrg 2284d522f475Smrgvoid 2285d522f475SmrgHandleSelectSet(Widget w, 2286d522f475Smrg XEvent * event, 2287d522f475Smrg String * params, 2288d522f475Smrg Cardinal *num_params) 2289d522f475Smrg{ 2290956cc18dSsnj XtermWidget xw; 2291956cc18dSsnj 2292956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2293956cc18dSsnj SelectSet(xw, event, params, *num_params); 2294d522f475Smrg } 2295d522f475Smrg} 2296d522f475Smrg 2297d522f475Smrg/* ARGSUSED */ 2298d522f475Smrgstatic void 2299d522f475SmrgSelectSet(XtermWidget xw, 2300d522f475Smrg XEvent * event GCC_UNUSED, 2301d522f475Smrg String * params, 2302d522f475Smrg Cardinal num_params) 2303d522f475Smrg{ 2304956cc18dSsnj TScreen *screen = TScreenOf(xw); 2305d522f475Smrg 2306d522f475Smrg TRACE(("SelectSet\n")); 2307d522f475Smrg /* Only do select stuff if non-null select */ 2308d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 2309d522f475Smrg SaltTextAway(xw, &(screen->startSel), &(screen->endSel), params, num_params); 2310d522f475Smrg } else { 2311d522f475Smrg DisownSelection(xw); 2312d522f475Smrg } 2313d522f475Smrg} 2314d522f475Smrg 2315d522f475Smrg#define Abs(x) ((x) < 0 ? -(x) : (x)) 2316d522f475Smrg 2317d522f475Smrg/* ARGSUSED */ 2318d522f475Smrgstatic void 2319d522f475Smrgdo_start_extend(XtermWidget xw, 2320d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2321d522f475Smrg String * params GCC_UNUSED, 2322d522f475Smrg Cardinal *num_params GCC_UNUSED, 2323d522f475Smrg Bool use_cursor_loc) 2324d522f475Smrg{ 2325956cc18dSsnj TScreen *screen = TScreenOf(xw); 2326d522f475Smrg int coord; 2327d522f475Smrg CELL cell; 2328d522f475Smrg 2329d522f475Smrg if (SendMousePosition(xw, event)) 2330d522f475Smrg return; 2331d522f475Smrg 2332d522f475Smrg screen->firstValidRow = 0; 2333d522f475Smrg screen->lastValidRow = screen->max_row; 2334d522f475Smrg#if OPT_READLINE 2335492d43a5Smrg if ((KeyModifiers(event) & ShiftMask) 2336d522f475Smrg || event->xbutton.button != Button3 2337d522f475Smrg || !(SCREEN_FLAG(screen, dclick3_deletes))) 2338d522f475Smrg#endif 2339956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2340d522f475Smrg event->xbutton.time, 2341d522f475Smrg screen->selectUnit, 2342d522f475Smrg event->xbutton.button); 2343d522f475Smrg screen->replyToEmacs = False; 2344d522f475Smrg 2345d522f475Smrg#if OPT_READLINE 2346d522f475Smrg CheckSecondPress3(screen, event); 2347d522f475Smrg#endif 2348d522f475Smrg 2349d522f475Smrg if (screen->numberOfClicks == 1 2350d522f475Smrg || (SCREEN_FLAG(screen, dclick3_deletes) /* Dclick special */ 2351492d43a5Smrg &&!(KeyModifiers(event) & ShiftMask))) { 2352d522f475Smrg /* Save existing selection so we can reestablish it if the guy 2353d522f475Smrg extends past the other end of the selection */ 2354d522f475Smrg screen->saveStartR = screen->startExt = screen->startRaw; 2355d522f475Smrg screen->saveEndR = screen->endExt = screen->endRaw; 2356d522f475Smrg } else { 2357d522f475Smrg /* He just needed the selection mode changed, use old values. */ 2358d522f475Smrg screen->startExt = screen->startRaw = screen->saveStartR; 2359d522f475Smrg screen->endExt = screen->endRaw = screen->saveEndR; 2360d522f475Smrg } 2361d522f475Smrg if (use_cursor_loc) { 2362d522f475Smrg cell = screen->cursorp; 2363d522f475Smrg } else { 2364d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2365d522f475Smrg } 2366d522f475Smrg coord = Coordinate(screen, &cell); 2367d522f475Smrg 2368d522f475Smrg if (Abs(coord - Coordinate(screen, &(screen->startSel))) 2369d522f475Smrg < Abs(coord - Coordinate(screen, &(screen->endSel))) 2370d522f475Smrg || coord < Coordinate(screen, &(screen->startSel))) { 2371d522f475Smrg /* point is close to left side of selection */ 2372d522f475Smrg screen->eventMode = LEFTEXTENSION; 2373d522f475Smrg screen->startExt = cell; 2374d522f475Smrg } else { 2375d522f475Smrg /* point is close to left side of selection */ 2376d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2377d522f475Smrg screen->endExt = cell; 2378d522f475Smrg } 2379d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), True); 2380d522f475Smrg 2381d522f475Smrg#if OPT_READLINE 2382d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2383d522f475Smrg ExtendingSelection = 1; 2384d522f475Smrg#endif 2385d522f475Smrg} 2386d522f475Smrg 2387d522f475Smrgstatic void 2388d522f475SmrgExtendExtend(XtermWidget xw, const CELL * cell) 2389d522f475Smrg{ 2390956cc18dSsnj TScreen *screen = TScreenOf(xw); 2391d522f475Smrg int coord = Coordinate(screen, cell); 2392d522f475Smrg 2393d522f475Smrg TRACE(("ExtendExtend row=%d, col=%d\n", cell->row, cell->col)); 2394d522f475Smrg if (screen->eventMode == LEFTEXTENSION 2395d522f475Smrg && ((coord + (screen->selectUnit != Select_CHAR)) 2396d522f475Smrg > Coordinate(screen, &(screen->endSel)))) { 2397d522f475Smrg /* Whoops, he's changed his mind. Do RIGHTEXTENSION */ 2398d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2399d522f475Smrg screen->startExt = screen->saveStartR; 2400d522f475Smrg } else if (screen->eventMode == RIGHTEXTENSION 2401d522f475Smrg && coord < Coordinate(screen, &(screen->startSel))) { 2402d522f475Smrg /* Whoops, he's changed his mind. Do LEFTEXTENSION */ 2403d522f475Smrg screen->eventMode = LEFTEXTENSION; 2404d522f475Smrg screen->endExt = screen->saveEndR; 2405d522f475Smrg } 2406d522f475Smrg if (screen->eventMode == LEFTEXTENSION) { 2407d522f475Smrg screen->startExt = *cell; 2408d522f475Smrg } else { 2409d522f475Smrg screen->endExt = *cell; 2410d522f475Smrg } 2411d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 2412d522f475Smrg 2413d522f475Smrg#if OPT_READLINE 2414d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2415d522f475Smrg ExtendingSelection = 1; 2416d522f475Smrg#endif 2417d522f475Smrg} 2418d522f475Smrg 2419d522f475Smrgvoid 2420d522f475SmrgHandleStartExtend(Widget w, 2421d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2422d522f475Smrg String * params, /* unused */ 2423d522f475Smrg Cardinal *num_params) /* unused */ 2424d522f475Smrg{ 2425956cc18dSsnj XtermWidget xw; 2426956cc18dSsnj 2427956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2428956cc18dSsnj do_start_extend(xw, event, params, num_params, False); 2429956cc18dSsnj } 2430d522f475Smrg} 2431d522f475Smrg 2432d522f475Smrgvoid 2433d522f475SmrgHandleKeyboardStartExtend(Widget w, 2434d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2435d522f475Smrg String * params, /* unused */ 2436d522f475Smrg Cardinal *num_params) /* unused */ 2437d522f475Smrg{ 2438956cc18dSsnj XtermWidget xw; 2439956cc18dSsnj 2440956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2441956cc18dSsnj do_start_extend(xw, event, params, num_params, True); 2442956cc18dSsnj } 2443d522f475Smrg} 2444d522f475Smrg 2445d522f475Smrgvoid 2446d522f475SmrgScrollSelection(TScreen * screen, int amount, Bool always) 2447d522f475Smrg{ 2448d522f475Smrg int minrow = INX2ROW(screen, -screen->savedlines); 2449d522f475Smrg int maxrow = INX2ROW(screen, screen->max_row); 2450d522f475Smrg int maxcol = screen->max_col; 2451d522f475Smrg 2452d522f475Smrg#define scroll_update_one(cell) \ 2453d522f475Smrg (cell)->row += amount; \ 2454d522f475Smrg if ((cell)->row < minrow) { \ 2455d522f475Smrg (cell)->row = minrow; \ 2456d522f475Smrg (cell)->col = 0; \ 2457d522f475Smrg } \ 2458d522f475Smrg if ((cell)->row > maxrow) { \ 2459d522f475Smrg (cell)->row = maxrow; \ 2460d522f475Smrg (cell)->col = maxcol; \ 2461d522f475Smrg } 2462d522f475Smrg 2463d522f475Smrg scroll_update_one(&(screen->startRaw)); 2464d522f475Smrg scroll_update_one(&(screen->endRaw)); 2465d522f475Smrg scroll_update_one(&(screen->startSel)); 2466d522f475Smrg scroll_update_one(&(screen->endSel)); 2467d522f475Smrg 2468d522f475Smrg scroll_update_one(&(screen->rawPos)); 2469d522f475Smrg 2470d522f475Smrg /* 2471d522f475Smrg * If we are told to scroll the selection but it lies outside the scrolling 2472d522f475Smrg * margins, then that could cause the selection to move (bad). It is not 2473d522f475Smrg * simple to fix, because this function is called both for the scrollbar 2474d522f475Smrg * actions as well as application scrolling. The 'always' flag is set in 2475d522f475Smrg * the former case. The rest of the logic handles the latter. 2476d522f475Smrg */ 2477d522f475Smrg if (ScrnHaveSelection(screen)) { 2478d522f475Smrg int adjust; 2479d522f475Smrg 2480d522f475Smrg adjust = ROW2INX(screen, screen->startH.row); 2481d522f475Smrg if (always 2482d522f475Smrg || !ScrnHaveLineMargins(screen) 2483d522f475Smrg || ScrnIsLineInMargins(screen, adjust)) { 2484d522f475Smrg scroll_update_one(&screen->startH); 2485d522f475Smrg } 2486d522f475Smrg adjust = ROW2INX(screen, screen->endH.row); 2487d522f475Smrg if (always 2488d522f475Smrg || !ScrnHaveLineMargins(screen) 2489d522f475Smrg || ScrnIsLineInMargins(screen, adjust)) { 2490d522f475Smrg scroll_update_one(&screen->endH); 2491d522f475Smrg } 2492d522f475Smrg } 2493d522f475Smrg 2494d522f475Smrg screen->startHCoord = Coordinate(screen, &screen->startH); 2495d522f475Smrg screen->endHCoord = Coordinate(screen, &screen->endH); 2496d522f475Smrg} 2497d522f475Smrg 2498d522f475Smrg/*ARGSUSED*/ 2499d522f475Smrgvoid 2500d522f475SmrgResizeSelection(TScreen * screen GCC_UNUSED, int rows, int cols) 2501d522f475Smrg{ 2502d522f475Smrg rows--; /* decr to get 0-max */ 2503d522f475Smrg cols--; 2504d522f475Smrg 2505d522f475Smrg if (screen->startRaw.row > rows) 2506d522f475Smrg screen->startRaw.row = rows; 2507d522f475Smrg if (screen->startSel.row > rows) 2508d522f475Smrg screen->startSel.row = rows; 2509d522f475Smrg if (screen->endRaw.row > rows) 2510d522f475Smrg screen->endRaw.row = rows; 2511d522f475Smrg if (screen->endSel.row > rows) 2512d522f475Smrg screen->endSel.row = rows; 2513d522f475Smrg if (screen->rawPos.row > rows) 2514d522f475Smrg screen->rawPos.row = rows; 2515d522f475Smrg 2516d522f475Smrg if (screen->startRaw.col > cols) 2517d522f475Smrg screen->startRaw.col = cols; 2518d522f475Smrg if (screen->startSel.col > cols) 2519d522f475Smrg screen->startSel.col = cols; 2520d522f475Smrg if (screen->endRaw.col > cols) 2521d522f475Smrg screen->endRaw.col = cols; 2522d522f475Smrg if (screen->endSel.col > cols) 2523d522f475Smrg screen->endSel.col = cols; 2524d522f475Smrg if (screen->rawPos.col > cols) 2525d522f475Smrg screen->rawPos.col = cols; 2526d522f475Smrg} 2527d522f475Smrg 2528d522f475Smrg#if OPT_WIDE_CHARS 2529d522f475SmrgBool 2530d522f475Smrgiswide(int i) 2531d522f475Smrg{ 253220d2c4d2Smrg return (i == HIDDEN_CHAR) || (WideCells(i) == 2); 2533d522f475Smrg} 2534d522f475Smrg 2535d522f475Smrg#define isWideCell(row, col) iswide((int)XTERM_CELL(row, col)) 2536d522f475Smrg#endif 2537d522f475Smrg 2538d522f475Smrgstatic void 2539d522f475SmrgPointToCELL(TScreen * screen, 2540d522f475Smrg int y, 2541d522f475Smrg int x, 2542d522f475Smrg CELL * cell) 2543d522f475Smrg/* Convert pixel coordinates to character coordinates. 2544d522f475Smrg Rows are clipped between firstValidRow and lastValidRow. 2545d522f475Smrg Columns are clipped between to be 0 or greater, but are not clipped to some 2546d522f475Smrg maximum value. */ 2547d522f475Smrg{ 2548d522f475Smrg cell->row = (y - screen->border) / FontHeight(screen); 2549d522f475Smrg if (cell->row < screen->firstValidRow) 2550d522f475Smrg cell->row = screen->firstValidRow; 2551d522f475Smrg else if (cell->row > screen->lastValidRow) 2552d522f475Smrg cell->row = screen->lastValidRow; 2553d522f475Smrg cell->col = (x - OriginX(screen)) / FontWidth(screen); 2554d522f475Smrg if (cell->col < 0) 2555d522f475Smrg cell->col = 0; 2556d522f475Smrg else if (cell->col > MaxCols(screen)) { 2557d522f475Smrg cell->col = MaxCols(screen); 2558d522f475Smrg } 2559d522f475Smrg#if OPT_WIDE_CHARS 2560d522f475Smrg /* 2561d522f475Smrg * If we got a click on the right half of a doublewidth character, 2562d522f475Smrg * pretend it happened on the left half. 2563d522f475Smrg */ 2564d522f475Smrg if (cell->col > 0 2565d522f475Smrg && isWideCell(cell->row, cell->col - 1) 2566d522f475Smrg && (XTERM_CELL(cell->row, cell->col) == HIDDEN_CHAR)) { 2567d522f475Smrg cell->col -= 1; 2568d522f475Smrg } 2569d522f475Smrg#endif 2570d522f475Smrg} 2571d522f475Smrg 2572d522f475Smrg/* 2573d522f475Smrg * Find the last column at which text was drawn on the given row. 2574d522f475Smrg */ 2575d522f475Smrgstatic int 2576956cc18dSsnjLastTextCol(TScreen * screen, LineData * ld, int row) 2577d522f475Smrg{ 257820d2c4d2Smrg int i = -1; 2579d522f475Smrg Char *ch; 2580d522f475Smrg 258120d2c4d2Smrg if (ld != 0) { 258220d2c4d2Smrg if (okScrnRow(screen, row)) { 258320d2c4d2Smrg for (i = screen->max_col, 258420d2c4d2Smrg ch = ld->attribs + i; 258520d2c4d2Smrg i >= 0 && !(*ch & CHARDRAWN); 258620d2c4d2Smrg ch--, i--) { 258720d2c4d2Smrg ; 258820d2c4d2Smrg } 2589d522f475Smrg#if OPT_DEC_CHRSET 259020d2c4d2Smrg if (CSET_DOUBLE(GetLineDblCS(ld))) { 259120d2c4d2Smrg i *= 2; 259220d2c4d2Smrg } 2593d522f475Smrg#endif 259420d2c4d2Smrg } 2595d522f475Smrg } 2596d522f475Smrg return (i); 2597d522f475Smrg} 2598d522f475Smrg 2599d522f475Smrg#if !OPT_WIDE_CHARS 2600d522f475Smrg/* 2601d522f475Smrg** double click table for cut and paste in 8 bits 2602d522f475Smrg** 2603d522f475Smrg** This table is divided in four parts : 2604d522f475Smrg** 2605d522f475Smrg** - control characters [0,0x1f] U [0x80,0x9f] 2606d522f475Smrg** - separators [0x20,0x3f] U [0xa0,0xb9] 2607d522f475Smrg** - binding characters [0x40,0x7f] U [0xc0,0xff] 2608d522f475Smrg** - exceptions 2609d522f475Smrg*/ 2610d522f475Smrg/* *INDENT-OFF* */ 2611d522f475Smrgstatic int charClass[256] = 2612d522f475Smrg{ 2613d522f475Smrg/* NUL SOH STX ETX EOT ENQ ACK BEL */ 2614d522f475Smrg 32, 1, 1, 1, 1, 1, 1, 1, 2615d522f475Smrg/* BS HT NL VT NP CR SO SI */ 2616d522f475Smrg 1, 32, 1, 1, 1, 1, 1, 1, 2617d522f475Smrg/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 2618d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2619d522f475Smrg/* CAN EM SUB ESC FS GS RS US */ 2620d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2621d522f475Smrg/* SP ! " # $ % & ' */ 2622d522f475Smrg 32, 33, 34, 35, 36, 37, 38, 39, 2623d522f475Smrg/* ( ) * + , - . / */ 2624d522f475Smrg 40, 41, 42, 43, 44, 45, 46, 47, 2625d522f475Smrg/* 0 1 2 3 4 5 6 7 */ 2626d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2627d522f475Smrg/* 8 9 : ; < = > ? */ 2628d522f475Smrg 48, 48, 58, 59, 60, 61, 62, 63, 2629d522f475Smrg/* @ A B C D E F G */ 2630d522f475Smrg 64, 48, 48, 48, 48, 48, 48, 48, 2631d522f475Smrg/* H I J K L M N O */ 2632d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2633d522f475Smrg/* P Q R S T U V W */ 2634d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2635d522f475Smrg/* X Y Z [ \ ] ^ _ */ 2636d522f475Smrg 48, 48, 48, 91, 92, 93, 94, 48, 2637d522f475Smrg/* ` a b c d e f g */ 2638d522f475Smrg 96, 48, 48, 48, 48, 48, 48, 48, 2639d522f475Smrg/* h i j k l m n o */ 2640d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2641d522f475Smrg/* p q r s t u v w */ 2642d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2643d522f475Smrg/* x y z { | } ~ DEL */ 2644d522f475Smrg 48, 48, 48, 123, 124, 125, 126, 1, 2645d522f475Smrg/* x80 x81 x82 x83 IND NEL SSA ESA */ 2646d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2647d522f475Smrg/* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 2648d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2649d522f475Smrg/* DCS PU1 PU2 STS CCH MW SPA EPA */ 2650d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2651d522f475Smrg/* x98 x99 x9A CSI ST OSC PM APC */ 2652d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2653d522f475Smrg/* - i c/ L ox Y- | So */ 2654d522f475Smrg 160, 161, 162, 163, 164, 165, 166, 167, 2655d522f475Smrg/* .. c0 ip << _ R0 - */ 2656d522f475Smrg 168, 169, 170, 171, 172, 173, 174, 175, 2657d522f475Smrg/* o +- 2 3 ' u q| . */ 2658d522f475Smrg 176, 177, 178, 179, 180, 181, 182, 183, 2659d522f475Smrg/* , 1 2 >> 1/4 1/2 3/4 ? */ 2660d522f475Smrg 184, 185, 186, 187, 188, 189, 190, 191, 2661d522f475Smrg/* A` A' A^ A~ A: Ao AE C, */ 2662d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2663d522f475Smrg/* E` E' E^ E: I` I' I^ I: */ 2664d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2665d522f475Smrg/* D- N~ O` O' O^ O~ O: X */ 2666d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 215, 2667d522f475Smrg/* O/ U` U' U^ U: Y' P B */ 2668d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2669d522f475Smrg/* a` a' a^ a~ a: ao ae c, */ 2670d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2671d522f475Smrg/* e` e' e^ e: i` i' i^ i: */ 2672d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2673d522f475Smrg/* d n~ o` o' o^ o~ o: -: */ 2674d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 247, 2675d522f475Smrg/* o/ u` u' u^ u: y' P y: */ 2676d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48}; 2677d522f475Smrg/* *INDENT-ON* */ 2678d522f475Smrg 2679d522f475Smrgint 2680d522f475SmrgSetCharacterClassRange(int low, /* in range of [0..255] */ 2681d522f475Smrg int high, 2682d522f475Smrg int value) /* arbitrary */ 2683d522f475Smrg{ 2684d522f475Smrg 2685d522f475Smrg if (low < 0 || high > 255 || high < low) 2686d522f475Smrg return (-1); 2687d522f475Smrg 2688d522f475Smrg for (; low <= high; low++) 2689d522f475Smrg charClass[low] = value; 2690d522f475Smrg 2691d522f475Smrg return (0); 2692d522f475Smrg} 2693d522f475Smrg#endif 2694d522f475Smrg 2695d522f475Smrgstatic int 2696956cc18dSsnjclass_of(LineData * ld, CELL * cell) 2697d522f475Smrg{ 2698d522f475Smrg CELL temp = *cell; 2699d522f475Smrg 2700d522f475Smrg#if OPT_DEC_CHRSET 2701956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 2702d522f475Smrg temp.col /= 2; 2703d522f475Smrg } 2704d522f475Smrg#endif 2705d522f475Smrg 270620d2c4d2Smrg assert(temp.col < ld->lineSize); 2707956cc18dSsnj return CharacterClass((int) (ld->charData[temp.col])); 2708d522f475Smrg} 2709956cc18dSsnj 2710956cc18dSsnj#if OPT_WIDE_CHARS 2711956cc18dSsnj#define CClassSelects(name, cclass) \ 2712956cc18dSsnj (CClassOf(name) == cclass \ 2713956cc18dSsnj || XTERM_CELL(screen->name.row, screen->name.col) == HIDDEN_CHAR) 2714d522f475Smrg#else 2715956cc18dSsnj#define CClassSelects(name, cclass) \ 2716956cc18dSsnj (class_of(ld.name, &((screen->name))) == cclass) 2717d522f475Smrg#endif 2718d522f475Smrg 2719956cc18dSsnj#define CClassOf(name) class_of(ld.name, &((screen->name))) 2720956cc18dSsnj 2721d522f475Smrg/* 2722d522f475Smrg * If the given column is past the end of text on the given row, bump to the 2723d522f475Smrg * beginning of the next line. 2724d522f475Smrg */ 2725d522f475Smrgstatic Boolean 2726d522f475SmrgokPosition(TScreen * screen, 2727956cc18dSsnj LineData ** ld, 2728d522f475Smrg CELL * cell) 2729d522f475Smrg{ 273020d2c4d2Smrg Boolean result = True; 273120d2c4d2Smrg 273220d2c4d2Smrg if (cell->row > screen->max_row) { 273320d2c4d2Smrg result = False; 273420d2c4d2Smrg } else if (cell->col > (LastTextCol(screen, *ld, cell->row) + 1)) { 273520d2c4d2Smrg if (cell->row < screen->max_row) { 273620d2c4d2Smrg cell->col = 0; 273720d2c4d2Smrg *ld = GET_LINEDATA(screen, ++cell->row); 273820d2c4d2Smrg result = False; 273920d2c4d2Smrg } 2740d522f475Smrg } 274120d2c4d2Smrg return result; 2742d522f475Smrg} 2743d522f475Smrg 2744d522f475Smrgstatic void 2745956cc18dSsnjtrimLastLine(TScreen * screen, 2746956cc18dSsnj LineData ** ld, 2747956cc18dSsnj CELL * last) 2748d522f475Smrg{ 274920d2c4d2Smrg if (screen->cutNewline && last->row < screen->max_row) { 2750d522f475Smrg last->col = 0; 2751956cc18dSsnj *ld = GET_LINEDATA(screen, ++last->row); 2752d522f475Smrg } else { 2753956cc18dSsnj last->col = LastTextCol(screen, *ld, last->row) + 1; 2754d522f475Smrg } 2755d522f475Smrg} 2756d522f475Smrg 2757d522f475Smrg#if OPT_SELECT_REGEX 2758d522f475Smrg/* 2759d522f475Smrg * Returns the first row of a wrapped line. 2760d522f475Smrg */ 2761d522f475Smrgstatic int 2762d522f475SmrgfirstRowOfLine(TScreen * screen, int row, Bool visible) 2763d522f475Smrg{ 2764956cc18dSsnj LineData *ld = 0; 2765d522f475Smrg int limit = visible ? 0 : -screen->savedlines; 2766d522f475Smrg 2767d522f475Smrg while (row > limit && 2768956cc18dSsnj (ld = GET_LINEDATA(screen, row - 1)) != 0 && 2769956cc18dSsnj LineTstWrapped(ld)) { 2770d522f475Smrg --row; 2771956cc18dSsnj } 2772d522f475Smrg return row; 2773d522f475Smrg} 2774d522f475Smrg 2775d522f475Smrg/* 2776d522f475Smrg * Returns the last row of a wrapped line. 2777d522f475Smrg */ 2778d522f475Smrgstatic int 2779d522f475SmrglastRowOfLine(TScreen * screen, int row) 2780d522f475Smrg{ 2781956cc18dSsnj LineData *ld; 2782956cc18dSsnj 2783d522f475Smrg while (row < screen->max_row && 2784956cc18dSsnj (ld = GET_LINEDATA(screen, row)) != 0 && 2785956cc18dSsnj LineTstWrapped(ld)) { 2786d522f475Smrg ++row; 2787956cc18dSsnj } 2788d522f475Smrg return row; 2789d522f475Smrg} 2790d522f475Smrg 2791d522f475Smrg/* 2792d522f475Smrg * Returns the number of cells on the range of rows. 2793d522f475Smrg */ 2794d522f475Smrgstatic unsigned 2795d522f475SmrglengthOfLines(TScreen * screen, int firstRow, int lastRow) 2796d522f475Smrg{ 2797d522f475Smrg unsigned length = 0; 2798d522f475Smrg int n; 2799d522f475Smrg 2800d522f475Smrg for (n = firstRow; n <= lastRow; ++n) { 2801956cc18dSsnj LineData *ld = GET_LINEDATA(screen, n); 2802956cc18dSsnj int value = LastTextCol(screen, ld, n); 2803d522f475Smrg if (value >= 0) 28042eaa94a1Schristos length += (unsigned) (value + 1); 2805d522f475Smrg } 2806d522f475Smrg return length; 2807d522f475Smrg} 2808d522f475Smrg 2809d522f475Smrg/* 2810d522f475Smrg * Make a copy of the wrapped-line which corresponds to the given row as a 2811d522f475Smrg * string of bytes. Construct an index for the columns from the beginning of 2812d522f475Smrg * the line. 2813d522f475Smrg */ 2814d522f475Smrgstatic char * 2815d522f475Smrgmake_indexed_text(TScreen * screen, int row, unsigned length, int *indexed) 2816d522f475Smrg{ 2817d522f475Smrg Char *result = 0; 281820d2c4d2Smrg size_t need = (length + 1); 2819d522f475Smrg 2820d522f475Smrg /* 2821d522f475Smrg * Get a quick upper bound to the number of bytes needed, if the whole 2822d522f475Smrg * string were UTF-8. 2823d522f475Smrg */ 2824d522f475Smrg if_OPT_WIDE_CHARS(screen, { 2825956cc18dSsnj need *= ((screen->lineExtra + 1) * 6); 2826d522f475Smrg }); 2827d522f475Smrg 2828d522f475Smrg if ((result = TypeCallocN(Char, need + 1)) != 0) { 2829956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 2830d522f475Smrg unsigned used = 0; 2831d522f475Smrg Char *last = result; 2832d522f475Smrg 2833d522f475Smrg do { 2834d522f475Smrg int col = 0; 2835956cc18dSsnj int limit = LastTextCol(screen, ld, row); 2836d522f475Smrg 2837d522f475Smrg while (col <= limit) { 2838d522f475Smrg Char *next = last; 2839956cc18dSsnj unsigned data = ld->charData[col]; 2840d522f475Smrg 284120d2c4d2Smrg assert(col < ld->lineSize); 2842d522f475Smrg /* some internal points may not be drawn */ 2843d522f475Smrg if (data == 0) 2844d522f475Smrg data = ' '; 2845d522f475Smrg 2846d522f475Smrg if_WIDE_OR_NARROW(screen, { 2847d522f475Smrg next = convertToUTF8(last, data); 2848d522f475Smrg } 2849d522f475Smrg , { 2850d522f475Smrg *next++ = CharOf(data); 2851d522f475Smrg }); 2852d522f475Smrg 2853d522f475Smrg if_OPT_WIDE_CHARS(screen, { 2854956cc18dSsnj size_t off; 2855956cc18dSsnj for_each_combData(off, ld) { 2856956cc18dSsnj data = ld->combData[off][col]; 2857956cc18dSsnj if (data == 0) 2858d522f475Smrg break; 2859d522f475Smrg next = convertToUTF8(next, data); 2860d522f475Smrg } 2861d522f475Smrg }); 2862d522f475Smrg 286320d2c4d2Smrg indexed[used] = (int) (last - result); 2864d522f475Smrg *next = 0; 2865d522f475Smrg /* TRACE(("index[%d.%d] %d:%s\n", row, used, indexed[used], last)); */ 2866d522f475Smrg last = next; 2867d522f475Smrg ++used; 2868d522f475Smrg ++col; 286920d2c4d2Smrg indexed[used] = (int) (next - result); 2870d522f475Smrg } 2871d522f475Smrg } while (used < length && 2872956cc18dSsnj LineTstWrapped(ld) && 2873956cc18dSsnj (ld = GET_LINEDATA(screen, ++row)) != 0 && 2874956cc18dSsnj row < screen->max_row); 2875d522f475Smrg } 2876d522f475Smrg /* TRACE(("result:%s\n", result)); */ 2877d522f475Smrg return (char *) result; 2878d522f475Smrg} 2879d522f475Smrg 2880d522f475Smrg/* 2881d522f475Smrg * Find the column given an offset into the character string by using the 2882d522f475Smrg * index constructed in make_indexed_text(). 2883d522f475Smrg */ 2884d522f475Smrgstatic int 2885d522f475SmrgindexToCol(int *indexed, int len, int off) 2886d522f475Smrg{ 2887d522f475Smrg int col = 0; 2888d522f475Smrg while (indexed[col] < len) { 2889d522f475Smrg if (indexed[col] >= off) 2890d522f475Smrg break; 2891d522f475Smrg ++col; 2892d522f475Smrg } 2893d522f475Smrg return col; 2894d522f475Smrg} 2895d522f475Smrg 2896d522f475Smrg/* 2897d522f475Smrg * Given a row number, and a column offset from that (which may be wrapped), 2898d522f475Smrg * set the cell to the actual row/column values. 2899d522f475Smrg */ 2900d522f475Smrgstatic void 2901d522f475SmrgcolumnToCell(TScreen * screen, int row, int col, CELL * cell) 2902d522f475Smrg{ 2903d522f475Smrg while (row < screen->max_row) { 2904956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 2905956cc18dSsnj int last = LastTextCol(screen, ld, row); 2906d522f475Smrg 2907d522f475Smrg /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */ 2908d522f475Smrg if (col <= last) { 2909d522f475Smrg break; 2910d522f475Smrg } 2911d522f475Smrg /* 2912d522f475Smrg * Stop if the current row does not wrap (does not continue the current 2913d522f475Smrg * line). 2914d522f475Smrg */ 2915956cc18dSsnj if (!LineTstWrapped(ld)) { 2916d522f475Smrg col = last + 1; 2917d522f475Smrg break; 2918d522f475Smrg } 2919d522f475Smrg col -= (last + 1); 2920d522f475Smrg ++row; 2921d522f475Smrg } 2922d522f475Smrg if (col < 0) 2923d522f475Smrg col = 0; 2924d522f475Smrg cell->row = row; 2925d522f475Smrg cell->col = col; 2926d522f475Smrg} 2927d522f475Smrg 2928d522f475Smrg/* 2929d522f475Smrg * Given a cell, find the corresponding column offset. 2930d522f475Smrg */ 2931d522f475Smrgstatic int 2932d522f475SmrgcellToColumn(TScreen * screen, CELL * cell) 2933d522f475Smrg{ 2934956cc18dSsnj LineData *ld = 0; 2935d522f475Smrg int col = cell->col; 2936d522f475Smrg int row = firstRowOfLine(screen, cell->row, False); 2937d522f475Smrg while (row < cell->row) { 2938956cc18dSsnj ld = GET_LINEDATA(screen, row); 2939956cc18dSsnj col += LastTextCol(screen, ld, row++); 2940d522f475Smrg } 2941956cc18dSsnj#if OPT_DEC_CHRSET 2942956cc18dSsnj if (ld == 0) 2943956cc18dSsnj ld = GET_LINEDATA(screen, row); 2944956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 2945956cc18dSsnj col /= 2; 2946956cc18dSsnj#endif 2947d522f475Smrg return col; 2948d522f475Smrg} 2949d522f475Smrg 2950d522f475Smrgstatic void 2951d522f475Smrgdo_select_regex(TScreen * screen, CELL * startc, CELL * endc) 2952d522f475Smrg{ 2953956cc18dSsnj LineData *ld = GET_LINEDATA(screen, startc->row); 2954d522f475Smrg int inx = ((screen->numberOfClicks - 1) % screen->maxClicks); 2955d522f475Smrg char *expr = screen->selectExpr[inx]; 2956d522f475Smrg regex_t preg; 2957d522f475Smrg regmatch_t match; 2958d522f475Smrg char *search; 2959d522f475Smrg int *indexed; 2960d522f475Smrg 2961d522f475Smrg TRACE(("Select_REGEX:%s\n", NonNull(expr))); 2962956cc18dSsnj if (okPosition(screen, &ld, startc) && expr != 0) { 2963d522f475Smrg if (regcomp(&preg, expr, REG_EXTENDED) == 0) { 2964d522f475Smrg int firstRow = firstRowOfLine(screen, startc->row, True); 2965d522f475Smrg int lastRow = lastRowOfLine(screen, firstRow); 2966d522f475Smrg unsigned size = lengthOfLines(screen, firstRow, lastRow); 2967d522f475Smrg int actual = cellToColumn(screen, startc); 2968d522f475Smrg 2969d522f475Smrg TRACE(("regcomp ok rows %d..%d bytes %d\n", 2970d522f475Smrg firstRow, lastRow, size)); 2971d522f475Smrg 2972d522f475Smrg if ((indexed = TypeCallocN(int, size + 1)) != 0) { 2973d522f475Smrg if ((search = make_indexed_text(screen, 2974d522f475Smrg firstRow, 2975d522f475Smrg size, 2976d522f475Smrg indexed)) != 0) { 29772eaa94a1Schristos int len = (int) strlen(search); 2978d522f475Smrg int col; 2979d522f475Smrg int best_col = -1; 2980d522f475Smrg int best_len = -1; 2981d522f475Smrg 2982d522f475Smrg for (col = 0; indexed[col] < len; ++col) { 2983d522f475Smrg if (regexec(&preg, 2984d522f475Smrg search + indexed[col], 298520d2c4d2Smrg (size_t) 1, &match, 0) == 0) { 2986d522f475Smrg int start_inx = match.rm_so + indexed[col]; 2987d522f475Smrg int finis_inx = match.rm_eo + indexed[col]; 2988d522f475Smrg int start_col = indexToCol(indexed, len, start_inx); 2989d522f475Smrg int finis_col = indexToCol(indexed, len, finis_inx); 2990d522f475Smrg 2991d522f475Smrg if (start_col <= actual && 2992d522f475Smrg actual < finis_col) { 2993d522f475Smrg int test = finis_col - start_col; 2994d522f475Smrg if (best_len < test) { 2995d522f475Smrg best_len = test; 2996d522f475Smrg best_col = start_col; 2997d522f475Smrg TRACE(("match column %d len %d\n", 2998d522f475Smrg best_col, 2999d522f475Smrg best_len)); 3000d522f475Smrg } 3001d522f475Smrg } 3002d522f475Smrg } 3003d522f475Smrg } 3004d522f475Smrg if (best_col >= 0) { 3005d522f475Smrg int best_nxt = best_col + best_len; 3006d522f475Smrg columnToCell(screen, firstRow, best_col, startc); 3007d522f475Smrg columnToCell(screen, firstRow, best_nxt, endc); 3008d522f475Smrg TRACE(("search::%s\n", search)); 3009d522f475Smrg TRACE(("indexed:%d..%d -> %d..%d\n", 3010d522f475Smrg best_col, best_nxt, 3011d522f475Smrg indexed[best_col], 3012d522f475Smrg indexed[best_nxt])); 3013d522f475Smrg TRACE(("matched:%d:%s\n", 3014d522f475Smrg indexed[best_nxt] + 1 - 3015d522f475Smrg indexed[best_col], 3016956cc18dSsnj visibleChars((Char *) (search + indexed[best_col]), 3017d522f475Smrg (unsigned) (indexed[best_nxt] + 3018d522f475Smrg 1 - 3019d522f475Smrg indexed[best_col])))); 3020d522f475Smrg } 3021d522f475Smrg free(search); 3022d522f475Smrg } 3023d522f475Smrg free(indexed); 3024956cc18dSsnj#if OPT_DEC_CHRSET 3025956cc18dSsnj if ((ld = GET_LINEDATA(screen, startc->row)) != 0) { 3026956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3027956cc18dSsnj startc->col *= 2; 3028956cc18dSsnj } 3029956cc18dSsnj if ((ld = GET_LINEDATA(screen, endc->row)) != 0) { 3030956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3031956cc18dSsnj endc->col *= 2; 3032956cc18dSsnj } 3033956cc18dSsnj#endif 3034d522f475Smrg } 3035d522f475Smrg regfree(&preg); 3036d522f475Smrg } 3037d522f475Smrg } 3038d522f475Smrg} 3039d522f475Smrg#endif /* OPT_SELECT_REGEX */ 3040d522f475Smrg 3041956cc18dSsnj#define InitRow(name) \ 3042956cc18dSsnj ld.name = GET_LINEDATA(screen, screen->name.row) 3043956cc18dSsnj 3044956cc18dSsnj#define NextRow(name) \ 3045956cc18dSsnj ld.name = GET_LINEDATA(screen, ++screen->name.row) 3046956cc18dSsnj 3047956cc18dSsnj#define PrevRow(name) \ 3048956cc18dSsnj ld.name = GET_LINEDATA(screen, --screen->name.row) 3049956cc18dSsnj 305020d2c4d2Smrg#define MoreRows(name) \ 305120d2c4d2Smrg (screen->name.row < screen->max_row) 305220d2c4d2Smrg 3053956cc18dSsnj#define isPrevWrapped(name) \ 3054956cc18dSsnj (screen->name.row > 0 \ 3055956cc18dSsnj && (ltmp = GET_LINEDATA(screen, screen->name.row - 1)) != 0 \ 3056956cc18dSsnj && LineTstWrapped(ltmp)) 3057956cc18dSsnj 3058d522f475Smrg/* 3059d522f475Smrg * sets startSel endSel 3060d522f475Smrg * ensuring that they have legal values 3061d522f475Smrg */ 3062d522f475Smrgstatic void 3063d522f475SmrgComputeSelect(XtermWidget xw, 3064d522f475Smrg CELL * startc, 3065d522f475Smrg CELL * endc, 3066d522f475Smrg Bool extend) 3067d522f475Smrg{ 3068956cc18dSsnj TScreen *screen = TScreenOf(xw); 3069956cc18dSsnj 3070d522f475Smrg int length; 3071d522f475Smrg int cclass; 3072d522f475Smrg CELL first = *startc; 3073d522f475Smrg CELL last = *endc; 3074956cc18dSsnj Boolean ignored = False; 3075956cc18dSsnj 3076956cc18dSsnj struct { 3077956cc18dSsnj LineData *startSel; 3078956cc18dSsnj LineData *endSel; 3079956cc18dSsnj } ld; 3080956cc18dSsnj LineData *ltmp; 3081d522f475Smrg 3082d522f475Smrg TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n", 3083d522f475Smrg first.row, first.col, 3084d522f475Smrg last.row, last.col, 3085d522f475Smrg extend ? "" : "no")); 3086d522f475Smrg 3087d522f475Smrg#if OPT_WIDE_CHARS 3088d522f475Smrg if (first.col > 1 3089d522f475Smrg && isWideCell(first.row, first.col - 1) 3090d522f475Smrg && XTERM_CELL(first.row, first.col - 0) == HIDDEN_CHAR) { 309120d2c4d2Smrg TRACE(("Adjusting start. Changing downwards from %i.\n", first.col)); 3092d522f475Smrg first.col -= 1; 3093d522f475Smrg if (last.col == (first.col + 1)) 3094d522f475Smrg last.col--; 3095d522f475Smrg } 3096d522f475Smrg 3097d522f475Smrg if (last.col > 1 3098d522f475Smrg && isWideCell(last.row, last.col - 1) 3099d522f475Smrg && XTERM_CELL(last.row, last.col) == HIDDEN_CHAR) { 3100d522f475Smrg last.col += 1; 3101d522f475Smrg } 3102d522f475Smrg#endif 3103d522f475Smrg 3104d522f475Smrg if (Coordinate(screen, &first) <= Coordinate(screen, &last)) { 3105d522f475Smrg screen->startSel = screen->startRaw = first; 3106d522f475Smrg screen->endSel = screen->endRaw = last; 3107d522f475Smrg } else { /* Swap them */ 3108d522f475Smrg screen->startSel = screen->startRaw = last; 3109d522f475Smrg screen->endSel = screen->endRaw = first; 3110d522f475Smrg } 3111d522f475Smrg 3112956cc18dSsnj InitRow(startSel); 3113956cc18dSsnj InitRow(endSel); 3114956cc18dSsnj 3115d522f475Smrg switch (screen->selectUnit) { 3116d522f475Smrg case Select_CHAR: 3117956cc18dSsnj (void) okPosition(screen, &(ld.startSel), &(screen->startSel)); 3118956cc18dSsnj (void) okPosition(screen, &(ld.endSel), &(screen->endSel)); 3119d522f475Smrg break; 3120d522f475Smrg 3121d522f475Smrg case Select_WORD: 3122d522f475Smrg TRACE(("Select_WORD\n")); 3123956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 3124956cc18dSsnj cclass = CClassOf(startSel); 3125d522f475Smrg do { 3126d522f475Smrg --screen->startSel.col; 3127956cc18dSsnj if (screen->startSel.col < 0 3128956cc18dSsnj && isPrevWrapped(startSel)) { 3129956cc18dSsnj PrevRow(startSel); 3130956cc18dSsnj screen->startSel.col = LastTextCol(screen, ld.startSel, screen->startSel.row); 3131d522f475Smrg } 3132d522f475Smrg } while (screen->startSel.col >= 0 3133956cc18dSsnj && CClassSelects(startSel, cclass)); 3134d522f475Smrg ++screen->startSel.col; 3135d522f475Smrg } 3136d522f475Smrg#if OPT_WIDE_CHARS 3137d522f475Smrg if (screen->startSel.col 3138d522f475Smrg && XTERM_CELL(screen->startSel.row, 3139d522f475Smrg screen->startSel.col) == HIDDEN_CHAR) 3140d522f475Smrg screen->startSel.col++; 3141d522f475Smrg#endif 3142d522f475Smrg 3143956cc18dSsnj if (okPosition(screen, &(ld.endSel), &(screen->endSel))) { 3144956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 3145956cc18dSsnj cclass = CClassOf(endSel); 3146d522f475Smrg do { 3147d522f475Smrg ++screen->endSel.col; 3148d522f475Smrg if (screen->endSel.col > length 3149956cc18dSsnj && LineTstWrapped(ld.endSel)) { 315020d2c4d2Smrg if (!MoreRows(endSel)) 315120d2c4d2Smrg break; 3152d522f475Smrg screen->endSel.col = 0; 3153956cc18dSsnj NextRow(endSel); 3154956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 3155d522f475Smrg } 3156d522f475Smrg } while (screen->endSel.col <= length 3157956cc18dSsnj && CClassSelects(endSel, cclass)); 3158d522f475Smrg /* Word-select selects if pointing to any char in "word", 3159d522f475Smrg * especially note that it includes the last character in a word. 3160d522f475Smrg * So we do no --endSel.col and do special eol handling. 3161d522f475Smrg */ 316220d2c4d2Smrg if (screen->endSel.col > length + 1 316320d2c4d2Smrg && MoreRows(endSel)) { 3164d522f475Smrg screen->endSel.col = 0; 3165956cc18dSsnj NextRow(endSel); 3166d522f475Smrg } 3167d522f475Smrg } 3168d522f475Smrg#if OPT_WIDE_CHARS 3169d522f475Smrg if (screen->endSel.col 3170d522f475Smrg && XTERM_CELL(screen->endSel.row, 3171d522f475Smrg screen->endSel.col) == HIDDEN_CHAR) 3172d522f475Smrg screen->endSel.col++; 3173d522f475Smrg#endif 3174d522f475Smrg 3175d522f475Smrg screen->saveStartW = screen->startSel; 3176d522f475Smrg break; 3177d522f475Smrg 3178d522f475Smrg case Select_LINE: 3179d522f475Smrg TRACE(("Select_LINE\n")); 318020d2c4d2Smrg while (LineTstWrapped(ld.endSel) 318120d2c4d2Smrg && MoreRows(endSel)) { 3182956cc18dSsnj NextRow(endSel); 3183d522f475Smrg } 3184d522f475Smrg if (screen->cutToBeginningOfLine 3185d522f475Smrg || screen->startSel.row < screen->saveStartW.row) { 3186d522f475Smrg screen->startSel.col = 0; 3187956cc18dSsnj while (isPrevWrapped(startSel)) { 3188956cc18dSsnj PrevRow(startSel); 3189d522f475Smrg } 3190d522f475Smrg } else if (!extend) { 3191d522f475Smrg if ((first.row < screen->saveStartW.row) 3192d522f475Smrg || (isSameRow(&first, &(screen->saveStartW)) 3193d522f475Smrg && first.col < screen->saveStartW.col)) { 3194d522f475Smrg screen->startSel.col = 0; 3195956cc18dSsnj while (isPrevWrapped(startSel)) { 3196956cc18dSsnj PrevRow(startSel); 3197d522f475Smrg } 3198d522f475Smrg } else { 3199d522f475Smrg screen->startSel = screen->saveStartW; 3200d522f475Smrg } 3201d522f475Smrg } 3202956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 3203d522f475Smrg break; 3204d522f475Smrg 3205d522f475Smrg case Select_GROUP: /* paragraph */ 3206d522f475Smrg TRACE(("Select_GROUP\n")); 3207956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 3208d522f475Smrg /* scan backward for beginning of group */ 3209d522f475Smrg while (screen->startSel.row > 0 && 3210956cc18dSsnj (LastTextCol(screen, ld.startSel, screen->startSel.row - 3211956cc18dSsnj 1) > 0 || 3212956cc18dSsnj isPrevWrapped(startSel))) { 3213956cc18dSsnj PrevRow(startSel); 3214d522f475Smrg } 3215d522f475Smrg screen->startSel.col = 0; 3216d522f475Smrg /* scan forward for end of group */ 321720d2c4d2Smrg while (MoreRows(endSel) && 3218956cc18dSsnj (LastTextCol(screen, ld.endSel, screen->endSel.row + 1) > 3219956cc18dSsnj 0 || 3220956cc18dSsnj LineTstWrapped(ld.endSel))) { 3221956cc18dSsnj NextRow(endSel); 3222d522f475Smrg } 3223956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 3224d522f475Smrg } 3225d522f475Smrg break; 3226d522f475Smrg 3227d522f475Smrg case Select_PAGE: /* everything one can see */ 3228d522f475Smrg TRACE(("Select_PAGE\n")); 3229d522f475Smrg screen->startSel.row = 0; 3230d522f475Smrg screen->startSel.col = 0; 323120d2c4d2Smrg screen->endSel.row = MaxRows(screen); 3232d522f475Smrg screen->endSel.col = 0; 3233d522f475Smrg break; 3234d522f475Smrg 3235d522f475Smrg case Select_ALL: /* counts scrollback if in normal screen */ 3236d522f475Smrg TRACE(("Select_ALL\n")); 3237d522f475Smrg screen->startSel.row = -screen->savedlines; 3238d522f475Smrg screen->startSel.col = 0; 323920d2c4d2Smrg screen->endSel.row = MaxRows(screen); 3240d522f475Smrg screen->endSel.col = 0; 3241d522f475Smrg break; 3242d522f475Smrg 3243d522f475Smrg#if OPT_SELECT_REGEX 3244d522f475Smrg case Select_REGEX: 3245d522f475Smrg do_select_regex(screen, &(screen->startSel), &(screen->endSel)); 3246d522f475Smrg break; 3247d522f475Smrg#endif 3248d522f475Smrg 3249d522f475Smrg case NSELECTUNITS: /* always ignore */ 3250956cc18dSsnj ignored = True; 3251956cc18dSsnj break; 3252d522f475Smrg } 3253d522f475Smrg 3254956cc18dSsnj if (!ignored) { 3255956cc18dSsnj /* check boundaries */ 3256956cc18dSsnj ScrollSelection(screen, 0, False); 3257956cc18dSsnj TrackText(xw, &(screen->startSel), &(screen->endSel)); 3258956cc18dSsnj } 3259d522f475Smrg 3260d522f475Smrg return; 3261d522f475Smrg} 3262d522f475Smrg 3263d522f475Smrg/* Guaranteed (first.row, first.col) <= (last.row, last.col) */ 3264d522f475Smrgstatic void 3265d522f475SmrgTrackText(XtermWidget xw, 3266d522f475Smrg const CELL * firstp, 3267d522f475Smrg const CELL * lastp) 3268d522f475Smrg{ 3269956cc18dSsnj TScreen *screen = TScreenOf(xw); 3270d522f475Smrg int from, to; 3271d522f475Smrg CELL old_start, old_end; 3272d522f475Smrg CELL first = *firstp; 3273d522f475Smrg CELL last = *lastp; 3274d522f475Smrg 3275d522f475Smrg TRACE(("TrackText(first=%d,%d, last=%d,%d)\n", 3276d522f475Smrg first.row, first.col, last.row, last.col)); 3277d522f475Smrg 3278d522f475Smrg old_start = screen->startH; 3279d522f475Smrg old_end = screen->endH; 3280d522f475Smrg if (isSameCELL(&first, &old_start) && 3281d522f475Smrg isSameCELL(&last, &old_end)) 3282d522f475Smrg return; 3283d522f475Smrg screen->startH = first; 3284d522f475Smrg screen->endH = last; 3285d522f475Smrg from = Coordinate(screen, &screen->startH); 3286d522f475Smrg to = Coordinate(screen, &screen->endH); 3287d522f475Smrg if (to <= screen->startHCoord || from > screen->endHCoord) { 3288d522f475Smrg /* No overlap whatsoever between old and new hilite */ 3289d522f475Smrg ReHiliteText(xw, &old_start, &old_end); 3290d522f475Smrg ReHiliteText(xw, &first, &last); 3291d522f475Smrg } else { 3292d522f475Smrg if (from < screen->startHCoord) { 3293d522f475Smrg /* Extend left end */ 3294d522f475Smrg ReHiliteText(xw, &first, &old_start); 3295d522f475Smrg } else if (from > screen->startHCoord) { 3296d522f475Smrg /* Shorten left end */ 3297d522f475Smrg ReHiliteText(xw, &old_start, &first); 3298d522f475Smrg } 3299d522f475Smrg if (to > screen->endHCoord) { 3300d522f475Smrg /* Extend right end */ 3301d522f475Smrg ReHiliteText(xw, &old_end, &last); 3302d522f475Smrg } else if (to < screen->endHCoord) { 3303d522f475Smrg /* Shorten right end */ 3304d522f475Smrg ReHiliteText(xw, &last, &old_end); 3305d522f475Smrg } 3306d522f475Smrg } 3307d522f475Smrg screen->startHCoord = from; 3308d522f475Smrg screen->endHCoord = to; 3309d522f475Smrg} 3310d522f475Smrg 3311d522f475Smrg/* Guaranteed that (first->row, first->col) <= (last->row, last->col) */ 3312d522f475Smrgstatic void 3313d522f475SmrgReHiliteText(XtermWidget xw, 3314d522f475Smrg CELL * firstp, 3315d522f475Smrg CELL * lastp) 3316d522f475Smrg{ 3317956cc18dSsnj TScreen *screen = TScreenOf(xw); 3318d522f475Smrg int i; 3319d522f475Smrg CELL first = *firstp; 3320d522f475Smrg CELL last = *lastp; 3321d522f475Smrg 3322d522f475Smrg TRACE(("ReHiliteText from %d.%d to %d.%d\n", 3323d522f475Smrg first.row, first.col, last.row, last.col)); 3324d522f475Smrg 3325d522f475Smrg if (first.row < 0) 3326d522f475Smrg first.row = first.col = 0; 3327d522f475Smrg else if (first.row > screen->max_row) 3328d522f475Smrg return; /* nothing to do, since last.row >= first.row */ 3329d522f475Smrg 3330d522f475Smrg if (last.row < 0) 3331d522f475Smrg return; /* nothing to do, since first.row <= last.row */ 3332d522f475Smrg else if (last.row > screen->max_row) { 3333d522f475Smrg last.row = screen->max_row; 3334d522f475Smrg last.col = MaxCols(screen); 3335d522f475Smrg } 3336d522f475Smrg if (isSameCELL(&first, &last)) 3337d522f475Smrg return; 3338d522f475Smrg 3339d522f475Smrg if (!isSameRow(&first, &last)) { /* do multiple rows */ 3340d522f475Smrg if ((i = screen->max_col - first.col + 1) > 0) { /* first row */ 3341d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, i, True); 3342d522f475Smrg } 3343d522f475Smrg if ((i = last.row - first.row - 1) > 0) { /* middle rows */ 3344d522f475Smrg ScrnRefresh(xw, first.row + 1, 0, i, MaxCols(screen), True); 3345d522f475Smrg } 3346d522f475Smrg if (last.col > 0 && last.row <= screen->max_row) { /* last row */ 3347d522f475Smrg ScrnRefresh(xw, last.row, 0, 1, last.col, True); 3348d522f475Smrg } 3349d522f475Smrg } else { /* do single row */ 3350d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, last.col - first.col, True); 3351d522f475Smrg } 3352d522f475Smrg} 3353d522f475Smrg 3354d522f475Smrg/* 3355d522f475Smrg * Guaranteed that (cellc->row, cellc->col) <= (cell->row, cell->col), and that both points are valid 3356d522f475Smrg * (may have cell->row = screen->max_row+1, cell->col = 0). 3357d522f475Smrg */ 3358d522f475Smrgstatic void 3359d522f475SmrgSaltTextAway(XtermWidget xw, 3360d522f475Smrg CELL * cellc, 3361d522f475Smrg CELL * cell, 3362d522f475Smrg String * params, /* selections */ 3363d522f475Smrg Cardinal num_params) 3364d522f475Smrg{ 3365956cc18dSsnj TScreen *screen = TScreenOf(xw); 3366d522f475Smrg int i, j = 0; 3367d522f475Smrg int eol; 3368956cc18dSsnj int tmp; 3369d522f475Smrg Char *line; 3370d522f475Smrg Char *lp; 3371d522f475Smrg CELL first = *cellc; 3372d522f475Smrg CELL last = *cell; 3373d522f475Smrg 3374d522f475Smrg if (isSameRow(&first, &last) && first.col > last.col) { 3375956cc18dSsnj EXCHANGE(first.col, last.col, tmp); 3376d522f475Smrg } 3377d522f475Smrg 3378d522f475Smrg --last.col; 3379d522f475Smrg /* first we need to know how long the string is before we can save it */ 3380d522f475Smrg 3381d522f475Smrg if (isSameRow(&last, &first)) { 3382d522f475Smrg j = Length(screen, first.row, first.col, last.col); 3383d522f475Smrg } else { /* two cases, cut is on same line, cut spans multiple lines */ 3384d522f475Smrg j += Length(screen, first.row, first.col, screen->max_col) + 1; 3385d522f475Smrg for (i = first.row + 1; i < last.row; i++) 3386d522f475Smrg j += Length(screen, i, 0, screen->max_col) + 1; 3387d522f475Smrg if (last.col >= 0) 3388d522f475Smrg j += Length(screen, last.row, 0, last.col); 3389d522f475Smrg } 3390d522f475Smrg 3391d522f475Smrg /* UTF-8 may require more space */ 3392d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3393d522f475Smrg j *= 4; 3394d522f475Smrg }); 3395d522f475Smrg 3396d522f475Smrg /* now get some memory to save it in */ 3397d522f475Smrg 3398d522f475Smrg if (screen->selection_size <= j) { 339920d2c4d2Smrg if ((line = (Char *) malloc((size_t) j + 1)) == 0) 3400d522f475Smrg SysError(ERROR_BMALLOC2); 3401d522f475Smrg XtFree((char *) screen->selection_data); 3402d522f475Smrg screen->selection_data = line; 3403d522f475Smrg screen->selection_size = j + 1; 3404d522f475Smrg } else { 3405d522f475Smrg line = screen->selection_data; 3406d522f475Smrg } 3407d522f475Smrg 3408d522f475Smrg if ((line == 0) 3409d522f475Smrg || (j < 0)) 3410d522f475Smrg return; 3411d522f475Smrg 3412d522f475Smrg line[j] = '\0'; /* make sure it is null terminated */ 3413d522f475Smrg lp = line; /* lp points to where to save the text */ 3414d522f475Smrg if (isSameRow(&last, &first)) { 3415d522f475Smrg lp = SaveText(screen, last.row, first.col, last.col, lp, &eol); 3416d522f475Smrg } else { 3417d522f475Smrg lp = SaveText(screen, first.row, first.col, screen->max_col, lp, &eol); 3418d522f475Smrg if (eol) 3419d522f475Smrg *lp++ = '\n'; /* put in newline at end of line */ 3420d522f475Smrg for (i = first.row + 1; i < last.row; i++) { 3421d522f475Smrg lp = SaveText(screen, i, 0, screen->max_col, lp, &eol); 3422d522f475Smrg if (eol) 3423d522f475Smrg *lp++ = '\n'; 3424d522f475Smrg } 3425d522f475Smrg if (last.col >= 0) 3426d522f475Smrg lp = SaveText(screen, last.row, 0, last.col, lp, &eol); 3427d522f475Smrg } 3428d522f475Smrg *lp = '\0'; /* make sure we have end marked */ 3429d522f475Smrg 3430956cc18dSsnj TRACE(("Salted TEXT:%d:%s\n", (int) (lp - line), 3431956cc18dSsnj visibleChars(line, (unsigned) (lp - line)))); 3432d522f475Smrg 34332eaa94a1Schristos screen->selection_length = (unsigned long) (lp - line); 3434d522f475Smrg _OwnSelection(xw, params, num_params); 3435d522f475Smrg} 3436d522f475Smrg 3437d522f475Smrg#if OPT_PASTE64 3438d522f475Smrgvoid 3439d522f475SmrgClearSelectionBuffer(TScreen * screen) 3440d522f475Smrg{ 3441d522f475Smrg screen->selection_length = 0; 3442d522f475Smrg screen->base64_count = 0; 3443d522f475Smrg} 3444d522f475Smrg 3445d522f475Smrgstatic void 344620d2c4d2SmrgAppendStrToSelectionBuffer(TScreen * screen, Char * text, size_t len) 3447d522f475Smrg{ 3448d522f475Smrg if (len != 0) { 34492eaa94a1Schristos int j = (int) (screen->selection_length + len); /* New length */ 3450d522f475Smrg int k = j + (j >> 2) + 80; /* New size if we grow buffer: grow by ~50% */ 3451d522f475Smrg if (j + 1 >= screen->selection_size) { 3452d522f475Smrg if (!screen->selection_length) { 3453d522f475Smrg /* New buffer */ 3454d522f475Smrg Char *line; 345520d2c4d2Smrg if ((line = (Char *) malloc((size_t) k)) == 0) 3456d522f475Smrg SysError(ERROR_BMALLOC2); 3457d522f475Smrg XtFree((char *) screen->selection_data); 3458d522f475Smrg screen->selection_data = line; 3459d522f475Smrg } else { 3460d522f475Smrg /* Realloc buffer */ 3461d522f475Smrg screen->selection_data = (Char *) 3462d522f475Smrg realloc(screen->selection_data, 346320d2c4d2Smrg (size_t) k); 3464d522f475Smrg if (screen->selection_data == 0) 3465d522f475Smrg SysError(ERROR_BMALLOC2); 3466d522f475Smrg } 3467d522f475Smrg screen->selection_size = k; 3468d522f475Smrg } 346920d2c4d2Smrg if (screen->selection_data != 0) { 347020d2c4d2Smrg memcpy(screen->selection_data + screen->selection_length, text, len); 347120d2c4d2Smrg screen->selection_length += len; 347220d2c4d2Smrg screen->selection_data[screen->selection_length] = 0; 347320d2c4d2Smrg } 3474d522f475Smrg } 3475d522f475Smrg} 3476d522f475Smrg 3477d522f475Smrgvoid 3478d522f475SmrgAppendToSelectionBuffer(TScreen * screen, unsigned c) 3479d522f475Smrg{ 34802eaa94a1Schristos unsigned six; 3481d522f475Smrg Char ch; 3482d522f475Smrg 3483d522f475Smrg /* Decode base64 character */ 3484d522f475Smrg if (c >= 'A' && c <= 'Z') 3485d522f475Smrg six = c - 'A'; 3486d522f475Smrg else if (c >= 'a' && c <= 'z') 3487d522f475Smrg six = c - 'a' + 26; 3488d522f475Smrg else if (c >= '0' && c <= '9') 3489d522f475Smrg six = c - '0' + 52; 3490d522f475Smrg else if (c == '+') 3491d522f475Smrg six = 62; 3492d522f475Smrg else if (c == '/') 3493d522f475Smrg six = 63; 3494d522f475Smrg else 3495d522f475Smrg return; 3496d522f475Smrg 3497d522f475Smrg /* Accumulate bytes */ 3498d522f475Smrg switch (screen->base64_count) { 3499d522f475Smrg case 0: 3500d522f475Smrg screen->base64_accu = six; 3501d522f475Smrg screen->base64_count = 6; 3502d522f475Smrg break; 3503d522f475Smrg 3504d522f475Smrg case 2: 35052eaa94a1Schristos ch = CharOf((screen->base64_accu << 6) + six); 3506d522f475Smrg screen->base64_count = 0; 350720d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3508d522f475Smrg break; 3509d522f475Smrg 3510d522f475Smrg case 4: 35112eaa94a1Schristos ch = CharOf((screen->base64_accu << 4) + (six >> 2)); 3512d522f475Smrg screen->base64_accu = (six & 0x3); 3513d522f475Smrg screen->base64_count = 2; 351420d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3515d522f475Smrg break; 3516d522f475Smrg 3517d522f475Smrg case 6: 35182eaa94a1Schristos ch = CharOf((screen->base64_accu << 2) + (six >> 4)); 3519d522f475Smrg screen->base64_accu = (six & 0xF); 3520d522f475Smrg screen->base64_count = 4; 352120d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3522d522f475Smrg break; 3523d522f475Smrg } 3524d522f475Smrg} 3525d522f475Smrg 3526d522f475Smrgvoid 352720d2c4d2SmrgCompleteSelection(XtermWidget xw, String * args, Cardinal len) 3528d522f475Smrg{ 3529956cc18dSsnj TScreen *screen = TScreenOf(xw); 3530956cc18dSsnj 3531956cc18dSsnj screen->base64_count = 0; 3532956cc18dSsnj screen->base64_accu = 0; 3533d522f475Smrg _OwnSelection(xw, args, len); 3534d522f475Smrg} 3535d522f475Smrg#endif /* OPT_PASTE64 */ 3536d522f475Smrg 3537d522f475Smrgstatic Bool 3538d522f475Smrg_ConvertSelectionHelper(Widget w, 3539d522f475Smrg Atom * type, 3540d522f475Smrg XtPointer *value, 3541d522f475Smrg unsigned long *length, 3542d522f475Smrg int *format, 3543d522f475Smrg int (*conversion_function) (Display *, 3544d522f475Smrg char **, int, 3545d522f475Smrg XICCEncodingStyle, 3546d522f475Smrg XTextProperty *), 3547d522f475Smrg XICCEncodingStyle conversion_style) 3548d522f475Smrg{ 3549956cc18dSsnj XtermWidget xw; 3550956cc18dSsnj 3551956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3552956cc18dSsnj TScreen *screen = TScreenOf(xw); 3553d522f475Smrg Display *dpy = XtDisplay(w); 3554d522f475Smrg XTextProperty textprop; 3555d522f475Smrg char *the_data = (char *) screen->selection_data; 3556d522f475Smrg 3557d522f475Smrg if (conversion_function(dpy, &the_data, 1, 3558d522f475Smrg conversion_style, 3559d522f475Smrg &textprop) >= Success) { 3560d522f475Smrg *value = (XtPointer) textprop.value; 3561d522f475Smrg *length = textprop.nitems; 3562d522f475Smrg *type = textprop.encoding; 3563d522f475Smrg *format = textprop.format; 3564d522f475Smrg return True; 3565d522f475Smrg } 3566d522f475Smrg } 3567d522f475Smrg return False; 3568d522f475Smrg} 3569d522f475Smrg 35702eaa94a1Schristosstatic Boolean 35712eaa94a1SchristosSaveConvertedLength(XtPointer *target, unsigned long source) 35722eaa94a1Schristos{ 35732eaa94a1Schristos Boolean result = False; 35742eaa94a1Schristos 35752eaa94a1Schristos *target = XtMalloc(4); 35762eaa94a1Schristos if (*target != 0) { 35772eaa94a1Schristos result = True; 35782eaa94a1Schristos if (sizeof(unsigned long) == 4) { 35792eaa94a1Schristos *(unsigned long *) *target = source; 35802eaa94a1Schristos } else if (sizeof(unsigned) == 4) { 358120d2c4d2Smrg *(unsigned *) *target = (unsigned) source; 35822eaa94a1Schristos } else if (sizeof(unsigned short) == 4) { 35832eaa94a1Schristos *(unsigned short *) *target = (unsigned short) source; 35842eaa94a1Schristos } else { 35852eaa94a1Schristos /* FIXME - does this depend on byte-order? */ 35862eaa94a1Schristos unsigned long temp = source; 358720d2c4d2Smrg memcpy((char *) *target, 358820d2c4d2Smrg ((char *) &temp) + sizeof(temp) - 4, 358920d2c4d2Smrg (size_t) 4); 35902eaa94a1Schristos } 35912eaa94a1Schristos } 35922eaa94a1Schristos return result; 35932eaa94a1Schristos} 35942eaa94a1Schristos 3595d522f475Smrgstatic Boolean 3596d522f475SmrgConvertSelection(Widget w, 3597d522f475Smrg Atom * selection, 3598d522f475Smrg Atom * target, 3599d522f475Smrg Atom * type, 3600d522f475Smrg XtPointer *value, 3601d522f475Smrg unsigned long *length, 3602d522f475Smrg int *format) 3603d522f475Smrg{ 3604d522f475Smrg Display *dpy = XtDisplay(w); 3605d522f475Smrg TScreen *screen; 3606d522f475Smrg Bool result = False; 3607d522f475Smrg 3608956cc18dSsnj XtermWidget xw; 3609956cc18dSsnj 3610956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 3611d522f475Smrg return False; 3612d522f475Smrg 3613956cc18dSsnj screen = TScreenOf(xw); 3614d522f475Smrg 3615d522f475Smrg if (screen->selection_data == NULL) 3616d522f475Smrg return False; /* can this happen? */ 3617d522f475Smrg 3618956cc18dSsnj TRACE(("ConvertSelection %s\n", 3619956cc18dSsnj visibleSelectionTarget(dpy, *target))); 3620956cc18dSsnj 3621d522f475Smrg if (*target == XA_TARGETS(dpy)) { 3622d522f475Smrg Atom *allocP; 3623d522f475Smrg Atom *targetP; 3624d522f475Smrg Atom *std_targets; 3625d522f475Smrg XPointer std_return = 0; 3626d522f475Smrg unsigned long std_length; 3627d522f475Smrg 3628d522f475Smrg if (XmuConvertStandardSelection(w, screen->selection_time, selection, 3629d522f475Smrg target, type, &std_return, 3630d522f475Smrg &std_length, format)) { 3631956cc18dSsnj Atom *my_targets = _SelectionTargets(w); 3632956cc18dSsnj 3633956cc18dSsnj TRACE(("XmuConvertStandardSelection - success\n")); 3634a1f3da82Smrg std_targets = (Atom *) (void *) (std_return); 3635d522f475Smrg *length = std_length + 6; 3636d522f475Smrg 3637a1f3da82Smrg targetP = TypeXtMallocN(Atom, *length); 3638d522f475Smrg allocP = targetP; 3639d522f475Smrg 3640d522f475Smrg *value = (XtPointer) targetP; 3641d522f475Smrg 3642956cc18dSsnj while (*my_targets != None) { 3643956cc18dSsnj *targetP++ = *my_targets++; 3644956cc18dSsnj } 3645d522f475Smrg *targetP++ = XA_LENGTH(dpy); 3646d522f475Smrg *targetP++ = XA_LIST_LENGTH(dpy); 3647d522f475Smrg 36482eaa94a1Schristos *length = std_length + (unsigned long) (targetP - allocP); 3649d522f475Smrg 3650d522f475Smrg memcpy(targetP, std_targets, sizeof(Atom) * std_length); 3651d522f475Smrg XtFree((char *) std_targets); 3652d522f475Smrg *type = XA_ATOM; 3653d522f475Smrg *format = 32; 3654d522f475Smrg result = True; 3655956cc18dSsnj } else { 3656956cc18dSsnj TRACE(("XmuConvertStandardSelection - failed\n")); 3657d522f475Smrg } 3658d522f475Smrg } 3659d522f475Smrg#if OPT_WIDE_CHARS 3660d522f475Smrg else if (screen->wide_chars && *target == XA_STRING) { 3661d522f475Smrg result = 3662d522f475Smrg _ConvertSelectionHelper(w, 3663d522f475Smrg type, value, length, format, 3664d522f475Smrg Xutf8TextListToTextProperty, 3665d522f475Smrg XStringStyle); 3666956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3667d522f475Smrg } else if (screen->wide_chars && *target == XA_UTF8_STRING(dpy)) { 3668d522f475Smrg result = 3669d522f475Smrg _ConvertSelectionHelper(w, 3670d522f475Smrg type, value, length, format, 3671d522f475Smrg Xutf8TextListToTextProperty, 3672d522f475Smrg XUTF8StringStyle); 3673956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3674d522f475Smrg } else if (screen->wide_chars && *target == XA_TEXT(dpy)) { 3675d522f475Smrg result = 3676d522f475Smrg _ConvertSelectionHelper(w, 3677d522f475Smrg type, value, length, format, 3678d522f475Smrg Xutf8TextListToTextProperty, 3679d522f475Smrg XStdICCTextStyle); 3680956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3681d522f475Smrg } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(dpy)) { 3682d522f475Smrg result = 3683d522f475Smrg _ConvertSelectionHelper(w, 3684d522f475Smrg type, value, length, format, 3685d522f475Smrg Xutf8TextListToTextProperty, 3686d522f475Smrg XCompoundTextStyle); 3687956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3688d522f475Smrg } 3689d522f475Smrg#endif 3690d522f475Smrg 3691d522f475Smrg else if (*target == XA_STRING) { /* not wide_chars */ 3692d522f475Smrg /* We can only reach this point if the selection requestor 3693d522f475Smrg requested STRING before any of TEXT, COMPOUND_TEXT or 3694d522f475Smrg UTF8_STRING. We therefore assume that the requestor is not 3695d522f475Smrg properly internationalised, and dump raw eight-bit data 3696d522f475Smrg with no conversion into the selection. Yes, this breaks 3697d522f475Smrg the ICCCM in non-Latin-1 locales. */ 3698d522f475Smrg *type = XA_STRING; 3699d522f475Smrg *value = (XtPointer) screen->selection_data; 3700d522f475Smrg *length = screen->selection_length; 3701d522f475Smrg *format = 8; 3702d522f475Smrg result = True; 3703956cc18dSsnj TRACE(("...raw 8-bit data:%d\n", result)); 3704d522f475Smrg } else if (*target == XA_TEXT(dpy)) { /* not wide_chars */ 3705d522f475Smrg result = 3706d522f475Smrg _ConvertSelectionHelper(w, 3707d522f475Smrg type, value, length, format, 3708d522f475Smrg XmbTextListToTextProperty, 3709d522f475Smrg XStdICCTextStyle); 3710956cc18dSsnj TRACE(("...XmbTextListToTextProperty(StdICC):%d\n", result)); 3711d522f475Smrg } else if (*target == XA_COMPOUND_TEXT(dpy)) { /* not wide_chars */ 3712d522f475Smrg result = 3713d522f475Smrg _ConvertSelectionHelper(w, 3714d522f475Smrg type, value, length, format, 3715d522f475Smrg XmbTextListToTextProperty, 3716d522f475Smrg XCompoundTextStyle); 3717956cc18dSsnj TRACE(("...XmbTextListToTextProperty(Compound):%d\n", result)); 3718d522f475Smrg } 3719d522f475Smrg#ifdef X_HAVE_UTF8_STRING 3720d522f475Smrg else if (*target == XA_UTF8_STRING(dpy)) { /* not wide_chars */ 3721d522f475Smrg result = 3722d522f475Smrg _ConvertSelectionHelper(w, 3723d522f475Smrg type, value, length, format, 3724d522f475Smrg XmbTextListToTextProperty, 3725d522f475Smrg XUTF8StringStyle); 3726956cc18dSsnj TRACE(("...XmbTextListToTextProperty(UTF8):%d\n", result)); 3727d522f475Smrg } 3728d522f475Smrg#endif 3729d522f475Smrg else if (*target == XA_LIST_LENGTH(dpy)) { 373020d2c4d2Smrg result = SaveConvertedLength(value, (unsigned long) 1); 3731d522f475Smrg *type = XA_INTEGER; 3732d522f475Smrg *length = 1; 3733d522f475Smrg *format = 32; 3734956cc18dSsnj TRACE(("...list of values:%d\n", result)); 3735d522f475Smrg } else if (*target == XA_LENGTH(dpy)) { 3736d522f475Smrg /* This value is wrong if we have UTF-8 text */ 37372eaa94a1Schristos result = SaveConvertedLength(value, screen->selection_length); 3738d522f475Smrg *type = XA_INTEGER; 3739d522f475Smrg *length = 1; 3740d522f475Smrg *format = 32; 3741956cc18dSsnj TRACE(("...list of values:%d\n", result)); 3742d522f475Smrg } else if (XmuConvertStandardSelection(w, 3743d522f475Smrg screen->selection_time, selection, 3744d522f475Smrg target, type, (XPointer *) value, 3745d522f475Smrg length, format)) { 3746d522f475Smrg result = True; 3747956cc18dSsnj TRACE(("...XmuConvertStandardSelection:%d\n", result)); 3748d522f475Smrg } 3749d522f475Smrg 3750d522f475Smrg /* else */ 37512eaa94a1Schristos return (Boolean) result; 3752d522f475Smrg} 3753d522f475Smrg 3754d522f475Smrgstatic void 3755d522f475SmrgLoseSelection(Widget w, Atom * selection) 3756d522f475Smrg{ 3757d522f475Smrg TScreen *screen; 3758d522f475Smrg Atom *atomP; 3759d522f475Smrg Cardinal i; 3760d522f475Smrg 3761956cc18dSsnj XtermWidget xw; 3762956cc18dSsnj 3763956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 3764d522f475Smrg return; 3765d522f475Smrg 3766956cc18dSsnj screen = TScreenOf(xw); 3767d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 3768d522f475Smrg i < screen->selection_count; i++, atomP++) { 3769d522f475Smrg if (*selection == *atomP) 3770d522f475Smrg *atomP = (Atom) 0; 3771d522f475Smrg if (CutBuffer(*atomP) >= 0) { 3772d522f475Smrg *atomP = (Atom) 0; 3773d522f475Smrg } 3774d522f475Smrg } 3775d522f475Smrg 3776d522f475Smrg for (i = screen->selection_count; i; i--) { 3777d522f475Smrg if (screen->selection_atoms[i - 1] != 0) 3778d522f475Smrg break; 3779d522f475Smrg } 3780d522f475Smrg screen->selection_count = i; 3781d522f475Smrg 3782d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 3783d522f475Smrg i < screen->selection_count; i++, atomP++) { 3784d522f475Smrg if (*atomP == (Atom) 0) { 3785d522f475Smrg *atomP = screen->selection_atoms[--screen->selection_count]; 3786d522f475Smrg } 3787d522f475Smrg } 3788d522f475Smrg 3789d522f475Smrg if (screen->selection_count == 0) 3790956cc18dSsnj TrackText(xw, &zeroCELL, &zeroCELL); 3791d522f475Smrg} 3792d522f475Smrg 3793d522f475Smrg/* ARGSUSED */ 3794d522f475Smrgstatic void 3795d522f475SmrgSelectionDone(Widget w GCC_UNUSED, 3796d522f475Smrg Atom * selection GCC_UNUSED, 3797d522f475Smrg Atom * target GCC_UNUSED) 3798d522f475Smrg{ 3799d522f475Smrg /* empty proc so Intrinsics know we want to keep storage */ 3800d522f475Smrg} 3801d522f475Smrg 3802d522f475Smrgstatic void 3803d522f475Smrg_OwnSelection(XtermWidget xw, 3804d522f475Smrg String * selections, 3805d522f475Smrg Cardinal count) 3806d522f475Smrg{ 3807956cc18dSsnj TScreen *screen = TScreenOf(xw); 3808d522f475Smrg Atom *atoms = screen->selection_atoms; 3809d522f475Smrg Cardinal i; 3810d522f475Smrg Bool have_selection = False; 3811d522f475Smrg 381220d2c4d2Smrg if (count == 0) 381320d2c4d2Smrg return; 38142eaa94a1Schristos if (screen->selection_length == 0) 3815d522f475Smrg return; 3816d522f475Smrg 3817956cc18dSsnj TRACE(("_OwnSelection count %d\n", count)); 3818d522f475Smrg selections = MapSelections(xw, selections, count); 3819d522f475Smrg 3820d522f475Smrg if (count > screen->sel_atoms_size) { 3821d522f475Smrg XtFree((char *) atoms); 3822a1f3da82Smrg atoms = TypeXtMallocN(Atom, count); 3823d522f475Smrg screen->selection_atoms = atoms; 3824d522f475Smrg screen->sel_atoms_size = count; 3825d522f475Smrg } 3826d522f475Smrg XmuInternStrings(XtDisplay((Widget) xw), selections, count, atoms); 3827d522f475Smrg for (i = 0; i < count; i++) { 3828d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 3829d522f475Smrg if (cutbuffer >= 0) { 38302eaa94a1Schristos unsigned long limit = 38312eaa94a1Schristos (unsigned long) (4 * XMaxRequestSize(XtDisplay((Widget) xw)) - 32); 38322eaa94a1Schristos if (screen->selection_length > limit) { 383320d2c4d2Smrg TRACE(("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 383420d2c4d2Smrg screen->selection_length, cutbuffer)); 3835d522f475Smrg fprintf(stderr, 3836956cc18dSsnj "%s: selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 3837a1f3da82Smrg ProgramName, screen->selection_length, cutbuffer); 3838d522f475Smrg } else { 3839d522f475Smrg /* This used to just use the UTF-8 data, which was totally 3840d522f475Smrg * broken as not even the corresponding paste code in Xterm 3841d522f475Smrg * understood this! So now it converts to Latin1 first. 3842d522f475Smrg * Robert Brady, 2000-09-05 3843d522f475Smrg */ 3844d522f475Smrg unsigned long length = screen->selection_length; 3845d522f475Smrg Char *data = screen->selection_data; 3846d522f475Smrg if_OPT_WIDE_CHARS((screen), { 3847956cc18dSsnj data = UTF8toLatin1(screen, data, length, &length); 3848d522f475Smrg }); 3849d522f475Smrg TRACE(("XStoreBuffer(%d)\n", cutbuffer)); 3850d522f475Smrg XStoreBuffer(XtDisplay((Widget) xw), 3851d522f475Smrg (char *) data, 3852d522f475Smrg (int) length, 3853d522f475Smrg cutbuffer); 3854d522f475Smrg } 3855d522f475Smrg } else if (!screen->replyToEmacs) { 3856d522f475Smrg have_selection |= 3857d522f475Smrg XtOwnSelection((Widget) xw, atoms[i], 3858d522f475Smrg screen->selection_time, 3859d522f475Smrg ConvertSelection, LoseSelection, SelectionDone); 3860d522f475Smrg } 3861d522f475Smrg } 3862d522f475Smrg if (!screen->replyToEmacs) 3863d522f475Smrg screen->selection_count = count; 3864d522f475Smrg if (!have_selection) 3865d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 3866d522f475Smrg} 3867d522f475Smrg 3868d522f475Smrgstatic void 3869d522f475SmrgResetSelectionState(TScreen * screen) 3870d522f475Smrg{ 3871d522f475Smrg screen->selection_count = 0; 3872d522f475Smrg screen->startH = zeroCELL; 3873d522f475Smrg screen->endH = zeroCELL; 3874d522f475Smrg} 3875d522f475Smrg 3876d522f475Smrgvoid 3877d522f475SmrgDisownSelection(XtermWidget xw) 3878d522f475Smrg{ 3879956cc18dSsnj TScreen *screen = TScreenOf(xw); 3880d522f475Smrg Atom *atoms = screen->selection_atoms; 3881d522f475Smrg Cardinal count = screen->selection_count; 3882d522f475Smrg Cardinal i; 3883d522f475Smrg 3884d522f475Smrg TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n", 3885d522f475Smrg count, 3886d522f475Smrg screen->startH.row, 3887d522f475Smrg screen->startH.col, 3888d522f475Smrg screen->endH.row, 3889d522f475Smrg screen->endH.col)); 3890d522f475Smrg 3891d522f475Smrg for (i = 0; i < count; i++) { 3892d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 3893d522f475Smrg if (cutbuffer < 0) { 3894d522f475Smrg XtDisownSelection((Widget) xw, atoms[i], 3895d522f475Smrg screen->selection_time); 3896d522f475Smrg } 3897d522f475Smrg } 3898d522f475Smrg /* 3899d522f475Smrg * If none of the callbacks via XtDisownSelection() reset highlighting 3900d522f475Smrg * do it now. 3901d522f475Smrg */ 3902d522f475Smrg if (ScrnHaveSelection(screen)) { 3903d522f475Smrg /* save data which will be reset */ 3904d522f475Smrg CELL first = screen->startH; 3905d522f475Smrg CELL last = screen->endH; 3906d522f475Smrg 3907d522f475Smrg ResetSelectionState(screen); 3908d522f475Smrg ReHiliteText(xw, &first, &last); 3909d522f475Smrg } else { 3910d522f475Smrg ResetSelectionState(screen); 3911d522f475Smrg } 3912d522f475Smrg} 3913d522f475Smrg 3914d522f475Smrgvoid 3915d522f475SmrgUnhiliteSelection(XtermWidget xw) 3916d522f475Smrg{ 3917956cc18dSsnj TScreen *screen = TScreenOf(xw); 3918d522f475Smrg 3919d522f475Smrg if (ScrnHaveSelection(screen)) { 3920d522f475Smrg CELL first = screen->startH; 3921d522f475Smrg CELL last = screen->endH; 3922d522f475Smrg 3923d522f475Smrg screen->startH = zeroCELL; 3924d522f475Smrg screen->endH = zeroCELL; 3925d522f475Smrg ReHiliteText(xw, &first, &last); 3926d522f475Smrg } 3927d522f475Smrg} 3928d522f475Smrg 3929d522f475Smrg/* returns number of chars in line from scol to ecol out */ 3930d522f475Smrg/* ARGSUSED */ 3931d522f475Smrgstatic int 3932956cc18dSsnjLength(TScreen * screen, 3933d522f475Smrg int row, 3934d522f475Smrg int scol, 3935d522f475Smrg int ecol) 3936d522f475Smrg{ 3937956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 3938956cc18dSsnj int lastcol = LastTextCol(screen, ld, row); 3939d522f475Smrg 3940d522f475Smrg if (ecol > lastcol) 3941d522f475Smrg ecol = lastcol; 3942d522f475Smrg return (ecol - scol + 1); 3943d522f475Smrg} 3944d522f475Smrg 3945d522f475Smrg/* copies text into line, preallocated */ 3946d522f475Smrgstatic Char * 3947d522f475SmrgSaveText(TScreen * screen, 3948d522f475Smrg int row, 3949d522f475Smrg int scol, 3950d522f475Smrg int ecol, 3951d522f475Smrg Char * lp, /* pointer to where to put the text */ 3952d522f475Smrg int *eol) 3953d522f475Smrg{ 3954956cc18dSsnj LineData *ld; 3955d522f475Smrg int i = 0; 3956d522f475Smrg unsigned c; 3957d522f475Smrg Char *result = lp; 3958d522f475Smrg#if OPT_WIDE_CHARS 39592eaa94a1Schristos unsigned previous = 0; 3960d522f475Smrg#endif 3961d522f475Smrg 3962956cc18dSsnj ld = GET_LINEDATA(screen, row); 3963d522f475Smrg i = Length(screen, row, scol, ecol); 3964d522f475Smrg ecol = scol + i; 3965d522f475Smrg#if OPT_DEC_CHRSET 3966956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 3967d522f475Smrg scol = (scol + 0) / 2; 3968d522f475Smrg ecol = (ecol + 1) / 2; 3969d522f475Smrg } 3970d522f475Smrg#endif 3971956cc18dSsnj *eol = !LineTstWrapped(ld); 3972d522f475Smrg for (i = scol; i < ecol; i++) { 397320d2c4d2Smrg assert(i < ld->lineSize); 3974956cc18dSsnj c = E2A(ld->charData[i]); 3975d522f475Smrg#if OPT_WIDE_CHARS 3976d522f475Smrg /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a 3977d522f475Smrg * wide character. 3978d522f475Smrg */ 3979956cc18dSsnj if (c == HIDDEN_CHAR && isWide((int) previous)) { 3980d522f475Smrg previous = c; 3981d522f475Smrg /* Combining characters attached to double-width characters 3982d522f475Smrg are in memory attached to the HIDDEN_CHAR */ 3983d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3984d522f475Smrg if (screen->utf8_mode != uFalse) { 3985d522f475Smrg unsigned ch; 3986956cc18dSsnj size_t off; 3987956cc18dSsnj for_each_combData(off, ld) { 3988956cc18dSsnj ch = ld->combData[off][i]; 3989956cc18dSsnj if (ch == 0) 3990d522f475Smrg break; 3991d522f475Smrg lp = convertToUTF8(lp, ch); 3992d522f475Smrg } 3993d522f475Smrg } 3994d522f475Smrg }); 3995d522f475Smrg continue; 3996d522f475Smrg } 3997d522f475Smrg previous = c; 3998d522f475Smrg if (screen->utf8_mode != uFalse) { 3999d522f475Smrg lp = convertToUTF8(lp, (c != 0) ? c : ' '); 4000d522f475Smrg if_OPT_WIDE_CHARS(screen, { 4001d522f475Smrg unsigned ch; 4002956cc18dSsnj size_t off; 4003956cc18dSsnj for_each_combData(off, ld) { 4004956cc18dSsnj ch = ld->combData[off][i]; 4005956cc18dSsnj if (ch == 0) 4006d522f475Smrg break; 4007d522f475Smrg lp = convertToUTF8(lp, ch); 4008d522f475Smrg } 4009d522f475Smrg }); 4010d522f475Smrg } else 4011d522f475Smrg#endif 4012d522f475Smrg { 4013d522f475Smrg if (c == 0) { 4014d522f475Smrg c = E2A(' '); 4015d522f475Smrg } else if (c < E2A(' ')) { 4016d522f475Smrg c = DECtoASCII(c); 4017d522f475Smrg } else if (c == 0x7f) { 4018d522f475Smrg c = 0x5f; 4019d522f475Smrg } 40202eaa94a1Schristos *lp++ = CharOf(A2E(c)); 4021d522f475Smrg } 4022d522f475Smrg if (c != E2A(' ')) 4023d522f475Smrg result = lp; 4024d522f475Smrg } 4025d522f475Smrg 4026d522f475Smrg /* 4027d522f475Smrg * If requested, trim trailing blanks from selected lines. Do not do this 4028d522f475Smrg * if the line is wrapped. 4029d522f475Smrg */ 4030d522f475Smrg if (!*eol || !screen->trim_selection) 4031d522f475Smrg result = lp; 4032d522f475Smrg 4033d522f475Smrg return (result); 4034d522f475Smrg} 4035d522f475Smrg 4036d522f475Smrg/* 32 + following 7-bit word: 4037d522f475Smrg 4038d522f475Smrg 1:0 Button no: 0, 1, 2. 3=release. 4039d522f475Smrg 2 shift 4040d522f475Smrg 3 meta 4041d522f475Smrg 4 ctrl 4042d522f475Smrg 5 set for motion notify 4043d522f475Smrg 6 set for wheel 4044d522f475Smrg*/ 4045d522f475Smrg 4046d522f475Smrg/* Position: 32 - 255. */ 4047a1f3da82Smrgstatic int 4048d522f475SmrgBtnCode(XButtonEvent * event, int button) 4049d522f475Smrg{ 40502eaa94a1Schristos int result = (int) (32 + (KeyState(event->state) << 2)); 4051d522f475Smrg 4052d522f475Smrg if (button < 0 || button > 5) { 4053d522f475Smrg result += 3; 4054d522f475Smrg } else { 4055d522f475Smrg if (button > 3) 4056d522f475Smrg result += (64 - 4); 4057d522f475Smrg if (event->type == MotionNotify) 4058d522f475Smrg result += 32; 4059d522f475Smrg result += button; 4060d522f475Smrg } 4061a1f3da82Smrg return result; 4062a1f3da82Smrg} 4063a1f3da82Smrg 4064a1f3da82Smrgstatic unsigned 4065a1f3da82SmrgEmitButtonCode(TScreen * screen, Char * line, unsigned count, XButtonEvent * event) 4066a1f3da82Smrg{ 4067a1f3da82Smrg int value = BtnCode(event, screen->mouse_button); 4068a1f3da82Smrg 4069a1f3da82Smrg if (!screen->ext_mode_mouse || value < 128) { 4070a1f3da82Smrg line[count++] = CharOf(value); 4071a1f3da82Smrg } else { 4072a1f3da82Smrg line[count++] = CharOf(0xC0 + (value >> 6)); 4073a1f3da82Smrg line[count++] = CharOf(0x80 + (value & 0x3F)); 4074a1f3da82Smrg } 4075a1f3da82Smrg return count; 4076d522f475Smrg} 4077d522f475Smrg 4078d522f475Smrgstatic void 4079d522f475SmrgEditorButton(XtermWidget xw, XButtonEvent * event) 4080d522f475Smrg{ 4081956cc18dSsnj TScreen *screen = TScreenOf(xw); 4082d522f475Smrg int pty = screen->respond; 4083492d43a5Smrg int mouse_limit = screen->ext_mode_mouse ? EXT_MOUSE_LIMIT : MOUSE_LIMIT; 4084492d43a5Smrg Char line[10]; 4085d522f475Smrg int row, col; 4086d522f475Smrg int button; 4087d522f475Smrg unsigned count = 0; 4088d522f475Smrg Boolean changed = True; 4089d522f475Smrg 4090d522f475Smrg /* If button event, get button # adjusted for DEC compatibility */ 40912eaa94a1Schristos button = (int) (event->button - 1); 4092d522f475Smrg if (button >= 3) 4093d522f475Smrg button++; 4094d522f475Smrg 4095d522f475Smrg /* Compute character position of mouse pointer */ 4096d522f475Smrg row = (event->y - screen->border) / FontHeight(screen); 4097d522f475Smrg col = (event->x - OriginX(screen)) / FontWidth(screen); 4098d522f475Smrg 4099d522f475Smrg /* Limit to screen dimensions */ 4100d522f475Smrg if (row < 0) 4101d522f475Smrg row = 0; 4102d522f475Smrg else if (row > screen->max_row) 4103d522f475Smrg row = screen->max_row; 4104d522f475Smrg 4105d522f475Smrg if (col < 0) 4106d522f475Smrg col = 0; 4107d522f475Smrg else if (col > screen->max_col) 4108d522f475Smrg col = screen->max_col; 4109492d43a5Smrg 4110492d43a5Smrg /* Limit to representable mouse dimensions */ 4111492d43a5Smrg if (row > mouse_limit) 4112492d43a5Smrg row = mouse_limit; 4113492d43a5Smrg if (col > mouse_limit) 4114492d43a5Smrg col = mouse_limit; 4115d522f475Smrg 4116d522f475Smrg /* Build key sequence starting with \E[M */ 4117d522f475Smrg if (screen->control_eight_bits) { 4118d522f475Smrg line[count++] = ANSI_CSI; 4119d522f475Smrg } else { 4120d522f475Smrg line[count++] = ANSI_ESC; 4121d522f475Smrg line[count++] = '['; 4122d522f475Smrg } 4123d522f475Smrg#if OPT_SCO_FUNC_KEYS 4124d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 4125d522f475Smrg /* 4126d522f475Smrg * SCO function key F1 is \E[M, which would conflict with xterm's 4127d522f475Smrg * normal kmous. 4128d522f475Smrg */ 4129d522f475Smrg line[count++] = '>'; 4130d522f475Smrg } 4131d522f475Smrg#endif 4132d522f475Smrg line[count++] = 'M'; 4133d522f475Smrg 4134d522f475Smrg /* Add event code to key sequence */ 4135d522f475Smrg if (screen->send_mouse_pos == X10_MOUSE) { 41362eaa94a1Schristos line[count++] = CharOf(' ' + button); 4137d522f475Smrg } else { 4138d522f475Smrg /* Button-Motion events */ 4139d522f475Smrg switch (event->type) { 4140d522f475Smrg case ButtonPress: 4141a1f3da82Smrg screen->mouse_button = button; 4142a1f3da82Smrg count = EmitButtonCode(screen, line, count, event); 4143d522f475Smrg break; 4144d522f475Smrg case ButtonRelease: 4145d522f475Smrg /* 4146d522f475Smrg * Wheel mouse interface generates release-events for buttons 4147d522f475Smrg * 4 and 5, coded here as 3 and 4 respectively. We change the 4148d522f475Smrg * release for buttons 1..3 to a -1. 4149d522f475Smrg */ 4150d522f475Smrg if (button < 3) 4151d522f475Smrg button = -1; 4152a1f3da82Smrg screen->mouse_button = button; 4153a1f3da82Smrg count = EmitButtonCode(screen, line, count, event); 4154d522f475Smrg break; 4155d522f475Smrg case MotionNotify: 4156d522f475Smrg /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion 4157d522f475Smrg * events only if character cell has changed. 4158d522f475Smrg */ 4159d522f475Smrg if ((row == screen->mouse_row) 4160d522f475Smrg && (col == screen->mouse_col)) { 4161d522f475Smrg changed = False; 4162d522f475Smrg } else { 4163a1f3da82Smrg count = EmitButtonCode(screen, line, count, event); 4164d522f475Smrg } 4165d522f475Smrg break; 4166d522f475Smrg default: 4167d522f475Smrg changed = False; 4168d522f475Smrg break; 4169d522f475Smrg } 4170d522f475Smrg } 4171d522f475Smrg 4172d522f475Smrg if (changed) { 4173d522f475Smrg screen->mouse_row = row; 4174d522f475Smrg screen->mouse_col = col; 4175d522f475Smrg 4176492d43a5Smrg TRACE(("mouse at %d,%d button+mask = %#x\n", row, col, line[count - 1])); 4177d522f475Smrg 4178492d43a5Smrg /* Add pointer position to key sequence */ 4179492d43a5Smrg count = EmitMousePosition(screen, line, count, col); 4180492d43a5Smrg count = EmitMousePosition(screen, line, count, row); 4181d522f475Smrg 4182d522f475Smrg /* Transmit key sequence to process running under xterm */ 4183d522f475Smrg v_write(pty, line, count); 4184d522f475Smrg } 4185d522f475Smrg return; 4186d522f475Smrg} 4187d522f475Smrg 4188d522f475Smrg#if OPT_FOCUS_EVENT 4189d522f475Smrgvoid 4190d522f475SmrgSendFocusButton(XtermWidget xw, XFocusChangeEvent * event) 4191d522f475Smrg{ 4192956cc18dSsnj TScreen *screen = TScreenOf(xw); 4193d522f475Smrg 4194d522f475Smrg if (screen->send_focus_pos) { 4195d522f475Smrg ANSI reply; 4196d522f475Smrg 4197d522f475Smrg memset(&reply, 0, sizeof(reply)); 4198d522f475Smrg reply.a_type = ANSI_CSI; 4199d522f475Smrg 4200d522f475Smrg#if OPT_SCO_FUNC_KEYS 4201d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 4202d522f475Smrg reply.a_pintro = '>'; 4203d522f475Smrg } 4204d522f475Smrg#endif 42052eaa94a1Schristos reply.a_final = CharOf((event->type == FocusIn) ? 'I' : 'O'); 4206d522f475Smrg unparseseq(xw, &reply); 4207d522f475Smrg } 4208d522f475Smrg return; 4209d522f475Smrg} 4210d522f475Smrg#endif /* OPT_FOCUS_EVENT */ 4211