button.c revision 492d43a5
1492d43a5Smrg/* $XTermId: button.c,v 1.390 2010/10/22 00:53:57 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 420d2c4d2Smrg * Copyright 1999-2009,2010 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/* 1120492d43a5Smrg * Like "select-end" (optionally copies the selection to the given targets), 1121492d43a5Smrg * but also sets the modes so that releasing the mouse button or moving the 1122492d43a5Smrg * mouse does not alter the selection. 1123492d43a5Smrg */ 1124492d43a5Smrgstatic void 1125492d43a5Smrgdo_select_stop(XtermWidget xw, 1126492d43a5Smrg XEvent * event, /* must be XButtonEvent */ 1127492d43a5Smrg String * params, /* selections */ 1128492d43a5Smrg Cardinal *num_params, 1129492d43a5Smrg Bool use_cursor_loc) 1130492d43a5Smrg{ 1131492d43a5Smrg TScreen *screen = TScreenOf(xw); 1132492d43a5Smrg 1133492d43a5Smrg screen->selection_time = event->xbutton.time; 1134492d43a5Smrg switch (screen->eventMode) { 1135492d43a5Smrg case NORMAL: 1136492d43a5Smrg (void) SendMousePosition(xw, event); 1137492d43a5Smrg break; 1138492d43a5Smrg case LEFTEXTENSION: 1139492d43a5Smrg case RIGHTEXTENSION: 1140492d43a5Smrg EndExtend(xw, event, params, *num_params, use_cursor_loc); 1141492d43a5Smrg break; 1142492d43a5Smrg } 1143492d43a5Smrg} 1144492d43a5Smrg 1145492d43a5Smrgvoid 1146492d43a5SmrgHandleSelectStop(Widget w, 1147492d43a5Smrg XEvent * event, /* must be XButtonEvent */ 1148492d43a5Smrg String * params, /* selections */ 1149492d43a5Smrg Cardinal *num_params) 1150492d43a5Smrg{ 1151492d43a5Smrg XtermWidget xw; 1152492d43a5Smrg 1153492d43a5Smrg if ((xw = getXtermWidget(w)) != 0) { 1154492d43a5Smrg do_select_stop(xw, event, params, num_params, False); 1155492d43a5Smrg } 1156492d43a5Smrg} 1157492d43a5Smrg 1158492d43a5Smrgvoid 1159492d43a5SmrgHandleKeyboardSelectStop(Widget w, 1160492d43a5Smrg XEvent * event, /* must be XButtonEvent */ 1161492d43a5Smrg String * params, /* selections */ 1162492d43a5Smrg Cardinal *num_params) 1163492d43a5Smrg{ 1164492d43a5Smrg XtermWidget xw; 1165492d43a5Smrg 1166492d43a5Smrg if ((xw = getXtermWidget(w)) != 0) { 1167492d43a5Smrg do_select_stop(xw, event, params, num_params, True); 1168492d43a5Smrg } 1169492d43a5Smrg} 1170492d43a5Smrg 1171d522f475Smrgstruct _SelectionList { 1172d522f475Smrg String *params; 1173d522f475Smrg Cardinal count; 1174d522f475Smrg Atom *targets; 1175d522f475Smrg Time time; 1176d522f475Smrg}; 1177d522f475Smrg 1178d522f475Smrgstatic unsigned 1179d522f475SmrgDECtoASCII(unsigned ch) 1180d522f475Smrg{ 1181d522f475Smrg if (xtermIsDecGraphic(ch)) { 11822eaa94a1Schristos ch = CharOf("###########+++++##-##++++|######"[ch]); 11832eaa94a1Schristos /* 01234567890123456789012345678901 */ 1184d522f475Smrg } 1185d522f475Smrg return ch; 1186d522f475Smrg} 118720d2c4d2Smrg 118820d2c4d2Smrg#if OPT_WIDE_CHARS 118920d2c4d2Smrgstatic Cardinal 119020d2c4d2SmrgaddXtermChar(Char ** buffer, Cardinal *used, Cardinal offset, unsigned value) 119120d2c4d2Smrg{ 119220d2c4d2Smrg if (offset + 1 >= *used) { 119320d2c4d2Smrg *used = 1 + (2 * (offset + 1)); 119420d2c4d2Smrg allocXtermChars(buffer, *used); 119520d2c4d2Smrg } 119620d2c4d2Smrg (*buffer)[offset++] = (Char) value; 119720d2c4d2Smrg return offset; 119820d2c4d2Smrg} 119920d2c4d2Smrg#define AddChar(buffer, used, offset, value) \ 120020d2c4d2Smrg offset = addXtermChar(buffer, used, offset, (unsigned) value) 120120d2c4d2Smrg 1202d522f475Smrg/* 1203d522f475Smrg * Convert a UTF-8 string to Latin-1, replacing non Latin-1 characters by `#', 1204d522f475Smrg * or ASCII/Latin-1 equivalents for special cases. 1205d522f475Smrg */ 1206d522f475Smrgstatic Char * 120720d2c4d2SmrgUTF8toLatin1(TScreen * screen, Char * s, unsigned long len, unsigned long *result) 1208d522f475Smrg{ 1209d522f475Smrg static Char *buffer; 1210956cc18dSsnj static Cardinal used; 1211d522f475Smrg 121220d2c4d2Smrg Cardinal offset = 0; 1213d522f475Smrg 1214492d43a5Smrg const Char *p; 1215d522f475Smrg 121620d2c4d2Smrg if (len != 0) { 1217d522f475Smrg PtyData data; 1218d522f475Smrg 1219d522f475Smrg fakePtyData(&data, s, s + len); 1220d522f475Smrg while (decodeUtf8(&data)) { 1221956cc18dSsnj Bool fails = False; 1222956cc18dSsnj Bool extra = False; 1223d522f475Smrg IChar value = skipPtyData(&data); 1224d522f475Smrg if (value == UCS_REPL) { 1225956cc18dSsnj fails = True; 1226d522f475Smrg } else if (value < 256) { 122720d2c4d2Smrg AddChar(&buffer, &used, offset, CharOf(value)); 1228d522f475Smrg } else { 1229d522f475Smrg unsigned eqv = ucs2dec(value); 1230d522f475Smrg if (xtermIsDecGraphic(eqv)) { 123120d2c4d2Smrg AddChar(&buffer, &used, offset, DECtoASCII(eqv)); 1232d522f475Smrg } else { 1233d522f475Smrg eqv = AsciiEquivs(value); 1234956cc18dSsnj if (eqv == value) { 1235956cc18dSsnj fails = True; 1236956cc18dSsnj } else { 123720d2c4d2Smrg AddChar(&buffer, &used, offset, eqv); 1238956cc18dSsnj } 1239956cc18dSsnj if (isWide((wchar_t) value)) 1240956cc18dSsnj extra = True; 1241956cc18dSsnj } 1242956cc18dSsnj } 1243956cc18dSsnj 1244956cc18dSsnj /* 1245956cc18dSsnj * If we're not able to plug in a single-byte result, insert the 1246956cc18dSsnj * defaultString (which normally is a single "#", but could be 1247956cc18dSsnj * whatever the user wants). 1248956cc18dSsnj */ 1249956cc18dSsnj if (fails) { 1250492d43a5Smrg for (p = (const Char *) screen->default_string; *p != '\0'; ++p) { 125120d2c4d2Smrg AddChar(&buffer, &used, offset, *p); 1252d522f475Smrg } 1253d522f475Smrg } 1254956cc18dSsnj if (extra) 125520d2c4d2Smrg AddChar(&buffer, &used, offset, ' '); 1256d522f475Smrg } 125720d2c4d2Smrg AddChar(&buffer, &used, offset, '\0'); 125820d2c4d2Smrg *result = (unsigned long) (offset - 1); 1259d522f475Smrg } else { 1260d522f475Smrg *result = 0; 1261d522f475Smrg } 1262d522f475Smrg return buffer; 1263d522f475Smrg} 126420d2c4d2Smrg 126520d2c4d2Smrgint 126620d2c4d2SmrgxtermUtf8ToTextList(XtermWidget xw, 126720d2c4d2Smrg XTextProperty * text_prop, 126820d2c4d2Smrg char ***text_list, 126920d2c4d2Smrg int *text_list_count) 127020d2c4d2Smrg{ 127120d2c4d2Smrg TScreen *screen = TScreenOf(xw); 127220d2c4d2Smrg Display *dpy = screen->display; 127320d2c4d2Smrg int rc = -1; 127420d2c4d2Smrg 127520d2c4d2Smrg if (text_prop->format == 8 127620d2c4d2Smrg && (rc = Xutf8TextPropertyToTextList(dpy, text_prop, 127720d2c4d2Smrg text_list, 127820d2c4d2Smrg text_list_count)) >= 0) { 127920d2c4d2Smrg if (*text_list != NULL && *text_list_count != 0) { 128020d2c4d2Smrg int i; 128120d2c4d2Smrg Char *data; 128220d2c4d2Smrg char **new_text_list, *tmp; 128320d2c4d2Smrg unsigned long size, new_size; 128420d2c4d2Smrg 128520d2c4d2Smrg TRACE(("xtermUtf8ToTextList size %d\n", *text_list_count)); 128620d2c4d2Smrg 128720d2c4d2Smrg /* 128820d2c4d2Smrg * XLib StringList actually uses only two pointers, one for the 128920d2c4d2Smrg * list itself, and one for the data. Pointer to the data is the 129020d2c4d2Smrg * first element of the list, the rest (if any) list elements point 129120d2c4d2Smrg * to the same memory block as the first element 129220d2c4d2Smrg */ 129320d2c4d2Smrg new_size = 0; 129420d2c4d2Smrg for (i = 0; i < *text_list_count; ++i) { 129520d2c4d2Smrg data = (Char *) (*text_list)[i]; 129620d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 129720d2c4d2Smrg (void) UTF8toLatin1(screen, data, size, &size); 129820d2c4d2Smrg new_size += size + 1; 129920d2c4d2Smrg } 130020d2c4d2Smrg new_text_list = 130120d2c4d2Smrg (char **) XtMalloc((Cardinal) sizeof(char *) * (unsigned) *text_list_count); 130220d2c4d2Smrg new_text_list[0] = tmp = XtMalloc((Cardinal) new_size); 130320d2c4d2Smrg for (i = 0; i < (*text_list_count); ++i) { 130420d2c4d2Smrg data = (Char *) (*text_list)[i]; 130520d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 130620d2c4d2Smrg data = UTF8toLatin1(screen, data, size, &size); 130720d2c4d2Smrg memcpy(tmp, data, size + 1); 130820d2c4d2Smrg new_text_list[i] = tmp; 130920d2c4d2Smrg tmp += size + 1; 131020d2c4d2Smrg } 131120d2c4d2Smrg XFreeStringList((*text_list)); 131220d2c4d2Smrg *text_list = new_text_list; 131320d2c4d2Smrg } else { 131420d2c4d2Smrg rc = -1; 131520d2c4d2Smrg } 131620d2c4d2Smrg } 131720d2c4d2Smrg return rc; 131820d2c4d2Smrg} 1319d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1320d522f475Smrg 1321956cc18dSsnjstatic char * 1322956cc18dSsnjparseItem(char *value, char *nextc) 1323d522f475Smrg{ 1324956cc18dSsnj char *nextp = value; 1325956cc18dSsnj while (*nextp != '\0' && *nextp != ',') { 1326956cc18dSsnj *nextp = x_toupper(*nextp); 1327956cc18dSsnj ++nextp; 1328956cc18dSsnj } 1329956cc18dSsnj *nextc = *nextp; 1330956cc18dSsnj *nextp = '\0'; 1331956cc18dSsnj x_strtrim(value); 1332d522f475Smrg 1333956cc18dSsnj return nextp; 1334956cc18dSsnj} 1335d522f475Smrg 1336956cc18dSsnj/* 1337956cc18dSsnj * All of the wanted strings are unique in the first character, so we can 1338956cc18dSsnj * use simple abbreviations. 1339956cc18dSsnj */ 1340956cc18dSsnjstatic Bool 1341956cc18dSsnjsameItem(const char *actual, const char *wanted) 1342956cc18dSsnj{ 1343956cc18dSsnj Bool result = False; 1344956cc18dSsnj size_t have = strlen(actual); 1345956cc18dSsnj size_t need = strlen(wanted); 1346d522f475Smrg 1347956cc18dSsnj if (have != 0 && have <= need) { 1348956cc18dSsnj if (!strncmp(actual, wanted, have)) { 1349956cc18dSsnj TRACE(("...matched \"%s\"\n", wanted)); 1350956cc18dSsnj result = True; 1351956cc18dSsnj } 1352956cc18dSsnj } 1353956cc18dSsnj 1354956cc18dSsnj return result; 1355956cc18dSsnj} 1356956cc18dSsnj 1357956cc18dSsnj/* 1358956cc18dSsnj * Handle the eightBitSelectTypes or utf8SelectTypes resource values. 1359956cc18dSsnj */ 1360956cc18dSsnjstatic Bool 1361956cc18dSsnjoverrideTargets(Widget w, String value, Atom ** resultp) 1362956cc18dSsnj{ 1363956cc18dSsnj Bool override = False; 1364956cc18dSsnj XtermWidget xw; 1365956cc18dSsnj 1366956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1367956cc18dSsnj TScreen *screen = TScreenOf(xw); 1368956cc18dSsnj 136920d2c4d2Smrg if (!IsEmpty(value)) { 1370492d43a5Smrg char *copied = x_strdup(value); 1371956cc18dSsnj if (copied != 0) { 1372956cc18dSsnj Atom *result = 0; 1373956cc18dSsnj Cardinal count = 1; 1374956cc18dSsnj int n; 1375d522f475Smrg 1376956cc18dSsnj TRACE(("decoding SelectTypes \"%s\"\n", value)); 1377956cc18dSsnj for (n = 0; copied[n] != '\0'; ++n) { 1378956cc18dSsnj if (copied[n] == ',') 1379956cc18dSsnj ++count; 1380956cc18dSsnj } 138120d2c4d2Smrg result = (Atom *) XtMalloc(((2 * count) + 1) 138220d2c4d2Smrg * (Cardinal) sizeof(Atom)); 1383956cc18dSsnj if (result == NULL) { 1384956cc18dSsnj TRACE(("Couldn't allocate selection types\n")); 1385956cc18dSsnj } else { 1386956cc18dSsnj char nextc = '?'; 138720d2c4d2Smrg char *listp = (char *) copied; 1388956cc18dSsnj count = 0; 1389956cc18dSsnj do { 1390956cc18dSsnj char *nextp = parseItem(listp, &nextc); 1391956cc18dSsnj size_t len = strlen(listp); 1392956cc18dSsnj 1393956cc18dSsnj if (len == 0) { 1394956cc18dSsnj ; 1395956cc18dSsnj } 1396956cc18dSsnj#if OPT_WIDE_CHARS 1397956cc18dSsnj else if (sameItem(listp, "UTF8")) { 1398956cc18dSsnj result[count++] = XA_UTF8_STRING(XtDisplay(w)); 1399956cc18dSsnj } 1400956cc18dSsnj#endif 1401956cc18dSsnj else if (sameItem(listp, "I18N")) { 1402956cc18dSsnj if (screen->i18nSelections) { 1403956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 1404956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1405956cc18dSsnj } 1406956cc18dSsnj } else if (sameItem(listp, "TEXT")) { 1407956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 1408956cc18dSsnj } else if (sameItem(listp, "COMPOUND_TEXT")) { 1409956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1410956cc18dSsnj } else if (sameItem(listp, "STRING")) { 1411956cc18dSsnj result[count++] = XA_STRING; 1412956cc18dSsnj } 1413956cc18dSsnj *nextp++ = nextc; 1414956cc18dSsnj listp = nextp; 1415956cc18dSsnj } while (nextc != '\0'); 1416956cc18dSsnj if (count) { 1417956cc18dSsnj result[count] = None; 1418956cc18dSsnj override = True; 1419956cc18dSsnj *resultp = result; 1420956cc18dSsnj } else { 1421956cc18dSsnj XtFree((char *) result); 1422956cc18dSsnj } 1423956cc18dSsnj } 1424956cc18dSsnj } else { 1425956cc18dSsnj TRACE(("Couldn't allocate copy of selection types\n")); 1426d522f475Smrg } 1427956cc18dSsnj } 1428956cc18dSsnj } 1429956cc18dSsnj return override; 1430956cc18dSsnj} 1431956cc18dSsnj 1432956cc18dSsnj#if OPT_WIDE_CHARS 1433956cc18dSsnjstatic Atom * 1434956cc18dSsnjallocUtf8Targets(Widget w, TScreen * screen) 1435956cc18dSsnj{ 1436956cc18dSsnj Atom **resultp = &(screen->selection_targets_utf8); 1437956cc18dSsnj 1438956cc18dSsnj if (*resultp == 0) { 1439956cc18dSsnj Atom *result; 1440956cc18dSsnj 1441956cc18dSsnj if (!overrideTargets(w, screen->utf8_select_types, &result)) { 1442956cc18dSsnj result = (Atom *) XtMalloc((Cardinal) (5 * sizeof(Atom))); 1443956cc18dSsnj if (result == NULL) { 1444956cc18dSsnj TRACE(("Couldn't allocate utf-8 selection targets\n")); 1445956cc18dSsnj } else { 1446956cc18dSsnj int n = 0; 1447956cc18dSsnj 1448956cc18dSsnj result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1449d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1450956cc18dSsnj if (screen->i18nSelections) { 1451956cc18dSsnj result[n++] = XA_TEXT(XtDisplay(w)); 1452956cc18dSsnj result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1453956cc18dSsnj } 1454d522f475Smrg#endif 1455956cc18dSsnj result[n++] = XA_STRING; 1456956cc18dSsnj result[n] = None; 1457956cc18dSsnj } 1458d522f475Smrg } 1459956cc18dSsnj 1460956cc18dSsnj *resultp = result; 1461d522f475Smrg } 1462956cc18dSsnj 1463956cc18dSsnj return *resultp; 1464956cc18dSsnj} 1465d522f475Smrg#endif 1466d522f475Smrg 1467956cc18dSsnjstatic Atom * 1468956cc18dSsnjalloc8bitTargets(Widget w, TScreen * screen) 1469956cc18dSsnj{ 1470956cc18dSsnj Atom **resultp = &(screen->selection_targets_8bit); 1471956cc18dSsnj 1472956cc18dSsnj if (*resultp == 0) { 1473956cc18dSsnj Atom *result = 0; 1474956cc18dSsnj 1475956cc18dSsnj if (!overrideTargets(w, screen->eightbit_select_types, &result)) { 1476956cc18dSsnj result = (Atom *) XtMalloc((Cardinal) (5 * sizeof(Atom))); 1477956cc18dSsnj if (result == NULL) { 1478956cc18dSsnj TRACE(("Couldn't allocate 8bit selection targets\n")); 1479956cc18dSsnj } else { 1480956cc18dSsnj int n = 0; 1481956cc18dSsnj 1482d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1483956cc18dSsnj result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1484956cc18dSsnj#endif 1485956cc18dSsnj if (screen->i18nSelections) { 1486956cc18dSsnj result[n++] = XA_TEXT(XtDisplay(w)); 1487956cc18dSsnj result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1488956cc18dSsnj } 1489956cc18dSsnj result[n++] = XA_STRING; 1490956cc18dSsnj result[n] = None; 1491956cc18dSsnj } 1492956cc18dSsnj } 1493956cc18dSsnj 1494956cc18dSsnj *resultp = result; 1495956cc18dSsnj } 1496956cc18dSsnj 1497956cc18dSsnj return *resultp; 1498956cc18dSsnj} 1499956cc18dSsnj 1500956cc18dSsnjstatic Atom * 1501956cc18dSsnj_SelectionTargets(Widget w) 1502956cc18dSsnj{ 1503956cc18dSsnj Atom *result; 1504956cc18dSsnj TScreen *screen; 1505956cc18dSsnj XtermWidget xw; 1506956cc18dSsnj 1507956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) { 1508956cc18dSsnj result = NULL; 1509956cc18dSsnj } else { 1510956cc18dSsnj screen = TScreenOf(xw); 1511956cc18dSsnj 1512956cc18dSsnj#if OPT_WIDE_CHARS 1513956cc18dSsnj if (screen->wide_chars) { 1514956cc18dSsnj result = allocUtf8Targets(w, screen); 1515956cc18dSsnj } else 1516d522f475Smrg#endif 1517956cc18dSsnj { 1518956cc18dSsnj /* not screen->wide_chars */ 1519956cc18dSsnj result = alloc8bitTargets(w, screen); 1520d522f475Smrg } 1521d522f475Smrg } 1522956cc18dSsnj 1523956cc18dSsnj return result; 1524d522f475Smrg} 1525d522f475Smrg 1526d522f475Smrg#define isSELECT(value) (!strcmp(value, "SELECT")) 1527d522f475Smrg 1528d522f475Smrgstatic void 1529d522f475SmrgUnmapSelections(XtermWidget xw) 1530d522f475Smrg{ 1531956cc18dSsnj TScreen *screen = TScreenOf(xw); 1532d522f475Smrg Cardinal n; 1533d522f475Smrg 1534d522f475Smrg if (screen->mappedSelect) { 1535d522f475Smrg for (n = 0; screen->mappedSelect[n] != 0; ++n) 153620d2c4d2Smrg free((void *) screen->mappedSelect[n]); 1537d522f475Smrg free(screen->mappedSelect); 1538d522f475Smrg screen->mappedSelect = 0; 1539d522f475Smrg } 1540d522f475Smrg} 1541d522f475Smrg 1542d522f475Smrg/* 1543d522f475Smrg * xterm generally uses the primary selection. Some applications prefer 1544d522f475Smrg * (or are limited to) the clipboard. Since the translations resource is 1545d522f475Smrg * complicated, users seldom change the way it affects selection. But it 1546d522f475Smrg * is simple to remap the choice between primary and clipboard before the 1547d522f475Smrg * call to XmuInternStrings(). 1548d522f475Smrg */ 1549d522f475Smrgstatic String * 1550d522f475SmrgMapSelections(XtermWidget xw, String * params, Cardinal num_params) 1551d522f475Smrg{ 1552d522f475Smrg String *result = params; 1553d522f475Smrg 1554d522f475Smrg if (num_params > 0) { 1555d522f475Smrg Cardinal j; 1556d522f475Smrg Boolean map = False; 1557d522f475Smrg 1558d522f475Smrg for (j = 0; j < num_params; ++j) { 1559d522f475Smrg TRACE(("param[%d]:%s\n", j, params[j])); 1560d522f475Smrg if (isSELECT(params[j])) { 1561d522f475Smrg map = True; 1562d522f475Smrg break; 1563d522f475Smrg } 1564d522f475Smrg } 1565d522f475Smrg if (map) { 1566956cc18dSsnj TScreen *screen = TScreenOf(xw); 1567956cc18dSsnj const char *mapTo = (screen->selectToClipboard 1568d522f475Smrg ? "CLIPBOARD" 1569d522f475Smrg : "PRIMARY"); 1570d522f475Smrg 1571d522f475Smrg UnmapSelections(xw); 1572d522f475Smrg if ((result = TypeMallocN(String, num_params + 1)) != 0) { 1573d522f475Smrg result[num_params] = 0; 1574d522f475Smrg for (j = 0; j < num_params; ++j) { 1575d522f475Smrg result[j] = x_strdup((isSELECT(params[j]) 1576d522f475Smrg ? mapTo 1577d522f475Smrg : params[j])); 1578d522f475Smrg if (result[j] == 0) { 1579d522f475Smrg UnmapSelections(xw); 1580d522f475Smrg result = 0; 1581d522f475Smrg break; 1582d522f475Smrg } 1583d522f475Smrg } 1584956cc18dSsnj screen->mappedSelect = result; 1585d522f475Smrg } 1586d522f475Smrg } 1587d522f475Smrg } 1588d522f475Smrg return result; 1589d522f475Smrg} 1590d522f475Smrg 1591d522f475Smrg/* 1592d522f475Smrg * Lookup the cut-buffer number, which will be in the range 0-7. 1593d522f475Smrg * If it is not a cut-buffer, it is the primary selection (-1). 1594d522f475Smrg */ 1595d522f475Smrgstatic int 159620d2c4d2SmrgCutBuffer(Atom code) 1597d522f475Smrg{ 1598d522f475Smrg int cutbuffer; 159920d2c4d2Smrg switch ((unsigned) code) { 1600d522f475Smrg case XA_CUT_BUFFER0: 1601d522f475Smrg cutbuffer = 0; 1602d522f475Smrg break; 1603d522f475Smrg case XA_CUT_BUFFER1: 1604d522f475Smrg cutbuffer = 1; 1605d522f475Smrg break; 1606d522f475Smrg case XA_CUT_BUFFER2: 1607d522f475Smrg cutbuffer = 2; 1608d522f475Smrg break; 1609d522f475Smrg case XA_CUT_BUFFER3: 1610d522f475Smrg cutbuffer = 3; 1611d522f475Smrg break; 1612d522f475Smrg case XA_CUT_BUFFER4: 1613d522f475Smrg cutbuffer = 4; 1614d522f475Smrg break; 1615d522f475Smrg case XA_CUT_BUFFER5: 1616d522f475Smrg cutbuffer = 5; 1617d522f475Smrg break; 1618d522f475Smrg case XA_CUT_BUFFER6: 1619d522f475Smrg cutbuffer = 6; 1620d522f475Smrg break; 1621d522f475Smrg case XA_CUT_BUFFER7: 1622d522f475Smrg cutbuffer = 7; 1623d522f475Smrg break; 1624d522f475Smrg default: 1625d522f475Smrg cutbuffer = -1; 1626d522f475Smrg break; 1627d522f475Smrg } 1628d522f475Smrg return cutbuffer; 1629d522f475Smrg} 1630d522f475Smrg 1631d522f475Smrg#if OPT_PASTE64 1632d522f475Smrgstatic void 1633d522f475SmrgFinishPaste64(XtermWidget xw) 1634d522f475Smrg{ 1635956cc18dSsnj TScreen *screen = TScreenOf(xw); 1636956cc18dSsnj 1637956cc18dSsnj TRACE(("FinishPaste64(%d)\n", screen->base64_paste)); 1638956cc18dSsnj if (screen->base64_paste) { 1639956cc18dSsnj screen->base64_paste = 0; 1640956cc18dSsnj unparseputc1(xw, screen->base64_final); 1641d522f475Smrg unparse_end(xw); 1642d522f475Smrg } 1643d522f475Smrg} 1644d522f475Smrg#endif 1645d522f475Smrg 1646d522f475Smrg#if !OPT_PASTE64 1647d522f475Smrgstatic 1648d522f475Smrg#endif 1649d522f475Smrgvoid 1650d522f475SmrgxtermGetSelection(Widget w, 1651d522f475Smrg Time ev_time, 1652d522f475Smrg String * params, /* selections in precedence order */ 1653d522f475Smrg Cardinal num_params, 1654d522f475Smrg Atom * targets) 1655d522f475Smrg{ 1656d522f475Smrg Atom selection; 1657d522f475Smrg int cutbuffer; 1658d522f475Smrg Atom target; 1659d522f475Smrg 1660956cc18dSsnj XtermWidget xw; 1661956cc18dSsnj 166220d2c4d2Smrg if (num_params == 0) 166320d2c4d2Smrg return; 1664956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 1665d522f475Smrg return; 1666d522f475Smrg 1667956cc18dSsnj TRACE(("xtermGetSelection num_params %d\n", num_params)); 1668956cc18dSsnj params = MapSelections(xw, params, num_params); 1669d522f475Smrg 1670d522f475Smrg XmuInternStrings(XtDisplay(w), params, (Cardinal) 1, &selection); 1671d522f475Smrg cutbuffer = CutBuffer(selection); 1672d522f475Smrg 1673956cc18dSsnj TRACE(("Cutbuffer: %d, target: %s\n", cutbuffer, 1674956cc18dSsnj (targets 1675956cc18dSsnj ? visibleSelectionTarget(XtDisplay(w), targets[0]) 1676956cc18dSsnj : "None"))); 1677d522f475Smrg 1678d522f475Smrg if (cutbuffer >= 0) { 1679d522f475Smrg int inbytes; 1680d522f475Smrg unsigned long nbytes; 1681d522f475Smrg int fmt8 = 8; 1682d522f475Smrg Atom type = XA_STRING; 1683d522f475Smrg char *line; 1684d522f475Smrg 1685d522f475Smrg /* 'line' is freed in SelectionReceived */ 1686d522f475Smrg line = XFetchBuffer(XtDisplay(w), &inbytes, cutbuffer); 1687d522f475Smrg nbytes = (unsigned long) inbytes; 1688d522f475Smrg 1689d522f475Smrg if (nbytes > 0) 1690d522f475Smrg SelectionReceived(w, NULL, &selection, &type, (XtPointer) line, 1691d522f475Smrg &nbytes, &fmt8); 1692d522f475Smrg else if (num_params > 1) { 1693d522f475Smrg xtermGetSelection(w, ev_time, params + 1, num_params - 1, NULL); 1694d522f475Smrg } 1695d522f475Smrg#if OPT_PASTE64 1696d522f475Smrg else { 1697956cc18dSsnj FinishPaste64(xw); 1698d522f475Smrg } 1699d522f475Smrg#endif 1700d522f475Smrg return; 1701d522f475Smrg } else { 1702d522f475Smrg struct _SelectionList *list; 1703d522f475Smrg 1704d522f475Smrg if (targets == NULL || targets[0] == None) { 1705d522f475Smrg targets = _SelectionTargets(w); 1706d522f475Smrg } 1707d522f475Smrg 1708d522f475Smrg if (targets != 0) { 1709d522f475Smrg target = targets[0]; 1710d522f475Smrg 1711d522f475Smrg if (targets[1] == None) { /* last target in list */ 1712d522f475Smrg params++; 1713d522f475Smrg num_params--; 1714d522f475Smrg targets = _SelectionTargets(w); 1715d522f475Smrg } else { 1716d522f475Smrg targets = &(targets[1]); 1717d522f475Smrg } 1718d522f475Smrg 1719d522f475Smrg if (num_params) { 1720d522f475Smrg /* 'list' is freed in SelectionReceived */ 1721d522f475Smrg list = XtNew(struct _SelectionList); 1722d522f475Smrg if (list != 0) { 1723d522f475Smrg list->params = params; 1724d522f475Smrg list->count = num_params; 1725d522f475Smrg list->targets = targets; 1726d522f475Smrg list->time = ev_time; 1727d522f475Smrg } 1728d522f475Smrg } else { 1729d522f475Smrg list = NULL; 1730d522f475Smrg } 1731d522f475Smrg 1732d522f475Smrg XtGetSelectionValue(w, selection, 1733d522f475Smrg target, 1734d522f475Smrg SelectionReceived, 1735d522f475Smrg (XtPointer) list, ev_time); 1736d522f475Smrg } 1737d522f475Smrg } 1738d522f475Smrg} 1739d522f475Smrg 1740d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 1741d522f475Smrgstatic void 1742d522f475SmrgGettingSelection(Display * dpy, Atom type, Char * line, unsigned long len) 1743d522f475Smrg{ 1744d522f475Smrg Char *cp; 1745d522f475Smrg char *name; 1746d522f475Smrg 1747d522f475Smrg name = XGetAtomName(dpy, type); 1748d522f475Smrg 1749d522f475Smrg TRACE(("Getting %s (%ld)\n", name, (long int) type)); 1750d522f475Smrg for (cp = line; cp < line + len; cp++) { 1751956cc18dSsnj TRACE(("[%d:%lu]", (int) (cp + 1 - line), len)); 1752d522f475Smrg if (isprint(*cp)) { 1753d522f475Smrg TRACE(("%c\n", *cp)); 1754d522f475Smrg } else { 1755d522f475Smrg TRACE(("\\x%02x\n", *cp)); 1756d522f475Smrg } 1757d522f475Smrg } 1758d522f475Smrg} 1759d522f475Smrg#else 1760d522f475Smrg#define GettingSelection(dpy,type,line,len) /* nothing */ 1761d522f475Smrg#endif 1762d522f475Smrg 1763d522f475Smrg#ifdef VMS 1764d522f475Smrg# define tty_vwrite(pty,lag,l) tt_write(lag,l) 1765d522f475Smrg#else /* !( VMS ) */ 1766d522f475Smrg# define tty_vwrite(pty,lag,l) v_write(pty,lag,l) 1767d522f475Smrg#endif /* defined VMS */ 1768d522f475Smrg 1769d522f475Smrg#if OPT_PASTE64 1770d522f475Smrg/* Return base64 code character given 6-bit number */ 1771d522f475Smrgstatic const char base64_code[] = "\ 1772d522f475SmrgABCDEFGHIJKLMNOPQRSTUVWXYZ\ 1773d522f475Smrgabcdefghijklmnopqrstuvwxyz\ 1774d522f475Smrg0123456789+/"; 1775d522f475Smrgstatic void 1776d522f475Smrgbase64_flush(TScreen * screen) 1777d522f475Smrg{ 1778d522f475Smrg Char x; 1779d522f475Smrg switch (screen->base64_count) { 1780d522f475Smrg case 0: 1781d522f475Smrg break; 1782d522f475Smrg case 2: 17832eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 4]); 1784d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1785d522f475Smrg break; 1786d522f475Smrg case 4: 17872eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 2]); 1788d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1789d522f475Smrg break; 1790d522f475Smrg } 1791d522f475Smrg if (screen->base64_pad & 3) 1792d522f475Smrg tty_vwrite(screen->respond, 1793492d43a5Smrg (const Char *) "===", 1794d522f475Smrg (unsigned) (4 - (screen->base64_pad & 3))); 1795d522f475Smrg screen->base64_count = 0; 1796d522f475Smrg screen->base64_accu = 0; 1797d522f475Smrg screen->base64_pad = 0; 1798d522f475Smrg} 1799d522f475Smrg#endif /* OPT_PASTE64 */ 1800d522f475Smrg 1801d522f475Smrgstatic void 1802d522f475Smrg_qWriteSelectionData(TScreen * screen, Char * lag, unsigned length) 1803d522f475Smrg{ 1804d522f475Smrg#if OPT_PASTE64 1805d522f475Smrg if (screen->base64_paste) { 1806d522f475Smrg /* Send data as base64 */ 1807d522f475Smrg Char *p = lag; 1808d522f475Smrg Char buf[64]; 1809d522f475Smrg unsigned x = 0; 1810d522f475Smrg while (length--) { 1811d522f475Smrg switch (screen->base64_count) { 1812d522f475Smrg case 0: 18132eaa94a1Schristos buf[x++] = CharOf(base64_code[*p >> 2]); 18142eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0x3); 1815d522f475Smrg screen->base64_count = 2; 1816d522f475Smrg ++p; 1817d522f475Smrg break; 1818d522f475Smrg case 2: 18192eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 4) + 18202eaa94a1Schristos (*p >> 4)]); 18212eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0xF); 1822d522f475Smrg screen->base64_count = 4; 1823d522f475Smrg ++p; 1824d522f475Smrg break; 1825d522f475Smrg case 4: 18262eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 2) + 18272eaa94a1Schristos (*p >> 6)]); 18282eaa94a1Schristos buf[x++] = CharOf(base64_code[*p & 0x3F]); 1829d522f475Smrg screen->base64_accu = 0; 1830d522f475Smrg screen->base64_count = 0; 1831d522f475Smrg ++p; 1832d522f475Smrg break; 1833d522f475Smrg } 1834d522f475Smrg if (x >= 63) { 1835d522f475Smrg /* Write 63 or 64 characters */ 1836d522f475Smrg screen->base64_pad += x; 1837d522f475Smrg tty_vwrite(screen->respond, buf, x); 1838d522f475Smrg x = 0; 1839d522f475Smrg } 1840d522f475Smrg } 1841d522f475Smrg if (x != 0) { 1842d522f475Smrg screen->base64_pad += x; 1843d522f475Smrg tty_vwrite(screen->respond, buf, x); 1844d522f475Smrg } 1845d522f475Smrg } else 1846d522f475Smrg#endif /* OPT_PASTE64 */ 1847d522f475Smrg#if OPT_READLINE 1848d522f475Smrg if (SCREEN_FLAG(screen, paste_quotes)) { 1849d522f475Smrg while (length--) { 1850492d43a5Smrg tty_vwrite(screen->respond, (const Char *) "\026", 1); /* Control-V */ 1851d522f475Smrg tty_vwrite(screen->respond, lag++, 1); 1852d522f475Smrg } 1853d522f475Smrg } else 1854d522f475Smrg#endif 1855d522f475Smrg tty_vwrite(screen->respond, lag, length); 1856d522f475Smrg} 1857d522f475Smrg 1858d522f475Smrgstatic void 185920d2c4d2Smrg_WriteSelectionData(TScreen * screen, Char * line, size_t length) 1860d522f475Smrg{ 1861d522f475Smrg /* Write data to pty a line at a time. */ 1862d522f475Smrg /* Doing this one line at a time may no longer be necessary 1863d522f475Smrg because v_write has been re-written. */ 1864d522f475Smrg 1865d522f475Smrg Char *lag, *end; 1866d522f475Smrg 1867d522f475Smrg /* in the VMS version, if tt_pasting isn't set to True then qio 1868d522f475Smrg reads aren't blocked and an infinite loop is entered, where the 1869d522f475Smrg pasted text shows up as new input, goes in again, shows up 1870d522f475Smrg again, ad nauseum. */ 1871d522f475Smrg#ifdef VMS 1872d522f475Smrg tt_pasting = True; 1873d522f475Smrg#endif 1874d522f475Smrg 1875d522f475Smrg end = &line[length]; 1876d522f475Smrg lag = line; 1877d522f475Smrg 1878d522f475Smrg#if OPT_PASTE64 1879d522f475Smrg if (screen->base64_paste) { 1880d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (end - lag)); 1881d522f475Smrg base64_flush(screen); 1882d522f475Smrg } else 1883d522f475Smrg#endif 1884d522f475Smrg { 1885d522f475Smrg if (!SCREEN_FLAG(screen, paste_literal_nl)) { 1886d522f475Smrg Char *cp; 1887d522f475Smrg for (cp = line; cp != end; cp++) { 1888d522f475Smrg if (*cp == '\n') { 1889d522f475Smrg *cp = '\r'; 1890d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (cp - lag + 1)); 1891d522f475Smrg lag = cp + 1; 1892d522f475Smrg } 1893d522f475Smrg } 1894d522f475Smrg } 1895d522f475Smrg 1896d522f475Smrg if (lag != end) { 1897d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (end - lag)); 1898d522f475Smrg } 1899d522f475Smrg } 1900d522f475Smrg#ifdef VMS 1901d522f475Smrg tt_pasting = False; 1902d522f475Smrg tt_start_read(); /* reenable reads or a character may be lost */ 1903d522f475Smrg#endif 1904d522f475Smrg} 1905d522f475Smrg 1906d522f475Smrg#if OPT_READLINE 1907d522f475Smrgstatic void 1908492d43a5Smrg_WriteKey(TScreen * screen, const Char * in) 1909d522f475Smrg{ 1910d522f475Smrg Char line[16]; 1911d522f475Smrg unsigned count = 0; 1912492d43a5Smrg size_t length = strlen((const char *) in); 1913d522f475Smrg 1914d522f475Smrg if (screen->control_eight_bits) { 1915d522f475Smrg line[count++] = ANSI_CSI; 1916d522f475Smrg } else { 1917d522f475Smrg line[count++] = ANSI_ESC; 1918d522f475Smrg line[count++] = '['; 1919d522f475Smrg } 1920d522f475Smrg while (length--) 1921d522f475Smrg line[count++] = *in++; 1922d522f475Smrg line[count++] = '~'; 1923d522f475Smrg tty_vwrite(screen->respond, line, count); 1924d522f475Smrg} 1925d522f475Smrg#endif /* OPT_READLINE */ 1926d522f475Smrg 1927d522f475Smrg/* SelectionReceived: stuff received selection text into pty */ 1928d522f475Smrg 1929d522f475Smrg/* ARGSUSED */ 1930d522f475Smrgstatic void 1931d522f475SmrgSelectionReceived(Widget w, 1932d522f475Smrg XtPointer client_data, 1933d522f475Smrg Atom * selection GCC_UNUSED, 1934d522f475Smrg Atom * type, 1935d522f475Smrg XtPointer value, 1936d522f475Smrg unsigned long *length, 1937d522f475Smrg int *format) 1938d522f475Smrg{ 1939d522f475Smrg char **text_list = NULL; 1940d522f475Smrg int text_list_count; 1941d522f475Smrg XTextProperty text_prop; 1942d522f475Smrg TScreen *screen; 1943d522f475Smrg Display *dpy; 1944d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 1945d522f475Smrg Char *line = (Char *) value; 1946d522f475Smrg#endif 1947d522f475Smrg 1948956cc18dSsnj XtermWidget xw; 1949956cc18dSsnj 1950956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 1951d522f475Smrg return; 1952956cc18dSsnj 1953956cc18dSsnj screen = TScreenOf(xw); 1954d522f475Smrg dpy = XtDisplay(w); 1955d522f475Smrg 1956d522f475Smrg if (*type == 0 /*XT_CONVERT_FAIL */ 1957d522f475Smrg || *length == 0 1958d522f475Smrg || value == NULL) 1959d522f475Smrg goto fail; 1960d522f475Smrg 1961d522f475Smrg text_prop.value = (unsigned char *) value; 1962d522f475Smrg text_prop.encoding = *type; 1963d522f475Smrg text_prop.format = *format; 1964d522f475Smrg text_prop.nitems = *length; 1965d522f475Smrg 1966956cc18dSsnj TRACE(("SelectionReceived %s format %d, nitems %ld\n", 1967956cc18dSsnj visibleSelectionTarget(dpy, text_prop.encoding), 1968956cc18dSsnj text_prop.format, 1969956cc18dSsnj text_prop.nitems)); 1970956cc18dSsnj 1971d522f475Smrg#if OPT_WIDE_CHARS 1972d522f475Smrg if (screen->wide_chars) { 1973d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 1974d522f475Smrg *type == XA_STRING || 1975d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 1976d522f475Smrg GettingSelection(dpy, *type, line, *length); 1977d522f475Smrg if (Xutf8TextPropertyToTextList(dpy, &text_prop, 1978d522f475Smrg &text_list, 1979d522f475Smrg &text_list_count) < 0) { 1980d522f475Smrg TRACE(("Conversion failed\n")); 1981d522f475Smrg text_list = NULL; 1982d522f475Smrg } 1983d522f475Smrg } 1984d522f475Smrg } else 1985d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1986d522f475Smrg { 1987d522f475Smrg /* Convert the selection to locale's multibyte encoding. */ 1988d522f475Smrg 1989d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 1990d522f475Smrg *type == XA_STRING || 1991d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 1992d522f475Smrg Status rc; 1993d522f475Smrg 1994d522f475Smrg GettingSelection(dpy, *type, line, *length); 1995d522f475Smrg 1996d522f475Smrg#if OPT_WIDE_CHARS 1997d522f475Smrg if (*type == XA_UTF8_STRING(dpy) && 1998d522f475Smrg !(screen->wide_chars || screen->c1_printable)) { 199920d2c4d2Smrg rc = xtermUtf8ToTextList(xw, &text_prop, 200020d2c4d2Smrg &text_list, &text_list_count); 2001d522f475Smrg } else 2002d522f475Smrg#endif 2003d522f475Smrg if (*type == XA_STRING && screen->brokenSelections) { 2004d522f475Smrg rc = XTextPropertyToStringList(&text_prop, 2005d522f475Smrg &text_list, &text_list_count); 2006d522f475Smrg } else { 2007d522f475Smrg rc = XmbTextPropertyToTextList(dpy, &text_prop, 2008d522f475Smrg &text_list, 2009d522f475Smrg &text_list_count); 2010d522f475Smrg } 2011d522f475Smrg if (rc < 0) { 2012d522f475Smrg TRACE(("Conversion failed\n")); 2013d522f475Smrg text_list = NULL; 2014d522f475Smrg } 2015d522f475Smrg } 2016d522f475Smrg } 2017d522f475Smrg 2018d522f475Smrg if (text_list != NULL && text_list_count != 0) { 2019d522f475Smrg int i; 2020d522f475Smrg 2021d522f475Smrg#if OPT_PASTE64 2022d522f475Smrg if (screen->base64_paste) { 2023d522f475Smrg ; 2024d522f475Smrg } else 2025d522f475Smrg#endif 2026d522f475Smrg#if OPT_READLINE 2027d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 2028492d43a5Smrg _WriteKey(screen, (const Char *) "200"); 2029d522f475Smrg } 2030d522f475Smrg#endif 2031d522f475Smrg for (i = 0; i < text_list_count; i++) { 203220d2c4d2Smrg size_t len = strlen(text_list[i]); 2033d522f475Smrg _WriteSelectionData(screen, (Char *) text_list[i], len); 2034d522f475Smrg } 2035d522f475Smrg#if OPT_PASTE64 2036d522f475Smrg if (screen->base64_paste) { 2037956cc18dSsnj FinishPaste64(xw); 2038d522f475Smrg } else 2039d522f475Smrg#endif 2040d522f475Smrg#if OPT_READLINE 2041d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 2042492d43a5Smrg _WriteKey(screen, (const Char *) "201"); 2043d522f475Smrg } 2044d522f475Smrg#endif 2045d522f475Smrg XFreeStringList(text_list); 2046d522f475Smrg } else 2047d522f475Smrg goto fail; 2048d522f475Smrg 2049d522f475Smrg XtFree((char *) client_data); 2050d522f475Smrg XtFree((char *) value); 2051d522f475Smrg 2052d522f475Smrg return; 2053d522f475Smrg 2054d522f475Smrg fail: 2055d522f475Smrg if (client_data != 0) { 2056d522f475Smrg struct _SelectionList *list = (struct _SelectionList *) client_data; 2057956cc18dSsnj 2058956cc18dSsnj TRACE(("SelectionReceived ->xtermGetSelection\n")); 2059d522f475Smrg xtermGetSelection(w, list->time, 2060d522f475Smrg list->params, list->count, list->targets); 2061d522f475Smrg XtFree((char *) client_data); 2062d522f475Smrg#if OPT_PASTE64 2063d522f475Smrg } else { 2064956cc18dSsnj FinishPaste64(xw); 2065d522f475Smrg#endif 2066d522f475Smrg } 2067d522f475Smrg return; 2068d522f475Smrg} 2069d522f475Smrg 2070d522f475Smrgvoid 2071d522f475SmrgHandleInsertSelection(Widget w, 2072d522f475Smrg XEvent * event, /* assumed to be XButtonEvent* */ 2073d522f475Smrg String * params, /* selections in precedence order */ 2074d522f475Smrg Cardinal *num_params) 2075d522f475Smrg{ 2076956cc18dSsnj XtermWidget xw; 2077d522f475Smrg 2078956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2079d522f475Smrg if (!SendMousePosition(xw, event)) { 2080d522f475Smrg#if OPT_READLINE 2081d522f475Smrg int ldelta; 2082956cc18dSsnj TScreen *screen = TScreenOf(xw); 2083492d43a5Smrg if (IsBtnEvent(event) 2084d522f475Smrg /* Disable on Shift-mouse, including the application-mouse modes */ 2085492d43a5Smrg && !(KeyModifiers(event) & ShiftMask) 2086d522f475Smrg && (screen->send_mouse_pos == MOUSE_OFF) 2087d522f475Smrg && SCREEN_FLAG(screen, paste_moves) 2088d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta)) 2089d522f475Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta); 2090d522f475Smrg#endif /* OPT_READLINE */ 2091d522f475Smrg 2092d522f475Smrg xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL); 2093d522f475Smrg } 2094d522f475Smrg } 2095d522f475Smrg} 2096d522f475Smrg 2097d522f475Smrgstatic SelectUnit 2098956cc18dSsnjEvalSelectUnit(XtermWidget xw, 2099d522f475Smrg Time buttonDownTime, 2100d522f475Smrg SelectUnit defaultUnit, 2101d522f475Smrg unsigned int button) 2102d522f475Smrg{ 2103956cc18dSsnj TScreen *screen = TScreenOf(xw); 2104d522f475Smrg SelectUnit result; 2105d522f475Smrg int delta; 2106d522f475Smrg 2107d522f475Smrg if (button != screen->lastButton) { 210820d2c4d2Smrg delta = screen->multiClickTime + 1; 2109d522f475Smrg } else if (screen->lastButtonUpTime == (Time) 0) { 2110d522f475Smrg /* first time and once in a blue moon */ 2111d522f475Smrg delta = screen->multiClickTime + 1; 2112d522f475Smrg } else if (buttonDownTime > screen->lastButtonUpTime) { 2113d522f475Smrg /* most of the time */ 21142eaa94a1Schristos delta = (int) (buttonDownTime - screen->lastButtonUpTime); 2115d522f475Smrg } else { 2116d522f475Smrg /* time has rolled over since lastButtonUpTime */ 21172eaa94a1Schristos delta = (int) ((((Time) ~ 0) - screen->lastButtonUpTime) + buttonDownTime); 2118d522f475Smrg } 2119d522f475Smrg 2120d522f475Smrg if (delta > screen->multiClickTime) { 2121d522f475Smrg screen->numberOfClicks = 1; 2122d522f475Smrg result = defaultUnit; 2123d522f475Smrg } else { 2124d522f475Smrg result = screen->selectMap[screen->numberOfClicks % screen->maxClicks]; 2125d522f475Smrg screen->numberOfClicks += 1; 2126d522f475Smrg } 2127d522f475Smrg TRACE(("EvalSelectUnit(%d) = %d\n", screen->numberOfClicks, result)); 2128d522f475Smrg return result; 2129d522f475Smrg} 2130d522f475Smrg 2131d522f475Smrgstatic void 2132d522f475Smrgdo_select_start(XtermWidget xw, 2133d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2134d522f475Smrg CELL * cell) 2135d522f475Smrg{ 2136956cc18dSsnj TScreen *screen = TScreenOf(xw); 2137d522f475Smrg 2138d522f475Smrg if (SendMousePosition(xw, event)) 2139d522f475Smrg return; 2140956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2141d522f475Smrg event->xbutton.time, 2142d522f475Smrg Select_CHAR, 2143d522f475Smrg event->xbutton.button); 2144d522f475Smrg screen->replyToEmacs = False; 2145d522f475Smrg 2146d522f475Smrg#if OPT_READLINE 2147d522f475Smrg lastButtonDownTime = event->xbutton.time; 2148d522f475Smrg#endif 2149d522f475Smrg 2150d522f475Smrg StartSelect(xw, cell); 2151d522f475Smrg} 2152d522f475Smrg 2153d522f475Smrg/* ARGSUSED */ 2154d522f475Smrgvoid 2155d522f475SmrgHandleSelectStart(Widget w, 2156d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2157d522f475Smrg String * params GCC_UNUSED, 2158d522f475Smrg Cardinal *num_params GCC_UNUSED) 2159d522f475Smrg{ 2160956cc18dSsnj XtermWidget xw; 2161956cc18dSsnj 2162956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2163956cc18dSsnj TScreen *screen = TScreenOf(xw); 2164d522f475Smrg CELL cell; 2165d522f475Smrg 2166d522f475Smrg screen->firstValidRow = 0; 2167d522f475Smrg screen->lastValidRow = screen->max_row; 2168d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2169d522f475Smrg 2170d522f475Smrg#if OPT_READLINE 2171d522f475Smrg ExtendingSelection = 0; 2172d522f475Smrg#endif 2173d522f475Smrg 2174d522f475Smrg do_select_start(xw, event, &cell); 2175d522f475Smrg } 2176d522f475Smrg} 2177d522f475Smrg 2178d522f475Smrg/* ARGSUSED */ 2179d522f475Smrgvoid 2180d522f475SmrgHandleKeyboardSelectStart(Widget w, 2181d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2182d522f475Smrg String * params GCC_UNUSED, 2183d522f475Smrg Cardinal *num_params GCC_UNUSED) 2184d522f475Smrg{ 2185956cc18dSsnj XtermWidget xw; 2186956cc18dSsnj 2187956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2188956cc18dSsnj TScreen *screen = TScreenOf(xw); 2189d522f475Smrg do_select_start(xw, event, &screen->cursorp); 2190d522f475Smrg } 2191d522f475Smrg} 2192d522f475Smrg 2193d522f475Smrgstatic void 2194d522f475SmrgTrackDown(XtermWidget xw, XButtonEvent * event) 2195d522f475Smrg{ 2196956cc18dSsnj TScreen *screen = TScreenOf(xw); 2197d522f475Smrg CELL cell; 2198d522f475Smrg 2199956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2200d522f475Smrg event->time, 2201d522f475Smrg Select_CHAR, 2202d522f475Smrg event->button); 2203d522f475Smrg if (screen->numberOfClicks > 1) { 2204d522f475Smrg PointToCELL(screen, event->y, event->x, &cell); 2205d522f475Smrg screen->replyToEmacs = True; 2206d522f475Smrg StartSelect(xw, &cell); 2207d522f475Smrg } else { 2208d522f475Smrg screen->waitingForTrackInfo = True; 2209492d43a5Smrg EditorButton(xw, event); 2210d522f475Smrg } 2211d522f475Smrg} 2212d522f475Smrg 2213d522f475Smrg#define boundsCheck(x) if (x < 0) \ 2214d522f475Smrg x = 0; \ 2215d522f475Smrg else if (x >= screen->max_row) \ 2216d522f475Smrg x = screen->max_row 2217d522f475Smrg 2218d522f475Smrgvoid 2219d522f475SmrgTrackMouse(XtermWidget xw, 2220d522f475Smrg int func, 2221d522f475Smrg CELL * start, 2222d522f475Smrg int firstrow, 2223d522f475Smrg int lastrow) 2224d522f475Smrg{ 2225956cc18dSsnj TScreen *screen = TScreenOf(xw); 2226d522f475Smrg 2227d522f475Smrg if (screen->waitingForTrackInfo) { /* if Timed, ignore */ 2228d522f475Smrg screen->waitingForTrackInfo = False; 2229d522f475Smrg 2230d522f475Smrg if (func != 0) { 2231d522f475Smrg CELL first = *start; 2232d522f475Smrg 2233d522f475Smrg boundsCheck(first.row); 2234d522f475Smrg boundsCheck(firstrow); 2235d522f475Smrg boundsCheck(lastrow); 2236d522f475Smrg screen->firstValidRow = firstrow; 2237d522f475Smrg screen->lastValidRow = lastrow; 2238d522f475Smrg screen->replyToEmacs = True; 2239d522f475Smrg StartSelect(xw, &first); 2240d522f475Smrg } 2241d522f475Smrg } 2242d522f475Smrg} 2243d522f475Smrg 2244d522f475Smrgstatic void 2245d522f475SmrgStartSelect(XtermWidget xw, const CELL * cell) 2246d522f475Smrg{ 2247956cc18dSsnj TScreen *screen = TScreenOf(xw); 2248d522f475Smrg 2249d522f475Smrg TRACE(("StartSelect row=%d, col=%d\n", cell->row, cell->col)); 2250d522f475Smrg if (screen->cursor_state) 2251d522f475Smrg HideCursor(); 2252d522f475Smrg if (screen->numberOfClicks == 1) { 2253d522f475Smrg /* set start of selection */ 2254d522f475Smrg screen->rawPos = *cell; 2255d522f475Smrg } 2256d522f475Smrg /* else use old values in rawPos */ 2257d522f475Smrg screen->saveStartR = screen->startExt = screen->rawPos; 2258d522f475Smrg screen->saveEndR = screen->endExt = screen->rawPos; 2259d522f475Smrg if (Coordinate(screen, cell) < Coordinate(screen, &(screen->rawPos))) { 2260d522f475Smrg screen->eventMode = LEFTEXTENSION; 2261d522f475Smrg screen->startExt = *cell; 2262d522f475Smrg } else { 2263d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2264d522f475Smrg screen->endExt = *cell; 2265d522f475Smrg } 2266d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 2267d522f475Smrg} 2268d522f475Smrg 2269d522f475Smrgstatic void 2270d522f475SmrgEndExtend(XtermWidget xw, 2271d522f475Smrg XEvent * event, /* must be XButtonEvent */ 2272d522f475Smrg String * params, /* selections */ 2273d522f475Smrg Cardinal num_params, 2274d522f475Smrg Bool use_cursor_loc) 2275d522f475Smrg{ 2276d522f475Smrg CELL cell; 2277d522f475Smrg unsigned count; 2278956cc18dSsnj TScreen *screen = TScreenOf(xw); 2279492d43a5Smrg Char line[20]; 2280d522f475Smrg 2281d522f475Smrg if (use_cursor_loc) { 2282d522f475Smrg cell = screen->cursorp; 2283d522f475Smrg } else { 2284d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2285d522f475Smrg } 2286d522f475Smrg ExtendExtend(xw, &cell); 2287d522f475Smrg screen->lastButtonUpTime = event->xbutton.time; 2288d522f475Smrg screen->lastButton = event->xbutton.button; 2289d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 2290d522f475Smrg if (screen->replyToEmacs) { 2291d522f475Smrg count = 0; 2292d522f475Smrg if (screen->control_eight_bits) { 2293d522f475Smrg line[count++] = ANSI_CSI; 2294d522f475Smrg } else { 2295d522f475Smrg line[count++] = ANSI_ESC; 2296d522f475Smrg line[count++] = '['; 2297d522f475Smrg } 2298d522f475Smrg if (isSameCELL(&(screen->rawPos), &(screen->startSel)) 2299d522f475Smrg && isSameCELL(&cell, &(screen->endSel))) { 2300d522f475Smrg /* Use short-form emacs select */ 2301d522f475Smrg line[count++] = 't'; 2302492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 2303492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 2304d522f475Smrg } else { 2305d522f475Smrg /* long-form, specify everything */ 2306d522f475Smrg line[count++] = 'T'; 2307492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.col); 2308492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->startSel.row); 2309492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.col); 2310492d43a5Smrg count = EmitMousePosition(screen, line, count, screen->endSel.row); 2311492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.col); 2312492d43a5Smrg count = EmitMousePosition(screen, line, count, cell.row); 2313d522f475Smrg } 2314d522f475Smrg v_write(screen->respond, line, count); 2315d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 2316d522f475Smrg } 2317d522f475Smrg } 2318d522f475Smrg SelectSet(xw, event, params, num_params); 2319d522f475Smrg screen->eventMode = NORMAL; 2320d522f475Smrg} 2321d522f475Smrg 2322d522f475Smrgvoid 2323d522f475SmrgHandleSelectSet(Widget w, 2324d522f475Smrg XEvent * event, 2325d522f475Smrg String * params, 2326d522f475Smrg Cardinal *num_params) 2327d522f475Smrg{ 2328956cc18dSsnj XtermWidget xw; 2329956cc18dSsnj 2330956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2331956cc18dSsnj SelectSet(xw, event, params, *num_params); 2332d522f475Smrg } 2333d522f475Smrg} 2334d522f475Smrg 2335d522f475Smrg/* ARGSUSED */ 2336d522f475Smrgstatic void 2337d522f475SmrgSelectSet(XtermWidget xw, 2338d522f475Smrg XEvent * event GCC_UNUSED, 2339d522f475Smrg String * params, 2340d522f475Smrg Cardinal num_params) 2341d522f475Smrg{ 2342956cc18dSsnj TScreen *screen = TScreenOf(xw); 2343d522f475Smrg 2344d522f475Smrg TRACE(("SelectSet\n")); 2345d522f475Smrg /* Only do select stuff if non-null select */ 2346d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 2347d522f475Smrg SaltTextAway(xw, &(screen->startSel), &(screen->endSel), params, num_params); 2348d522f475Smrg } else { 2349d522f475Smrg DisownSelection(xw); 2350d522f475Smrg } 2351d522f475Smrg} 2352d522f475Smrg 2353d522f475Smrg#define Abs(x) ((x) < 0 ? -(x) : (x)) 2354d522f475Smrg 2355d522f475Smrg/* ARGSUSED */ 2356d522f475Smrgstatic void 2357d522f475Smrgdo_start_extend(XtermWidget xw, 2358d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2359d522f475Smrg String * params GCC_UNUSED, 2360d522f475Smrg Cardinal *num_params GCC_UNUSED, 2361d522f475Smrg Bool use_cursor_loc) 2362d522f475Smrg{ 2363956cc18dSsnj TScreen *screen = TScreenOf(xw); 2364d522f475Smrg int coord; 2365d522f475Smrg CELL cell; 2366d522f475Smrg 2367d522f475Smrg if (SendMousePosition(xw, event)) 2368d522f475Smrg return; 2369d522f475Smrg 2370d522f475Smrg screen->firstValidRow = 0; 2371d522f475Smrg screen->lastValidRow = screen->max_row; 2372d522f475Smrg#if OPT_READLINE 2373492d43a5Smrg if ((KeyModifiers(event) & ShiftMask) 2374d522f475Smrg || event->xbutton.button != Button3 2375d522f475Smrg || !(SCREEN_FLAG(screen, dclick3_deletes))) 2376d522f475Smrg#endif 2377956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2378d522f475Smrg event->xbutton.time, 2379d522f475Smrg screen->selectUnit, 2380d522f475Smrg event->xbutton.button); 2381d522f475Smrg screen->replyToEmacs = False; 2382d522f475Smrg 2383d522f475Smrg#if OPT_READLINE 2384d522f475Smrg CheckSecondPress3(screen, event); 2385d522f475Smrg#endif 2386d522f475Smrg 2387d522f475Smrg if (screen->numberOfClicks == 1 2388d522f475Smrg || (SCREEN_FLAG(screen, dclick3_deletes) /* Dclick special */ 2389492d43a5Smrg &&!(KeyModifiers(event) & ShiftMask))) { 2390d522f475Smrg /* Save existing selection so we can reestablish it if the guy 2391d522f475Smrg extends past the other end of the selection */ 2392d522f475Smrg screen->saveStartR = screen->startExt = screen->startRaw; 2393d522f475Smrg screen->saveEndR = screen->endExt = screen->endRaw; 2394d522f475Smrg } else { 2395d522f475Smrg /* He just needed the selection mode changed, use old values. */ 2396d522f475Smrg screen->startExt = screen->startRaw = screen->saveStartR; 2397d522f475Smrg screen->endExt = screen->endRaw = screen->saveEndR; 2398d522f475Smrg } 2399d522f475Smrg if (use_cursor_loc) { 2400d522f475Smrg cell = screen->cursorp; 2401d522f475Smrg } else { 2402d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2403d522f475Smrg } 2404d522f475Smrg coord = Coordinate(screen, &cell); 2405d522f475Smrg 2406d522f475Smrg if (Abs(coord - Coordinate(screen, &(screen->startSel))) 2407d522f475Smrg < Abs(coord - Coordinate(screen, &(screen->endSel))) 2408d522f475Smrg || coord < Coordinate(screen, &(screen->startSel))) { 2409d522f475Smrg /* point is close to left side of selection */ 2410d522f475Smrg screen->eventMode = LEFTEXTENSION; 2411d522f475Smrg screen->startExt = cell; 2412d522f475Smrg } else { 2413d522f475Smrg /* point is close to left side of selection */ 2414d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2415d522f475Smrg screen->endExt = cell; 2416d522f475Smrg } 2417d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), True); 2418d522f475Smrg 2419d522f475Smrg#if OPT_READLINE 2420d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2421d522f475Smrg ExtendingSelection = 1; 2422d522f475Smrg#endif 2423d522f475Smrg} 2424d522f475Smrg 2425d522f475Smrgstatic void 2426d522f475SmrgExtendExtend(XtermWidget xw, const CELL * cell) 2427d522f475Smrg{ 2428956cc18dSsnj TScreen *screen = TScreenOf(xw); 2429d522f475Smrg int coord = Coordinate(screen, cell); 2430d522f475Smrg 2431d522f475Smrg TRACE(("ExtendExtend row=%d, col=%d\n", cell->row, cell->col)); 2432d522f475Smrg if (screen->eventMode == LEFTEXTENSION 2433d522f475Smrg && ((coord + (screen->selectUnit != Select_CHAR)) 2434d522f475Smrg > Coordinate(screen, &(screen->endSel)))) { 2435d522f475Smrg /* Whoops, he's changed his mind. Do RIGHTEXTENSION */ 2436d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2437d522f475Smrg screen->startExt = screen->saveStartR; 2438d522f475Smrg } else if (screen->eventMode == RIGHTEXTENSION 2439d522f475Smrg && coord < Coordinate(screen, &(screen->startSel))) { 2440d522f475Smrg /* Whoops, he's changed his mind. Do LEFTEXTENSION */ 2441d522f475Smrg screen->eventMode = LEFTEXTENSION; 2442d522f475Smrg screen->endExt = screen->saveEndR; 2443d522f475Smrg } 2444d522f475Smrg if (screen->eventMode == LEFTEXTENSION) { 2445d522f475Smrg screen->startExt = *cell; 2446d522f475Smrg } else { 2447d522f475Smrg screen->endExt = *cell; 2448d522f475Smrg } 2449d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 2450d522f475Smrg 2451d522f475Smrg#if OPT_READLINE 2452d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2453d522f475Smrg ExtendingSelection = 1; 2454d522f475Smrg#endif 2455d522f475Smrg} 2456d522f475Smrg 2457d522f475Smrgvoid 2458d522f475SmrgHandleStartExtend(Widget w, 2459d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2460d522f475Smrg String * params, /* unused */ 2461d522f475Smrg Cardinal *num_params) /* unused */ 2462d522f475Smrg{ 2463956cc18dSsnj XtermWidget xw; 2464956cc18dSsnj 2465956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2466956cc18dSsnj do_start_extend(xw, event, params, num_params, False); 2467956cc18dSsnj } 2468d522f475Smrg} 2469d522f475Smrg 2470d522f475Smrgvoid 2471d522f475SmrgHandleKeyboardStartExtend(Widget w, 2472d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2473d522f475Smrg String * params, /* unused */ 2474d522f475Smrg Cardinal *num_params) /* unused */ 2475d522f475Smrg{ 2476956cc18dSsnj XtermWidget xw; 2477956cc18dSsnj 2478956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2479956cc18dSsnj do_start_extend(xw, event, params, num_params, True); 2480956cc18dSsnj } 2481d522f475Smrg} 2482d522f475Smrg 2483d522f475Smrgvoid 2484d522f475SmrgScrollSelection(TScreen * screen, int amount, Bool always) 2485d522f475Smrg{ 2486d522f475Smrg int minrow = INX2ROW(screen, -screen->savedlines); 2487d522f475Smrg int maxrow = INX2ROW(screen, screen->max_row); 2488d522f475Smrg int maxcol = screen->max_col; 2489d522f475Smrg 2490d522f475Smrg#define scroll_update_one(cell) \ 2491d522f475Smrg (cell)->row += amount; \ 2492d522f475Smrg if ((cell)->row < minrow) { \ 2493d522f475Smrg (cell)->row = minrow; \ 2494d522f475Smrg (cell)->col = 0; \ 2495d522f475Smrg } \ 2496d522f475Smrg if ((cell)->row > maxrow) { \ 2497d522f475Smrg (cell)->row = maxrow; \ 2498d522f475Smrg (cell)->col = maxcol; \ 2499d522f475Smrg } 2500d522f475Smrg 2501d522f475Smrg scroll_update_one(&(screen->startRaw)); 2502d522f475Smrg scroll_update_one(&(screen->endRaw)); 2503d522f475Smrg scroll_update_one(&(screen->startSel)); 2504d522f475Smrg scroll_update_one(&(screen->endSel)); 2505d522f475Smrg 2506d522f475Smrg scroll_update_one(&(screen->rawPos)); 2507d522f475Smrg 2508d522f475Smrg /* 2509d522f475Smrg * If we are told to scroll the selection but it lies outside the scrolling 2510d522f475Smrg * margins, then that could cause the selection to move (bad). It is not 2511d522f475Smrg * simple to fix, because this function is called both for the scrollbar 2512d522f475Smrg * actions as well as application scrolling. The 'always' flag is set in 2513d522f475Smrg * the former case. The rest of the logic handles the latter. 2514d522f475Smrg */ 2515d522f475Smrg if (ScrnHaveSelection(screen)) { 2516d522f475Smrg int adjust; 2517d522f475Smrg 2518d522f475Smrg adjust = ROW2INX(screen, screen->startH.row); 2519d522f475Smrg if (always 2520d522f475Smrg || !ScrnHaveLineMargins(screen) 2521d522f475Smrg || ScrnIsLineInMargins(screen, adjust)) { 2522d522f475Smrg scroll_update_one(&screen->startH); 2523d522f475Smrg } 2524d522f475Smrg adjust = ROW2INX(screen, screen->endH.row); 2525d522f475Smrg if (always 2526d522f475Smrg || !ScrnHaveLineMargins(screen) 2527d522f475Smrg || ScrnIsLineInMargins(screen, adjust)) { 2528d522f475Smrg scroll_update_one(&screen->endH); 2529d522f475Smrg } 2530d522f475Smrg } 2531d522f475Smrg 2532d522f475Smrg screen->startHCoord = Coordinate(screen, &screen->startH); 2533d522f475Smrg screen->endHCoord = Coordinate(screen, &screen->endH); 2534d522f475Smrg} 2535d522f475Smrg 2536d522f475Smrg/*ARGSUSED*/ 2537d522f475Smrgvoid 2538d522f475SmrgResizeSelection(TScreen * screen GCC_UNUSED, int rows, int cols) 2539d522f475Smrg{ 2540d522f475Smrg rows--; /* decr to get 0-max */ 2541d522f475Smrg cols--; 2542d522f475Smrg 2543d522f475Smrg if (screen->startRaw.row > rows) 2544d522f475Smrg screen->startRaw.row = rows; 2545d522f475Smrg if (screen->startSel.row > rows) 2546d522f475Smrg screen->startSel.row = rows; 2547d522f475Smrg if (screen->endRaw.row > rows) 2548d522f475Smrg screen->endRaw.row = rows; 2549d522f475Smrg if (screen->endSel.row > rows) 2550d522f475Smrg screen->endSel.row = rows; 2551d522f475Smrg if (screen->rawPos.row > rows) 2552d522f475Smrg screen->rawPos.row = rows; 2553d522f475Smrg 2554d522f475Smrg if (screen->startRaw.col > cols) 2555d522f475Smrg screen->startRaw.col = cols; 2556d522f475Smrg if (screen->startSel.col > cols) 2557d522f475Smrg screen->startSel.col = cols; 2558d522f475Smrg if (screen->endRaw.col > cols) 2559d522f475Smrg screen->endRaw.col = cols; 2560d522f475Smrg if (screen->endSel.col > cols) 2561d522f475Smrg screen->endSel.col = cols; 2562d522f475Smrg if (screen->rawPos.col > cols) 2563d522f475Smrg screen->rawPos.col = cols; 2564d522f475Smrg} 2565d522f475Smrg 2566d522f475Smrg#if OPT_WIDE_CHARS 2567d522f475SmrgBool 2568d522f475Smrgiswide(int i) 2569d522f475Smrg{ 257020d2c4d2Smrg return (i == HIDDEN_CHAR) || (WideCells(i) == 2); 2571d522f475Smrg} 2572d522f475Smrg 2573d522f475Smrg#define isWideCell(row, col) iswide((int)XTERM_CELL(row, col)) 2574d522f475Smrg#endif 2575d522f475Smrg 2576d522f475Smrgstatic void 2577d522f475SmrgPointToCELL(TScreen * screen, 2578d522f475Smrg int y, 2579d522f475Smrg int x, 2580d522f475Smrg CELL * cell) 2581d522f475Smrg/* Convert pixel coordinates to character coordinates. 2582d522f475Smrg Rows are clipped between firstValidRow and lastValidRow. 2583d522f475Smrg Columns are clipped between to be 0 or greater, but are not clipped to some 2584d522f475Smrg maximum value. */ 2585d522f475Smrg{ 2586d522f475Smrg cell->row = (y - screen->border) / FontHeight(screen); 2587d522f475Smrg if (cell->row < screen->firstValidRow) 2588d522f475Smrg cell->row = screen->firstValidRow; 2589d522f475Smrg else if (cell->row > screen->lastValidRow) 2590d522f475Smrg cell->row = screen->lastValidRow; 2591d522f475Smrg cell->col = (x - OriginX(screen)) / FontWidth(screen); 2592d522f475Smrg if (cell->col < 0) 2593d522f475Smrg cell->col = 0; 2594d522f475Smrg else if (cell->col > MaxCols(screen)) { 2595d522f475Smrg cell->col = MaxCols(screen); 2596d522f475Smrg } 2597d522f475Smrg#if OPT_WIDE_CHARS 2598d522f475Smrg /* 2599d522f475Smrg * If we got a click on the right half of a doublewidth character, 2600d522f475Smrg * pretend it happened on the left half. 2601d522f475Smrg */ 2602d522f475Smrg if (cell->col > 0 2603d522f475Smrg && isWideCell(cell->row, cell->col - 1) 2604d522f475Smrg && (XTERM_CELL(cell->row, cell->col) == HIDDEN_CHAR)) { 2605d522f475Smrg cell->col -= 1; 2606d522f475Smrg } 2607d522f475Smrg#endif 2608d522f475Smrg} 2609d522f475Smrg 2610d522f475Smrg/* 2611d522f475Smrg * Find the last column at which text was drawn on the given row. 2612d522f475Smrg */ 2613d522f475Smrgstatic int 2614956cc18dSsnjLastTextCol(TScreen * screen, LineData * ld, int row) 2615d522f475Smrg{ 261620d2c4d2Smrg int i = -1; 2617d522f475Smrg Char *ch; 2618d522f475Smrg 261920d2c4d2Smrg if (ld != 0) { 262020d2c4d2Smrg if (okScrnRow(screen, row)) { 262120d2c4d2Smrg for (i = screen->max_col, 262220d2c4d2Smrg ch = ld->attribs + i; 262320d2c4d2Smrg i >= 0 && !(*ch & CHARDRAWN); 262420d2c4d2Smrg ch--, i--) { 262520d2c4d2Smrg ; 262620d2c4d2Smrg } 2627d522f475Smrg#if OPT_DEC_CHRSET 262820d2c4d2Smrg if (CSET_DOUBLE(GetLineDblCS(ld))) { 262920d2c4d2Smrg i *= 2; 263020d2c4d2Smrg } 2631d522f475Smrg#endif 263220d2c4d2Smrg } 2633d522f475Smrg } 2634d522f475Smrg return (i); 2635d522f475Smrg} 2636d522f475Smrg 2637d522f475Smrg#if !OPT_WIDE_CHARS 2638d522f475Smrg/* 2639d522f475Smrg** double click table for cut and paste in 8 bits 2640d522f475Smrg** 2641d522f475Smrg** This table is divided in four parts : 2642d522f475Smrg** 2643d522f475Smrg** - control characters [0,0x1f] U [0x80,0x9f] 2644d522f475Smrg** - separators [0x20,0x3f] U [0xa0,0xb9] 2645d522f475Smrg** - binding characters [0x40,0x7f] U [0xc0,0xff] 2646d522f475Smrg** - exceptions 2647d522f475Smrg*/ 2648d522f475Smrg/* *INDENT-OFF* */ 2649d522f475Smrgstatic int charClass[256] = 2650d522f475Smrg{ 2651d522f475Smrg/* NUL SOH STX ETX EOT ENQ ACK BEL */ 2652d522f475Smrg 32, 1, 1, 1, 1, 1, 1, 1, 2653d522f475Smrg/* BS HT NL VT NP CR SO SI */ 2654d522f475Smrg 1, 32, 1, 1, 1, 1, 1, 1, 2655d522f475Smrg/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 2656d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2657d522f475Smrg/* CAN EM SUB ESC FS GS RS US */ 2658d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2659d522f475Smrg/* SP ! " # $ % & ' */ 2660d522f475Smrg 32, 33, 34, 35, 36, 37, 38, 39, 2661d522f475Smrg/* ( ) * + , - . / */ 2662d522f475Smrg 40, 41, 42, 43, 44, 45, 46, 47, 2663d522f475Smrg/* 0 1 2 3 4 5 6 7 */ 2664d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2665d522f475Smrg/* 8 9 : ; < = > ? */ 2666d522f475Smrg 48, 48, 58, 59, 60, 61, 62, 63, 2667d522f475Smrg/* @ A B C D E F G */ 2668d522f475Smrg 64, 48, 48, 48, 48, 48, 48, 48, 2669d522f475Smrg/* H I J K L M N O */ 2670d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2671d522f475Smrg/* P Q R S T U V W */ 2672d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2673d522f475Smrg/* X Y Z [ \ ] ^ _ */ 2674d522f475Smrg 48, 48, 48, 91, 92, 93, 94, 48, 2675d522f475Smrg/* ` a b c d e f g */ 2676d522f475Smrg 96, 48, 48, 48, 48, 48, 48, 48, 2677d522f475Smrg/* h i j k l m n o */ 2678d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2679d522f475Smrg/* p q r s t u v w */ 2680d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2681d522f475Smrg/* x y z { | } ~ DEL */ 2682d522f475Smrg 48, 48, 48, 123, 124, 125, 126, 1, 2683d522f475Smrg/* x80 x81 x82 x83 IND NEL SSA ESA */ 2684d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2685d522f475Smrg/* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 2686d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2687d522f475Smrg/* DCS PU1 PU2 STS CCH MW SPA EPA */ 2688d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2689d522f475Smrg/* x98 x99 x9A CSI ST OSC PM APC */ 2690d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2691d522f475Smrg/* - i c/ L ox Y- | So */ 2692d522f475Smrg 160, 161, 162, 163, 164, 165, 166, 167, 2693d522f475Smrg/* .. c0 ip << _ R0 - */ 2694d522f475Smrg 168, 169, 170, 171, 172, 173, 174, 175, 2695d522f475Smrg/* o +- 2 3 ' u q| . */ 2696d522f475Smrg 176, 177, 178, 179, 180, 181, 182, 183, 2697d522f475Smrg/* , 1 2 >> 1/4 1/2 3/4 ? */ 2698d522f475Smrg 184, 185, 186, 187, 188, 189, 190, 191, 2699d522f475Smrg/* A` A' A^ A~ A: Ao AE C, */ 2700d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2701d522f475Smrg/* E` E' E^ E: I` I' I^ I: */ 2702d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2703d522f475Smrg/* D- N~ O` O' O^ O~ O: X */ 2704d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 215, 2705d522f475Smrg/* O/ U` U' U^ U: Y' P B */ 2706d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2707d522f475Smrg/* a` a' a^ a~ a: ao ae c, */ 2708d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2709d522f475Smrg/* e` e' e^ e: i` i' i^ i: */ 2710d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2711d522f475Smrg/* d n~ o` o' o^ o~ o: -: */ 2712d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 247, 2713d522f475Smrg/* o/ u` u' u^ u: y' P y: */ 2714d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48}; 2715d522f475Smrg/* *INDENT-ON* */ 2716d522f475Smrg 2717d522f475Smrgint 2718d522f475SmrgSetCharacterClassRange(int low, /* in range of [0..255] */ 2719d522f475Smrg int high, 2720d522f475Smrg int value) /* arbitrary */ 2721d522f475Smrg{ 2722d522f475Smrg 2723d522f475Smrg if (low < 0 || high > 255 || high < low) 2724d522f475Smrg return (-1); 2725d522f475Smrg 2726d522f475Smrg for (; low <= high; low++) 2727d522f475Smrg charClass[low] = value; 2728d522f475Smrg 2729d522f475Smrg return (0); 2730d522f475Smrg} 2731d522f475Smrg#endif 2732d522f475Smrg 2733d522f475Smrgstatic int 2734956cc18dSsnjclass_of(LineData * ld, CELL * cell) 2735d522f475Smrg{ 2736d522f475Smrg CELL temp = *cell; 2737d522f475Smrg 2738d522f475Smrg#if OPT_DEC_CHRSET 2739956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 2740d522f475Smrg temp.col /= 2; 2741d522f475Smrg } 2742d522f475Smrg#endif 2743d522f475Smrg 274420d2c4d2Smrg assert(temp.col < ld->lineSize); 2745956cc18dSsnj return CharacterClass((int) (ld->charData[temp.col])); 2746d522f475Smrg} 2747956cc18dSsnj 2748956cc18dSsnj#if OPT_WIDE_CHARS 2749956cc18dSsnj#define CClassSelects(name, cclass) \ 2750956cc18dSsnj (CClassOf(name) == cclass \ 2751956cc18dSsnj || XTERM_CELL(screen->name.row, screen->name.col) == HIDDEN_CHAR) 2752d522f475Smrg#else 2753956cc18dSsnj#define CClassSelects(name, cclass) \ 2754956cc18dSsnj (class_of(ld.name, &((screen->name))) == cclass) 2755d522f475Smrg#endif 2756d522f475Smrg 2757956cc18dSsnj#define CClassOf(name) class_of(ld.name, &((screen->name))) 2758956cc18dSsnj 2759d522f475Smrg/* 2760d522f475Smrg * If the given column is past the end of text on the given row, bump to the 2761d522f475Smrg * beginning of the next line. 2762d522f475Smrg */ 2763d522f475Smrgstatic Boolean 2764d522f475SmrgokPosition(TScreen * screen, 2765956cc18dSsnj LineData ** ld, 2766d522f475Smrg CELL * cell) 2767d522f475Smrg{ 276820d2c4d2Smrg Boolean result = True; 276920d2c4d2Smrg 277020d2c4d2Smrg if (cell->row > screen->max_row) { 277120d2c4d2Smrg result = False; 277220d2c4d2Smrg } else if (cell->col > (LastTextCol(screen, *ld, cell->row) + 1)) { 277320d2c4d2Smrg if (cell->row < screen->max_row) { 277420d2c4d2Smrg cell->col = 0; 277520d2c4d2Smrg *ld = GET_LINEDATA(screen, ++cell->row); 277620d2c4d2Smrg result = False; 277720d2c4d2Smrg } 2778d522f475Smrg } 277920d2c4d2Smrg return result; 2780d522f475Smrg} 2781d522f475Smrg 2782d522f475Smrgstatic void 2783956cc18dSsnjtrimLastLine(TScreen * screen, 2784956cc18dSsnj LineData ** ld, 2785956cc18dSsnj CELL * last) 2786d522f475Smrg{ 278720d2c4d2Smrg if (screen->cutNewline && last->row < screen->max_row) { 2788d522f475Smrg last->col = 0; 2789956cc18dSsnj *ld = GET_LINEDATA(screen, ++last->row); 2790d522f475Smrg } else { 2791956cc18dSsnj last->col = LastTextCol(screen, *ld, last->row) + 1; 2792d522f475Smrg } 2793d522f475Smrg} 2794d522f475Smrg 2795d522f475Smrg#if OPT_SELECT_REGEX 2796d522f475Smrg/* 2797d522f475Smrg * Returns the first row of a wrapped line. 2798d522f475Smrg */ 2799d522f475Smrgstatic int 2800d522f475SmrgfirstRowOfLine(TScreen * screen, int row, Bool visible) 2801d522f475Smrg{ 2802956cc18dSsnj LineData *ld = 0; 2803d522f475Smrg int limit = visible ? 0 : -screen->savedlines; 2804d522f475Smrg 2805d522f475Smrg while (row > limit && 2806956cc18dSsnj (ld = GET_LINEDATA(screen, row - 1)) != 0 && 2807956cc18dSsnj LineTstWrapped(ld)) { 2808d522f475Smrg --row; 2809956cc18dSsnj } 2810d522f475Smrg return row; 2811d522f475Smrg} 2812d522f475Smrg 2813d522f475Smrg/* 2814d522f475Smrg * Returns the last row of a wrapped line. 2815d522f475Smrg */ 2816d522f475Smrgstatic int 2817d522f475SmrglastRowOfLine(TScreen * screen, int row) 2818d522f475Smrg{ 2819956cc18dSsnj LineData *ld; 2820956cc18dSsnj 2821d522f475Smrg while (row < screen->max_row && 2822956cc18dSsnj (ld = GET_LINEDATA(screen, row)) != 0 && 2823956cc18dSsnj LineTstWrapped(ld)) { 2824d522f475Smrg ++row; 2825956cc18dSsnj } 2826d522f475Smrg return row; 2827d522f475Smrg} 2828d522f475Smrg 2829d522f475Smrg/* 2830d522f475Smrg * Returns the number of cells on the range of rows. 2831d522f475Smrg */ 2832d522f475Smrgstatic unsigned 2833d522f475SmrglengthOfLines(TScreen * screen, int firstRow, int lastRow) 2834d522f475Smrg{ 2835d522f475Smrg unsigned length = 0; 2836d522f475Smrg int n; 2837d522f475Smrg 2838d522f475Smrg for (n = firstRow; n <= lastRow; ++n) { 2839956cc18dSsnj LineData *ld = GET_LINEDATA(screen, n); 2840956cc18dSsnj int value = LastTextCol(screen, ld, n); 2841d522f475Smrg if (value >= 0) 28422eaa94a1Schristos length += (unsigned) (value + 1); 2843d522f475Smrg } 2844d522f475Smrg return length; 2845d522f475Smrg} 2846d522f475Smrg 2847d522f475Smrg/* 2848d522f475Smrg * Make a copy of the wrapped-line which corresponds to the given row as a 2849d522f475Smrg * string of bytes. Construct an index for the columns from the beginning of 2850d522f475Smrg * the line. 2851d522f475Smrg */ 2852d522f475Smrgstatic char * 2853d522f475Smrgmake_indexed_text(TScreen * screen, int row, unsigned length, int *indexed) 2854d522f475Smrg{ 2855d522f475Smrg Char *result = 0; 285620d2c4d2Smrg size_t need = (length + 1); 2857d522f475Smrg 2858d522f475Smrg /* 2859d522f475Smrg * Get a quick upper bound to the number of bytes needed, if the whole 2860d522f475Smrg * string were UTF-8. 2861d522f475Smrg */ 2862d522f475Smrg if_OPT_WIDE_CHARS(screen, { 2863956cc18dSsnj need *= ((screen->lineExtra + 1) * 6); 2864d522f475Smrg }); 2865d522f475Smrg 2866d522f475Smrg if ((result = TypeCallocN(Char, need + 1)) != 0) { 2867956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 2868d522f475Smrg unsigned used = 0; 2869d522f475Smrg Char *last = result; 2870d522f475Smrg 2871d522f475Smrg do { 2872d522f475Smrg int col = 0; 2873956cc18dSsnj int limit = LastTextCol(screen, ld, row); 2874d522f475Smrg 2875d522f475Smrg while (col <= limit) { 2876d522f475Smrg Char *next = last; 2877956cc18dSsnj unsigned data = ld->charData[col]; 2878d522f475Smrg 287920d2c4d2Smrg assert(col < ld->lineSize); 2880d522f475Smrg /* some internal points may not be drawn */ 2881d522f475Smrg if (data == 0) 2882d522f475Smrg data = ' '; 2883d522f475Smrg 2884d522f475Smrg if_WIDE_OR_NARROW(screen, { 2885d522f475Smrg next = convertToUTF8(last, data); 2886d522f475Smrg } 2887d522f475Smrg , { 2888d522f475Smrg *next++ = CharOf(data); 2889d522f475Smrg }); 2890d522f475Smrg 2891d522f475Smrg if_OPT_WIDE_CHARS(screen, { 2892956cc18dSsnj size_t off; 2893956cc18dSsnj for_each_combData(off, ld) { 2894956cc18dSsnj data = ld->combData[off][col]; 2895956cc18dSsnj if (data == 0) 2896d522f475Smrg break; 2897d522f475Smrg next = convertToUTF8(next, data); 2898d522f475Smrg } 2899d522f475Smrg }); 2900d522f475Smrg 290120d2c4d2Smrg indexed[used] = (int) (last - result); 2902d522f475Smrg *next = 0; 2903d522f475Smrg /* TRACE(("index[%d.%d] %d:%s\n", row, used, indexed[used], last)); */ 2904d522f475Smrg last = next; 2905d522f475Smrg ++used; 2906d522f475Smrg ++col; 290720d2c4d2Smrg indexed[used] = (int) (next - result); 2908d522f475Smrg } 2909d522f475Smrg } while (used < length && 2910956cc18dSsnj LineTstWrapped(ld) && 2911956cc18dSsnj (ld = GET_LINEDATA(screen, ++row)) != 0 && 2912956cc18dSsnj row < screen->max_row); 2913d522f475Smrg } 2914d522f475Smrg /* TRACE(("result:%s\n", result)); */ 2915d522f475Smrg return (char *) result; 2916d522f475Smrg} 2917d522f475Smrg 2918d522f475Smrg/* 2919d522f475Smrg * Find the column given an offset into the character string by using the 2920d522f475Smrg * index constructed in make_indexed_text(). 2921d522f475Smrg */ 2922d522f475Smrgstatic int 2923d522f475SmrgindexToCol(int *indexed, int len, int off) 2924d522f475Smrg{ 2925d522f475Smrg int col = 0; 2926d522f475Smrg while (indexed[col] < len) { 2927d522f475Smrg if (indexed[col] >= off) 2928d522f475Smrg break; 2929d522f475Smrg ++col; 2930d522f475Smrg } 2931d522f475Smrg return col; 2932d522f475Smrg} 2933d522f475Smrg 2934d522f475Smrg/* 2935d522f475Smrg * Given a row number, and a column offset from that (which may be wrapped), 2936d522f475Smrg * set the cell to the actual row/column values. 2937d522f475Smrg */ 2938d522f475Smrgstatic void 2939d522f475SmrgcolumnToCell(TScreen * screen, int row, int col, CELL * cell) 2940d522f475Smrg{ 2941d522f475Smrg while (row < screen->max_row) { 2942956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 2943956cc18dSsnj int last = LastTextCol(screen, ld, row); 2944d522f475Smrg 2945d522f475Smrg /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */ 2946d522f475Smrg if (col <= last) { 2947d522f475Smrg break; 2948d522f475Smrg } 2949d522f475Smrg /* 2950d522f475Smrg * Stop if the current row does not wrap (does not continue the current 2951d522f475Smrg * line). 2952d522f475Smrg */ 2953956cc18dSsnj if (!LineTstWrapped(ld)) { 2954d522f475Smrg col = last + 1; 2955d522f475Smrg break; 2956d522f475Smrg } 2957d522f475Smrg col -= (last + 1); 2958d522f475Smrg ++row; 2959d522f475Smrg } 2960d522f475Smrg if (col < 0) 2961d522f475Smrg col = 0; 2962d522f475Smrg cell->row = row; 2963d522f475Smrg cell->col = col; 2964d522f475Smrg} 2965d522f475Smrg 2966d522f475Smrg/* 2967d522f475Smrg * Given a cell, find the corresponding column offset. 2968d522f475Smrg */ 2969d522f475Smrgstatic int 2970d522f475SmrgcellToColumn(TScreen * screen, CELL * cell) 2971d522f475Smrg{ 2972956cc18dSsnj LineData *ld = 0; 2973d522f475Smrg int col = cell->col; 2974d522f475Smrg int row = firstRowOfLine(screen, cell->row, False); 2975d522f475Smrg while (row < cell->row) { 2976956cc18dSsnj ld = GET_LINEDATA(screen, row); 2977956cc18dSsnj col += LastTextCol(screen, ld, row++); 2978d522f475Smrg } 2979956cc18dSsnj#if OPT_DEC_CHRSET 2980956cc18dSsnj if (ld == 0) 2981956cc18dSsnj ld = GET_LINEDATA(screen, row); 2982956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 2983956cc18dSsnj col /= 2; 2984956cc18dSsnj#endif 2985d522f475Smrg return col; 2986d522f475Smrg} 2987d522f475Smrg 2988d522f475Smrgstatic void 2989d522f475Smrgdo_select_regex(TScreen * screen, CELL * startc, CELL * endc) 2990d522f475Smrg{ 2991956cc18dSsnj LineData *ld = GET_LINEDATA(screen, startc->row); 2992d522f475Smrg int inx = ((screen->numberOfClicks - 1) % screen->maxClicks); 2993d522f475Smrg char *expr = screen->selectExpr[inx]; 2994d522f475Smrg regex_t preg; 2995d522f475Smrg regmatch_t match; 2996d522f475Smrg char *search; 2997d522f475Smrg int *indexed; 2998d522f475Smrg 2999d522f475Smrg TRACE(("Select_REGEX:%s\n", NonNull(expr))); 3000956cc18dSsnj if (okPosition(screen, &ld, startc) && expr != 0) { 3001d522f475Smrg if (regcomp(&preg, expr, REG_EXTENDED) == 0) { 3002d522f475Smrg int firstRow = firstRowOfLine(screen, startc->row, True); 3003d522f475Smrg int lastRow = lastRowOfLine(screen, firstRow); 3004d522f475Smrg unsigned size = lengthOfLines(screen, firstRow, lastRow); 3005d522f475Smrg int actual = cellToColumn(screen, startc); 3006d522f475Smrg 3007d522f475Smrg TRACE(("regcomp ok rows %d..%d bytes %d\n", 3008d522f475Smrg firstRow, lastRow, size)); 3009d522f475Smrg 3010d522f475Smrg if ((indexed = TypeCallocN(int, size + 1)) != 0) { 3011d522f475Smrg if ((search = make_indexed_text(screen, 3012d522f475Smrg firstRow, 3013d522f475Smrg size, 3014d522f475Smrg indexed)) != 0) { 30152eaa94a1Schristos int len = (int) strlen(search); 3016d522f475Smrg int col; 3017d522f475Smrg int best_col = -1; 3018d522f475Smrg int best_len = -1; 3019d522f475Smrg 3020d522f475Smrg for (col = 0; indexed[col] < len; ++col) { 3021d522f475Smrg if (regexec(&preg, 3022d522f475Smrg search + indexed[col], 302320d2c4d2Smrg (size_t) 1, &match, 0) == 0) { 3024d522f475Smrg int start_inx = match.rm_so + indexed[col]; 3025d522f475Smrg int finis_inx = match.rm_eo + indexed[col]; 3026d522f475Smrg int start_col = indexToCol(indexed, len, start_inx); 3027d522f475Smrg int finis_col = indexToCol(indexed, len, finis_inx); 3028d522f475Smrg 3029d522f475Smrg if (start_col <= actual && 3030d522f475Smrg actual < finis_col) { 3031d522f475Smrg int test = finis_col - start_col; 3032d522f475Smrg if (best_len < test) { 3033d522f475Smrg best_len = test; 3034d522f475Smrg best_col = start_col; 3035d522f475Smrg TRACE(("match column %d len %d\n", 3036d522f475Smrg best_col, 3037d522f475Smrg best_len)); 3038d522f475Smrg } 3039d522f475Smrg } 3040d522f475Smrg } 3041d522f475Smrg } 3042d522f475Smrg if (best_col >= 0) { 3043d522f475Smrg int best_nxt = best_col + best_len; 3044d522f475Smrg columnToCell(screen, firstRow, best_col, startc); 3045d522f475Smrg columnToCell(screen, firstRow, best_nxt, endc); 3046d522f475Smrg TRACE(("search::%s\n", search)); 3047d522f475Smrg TRACE(("indexed:%d..%d -> %d..%d\n", 3048d522f475Smrg best_col, best_nxt, 3049d522f475Smrg indexed[best_col], 3050d522f475Smrg indexed[best_nxt])); 3051d522f475Smrg TRACE(("matched:%d:%s\n", 3052d522f475Smrg indexed[best_nxt] + 1 - 3053d522f475Smrg indexed[best_col], 3054956cc18dSsnj visibleChars((Char *) (search + indexed[best_col]), 3055d522f475Smrg (unsigned) (indexed[best_nxt] + 3056d522f475Smrg 1 - 3057d522f475Smrg indexed[best_col])))); 3058d522f475Smrg } 3059d522f475Smrg free(search); 3060d522f475Smrg } 3061d522f475Smrg free(indexed); 3062956cc18dSsnj#if OPT_DEC_CHRSET 3063956cc18dSsnj if ((ld = GET_LINEDATA(screen, startc->row)) != 0) { 3064956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3065956cc18dSsnj startc->col *= 2; 3066956cc18dSsnj } 3067956cc18dSsnj if ((ld = GET_LINEDATA(screen, endc->row)) != 0) { 3068956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 3069956cc18dSsnj endc->col *= 2; 3070956cc18dSsnj } 3071956cc18dSsnj#endif 3072d522f475Smrg } 3073d522f475Smrg regfree(&preg); 3074d522f475Smrg } 3075d522f475Smrg } 3076d522f475Smrg} 3077d522f475Smrg#endif /* OPT_SELECT_REGEX */ 3078d522f475Smrg 3079956cc18dSsnj#define InitRow(name) \ 3080956cc18dSsnj ld.name = GET_LINEDATA(screen, screen->name.row) 3081956cc18dSsnj 3082956cc18dSsnj#define NextRow(name) \ 3083956cc18dSsnj ld.name = GET_LINEDATA(screen, ++screen->name.row) 3084956cc18dSsnj 3085956cc18dSsnj#define PrevRow(name) \ 3086956cc18dSsnj ld.name = GET_LINEDATA(screen, --screen->name.row) 3087956cc18dSsnj 308820d2c4d2Smrg#define MoreRows(name) \ 308920d2c4d2Smrg (screen->name.row < screen->max_row) 309020d2c4d2Smrg 3091956cc18dSsnj#define isPrevWrapped(name) \ 3092956cc18dSsnj (screen->name.row > 0 \ 3093956cc18dSsnj && (ltmp = GET_LINEDATA(screen, screen->name.row - 1)) != 0 \ 3094956cc18dSsnj && LineTstWrapped(ltmp)) 3095956cc18dSsnj 3096d522f475Smrg/* 3097d522f475Smrg * sets startSel endSel 3098d522f475Smrg * ensuring that they have legal values 3099d522f475Smrg */ 3100d522f475Smrgstatic void 3101d522f475SmrgComputeSelect(XtermWidget xw, 3102d522f475Smrg CELL * startc, 3103d522f475Smrg CELL * endc, 3104d522f475Smrg Bool extend) 3105d522f475Smrg{ 3106956cc18dSsnj TScreen *screen = TScreenOf(xw); 3107956cc18dSsnj 3108d522f475Smrg int length; 3109d522f475Smrg int cclass; 3110d522f475Smrg CELL first = *startc; 3111d522f475Smrg CELL last = *endc; 3112956cc18dSsnj Boolean ignored = False; 3113956cc18dSsnj 3114956cc18dSsnj struct { 3115956cc18dSsnj LineData *startSel; 3116956cc18dSsnj LineData *endSel; 3117956cc18dSsnj } ld; 3118956cc18dSsnj LineData *ltmp; 3119d522f475Smrg 3120d522f475Smrg TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n", 3121d522f475Smrg first.row, first.col, 3122d522f475Smrg last.row, last.col, 3123d522f475Smrg extend ? "" : "no")); 3124d522f475Smrg 3125d522f475Smrg#if OPT_WIDE_CHARS 3126d522f475Smrg if (first.col > 1 3127d522f475Smrg && isWideCell(first.row, first.col - 1) 3128d522f475Smrg && XTERM_CELL(first.row, first.col - 0) == HIDDEN_CHAR) { 312920d2c4d2Smrg TRACE(("Adjusting start. Changing downwards from %i.\n", first.col)); 3130d522f475Smrg first.col -= 1; 3131d522f475Smrg if (last.col == (first.col + 1)) 3132d522f475Smrg last.col--; 3133d522f475Smrg } 3134d522f475Smrg 3135d522f475Smrg if (last.col > 1 3136d522f475Smrg && isWideCell(last.row, last.col - 1) 3137d522f475Smrg && XTERM_CELL(last.row, last.col) == HIDDEN_CHAR) { 3138d522f475Smrg last.col += 1; 3139d522f475Smrg } 3140d522f475Smrg#endif 3141d522f475Smrg 3142d522f475Smrg if (Coordinate(screen, &first) <= Coordinate(screen, &last)) { 3143d522f475Smrg screen->startSel = screen->startRaw = first; 3144d522f475Smrg screen->endSel = screen->endRaw = last; 3145d522f475Smrg } else { /* Swap them */ 3146d522f475Smrg screen->startSel = screen->startRaw = last; 3147d522f475Smrg screen->endSel = screen->endRaw = first; 3148d522f475Smrg } 3149d522f475Smrg 3150956cc18dSsnj InitRow(startSel); 3151956cc18dSsnj InitRow(endSel); 3152956cc18dSsnj 3153d522f475Smrg switch (screen->selectUnit) { 3154d522f475Smrg case Select_CHAR: 3155956cc18dSsnj (void) okPosition(screen, &(ld.startSel), &(screen->startSel)); 3156956cc18dSsnj (void) okPosition(screen, &(ld.endSel), &(screen->endSel)); 3157d522f475Smrg break; 3158d522f475Smrg 3159d522f475Smrg case Select_WORD: 3160d522f475Smrg TRACE(("Select_WORD\n")); 3161956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 3162956cc18dSsnj cclass = CClassOf(startSel); 3163d522f475Smrg do { 3164d522f475Smrg --screen->startSel.col; 3165956cc18dSsnj if (screen->startSel.col < 0 3166956cc18dSsnj && isPrevWrapped(startSel)) { 3167956cc18dSsnj PrevRow(startSel); 3168956cc18dSsnj screen->startSel.col = LastTextCol(screen, ld.startSel, screen->startSel.row); 3169d522f475Smrg } 3170d522f475Smrg } while (screen->startSel.col >= 0 3171956cc18dSsnj && CClassSelects(startSel, cclass)); 3172d522f475Smrg ++screen->startSel.col; 3173d522f475Smrg } 3174d522f475Smrg#if OPT_WIDE_CHARS 3175d522f475Smrg if (screen->startSel.col 3176d522f475Smrg && XTERM_CELL(screen->startSel.row, 3177d522f475Smrg screen->startSel.col) == HIDDEN_CHAR) 3178d522f475Smrg screen->startSel.col++; 3179d522f475Smrg#endif 3180d522f475Smrg 3181956cc18dSsnj if (okPosition(screen, &(ld.endSel), &(screen->endSel))) { 3182956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 3183956cc18dSsnj cclass = CClassOf(endSel); 3184d522f475Smrg do { 3185d522f475Smrg ++screen->endSel.col; 3186d522f475Smrg if (screen->endSel.col > length 3187956cc18dSsnj && LineTstWrapped(ld.endSel)) { 318820d2c4d2Smrg if (!MoreRows(endSel)) 318920d2c4d2Smrg break; 3190d522f475Smrg screen->endSel.col = 0; 3191956cc18dSsnj NextRow(endSel); 3192956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 3193d522f475Smrg } 3194d522f475Smrg } while (screen->endSel.col <= length 3195956cc18dSsnj && CClassSelects(endSel, cclass)); 3196d522f475Smrg /* Word-select selects if pointing to any char in "word", 3197d522f475Smrg * especially note that it includes the last character in a word. 3198d522f475Smrg * So we do no --endSel.col and do special eol handling. 3199d522f475Smrg */ 320020d2c4d2Smrg if (screen->endSel.col > length + 1 320120d2c4d2Smrg && MoreRows(endSel)) { 3202d522f475Smrg screen->endSel.col = 0; 3203956cc18dSsnj NextRow(endSel); 3204d522f475Smrg } 3205d522f475Smrg } 3206d522f475Smrg#if OPT_WIDE_CHARS 3207d522f475Smrg if (screen->endSel.col 3208d522f475Smrg && XTERM_CELL(screen->endSel.row, 3209d522f475Smrg screen->endSel.col) == HIDDEN_CHAR) 3210d522f475Smrg screen->endSel.col++; 3211d522f475Smrg#endif 3212d522f475Smrg 3213d522f475Smrg screen->saveStartW = screen->startSel; 3214d522f475Smrg break; 3215d522f475Smrg 3216d522f475Smrg case Select_LINE: 3217d522f475Smrg TRACE(("Select_LINE\n")); 321820d2c4d2Smrg while (LineTstWrapped(ld.endSel) 321920d2c4d2Smrg && MoreRows(endSel)) { 3220956cc18dSsnj NextRow(endSel); 3221d522f475Smrg } 3222d522f475Smrg if (screen->cutToBeginningOfLine 3223d522f475Smrg || screen->startSel.row < screen->saveStartW.row) { 3224d522f475Smrg screen->startSel.col = 0; 3225956cc18dSsnj while (isPrevWrapped(startSel)) { 3226956cc18dSsnj PrevRow(startSel); 3227d522f475Smrg } 3228d522f475Smrg } else if (!extend) { 3229d522f475Smrg if ((first.row < screen->saveStartW.row) 3230d522f475Smrg || (isSameRow(&first, &(screen->saveStartW)) 3231d522f475Smrg && first.col < screen->saveStartW.col)) { 3232d522f475Smrg screen->startSel.col = 0; 3233956cc18dSsnj while (isPrevWrapped(startSel)) { 3234956cc18dSsnj PrevRow(startSel); 3235d522f475Smrg } 3236d522f475Smrg } else { 3237d522f475Smrg screen->startSel = screen->saveStartW; 3238d522f475Smrg } 3239d522f475Smrg } 3240956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 3241d522f475Smrg break; 3242d522f475Smrg 3243d522f475Smrg case Select_GROUP: /* paragraph */ 3244d522f475Smrg TRACE(("Select_GROUP\n")); 3245956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 3246d522f475Smrg /* scan backward for beginning of group */ 3247d522f475Smrg while (screen->startSel.row > 0 && 3248956cc18dSsnj (LastTextCol(screen, ld.startSel, screen->startSel.row - 3249956cc18dSsnj 1) > 0 || 3250956cc18dSsnj isPrevWrapped(startSel))) { 3251956cc18dSsnj PrevRow(startSel); 3252d522f475Smrg } 3253d522f475Smrg screen->startSel.col = 0; 3254d522f475Smrg /* scan forward for end of group */ 325520d2c4d2Smrg while (MoreRows(endSel) && 3256956cc18dSsnj (LastTextCol(screen, ld.endSel, screen->endSel.row + 1) > 3257956cc18dSsnj 0 || 3258956cc18dSsnj LineTstWrapped(ld.endSel))) { 3259956cc18dSsnj NextRow(endSel); 3260d522f475Smrg } 3261956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 3262d522f475Smrg } 3263d522f475Smrg break; 3264d522f475Smrg 3265d522f475Smrg case Select_PAGE: /* everything one can see */ 3266d522f475Smrg TRACE(("Select_PAGE\n")); 3267d522f475Smrg screen->startSel.row = 0; 3268d522f475Smrg screen->startSel.col = 0; 326920d2c4d2Smrg screen->endSel.row = MaxRows(screen); 3270d522f475Smrg screen->endSel.col = 0; 3271d522f475Smrg break; 3272d522f475Smrg 3273d522f475Smrg case Select_ALL: /* counts scrollback if in normal screen */ 3274d522f475Smrg TRACE(("Select_ALL\n")); 3275d522f475Smrg screen->startSel.row = -screen->savedlines; 3276d522f475Smrg screen->startSel.col = 0; 327720d2c4d2Smrg screen->endSel.row = MaxRows(screen); 3278d522f475Smrg screen->endSel.col = 0; 3279d522f475Smrg break; 3280d522f475Smrg 3281d522f475Smrg#if OPT_SELECT_REGEX 3282d522f475Smrg case Select_REGEX: 3283d522f475Smrg do_select_regex(screen, &(screen->startSel), &(screen->endSel)); 3284d522f475Smrg break; 3285d522f475Smrg#endif 3286d522f475Smrg 3287d522f475Smrg case NSELECTUNITS: /* always ignore */ 3288956cc18dSsnj ignored = True; 3289956cc18dSsnj break; 3290d522f475Smrg } 3291d522f475Smrg 3292956cc18dSsnj if (!ignored) { 3293956cc18dSsnj /* check boundaries */ 3294956cc18dSsnj ScrollSelection(screen, 0, False); 3295956cc18dSsnj TrackText(xw, &(screen->startSel), &(screen->endSel)); 3296956cc18dSsnj } 3297d522f475Smrg 3298d522f475Smrg return; 3299d522f475Smrg} 3300d522f475Smrg 3301d522f475Smrg/* Guaranteed (first.row, first.col) <= (last.row, last.col) */ 3302d522f475Smrgstatic void 3303d522f475SmrgTrackText(XtermWidget xw, 3304d522f475Smrg const CELL * firstp, 3305d522f475Smrg const CELL * lastp) 3306d522f475Smrg{ 3307956cc18dSsnj TScreen *screen = TScreenOf(xw); 3308d522f475Smrg int from, to; 3309d522f475Smrg CELL old_start, old_end; 3310d522f475Smrg CELL first = *firstp; 3311d522f475Smrg CELL last = *lastp; 3312d522f475Smrg 3313d522f475Smrg TRACE(("TrackText(first=%d,%d, last=%d,%d)\n", 3314d522f475Smrg first.row, first.col, last.row, last.col)); 3315d522f475Smrg 3316d522f475Smrg old_start = screen->startH; 3317d522f475Smrg old_end = screen->endH; 3318d522f475Smrg if (isSameCELL(&first, &old_start) && 3319d522f475Smrg isSameCELL(&last, &old_end)) 3320d522f475Smrg return; 3321d522f475Smrg screen->startH = first; 3322d522f475Smrg screen->endH = last; 3323d522f475Smrg from = Coordinate(screen, &screen->startH); 3324d522f475Smrg to = Coordinate(screen, &screen->endH); 3325d522f475Smrg if (to <= screen->startHCoord || from > screen->endHCoord) { 3326d522f475Smrg /* No overlap whatsoever between old and new hilite */ 3327d522f475Smrg ReHiliteText(xw, &old_start, &old_end); 3328d522f475Smrg ReHiliteText(xw, &first, &last); 3329d522f475Smrg } else { 3330d522f475Smrg if (from < screen->startHCoord) { 3331d522f475Smrg /* Extend left end */ 3332d522f475Smrg ReHiliteText(xw, &first, &old_start); 3333d522f475Smrg } else if (from > screen->startHCoord) { 3334d522f475Smrg /* Shorten left end */ 3335d522f475Smrg ReHiliteText(xw, &old_start, &first); 3336d522f475Smrg } 3337d522f475Smrg if (to > screen->endHCoord) { 3338d522f475Smrg /* Extend right end */ 3339d522f475Smrg ReHiliteText(xw, &old_end, &last); 3340d522f475Smrg } else if (to < screen->endHCoord) { 3341d522f475Smrg /* Shorten right end */ 3342d522f475Smrg ReHiliteText(xw, &last, &old_end); 3343d522f475Smrg } 3344d522f475Smrg } 3345d522f475Smrg screen->startHCoord = from; 3346d522f475Smrg screen->endHCoord = to; 3347d522f475Smrg} 3348d522f475Smrg 3349d522f475Smrg/* Guaranteed that (first->row, first->col) <= (last->row, last->col) */ 3350d522f475Smrgstatic void 3351d522f475SmrgReHiliteText(XtermWidget xw, 3352d522f475Smrg CELL * firstp, 3353d522f475Smrg CELL * lastp) 3354d522f475Smrg{ 3355956cc18dSsnj TScreen *screen = TScreenOf(xw); 3356d522f475Smrg int i; 3357d522f475Smrg CELL first = *firstp; 3358d522f475Smrg CELL last = *lastp; 3359d522f475Smrg 3360d522f475Smrg TRACE(("ReHiliteText from %d.%d to %d.%d\n", 3361d522f475Smrg first.row, first.col, last.row, last.col)); 3362d522f475Smrg 3363d522f475Smrg if (first.row < 0) 3364d522f475Smrg first.row = first.col = 0; 3365d522f475Smrg else if (first.row > screen->max_row) 3366d522f475Smrg return; /* nothing to do, since last.row >= first.row */ 3367d522f475Smrg 3368d522f475Smrg if (last.row < 0) 3369d522f475Smrg return; /* nothing to do, since first.row <= last.row */ 3370d522f475Smrg else if (last.row > screen->max_row) { 3371d522f475Smrg last.row = screen->max_row; 3372d522f475Smrg last.col = MaxCols(screen); 3373d522f475Smrg } 3374d522f475Smrg if (isSameCELL(&first, &last)) 3375d522f475Smrg return; 3376d522f475Smrg 3377d522f475Smrg if (!isSameRow(&first, &last)) { /* do multiple rows */ 3378d522f475Smrg if ((i = screen->max_col - first.col + 1) > 0) { /* first row */ 3379d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, i, True); 3380d522f475Smrg } 3381d522f475Smrg if ((i = last.row - first.row - 1) > 0) { /* middle rows */ 3382d522f475Smrg ScrnRefresh(xw, first.row + 1, 0, i, MaxCols(screen), True); 3383d522f475Smrg } 3384d522f475Smrg if (last.col > 0 && last.row <= screen->max_row) { /* last row */ 3385d522f475Smrg ScrnRefresh(xw, last.row, 0, 1, last.col, True); 3386d522f475Smrg } 3387d522f475Smrg } else { /* do single row */ 3388d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, last.col - first.col, True); 3389d522f475Smrg } 3390d522f475Smrg} 3391d522f475Smrg 3392d522f475Smrg/* 3393d522f475Smrg * Guaranteed that (cellc->row, cellc->col) <= (cell->row, cell->col), and that both points are valid 3394d522f475Smrg * (may have cell->row = screen->max_row+1, cell->col = 0). 3395d522f475Smrg */ 3396d522f475Smrgstatic void 3397d522f475SmrgSaltTextAway(XtermWidget xw, 3398d522f475Smrg CELL * cellc, 3399d522f475Smrg CELL * cell, 3400d522f475Smrg String * params, /* selections */ 3401d522f475Smrg Cardinal num_params) 3402d522f475Smrg{ 3403956cc18dSsnj TScreen *screen = TScreenOf(xw); 3404d522f475Smrg int i, j = 0; 3405d522f475Smrg int eol; 3406956cc18dSsnj int tmp; 3407d522f475Smrg Char *line; 3408d522f475Smrg Char *lp; 3409d522f475Smrg CELL first = *cellc; 3410d522f475Smrg CELL last = *cell; 3411d522f475Smrg 3412d522f475Smrg if (isSameRow(&first, &last) && first.col > last.col) { 3413956cc18dSsnj EXCHANGE(first.col, last.col, tmp); 3414d522f475Smrg } 3415d522f475Smrg 3416d522f475Smrg --last.col; 3417d522f475Smrg /* first we need to know how long the string is before we can save it */ 3418d522f475Smrg 3419d522f475Smrg if (isSameRow(&last, &first)) { 3420d522f475Smrg j = Length(screen, first.row, first.col, last.col); 3421d522f475Smrg } else { /* two cases, cut is on same line, cut spans multiple lines */ 3422d522f475Smrg j += Length(screen, first.row, first.col, screen->max_col) + 1; 3423d522f475Smrg for (i = first.row + 1; i < last.row; i++) 3424d522f475Smrg j += Length(screen, i, 0, screen->max_col) + 1; 3425d522f475Smrg if (last.col >= 0) 3426d522f475Smrg j += Length(screen, last.row, 0, last.col); 3427d522f475Smrg } 3428d522f475Smrg 3429d522f475Smrg /* UTF-8 may require more space */ 3430d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3431d522f475Smrg j *= 4; 3432d522f475Smrg }); 3433d522f475Smrg 3434d522f475Smrg /* now get some memory to save it in */ 3435d522f475Smrg 3436d522f475Smrg if (screen->selection_size <= j) { 343720d2c4d2Smrg if ((line = (Char *) malloc((size_t) j + 1)) == 0) 3438d522f475Smrg SysError(ERROR_BMALLOC2); 3439d522f475Smrg XtFree((char *) screen->selection_data); 3440d522f475Smrg screen->selection_data = line; 3441d522f475Smrg screen->selection_size = j + 1; 3442d522f475Smrg } else { 3443d522f475Smrg line = screen->selection_data; 3444d522f475Smrg } 3445d522f475Smrg 3446d522f475Smrg if ((line == 0) 3447d522f475Smrg || (j < 0)) 3448d522f475Smrg return; 3449d522f475Smrg 3450d522f475Smrg line[j] = '\0'; /* make sure it is null terminated */ 3451d522f475Smrg lp = line; /* lp points to where to save the text */ 3452d522f475Smrg if (isSameRow(&last, &first)) { 3453d522f475Smrg lp = SaveText(screen, last.row, first.col, last.col, lp, &eol); 3454d522f475Smrg } else { 3455d522f475Smrg lp = SaveText(screen, first.row, first.col, screen->max_col, lp, &eol); 3456d522f475Smrg if (eol) 3457d522f475Smrg *lp++ = '\n'; /* put in newline at end of line */ 3458d522f475Smrg for (i = first.row + 1; i < last.row; i++) { 3459d522f475Smrg lp = SaveText(screen, i, 0, screen->max_col, lp, &eol); 3460d522f475Smrg if (eol) 3461d522f475Smrg *lp++ = '\n'; 3462d522f475Smrg } 3463d522f475Smrg if (last.col >= 0) 3464d522f475Smrg lp = SaveText(screen, last.row, 0, last.col, lp, &eol); 3465d522f475Smrg } 3466d522f475Smrg *lp = '\0'; /* make sure we have end marked */ 3467d522f475Smrg 3468956cc18dSsnj TRACE(("Salted TEXT:%d:%s\n", (int) (lp - line), 3469956cc18dSsnj visibleChars(line, (unsigned) (lp - line)))); 3470d522f475Smrg 34712eaa94a1Schristos screen->selection_length = (unsigned long) (lp - line); 3472d522f475Smrg _OwnSelection(xw, params, num_params); 3473d522f475Smrg} 3474d522f475Smrg 3475d522f475Smrg#if OPT_PASTE64 3476d522f475Smrgvoid 3477d522f475SmrgClearSelectionBuffer(TScreen * screen) 3478d522f475Smrg{ 3479d522f475Smrg screen->selection_length = 0; 3480d522f475Smrg screen->base64_count = 0; 3481d522f475Smrg} 3482d522f475Smrg 3483d522f475Smrgstatic void 348420d2c4d2SmrgAppendStrToSelectionBuffer(TScreen * screen, Char * text, size_t len) 3485d522f475Smrg{ 3486d522f475Smrg if (len != 0) { 34872eaa94a1Schristos int j = (int) (screen->selection_length + len); /* New length */ 3488d522f475Smrg int k = j + (j >> 2) + 80; /* New size if we grow buffer: grow by ~50% */ 3489d522f475Smrg if (j + 1 >= screen->selection_size) { 3490d522f475Smrg if (!screen->selection_length) { 3491d522f475Smrg /* New buffer */ 3492d522f475Smrg Char *line; 349320d2c4d2Smrg if ((line = (Char *) malloc((size_t) k)) == 0) 3494d522f475Smrg SysError(ERROR_BMALLOC2); 3495d522f475Smrg XtFree((char *) screen->selection_data); 3496d522f475Smrg screen->selection_data = line; 3497d522f475Smrg } else { 3498d522f475Smrg /* Realloc buffer */ 3499d522f475Smrg screen->selection_data = (Char *) 3500d522f475Smrg realloc(screen->selection_data, 350120d2c4d2Smrg (size_t) k); 3502d522f475Smrg if (screen->selection_data == 0) 3503d522f475Smrg SysError(ERROR_BMALLOC2); 3504d522f475Smrg } 3505d522f475Smrg screen->selection_size = k; 3506d522f475Smrg } 350720d2c4d2Smrg if (screen->selection_data != 0) { 350820d2c4d2Smrg memcpy(screen->selection_data + screen->selection_length, text, len); 350920d2c4d2Smrg screen->selection_length += len; 351020d2c4d2Smrg screen->selection_data[screen->selection_length] = 0; 351120d2c4d2Smrg } 3512d522f475Smrg } 3513d522f475Smrg} 3514d522f475Smrg 3515d522f475Smrgvoid 3516d522f475SmrgAppendToSelectionBuffer(TScreen * screen, unsigned c) 3517d522f475Smrg{ 35182eaa94a1Schristos unsigned six; 3519d522f475Smrg Char ch; 3520d522f475Smrg 3521d522f475Smrg /* Decode base64 character */ 3522d522f475Smrg if (c >= 'A' && c <= 'Z') 3523d522f475Smrg six = c - 'A'; 3524d522f475Smrg else if (c >= 'a' && c <= 'z') 3525d522f475Smrg six = c - 'a' + 26; 3526d522f475Smrg else if (c >= '0' && c <= '9') 3527d522f475Smrg six = c - '0' + 52; 3528d522f475Smrg else if (c == '+') 3529d522f475Smrg six = 62; 3530d522f475Smrg else if (c == '/') 3531d522f475Smrg six = 63; 3532d522f475Smrg else 3533d522f475Smrg return; 3534d522f475Smrg 3535d522f475Smrg /* Accumulate bytes */ 3536d522f475Smrg switch (screen->base64_count) { 3537d522f475Smrg case 0: 3538d522f475Smrg screen->base64_accu = six; 3539d522f475Smrg screen->base64_count = 6; 3540d522f475Smrg break; 3541d522f475Smrg 3542d522f475Smrg case 2: 35432eaa94a1Schristos ch = CharOf((screen->base64_accu << 6) + six); 3544d522f475Smrg screen->base64_count = 0; 354520d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3546d522f475Smrg break; 3547d522f475Smrg 3548d522f475Smrg case 4: 35492eaa94a1Schristos ch = CharOf((screen->base64_accu << 4) + (six >> 2)); 3550d522f475Smrg screen->base64_accu = (six & 0x3); 3551d522f475Smrg screen->base64_count = 2; 355220d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3553d522f475Smrg break; 3554d522f475Smrg 3555d522f475Smrg case 6: 35562eaa94a1Schristos ch = CharOf((screen->base64_accu << 2) + (six >> 4)); 3557d522f475Smrg screen->base64_accu = (six & 0xF); 3558d522f475Smrg screen->base64_count = 4; 355920d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3560d522f475Smrg break; 3561d522f475Smrg } 3562d522f475Smrg} 3563d522f475Smrg 3564d522f475Smrgvoid 356520d2c4d2SmrgCompleteSelection(XtermWidget xw, String * args, Cardinal len) 3566d522f475Smrg{ 3567956cc18dSsnj TScreen *screen = TScreenOf(xw); 3568956cc18dSsnj 3569956cc18dSsnj screen->base64_count = 0; 3570956cc18dSsnj screen->base64_accu = 0; 3571d522f475Smrg _OwnSelection(xw, args, len); 3572d522f475Smrg} 3573d522f475Smrg#endif /* OPT_PASTE64 */ 3574d522f475Smrg 3575d522f475Smrgstatic Bool 3576d522f475Smrg_ConvertSelectionHelper(Widget w, 3577d522f475Smrg Atom * type, 3578d522f475Smrg XtPointer *value, 3579d522f475Smrg unsigned long *length, 3580d522f475Smrg int *format, 3581d522f475Smrg int (*conversion_function) (Display *, 3582d522f475Smrg char **, int, 3583d522f475Smrg XICCEncodingStyle, 3584d522f475Smrg XTextProperty *), 3585d522f475Smrg XICCEncodingStyle conversion_style) 3586d522f475Smrg{ 3587956cc18dSsnj XtermWidget xw; 3588956cc18dSsnj 3589956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3590956cc18dSsnj TScreen *screen = TScreenOf(xw); 3591d522f475Smrg Display *dpy = XtDisplay(w); 3592d522f475Smrg XTextProperty textprop; 3593d522f475Smrg char *the_data = (char *) screen->selection_data; 3594d522f475Smrg 3595d522f475Smrg if (conversion_function(dpy, &the_data, 1, 3596d522f475Smrg conversion_style, 3597d522f475Smrg &textprop) >= Success) { 3598d522f475Smrg *value = (XtPointer) textprop.value; 3599d522f475Smrg *length = textprop.nitems; 3600d522f475Smrg *type = textprop.encoding; 3601d522f475Smrg *format = textprop.format; 3602d522f475Smrg return True; 3603d522f475Smrg } 3604d522f475Smrg } 3605d522f475Smrg return False; 3606d522f475Smrg} 3607d522f475Smrg 36082eaa94a1Schristosstatic Boolean 36092eaa94a1SchristosSaveConvertedLength(XtPointer *target, unsigned long source) 36102eaa94a1Schristos{ 36112eaa94a1Schristos Boolean result = False; 36122eaa94a1Schristos 36132eaa94a1Schristos *target = XtMalloc(4); 36142eaa94a1Schristos if (*target != 0) { 36152eaa94a1Schristos result = True; 36162eaa94a1Schristos if (sizeof(unsigned long) == 4) { 36172eaa94a1Schristos *(unsigned long *) *target = source; 36182eaa94a1Schristos } else if (sizeof(unsigned) == 4) { 361920d2c4d2Smrg *(unsigned *) *target = (unsigned) source; 36202eaa94a1Schristos } else if (sizeof(unsigned short) == 4) { 36212eaa94a1Schristos *(unsigned short *) *target = (unsigned short) source; 36222eaa94a1Schristos } else { 36232eaa94a1Schristos /* FIXME - does this depend on byte-order? */ 36242eaa94a1Schristos unsigned long temp = source; 362520d2c4d2Smrg memcpy((char *) *target, 362620d2c4d2Smrg ((char *) &temp) + sizeof(temp) - 4, 362720d2c4d2Smrg (size_t) 4); 36282eaa94a1Schristos } 36292eaa94a1Schristos } 36302eaa94a1Schristos return result; 36312eaa94a1Schristos} 36322eaa94a1Schristos 3633d522f475Smrgstatic Boolean 3634d522f475SmrgConvertSelection(Widget w, 3635d522f475Smrg Atom * selection, 3636d522f475Smrg Atom * target, 3637d522f475Smrg Atom * type, 3638d522f475Smrg XtPointer *value, 3639d522f475Smrg unsigned long *length, 3640d522f475Smrg int *format) 3641d522f475Smrg{ 3642d522f475Smrg Display *dpy = XtDisplay(w); 3643d522f475Smrg TScreen *screen; 3644d522f475Smrg Bool result = False; 3645d522f475Smrg 3646956cc18dSsnj XtermWidget xw; 3647956cc18dSsnj 3648956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 3649d522f475Smrg return False; 3650d522f475Smrg 3651956cc18dSsnj screen = TScreenOf(xw); 3652d522f475Smrg 3653d522f475Smrg if (screen->selection_data == NULL) 3654d522f475Smrg return False; /* can this happen? */ 3655d522f475Smrg 3656956cc18dSsnj TRACE(("ConvertSelection %s\n", 3657956cc18dSsnj visibleSelectionTarget(dpy, *target))); 3658956cc18dSsnj 3659d522f475Smrg if (*target == XA_TARGETS(dpy)) { 3660d522f475Smrg Atom *allocP; 3661d522f475Smrg Atom *targetP; 3662d522f475Smrg Atom *std_targets; 3663d522f475Smrg XPointer std_return = 0; 3664d522f475Smrg unsigned long std_length; 3665d522f475Smrg 3666d522f475Smrg if (XmuConvertStandardSelection(w, screen->selection_time, selection, 3667d522f475Smrg target, type, &std_return, 3668d522f475Smrg &std_length, format)) { 3669956cc18dSsnj Atom *my_targets = _SelectionTargets(w); 3670956cc18dSsnj 3671956cc18dSsnj TRACE(("XmuConvertStandardSelection - success\n")); 3672d522f475Smrg std_targets = (Atom *) (std_return); 3673d522f475Smrg *length = std_length + 6; 3674d522f475Smrg 3675956cc18dSsnj targetP = (Atom *) XtMalloc((Cardinal) (sizeof(Atom) * (*length))); 3676d522f475Smrg allocP = targetP; 3677d522f475Smrg 3678d522f475Smrg *value = (XtPointer) targetP; 3679d522f475Smrg 3680956cc18dSsnj while (*my_targets != None) { 3681956cc18dSsnj *targetP++ = *my_targets++; 3682956cc18dSsnj } 3683d522f475Smrg *targetP++ = XA_LENGTH(dpy); 3684d522f475Smrg *targetP++ = XA_LIST_LENGTH(dpy); 3685d522f475Smrg 36862eaa94a1Schristos *length = std_length + (unsigned long) (targetP - allocP); 3687d522f475Smrg 3688d522f475Smrg memcpy(targetP, std_targets, sizeof(Atom) * std_length); 3689d522f475Smrg XtFree((char *) std_targets); 3690d522f475Smrg *type = XA_ATOM; 3691d522f475Smrg *format = 32; 3692d522f475Smrg result = True; 3693956cc18dSsnj } else { 3694956cc18dSsnj TRACE(("XmuConvertStandardSelection - failed\n")); 3695d522f475Smrg } 3696d522f475Smrg } 3697d522f475Smrg#if OPT_WIDE_CHARS 3698d522f475Smrg else if (screen->wide_chars && *target == XA_STRING) { 3699d522f475Smrg result = 3700d522f475Smrg _ConvertSelectionHelper(w, 3701d522f475Smrg type, value, length, format, 3702d522f475Smrg Xutf8TextListToTextProperty, 3703d522f475Smrg XStringStyle); 3704956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3705d522f475Smrg } else if (screen->wide_chars && *target == XA_UTF8_STRING(dpy)) { 3706d522f475Smrg result = 3707d522f475Smrg _ConvertSelectionHelper(w, 3708d522f475Smrg type, value, length, format, 3709d522f475Smrg Xutf8TextListToTextProperty, 3710d522f475Smrg XUTF8StringStyle); 3711956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3712d522f475Smrg } else if (screen->wide_chars && *target == XA_TEXT(dpy)) { 3713d522f475Smrg result = 3714d522f475Smrg _ConvertSelectionHelper(w, 3715d522f475Smrg type, value, length, format, 3716d522f475Smrg Xutf8TextListToTextProperty, 3717d522f475Smrg XStdICCTextStyle); 3718956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3719d522f475Smrg } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(dpy)) { 3720d522f475Smrg result = 3721d522f475Smrg _ConvertSelectionHelper(w, 3722d522f475Smrg type, value, length, format, 3723d522f475Smrg Xutf8TextListToTextProperty, 3724d522f475Smrg XCompoundTextStyle); 3725956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3726d522f475Smrg } 3727d522f475Smrg#endif 3728d522f475Smrg 3729d522f475Smrg else if (*target == XA_STRING) { /* not wide_chars */ 3730d522f475Smrg /* We can only reach this point if the selection requestor 3731d522f475Smrg requested STRING before any of TEXT, COMPOUND_TEXT or 3732d522f475Smrg UTF8_STRING. We therefore assume that the requestor is not 3733d522f475Smrg properly internationalised, and dump raw eight-bit data 3734d522f475Smrg with no conversion into the selection. Yes, this breaks 3735d522f475Smrg the ICCCM in non-Latin-1 locales. */ 3736d522f475Smrg *type = XA_STRING; 3737d522f475Smrg *value = (XtPointer) screen->selection_data; 3738d522f475Smrg *length = screen->selection_length; 3739d522f475Smrg *format = 8; 3740d522f475Smrg result = True; 3741956cc18dSsnj TRACE(("...raw 8-bit data:%d\n", result)); 3742d522f475Smrg } else if (*target == XA_TEXT(dpy)) { /* not wide_chars */ 3743d522f475Smrg result = 3744d522f475Smrg _ConvertSelectionHelper(w, 3745d522f475Smrg type, value, length, format, 3746d522f475Smrg XmbTextListToTextProperty, 3747d522f475Smrg XStdICCTextStyle); 3748956cc18dSsnj TRACE(("...XmbTextListToTextProperty(StdICC):%d\n", result)); 3749d522f475Smrg } else if (*target == XA_COMPOUND_TEXT(dpy)) { /* not wide_chars */ 3750d522f475Smrg result = 3751d522f475Smrg _ConvertSelectionHelper(w, 3752d522f475Smrg type, value, length, format, 3753d522f475Smrg XmbTextListToTextProperty, 3754d522f475Smrg XCompoundTextStyle); 3755956cc18dSsnj TRACE(("...XmbTextListToTextProperty(Compound):%d\n", result)); 3756d522f475Smrg } 3757d522f475Smrg#ifdef X_HAVE_UTF8_STRING 3758d522f475Smrg else if (*target == XA_UTF8_STRING(dpy)) { /* not wide_chars */ 3759d522f475Smrg result = 3760d522f475Smrg _ConvertSelectionHelper(w, 3761d522f475Smrg type, value, length, format, 3762d522f475Smrg XmbTextListToTextProperty, 3763d522f475Smrg XUTF8StringStyle); 3764956cc18dSsnj TRACE(("...XmbTextListToTextProperty(UTF8):%d\n", result)); 3765d522f475Smrg } 3766d522f475Smrg#endif 3767d522f475Smrg else if (*target == XA_LIST_LENGTH(dpy)) { 376820d2c4d2Smrg result = SaveConvertedLength(value, (unsigned long) 1); 3769d522f475Smrg *type = XA_INTEGER; 3770d522f475Smrg *length = 1; 3771d522f475Smrg *format = 32; 3772956cc18dSsnj TRACE(("...list of values:%d\n", result)); 3773d522f475Smrg } else if (*target == XA_LENGTH(dpy)) { 3774d522f475Smrg /* This value is wrong if we have UTF-8 text */ 37752eaa94a1Schristos result = SaveConvertedLength(value, screen->selection_length); 3776d522f475Smrg *type = XA_INTEGER; 3777d522f475Smrg *length = 1; 3778d522f475Smrg *format = 32; 3779956cc18dSsnj TRACE(("...list of values:%d\n", result)); 3780d522f475Smrg } else if (XmuConvertStandardSelection(w, 3781d522f475Smrg screen->selection_time, selection, 3782d522f475Smrg target, type, (XPointer *) value, 3783d522f475Smrg length, format)) { 3784d522f475Smrg result = True; 3785956cc18dSsnj TRACE(("...XmuConvertStandardSelection:%d\n", result)); 3786d522f475Smrg } 3787d522f475Smrg 3788d522f475Smrg /* else */ 37892eaa94a1Schristos return (Boolean) result; 3790d522f475Smrg} 3791d522f475Smrg 3792d522f475Smrgstatic void 3793d522f475SmrgLoseSelection(Widget w, Atom * selection) 3794d522f475Smrg{ 3795d522f475Smrg TScreen *screen; 3796d522f475Smrg Atom *atomP; 3797d522f475Smrg Cardinal i; 3798d522f475Smrg 3799956cc18dSsnj XtermWidget xw; 3800956cc18dSsnj 3801956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 3802d522f475Smrg return; 3803d522f475Smrg 3804956cc18dSsnj screen = TScreenOf(xw); 3805d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 3806d522f475Smrg i < screen->selection_count; i++, atomP++) { 3807d522f475Smrg if (*selection == *atomP) 3808d522f475Smrg *atomP = (Atom) 0; 3809d522f475Smrg if (CutBuffer(*atomP) >= 0) { 3810d522f475Smrg *atomP = (Atom) 0; 3811d522f475Smrg } 3812d522f475Smrg } 3813d522f475Smrg 3814d522f475Smrg for (i = screen->selection_count; i; i--) { 3815d522f475Smrg if (screen->selection_atoms[i - 1] != 0) 3816d522f475Smrg break; 3817d522f475Smrg } 3818d522f475Smrg screen->selection_count = i; 3819d522f475Smrg 3820d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 3821d522f475Smrg i < screen->selection_count; i++, atomP++) { 3822d522f475Smrg if (*atomP == (Atom) 0) { 3823d522f475Smrg *atomP = screen->selection_atoms[--screen->selection_count]; 3824d522f475Smrg } 3825d522f475Smrg } 3826d522f475Smrg 3827d522f475Smrg if (screen->selection_count == 0) 3828956cc18dSsnj TrackText(xw, &zeroCELL, &zeroCELL); 3829d522f475Smrg} 3830d522f475Smrg 3831d522f475Smrg/* ARGSUSED */ 3832d522f475Smrgstatic void 3833d522f475SmrgSelectionDone(Widget w GCC_UNUSED, 3834d522f475Smrg Atom * selection GCC_UNUSED, 3835d522f475Smrg Atom * target GCC_UNUSED) 3836d522f475Smrg{ 3837d522f475Smrg /* empty proc so Intrinsics know we want to keep storage */ 3838d522f475Smrg} 3839d522f475Smrg 3840d522f475Smrgstatic void 3841d522f475Smrg_OwnSelection(XtermWidget xw, 3842d522f475Smrg String * selections, 3843d522f475Smrg Cardinal count) 3844d522f475Smrg{ 3845956cc18dSsnj TScreen *screen = TScreenOf(xw); 3846d522f475Smrg Atom *atoms = screen->selection_atoms; 3847d522f475Smrg Cardinal i; 3848d522f475Smrg Bool have_selection = False; 3849d522f475Smrg 385020d2c4d2Smrg if (count == 0) 385120d2c4d2Smrg return; 38522eaa94a1Schristos if (screen->selection_length == 0) 3853d522f475Smrg return; 3854d522f475Smrg 3855956cc18dSsnj TRACE(("_OwnSelection count %d\n", count)); 3856d522f475Smrg selections = MapSelections(xw, selections, count); 3857d522f475Smrg 3858d522f475Smrg if (count > screen->sel_atoms_size) { 3859d522f475Smrg XtFree((char *) atoms); 3860956cc18dSsnj atoms = (Atom *) XtMalloc((Cardinal) (count * sizeof(Atom))); 3861d522f475Smrg screen->selection_atoms = atoms; 3862d522f475Smrg screen->sel_atoms_size = count; 3863d522f475Smrg } 3864d522f475Smrg XmuInternStrings(XtDisplay((Widget) xw), selections, count, atoms); 3865d522f475Smrg for (i = 0; i < count; i++) { 3866d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 3867d522f475Smrg if (cutbuffer >= 0) { 38682eaa94a1Schristos unsigned long limit = 38692eaa94a1Schristos (unsigned long) (4 * XMaxRequestSize(XtDisplay((Widget) xw)) - 32); 38702eaa94a1Schristos if (screen->selection_length > limit) { 387120d2c4d2Smrg TRACE(("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 387220d2c4d2Smrg screen->selection_length, cutbuffer)); 3873d522f475Smrg fprintf(stderr, 3874956cc18dSsnj "%s: selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 3875d522f475Smrg xterm_name, screen->selection_length, cutbuffer); 3876d522f475Smrg } else { 3877d522f475Smrg /* This used to just use the UTF-8 data, which was totally 3878d522f475Smrg * broken as not even the corresponding paste code in Xterm 3879d522f475Smrg * understood this! So now it converts to Latin1 first. 3880d522f475Smrg * Robert Brady, 2000-09-05 3881d522f475Smrg */ 3882d522f475Smrg unsigned long length = screen->selection_length; 3883d522f475Smrg Char *data = screen->selection_data; 3884d522f475Smrg if_OPT_WIDE_CHARS((screen), { 3885956cc18dSsnj data = UTF8toLatin1(screen, data, length, &length); 3886d522f475Smrg }); 3887d522f475Smrg TRACE(("XStoreBuffer(%d)\n", cutbuffer)); 3888d522f475Smrg XStoreBuffer(XtDisplay((Widget) xw), 3889d522f475Smrg (char *) data, 3890d522f475Smrg (int) length, 3891d522f475Smrg cutbuffer); 3892d522f475Smrg } 3893d522f475Smrg } else if (!screen->replyToEmacs) { 3894d522f475Smrg have_selection |= 3895d522f475Smrg XtOwnSelection((Widget) xw, atoms[i], 3896d522f475Smrg screen->selection_time, 3897d522f475Smrg ConvertSelection, LoseSelection, SelectionDone); 3898d522f475Smrg } 3899d522f475Smrg } 3900d522f475Smrg if (!screen->replyToEmacs) 3901d522f475Smrg screen->selection_count = count; 3902d522f475Smrg if (!have_selection) 3903d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 3904d522f475Smrg} 3905d522f475Smrg 3906d522f475Smrgstatic void 3907d522f475SmrgResetSelectionState(TScreen * screen) 3908d522f475Smrg{ 3909d522f475Smrg screen->selection_count = 0; 3910d522f475Smrg screen->startH = zeroCELL; 3911d522f475Smrg screen->endH = zeroCELL; 3912d522f475Smrg} 3913d522f475Smrg 3914d522f475Smrgvoid 3915d522f475SmrgDisownSelection(XtermWidget xw) 3916d522f475Smrg{ 3917956cc18dSsnj TScreen *screen = TScreenOf(xw); 3918d522f475Smrg Atom *atoms = screen->selection_atoms; 3919d522f475Smrg Cardinal count = screen->selection_count; 3920d522f475Smrg Cardinal i; 3921d522f475Smrg 3922d522f475Smrg TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n", 3923d522f475Smrg count, 3924d522f475Smrg screen->startH.row, 3925d522f475Smrg screen->startH.col, 3926d522f475Smrg screen->endH.row, 3927d522f475Smrg screen->endH.col)); 3928d522f475Smrg 3929d522f475Smrg for (i = 0; i < count; i++) { 3930d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 3931d522f475Smrg if (cutbuffer < 0) { 3932d522f475Smrg XtDisownSelection((Widget) xw, atoms[i], 3933d522f475Smrg screen->selection_time); 3934d522f475Smrg } 3935d522f475Smrg } 3936d522f475Smrg /* 3937d522f475Smrg * If none of the callbacks via XtDisownSelection() reset highlighting 3938d522f475Smrg * do it now. 3939d522f475Smrg */ 3940d522f475Smrg if (ScrnHaveSelection(screen)) { 3941d522f475Smrg /* save data which will be reset */ 3942d522f475Smrg CELL first = screen->startH; 3943d522f475Smrg CELL last = screen->endH; 3944d522f475Smrg 3945d522f475Smrg ResetSelectionState(screen); 3946d522f475Smrg ReHiliteText(xw, &first, &last); 3947d522f475Smrg } else { 3948d522f475Smrg ResetSelectionState(screen); 3949d522f475Smrg } 3950d522f475Smrg} 3951d522f475Smrg 3952d522f475Smrgvoid 3953d522f475SmrgUnhiliteSelection(XtermWidget xw) 3954d522f475Smrg{ 3955956cc18dSsnj TScreen *screen = TScreenOf(xw); 3956d522f475Smrg 3957d522f475Smrg if (ScrnHaveSelection(screen)) { 3958d522f475Smrg CELL first = screen->startH; 3959d522f475Smrg CELL last = screen->endH; 3960d522f475Smrg 3961d522f475Smrg screen->startH = zeroCELL; 3962d522f475Smrg screen->endH = zeroCELL; 3963d522f475Smrg ReHiliteText(xw, &first, &last); 3964d522f475Smrg } 3965d522f475Smrg} 3966d522f475Smrg 3967d522f475Smrg/* returns number of chars in line from scol to ecol out */ 3968d522f475Smrg/* ARGSUSED */ 3969d522f475Smrgstatic int 3970956cc18dSsnjLength(TScreen * screen, 3971d522f475Smrg int row, 3972d522f475Smrg int scol, 3973d522f475Smrg int ecol) 3974d522f475Smrg{ 3975956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 3976956cc18dSsnj int lastcol = LastTextCol(screen, ld, row); 3977d522f475Smrg 3978d522f475Smrg if (ecol > lastcol) 3979d522f475Smrg ecol = lastcol; 3980d522f475Smrg return (ecol - scol + 1); 3981d522f475Smrg} 3982d522f475Smrg 3983d522f475Smrg/* copies text into line, preallocated */ 3984d522f475Smrgstatic Char * 3985d522f475SmrgSaveText(TScreen * screen, 3986d522f475Smrg int row, 3987d522f475Smrg int scol, 3988d522f475Smrg int ecol, 3989d522f475Smrg Char * lp, /* pointer to where to put the text */ 3990d522f475Smrg int *eol) 3991d522f475Smrg{ 3992956cc18dSsnj LineData *ld; 3993d522f475Smrg int i = 0; 3994d522f475Smrg unsigned c; 3995d522f475Smrg Char *result = lp; 3996d522f475Smrg#if OPT_WIDE_CHARS 39972eaa94a1Schristos unsigned previous = 0; 3998d522f475Smrg#endif 3999d522f475Smrg 4000956cc18dSsnj ld = GET_LINEDATA(screen, row); 4001d522f475Smrg i = Length(screen, row, scol, ecol); 4002d522f475Smrg ecol = scol + i; 4003d522f475Smrg#if OPT_DEC_CHRSET 4004956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 4005d522f475Smrg scol = (scol + 0) / 2; 4006d522f475Smrg ecol = (ecol + 1) / 2; 4007d522f475Smrg } 4008d522f475Smrg#endif 4009956cc18dSsnj *eol = !LineTstWrapped(ld); 4010d522f475Smrg for (i = scol; i < ecol; i++) { 401120d2c4d2Smrg assert(i < ld->lineSize); 4012956cc18dSsnj c = E2A(ld->charData[i]); 4013d522f475Smrg#if OPT_WIDE_CHARS 4014d522f475Smrg /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a 4015d522f475Smrg * wide character. 4016d522f475Smrg */ 4017956cc18dSsnj if (c == HIDDEN_CHAR && isWide((int) previous)) { 4018d522f475Smrg previous = c; 4019d522f475Smrg /* Combining characters attached to double-width characters 4020d522f475Smrg are in memory attached to the HIDDEN_CHAR */ 4021d522f475Smrg if_OPT_WIDE_CHARS(screen, { 4022d522f475Smrg if (screen->utf8_mode != uFalse) { 4023d522f475Smrg unsigned ch; 4024956cc18dSsnj size_t off; 4025956cc18dSsnj for_each_combData(off, ld) { 4026956cc18dSsnj ch = ld->combData[off][i]; 4027956cc18dSsnj if (ch == 0) 4028d522f475Smrg break; 4029d522f475Smrg lp = convertToUTF8(lp, ch); 4030d522f475Smrg } 4031d522f475Smrg } 4032d522f475Smrg }); 4033d522f475Smrg continue; 4034d522f475Smrg } 4035d522f475Smrg previous = c; 4036d522f475Smrg if (screen->utf8_mode != uFalse) { 4037d522f475Smrg lp = convertToUTF8(lp, (c != 0) ? c : ' '); 4038d522f475Smrg if_OPT_WIDE_CHARS(screen, { 4039d522f475Smrg unsigned ch; 4040956cc18dSsnj size_t off; 4041956cc18dSsnj for_each_combData(off, ld) { 4042956cc18dSsnj ch = ld->combData[off][i]; 4043956cc18dSsnj if (ch == 0) 4044d522f475Smrg break; 4045d522f475Smrg lp = convertToUTF8(lp, ch); 4046d522f475Smrg } 4047d522f475Smrg }); 4048d522f475Smrg } else 4049d522f475Smrg#endif 4050d522f475Smrg { 4051d522f475Smrg if (c == 0) { 4052d522f475Smrg c = E2A(' '); 4053d522f475Smrg } else if (c < E2A(' ')) { 4054d522f475Smrg c = DECtoASCII(c); 4055d522f475Smrg } else if (c == 0x7f) { 4056d522f475Smrg c = 0x5f; 4057d522f475Smrg } 40582eaa94a1Schristos *lp++ = CharOf(A2E(c)); 4059d522f475Smrg } 4060d522f475Smrg if (c != E2A(' ')) 4061d522f475Smrg result = lp; 4062d522f475Smrg } 4063d522f475Smrg 4064d522f475Smrg /* 4065d522f475Smrg * If requested, trim trailing blanks from selected lines. Do not do this 4066d522f475Smrg * if the line is wrapped. 4067d522f475Smrg */ 4068d522f475Smrg if (!*eol || !screen->trim_selection) 4069d522f475Smrg result = lp; 4070d522f475Smrg 4071d522f475Smrg return (result); 4072d522f475Smrg} 4073d522f475Smrg 4074d522f475Smrg/* 32 + following 7-bit word: 4075d522f475Smrg 4076d522f475Smrg 1:0 Button no: 0, 1, 2. 3=release. 4077d522f475Smrg 2 shift 4078d522f475Smrg 3 meta 4079d522f475Smrg 4 ctrl 4080d522f475Smrg 5 set for motion notify 4081d522f475Smrg 6 set for wheel 4082d522f475Smrg*/ 4083d522f475Smrg 4084d522f475Smrg/* Position: 32 - 255. */ 4085d522f475Smrg 40862eaa94a1Schristosstatic Char 4087d522f475SmrgBtnCode(XButtonEvent * event, int button) 4088d522f475Smrg{ 40892eaa94a1Schristos int result = (int) (32 + (KeyState(event->state) << 2)); 4090d522f475Smrg 4091d522f475Smrg if (button < 0 || button > 5) { 4092d522f475Smrg result += 3; 4093d522f475Smrg } else { 4094d522f475Smrg if (button > 3) 4095d522f475Smrg result += (64 - 4); 4096d522f475Smrg if (event->type == MotionNotify) 4097d522f475Smrg result += 32; 4098d522f475Smrg result += button; 4099d522f475Smrg } 41002eaa94a1Schristos return CharOf(result); 4101d522f475Smrg} 4102d522f475Smrg 4103d522f475Smrgstatic void 4104d522f475SmrgEditorButton(XtermWidget xw, XButtonEvent * event) 4105d522f475Smrg{ 4106956cc18dSsnj TScreen *screen = TScreenOf(xw); 4107d522f475Smrg int pty = screen->respond; 4108492d43a5Smrg int mouse_limit = screen->ext_mode_mouse ? EXT_MOUSE_LIMIT : MOUSE_LIMIT; 4109492d43a5Smrg Char line[10]; 4110d522f475Smrg int row, col; 4111d522f475Smrg int button; 4112d522f475Smrg unsigned count = 0; 4113d522f475Smrg Boolean changed = True; 4114d522f475Smrg 4115d522f475Smrg /* If button event, get button # adjusted for DEC compatibility */ 41162eaa94a1Schristos button = (int) (event->button - 1); 4117d522f475Smrg if (button >= 3) 4118d522f475Smrg button++; 4119d522f475Smrg 4120d522f475Smrg /* Compute character position of mouse pointer */ 4121d522f475Smrg row = (event->y - screen->border) / FontHeight(screen); 4122d522f475Smrg col = (event->x - OriginX(screen)) / FontWidth(screen); 4123d522f475Smrg 4124d522f475Smrg /* Limit to screen dimensions */ 4125d522f475Smrg if (row < 0) 4126d522f475Smrg row = 0; 4127d522f475Smrg else if (row > screen->max_row) 4128d522f475Smrg row = screen->max_row; 4129d522f475Smrg 4130d522f475Smrg if (col < 0) 4131d522f475Smrg col = 0; 4132d522f475Smrg else if (col > screen->max_col) 4133d522f475Smrg col = screen->max_col; 4134492d43a5Smrg 4135492d43a5Smrg /* Limit to representable mouse dimensions */ 4136492d43a5Smrg if (row > mouse_limit) 4137492d43a5Smrg row = mouse_limit; 4138492d43a5Smrg if (col > mouse_limit) 4139492d43a5Smrg col = mouse_limit; 4140d522f475Smrg 4141d522f475Smrg /* Build key sequence starting with \E[M */ 4142d522f475Smrg if (screen->control_eight_bits) { 4143d522f475Smrg line[count++] = ANSI_CSI; 4144d522f475Smrg } else { 4145d522f475Smrg line[count++] = ANSI_ESC; 4146d522f475Smrg line[count++] = '['; 4147d522f475Smrg } 4148d522f475Smrg#if OPT_SCO_FUNC_KEYS 4149d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 4150d522f475Smrg /* 4151d522f475Smrg * SCO function key F1 is \E[M, which would conflict with xterm's 4152d522f475Smrg * normal kmous. 4153d522f475Smrg */ 4154d522f475Smrg line[count++] = '>'; 4155d522f475Smrg } 4156d522f475Smrg#endif 4157d522f475Smrg line[count++] = 'M'; 4158d522f475Smrg 4159d522f475Smrg /* Add event code to key sequence */ 4160d522f475Smrg if (screen->send_mouse_pos == X10_MOUSE) { 41612eaa94a1Schristos line[count++] = CharOf(' ' + button); 4162d522f475Smrg } else { 4163d522f475Smrg /* Button-Motion events */ 4164d522f475Smrg switch (event->type) { 4165d522f475Smrg case ButtonPress: 4166d522f475Smrg line[count++] = BtnCode(event, screen->mouse_button = button); 4167d522f475Smrg break; 4168d522f475Smrg case ButtonRelease: 4169d522f475Smrg /* 4170d522f475Smrg * Wheel mouse interface generates release-events for buttons 4171d522f475Smrg * 4 and 5, coded here as 3 and 4 respectively. We change the 4172d522f475Smrg * release for buttons 1..3 to a -1. 4173d522f475Smrg */ 4174d522f475Smrg if (button < 3) 4175d522f475Smrg button = -1; 4176d522f475Smrg line[count++] = BtnCode(event, screen->mouse_button = button); 4177d522f475Smrg break; 4178d522f475Smrg case MotionNotify: 4179d522f475Smrg /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion 4180d522f475Smrg * events only if character cell has changed. 4181d522f475Smrg */ 4182d522f475Smrg if ((row == screen->mouse_row) 4183d522f475Smrg && (col == screen->mouse_col)) { 4184d522f475Smrg changed = False; 4185d522f475Smrg } else { 4186d522f475Smrg line[count++] = BtnCode(event, screen->mouse_button); 4187d522f475Smrg } 4188d522f475Smrg break; 4189d522f475Smrg default: 4190d522f475Smrg changed = False; 4191d522f475Smrg break; 4192d522f475Smrg } 4193d522f475Smrg } 4194d522f475Smrg 4195d522f475Smrg if (changed) { 4196d522f475Smrg screen->mouse_row = row; 4197d522f475Smrg screen->mouse_col = col; 4198d522f475Smrg 4199492d43a5Smrg TRACE(("mouse at %d,%d button+mask = %#x\n", row, col, line[count - 1])); 4200d522f475Smrg 4201492d43a5Smrg /* Add pointer position to key sequence */ 4202492d43a5Smrg count = EmitMousePosition(screen, line, count, col); 4203492d43a5Smrg count = EmitMousePosition(screen, line, count, row); 4204d522f475Smrg 4205d522f475Smrg /* Transmit key sequence to process running under xterm */ 4206d522f475Smrg v_write(pty, line, count); 4207d522f475Smrg } 4208d522f475Smrg return; 4209d522f475Smrg} 4210d522f475Smrg 4211d522f475Smrg#if OPT_FOCUS_EVENT 4212d522f475Smrgvoid 4213d522f475SmrgSendFocusButton(XtermWidget xw, XFocusChangeEvent * event) 4214d522f475Smrg{ 4215956cc18dSsnj TScreen *screen = TScreenOf(xw); 4216d522f475Smrg 4217d522f475Smrg if (screen->send_focus_pos) { 4218d522f475Smrg ANSI reply; 4219d522f475Smrg 4220d522f475Smrg memset(&reply, 0, sizeof(reply)); 4221d522f475Smrg reply.a_type = ANSI_CSI; 4222d522f475Smrg 4223d522f475Smrg#if OPT_SCO_FUNC_KEYS 4224d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 4225d522f475Smrg reply.a_pintro = '>'; 4226d522f475Smrg } 4227d522f475Smrg#endif 42282eaa94a1Schristos reply.a_final = CharOf((event->type == FocusIn) ? 'I' : 'O'); 4229d522f475Smrg unparseseq(xw, &reply); 4230d522f475Smrg } 4231d522f475Smrg return; 4232d522f475Smrg} 4233d522f475Smrg#endif /* OPT_FOCUS_EVENT */ 4234