button.c revision 20d2c4d2
120d2c4d2Smrg/* $XTermId: button.c,v 1.377 2010/06/04 09:27:07 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 118d522f475Smrg#define KeyModifiers (event->xbutton.state & OurModifiers) 119d522f475Smrg 1202eaa94a1Schristos#define KeyState(x) (((int) ((x) & (ShiftMask|ControlMask))) \ 1212eaa94a1Schristos + (((x) & Mod1Mask) ? 2 : 0)) 122d522f475Smrg /* adds together the bits: 123d522f475Smrg shift key -> 1 124d522f475Smrg meta key -> 2 125d522f475Smrg control key -> 4 */ 126d522f475Smrg 127d522f475Smrg#define Coordinate(s,c) ((c)->row * MaxCols(s) + (c)->col) 128d522f475Smrg 129d522f475Smrgstatic const CELL zeroCELL = 130d522f475Smrg{0, 0}; 131d522f475Smrg 132d522f475Smrg#if OPT_DEC_LOCATOR 133d522f475Smrgstatic Bool SendLocatorPosition(XtermWidget xw, XEvent * event); 134d522f475Smrgstatic void CheckLocatorPosition(XtermWidget xw, XEvent * event); 135d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 136d522f475Smrg 137d522f475Smrg/* Multi-click handling */ 138d522f475Smrg#if OPT_READLINE 139d522f475Smrgstatic Time lastButtonDownTime = 0; 140d522f475Smrgstatic int ExtendingSelection = 0; 141d522f475Smrgstatic Time lastButton3UpTime = 0; 142d522f475Smrgstatic Time lastButton3DoubleDownTime = 0; 143d522f475Smrgstatic CELL lastButton3; /* At the release time */ 144d522f475Smrg#endif /* OPT_READLINE */ 145d522f475Smrg 146d522f475Smrgstatic Char *SaveText(TScreen * screen, int row, int scol, int ecol, 147d522f475Smrg Char * lp, int *eol); 148d522f475Smrgstatic int Length(TScreen * screen, int row, int scol, int ecol); 149d522f475Smrgstatic void ComputeSelect(XtermWidget xw, CELL * startc, CELL * endc, Bool extend); 150d522f475Smrgstatic void EditorButton(XtermWidget xw, XButtonEvent * event); 151d522f475Smrgstatic void EndExtend(XtermWidget w, XEvent * event, String * params, Cardinal 152d522f475Smrg num_params, Bool use_cursor_loc); 153d522f475Smrgstatic void ExtendExtend(XtermWidget xw, const CELL * cell); 154d522f475Smrgstatic void PointToCELL(TScreen * screen, int y, int x, CELL * cell); 155d522f475Smrgstatic void ReHiliteText(XtermWidget xw, CELL * first, CELL * last); 156d522f475Smrgstatic void SaltTextAway(XtermWidget xw, CELL * cellc, CELL * cell, 157d522f475Smrg String * params, Cardinal num_params); 158d522f475Smrgstatic void SelectSet(XtermWidget xw, XEvent * event, String * params, Cardinal num_params); 159d522f475Smrgstatic void SelectionReceived PROTO_XT_SEL_CB_ARGS; 160d522f475Smrgstatic void StartSelect(XtermWidget xw, const CELL * cell); 161d522f475Smrgstatic void TrackDown(XtermWidget xw, XButtonEvent * event); 162d522f475Smrgstatic void TrackText(XtermWidget xw, const CELL * first, const CELL * last); 163d522f475Smrgstatic void _OwnSelection(XtermWidget xw, String * selections, Cardinal count); 164d522f475Smrgstatic void do_select_end(XtermWidget xw, XEvent * event, String * params, 165d522f475Smrg Cardinal *num_params, Bool use_cursor_loc); 166d522f475Smrg 167d522f475SmrgBool 168d522f475SmrgSendMousePosition(XtermWidget xw, XEvent * event) 169d522f475Smrg{ 170956cc18dSsnj TScreen *screen = TScreenOf(xw); 171d522f475Smrg 172d522f475Smrg /* If send_mouse_pos mode isn't on, we shouldn't be here */ 173d522f475Smrg if (screen->send_mouse_pos == MOUSE_OFF) 174d522f475Smrg return False; 175d522f475Smrg 176d522f475Smrg#if OPT_DEC_LOCATOR 177d522f475Smrg if (screen->send_mouse_pos == DEC_LOCATOR) { 178d522f475Smrg return (SendLocatorPosition(xw, event)); 179d522f475Smrg } 180d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 181d522f475Smrg 182d522f475Smrg /* Make sure the event is an appropriate type */ 183d522f475Smrg if ((screen->send_mouse_pos != BTN_EVENT_MOUSE) 184d522f475Smrg && (screen->send_mouse_pos != ANY_EVENT_MOUSE) 185d522f475Smrg && event->type != ButtonPress 186d522f475Smrg && event->type != ButtonRelease) 187d522f475Smrg return False; 188d522f475Smrg 189d522f475Smrg switch (screen->send_mouse_pos) { 190d522f475Smrg case X10_MOUSE: /* X10 compatibility sequences */ 191d522f475Smrg 192d522f475Smrg if (KeyModifiers == 0) { 193d522f475Smrg if (event->type == ButtonPress) 194d522f475Smrg EditorButton(xw, (XButtonEvent *) event); 195d522f475Smrg return True; 196d522f475Smrg } 197d522f475Smrg return False; 198d522f475Smrg 199d522f475Smrg case VT200_HIGHLIGHT_MOUSE: /* DEC vt200 hilite tracking */ 200d522f475Smrg if (event->type == ButtonPress && 201d522f475Smrg KeyModifiers == 0 && 202d522f475Smrg event->xbutton.button == Button1) { 203d522f475Smrg TrackDown(xw, (XButtonEvent *) event); 204d522f475Smrg return True; 205d522f475Smrg } 206d522f475Smrg if (KeyModifiers == 0 || KeyModifiers == ControlMask) { 207d522f475Smrg EditorButton(xw, (XButtonEvent *) event); 208d522f475Smrg return True; 209d522f475Smrg } 210d522f475Smrg return False; 211d522f475Smrg 212d522f475Smrg case VT200_MOUSE: /* DEC vt200 compatible */ 213d522f475Smrg 214d522f475Smrg /* xterm extension for motion reporting. June 1998 */ 215d522f475Smrg /* EditorButton() will distinguish between the modes */ 216d522f475Smrg case BTN_EVENT_MOUSE: 217d522f475Smrg case ANY_EVENT_MOUSE: 218d522f475Smrg if (KeyModifiers == 0 || KeyModifiers == ControlMask) { 2192eaa94a1Schristos if (event->type == MotionNotify) { 2202eaa94a1Schristos ((XButtonEvent *) event)->button = 0; 2212eaa94a1Schristos } 222d522f475Smrg EditorButton(xw, (XButtonEvent *) event); 223d522f475Smrg return True; 224d522f475Smrg } 225d522f475Smrg return False; 226d522f475Smrg 227d522f475Smrg default: 228d522f475Smrg return False; 229d522f475Smrg } 230d522f475Smrg} 231d522f475Smrg 232d522f475Smrg#if OPT_DEC_LOCATOR 233d522f475Smrg 234d522f475Smrg#define LocatorCoords( row, col, x, y, oor ) \ 235d522f475Smrg if( screen->locator_pixels ) { \ 236d522f475Smrg (oor)=False; (row) = (y)+1; (col) = (x)+1; \ 237d522f475Smrg /* Limit to screen dimensions */ \ 238d522f475Smrg if ((row) < 1) (row) = 1,(oor)=True; \ 239d522f475Smrg else if ((row) > screen->border*2+Height(screen)) \ 240d522f475Smrg (row) = screen->border*2+Height(screen),(oor)=True; \ 241d522f475Smrg if ((col) < 1) (col) = 1,(oor)=True; \ 242d522f475Smrg else if ((col) > OriginX(screen)*2+Width(screen)) \ 243d522f475Smrg (col) = OriginX(screen)*2+Width(screen),(oor)=True; \ 244d522f475Smrg } else { \ 245d522f475Smrg (oor)=False; \ 246d522f475Smrg /* Compute character position of mouse pointer */ \ 247d522f475Smrg (row) = ((y) - screen->border) / FontHeight(screen); \ 248d522f475Smrg (col) = ((x) - OriginX(screen)) / FontWidth(screen); \ 249d522f475Smrg /* Limit to screen dimensions */ \ 250d522f475Smrg if ((row) < 0) (row) = 0,(oor)=True; \ 251d522f475Smrg else if ((row) > screen->max_row) \ 252d522f475Smrg (row) = screen->max_row,(oor)=True; \ 253d522f475Smrg if ((col) < 0) (col) = 0,(oor)=True; \ 254d522f475Smrg else if ((col) > screen->max_col) \ 255d522f475Smrg (col) = screen->max_col,(oor)=True; \ 256d522f475Smrg (row)++; (col)++; \ 257d522f475Smrg } 258d522f475Smrg 259d522f475Smrgstatic Bool 260d522f475SmrgSendLocatorPosition(XtermWidget xw, XEvent * event) 261d522f475Smrg{ 262d522f475Smrg ANSI reply; 263956cc18dSsnj TScreen *screen = TScreenOf(xw); 264d522f475Smrg int row, col; 265d522f475Smrg Bool oor; 266d522f475Smrg int button; 2672eaa94a1Schristos unsigned state; 268d522f475Smrg 269d522f475Smrg /* Make sure the event is an appropriate type */ 270d522f475Smrg if ((event->type != ButtonPress && 271d522f475Smrg event->type != ButtonRelease && 272d522f475Smrg !screen->loc_filter) || 273d522f475Smrg (KeyModifiers != 0 && KeyModifiers != ControlMask)) 274d522f475Smrg return (False); 275d522f475Smrg 276d522f475Smrg if ((event->type == ButtonPress && 277d522f475Smrg !(screen->locator_events & LOC_BTNS_DN)) || 278d522f475Smrg (event->type == ButtonRelease && 279d522f475Smrg !(screen->locator_events & LOC_BTNS_UP))) 280d522f475Smrg return (True); 281d522f475Smrg 282d522f475Smrg if (event->type == MotionNotify) { 283d522f475Smrg CheckLocatorPosition(xw, event); 284d522f475Smrg return (True); 285d522f475Smrg } 286d522f475Smrg 287d522f475Smrg /* get button # */ 2882eaa94a1Schristos button = (int) event->xbutton.button - 1; 289d522f475Smrg 290d522f475Smrg LocatorCoords(row, col, event->xbutton.x, event->xbutton.y, oor); 291d522f475Smrg 292d522f475Smrg /* 293d522f475Smrg * DECterm mouse: 294d522f475Smrg * 295d522f475Smrg * ESCAPE '[' event ; mask ; row ; column '&' 'w' 296d522f475Smrg */ 297d522f475Smrg memset(&reply, 0, sizeof(reply)); 298d522f475Smrg reply.a_type = ANSI_CSI; 299d522f475Smrg 300d522f475Smrg if (oor) { 301d522f475Smrg reply.a_nparam = 1; 302d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 303d522f475Smrg reply.a_inters = '&'; 304d522f475Smrg reply.a_final = 'w'; 305d522f475Smrg unparseseq(xw, &reply); 306d522f475Smrg 307d522f475Smrg if (screen->locator_reset) { 308d522f475Smrg MotionOff(screen, xw); 309d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 310d522f475Smrg } 311d522f475Smrg return (True); 312d522f475Smrg } 313d522f475Smrg 314d522f475Smrg /* 315d522f475Smrg * event: 316d522f475Smrg * 1 no buttons 317d522f475Smrg * 2 left button down 318d522f475Smrg * 3 left button up 319d522f475Smrg * 4 middle button down 320d522f475Smrg * 5 middle button up 321d522f475Smrg * 6 right button down 322d522f475Smrg * 7 right button up 323d522f475Smrg * 8 M4 down 324d522f475Smrg * 9 M4 up 325d522f475Smrg */ 326d522f475Smrg reply.a_nparam = 4; 327d522f475Smrg switch (event->type) { 328d522f475Smrg case ButtonPress: 3292eaa94a1Schristos reply.a_param[0] = (ParmType) (2 + (button << 1)); 330d522f475Smrg break; 331d522f475Smrg case ButtonRelease: 3322eaa94a1Schristos reply.a_param[0] = (ParmType) (3 + (button << 1)); 333d522f475Smrg break; 334d522f475Smrg default: 335d522f475Smrg return (True); 336d522f475Smrg } 337d522f475Smrg /* 338d522f475Smrg * mask: 339d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 340d522f475Smrg * M4 down left down middle down right down 341d522f475Smrg * 342d522f475Smrg * Notice that Button1 (left) and Button3 (right) are swapped in the mask. 343d522f475Smrg * Also, mask should be the state after the button press/release, 344d522f475Smrg * X provides the state not including the button press/release. 345d522f475Smrg */ 346d522f475Smrg state = (event->xbutton.state 347d522f475Smrg & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8; 3484e40088cSchristos /* update mask to "after" state */ 34920d2c4d2Smrg state ^= ((unsigned) (1 << button)); 3504e40088cSchristos /* swap Button1 & Button3 */ 351956cc18dSsnj state = ((state & (unsigned) ~(4 | 1)) 352956cc18dSsnj | ((state & 1) ? 4 : 0) 353956cc18dSsnj | ((state & 4) ? 1 : 0)); 354d522f475Smrg 3552eaa94a1Schristos reply.a_param[1] = (ParmType) state; 3562eaa94a1Schristos reply.a_param[2] = (ParmType) row; 3572eaa94a1Schristos reply.a_param[3] = (ParmType) col; 358d522f475Smrg reply.a_inters = '&'; 359d522f475Smrg reply.a_final = 'w'; 360d522f475Smrg 361d522f475Smrg unparseseq(xw, &reply); 362d522f475Smrg 363d522f475Smrg if (screen->locator_reset) { 364d522f475Smrg MotionOff(screen, xw); 365d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 366d522f475Smrg } 367d522f475Smrg 368d522f475Smrg /* 369d522f475Smrg * DECterm turns the Locator off if a button is pressed while a filter rectangle 370d522f475Smrg * is active. This might be a bug, but I don't know, so I'll emulate it anyways. 371d522f475Smrg */ 372d522f475Smrg if (screen->loc_filter) { 373d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 374d522f475Smrg screen->loc_filter = False; 375d522f475Smrg screen->locator_events = 0; 376d522f475Smrg MotionOff(screen, xw); 377d522f475Smrg } 378d522f475Smrg 379d522f475Smrg return (True); 380d522f475Smrg} 381d522f475Smrg 382d522f475Smrg/* 383d522f475Smrg * mask: 384d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 385d522f475Smrg * M4 down left down middle down right down 386d522f475Smrg * 387d522f475Smrg * Button1 (left) and Button3 (right) are swapped in the mask relative to X. 388d522f475Smrg */ 389d522f475Smrg#define ButtonState(state, mask) \ 3902eaa94a1Schristos{ (state) = (int) (((mask) & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8); \ 391d522f475Smrg /* swap Button1 & Button3 */ \ 392d522f475Smrg (state) = ((state) & ~(4|1)) | (((state)&1)?4:0) | (((state)&4)?1:0); \ 393d522f475Smrg} 394d522f475Smrg 395d522f475Smrgvoid 396d522f475SmrgGetLocatorPosition(XtermWidget xw) 397d522f475Smrg{ 398d522f475Smrg ANSI reply; 399956cc18dSsnj TScreen *screen = TScreenOf(xw); 400d522f475Smrg Window root, child; 401d522f475Smrg int rx, ry, x, y; 402d522f475Smrg unsigned int mask; 403d522f475Smrg int row = 0, col = 0; 404d522f475Smrg Bool oor = False; 405d522f475Smrg Bool ret = False; 406d522f475Smrg int state; 407d522f475Smrg 408d522f475Smrg /* 409d522f475Smrg * DECterm turns the Locator off if the position is requested while a filter rectangle 410d522f475Smrg * is active. This might be a bug, but I don't know, so I'll emulate it anyways. 411d522f475Smrg */ 412d522f475Smrg if (screen->loc_filter) { 413d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 414d522f475Smrg screen->loc_filter = False; 415d522f475Smrg screen->locator_events = 0; 416d522f475Smrg MotionOff(screen, xw); 417d522f475Smrg } 418d522f475Smrg 419d522f475Smrg memset(&reply, 0, sizeof(reply)); 420d522f475Smrg reply.a_type = ANSI_CSI; 421d522f475Smrg 422d522f475Smrg if (screen->send_mouse_pos == DEC_LOCATOR) { 423d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), &root, 424d522f475Smrg &child, &rx, &ry, &x, &y, &mask); 425d522f475Smrg if (ret) { 426d522f475Smrg LocatorCoords(row, col, x, y, oor); 427d522f475Smrg } 428d522f475Smrg } 429d522f475Smrg if (ret == False || oor) { 430d522f475Smrg reply.a_nparam = 1; 431d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 432d522f475Smrg reply.a_inters = '&'; 433d522f475Smrg reply.a_final = 'w'; 434d522f475Smrg unparseseq(xw, &reply); 435d522f475Smrg 436d522f475Smrg if (screen->locator_reset) { 437d522f475Smrg MotionOff(screen, xw); 438d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 439d522f475Smrg } 440d522f475Smrg return; 441d522f475Smrg } 442d522f475Smrg 443d522f475Smrg ButtonState(state, mask); 444d522f475Smrg 445d522f475Smrg reply.a_nparam = 4; 446d522f475Smrg reply.a_param[0] = 1; /* Event - 1 = response to locator request */ 4472eaa94a1Schristos reply.a_param[1] = (ParmType) state; 4482eaa94a1Schristos reply.a_param[2] = (ParmType) row; 4492eaa94a1Schristos reply.a_param[3] = (ParmType) col; 450d522f475Smrg reply.a_inters = '&'; 451d522f475Smrg reply.a_final = 'w'; 452d522f475Smrg unparseseq(xw, &reply); 453d522f475Smrg 454d522f475Smrg if (screen->locator_reset) { 455d522f475Smrg MotionOff(screen, xw); 456d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 457d522f475Smrg } 458d522f475Smrg} 459d522f475Smrg 460d522f475Smrgvoid 461d522f475SmrgInitLocatorFilter(XtermWidget xw) 462d522f475Smrg{ 463d522f475Smrg ANSI reply; 464956cc18dSsnj TScreen *screen = TScreenOf(xw); 465d522f475Smrg Window root, child; 466d522f475Smrg int rx, ry, x, y; 467d522f475Smrg unsigned int mask; 468d522f475Smrg int row = 0, col = 0; 469d522f475Smrg Bool oor = 0; 470d522f475Smrg Bool ret; 471d522f475Smrg int state; 472d522f475Smrg 473d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), 474d522f475Smrg &root, &child, &rx, &ry, &x, &y, &mask); 475d522f475Smrg if (ret) { 476d522f475Smrg LocatorCoords(row, col, x, y, oor); 477d522f475Smrg } 478d522f475Smrg if (ret == False || oor) { 479d522f475Smrg /* Locator is unavailable */ 480d522f475Smrg 481d522f475Smrg if (screen->loc_filter_top != LOC_FILTER_POS || 482d522f475Smrg screen->loc_filter_left != LOC_FILTER_POS || 483d522f475Smrg screen->loc_filter_bottom != LOC_FILTER_POS || 484d522f475Smrg screen->loc_filter_right != LOC_FILTER_POS) { 485d522f475Smrg /* 486d522f475Smrg * If any explicit coordinates were received, 487d522f475Smrg * report immediately with no coordinates. 488d522f475Smrg */ 489d522f475Smrg memset(&reply, 0, sizeof(reply)); 490d522f475Smrg reply.a_type = ANSI_CSI; 491d522f475Smrg reply.a_nparam = 1; 492d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 493d522f475Smrg reply.a_inters = '&'; 494d522f475Smrg reply.a_final = 'w'; 495d522f475Smrg unparseseq(xw, &reply); 496d522f475Smrg 497d522f475Smrg if (screen->locator_reset) { 498d522f475Smrg MotionOff(screen, xw); 499d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 500d522f475Smrg } 501d522f475Smrg } else { 502d522f475Smrg /* 503d522f475Smrg * No explicit coordinates were received, and the pointer is 504d522f475Smrg * unavailable. Report when the pointer re-enters the window. 505d522f475Smrg */ 506d522f475Smrg screen->loc_filter = True; 507d522f475Smrg MotionOn(screen, xw); 508d522f475Smrg } 509d522f475Smrg return; 510d522f475Smrg } 511d522f475Smrg 512d522f475Smrg /* 513d522f475Smrg * Adjust rectangle coordinates: 514d522f475Smrg * 1. Replace "LOC_FILTER_POS" with current coordinates 515d522f475Smrg * 2. Limit coordinates to screen size 516d522f475Smrg * 3. make sure top and left are less than bottom and right, resp. 517d522f475Smrg */ 518d522f475Smrg if (screen->locator_pixels) { 519d522f475Smrg rx = OriginX(screen) * 2 + Width(screen); 520d522f475Smrg ry = screen->border * 2 + Height(screen); 521d522f475Smrg } else { 522d522f475Smrg rx = screen->max_col; 523d522f475Smrg ry = screen->max_row; 524d522f475Smrg } 525d522f475Smrg 526d522f475Smrg#define Adjust( coord, def, max ) \ 527d522f475Smrg if( (coord) == LOC_FILTER_POS ) (coord) = (def); \ 528d522f475Smrg else if ((coord) < 1) (coord) = 1; \ 529d522f475Smrg else if ((coord) > (max)) (coord) = (max) 530d522f475Smrg 531d522f475Smrg Adjust(screen->loc_filter_top, row, ry); 532d522f475Smrg Adjust(screen->loc_filter_left, col, rx); 533d522f475Smrg Adjust(screen->loc_filter_bottom, row, ry); 534d522f475Smrg Adjust(screen->loc_filter_right, col, rx); 535d522f475Smrg 536d522f475Smrg if (screen->loc_filter_top > screen->loc_filter_bottom) { 537d522f475Smrg ry = screen->loc_filter_top; 538d522f475Smrg screen->loc_filter_top = screen->loc_filter_bottom; 539d522f475Smrg screen->loc_filter_bottom = ry; 540d522f475Smrg } 541d522f475Smrg 542d522f475Smrg if (screen->loc_filter_left > screen->loc_filter_right) { 543d522f475Smrg rx = screen->loc_filter_left; 544d522f475Smrg screen->loc_filter_left = screen->loc_filter_right; 545d522f475Smrg screen->loc_filter_right = rx; 546d522f475Smrg } 547d522f475Smrg 548d522f475Smrg if ((col < screen->loc_filter_left) || 549d522f475Smrg (col > screen->loc_filter_right) || 550d522f475Smrg (row < screen->loc_filter_top) || 551d522f475Smrg (row > screen->loc_filter_bottom)) { 552d522f475Smrg /* Pointer is already outside the rectangle - report immediately */ 553d522f475Smrg ButtonState(state, mask); 554d522f475Smrg 555d522f475Smrg memset(&reply, 0, sizeof(reply)); 556d522f475Smrg reply.a_type = ANSI_CSI; 557d522f475Smrg reply.a_nparam = 4; 558d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 5592eaa94a1Schristos reply.a_param[1] = (ParmType) state; 5602eaa94a1Schristos reply.a_param[2] = (ParmType) row; 5612eaa94a1Schristos reply.a_param[3] = (ParmType) col; 562d522f475Smrg reply.a_inters = '&'; 563d522f475Smrg reply.a_final = 'w'; 564d522f475Smrg unparseseq(xw, &reply); 565d522f475Smrg 566d522f475Smrg if (screen->locator_reset) { 567d522f475Smrg MotionOff(screen, xw); 568d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 569d522f475Smrg } 570d522f475Smrg return; 571d522f475Smrg } 572d522f475Smrg 573d522f475Smrg /* 574d522f475Smrg * Rectangle is set up. Allow pointer tracking 575d522f475Smrg * to detect if the mouse leaves the rectangle. 576d522f475Smrg */ 577d522f475Smrg screen->loc_filter = True; 578d522f475Smrg MotionOn(screen, xw); 579d522f475Smrg} 580d522f475Smrg 581d522f475Smrgstatic void 582d522f475SmrgCheckLocatorPosition(XtermWidget xw, XEvent * event) 583d522f475Smrg{ 584d522f475Smrg ANSI reply; 585956cc18dSsnj TScreen *screen = TScreenOf(xw); 586d522f475Smrg int row, col; 587d522f475Smrg Bool oor; 588d522f475Smrg int state; 589d522f475Smrg 590d522f475Smrg LocatorCoords(row, col, event->xbutton.x, event->xbutton.y, oor); 591d522f475Smrg 592d522f475Smrg /* 593d522f475Smrg * Send report if the pointer left the filter rectangle, if 594d522f475Smrg * the pointer left the window, or if the filter rectangle 595d522f475Smrg * had no coordinates and the pointer re-entered the window. 596d522f475Smrg */ 597d522f475Smrg if (oor || (screen->loc_filter_top == LOC_FILTER_POS) || 598d522f475Smrg (col < screen->loc_filter_left) || 599d522f475Smrg (col > screen->loc_filter_right) || 600d522f475Smrg (row < screen->loc_filter_top) || 601d522f475Smrg (row > screen->loc_filter_bottom)) { 602d522f475Smrg /* Filter triggered - disable it */ 603d522f475Smrg screen->loc_filter = False; 604d522f475Smrg MotionOff(screen, xw); 605d522f475Smrg 606d522f475Smrg memset(&reply, 0, sizeof(reply)); 607d522f475Smrg reply.a_type = ANSI_CSI; 608d522f475Smrg if (oor) { 609d522f475Smrg reply.a_nparam = 1; 610d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 611d522f475Smrg } else { 612d522f475Smrg ButtonState(state, event->xbutton.state); 613d522f475Smrg 614d522f475Smrg reply.a_nparam = 4; 615d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 6162eaa94a1Schristos reply.a_param[1] = (ParmType) state; 6172eaa94a1Schristos reply.a_param[2] = (ParmType) row; 6182eaa94a1Schristos reply.a_param[3] = (ParmType) col; 619d522f475Smrg } 620d522f475Smrg 621d522f475Smrg reply.a_inters = '&'; 622d522f475Smrg reply.a_final = 'w'; 623d522f475Smrg unparseseq(xw, &reply); 624d522f475Smrg 625d522f475Smrg if (screen->locator_reset) { 626d522f475Smrg MotionOff(screen, xw); 627d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 628d522f475Smrg } 629d522f475Smrg } 630d522f475Smrg} 631d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 632d522f475Smrg 633d522f475Smrg#if OPT_READLINE 634d522f475Smrgstatic int 635d522f475SmrgisClick1_clean(TScreen * screen, XEvent * event) 636d522f475Smrg{ 637d522f475Smrg int delta; 638d522f475Smrg 639d522f475Smrg if (!(event->type == ButtonPress || event->type == ButtonRelease) 640d522f475Smrg /* Disable on Shift-Click-1, including the application-mouse modes */ 641d522f475Smrg || (KeyModifiers & ShiftMask) 642d522f475Smrg || (screen->send_mouse_pos != MOUSE_OFF) /* Kinda duplicate... */ 643d522f475Smrg ||ExtendingSelection) /* Was moved */ 644d522f475Smrg return 0; 645d522f475Smrg 646d522f475Smrg if (event->type != ButtonRelease) 647d522f475Smrg return 0; 648d522f475Smrg 649d522f475Smrg if (lastButtonDownTime == (Time) 0) { 650d522f475Smrg /* first time or once in a blue moon */ 651d522f475Smrg delta = screen->multiClickTime + 1; 652d522f475Smrg } else if (event->xbutton.time > lastButtonDownTime) { 653d522f475Smrg /* most of the time */ 6542eaa94a1Schristos delta = (int) (event->xbutton.time - lastButtonDownTime); 655d522f475Smrg } else { 656d522f475Smrg /* time has rolled over since lastButtonUpTime */ 6572eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time); 658d522f475Smrg } 659d522f475Smrg 660d522f475Smrg return delta <= screen->multiClickTime; 661d522f475Smrg} 662d522f475Smrg 663d522f475Smrgstatic int 664d522f475SmrgisDoubleClick3(TScreen * screen, XEvent * event) 665d522f475Smrg{ 666d522f475Smrg int delta; 667d522f475Smrg 668d522f475Smrg if (event->type != ButtonRelease 669d522f475Smrg || (KeyModifiers & ShiftMask) 670d522f475Smrg || event->xbutton.button != Button3) { 671d522f475Smrg lastButton3UpTime = 0; /* Disable the cached info */ 672d522f475Smrg return 0; 673d522f475Smrg } 674d522f475Smrg /* Process Btn3Release. */ 675d522f475Smrg if (lastButton3DoubleDownTime == (Time) 0) { 676d522f475Smrg /* No previous click or once in a blue moon */ 677d522f475Smrg delta = screen->multiClickTime + 1; 678d522f475Smrg } else if (event->xbutton.time > lastButton3DoubleDownTime) { 679d522f475Smrg /* most of the time */ 6802eaa94a1Schristos delta = (int) (event->xbutton.time - lastButton3DoubleDownTime); 681d522f475Smrg } else { 682d522f475Smrg /* time has rolled over since lastButton3DoubleDownTime */ 6832eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButton3DoubleDownTime) + event->xbutton.time); 684d522f475Smrg } 685d522f475Smrg if (delta <= screen->multiClickTime) { 686d522f475Smrg /* Double click */ 687d522f475Smrg CELL cell; 688d522f475Smrg 689d522f475Smrg /* Cannot check ExtendingSelection, since mouse-3 always sets it */ 690d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 691d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 692d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the third click */ 693d522f475Smrg return 1; 694d522f475Smrg } 695d522f475Smrg } 696d522f475Smrg /* Not a double click, memorize for future check. */ 697d522f475Smrg lastButton3UpTime = event->xbutton.time; 698d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &lastButton3); 699d522f475Smrg return 0; 700d522f475Smrg} 701d522f475Smrg 702d522f475Smrgstatic int 703d522f475SmrgCheckSecondPress3(TScreen * screen, XEvent * event) 704d522f475Smrg{ 705d522f475Smrg int delta; 706d522f475Smrg 707d522f475Smrg if (event->type != ButtonPress 708d522f475Smrg || (KeyModifiers & ShiftMask) 709d522f475Smrg || event->xbutton.button != Button3) { 710d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the cached info */ 711d522f475Smrg return 0; 712d522f475Smrg } 713d522f475Smrg /* Process Btn3Press. */ 714d522f475Smrg if (lastButton3UpTime == (Time) 0) { 715d522f475Smrg /* No previous click or once in a blue moon */ 716d522f475Smrg delta = screen->multiClickTime + 1; 717d522f475Smrg } else if (event->xbutton.time > lastButton3UpTime) { 718d522f475Smrg /* most of the time */ 7192eaa94a1Schristos delta = (int) (event->xbutton.time - lastButton3UpTime); 720d522f475Smrg } else { 721d522f475Smrg /* time has rolled over since lastButton3UpTime */ 7222eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButton3UpTime) + event->xbutton.time); 723d522f475Smrg } 724d522f475Smrg if (delta <= screen->multiClickTime) { 725d522f475Smrg CELL cell; 726d522f475Smrg 727d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 728d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 729d522f475Smrg /* A candidate for a double-click */ 730d522f475Smrg lastButton3DoubleDownTime = event->xbutton.time; 731d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &lastButton3); 732d522f475Smrg return 1; 733d522f475Smrg } 734d522f475Smrg lastButton3UpTime = 0; /* Disable the info about the previous click */ 735d522f475Smrg } 736d522f475Smrg /* Either too long, or moved, disable. */ 737d522f475Smrg lastButton3DoubleDownTime = 0; 738d522f475Smrg return 0; 739d522f475Smrg} 740d522f475Smrg 741d522f475Smrgstatic int 742d522f475SmrgrowOnCurrentLine(TScreen * screen, 743d522f475Smrg int line, 744d522f475Smrg int *deltap) /* must be XButtonEvent */ 745d522f475Smrg{ 746956cc18dSsnj int result = 1; 747d522f475Smrg int l1, l2; 748d522f475Smrg 749d522f475Smrg *deltap = 0; 750956cc18dSsnj if (line != screen->cur_row) { 751956cc18dSsnj if (line < screen->cur_row) 752956cc18dSsnj l1 = line, l2 = screen->cur_row; 753956cc18dSsnj else 754956cc18dSsnj l2 = line, l1 = screen->cur_row; 755956cc18dSsnj l1--; 756956cc18dSsnj while (++l1 < l2) { 757956cc18dSsnj LineData *ld = GET_LINEDATA(screen, l1); 758956cc18dSsnj if (!LineTstWrapped(ld)) { 759956cc18dSsnj result = 0; 760956cc18dSsnj break; 761956cc18dSsnj } 762956cc18dSsnj } 763956cc18dSsnj if (result) { 764956cc18dSsnj /* Everything is on one "wrapped line" now */ 765956cc18dSsnj *deltap = line - screen->cur_row; 766956cc18dSsnj } 767956cc18dSsnj } 768956cc18dSsnj return result; 769d522f475Smrg} 770d522f475Smrg 771d522f475Smrgstatic int 772d522f475SmrgeventRow(TScreen * screen, XEvent * event) /* must be XButtonEvent */ 773d522f475Smrg{ 774d522f475Smrg return (event->xbutton.y - screen->border) / FontHeight(screen); 775d522f475Smrg} 776d522f475Smrg 777d522f475Smrgstatic int 778d522f475SmrgeventColBetween(TScreen * screen, XEvent * event) /* must be XButtonEvent */ 779d522f475Smrg{ 780d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 781d522f475Smrg return ((event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) / 2) 782d522f475Smrg / FontWidth(screen)); 783d522f475Smrg} 784d522f475Smrg 785d522f475Smrgstatic int 786d522f475SmrgReadLineMovePoint(TScreen * screen, int col, int ldelta) 787d522f475Smrg{ 788d522f475Smrg Char line[6]; 789d522f475Smrg unsigned count = 0; 790d522f475Smrg 791d522f475Smrg col += ldelta * MaxCols(screen) - screen->cur_col; 792d522f475Smrg if (col == 0) 793d522f475Smrg return 0; 794d522f475Smrg if (screen->control_eight_bits) { 795d522f475Smrg line[count++] = ANSI_CSI; 796d522f475Smrg } else { 797d522f475Smrg line[count++] = ANSI_ESC; 798d522f475Smrg line[count++] = '['; /* XXX maybe sometimes O is better? */ 799d522f475Smrg } 80020d2c4d2Smrg line[count] = CharOf(col > 0 ? 'C' : 'D'); 801d522f475Smrg if (col < 0) 802d522f475Smrg col = -col; 803d522f475Smrg while (col--) 804d522f475Smrg v_write(screen->respond, line, 3); 805d522f475Smrg return 1; 806d522f475Smrg} 807d522f475Smrg 808d522f475Smrgstatic int 809d522f475SmrgReadLineDelete(TScreen * screen, CELL * cell1, CELL * cell2) 810d522f475Smrg{ 811d522f475Smrg int del; 812d522f475Smrg 813d522f475Smrg del = (cell2->col - cell1->col) + ((cell2->row - cell1->row) * MaxCols(screen)); 814d522f475Smrg if (del <= 0) /* Just in case... */ 815d522f475Smrg return 0; 816d522f475Smrg while (del--) 817d522f475Smrg v_write(screen->respond, (Char *) "\177", 1); 818d522f475Smrg return 1; 819d522f475Smrg} 820d522f475Smrg#endif /* OPT_READLINE */ 821d522f475Smrg 822d522f475Smrg/* ^XM-G<line+' '><col+' '> */ 823d522f475Smrgvoid 824d522f475SmrgDiredButton(Widget w, 825d522f475Smrg XEvent * event, /* must be XButtonEvent */ 826d522f475Smrg String * params GCC_UNUSED, /* selections */ 827d522f475Smrg Cardinal *num_params GCC_UNUSED) 828d522f475Smrg{ 829956cc18dSsnj XtermWidget xw; 830956cc18dSsnj 831956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 832956cc18dSsnj TScreen *screen = TScreenOf(xw); 833d522f475Smrg Char Line[6]; 834d522f475Smrg unsigned line, col; 835d522f475Smrg 8362eaa94a1Schristos if ((event->type == ButtonPress || event->type == ButtonRelease) 8372eaa94a1Schristos && (event->xbutton.y >= screen->border) 8382eaa94a1Schristos && (event->xbutton.x >= OriginX(screen))) { 83920d2c4d2Smrg line = (unsigned) ((event->xbutton.y - screen->border) 84020d2c4d2Smrg / FontHeight(screen)); 84120d2c4d2Smrg col = (unsigned) ((event->xbutton.x - OriginX(screen)) 84220d2c4d2Smrg / FontWidth(screen)); 843d522f475Smrg Line[0] = CONTROL('X'); 844d522f475Smrg Line[1] = ANSI_ESC; 845d522f475Smrg Line[2] = 'G'; 8462eaa94a1Schristos Line[3] = CharOf(' ' + col); 8472eaa94a1Schristos Line[4] = CharOf(' ' + line); 848d522f475Smrg v_write(screen->respond, Line, 5); 849d522f475Smrg } 850d522f475Smrg } 851d522f475Smrg} 852d522f475Smrg 853d522f475Smrg#if OPT_READLINE 854d522f475Smrgvoid 855d522f475SmrgReadLineButton(Widget w, 856d522f475Smrg XEvent * event, /* must be XButtonEvent */ 857d522f475Smrg String * params GCC_UNUSED, /* selections */ 858d522f475Smrg Cardinal *num_params GCC_UNUSED) 859d522f475Smrg{ 860956cc18dSsnj XtermWidget xw; 861956cc18dSsnj 862956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 863956cc18dSsnj TScreen *screen = TScreenOf(xw); 864d522f475Smrg Char Line[6]; 865d522f475Smrg int line, col, ldelta = 0; 866d522f475Smrg 867d522f475Smrg if (!(event->type == ButtonPress || event->type == ButtonRelease) 868d522f475Smrg || (screen->send_mouse_pos != MOUSE_OFF) || ExtendingSelection) 869d522f475Smrg goto finish; 870d522f475Smrg if (event->type == ButtonRelease) { 871d522f475Smrg int delta; 872d522f475Smrg 873d522f475Smrg if (lastButtonDownTime == (Time) 0) { 874d522f475Smrg /* first time and once in a blue moon */ 875d522f475Smrg delta = screen->multiClickTime + 1; 876d522f475Smrg } else if (event->xbutton.time > lastButtonDownTime) { 877d522f475Smrg /* most of the time */ 8782eaa94a1Schristos delta = (int) (event->xbutton.time - lastButtonDownTime); 879d522f475Smrg } else { 880d522f475Smrg /* time has rolled over since lastButtonUpTime */ 8812eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time); 882d522f475Smrg } 883d522f475Smrg if (delta > screen->multiClickTime) 884d522f475Smrg goto finish; /* All this work for this... */ 885d522f475Smrg } 886d522f475Smrg line = (event->xbutton.y - screen->border) / FontHeight(screen); 887956cc18dSsnj if (!rowOnCurrentLine(screen, line, &ldelta)) 888956cc18dSsnj goto finish; 889d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 890d522f475Smrg col = (event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) 891d522f475Smrg / 2) 892d522f475Smrg / FontWidth(screen) - screen->cur_col + ldelta * MaxCols(screen); 893d522f475Smrg if (col == 0) 894d522f475Smrg goto finish; 895d522f475Smrg Line[0] = ANSI_ESC; 896d522f475Smrg /* XXX: sometimes it is better to send '['? */ 897d522f475Smrg Line[1] = 'O'; 8982eaa94a1Schristos Line[2] = CharOf(col > 0 ? 'C' : 'D'); 899d522f475Smrg if (col < 0) 900d522f475Smrg col = -col; 901d522f475Smrg while (col--) 902d522f475Smrg v_write(screen->respond, Line, 3); 903d522f475Smrg finish: 904d522f475Smrg if (event->type == ButtonRelease) 905d522f475Smrg do_select_end(xw, event, params, num_params, False); 906d522f475Smrg } 907d522f475Smrg} 908d522f475Smrg#endif /* OPT_READLINE */ 909d522f475Smrg 910d522f475Smrg/* repeats <ESC>n or <ESC>p */ 911d522f475Smrgvoid 912d522f475SmrgViButton(Widget w, 913d522f475Smrg XEvent * event, /* must be XButtonEvent */ 914d522f475Smrg String * params GCC_UNUSED, /* selections */ 915d522f475Smrg Cardinal *num_params GCC_UNUSED) 916d522f475Smrg{ 917956cc18dSsnj XtermWidget xw; 918956cc18dSsnj 919956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 920956cc18dSsnj TScreen *screen = TScreenOf(xw); 921d522f475Smrg int pty = screen->respond; 922d522f475Smrg Char Line[6]; 923d522f475Smrg int line; 924d522f475Smrg 925d522f475Smrg if (event->type == ButtonPress || event->type == ButtonRelease) { 926d522f475Smrg 927d522f475Smrg line = screen->cur_row - 928d522f475Smrg ((event->xbutton.y - screen->border) / FontHeight(screen)); 929d522f475Smrg if (line != 0) { 930d522f475Smrg Line[0] = ANSI_ESC; /* force an exit from insert-mode */ 931d522f475Smrg v_write(pty, Line, 1); 932d522f475Smrg 933d522f475Smrg if (line < 0) { 934d522f475Smrg line = -line; 935d522f475Smrg Line[0] = CONTROL('n'); 936d522f475Smrg } else { 937d522f475Smrg Line[0] = CONTROL('p'); 938d522f475Smrg } 939d522f475Smrg while (--line >= 0) 940d522f475Smrg v_write(pty, Line, 1); 941d522f475Smrg } 942d522f475Smrg } 943d522f475Smrg } 944d522f475Smrg} 945d522f475Smrg 946d522f475Smrg/* 947d522f475Smrg * This function handles button-motion events 948d522f475Smrg */ 949d522f475Smrg/*ARGSUSED*/ 950d522f475Smrgvoid 951d522f475SmrgHandleSelectExtend(Widget w, 952d522f475Smrg XEvent * event, /* must be XMotionEvent */ 953d522f475Smrg String * params GCC_UNUSED, 954d522f475Smrg Cardinal *num_params GCC_UNUSED) 955d522f475Smrg{ 956956cc18dSsnj XtermWidget xw; 957956cc18dSsnj 958956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 959956cc18dSsnj TScreen *screen = TScreenOf(xw); 960d522f475Smrg CELL cell; 961d522f475Smrg 962d522f475Smrg screen->selection_time = event->xmotion.time; 963d522f475Smrg switch (screen->eventMode) { 964d522f475Smrg /* If not in one of the DEC mouse-reporting modes */ 965d522f475Smrg case LEFTEXTENSION: 966d522f475Smrg case RIGHTEXTENSION: 967d522f475Smrg PointToCELL(screen, event->xmotion.y, event->xmotion.x, &cell); 968d522f475Smrg ExtendExtend(xw, &cell); 969d522f475Smrg break; 970d522f475Smrg 971d522f475Smrg /* If in motion reporting mode, send mouse position to 972d522f475Smrg character process as a key sequence \E[M... */ 973d522f475Smrg case NORMAL: 974d522f475Smrg /* will get here if send_mouse_pos != MOUSE_OFF */ 975d522f475Smrg if (screen->send_mouse_pos == BTN_EVENT_MOUSE 976d522f475Smrg || screen->send_mouse_pos == ANY_EVENT_MOUSE) { 977d522f475Smrg (void) SendMousePosition(xw, event); 978d522f475Smrg } 979d522f475Smrg break; 980d522f475Smrg } 981d522f475Smrg } 982d522f475Smrg} 983d522f475Smrg 984d522f475Smrgvoid 985d522f475SmrgHandleKeyboardSelectExtend(Widget w, 986d522f475Smrg XEvent * event GCC_UNUSED, /* must be XButtonEvent */ 987d522f475Smrg String * params GCC_UNUSED, 988d522f475Smrg Cardinal *num_params GCC_UNUSED) 989d522f475Smrg{ 990956cc18dSsnj XtermWidget xw; 991956cc18dSsnj 992956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 993956cc18dSsnj TScreen *screen = TScreenOf(xw); 994d522f475Smrg ExtendExtend(xw, &screen->cursorp); 995d522f475Smrg } 996d522f475Smrg} 997d522f475Smrg 998d522f475Smrgstatic void 999d522f475Smrgdo_select_end(XtermWidget xw, 1000d522f475Smrg XEvent * event, /* must be XButtonEvent */ 1001d522f475Smrg String * params, /* selections */ 1002d522f475Smrg Cardinal *num_params, 1003d522f475Smrg Bool use_cursor_loc) 1004d522f475Smrg{ 1005d522f475Smrg#if OPT_READLINE 1006d522f475Smrg int ldelta1, ldelta2; 1007d522f475Smrg#endif 1008956cc18dSsnj TScreen *screen = TScreenOf(xw); 1009d522f475Smrg 1010d522f475Smrg screen->selection_time = event->xbutton.time; 1011d522f475Smrg switch (screen->eventMode) { 1012d522f475Smrg case NORMAL: 1013d522f475Smrg (void) SendMousePosition(xw, event); 1014d522f475Smrg break; 1015d522f475Smrg case LEFTEXTENSION: 1016d522f475Smrg case RIGHTEXTENSION: 1017d522f475Smrg EndExtend(xw, event, params, *num_params, use_cursor_loc); 1018d522f475Smrg#if OPT_READLINE 1019d522f475Smrg if (isClick1_clean(screen, event) 1020d522f475Smrg && SCREEN_FLAG(screen, click1_moves) 1021d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta1)) { 1022d522f475Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta1); 1023d522f475Smrg } 1024d522f475Smrg if (isDoubleClick3(screen, event) 1025d522f475Smrg && SCREEN_FLAG(screen, dclick3_deletes) 1026d522f475Smrg && rowOnCurrentLine(screen, screen->startSel.row, &ldelta1) 1027d522f475Smrg && rowOnCurrentLine(screen, screen->endSel.row, &ldelta2)) { 1028d522f475Smrg ReadLineMovePoint(screen, screen->endSel.col, ldelta2); 1029d522f475Smrg ReadLineDelete(screen, &screen->startSel, &(screen->endSel)); 1030d522f475Smrg } 1031d522f475Smrg#endif /* OPT_READLINE */ 1032d522f475Smrg break; 1033d522f475Smrg } 1034d522f475Smrg} 1035d522f475Smrg 1036d522f475Smrgvoid 1037d522f475SmrgHandleSelectEnd(Widget w, 1038d522f475Smrg XEvent * event, /* must be XButtonEvent */ 1039d522f475Smrg String * params, /* selections */ 1040d522f475Smrg Cardinal *num_params) 1041d522f475Smrg{ 1042956cc18dSsnj XtermWidget xw; 1043956cc18dSsnj 1044956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1045956cc18dSsnj do_select_end(xw, event, params, num_params, False); 1046956cc18dSsnj } 1047d522f475Smrg} 1048d522f475Smrg 1049d522f475Smrgvoid 1050d522f475SmrgHandleKeyboardSelectEnd(Widget w, 1051d522f475Smrg XEvent * event, /* must be XButtonEvent */ 1052d522f475Smrg String * params, /* selections */ 1053d522f475Smrg Cardinal *num_params) 1054d522f475Smrg{ 1055956cc18dSsnj XtermWidget xw; 1056956cc18dSsnj 1057956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1058956cc18dSsnj do_select_end(xw, event, params, num_params, True); 1059956cc18dSsnj } 1060d522f475Smrg} 1061d522f475Smrg 1062d522f475Smrgstruct _SelectionList { 1063d522f475Smrg String *params; 1064d522f475Smrg Cardinal count; 1065d522f475Smrg Atom *targets; 1066d522f475Smrg Time time; 1067d522f475Smrg}; 1068d522f475Smrg 1069d522f475Smrgstatic unsigned 1070d522f475SmrgDECtoASCII(unsigned ch) 1071d522f475Smrg{ 1072d522f475Smrg if (xtermIsDecGraphic(ch)) { 10732eaa94a1Schristos ch = CharOf("###########+++++##-##++++|######"[ch]); 10742eaa94a1Schristos /* 01234567890123456789012345678901 */ 1075d522f475Smrg } 1076d522f475Smrg return ch; 1077d522f475Smrg} 107820d2c4d2Smrg 107920d2c4d2Smrg#if OPT_WIDE_CHARS 108020d2c4d2Smrgstatic Cardinal 108120d2c4d2SmrgaddXtermChar(Char ** buffer, Cardinal *used, Cardinal offset, unsigned value) 108220d2c4d2Smrg{ 108320d2c4d2Smrg if (offset + 1 >= *used) { 108420d2c4d2Smrg *used = 1 + (2 * (offset + 1)); 108520d2c4d2Smrg allocXtermChars(buffer, *used); 108620d2c4d2Smrg } 108720d2c4d2Smrg (*buffer)[offset++] = (Char) value; 108820d2c4d2Smrg return offset; 108920d2c4d2Smrg} 109020d2c4d2Smrg#define AddChar(buffer, used, offset, value) \ 109120d2c4d2Smrg offset = addXtermChar(buffer, used, offset, (unsigned) value) 109220d2c4d2Smrg 1093d522f475Smrg/* 1094d522f475Smrg * Convert a UTF-8 string to Latin-1, replacing non Latin-1 characters by `#', 1095d522f475Smrg * or ASCII/Latin-1 equivalents for special cases. 1096d522f475Smrg */ 1097d522f475Smrgstatic Char * 109820d2c4d2SmrgUTF8toLatin1(TScreen * screen, Char * s, unsigned long len, unsigned long *result) 1099d522f475Smrg{ 1100d522f475Smrg static Char *buffer; 1101956cc18dSsnj static Cardinal used; 1102d522f475Smrg 110320d2c4d2Smrg Cardinal offset = 0; 1104d522f475Smrg 110520d2c4d2Smrg Char *p; 1106d522f475Smrg 110720d2c4d2Smrg if (len != 0) { 1108d522f475Smrg PtyData data; 1109d522f475Smrg 1110d522f475Smrg fakePtyData(&data, s, s + len); 1111d522f475Smrg while (decodeUtf8(&data)) { 1112956cc18dSsnj Bool fails = False; 1113956cc18dSsnj Bool extra = False; 1114d522f475Smrg IChar value = skipPtyData(&data); 1115d522f475Smrg if (value == UCS_REPL) { 1116956cc18dSsnj fails = True; 1117d522f475Smrg } else if (value < 256) { 111820d2c4d2Smrg AddChar(&buffer, &used, offset, CharOf(value)); 1119d522f475Smrg } else { 1120d522f475Smrg unsigned eqv = ucs2dec(value); 1121d522f475Smrg if (xtermIsDecGraphic(eqv)) { 112220d2c4d2Smrg AddChar(&buffer, &used, offset, DECtoASCII(eqv)); 1123d522f475Smrg } else { 1124d522f475Smrg eqv = AsciiEquivs(value); 1125956cc18dSsnj if (eqv == value) { 1126956cc18dSsnj fails = True; 1127956cc18dSsnj } else { 112820d2c4d2Smrg AddChar(&buffer, &used, offset, eqv); 1129956cc18dSsnj } 1130956cc18dSsnj if (isWide((wchar_t) value)) 1131956cc18dSsnj extra = True; 1132956cc18dSsnj } 1133956cc18dSsnj } 1134956cc18dSsnj 1135956cc18dSsnj /* 1136956cc18dSsnj * If we're not able to plug in a single-byte result, insert the 1137956cc18dSsnj * defaultString (which normally is a single "#", but could be 1138956cc18dSsnj * whatever the user wants). 1139956cc18dSsnj */ 1140956cc18dSsnj if (fails) { 1141956cc18dSsnj for (p = (Char *) screen->default_string; *p != '\0'; ++p) { 114220d2c4d2Smrg AddChar(&buffer, &used, offset, *p); 1143d522f475Smrg } 1144d522f475Smrg } 1145956cc18dSsnj if (extra) 114620d2c4d2Smrg AddChar(&buffer, &used, offset, ' '); 1147d522f475Smrg } 114820d2c4d2Smrg AddChar(&buffer, &used, offset, '\0'); 114920d2c4d2Smrg *result = (unsigned long) (offset - 1); 1150d522f475Smrg } else { 1151d522f475Smrg *result = 0; 1152d522f475Smrg } 1153d522f475Smrg return buffer; 1154d522f475Smrg} 115520d2c4d2Smrg 115620d2c4d2Smrgint 115720d2c4d2SmrgxtermUtf8ToTextList(XtermWidget xw, 115820d2c4d2Smrg XTextProperty * text_prop, 115920d2c4d2Smrg char ***text_list, 116020d2c4d2Smrg int *text_list_count) 116120d2c4d2Smrg{ 116220d2c4d2Smrg TScreen *screen = TScreenOf(xw); 116320d2c4d2Smrg Display *dpy = screen->display; 116420d2c4d2Smrg int rc = -1; 116520d2c4d2Smrg 116620d2c4d2Smrg if (text_prop->format == 8 116720d2c4d2Smrg && (rc = Xutf8TextPropertyToTextList(dpy, text_prop, 116820d2c4d2Smrg text_list, 116920d2c4d2Smrg text_list_count)) >= 0) { 117020d2c4d2Smrg if (*text_list != NULL && *text_list_count != 0) { 117120d2c4d2Smrg int i; 117220d2c4d2Smrg Char *data; 117320d2c4d2Smrg char **new_text_list, *tmp; 117420d2c4d2Smrg unsigned long size, new_size; 117520d2c4d2Smrg 117620d2c4d2Smrg TRACE(("xtermUtf8ToTextList size %d\n", *text_list_count)); 117720d2c4d2Smrg 117820d2c4d2Smrg /* 117920d2c4d2Smrg * XLib StringList actually uses only two pointers, one for the 118020d2c4d2Smrg * list itself, and one for the data. Pointer to the data is the 118120d2c4d2Smrg * first element of the list, the rest (if any) list elements point 118220d2c4d2Smrg * to the same memory block as the first element 118320d2c4d2Smrg */ 118420d2c4d2Smrg new_size = 0; 118520d2c4d2Smrg for (i = 0; i < *text_list_count; ++i) { 118620d2c4d2Smrg data = (Char *) (*text_list)[i]; 118720d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 118820d2c4d2Smrg (void) UTF8toLatin1(screen, data, size, &size); 118920d2c4d2Smrg new_size += size + 1; 119020d2c4d2Smrg } 119120d2c4d2Smrg new_text_list = 119220d2c4d2Smrg (char **) XtMalloc((Cardinal) sizeof(char *) * (unsigned) *text_list_count); 119320d2c4d2Smrg new_text_list[0] = tmp = XtMalloc((Cardinal) new_size); 119420d2c4d2Smrg for (i = 0; i < (*text_list_count); ++i) { 119520d2c4d2Smrg data = (Char *) (*text_list)[i]; 119620d2c4d2Smrg size = strlen((*text_list)[i]) + 1; 119720d2c4d2Smrg data = UTF8toLatin1(screen, data, size, &size); 119820d2c4d2Smrg memcpy(tmp, data, size + 1); 119920d2c4d2Smrg new_text_list[i] = tmp; 120020d2c4d2Smrg tmp += size + 1; 120120d2c4d2Smrg } 120220d2c4d2Smrg XFreeStringList((*text_list)); 120320d2c4d2Smrg *text_list = new_text_list; 120420d2c4d2Smrg } else { 120520d2c4d2Smrg rc = -1; 120620d2c4d2Smrg } 120720d2c4d2Smrg } 120820d2c4d2Smrg return rc; 120920d2c4d2Smrg} 1210d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1211d522f475Smrg 1212956cc18dSsnjstatic char * 1213956cc18dSsnjparseItem(char *value, char *nextc) 1214d522f475Smrg{ 1215956cc18dSsnj char *nextp = value; 1216956cc18dSsnj while (*nextp != '\0' && *nextp != ',') { 1217956cc18dSsnj *nextp = x_toupper(*nextp); 1218956cc18dSsnj ++nextp; 1219956cc18dSsnj } 1220956cc18dSsnj *nextc = *nextp; 1221956cc18dSsnj *nextp = '\0'; 1222956cc18dSsnj x_strtrim(value); 1223d522f475Smrg 1224956cc18dSsnj return nextp; 1225956cc18dSsnj} 1226d522f475Smrg 1227956cc18dSsnj/* 1228956cc18dSsnj * All of the wanted strings are unique in the first character, so we can 1229956cc18dSsnj * use simple abbreviations. 1230956cc18dSsnj */ 1231956cc18dSsnjstatic Bool 1232956cc18dSsnjsameItem(const char *actual, const char *wanted) 1233956cc18dSsnj{ 1234956cc18dSsnj Bool result = False; 1235956cc18dSsnj size_t have = strlen(actual); 1236956cc18dSsnj size_t need = strlen(wanted); 1237d522f475Smrg 1238956cc18dSsnj if (have != 0 && have <= need) { 1239956cc18dSsnj if (!strncmp(actual, wanted, have)) { 1240956cc18dSsnj TRACE(("...matched \"%s\"\n", wanted)); 1241956cc18dSsnj result = True; 1242956cc18dSsnj } 1243956cc18dSsnj } 1244956cc18dSsnj 1245956cc18dSsnj return result; 1246956cc18dSsnj} 1247956cc18dSsnj 1248956cc18dSsnj/* 1249956cc18dSsnj * Handle the eightBitSelectTypes or utf8SelectTypes resource values. 1250956cc18dSsnj */ 1251956cc18dSsnjstatic Bool 1252956cc18dSsnjoverrideTargets(Widget w, String value, Atom ** resultp) 1253956cc18dSsnj{ 1254956cc18dSsnj Bool override = False; 1255956cc18dSsnj XtermWidget xw; 1256956cc18dSsnj 1257956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1258956cc18dSsnj TScreen *screen = TScreenOf(xw); 1259956cc18dSsnj 126020d2c4d2Smrg if (!IsEmpty(value)) { 1261956cc18dSsnj String copied = x_strdup(value); 1262956cc18dSsnj if (copied != 0) { 1263956cc18dSsnj Atom *result = 0; 1264956cc18dSsnj Cardinal count = 1; 1265956cc18dSsnj int n; 1266d522f475Smrg 1267956cc18dSsnj TRACE(("decoding SelectTypes \"%s\"\n", value)); 1268956cc18dSsnj for (n = 0; copied[n] != '\0'; ++n) { 1269956cc18dSsnj if (copied[n] == ',') 1270956cc18dSsnj ++count; 1271956cc18dSsnj } 127220d2c4d2Smrg result = (Atom *) XtMalloc(((2 * count) + 1) 127320d2c4d2Smrg * (Cardinal) sizeof(Atom)); 1274956cc18dSsnj if (result == NULL) { 1275956cc18dSsnj TRACE(("Couldn't allocate selection types\n")); 1276956cc18dSsnj } else { 1277956cc18dSsnj char nextc = '?'; 127820d2c4d2Smrg char *listp = (char *) copied; 1279956cc18dSsnj count = 0; 1280956cc18dSsnj do { 1281956cc18dSsnj char *nextp = parseItem(listp, &nextc); 1282956cc18dSsnj size_t len = strlen(listp); 1283956cc18dSsnj 1284956cc18dSsnj if (len == 0) { 1285956cc18dSsnj ; 1286956cc18dSsnj } 1287956cc18dSsnj#if OPT_WIDE_CHARS 1288956cc18dSsnj else if (sameItem(listp, "UTF8")) { 1289956cc18dSsnj result[count++] = XA_UTF8_STRING(XtDisplay(w)); 1290956cc18dSsnj } 1291956cc18dSsnj#endif 1292956cc18dSsnj else if (sameItem(listp, "I18N")) { 1293956cc18dSsnj if (screen->i18nSelections) { 1294956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 1295956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1296956cc18dSsnj } 1297956cc18dSsnj } else if (sameItem(listp, "TEXT")) { 1298956cc18dSsnj result[count++] = XA_TEXT(XtDisplay(w)); 1299956cc18dSsnj } else if (sameItem(listp, "COMPOUND_TEXT")) { 1300956cc18dSsnj result[count++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1301956cc18dSsnj } else if (sameItem(listp, "STRING")) { 1302956cc18dSsnj result[count++] = XA_STRING; 1303956cc18dSsnj } 1304956cc18dSsnj *nextp++ = nextc; 1305956cc18dSsnj listp = nextp; 1306956cc18dSsnj } while (nextc != '\0'); 1307956cc18dSsnj if (count) { 1308956cc18dSsnj result[count] = None; 1309956cc18dSsnj override = True; 1310956cc18dSsnj *resultp = result; 1311956cc18dSsnj } else { 1312956cc18dSsnj XtFree((char *) result); 1313956cc18dSsnj } 1314956cc18dSsnj } 1315956cc18dSsnj } else { 1316956cc18dSsnj TRACE(("Couldn't allocate copy of selection types\n")); 1317d522f475Smrg } 1318956cc18dSsnj } 1319956cc18dSsnj } 1320956cc18dSsnj return override; 1321956cc18dSsnj} 1322956cc18dSsnj 1323956cc18dSsnj#if OPT_WIDE_CHARS 1324956cc18dSsnjstatic Atom * 1325956cc18dSsnjallocUtf8Targets(Widget w, TScreen * screen) 1326956cc18dSsnj{ 1327956cc18dSsnj Atom **resultp = &(screen->selection_targets_utf8); 1328956cc18dSsnj 1329956cc18dSsnj if (*resultp == 0) { 1330956cc18dSsnj Atom *result; 1331956cc18dSsnj 1332956cc18dSsnj if (!overrideTargets(w, screen->utf8_select_types, &result)) { 1333956cc18dSsnj result = (Atom *) XtMalloc((Cardinal) (5 * sizeof(Atom))); 1334956cc18dSsnj if (result == NULL) { 1335956cc18dSsnj TRACE(("Couldn't allocate utf-8 selection targets\n")); 1336956cc18dSsnj } else { 1337956cc18dSsnj int n = 0; 1338956cc18dSsnj 1339956cc18dSsnj result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1340d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1341956cc18dSsnj if (screen->i18nSelections) { 1342956cc18dSsnj result[n++] = XA_TEXT(XtDisplay(w)); 1343956cc18dSsnj result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1344956cc18dSsnj } 1345d522f475Smrg#endif 1346956cc18dSsnj result[n++] = XA_STRING; 1347956cc18dSsnj result[n] = None; 1348956cc18dSsnj } 1349d522f475Smrg } 1350956cc18dSsnj 1351956cc18dSsnj *resultp = result; 1352d522f475Smrg } 1353956cc18dSsnj 1354956cc18dSsnj return *resultp; 1355956cc18dSsnj} 1356d522f475Smrg#endif 1357d522f475Smrg 1358956cc18dSsnjstatic Atom * 1359956cc18dSsnjalloc8bitTargets(Widget w, TScreen * screen) 1360956cc18dSsnj{ 1361956cc18dSsnj Atom **resultp = &(screen->selection_targets_8bit); 1362956cc18dSsnj 1363956cc18dSsnj if (*resultp == 0) { 1364956cc18dSsnj Atom *result = 0; 1365956cc18dSsnj 1366956cc18dSsnj if (!overrideTargets(w, screen->eightbit_select_types, &result)) { 1367956cc18dSsnj result = (Atom *) XtMalloc((Cardinal) (5 * sizeof(Atom))); 1368956cc18dSsnj if (result == NULL) { 1369956cc18dSsnj TRACE(("Couldn't allocate 8bit selection targets\n")); 1370956cc18dSsnj } else { 1371956cc18dSsnj int n = 0; 1372956cc18dSsnj 1373d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1374956cc18dSsnj result[n++] = XA_UTF8_STRING(XtDisplay(w)); 1375956cc18dSsnj#endif 1376956cc18dSsnj if (screen->i18nSelections) { 1377956cc18dSsnj result[n++] = XA_TEXT(XtDisplay(w)); 1378956cc18dSsnj result[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1379956cc18dSsnj } 1380956cc18dSsnj result[n++] = XA_STRING; 1381956cc18dSsnj result[n] = None; 1382956cc18dSsnj } 1383956cc18dSsnj } 1384956cc18dSsnj 1385956cc18dSsnj *resultp = result; 1386956cc18dSsnj } 1387956cc18dSsnj 1388956cc18dSsnj return *resultp; 1389956cc18dSsnj} 1390956cc18dSsnj 1391956cc18dSsnjstatic Atom * 1392956cc18dSsnj_SelectionTargets(Widget w) 1393956cc18dSsnj{ 1394956cc18dSsnj Atom *result; 1395956cc18dSsnj TScreen *screen; 1396956cc18dSsnj XtermWidget xw; 1397956cc18dSsnj 1398956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) { 1399956cc18dSsnj result = NULL; 1400956cc18dSsnj } else { 1401956cc18dSsnj screen = TScreenOf(xw); 1402956cc18dSsnj 1403956cc18dSsnj#if OPT_WIDE_CHARS 1404956cc18dSsnj if (screen->wide_chars) { 1405956cc18dSsnj result = allocUtf8Targets(w, screen); 1406956cc18dSsnj } else 1407d522f475Smrg#endif 1408956cc18dSsnj { 1409956cc18dSsnj /* not screen->wide_chars */ 1410956cc18dSsnj result = alloc8bitTargets(w, screen); 1411d522f475Smrg } 1412d522f475Smrg } 1413956cc18dSsnj 1414956cc18dSsnj return result; 1415d522f475Smrg} 1416d522f475Smrg 1417d522f475Smrg#define isSELECT(value) (!strcmp(value, "SELECT")) 1418d522f475Smrg 1419d522f475Smrgstatic void 1420d522f475SmrgUnmapSelections(XtermWidget xw) 1421d522f475Smrg{ 1422956cc18dSsnj TScreen *screen = TScreenOf(xw); 1423d522f475Smrg Cardinal n; 1424d522f475Smrg 1425d522f475Smrg if (screen->mappedSelect) { 1426d522f475Smrg for (n = 0; screen->mappedSelect[n] != 0; ++n) 142720d2c4d2Smrg free((void *) screen->mappedSelect[n]); 1428d522f475Smrg free(screen->mappedSelect); 1429d522f475Smrg screen->mappedSelect = 0; 1430d522f475Smrg } 1431d522f475Smrg} 1432d522f475Smrg 1433d522f475Smrg/* 1434d522f475Smrg * xterm generally uses the primary selection. Some applications prefer 1435d522f475Smrg * (or are limited to) the clipboard. Since the translations resource is 1436d522f475Smrg * complicated, users seldom change the way it affects selection. But it 1437d522f475Smrg * is simple to remap the choice between primary and clipboard before the 1438d522f475Smrg * call to XmuInternStrings(). 1439d522f475Smrg */ 1440d522f475Smrgstatic String * 1441d522f475SmrgMapSelections(XtermWidget xw, String * params, Cardinal num_params) 1442d522f475Smrg{ 1443d522f475Smrg String *result = params; 1444d522f475Smrg 1445d522f475Smrg if (num_params > 0) { 1446d522f475Smrg Cardinal j; 1447d522f475Smrg Boolean map = False; 1448d522f475Smrg 1449d522f475Smrg for (j = 0; j < num_params; ++j) { 1450d522f475Smrg TRACE(("param[%d]:%s\n", j, params[j])); 1451d522f475Smrg if (isSELECT(params[j])) { 1452d522f475Smrg map = True; 1453d522f475Smrg break; 1454d522f475Smrg } 1455d522f475Smrg } 1456d522f475Smrg if (map) { 1457956cc18dSsnj TScreen *screen = TScreenOf(xw); 1458956cc18dSsnj const char *mapTo = (screen->selectToClipboard 1459d522f475Smrg ? "CLIPBOARD" 1460d522f475Smrg : "PRIMARY"); 1461d522f475Smrg 1462d522f475Smrg UnmapSelections(xw); 1463d522f475Smrg if ((result = TypeMallocN(String, num_params + 1)) != 0) { 1464d522f475Smrg result[num_params] = 0; 1465d522f475Smrg for (j = 0; j < num_params; ++j) { 1466d522f475Smrg result[j] = x_strdup((isSELECT(params[j]) 1467d522f475Smrg ? mapTo 1468d522f475Smrg : params[j])); 1469d522f475Smrg if (result[j] == 0) { 1470d522f475Smrg UnmapSelections(xw); 1471d522f475Smrg result = 0; 1472d522f475Smrg break; 1473d522f475Smrg } 1474d522f475Smrg } 1475956cc18dSsnj screen->mappedSelect = result; 1476d522f475Smrg } 1477d522f475Smrg } 1478d522f475Smrg } 1479d522f475Smrg return result; 1480d522f475Smrg} 1481d522f475Smrg 1482d522f475Smrg/* 1483d522f475Smrg * Lookup the cut-buffer number, which will be in the range 0-7. 1484d522f475Smrg * If it is not a cut-buffer, it is the primary selection (-1). 1485d522f475Smrg */ 1486d522f475Smrgstatic int 148720d2c4d2SmrgCutBuffer(Atom code) 1488d522f475Smrg{ 1489d522f475Smrg int cutbuffer; 149020d2c4d2Smrg switch ((unsigned) code) { 1491d522f475Smrg case XA_CUT_BUFFER0: 1492d522f475Smrg cutbuffer = 0; 1493d522f475Smrg break; 1494d522f475Smrg case XA_CUT_BUFFER1: 1495d522f475Smrg cutbuffer = 1; 1496d522f475Smrg break; 1497d522f475Smrg case XA_CUT_BUFFER2: 1498d522f475Smrg cutbuffer = 2; 1499d522f475Smrg break; 1500d522f475Smrg case XA_CUT_BUFFER3: 1501d522f475Smrg cutbuffer = 3; 1502d522f475Smrg break; 1503d522f475Smrg case XA_CUT_BUFFER4: 1504d522f475Smrg cutbuffer = 4; 1505d522f475Smrg break; 1506d522f475Smrg case XA_CUT_BUFFER5: 1507d522f475Smrg cutbuffer = 5; 1508d522f475Smrg break; 1509d522f475Smrg case XA_CUT_BUFFER6: 1510d522f475Smrg cutbuffer = 6; 1511d522f475Smrg break; 1512d522f475Smrg case XA_CUT_BUFFER7: 1513d522f475Smrg cutbuffer = 7; 1514d522f475Smrg break; 1515d522f475Smrg default: 1516d522f475Smrg cutbuffer = -1; 1517d522f475Smrg break; 1518d522f475Smrg } 1519d522f475Smrg return cutbuffer; 1520d522f475Smrg} 1521d522f475Smrg 1522d522f475Smrg#if OPT_PASTE64 1523d522f475Smrgstatic void 1524d522f475SmrgFinishPaste64(XtermWidget xw) 1525d522f475Smrg{ 1526956cc18dSsnj TScreen *screen = TScreenOf(xw); 1527956cc18dSsnj 1528956cc18dSsnj TRACE(("FinishPaste64(%d)\n", screen->base64_paste)); 1529956cc18dSsnj if (screen->base64_paste) { 1530956cc18dSsnj screen->base64_paste = 0; 1531956cc18dSsnj unparseputc1(xw, screen->base64_final); 1532d522f475Smrg unparse_end(xw); 1533d522f475Smrg } 1534d522f475Smrg} 1535d522f475Smrg#endif 1536d522f475Smrg 1537d522f475Smrg#if !OPT_PASTE64 1538d522f475Smrgstatic 1539d522f475Smrg#endif 1540d522f475Smrgvoid 1541d522f475SmrgxtermGetSelection(Widget w, 1542d522f475Smrg Time ev_time, 1543d522f475Smrg String * params, /* selections in precedence order */ 1544d522f475Smrg Cardinal num_params, 1545d522f475Smrg Atom * targets) 1546d522f475Smrg{ 1547d522f475Smrg Atom selection; 1548d522f475Smrg int cutbuffer; 1549d522f475Smrg Atom target; 1550d522f475Smrg 1551956cc18dSsnj XtermWidget xw; 1552956cc18dSsnj 155320d2c4d2Smrg if (num_params == 0) 155420d2c4d2Smrg return; 1555956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 1556d522f475Smrg return; 1557d522f475Smrg 1558956cc18dSsnj TRACE(("xtermGetSelection num_params %d\n", num_params)); 1559956cc18dSsnj params = MapSelections(xw, params, num_params); 1560d522f475Smrg 1561d522f475Smrg XmuInternStrings(XtDisplay(w), params, (Cardinal) 1, &selection); 1562d522f475Smrg cutbuffer = CutBuffer(selection); 1563d522f475Smrg 1564956cc18dSsnj TRACE(("Cutbuffer: %d, target: %s\n", cutbuffer, 1565956cc18dSsnj (targets 1566956cc18dSsnj ? visibleSelectionTarget(XtDisplay(w), targets[0]) 1567956cc18dSsnj : "None"))); 1568d522f475Smrg 1569d522f475Smrg if (cutbuffer >= 0) { 1570d522f475Smrg int inbytes; 1571d522f475Smrg unsigned long nbytes; 1572d522f475Smrg int fmt8 = 8; 1573d522f475Smrg Atom type = XA_STRING; 1574d522f475Smrg char *line; 1575d522f475Smrg 1576d522f475Smrg /* 'line' is freed in SelectionReceived */ 1577d522f475Smrg line = XFetchBuffer(XtDisplay(w), &inbytes, cutbuffer); 1578d522f475Smrg nbytes = (unsigned long) inbytes; 1579d522f475Smrg 1580d522f475Smrg if (nbytes > 0) 1581d522f475Smrg SelectionReceived(w, NULL, &selection, &type, (XtPointer) line, 1582d522f475Smrg &nbytes, &fmt8); 1583d522f475Smrg else if (num_params > 1) { 1584d522f475Smrg xtermGetSelection(w, ev_time, params + 1, num_params - 1, NULL); 1585d522f475Smrg } 1586d522f475Smrg#if OPT_PASTE64 1587d522f475Smrg else { 1588956cc18dSsnj FinishPaste64(xw); 1589d522f475Smrg } 1590d522f475Smrg#endif 1591d522f475Smrg return; 1592d522f475Smrg } else { 1593d522f475Smrg struct _SelectionList *list; 1594d522f475Smrg 1595d522f475Smrg if (targets == NULL || targets[0] == None) { 1596d522f475Smrg targets = _SelectionTargets(w); 1597d522f475Smrg } 1598d522f475Smrg 1599d522f475Smrg if (targets != 0) { 1600d522f475Smrg target = targets[0]; 1601d522f475Smrg 1602d522f475Smrg if (targets[1] == None) { /* last target in list */ 1603d522f475Smrg params++; 1604d522f475Smrg num_params--; 1605d522f475Smrg targets = _SelectionTargets(w); 1606d522f475Smrg } else { 1607d522f475Smrg targets = &(targets[1]); 1608d522f475Smrg } 1609d522f475Smrg 1610d522f475Smrg if (num_params) { 1611d522f475Smrg /* 'list' is freed in SelectionReceived */ 1612d522f475Smrg list = XtNew(struct _SelectionList); 1613d522f475Smrg if (list != 0) { 1614d522f475Smrg list->params = params; 1615d522f475Smrg list->count = num_params; 1616d522f475Smrg list->targets = targets; 1617d522f475Smrg list->time = ev_time; 1618d522f475Smrg } 1619d522f475Smrg } else { 1620d522f475Smrg list = NULL; 1621d522f475Smrg } 1622d522f475Smrg 1623d522f475Smrg XtGetSelectionValue(w, selection, 1624d522f475Smrg target, 1625d522f475Smrg SelectionReceived, 1626d522f475Smrg (XtPointer) list, ev_time); 1627d522f475Smrg } 1628d522f475Smrg } 1629d522f475Smrg} 1630d522f475Smrg 1631d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 1632d522f475Smrgstatic void 1633d522f475SmrgGettingSelection(Display * dpy, Atom type, Char * line, unsigned long len) 1634d522f475Smrg{ 1635d522f475Smrg Char *cp; 1636d522f475Smrg char *name; 1637d522f475Smrg 1638d522f475Smrg name = XGetAtomName(dpy, type); 1639d522f475Smrg 1640d522f475Smrg TRACE(("Getting %s (%ld)\n", name, (long int) type)); 1641d522f475Smrg for (cp = line; cp < line + len; cp++) { 1642956cc18dSsnj TRACE(("[%d:%lu]", (int) (cp + 1 - line), len)); 1643d522f475Smrg if (isprint(*cp)) { 1644d522f475Smrg TRACE(("%c\n", *cp)); 1645d522f475Smrg } else { 1646d522f475Smrg TRACE(("\\x%02x\n", *cp)); 1647d522f475Smrg } 1648d522f475Smrg } 1649d522f475Smrg} 1650d522f475Smrg#else 1651d522f475Smrg#define GettingSelection(dpy,type,line,len) /* nothing */ 1652d522f475Smrg#endif 1653d522f475Smrg 1654d522f475Smrg#ifdef VMS 1655d522f475Smrg# define tty_vwrite(pty,lag,l) tt_write(lag,l) 1656d522f475Smrg#else /* !( VMS ) */ 1657d522f475Smrg# define tty_vwrite(pty,lag,l) v_write(pty,lag,l) 1658d522f475Smrg#endif /* defined VMS */ 1659d522f475Smrg 1660d522f475Smrg#if OPT_PASTE64 1661d522f475Smrg/* Return base64 code character given 6-bit number */ 1662d522f475Smrgstatic const char base64_code[] = "\ 1663d522f475SmrgABCDEFGHIJKLMNOPQRSTUVWXYZ\ 1664d522f475Smrgabcdefghijklmnopqrstuvwxyz\ 1665d522f475Smrg0123456789+/"; 1666d522f475Smrgstatic void 1667d522f475Smrgbase64_flush(TScreen * screen) 1668d522f475Smrg{ 1669d522f475Smrg Char x; 1670d522f475Smrg switch (screen->base64_count) { 1671d522f475Smrg case 0: 1672d522f475Smrg break; 1673d522f475Smrg case 2: 16742eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 4]); 1675d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1676d522f475Smrg break; 1677d522f475Smrg case 4: 16782eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 2]); 1679d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1680d522f475Smrg break; 1681d522f475Smrg } 1682d522f475Smrg if (screen->base64_pad & 3) 1683d522f475Smrg tty_vwrite(screen->respond, 1684d522f475Smrg (Char *) "===", 1685d522f475Smrg (unsigned) (4 - (screen->base64_pad & 3))); 1686d522f475Smrg screen->base64_count = 0; 1687d522f475Smrg screen->base64_accu = 0; 1688d522f475Smrg screen->base64_pad = 0; 1689d522f475Smrg} 1690d522f475Smrg#endif /* OPT_PASTE64 */ 1691d522f475Smrg 1692d522f475Smrgstatic void 1693d522f475Smrg_qWriteSelectionData(TScreen * screen, Char * lag, unsigned length) 1694d522f475Smrg{ 1695d522f475Smrg#if OPT_PASTE64 1696d522f475Smrg if (screen->base64_paste) { 1697d522f475Smrg /* Send data as base64 */ 1698d522f475Smrg Char *p = lag; 1699d522f475Smrg Char buf[64]; 1700d522f475Smrg unsigned x = 0; 1701d522f475Smrg while (length--) { 1702d522f475Smrg switch (screen->base64_count) { 1703d522f475Smrg case 0: 17042eaa94a1Schristos buf[x++] = CharOf(base64_code[*p >> 2]); 17052eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0x3); 1706d522f475Smrg screen->base64_count = 2; 1707d522f475Smrg ++p; 1708d522f475Smrg break; 1709d522f475Smrg case 2: 17102eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 4) + 17112eaa94a1Schristos (*p >> 4)]); 17122eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0xF); 1713d522f475Smrg screen->base64_count = 4; 1714d522f475Smrg ++p; 1715d522f475Smrg break; 1716d522f475Smrg case 4: 17172eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 2) + 17182eaa94a1Schristos (*p >> 6)]); 17192eaa94a1Schristos buf[x++] = CharOf(base64_code[*p & 0x3F]); 1720d522f475Smrg screen->base64_accu = 0; 1721d522f475Smrg screen->base64_count = 0; 1722d522f475Smrg ++p; 1723d522f475Smrg break; 1724d522f475Smrg } 1725d522f475Smrg if (x >= 63) { 1726d522f475Smrg /* Write 63 or 64 characters */ 1727d522f475Smrg screen->base64_pad += x; 1728d522f475Smrg tty_vwrite(screen->respond, buf, x); 1729d522f475Smrg x = 0; 1730d522f475Smrg } 1731d522f475Smrg } 1732d522f475Smrg if (x != 0) { 1733d522f475Smrg screen->base64_pad += x; 1734d522f475Smrg tty_vwrite(screen->respond, buf, x); 1735d522f475Smrg } 1736d522f475Smrg } else 1737d522f475Smrg#endif /* OPT_PASTE64 */ 1738d522f475Smrg#if OPT_READLINE 1739d522f475Smrg if (SCREEN_FLAG(screen, paste_quotes)) { 1740d522f475Smrg while (length--) { 1741d522f475Smrg tty_vwrite(screen->respond, (Char *) "\026", 1); /* Control-V */ 1742d522f475Smrg tty_vwrite(screen->respond, lag++, 1); 1743d522f475Smrg } 1744d522f475Smrg } else 1745d522f475Smrg#endif 1746d522f475Smrg tty_vwrite(screen->respond, lag, length); 1747d522f475Smrg} 1748d522f475Smrg 1749d522f475Smrgstatic void 175020d2c4d2Smrg_WriteSelectionData(TScreen * screen, Char * line, size_t length) 1751d522f475Smrg{ 1752d522f475Smrg /* Write data to pty a line at a time. */ 1753d522f475Smrg /* Doing this one line at a time may no longer be necessary 1754d522f475Smrg because v_write has been re-written. */ 1755d522f475Smrg 1756d522f475Smrg Char *lag, *end; 1757d522f475Smrg 1758d522f475Smrg /* in the VMS version, if tt_pasting isn't set to True then qio 1759d522f475Smrg reads aren't blocked and an infinite loop is entered, where the 1760d522f475Smrg pasted text shows up as new input, goes in again, shows up 1761d522f475Smrg again, ad nauseum. */ 1762d522f475Smrg#ifdef VMS 1763d522f475Smrg tt_pasting = True; 1764d522f475Smrg#endif 1765d522f475Smrg 1766d522f475Smrg end = &line[length]; 1767d522f475Smrg lag = line; 1768d522f475Smrg 1769d522f475Smrg#if OPT_PASTE64 1770d522f475Smrg if (screen->base64_paste) { 1771d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (end - lag)); 1772d522f475Smrg base64_flush(screen); 1773d522f475Smrg } else 1774d522f475Smrg#endif 1775d522f475Smrg { 1776d522f475Smrg if (!SCREEN_FLAG(screen, paste_literal_nl)) { 1777d522f475Smrg Char *cp; 1778d522f475Smrg for (cp = line; cp != end; cp++) { 1779d522f475Smrg if (*cp == '\n') { 1780d522f475Smrg *cp = '\r'; 1781d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (cp - lag + 1)); 1782d522f475Smrg lag = cp + 1; 1783d522f475Smrg } 1784d522f475Smrg } 1785d522f475Smrg } 1786d522f475Smrg 1787d522f475Smrg if (lag != end) { 1788d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (end - lag)); 1789d522f475Smrg } 1790d522f475Smrg } 1791d522f475Smrg#ifdef VMS 1792d522f475Smrg tt_pasting = False; 1793d522f475Smrg tt_start_read(); /* reenable reads or a character may be lost */ 1794d522f475Smrg#endif 1795d522f475Smrg} 1796d522f475Smrg 1797d522f475Smrg#if OPT_READLINE 1798d522f475Smrgstatic void 1799d522f475Smrg_WriteKey(TScreen * screen, Char * in) 1800d522f475Smrg{ 1801d522f475Smrg Char line[16]; 1802d522f475Smrg unsigned count = 0; 180320d2c4d2Smrg size_t length = strlen((char *) in); 1804d522f475Smrg 1805d522f475Smrg if (screen->control_eight_bits) { 1806d522f475Smrg line[count++] = ANSI_CSI; 1807d522f475Smrg } else { 1808d522f475Smrg line[count++] = ANSI_ESC; 1809d522f475Smrg line[count++] = '['; 1810d522f475Smrg } 1811d522f475Smrg while (length--) 1812d522f475Smrg line[count++] = *in++; 1813d522f475Smrg line[count++] = '~'; 1814d522f475Smrg tty_vwrite(screen->respond, line, count); 1815d522f475Smrg} 1816d522f475Smrg#endif /* OPT_READLINE */ 1817d522f475Smrg 1818d522f475Smrg/* SelectionReceived: stuff received selection text into pty */ 1819d522f475Smrg 1820d522f475Smrg/* ARGSUSED */ 1821d522f475Smrgstatic void 1822d522f475SmrgSelectionReceived(Widget w, 1823d522f475Smrg XtPointer client_data, 1824d522f475Smrg Atom * selection GCC_UNUSED, 1825d522f475Smrg Atom * type, 1826d522f475Smrg XtPointer value, 1827d522f475Smrg unsigned long *length, 1828d522f475Smrg int *format) 1829d522f475Smrg{ 1830d522f475Smrg char **text_list = NULL; 1831d522f475Smrg int text_list_count; 1832d522f475Smrg XTextProperty text_prop; 1833d522f475Smrg TScreen *screen; 1834d522f475Smrg Display *dpy; 1835d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 1836d522f475Smrg Char *line = (Char *) value; 1837d522f475Smrg#endif 1838d522f475Smrg 1839956cc18dSsnj XtermWidget xw; 1840956cc18dSsnj 1841956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 1842d522f475Smrg return; 1843956cc18dSsnj 1844956cc18dSsnj screen = TScreenOf(xw); 1845d522f475Smrg dpy = XtDisplay(w); 1846d522f475Smrg 1847d522f475Smrg if (*type == 0 /*XT_CONVERT_FAIL */ 1848d522f475Smrg || *length == 0 1849d522f475Smrg || value == NULL) 1850d522f475Smrg goto fail; 1851d522f475Smrg 1852d522f475Smrg text_prop.value = (unsigned char *) value; 1853d522f475Smrg text_prop.encoding = *type; 1854d522f475Smrg text_prop.format = *format; 1855d522f475Smrg text_prop.nitems = *length; 1856d522f475Smrg 1857956cc18dSsnj TRACE(("SelectionReceived %s format %d, nitems %ld\n", 1858956cc18dSsnj visibleSelectionTarget(dpy, text_prop.encoding), 1859956cc18dSsnj text_prop.format, 1860956cc18dSsnj text_prop.nitems)); 1861956cc18dSsnj 1862d522f475Smrg#if OPT_WIDE_CHARS 1863d522f475Smrg if (screen->wide_chars) { 1864d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 1865d522f475Smrg *type == XA_STRING || 1866d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 1867d522f475Smrg GettingSelection(dpy, *type, line, *length); 1868d522f475Smrg if (Xutf8TextPropertyToTextList(dpy, &text_prop, 1869d522f475Smrg &text_list, 1870d522f475Smrg &text_list_count) < 0) { 1871d522f475Smrg TRACE(("Conversion failed\n")); 1872d522f475Smrg text_list = NULL; 1873d522f475Smrg } 1874d522f475Smrg } 1875d522f475Smrg } else 1876d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1877d522f475Smrg { 1878d522f475Smrg /* Convert the selection to locale's multibyte encoding. */ 1879d522f475Smrg 1880d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 1881d522f475Smrg *type == XA_STRING || 1882d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 1883d522f475Smrg Status rc; 1884d522f475Smrg 1885d522f475Smrg GettingSelection(dpy, *type, line, *length); 1886d522f475Smrg 1887d522f475Smrg#if OPT_WIDE_CHARS 1888d522f475Smrg if (*type == XA_UTF8_STRING(dpy) && 1889d522f475Smrg !(screen->wide_chars || screen->c1_printable)) { 189020d2c4d2Smrg rc = xtermUtf8ToTextList(xw, &text_prop, 189120d2c4d2Smrg &text_list, &text_list_count); 1892d522f475Smrg } else 1893d522f475Smrg#endif 1894d522f475Smrg if (*type == XA_STRING && screen->brokenSelections) { 1895d522f475Smrg rc = XTextPropertyToStringList(&text_prop, 1896d522f475Smrg &text_list, &text_list_count); 1897d522f475Smrg } else { 1898d522f475Smrg rc = XmbTextPropertyToTextList(dpy, &text_prop, 1899d522f475Smrg &text_list, 1900d522f475Smrg &text_list_count); 1901d522f475Smrg } 1902d522f475Smrg if (rc < 0) { 1903d522f475Smrg TRACE(("Conversion failed\n")); 1904d522f475Smrg text_list = NULL; 1905d522f475Smrg } 1906d522f475Smrg } 1907d522f475Smrg } 1908d522f475Smrg 1909d522f475Smrg if (text_list != NULL && text_list_count != 0) { 1910d522f475Smrg int i; 1911d522f475Smrg 1912d522f475Smrg#if OPT_PASTE64 1913d522f475Smrg if (screen->base64_paste) { 1914d522f475Smrg ; 1915d522f475Smrg } else 1916d522f475Smrg#endif 1917d522f475Smrg#if OPT_READLINE 1918d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 1919d522f475Smrg _WriteKey(screen, (Char *) "200"); 1920d522f475Smrg } 1921d522f475Smrg#endif 1922d522f475Smrg for (i = 0; i < text_list_count; i++) { 192320d2c4d2Smrg size_t len = strlen(text_list[i]); 1924d522f475Smrg _WriteSelectionData(screen, (Char *) text_list[i], len); 1925d522f475Smrg } 1926d522f475Smrg#if OPT_PASTE64 1927d522f475Smrg if (screen->base64_paste) { 1928956cc18dSsnj FinishPaste64(xw); 1929d522f475Smrg } else 1930d522f475Smrg#endif 1931d522f475Smrg#if OPT_READLINE 1932d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 1933d522f475Smrg _WriteKey(screen, (Char *) "201"); 1934d522f475Smrg } 1935d522f475Smrg#endif 1936d522f475Smrg XFreeStringList(text_list); 1937d522f475Smrg } else 1938d522f475Smrg goto fail; 1939d522f475Smrg 1940d522f475Smrg XtFree((char *) client_data); 1941d522f475Smrg XtFree((char *) value); 1942d522f475Smrg 1943d522f475Smrg return; 1944d522f475Smrg 1945d522f475Smrg fail: 1946d522f475Smrg if (client_data != 0) { 1947d522f475Smrg struct _SelectionList *list = (struct _SelectionList *) client_data; 1948956cc18dSsnj 1949956cc18dSsnj TRACE(("SelectionReceived ->xtermGetSelection\n")); 1950d522f475Smrg xtermGetSelection(w, list->time, 1951d522f475Smrg list->params, list->count, list->targets); 1952d522f475Smrg XtFree((char *) client_data); 1953d522f475Smrg#if OPT_PASTE64 1954d522f475Smrg } else { 1955956cc18dSsnj FinishPaste64(xw); 1956d522f475Smrg#endif 1957d522f475Smrg } 1958d522f475Smrg return; 1959d522f475Smrg} 1960d522f475Smrg 1961d522f475Smrgvoid 1962d522f475SmrgHandleInsertSelection(Widget w, 1963d522f475Smrg XEvent * event, /* assumed to be XButtonEvent* */ 1964d522f475Smrg String * params, /* selections in precedence order */ 1965d522f475Smrg Cardinal *num_params) 1966d522f475Smrg{ 1967956cc18dSsnj XtermWidget xw; 1968d522f475Smrg 1969956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1970d522f475Smrg if (!SendMousePosition(xw, event)) { 1971d522f475Smrg#if OPT_READLINE 1972d522f475Smrg int ldelta; 1973956cc18dSsnj TScreen *screen = TScreenOf(xw); 1974d522f475Smrg if ((event->type == ButtonPress || event->type == ButtonRelease) 1975d522f475Smrg /* Disable on Shift-mouse, including the application-mouse modes */ 1976d522f475Smrg && !(KeyModifiers & ShiftMask) 1977d522f475Smrg && (screen->send_mouse_pos == MOUSE_OFF) 1978d522f475Smrg && SCREEN_FLAG(screen, paste_moves) 1979d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta)) 1980d522f475Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta); 1981d522f475Smrg#endif /* OPT_READLINE */ 1982d522f475Smrg 1983d522f475Smrg xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL); 1984d522f475Smrg } 1985d522f475Smrg } 1986d522f475Smrg} 1987d522f475Smrg 1988d522f475Smrgstatic SelectUnit 1989956cc18dSsnjEvalSelectUnit(XtermWidget xw, 1990d522f475Smrg Time buttonDownTime, 1991d522f475Smrg SelectUnit defaultUnit, 1992d522f475Smrg unsigned int button) 1993d522f475Smrg{ 1994956cc18dSsnj TScreen *screen = TScreenOf(xw); 1995d522f475Smrg SelectUnit result; 1996d522f475Smrg int delta; 1997d522f475Smrg 1998d522f475Smrg if (button != screen->lastButton) { 199920d2c4d2Smrg delta = screen->multiClickTime + 1; 2000d522f475Smrg } else if (screen->lastButtonUpTime == (Time) 0) { 2001d522f475Smrg /* first time and once in a blue moon */ 2002d522f475Smrg delta = screen->multiClickTime + 1; 2003d522f475Smrg } else if (buttonDownTime > screen->lastButtonUpTime) { 2004d522f475Smrg /* most of the time */ 20052eaa94a1Schristos delta = (int) (buttonDownTime - screen->lastButtonUpTime); 2006d522f475Smrg } else { 2007d522f475Smrg /* time has rolled over since lastButtonUpTime */ 20082eaa94a1Schristos delta = (int) ((((Time) ~ 0) - screen->lastButtonUpTime) + buttonDownTime); 2009d522f475Smrg } 2010d522f475Smrg 2011d522f475Smrg if (delta > screen->multiClickTime) { 2012d522f475Smrg screen->numberOfClicks = 1; 2013d522f475Smrg result = defaultUnit; 2014d522f475Smrg } else { 2015d522f475Smrg result = screen->selectMap[screen->numberOfClicks % screen->maxClicks]; 2016d522f475Smrg screen->numberOfClicks += 1; 2017d522f475Smrg } 2018d522f475Smrg TRACE(("EvalSelectUnit(%d) = %d\n", screen->numberOfClicks, result)); 2019d522f475Smrg return result; 2020d522f475Smrg} 2021d522f475Smrg 2022d522f475Smrgstatic void 2023d522f475Smrgdo_select_start(XtermWidget xw, 2024d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2025d522f475Smrg CELL * cell) 2026d522f475Smrg{ 2027956cc18dSsnj TScreen *screen = TScreenOf(xw); 2028d522f475Smrg 2029d522f475Smrg if (SendMousePosition(xw, event)) 2030d522f475Smrg return; 2031956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2032d522f475Smrg event->xbutton.time, 2033d522f475Smrg Select_CHAR, 2034d522f475Smrg event->xbutton.button); 2035d522f475Smrg screen->replyToEmacs = False; 2036d522f475Smrg 2037d522f475Smrg#if OPT_READLINE 2038d522f475Smrg lastButtonDownTime = event->xbutton.time; 2039d522f475Smrg#endif 2040d522f475Smrg 2041d522f475Smrg StartSelect(xw, cell); 2042d522f475Smrg} 2043d522f475Smrg 2044d522f475Smrg/* ARGSUSED */ 2045d522f475Smrgvoid 2046d522f475SmrgHandleSelectStart(Widget w, 2047d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2048d522f475Smrg String * params GCC_UNUSED, 2049d522f475Smrg Cardinal *num_params GCC_UNUSED) 2050d522f475Smrg{ 2051956cc18dSsnj XtermWidget xw; 2052956cc18dSsnj 2053956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2054956cc18dSsnj TScreen *screen = TScreenOf(xw); 2055d522f475Smrg CELL cell; 2056d522f475Smrg 2057d522f475Smrg screen->firstValidRow = 0; 2058d522f475Smrg screen->lastValidRow = screen->max_row; 2059d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2060d522f475Smrg 2061d522f475Smrg#if OPT_READLINE 2062d522f475Smrg ExtendingSelection = 0; 2063d522f475Smrg#endif 2064d522f475Smrg 2065d522f475Smrg do_select_start(xw, event, &cell); 2066d522f475Smrg } 2067d522f475Smrg} 2068d522f475Smrg 2069d522f475Smrg/* ARGSUSED */ 2070d522f475Smrgvoid 2071d522f475SmrgHandleKeyboardSelectStart(Widget w, 2072d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2073d522f475Smrg String * params GCC_UNUSED, 2074d522f475Smrg Cardinal *num_params GCC_UNUSED) 2075d522f475Smrg{ 2076956cc18dSsnj XtermWidget xw; 2077956cc18dSsnj 2078956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2079956cc18dSsnj TScreen *screen = TScreenOf(xw); 2080d522f475Smrg do_select_start(xw, event, &screen->cursorp); 2081d522f475Smrg } 2082d522f475Smrg} 2083d522f475Smrg 2084d522f475Smrgstatic void 2085d522f475SmrgTrackDown(XtermWidget xw, XButtonEvent * event) 2086d522f475Smrg{ 2087956cc18dSsnj TScreen *screen = TScreenOf(xw); 2088d522f475Smrg CELL cell; 2089d522f475Smrg 2090956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2091d522f475Smrg event->time, 2092d522f475Smrg Select_CHAR, 2093d522f475Smrg event->button); 2094d522f475Smrg if (screen->numberOfClicks > 1) { 2095d522f475Smrg PointToCELL(screen, event->y, event->x, &cell); 2096d522f475Smrg screen->replyToEmacs = True; 2097d522f475Smrg StartSelect(xw, &cell); 2098d522f475Smrg } else { 2099d522f475Smrg screen->waitingForTrackInfo = True; 2100d522f475Smrg EditorButton(xw, (XButtonEvent *) event); 2101d522f475Smrg } 2102d522f475Smrg} 2103d522f475Smrg 2104d522f475Smrg#define boundsCheck(x) if (x < 0) \ 2105d522f475Smrg x = 0; \ 2106d522f475Smrg else if (x >= screen->max_row) \ 2107d522f475Smrg x = screen->max_row 2108d522f475Smrg 2109d522f475Smrgvoid 2110d522f475SmrgTrackMouse(XtermWidget xw, 2111d522f475Smrg int func, 2112d522f475Smrg CELL * start, 2113d522f475Smrg int firstrow, 2114d522f475Smrg int lastrow) 2115d522f475Smrg{ 2116956cc18dSsnj TScreen *screen = TScreenOf(xw); 2117d522f475Smrg 2118d522f475Smrg if (screen->waitingForTrackInfo) { /* if Timed, ignore */ 2119d522f475Smrg screen->waitingForTrackInfo = False; 2120d522f475Smrg 2121d522f475Smrg if (func != 0) { 2122d522f475Smrg CELL first = *start; 2123d522f475Smrg 2124d522f475Smrg boundsCheck(first.row); 2125d522f475Smrg boundsCheck(firstrow); 2126d522f475Smrg boundsCheck(lastrow); 2127d522f475Smrg screen->firstValidRow = firstrow; 2128d522f475Smrg screen->lastValidRow = lastrow; 2129d522f475Smrg screen->replyToEmacs = True; 2130d522f475Smrg StartSelect(xw, &first); 2131d522f475Smrg } 2132d522f475Smrg } 2133d522f475Smrg} 2134d522f475Smrg 2135d522f475Smrgstatic void 2136d522f475SmrgStartSelect(XtermWidget xw, const CELL * cell) 2137d522f475Smrg{ 2138956cc18dSsnj TScreen *screen = TScreenOf(xw); 2139d522f475Smrg 2140d522f475Smrg TRACE(("StartSelect row=%d, col=%d\n", cell->row, cell->col)); 2141d522f475Smrg if (screen->cursor_state) 2142d522f475Smrg HideCursor(); 2143d522f475Smrg if (screen->numberOfClicks == 1) { 2144d522f475Smrg /* set start of selection */ 2145d522f475Smrg screen->rawPos = *cell; 2146d522f475Smrg } 2147d522f475Smrg /* else use old values in rawPos */ 2148d522f475Smrg screen->saveStartR = screen->startExt = screen->rawPos; 2149d522f475Smrg screen->saveEndR = screen->endExt = screen->rawPos; 2150d522f475Smrg if (Coordinate(screen, cell) < Coordinate(screen, &(screen->rawPos))) { 2151d522f475Smrg screen->eventMode = LEFTEXTENSION; 2152d522f475Smrg screen->startExt = *cell; 2153d522f475Smrg } else { 2154d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2155d522f475Smrg screen->endExt = *cell; 2156d522f475Smrg } 2157d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 2158d522f475Smrg} 2159d522f475Smrg 2160d522f475Smrgstatic void 2161d522f475SmrgEndExtend(XtermWidget xw, 2162d522f475Smrg XEvent * event, /* must be XButtonEvent */ 2163d522f475Smrg String * params, /* selections */ 2164d522f475Smrg Cardinal num_params, 2165d522f475Smrg Bool use_cursor_loc) 2166d522f475Smrg{ 2167d522f475Smrg CELL cell; 2168d522f475Smrg unsigned count; 2169956cc18dSsnj TScreen *screen = TScreenOf(xw); 2170d522f475Smrg Char line[9]; 2171d522f475Smrg 2172d522f475Smrg if (use_cursor_loc) { 2173d522f475Smrg cell = screen->cursorp; 2174d522f475Smrg } else { 2175d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2176d522f475Smrg } 2177d522f475Smrg ExtendExtend(xw, &cell); 2178d522f475Smrg screen->lastButtonUpTime = event->xbutton.time; 2179d522f475Smrg screen->lastButton = event->xbutton.button; 2180d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 2181d522f475Smrg if (screen->replyToEmacs) { 2182d522f475Smrg count = 0; 2183d522f475Smrg if (screen->control_eight_bits) { 2184d522f475Smrg line[count++] = ANSI_CSI; 2185d522f475Smrg } else { 2186d522f475Smrg line[count++] = ANSI_ESC; 2187d522f475Smrg line[count++] = '['; 2188d522f475Smrg } 2189d522f475Smrg if (isSameCELL(&(screen->rawPos), &(screen->startSel)) 2190d522f475Smrg && isSameCELL(&cell, &(screen->endSel))) { 2191d522f475Smrg /* Use short-form emacs select */ 2192d522f475Smrg line[count++] = 't'; 21932eaa94a1Schristos line[count++] = CharOf(' ' + screen->endSel.col + 1); 21942eaa94a1Schristos line[count++] = CharOf(' ' + screen->endSel.row + 1); 2195d522f475Smrg } else { 2196d522f475Smrg /* long-form, specify everything */ 2197d522f475Smrg line[count++] = 'T'; 21982eaa94a1Schristos line[count++] = CharOf(' ' + screen->startSel.col + 1); 21992eaa94a1Schristos line[count++] = CharOf(' ' + screen->startSel.row + 1); 22002eaa94a1Schristos line[count++] = CharOf(' ' + screen->endSel.col + 1); 22012eaa94a1Schristos line[count++] = CharOf(' ' + screen->endSel.row + 1); 22022eaa94a1Schristos line[count++] = CharOf(' ' + cell.col + 1); 22032eaa94a1Schristos line[count++] = CharOf(' ' + cell.row + 1); 2204d522f475Smrg } 2205d522f475Smrg v_write(screen->respond, line, count); 2206d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 2207d522f475Smrg } 2208d522f475Smrg } 2209d522f475Smrg SelectSet(xw, event, params, num_params); 2210d522f475Smrg screen->eventMode = NORMAL; 2211d522f475Smrg} 2212d522f475Smrg 2213d522f475Smrgvoid 2214d522f475SmrgHandleSelectSet(Widget w, 2215d522f475Smrg XEvent * event, 2216d522f475Smrg String * params, 2217d522f475Smrg Cardinal *num_params) 2218d522f475Smrg{ 2219956cc18dSsnj XtermWidget xw; 2220956cc18dSsnj 2221956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2222956cc18dSsnj SelectSet(xw, event, params, *num_params); 2223d522f475Smrg } 2224d522f475Smrg} 2225d522f475Smrg 2226d522f475Smrg/* ARGSUSED */ 2227d522f475Smrgstatic void 2228d522f475SmrgSelectSet(XtermWidget xw, 2229d522f475Smrg XEvent * event GCC_UNUSED, 2230d522f475Smrg String * params, 2231d522f475Smrg Cardinal num_params) 2232d522f475Smrg{ 2233956cc18dSsnj TScreen *screen = TScreenOf(xw); 2234d522f475Smrg 2235d522f475Smrg TRACE(("SelectSet\n")); 2236d522f475Smrg /* Only do select stuff if non-null select */ 2237d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 2238d522f475Smrg SaltTextAway(xw, &(screen->startSel), &(screen->endSel), params, num_params); 2239d522f475Smrg } else { 2240d522f475Smrg DisownSelection(xw); 2241d522f475Smrg } 2242d522f475Smrg} 2243d522f475Smrg 2244d522f475Smrg#define Abs(x) ((x) < 0 ? -(x) : (x)) 2245d522f475Smrg 2246d522f475Smrg/* ARGSUSED */ 2247d522f475Smrgstatic void 2248d522f475Smrgdo_start_extend(XtermWidget xw, 2249d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2250d522f475Smrg String * params GCC_UNUSED, 2251d522f475Smrg Cardinal *num_params GCC_UNUSED, 2252d522f475Smrg Bool use_cursor_loc) 2253d522f475Smrg{ 2254956cc18dSsnj TScreen *screen = TScreenOf(xw); 2255d522f475Smrg int coord; 2256d522f475Smrg CELL cell; 2257d522f475Smrg 2258d522f475Smrg if (SendMousePosition(xw, event)) 2259d522f475Smrg return; 2260d522f475Smrg 2261d522f475Smrg screen->firstValidRow = 0; 2262d522f475Smrg screen->lastValidRow = screen->max_row; 2263d522f475Smrg#if OPT_READLINE 2264d522f475Smrg if ((KeyModifiers & ShiftMask) 2265d522f475Smrg || event->xbutton.button != Button3 2266d522f475Smrg || !(SCREEN_FLAG(screen, dclick3_deletes))) 2267d522f475Smrg#endif 2268956cc18dSsnj screen->selectUnit = EvalSelectUnit(xw, 2269d522f475Smrg event->xbutton.time, 2270d522f475Smrg screen->selectUnit, 2271d522f475Smrg event->xbutton.button); 2272d522f475Smrg screen->replyToEmacs = False; 2273d522f475Smrg 2274d522f475Smrg#if OPT_READLINE 2275d522f475Smrg CheckSecondPress3(screen, event); 2276d522f475Smrg#endif 2277d522f475Smrg 2278d522f475Smrg if (screen->numberOfClicks == 1 2279d522f475Smrg || (SCREEN_FLAG(screen, dclick3_deletes) /* Dclick special */ 2280d522f475Smrg &&!(KeyModifiers & ShiftMask))) { 2281d522f475Smrg /* Save existing selection so we can reestablish it if the guy 2282d522f475Smrg extends past the other end of the selection */ 2283d522f475Smrg screen->saveStartR = screen->startExt = screen->startRaw; 2284d522f475Smrg screen->saveEndR = screen->endExt = screen->endRaw; 2285d522f475Smrg } else { 2286d522f475Smrg /* He just needed the selection mode changed, use old values. */ 2287d522f475Smrg screen->startExt = screen->startRaw = screen->saveStartR; 2288d522f475Smrg screen->endExt = screen->endRaw = screen->saveEndR; 2289d522f475Smrg } 2290d522f475Smrg if (use_cursor_loc) { 2291d522f475Smrg cell = screen->cursorp; 2292d522f475Smrg } else { 2293d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2294d522f475Smrg } 2295d522f475Smrg coord = Coordinate(screen, &cell); 2296d522f475Smrg 2297d522f475Smrg if (Abs(coord - Coordinate(screen, &(screen->startSel))) 2298d522f475Smrg < Abs(coord - Coordinate(screen, &(screen->endSel))) 2299d522f475Smrg || coord < Coordinate(screen, &(screen->startSel))) { 2300d522f475Smrg /* point is close to left side of selection */ 2301d522f475Smrg screen->eventMode = LEFTEXTENSION; 2302d522f475Smrg screen->startExt = cell; 2303d522f475Smrg } else { 2304d522f475Smrg /* point is close to left side of selection */ 2305d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2306d522f475Smrg screen->endExt = cell; 2307d522f475Smrg } 2308d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), True); 2309d522f475Smrg 2310d522f475Smrg#if OPT_READLINE 2311d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2312d522f475Smrg ExtendingSelection = 1; 2313d522f475Smrg#endif 2314d522f475Smrg} 2315d522f475Smrg 2316d522f475Smrgstatic void 2317d522f475SmrgExtendExtend(XtermWidget xw, const CELL * cell) 2318d522f475Smrg{ 2319956cc18dSsnj TScreen *screen = TScreenOf(xw); 2320d522f475Smrg int coord = Coordinate(screen, cell); 2321d522f475Smrg 2322d522f475Smrg TRACE(("ExtendExtend row=%d, col=%d\n", cell->row, cell->col)); 2323d522f475Smrg if (screen->eventMode == LEFTEXTENSION 2324d522f475Smrg && ((coord + (screen->selectUnit != Select_CHAR)) 2325d522f475Smrg > Coordinate(screen, &(screen->endSel)))) { 2326d522f475Smrg /* Whoops, he's changed his mind. Do RIGHTEXTENSION */ 2327d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2328d522f475Smrg screen->startExt = screen->saveStartR; 2329d522f475Smrg } else if (screen->eventMode == RIGHTEXTENSION 2330d522f475Smrg && coord < Coordinate(screen, &(screen->startSel))) { 2331d522f475Smrg /* Whoops, he's changed his mind. Do LEFTEXTENSION */ 2332d522f475Smrg screen->eventMode = LEFTEXTENSION; 2333d522f475Smrg screen->endExt = screen->saveEndR; 2334d522f475Smrg } 2335d522f475Smrg if (screen->eventMode == LEFTEXTENSION) { 2336d522f475Smrg screen->startExt = *cell; 2337d522f475Smrg } else { 2338d522f475Smrg screen->endExt = *cell; 2339d522f475Smrg } 2340d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 2341d522f475Smrg 2342d522f475Smrg#if OPT_READLINE 2343d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2344d522f475Smrg ExtendingSelection = 1; 2345d522f475Smrg#endif 2346d522f475Smrg} 2347d522f475Smrg 2348d522f475Smrgvoid 2349d522f475SmrgHandleStartExtend(Widget w, 2350d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2351d522f475Smrg String * params, /* unused */ 2352d522f475Smrg Cardinal *num_params) /* unused */ 2353d522f475Smrg{ 2354956cc18dSsnj XtermWidget xw; 2355956cc18dSsnj 2356956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2357956cc18dSsnj do_start_extend(xw, event, params, num_params, False); 2358956cc18dSsnj } 2359d522f475Smrg} 2360d522f475Smrg 2361d522f475Smrgvoid 2362d522f475SmrgHandleKeyboardStartExtend(Widget w, 2363d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2364d522f475Smrg String * params, /* unused */ 2365d522f475Smrg Cardinal *num_params) /* unused */ 2366d522f475Smrg{ 2367956cc18dSsnj XtermWidget xw; 2368956cc18dSsnj 2369956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 2370956cc18dSsnj do_start_extend(xw, event, params, num_params, True); 2371956cc18dSsnj } 2372d522f475Smrg} 2373d522f475Smrg 2374d522f475Smrgvoid 2375d522f475SmrgScrollSelection(TScreen * screen, int amount, Bool always) 2376d522f475Smrg{ 2377d522f475Smrg int minrow = INX2ROW(screen, -screen->savedlines); 2378d522f475Smrg int maxrow = INX2ROW(screen, screen->max_row); 2379d522f475Smrg int maxcol = screen->max_col; 2380d522f475Smrg 2381d522f475Smrg#define scroll_update_one(cell) \ 2382d522f475Smrg (cell)->row += amount; \ 2383d522f475Smrg if ((cell)->row < minrow) { \ 2384d522f475Smrg (cell)->row = minrow; \ 2385d522f475Smrg (cell)->col = 0; \ 2386d522f475Smrg } \ 2387d522f475Smrg if ((cell)->row > maxrow) { \ 2388d522f475Smrg (cell)->row = maxrow; \ 2389d522f475Smrg (cell)->col = maxcol; \ 2390d522f475Smrg } 2391d522f475Smrg 2392d522f475Smrg scroll_update_one(&(screen->startRaw)); 2393d522f475Smrg scroll_update_one(&(screen->endRaw)); 2394d522f475Smrg scroll_update_one(&(screen->startSel)); 2395d522f475Smrg scroll_update_one(&(screen->endSel)); 2396d522f475Smrg 2397d522f475Smrg scroll_update_one(&(screen->rawPos)); 2398d522f475Smrg 2399d522f475Smrg /* 2400d522f475Smrg * If we are told to scroll the selection but it lies outside the scrolling 2401d522f475Smrg * margins, then that could cause the selection to move (bad). It is not 2402d522f475Smrg * simple to fix, because this function is called both for the scrollbar 2403d522f475Smrg * actions as well as application scrolling. The 'always' flag is set in 2404d522f475Smrg * the former case. The rest of the logic handles the latter. 2405d522f475Smrg */ 2406d522f475Smrg if (ScrnHaveSelection(screen)) { 2407d522f475Smrg int adjust; 2408d522f475Smrg 2409d522f475Smrg adjust = ROW2INX(screen, screen->startH.row); 2410d522f475Smrg if (always 2411d522f475Smrg || !ScrnHaveLineMargins(screen) 2412d522f475Smrg || ScrnIsLineInMargins(screen, adjust)) { 2413d522f475Smrg scroll_update_one(&screen->startH); 2414d522f475Smrg } 2415d522f475Smrg adjust = ROW2INX(screen, screen->endH.row); 2416d522f475Smrg if (always 2417d522f475Smrg || !ScrnHaveLineMargins(screen) 2418d522f475Smrg || ScrnIsLineInMargins(screen, adjust)) { 2419d522f475Smrg scroll_update_one(&screen->endH); 2420d522f475Smrg } 2421d522f475Smrg } 2422d522f475Smrg 2423d522f475Smrg screen->startHCoord = Coordinate(screen, &screen->startH); 2424d522f475Smrg screen->endHCoord = Coordinate(screen, &screen->endH); 2425d522f475Smrg} 2426d522f475Smrg 2427d522f475Smrg/*ARGSUSED*/ 2428d522f475Smrgvoid 2429d522f475SmrgResizeSelection(TScreen * screen GCC_UNUSED, int rows, int cols) 2430d522f475Smrg{ 2431d522f475Smrg rows--; /* decr to get 0-max */ 2432d522f475Smrg cols--; 2433d522f475Smrg 2434d522f475Smrg if (screen->startRaw.row > rows) 2435d522f475Smrg screen->startRaw.row = rows; 2436d522f475Smrg if (screen->startSel.row > rows) 2437d522f475Smrg screen->startSel.row = rows; 2438d522f475Smrg if (screen->endRaw.row > rows) 2439d522f475Smrg screen->endRaw.row = rows; 2440d522f475Smrg if (screen->endSel.row > rows) 2441d522f475Smrg screen->endSel.row = rows; 2442d522f475Smrg if (screen->rawPos.row > rows) 2443d522f475Smrg screen->rawPos.row = rows; 2444d522f475Smrg 2445d522f475Smrg if (screen->startRaw.col > cols) 2446d522f475Smrg screen->startRaw.col = cols; 2447d522f475Smrg if (screen->startSel.col > cols) 2448d522f475Smrg screen->startSel.col = cols; 2449d522f475Smrg if (screen->endRaw.col > cols) 2450d522f475Smrg screen->endRaw.col = cols; 2451d522f475Smrg if (screen->endSel.col > cols) 2452d522f475Smrg screen->endSel.col = cols; 2453d522f475Smrg if (screen->rawPos.col > cols) 2454d522f475Smrg screen->rawPos.col = cols; 2455d522f475Smrg} 2456d522f475Smrg 2457d522f475Smrg#if OPT_WIDE_CHARS 2458d522f475SmrgBool 2459d522f475Smrgiswide(int i) 2460d522f475Smrg{ 246120d2c4d2Smrg return (i == HIDDEN_CHAR) || (WideCells(i) == 2); 2462d522f475Smrg} 2463d522f475Smrg 2464d522f475Smrg#define isWideCell(row, col) iswide((int)XTERM_CELL(row, col)) 2465d522f475Smrg#endif 2466d522f475Smrg 2467d522f475Smrgstatic void 2468d522f475SmrgPointToCELL(TScreen * screen, 2469d522f475Smrg int y, 2470d522f475Smrg int x, 2471d522f475Smrg CELL * cell) 2472d522f475Smrg/* Convert pixel coordinates to character coordinates. 2473d522f475Smrg Rows are clipped between firstValidRow and lastValidRow. 2474d522f475Smrg Columns are clipped between to be 0 or greater, but are not clipped to some 2475d522f475Smrg maximum value. */ 2476d522f475Smrg{ 2477d522f475Smrg cell->row = (y - screen->border) / FontHeight(screen); 2478d522f475Smrg if (cell->row < screen->firstValidRow) 2479d522f475Smrg cell->row = screen->firstValidRow; 2480d522f475Smrg else if (cell->row > screen->lastValidRow) 2481d522f475Smrg cell->row = screen->lastValidRow; 2482d522f475Smrg cell->col = (x - OriginX(screen)) / FontWidth(screen); 2483d522f475Smrg if (cell->col < 0) 2484d522f475Smrg cell->col = 0; 2485d522f475Smrg else if (cell->col > MaxCols(screen)) { 2486d522f475Smrg cell->col = MaxCols(screen); 2487d522f475Smrg } 2488d522f475Smrg#if OPT_WIDE_CHARS 2489d522f475Smrg /* 2490d522f475Smrg * If we got a click on the right half of a doublewidth character, 2491d522f475Smrg * pretend it happened on the left half. 2492d522f475Smrg */ 2493d522f475Smrg if (cell->col > 0 2494d522f475Smrg && isWideCell(cell->row, cell->col - 1) 2495d522f475Smrg && (XTERM_CELL(cell->row, cell->col) == HIDDEN_CHAR)) { 2496d522f475Smrg cell->col -= 1; 2497d522f475Smrg } 2498d522f475Smrg#endif 2499d522f475Smrg} 2500d522f475Smrg 2501d522f475Smrg/* 2502d522f475Smrg * Find the last column at which text was drawn on the given row. 2503d522f475Smrg */ 2504d522f475Smrgstatic int 2505956cc18dSsnjLastTextCol(TScreen * screen, LineData * ld, int row) 2506d522f475Smrg{ 250720d2c4d2Smrg int i = -1; 2508d522f475Smrg Char *ch; 2509d522f475Smrg 251020d2c4d2Smrg if (ld != 0) { 251120d2c4d2Smrg if (okScrnRow(screen, row)) { 251220d2c4d2Smrg for (i = screen->max_col, 251320d2c4d2Smrg ch = ld->attribs + i; 251420d2c4d2Smrg i >= 0 && !(*ch & CHARDRAWN); 251520d2c4d2Smrg ch--, i--) { 251620d2c4d2Smrg ; 251720d2c4d2Smrg } 2518d522f475Smrg#if OPT_DEC_CHRSET 251920d2c4d2Smrg if (CSET_DOUBLE(GetLineDblCS(ld))) { 252020d2c4d2Smrg i *= 2; 252120d2c4d2Smrg } 2522d522f475Smrg#endif 252320d2c4d2Smrg } 2524d522f475Smrg } 2525d522f475Smrg return (i); 2526d522f475Smrg} 2527d522f475Smrg 2528d522f475Smrg#if !OPT_WIDE_CHARS 2529d522f475Smrg/* 2530d522f475Smrg** double click table for cut and paste in 8 bits 2531d522f475Smrg** 2532d522f475Smrg** This table is divided in four parts : 2533d522f475Smrg** 2534d522f475Smrg** - control characters [0,0x1f] U [0x80,0x9f] 2535d522f475Smrg** - separators [0x20,0x3f] U [0xa0,0xb9] 2536d522f475Smrg** - binding characters [0x40,0x7f] U [0xc0,0xff] 2537d522f475Smrg** - exceptions 2538d522f475Smrg*/ 2539d522f475Smrg/* *INDENT-OFF* */ 2540d522f475Smrgstatic int charClass[256] = 2541d522f475Smrg{ 2542d522f475Smrg/* NUL SOH STX ETX EOT ENQ ACK BEL */ 2543d522f475Smrg 32, 1, 1, 1, 1, 1, 1, 1, 2544d522f475Smrg/* BS HT NL VT NP CR SO SI */ 2545d522f475Smrg 1, 32, 1, 1, 1, 1, 1, 1, 2546d522f475Smrg/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 2547d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2548d522f475Smrg/* CAN EM SUB ESC FS GS RS US */ 2549d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2550d522f475Smrg/* SP ! " # $ % & ' */ 2551d522f475Smrg 32, 33, 34, 35, 36, 37, 38, 39, 2552d522f475Smrg/* ( ) * + , - . / */ 2553d522f475Smrg 40, 41, 42, 43, 44, 45, 46, 47, 2554d522f475Smrg/* 0 1 2 3 4 5 6 7 */ 2555d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2556d522f475Smrg/* 8 9 : ; < = > ? */ 2557d522f475Smrg 48, 48, 58, 59, 60, 61, 62, 63, 2558d522f475Smrg/* @ A B C D E F G */ 2559d522f475Smrg 64, 48, 48, 48, 48, 48, 48, 48, 2560d522f475Smrg/* H I J K L M N O */ 2561d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2562d522f475Smrg/* P Q R S T U V W */ 2563d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2564d522f475Smrg/* X Y Z [ \ ] ^ _ */ 2565d522f475Smrg 48, 48, 48, 91, 92, 93, 94, 48, 2566d522f475Smrg/* ` a b c d e f g */ 2567d522f475Smrg 96, 48, 48, 48, 48, 48, 48, 48, 2568d522f475Smrg/* h i j k l m n o */ 2569d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2570d522f475Smrg/* p q r s t u v w */ 2571d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2572d522f475Smrg/* x y z { | } ~ DEL */ 2573d522f475Smrg 48, 48, 48, 123, 124, 125, 126, 1, 2574d522f475Smrg/* x80 x81 x82 x83 IND NEL SSA ESA */ 2575d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2576d522f475Smrg/* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 2577d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2578d522f475Smrg/* DCS PU1 PU2 STS CCH MW SPA EPA */ 2579d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2580d522f475Smrg/* x98 x99 x9A CSI ST OSC PM APC */ 2581d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2582d522f475Smrg/* - i c/ L ox Y- | So */ 2583d522f475Smrg 160, 161, 162, 163, 164, 165, 166, 167, 2584d522f475Smrg/* .. c0 ip << _ R0 - */ 2585d522f475Smrg 168, 169, 170, 171, 172, 173, 174, 175, 2586d522f475Smrg/* o +- 2 3 ' u q| . */ 2587d522f475Smrg 176, 177, 178, 179, 180, 181, 182, 183, 2588d522f475Smrg/* , 1 2 >> 1/4 1/2 3/4 ? */ 2589d522f475Smrg 184, 185, 186, 187, 188, 189, 190, 191, 2590d522f475Smrg/* A` A' A^ A~ A: Ao AE C, */ 2591d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2592d522f475Smrg/* E` E' E^ E: I` I' I^ I: */ 2593d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2594d522f475Smrg/* D- N~ O` O' O^ O~ O: X */ 2595d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 215, 2596d522f475Smrg/* O/ U` U' U^ U: Y' P B */ 2597d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2598d522f475Smrg/* a` a' a^ a~ a: ao ae c, */ 2599d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2600d522f475Smrg/* e` e' e^ e: i` i' i^ i: */ 2601d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2602d522f475Smrg/* d n~ o` o' o^ o~ o: -: */ 2603d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 247, 2604d522f475Smrg/* o/ u` u' u^ u: y' P y: */ 2605d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48}; 2606d522f475Smrg/* *INDENT-ON* */ 2607d522f475Smrg 2608d522f475Smrgint 2609d522f475SmrgSetCharacterClassRange(int low, /* in range of [0..255] */ 2610d522f475Smrg int high, 2611d522f475Smrg int value) /* arbitrary */ 2612d522f475Smrg{ 2613d522f475Smrg 2614d522f475Smrg if (low < 0 || high > 255 || high < low) 2615d522f475Smrg return (-1); 2616d522f475Smrg 2617d522f475Smrg for (; low <= high; low++) 2618d522f475Smrg charClass[low] = value; 2619d522f475Smrg 2620d522f475Smrg return (0); 2621d522f475Smrg} 2622d522f475Smrg#endif 2623d522f475Smrg 2624d522f475Smrgstatic int 2625956cc18dSsnjclass_of(LineData * ld, CELL * cell) 2626d522f475Smrg{ 2627d522f475Smrg CELL temp = *cell; 2628d522f475Smrg 2629d522f475Smrg#if OPT_DEC_CHRSET 2630956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 2631d522f475Smrg temp.col /= 2; 2632d522f475Smrg } 2633d522f475Smrg#endif 2634d522f475Smrg 263520d2c4d2Smrg assert(temp.col < ld->lineSize); 2636956cc18dSsnj return CharacterClass((int) (ld->charData[temp.col])); 2637d522f475Smrg} 2638956cc18dSsnj 2639956cc18dSsnj#if OPT_WIDE_CHARS 2640956cc18dSsnj#define CClassSelects(name, cclass) \ 2641956cc18dSsnj (CClassOf(name) == cclass \ 2642956cc18dSsnj || XTERM_CELL(screen->name.row, screen->name.col) == HIDDEN_CHAR) 2643d522f475Smrg#else 2644956cc18dSsnj#define CClassSelects(name, cclass) \ 2645956cc18dSsnj (class_of(ld.name, &((screen->name))) == cclass) 2646d522f475Smrg#endif 2647d522f475Smrg 2648956cc18dSsnj#define CClassOf(name) class_of(ld.name, &((screen->name))) 2649956cc18dSsnj 2650d522f475Smrg/* 2651d522f475Smrg * If the given column is past the end of text on the given row, bump to the 2652d522f475Smrg * beginning of the next line. 2653d522f475Smrg */ 2654d522f475Smrgstatic Boolean 2655d522f475SmrgokPosition(TScreen * screen, 2656956cc18dSsnj LineData ** ld, 2657d522f475Smrg CELL * cell) 2658d522f475Smrg{ 265920d2c4d2Smrg Boolean result = True; 266020d2c4d2Smrg 266120d2c4d2Smrg if (cell->row > screen->max_row) { 266220d2c4d2Smrg result = False; 266320d2c4d2Smrg } else if (cell->col > (LastTextCol(screen, *ld, cell->row) + 1)) { 266420d2c4d2Smrg if (cell->row < screen->max_row) { 266520d2c4d2Smrg cell->col = 0; 266620d2c4d2Smrg *ld = GET_LINEDATA(screen, ++cell->row); 266720d2c4d2Smrg result = False; 266820d2c4d2Smrg } 2669d522f475Smrg } 267020d2c4d2Smrg return result; 2671d522f475Smrg} 2672d522f475Smrg 2673d522f475Smrgstatic void 2674956cc18dSsnjtrimLastLine(TScreen * screen, 2675956cc18dSsnj LineData ** ld, 2676956cc18dSsnj CELL * last) 2677d522f475Smrg{ 267820d2c4d2Smrg if (screen->cutNewline && last->row < screen->max_row) { 2679d522f475Smrg last->col = 0; 2680956cc18dSsnj *ld = GET_LINEDATA(screen, ++last->row); 2681d522f475Smrg } else { 2682956cc18dSsnj last->col = LastTextCol(screen, *ld, last->row) + 1; 2683d522f475Smrg } 2684d522f475Smrg} 2685d522f475Smrg 2686d522f475Smrg#if OPT_SELECT_REGEX 2687d522f475Smrg/* 2688d522f475Smrg * Returns the first row of a wrapped line. 2689d522f475Smrg */ 2690d522f475Smrgstatic int 2691d522f475SmrgfirstRowOfLine(TScreen * screen, int row, Bool visible) 2692d522f475Smrg{ 2693956cc18dSsnj LineData *ld = 0; 2694d522f475Smrg int limit = visible ? 0 : -screen->savedlines; 2695d522f475Smrg 2696d522f475Smrg while (row > limit && 2697956cc18dSsnj (ld = GET_LINEDATA(screen, row - 1)) != 0 && 2698956cc18dSsnj LineTstWrapped(ld)) { 2699d522f475Smrg --row; 2700956cc18dSsnj } 2701d522f475Smrg return row; 2702d522f475Smrg} 2703d522f475Smrg 2704d522f475Smrg/* 2705d522f475Smrg * Returns the last row of a wrapped line. 2706d522f475Smrg */ 2707d522f475Smrgstatic int 2708d522f475SmrglastRowOfLine(TScreen * screen, int row) 2709d522f475Smrg{ 2710956cc18dSsnj LineData *ld; 2711956cc18dSsnj 2712d522f475Smrg while (row < screen->max_row && 2713956cc18dSsnj (ld = GET_LINEDATA(screen, row)) != 0 && 2714956cc18dSsnj LineTstWrapped(ld)) { 2715d522f475Smrg ++row; 2716956cc18dSsnj } 2717d522f475Smrg return row; 2718d522f475Smrg} 2719d522f475Smrg 2720d522f475Smrg/* 2721d522f475Smrg * Returns the number of cells on the range of rows. 2722d522f475Smrg */ 2723d522f475Smrgstatic unsigned 2724d522f475SmrglengthOfLines(TScreen * screen, int firstRow, int lastRow) 2725d522f475Smrg{ 2726d522f475Smrg unsigned length = 0; 2727d522f475Smrg int n; 2728d522f475Smrg 2729d522f475Smrg for (n = firstRow; n <= lastRow; ++n) { 2730956cc18dSsnj LineData *ld = GET_LINEDATA(screen, n); 2731956cc18dSsnj int value = LastTextCol(screen, ld, n); 2732d522f475Smrg if (value >= 0) 27332eaa94a1Schristos length += (unsigned) (value + 1); 2734d522f475Smrg } 2735d522f475Smrg return length; 2736d522f475Smrg} 2737d522f475Smrg 2738d522f475Smrg/* 2739d522f475Smrg * Make a copy of the wrapped-line which corresponds to the given row as a 2740d522f475Smrg * string of bytes. Construct an index for the columns from the beginning of 2741d522f475Smrg * the line. 2742d522f475Smrg */ 2743d522f475Smrgstatic char * 2744d522f475Smrgmake_indexed_text(TScreen * screen, int row, unsigned length, int *indexed) 2745d522f475Smrg{ 2746d522f475Smrg Char *result = 0; 274720d2c4d2Smrg size_t need = (length + 1); 2748d522f475Smrg 2749d522f475Smrg /* 2750d522f475Smrg * Get a quick upper bound to the number of bytes needed, if the whole 2751d522f475Smrg * string were UTF-8. 2752d522f475Smrg */ 2753d522f475Smrg if_OPT_WIDE_CHARS(screen, { 2754956cc18dSsnj need *= ((screen->lineExtra + 1) * 6); 2755d522f475Smrg }); 2756d522f475Smrg 2757d522f475Smrg if ((result = TypeCallocN(Char, need + 1)) != 0) { 2758956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 2759d522f475Smrg unsigned used = 0; 2760d522f475Smrg Char *last = result; 2761d522f475Smrg 2762d522f475Smrg do { 2763d522f475Smrg int col = 0; 2764956cc18dSsnj int limit = LastTextCol(screen, ld, row); 2765d522f475Smrg 2766d522f475Smrg while (col <= limit) { 2767d522f475Smrg Char *next = last; 2768956cc18dSsnj unsigned data = ld->charData[col]; 2769d522f475Smrg 277020d2c4d2Smrg assert(col < ld->lineSize); 2771d522f475Smrg /* some internal points may not be drawn */ 2772d522f475Smrg if (data == 0) 2773d522f475Smrg data = ' '; 2774d522f475Smrg 2775d522f475Smrg if_WIDE_OR_NARROW(screen, { 2776d522f475Smrg next = convertToUTF8(last, data); 2777d522f475Smrg } 2778d522f475Smrg , { 2779d522f475Smrg *next++ = CharOf(data); 2780d522f475Smrg }); 2781d522f475Smrg 2782d522f475Smrg if_OPT_WIDE_CHARS(screen, { 2783956cc18dSsnj size_t off; 2784956cc18dSsnj for_each_combData(off, ld) { 2785956cc18dSsnj data = ld->combData[off][col]; 2786956cc18dSsnj if (data == 0) 2787d522f475Smrg break; 2788d522f475Smrg next = convertToUTF8(next, data); 2789d522f475Smrg } 2790d522f475Smrg }); 2791d522f475Smrg 279220d2c4d2Smrg indexed[used] = (int) (last - result); 2793d522f475Smrg *next = 0; 2794d522f475Smrg /* TRACE(("index[%d.%d] %d:%s\n", row, used, indexed[used], last)); */ 2795d522f475Smrg last = next; 2796d522f475Smrg ++used; 2797d522f475Smrg ++col; 279820d2c4d2Smrg indexed[used] = (int) (next - result); 2799d522f475Smrg } 2800d522f475Smrg } while (used < length && 2801956cc18dSsnj LineTstWrapped(ld) && 2802956cc18dSsnj (ld = GET_LINEDATA(screen, ++row)) != 0 && 2803956cc18dSsnj row < screen->max_row); 2804d522f475Smrg } 2805d522f475Smrg /* TRACE(("result:%s\n", result)); */ 2806d522f475Smrg return (char *) result; 2807d522f475Smrg} 2808d522f475Smrg 2809d522f475Smrg/* 2810d522f475Smrg * Find the column given an offset into the character string by using the 2811d522f475Smrg * index constructed in make_indexed_text(). 2812d522f475Smrg */ 2813d522f475Smrgstatic int 2814d522f475SmrgindexToCol(int *indexed, int len, int off) 2815d522f475Smrg{ 2816d522f475Smrg int col = 0; 2817d522f475Smrg while (indexed[col] < len) { 2818d522f475Smrg if (indexed[col] >= off) 2819d522f475Smrg break; 2820d522f475Smrg ++col; 2821d522f475Smrg } 2822d522f475Smrg return col; 2823d522f475Smrg} 2824d522f475Smrg 2825d522f475Smrg/* 2826d522f475Smrg * Given a row number, and a column offset from that (which may be wrapped), 2827d522f475Smrg * set the cell to the actual row/column values. 2828d522f475Smrg */ 2829d522f475Smrgstatic void 2830d522f475SmrgcolumnToCell(TScreen * screen, int row, int col, CELL * cell) 2831d522f475Smrg{ 2832d522f475Smrg while (row < screen->max_row) { 2833956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 2834956cc18dSsnj int last = LastTextCol(screen, ld, row); 2835d522f475Smrg 2836d522f475Smrg /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */ 2837d522f475Smrg if (col <= last) { 2838d522f475Smrg break; 2839d522f475Smrg } 2840d522f475Smrg /* 2841d522f475Smrg * Stop if the current row does not wrap (does not continue the current 2842d522f475Smrg * line). 2843d522f475Smrg */ 2844956cc18dSsnj if (!LineTstWrapped(ld)) { 2845d522f475Smrg col = last + 1; 2846d522f475Smrg break; 2847d522f475Smrg } 2848d522f475Smrg col -= (last + 1); 2849d522f475Smrg ++row; 2850d522f475Smrg } 2851d522f475Smrg if (col < 0) 2852d522f475Smrg col = 0; 2853d522f475Smrg cell->row = row; 2854d522f475Smrg cell->col = col; 2855d522f475Smrg} 2856d522f475Smrg 2857d522f475Smrg/* 2858d522f475Smrg * Given a cell, find the corresponding column offset. 2859d522f475Smrg */ 2860d522f475Smrgstatic int 2861d522f475SmrgcellToColumn(TScreen * screen, CELL * cell) 2862d522f475Smrg{ 2863956cc18dSsnj LineData *ld = 0; 2864d522f475Smrg int col = cell->col; 2865d522f475Smrg int row = firstRowOfLine(screen, cell->row, False); 2866d522f475Smrg while (row < cell->row) { 2867956cc18dSsnj ld = GET_LINEDATA(screen, row); 2868956cc18dSsnj col += LastTextCol(screen, ld, row++); 2869d522f475Smrg } 2870956cc18dSsnj#if OPT_DEC_CHRSET 2871956cc18dSsnj if (ld == 0) 2872956cc18dSsnj ld = GET_LINEDATA(screen, row); 2873956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 2874956cc18dSsnj col /= 2; 2875956cc18dSsnj#endif 2876d522f475Smrg return col; 2877d522f475Smrg} 2878d522f475Smrg 2879d522f475Smrgstatic void 2880d522f475Smrgdo_select_regex(TScreen * screen, CELL * startc, CELL * endc) 2881d522f475Smrg{ 2882956cc18dSsnj LineData *ld = GET_LINEDATA(screen, startc->row); 2883d522f475Smrg int inx = ((screen->numberOfClicks - 1) % screen->maxClicks); 2884d522f475Smrg char *expr = screen->selectExpr[inx]; 2885d522f475Smrg regex_t preg; 2886d522f475Smrg regmatch_t match; 2887d522f475Smrg char *search; 2888d522f475Smrg int *indexed; 2889d522f475Smrg 2890d522f475Smrg TRACE(("Select_REGEX:%s\n", NonNull(expr))); 2891956cc18dSsnj if (okPosition(screen, &ld, startc) && expr != 0) { 2892d522f475Smrg if (regcomp(&preg, expr, REG_EXTENDED) == 0) { 2893d522f475Smrg int firstRow = firstRowOfLine(screen, startc->row, True); 2894d522f475Smrg int lastRow = lastRowOfLine(screen, firstRow); 2895d522f475Smrg unsigned size = lengthOfLines(screen, firstRow, lastRow); 2896d522f475Smrg int actual = cellToColumn(screen, startc); 2897d522f475Smrg 2898d522f475Smrg TRACE(("regcomp ok rows %d..%d bytes %d\n", 2899d522f475Smrg firstRow, lastRow, size)); 2900d522f475Smrg 2901d522f475Smrg if ((indexed = TypeCallocN(int, size + 1)) != 0) { 2902d522f475Smrg if ((search = make_indexed_text(screen, 2903d522f475Smrg firstRow, 2904d522f475Smrg size, 2905d522f475Smrg indexed)) != 0) { 29062eaa94a1Schristos int len = (int) strlen(search); 2907d522f475Smrg int col; 2908d522f475Smrg int best_col = -1; 2909d522f475Smrg int best_len = -1; 2910d522f475Smrg 2911d522f475Smrg for (col = 0; indexed[col] < len; ++col) { 2912d522f475Smrg if (regexec(&preg, 2913d522f475Smrg search + indexed[col], 291420d2c4d2Smrg (size_t) 1, &match, 0) == 0) { 2915d522f475Smrg int start_inx = match.rm_so + indexed[col]; 2916d522f475Smrg int finis_inx = match.rm_eo + indexed[col]; 2917d522f475Smrg int start_col = indexToCol(indexed, len, start_inx); 2918d522f475Smrg int finis_col = indexToCol(indexed, len, finis_inx); 2919d522f475Smrg 2920d522f475Smrg if (start_col <= actual && 2921d522f475Smrg actual < finis_col) { 2922d522f475Smrg int test = finis_col - start_col; 2923d522f475Smrg if (best_len < test) { 2924d522f475Smrg best_len = test; 2925d522f475Smrg best_col = start_col; 2926d522f475Smrg TRACE(("match column %d len %d\n", 2927d522f475Smrg best_col, 2928d522f475Smrg best_len)); 2929d522f475Smrg } 2930d522f475Smrg } 2931d522f475Smrg } 2932d522f475Smrg } 2933d522f475Smrg if (best_col >= 0) { 2934d522f475Smrg int best_nxt = best_col + best_len; 2935d522f475Smrg columnToCell(screen, firstRow, best_col, startc); 2936d522f475Smrg columnToCell(screen, firstRow, best_nxt, endc); 2937d522f475Smrg TRACE(("search::%s\n", search)); 2938d522f475Smrg TRACE(("indexed:%d..%d -> %d..%d\n", 2939d522f475Smrg best_col, best_nxt, 2940d522f475Smrg indexed[best_col], 2941d522f475Smrg indexed[best_nxt])); 2942d522f475Smrg TRACE(("matched:%d:%s\n", 2943d522f475Smrg indexed[best_nxt] + 1 - 2944d522f475Smrg indexed[best_col], 2945956cc18dSsnj visibleChars((Char *) (search + indexed[best_col]), 2946d522f475Smrg (unsigned) (indexed[best_nxt] + 2947d522f475Smrg 1 - 2948d522f475Smrg indexed[best_col])))); 2949d522f475Smrg } 2950d522f475Smrg free(search); 2951d522f475Smrg } 2952d522f475Smrg free(indexed); 2953956cc18dSsnj#if OPT_DEC_CHRSET 2954956cc18dSsnj if ((ld = GET_LINEDATA(screen, startc->row)) != 0) { 2955956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 2956956cc18dSsnj startc->col *= 2; 2957956cc18dSsnj } 2958956cc18dSsnj if ((ld = GET_LINEDATA(screen, endc->row)) != 0) { 2959956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) 2960956cc18dSsnj endc->col *= 2; 2961956cc18dSsnj } 2962956cc18dSsnj#endif 2963d522f475Smrg } 2964d522f475Smrg regfree(&preg); 2965d522f475Smrg } 2966d522f475Smrg } 2967d522f475Smrg} 2968d522f475Smrg#endif /* OPT_SELECT_REGEX */ 2969d522f475Smrg 2970956cc18dSsnj#define InitRow(name) \ 2971956cc18dSsnj ld.name = GET_LINEDATA(screen, screen->name.row) 2972956cc18dSsnj 2973956cc18dSsnj#define NextRow(name) \ 2974956cc18dSsnj ld.name = GET_LINEDATA(screen, ++screen->name.row) 2975956cc18dSsnj 2976956cc18dSsnj#define PrevRow(name) \ 2977956cc18dSsnj ld.name = GET_LINEDATA(screen, --screen->name.row) 2978956cc18dSsnj 297920d2c4d2Smrg#define MoreRows(name) \ 298020d2c4d2Smrg (screen->name.row < screen->max_row) 298120d2c4d2Smrg 2982956cc18dSsnj#define isPrevWrapped(name) \ 2983956cc18dSsnj (screen->name.row > 0 \ 2984956cc18dSsnj && (ltmp = GET_LINEDATA(screen, screen->name.row - 1)) != 0 \ 2985956cc18dSsnj && LineTstWrapped(ltmp)) 2986956cc18dSsnj 2987d522f475Smrg/* 2988d522f475Smrg * sets startSel endSel 2989d522f475Smrg * ensuring that they have legal values 2990d522f475Smrg */ 2991d522f475Smrgstatic void 2992d522f475SmrgComputeSelect(XtermWidget xw, 2993d522f475Smrg CELL * startc, 2994d522f475Smrg CELL * endc, 2995d522f475Smrg Bool extend) 2996d522f475Smrg{ 2997956cc18dSsnj TScreen *screen = TScreenOf(xw); 2998956cc18dSsnj 2999d522f475Smrg int length; 3000d522f475Smrg int cclass; 3001d522f475Smrg CELL first = *startc; 3002d522f475Smrg CELL last = *endc; 3003956cc18dSsnj Boolean ignored = False; 3004956cc18dSsnj 3005956cc18dSsnj struct { 3006956cc18dSsnj LineData *startSel; 3007956cc18dSsnj LineData *endSel; 3008956cc18dSsnj } ld; 3009956cc18dSsnj LineData *ltmp; 3010d522f475Smrg 3011d522f475Smrg TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n", 3012d522f475Smrg first.row, first.col, 3013d522f475Smrg last.row, last.col, 3014d522f475Smrg extend ? "" : "no")); 3015d522f475Smrg 3016d522f475Smrg#if OPT_WIDE_CHARS 3017d522f475Smrg if (first.col > 1 3018d522f475Smrg && isWideCell(first.row, first.col - 1) 3019d522f475Smrg && XTERM_CELL(first.row, first.col - 0) == HIDDEN_CHAR) { 302020d2c4d2Smrg TRACE(("Adjusting start. Changing downwards from %i.\n", first.col)); 3021d522f475Smrg first.col -= 1; 3022d522f475Smrg if (last.col == (first.col + 1)) 3023d522f475Smrg last.col--; 3024d522f475Smrg } 3025d522f475Smrg 3026d522f475Smrg if (last.col > 1 3027d522f475Smrg && isWideCell(last.row, last.col - 1) 3028d522f475Smrg && XTERM_CELL(last.row, last.col) == HIDDEN_CHAR) { 3029d522f475Smrg last.col += 1; 3030d522f475Smrg } 3031d522f475Smrg#endif 3032d522f475Smrg 3033d522f475Smrg if (Coordinate(screen, &first) <= Coordinate(screen, &last)) { 3034d522f475Smrg screen->startSel = screen->startRaw = first; 3035d522f475Smrg screen->endSel = screen->endRaw = last; 3036d522f475Smrg } else { /* Swap them */ 3037d522f475Smrg screen->startSel = screen->startRaw = last; 3038d522f475Smrg screen->endSel = screen->endRaw = first; 3039d522f475Smrg } 3040d522f475Smrg 3041956cc18dSsnj InitRow(startSel); 3042956cc18dSsnj InitRow(endSel); 3043956cc18dSsnj 3044d522f475Smrg switch (screen->selectUnit) { 3045d522f475Smrg case Select_CHAR: 3046956cc18dSsnj (void) okPosition(screen, &(ld.startSel), &(screen->startSel)); 3047956cc18dSsnj (void) okPosition(screen, &(ld.endSel), &(screen->endSel)); 3048d522f475Smrg break; 3049d522f475Smrg 3050d522f475Smrg case Select_WORD: 3051d522f475Smrg TRACE(("Select_WORD\n")); 3052956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 3053956cc18dSsnj cclass = CClassOf(startSel); 3054d522f475Smrg do { 3055d522f475Smrg --screen->startSel.col; 3056956cc18dSsnj if (screen->startSel.col < 0 3057956cc18dSsnj && isPrevWrapped(startSel)) { 3058956cc18dSsnj PrevRow(startSel); 3059956cc18dSsnj screen->startSel.col = LastTextCol(screen, ld.startSel, screen->startSel.row); 3060d522f475Smrg } 3061d522f475Smrg } while (screen->startSel.col >= 0 3062956cc18dSsnj && CClassSelects(startSel, cclass)); 3063d522f475Smrg ++screen->startSel.col; 3064d522f475Smrg } 3065d522f475Smrg#if OPT_WIDE_CHARS 3066d522f475Smrg if (screen->startSel.col 3067d522f475Smrg && XTERM_CELL(screen->startSel.row, 3068d522f475Smrg screen->startSel.col) == HIDDEN_CHAR) 3069d522f475Smrg screen->startSel.col++; 3070d522f475Smrg#endif 3071d522f475Smrg 3072956cc18dSsnj if (okPosition(screen, &(ld.endSel), &(screen->endSel))) { 3073956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 3074956cc18dSsnj cclass = CClassOf(endSel); 3075d522f475Smrg do { 3076d522f475Smrg ++screen->endSel.col; 3077d522f475Smrg if (screen->endSel.col > length 3078956cc18dSsnj && LineTstWrapped(ld.endSel)) { 307920d2c4d2Smrg if (!MoreRows(endSel)) 308020d2c4d2Smrg break; 3081d522f475Smrg screen->endSel.col = 0; 3082956cc18dSsnj NextRow(endSel); 3083956cc18dSsnj length = LastTextCol(screen, ld.endSel, screen->endSel.row); 3084d522f475Smrg } 3085d522f475Smrg } while (screen->endSel.col <= length 3086956cc18dSsnj && CClassSelects(endSel, cclass)); 3087d522f475Smrg /* Word-select selects if pointing to any char in "word", 3088d522f475Smrg * especially note that it includes the last character in a word. 3089d522f475Smrg * So we do no --endSel.col and do special eol handling. 3090d522f475Smrg */ 309120d2c4d2Smrg if (screen->endSel.col > length + 1 309220d2c4d2Smrg && MoreRows(endSel)) { 3093d522f475Smrg screen->endSel.col = 0; 3094956cc18dSsnj NextRow(endSel); 3095d522f475Smrg } 3096d522f475Smrg } 3097d522f475Smrg#if OPT_WIDE_CHARS 3098d522f475Smrg if (screen->endSel.col 3099d522f475Smrg && XTERM_CELL(screen->endSel.row, 3100d522f475Smrg screen->endSel.col) == HIDDEN_CHAR) 3101d522f475Smrg screen->endSel.col++; 3102d522f475Smrg#endif 3103d522f475Smrg 3104d522f475Smrg screen->saveStartW = screen->startSel; 3105d522f475Smrg break; 3106d522f475Smrg 3107d522f475Smrg case Select_LINE: 3108d522f475Smrg TRACE(("Select_LINE\n")); 310920d2c4d2Smrg while (LineTstWrapped(ld.endSel) 311020d2c4d2Smrg && MoreRows(endSel)) { 3111956cc18dSsnj NextRow(endSel); 3112d522f475Smrg } 3113d522f475Smrg if (screen->cutToBeginningOfLine 3114d522f475Smrg || screen->startSel.row < screen->saveStartW.row) { 3115d522f475Smrg screen->startSel.col = 0; 3116956cc18dSsnj while (isPrevWrapped(startSel)) { 3117956cc18dSsnj PrevRow(startSel); 3118d522f475Smrg } 3119d522f475Smrg } else if (!extend) { 3120d522f475Smrg if ((first.row < screen->saveStartW.row) 3121d522f475Smrg || (isSameRow(&first, &(screen->saveStartW)) 3122d522f475Smrg && first.col < screen->saveStartW.col)) { 3123d522f475Smrg screen->startSel.col = 0; 3124956cc18dSsnj while (isPrevWrapped(startSel)) { 3125956cc18dSsnj PrevRow(startSel); 3126d522f475Smrg } 3127d522f475Smrg } else { 3128d522f475Smrg screen->startSel = screen->saveStartW; 3129d522f475Smrg } 3130d522f475Smrg } 3131956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 3132d522f475Smrg break; 3133d522f475Smrg 3134d522f475Smrg case Select_GROUP: /* paragraph */ 3135d522f475Smrg TRACE(("Select_GROUP\n")); 3136956cc18dSsnj if (okPosition(screen, &(ld.startSel), &(screen->startSel))) { 3137d522f475Smrg /* scan backward for beginning of group */ 3138d522f475Smrg while (screen->startSel.row > 0 && 3139956cc18dSsnj (LastTextCol(screen, ld.startSel, screen->startSel.row - 3140956cc18dSsnj 1) > 0 || 3141956cc18dSsnj isPrevWrapped(startSel))) { 3142956cc18dSsnj PrevRow(startSel); 3143d522f475Smrg } 3144d522f475Smrg screen->startSel.col = 0; 3145d522f475Smrg /* scan forward for end of group */ 314620d2c4d2Smrg while (MoreRows(endSel) && 3147956cc18dSsnj (LastTextCol(screen, ld.endSel, screen->endSel.row + 1) > 3148956cc18dSsnj 0 || 3149956cc18dSsnj LineTstWrapped(ld.endSel))) { 3150956cc18dSsnj NextRow(endSel); 3151d522f475Smrg } 3152956cc18dSsnj trimLastLine(screen, &(ld.endSel), &(screen->endSel)); 3153d522f475Smrg } 3154d522f475Smrg break; 3155d522f475Smrg 3156d522f475Smrg case Select_PAGE: /* everything one can see */ 3157d522f475Smrg TRACE(("Select_PAGE\n")); 3158d522f475Smrg screen->startSel.row = 0; 3159d522f475Smrg screen->startSel.col = 0; 316020d2c4d2Smrg screen->endSel.row = MaxRows(screen); 3161d522f475Smrg screen->endSel.col = 0; 3162d522f475Smrg break; 3163d522f475Smrg 3164d522f475Smrg case Select_ALL: /* counts scrollback if in normal screen */ 3165d522f475Smrg TRACE(("Select_ALL\n")); 3166d522f475Smrg screen->startSel.row = -screen->savedlines; 3167d522f475Smrg screen->startSel.col = 0; 316820d2c4d2Smrg screen->endSel.row = MaxRows(screen); 3169d522f475Smrg screen->endSel.col = 0; 3170d522f475Smrg break; 3171d522f475Smrg 3172d522f475Smrg#if OPT_SELECT_REGEX 3173d522f475Smrg case Select_REGEX: 3174d522f475Smrg do_select_regex(screen, &(screen->startSel), &(screen->endSel)); 3175d522f475Smrg break; 3176d522f475Smrg#endif 3177d522f475Smrg 3178d522f475Smrg case NSELECTUNITS: /* always ignore */ 3179956cc18dSsnj ignored = True; 3180956cc18dSsnj break; 3181d522f475Smrg } 3182d522f475Smrg 3183956cc18dSsnj if (!ignored) { 3184956cc18dSsnj /* check boundaries */ 3185956cc18dSsnj ScrollSelection(screen, 0, False); 3186956cc18dSsnj TrackText(xw, &(screen->startSel), &(screen->endSel)); 3187956cc18dSsnj } 3188d522f475Smrg 3189d522f475Smrg return; 3190d522f475Smrg} 3191d522f475Smrg 3192d522f475Smrg/* Guaranteed (first.row, first.col) <= (last.row, last.col) */ 3193d522f475Smrgstatic void 3194d522f475SmrgTrackText(XtermWidget xw, 3195d522f475Smrg const CELL * firstp, 3196d522f475Smrg const CELL * lastp) 3197d522f475Smrg{ 3198956cc18dSsnj TScreen *screen = TScreenOf(xw); 3199d522f475Smrg int from, to; 3200d522f475Smrg CELL old_start, old_end; 3201d522f475Smrg CELL first = *firstp; 3202d522f475Smrg CELL last = *lastp; 3203d522f475Smrg 3204d522f475Smrg TRACE(("TrackText(first=%d,%d, last=%d,%d)\n", 3205d522f475Smrg first.row, first.col, last.row, last.col)); 3206d522f475Smrg 3207d522f475Smrg old_start = screen->startH; 3208d522f475Smrg old_end = screen->endH; 3209d522f475Smrg if (isSameCELL(&first, &old_start) && 3210d522f475Smrg isSameCELL(&last, &old_end)) 3211d522f475Smrg return; 3212d522f475Smrg screen->startH = first; 3213d522f475Smrg screen->endH = last; 3214d522f475Smrg from = Coordinate(screen, &screen->startH); 3215d522f475Smrg to = Coordinate(screen, &screen->endH); 3216d522f475Smrg if (to <= screen->startHCoord || from > screen->endHCoord) { 3217d522f475Smrg /* No overlap whatsoever between old and new hilite */ 3218d522f475Smrg ReHiliteText(xw, &old_start, &old_end); 3219d522f475Smrg ReHiliteText(xw, &first, &last); 3220d522f475Smrg } else { 3221d522f475Smrg if (from < screen->startHCoord) { 3222d522f475Smrg /* Extend left end */ 3223d522f475Smrg ReHiliteText(xw, &first, &old_start); 3224d522f475Smrg } else if (from > screen->startHCoord) { 3225d522f475Smrg /* Shorten left end */ 3226d522f475Smrg ReHiliteText(xw, &old_start, &first); 3227d522f475Smrg } 3228d522f475Smrg if (to > screen->endHCoord) { 3229d522f475Smrg /* Extend right end */ 3230d522f475Smrg ReHiliteText(xw, &old_end, &last); 3231d522f475Smrg } else if (to < screen->endHCoord) { 3232d522f475Smrg /* Shorten right end */ 3233d522f475Smrg ReHiliteText(xw, &last, &old_end); 3234d522f475Smrg } 3235d522f475Smrg } 3236d522f475Smrg screen->startHCoord = from; 3237d522f475Smrg screen->endHCoord = to; 3238d522f475Smrg} 3239d522f475Smrg 3240d522f475Smrg/* Guaranteed that (first->row, first->col) <= (last->row, last->col) */ 3241d522f475Smrgstatic void 3242d522f475SmrgReHiliteText(XtermWidget xw, 3243d522f475Smrg CELL * firstp, 3244d522f475Smrg CELL * lastp) 3245d522f475Smrg{ 3246956cc18dSsnj TScreen *screen = TScreenOf(xw); 3247d522f475Smrg int i; 3248d522f475Smrg CELL first = *firstp; 3249d522f475Smrg CELL last = *lastp; 3250d522f475Smrg 3251d522f475Smrg TRACE(("ReHiliteText from %d.%d to %d.%d\n", 3252d522f475Smrg first.row, first.col, last.row, last.col)); 3253d522f475Smrg 3254d522f475Smrg if (first.row < 0) 3255d522f475Smrg first.row = first.col = 0; 3256d522f475Smrg else if (first.row > screen->max_row) 3257d522f475Smrg return; /* nothing to do, since last.row >= first.row */ 3258d522f475Smrg 3259d522f475Smrg if (last.row < 0) 3260d522f475Smrg return; /* nothing to do, since first.row <= last.row */ 3261d522f475Smrg else if (last.row > screen->max_row) { 3262d522f475Smrg last.row = screen->max_row; 3263d522f475Smrg last.col = MaxCols(screen); 3264d522f475Smrg } 3265d522f475Smrg if (isSameCELL(&first, &last)) 3266d522f475Smrg return; 3267d522f475Smrg 3268d522f475Smrg if (!isSameRow(&first, &last)) { /* do multiple rows */ 3269d522f475Smrg if ((i = screen->max_col - first.col + 1) > 0) { /* first row */ 3270d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, i, True); 3271d522f475Smrg } 3272d522f475Smrg if ((i = last.row - first.row - 1) > 0) { /* middle rows */ 3273d522f475Smrg ScrnRefresh(xw, first.row + 1, 0, i, MaxCols(screen), True); 3274d522f475Smrg } 3275d522f475Smrg if (last.col > 0 && last.row <= screen->max_row) { /* last row */ 3276d522f475Smrg ScrnRefresh(xw, last.row, 0, 1, last.col, True); 3277d522f475Smrg } 3278d522f475Smrg } else { /* do single row */ 3279d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, last.col - first.col, True); 3280d522f475Smrg } 3281d522f475Smrg} 3282d522f475Smrg 3283d522f475Smrg/* 3284d522f475Smrg * Guaranteed that (cellc->row, cellc->col) <= (cell->row, cell->col), and that both points are valid 3285d522f475Smrg * (may have cell->row = screen->max_row+1, cell->col = 0). 3286d522f475Smrg */ 3287d522f475Smrgstatic void 3288d522f475SmrgSaltTextAway(XtermWidget xw, 3289d522f475Smrg CELL * cellc, 3290d522f475Smrg CELL * cell, 3291d522f475Smrg String * params, /* selections */ 3292d522f475Smrg Cardinal num_params) 3293d522f475Smrg{ 3294956cc18dSsnj TScreen *screen = TScreenOf(xw); 3295d522f475Smrg int i, j = 0; 3296d522f475Smrg int eol; 3297956cc18dSsnj int tmp; 3298d522f475Smrg Char *line; 3299d522f475Smrg Char *lp; 3300d522f475Smrg CELL first = *cellc; 3301d522f475Smrg CELL last = *cell; 3302d522f475Smrg 3303d522f475Smrg if (isSameRow(&first, &last) && first.col > last.col) { 3304956cc18dSsnj EXCHANGE(first.col, last.col, tmp); 3305d522f475Smrg } 3306d522f475Smrg 3307d522f475Smrg --last.col; 3308d522f475Smrg /* first we need to know how long the string is before we can save it */ 3309d522f475Smrg 3310d522f475Smrg if (isSameRow(&last, &first)) { 3311d522f475Smrg j = Length(screen, first.row, first.col, last.col); 3312d522f475Smrg } else { /* two cases, cut is on same line, cut spans multiple lines */ 3313d522f475Smrg j += Length(screen, first.row, first.col, screen->max_col) + 1; 3314d522f475Smrg for (i = first.row + 1; i < last.row; i++) 3315d522f475Smrg j += Length(screen, i, 0, screen->max_col) + 1; 3316d522f475Smrg if (last.col >= 0) 3317d522f475Smrg j += Length(screen, last.row, 0, last.col); 3318d522f475Smrg } 3319d522f475Smrg 3320d522f475Smrg /* UTF-8 may require more space */ 3321d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3322d522f475Smrg j *= 4; 3323d522f475Smrg }); 3324d522f475Smrg 3325d522f475Smrg /* now get some memory to save it in */ 3326d522f475Smrg 3327d522f475Smrg if (screen->selection_size <= j) { 332820d2c4d2Smrg if ((line = (Char *) malloc((size_t) j + 1)) == 0) 3329d522f475Smrg SysError(ERROR_BMALLOC2); 3330d522f475Smrg XtFree((char *) screen->selection_data); 3331d522f475Smrg screen->selection_data = line; 3332d522f475Smrg screen->selection_size = j + 1; 3333d522f475Smrg } else { 3334d522f475Smrg line = screen->selection_data; 3335d522f475Smrg } 3336d522f475Smrg 3337d522f475Smrg if ((line == 0) 3338d522f475Smrg || (j < 0)) 3339d522f475Smrg return; 3340d522f475Smrg 3341d522f475Smrg line[j] = '\0'; /* make sure it is null terminated */ 3342d522f475Smrg lp = line; /* lp points to where to save the text */ 3343d522f475Smrg if (isSameRow(&last, &first)) { 3344d522f475Smrg lp = SaveText(screen, last.row, first.col, last.col, lp, &eol); 3345d522f475Smrg } else { 3346d522f475Smrg lp = SaveText(screen, first.row, first.col, screen->max_col, lp, &eol); 3347d522f475Smrg if (eol) 3348d522f475Smrg *lp++ = '\n'; /* put in newline at end of line */ 3349d522f475Smrg for (i = first.row + 1; i < last.row; i++) { 3350d522f475Smrg lp = SaveText(screen, i, 0, screen->max_col, lp, &eol); 3351d522f475Smrg if (eol) 3352d522f475Smrg *lp++ = '\n'; 3353d522f475Smrg } 3354d522f475Smrg if (last.col >= 0) 3355d522f475Smrg lp = SaveText(screen, last.row, 0, last.col, lp, &eol); 3356d522f475Smrg } 3357d522f475Smrg *lp = '\0'; /* make sure we have end marked */ 3358d522f475Smrg 3359956cc18dSsnj TRACE(("Salted TEXT:%d:%s\n", (int) (lp - line), 3360956cc18dSsnj visibleChars(line, (unsigned) (lp - line)))); 3361d522f475Smrg 33622eaa94a1Schristos screen->selection_length = (unsigned long) (lp - line); 3363d522f475Smrg _OwnSelection(xw, params, num_params); 3364d522f475Smrg} 3365d522f475Smrg 3366d522f475Smrg#if OPT_PASTE64 3367d522f475Smrgvoid 3368d522f475SmrgClearSelectionBuffer(TScreen * screen) 3369d522f475Smrg{ 3370d522f475Smrg screen->selection_length = 0; 3371d522f475Smrg screen->base64_count = 0; 3372d522f475Smrg} 3373d522f475Smrg 3374d522f475Smrgstatic void 337520d2c4d2SmrgAppendStrToSelectionBuffer(TScreen * screen, Char * text, size_t len) 3376d522f475Smrg{ 3377d522f475Smrg if (len != 0) { 33782eaa94a1Schristos int j = (int) (screen->selection_length + len); /* New length */ 3379d522f475Smrg int k = j + (j >> 2) + 80; /* New size if we grow buffer: grow by ~50% */ 3380d522f475Smrg if (j + 1 >= screen->selection_size) { 3381d522f475Smrg if (!screen->selection_length) { 3382d522f475Smrg /* New buffer */ 3383d522f475Smrg Char *line; 338420d2c4d2Smrg if ((line = (Char *) malloc((size_t) k)) == 0) 3385d522f475Smrg SysError(ERROR_BMALLOC2); 3386d522f475Smrg XtFree((char *) screen->selection_data); 3387d522f475Smrg screen->selection_data = line; 3388d522f475Smrg } else { 3389d522f475Smrg /* Realloc buffer */ 3390d522f475Smrg screen->selection_data = (Char *) 3391d522f475Smrg realloc(screen->selection_data, 339220d2c4d2Smrg (size_t) k); 3393d522f475Smrg if (screen->selection_data == 0) 3394d522f475Smrg SysError(ERROR_BMALLOC2); 3395d522f475Smrg } 3396d522f475Smrg screen->selection_size = k; 3397d522f475Smrg } 339820d2c4d2Smrg if (screen->selection_data != 0) { 339920d2c4d2Smrg memcpy(screen->selection_data + screen->selection_length, text, len); 340020d2c4d2Smrg screen->selection_length += len; 340120d2c4d2Smrg screen->selection_data[screen->selection_length] = 0; 340220d2c4d2Smrg } 3403d522f475Smrg } 3404d522f475Smrg} 3405d522f475Smrg 3406d522f475Smrgvoid 3407d522f475SmrgAppendToSelectionBuffer(TScreen * screen, unsigned c) 3408d522f475Smrg{ 34092eaa94a1Schristos unsigned six; 3410d522f475Smrg Char ch; 3411d522f475Smrg 3412d522f475Smrg /* Decode base64 character */ 3413d522f475Smrg if (c >= 'A' && c <= 'Z') 3414d522f475Smrg six = c - 'A'; 3415d522f475Smrg else if (c >= 'a' && c <= 'z') 3416d522f475Smrg six = c - 'a' + 26; 3417d522f475Smrg else if (c >= '0' && c <= '9') 3418d522f475Smrg six = c - '0' + 52; 3419d522f475Smrg else if (c == '+') 3420d522f475Smrg six = 62; 3421d522f475Smrg else if (c == '/') 3422d522f475Smrg six = 63; 3423d522f475Smrg else 3424d522f475Smrg return; 3425d522f475Smrg 3426d522f475Smrg /* Accumulate bytes */ 3427d522f475Smrg switch (screen->base64_count) { 3428d522f475Smrg case 0: 3429d522f475Smrg screen->base64_accu = six; 3430d522f475Smrg screen->base64_count = 6; 3431d522f475Smrg break; 3432d522f475Smrg 3433d522f475Smrg case 2: 34342eaa94a1Schristos ch = CharOf((screen->base64_accu << 6) + six); 3435d522f475Smrg screen->base64_count = 0; 343620d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3437d522f475Smrg break; 3438d522f475Smrg 3439d522f475Smrg case 4: 34402eaa94a1Schristos ch = CharOf((screen->base64_accu << 4) + (six >> 2)); 3441d522f475Smrg screen->base64_accu = (six & 0x3); 3442d522f475Smrg screen->base64_count = 2; 344320d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3444d522f475Smrg break; 3445d522f475Smrg 3446d522f475Smrg case 6: 34472eaa94a1Schristos ch = CharOf((screen->base64_accu << 2) + (six >> 4)); 3448d522f475Smrg screen->base64_accu = (six & 0xF); 3449d522f475Smrg screen->base64_count = 4; 345020d2c4d2Smrg AppendStrToSelectionBuffer(screen, &ch, (size_t) 1); 3451d522f475Smrg break; 3452d522f475Smrg } 3453d522f475Smrg} 3454d522f475Smrg 3455d522f475Smrgvoid 345620d2c4d2SmrgCompleteSelection(XtermWidget xw, String * args, Cardinal len) 3457d522f475Smrg{ 3458956cc18dSsnj TScreen *screen = TScreenOf(xw); 3459956cc18dSsnj 3460956cc18dSsnj screen->base64_count = 0; 3461956cc18dSsnj screen->base64_accu = 0; 3462d522f475Smrg _OwnSelection(xw, args, len); 3463d522f475Smrg} 3464d522f475Smrg#endif /* OPT_PASTE64 */ 3465d522f475Smrg 3466d522f475Smrgstatic Bool 3467d522f475Smrg_ConvertSelectionHelper(Widget w, 3468d522f475Smrg Atom * type, 3469d522f475Smrg XtPointer *value, 3470d522f475Smrg unsigned long *length, 3471d522f475Smrg int *format, 3472d522f475Smrg int (*conversion_function) (Display *, 3473d522f475Smrg char **, int, 3474d522f475Smrg XICCEncodingStyle, 3475d522f475Smrg XTextProperty *), 3476d522f475Smrg XICCEncodingStyle conversion_style) 3477d522f475Smrg{ 3478956cc18dSsnj XtermWidget xw; 3479956cc18dSsnj 3480956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3481956cc18dSsnj TScreen *screen = TScreenOf(xw); 3482d522f475Smrg Display *dpy = XtDisplay(w); 3483d522f475Smrg XTextProperty textprop; 3484d522f475Smrg char *the_data = (char *) screen->selection_data; 3485d522f475Smrg 3486d522f475Smrg if (conversion_function(dpy, &the_data, 1, 3487d522f475Smrg conversion_style, 3488d522f475Smrg &textprop) >= Success) { 3489d522f475Smrg *value = (XtPointer) textprop.value; 3490d522f475Smrg *length = textprop.nitems; 3491d522f475Smrg *type = textprop.encoding; 3492d522f475Smrg *format = textprop.format; 3493d522f475Smrg return True; 3494d522f475Smrg } 3495d522f475Smrg } 3496d522f475Smrg return False; 3497d522f475Smrg} 3498d522f475Smrg 34992eaa94a1Schristosstatic Boolean 35002eaa94a1SchristosSaveConvertedLength(XtPointer *target, unsigned long source) 35012eaa94a1Schristos{ 35022eaa94a1Schristos Boolean result = False; 35032eaa94a1Schristos 35042eaa94a1Schristos *target = XtMalloc(4); 35052eaa94a1Schristos if (*target != 0) { 35062eaa94a1Schristos result = True; 35072eaa94a1Schristos if (sizeof(unsigned long) == 4) { 35082eaa94a1Schristos *(unsigned long *) *target = source; 35092eaa94a1Schristos } else if (sizeof(unsigned) == 4) { 351020d2c4d2Smrg *(unsigned *) *target = (unsigned) source; 35112eaa94a1Schristos } else if (sizeof(unsigned short) == 4) { 35122eaa94a1Schristos *(unsigned short *) *target = (unsigned short) source; 35132eaa94a1Schristos } else { 35142eaa94a1Schristos /* FIXME - does this depend on byte-order? */ 35152eaa94a1Schristos unsigned long temp = source; 351620d2c4d2Smrg memcpy((char *) *target, 351720d2c4d2Smrg ((char *) &temp) + sizeof(temp) - 4, 351820d2c4d2Smrg (size_t) 4); 35192eaa94a1Schristos } 35202eaa94a1Schristos } 35212eaa94a1Schristos return result; 35222eaa94a1Schristos} 35232eaa94a1Schristos 3524d522f475Smrgstatic Boolean 3525d522f475SmrgConvertSelection(Widget w, 3526d522f475Smrg Atom * selection, 3527d522f475Smrg Atom * target, 3528d522f475Smrg Atom * type, 3529d522f475Smrg XtPointer *value, 3530d522f475Smrg unsigned long *length, 3531d522f475Smrg int *format) 3532d522f475Smrg{ 3533d522f475Smrg Display *dpy = XtDisplay(w); 3534d522f475Smrg TScreen *screen; 3535d522f475Smrg Bool result = False; 3536d522f475Smrg 3537956cc18dSsnj XtermWidget xw; 3538956cc18dSsnj 3539956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 3540d522f475Smrg return False; 3541d522f475Smrg 3542956cc18dSsnj screen = TScreenOf(xw); 3543d522f475Smrg 3544d522f475Smrg if (screen->selection_data == NULL) 3545d522f475Smrg return False; /* can this happen? */ 3546d522f475Smrg 3547956cc18dSsnj TRACE(("ConvertSelection %s\n", 3548956cc18dSsnj visibleSelectionTarget(dpy, *target))); 3549956cc18dSsnj 3550d522f475Smrg if (*target == XA_TARGETS(dpy)) { 3551d522f475Smrg Atom *allocP; 3552d522f475Smrg Atom *targetP; 3553d522f475Smrg Atom *std_targets; 3554d522f475Smrg XPointer std_return = 0; 3555d522f475Smrg unsigned long std_length; 3556d522f475Smrg 3557d522f475Smrg if (XmuConvertStandardSelection(w, screen->selection_time, selection, 3558d522f475Smrg target, type, &std_return, 3559d522f475Smrg &std_length, format)) { 3560956cc18dSsnj Atom *my_targets = _SelectionTargets(w); 3561956cc18dSsnj 3562956cc18dSsnj TRACE(("XmuConvertStandardSelection - success\n")); 3563d522f475Smrg std_targets = (Atom *) (std_return); 3564d522f475Smrg *length = std_length + 6; 3565d522f475Smrg 3566956cc18dSsnj targetP = (Atom *) XtMalloc((Cardinal) (sizeof(Atom) * (*length))); 3567d522f475Smrg allocP = targetP; 3568d522f475Smrg 3569d522f475Smrg *value = (XtPointer) targetP; 3570d522f475Smrg 3571956cc18dSsnj while (*my_targets != None) { 3572956cc18dSsnj *targetP++ = *my_targets++; 3573956cc18dSsnj } 3574d522f475Smrg *targetP++ = XA_LENGTH(dpy); 3575d522f475Smrg *targetP++ = XA_LIST_LENGTH(dpy); 3576d522f475Smrg 35772eaa94a1Schristos *length = std_length + (unsigned long) (targetP - allocP); 3578d522f475Smrg 3579d522f475Smrg memcpy(targetP, std_targets, sizeof(Atom) * std_length); 3580d522f475Smrg XtFree((char *) std_targets); 3581d522f475Smrg *type = XA_ATOM; 3582d522f475Smrg *format = 32; 3583d522f475Smrg result = True; 3584956cc18dSsnj } else { 3585956cc18dSsnj TRACE(("XmuConvertStandardSelection - failed\n")); 3586d522f475Smrg } 3587d522f475Smrg } 3588d522f475Smrg#if OPT_WIDE_CHARS 3589d522f475Smrg else if (screen->wide_chars && *target == XA_STRING) { 3590d522f475Smrg result = 3591d522f475Smrg _ConvertSelectionHelper(w, 3592d522f475Smrg type, value, length, format, 3593d522f475Smrg Xutf8TextListToTextProperty, 3594d522f475Smrg XStringStyle); 3595956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3596d522f475Smrg } else if (screen->wide_chars && *target == XA_UTF8_STRING(dpy)) { 3597d522f475Smrg result = 3598d522f475Smrg _ConvertSelectionHelper(w, 3599d522f475Smrg type, value, length, format, 3600d522f475Smrg Xutf8TextListToTextProperty, 3601d522f475Smrg XUTF8StringStyle); 3602956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3603d522f475Smrg } else if (screen->wide_chars && *target == XA_TEXT(dpy)) { 3604d522f475Smrg result = 3605d522f475Smrg _ConvertSelectionHelper(w, 3606d522f475Smrg type, value, length, format, 3607d522f475Smrg Xutf8TextListToTextProperty, 3608d522f475Smrg XStdICCTextStyle); 3609956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3610d522f475Smrg } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(dpy)) { 3611d522f475Smrg result = 3612d522f475Smrg _ConvertSelectionHelper(w, 3613d522f475Smrg type, value, length, format, 3614d522f475Smrg Xutf8TextListToTextProperty, 3615d522f475Smrg XCompoundTextStyle); 3616956cc18dSsnj TRACE(("...Xutf8TextListToTextProperty:%d\n", result)); 3617d522f475Smrg } 3618d522f475Smrg#endif 3619d522f475Smrg 3620d522f475Smrg else if (*target == XA_STRING) { /* not wide_chars */ 3621d522f475Smrg /* We can only reach this point if the selection requestor 3622d522f475Smrg requested STRING before any of TEXT, COMPOUND_TEXT or 3623d522f475Smrg UTF8_STRING. We therefore assume that the requestor is not 3624d522f475Smrg properly internationalised, and dump raw eight-bit data 3625d522f475Smrg with no conversion into the selection. Yes, this breaks 3626d522f475Smrg the ICCCM in non-Latin-1 locales. */ 3627d522f475Smrg *type = XA_STRING; 3628d522f475Smrg *value = (XtPointer) screen->selection_data; 3629d522f475Smrg *length = screen->selection_length; 3630d522f475Smrg *format = 8; 3631d522f475Smrg result = True; 3632956cc18dSsnj TRACE(("...raw 8-bit data:%d\n", result)); 3633d522f475Smrg } else if (*target == XA_TEXT(dpy)) { /* not wide_chars */ 3634d522f475Smrg result = 3635d522f475Smrg _ConvertSelectionHelper(w, 3636d522f475Smrg type, value, length, format, 3637d522f475Smrg XmbTextListToTextProperty, 3638d522f475Smrg XStdICCTextStyle); 3639956cc18dSsnj TRACE(("...XmbTextListToTextProperty(StdICC):%d\n", result)); 3640d522f475Smrg } else if (*target == XA_COMPOUND_TEXT(dpy)) { /* not wide_chars */ 3641d522f475Smrg result = 3642d522f475Smrg _ConvertSelectionHelper(w, 3643d522f475Smrg type, value, length, format, 3644d522f475Smrg XmbTextListToTextProperty, 3645d522f475Smrg XCompoundTextStyle); 3646956cc18dSsnj TRACE(("...XmbTextListToTextProperty(Compound):%d\n", result)); 3647d522f475Smrg } 3648d522f475Smrg#ifdef X_HAVE_UTF8_STRING 3649d522f475Smrg else if (*target == XA_UTF8_STRING(dpy)) { /* not wide_chars */ 3650d522f475Smrg result = 3651d522f475Smrg _ConvertSelectionHelper(w, 3652d522f475Smrg type, value, length, format, 3653d522f475Smrg XmbTextListToTextProperty, 3654d522f475Smrg XUTF8StringStyle); 3655956cc18dSsnj TRACE(("...XmbTextListToTextProperty(UTF8):%d\n", result)); 3656d522f475Smrg } 3657d522f475Smrg#endif 3658d522f475Smrg else if (*target == XA_LIST_LENGTH(dpy)) { 365920d2c4d2Smrg result = SaveConvertedLength(value, (unsigned long) 1); 3660d522f475Smrg *type = XA_INTEGER; 3661d522f475Smrg *length = 1; 3662d522f475Smrg *format = 32; 3663956cc18dSsnj TRACE(("...list of values:%d\n", result)); 3664d522f475Smrg } else if (*target == XA_LENGTH(dpy)) { 3665d522f475Smrg /* This value is wrong if we have UTF-8 text */ 36662eaa94a1Schristos result = SaveConvertedLength(value, screen->selection_length); 3667d522f475Smrg *type = XA_INTEGER; 3668d522f475Smrg *length = 1; 3669d522f475Smrg *format = 32; 3670956cc18dSsnj TRACE(("...list of values:%d\n", result)); 3671d522f475Smrg } else if (XmuConvertStandardSelection(w, 3672d522f475Smrg screen->selection_time, selection, 3673d522f475Smrg target, type, (XPointer *) value, 3674d522f475Smrg length, format)) { 3675d522f475Smrg result = True; 3676956cc18dSsnj TRACE(("...XmuConvertStandardSelection:%d\n", result)); 3677d522f475Smrg } 3678d522f475Smrg 3679d522f475Smrg /* else */ 36802eaa94a1Schristos return (Boolean) result; 3681d522f475Smrg} 3682d522f475Smrg 3683d522f475Smrgstatic void 3684d522f475SmrgLoseSelection(Widget w, Atom * selection) 3685d522f475Smrg{ 3686d522f475Smrg TScreen *screen; 3687d522f475Smrg Atom *atomP; 3688d522f475Smrg Cardinal i; 3689d522f475Smrg 3690956cc18dSsnj XtermWidget xw; 3691956cc18dSsnj 3692956cc18dSsnj if ((xw = getXtermWidget(w)) == 0) 3693d522f475Smrg return; 3694d522f475Smrg 3695956cc18dSsnj screen = TScreenOf(xw); 3696d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 3697d522f475Smrg i < screen->selection_count; i++, atomP++) { 3698d522f475Smrg if (*selection == *atomP) 3699d522f475Smrg *atomP = (Atom) 0; 3700d522f475Smrg if (CutBuffer(*atomP) >= 0) { 3701d522f475Smrg *atomP = (Atom) 0; 3702d522f475Smrg } 3703d522f475Smrg } 3704d522f475Smrg 3705d522f475Smrg for (i = screen->selection_count; i; i--) { 3706d522f475Smrg if (screen->selection_atoms[i - 1] != 0) 3707d522f475Smrg break; 3708d522f475Smrg } 3709d522f475Smrg screen->selection_count = i; 3710d522f475Smrg 3711d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 3712d522f475Smrg i < screen->selection_count; i++, atomP++) { 3713d522f475Smrg if (*atomP == (Atom) 0) { 3714d522f475Smrg *atomP = screen->selection_atoms[--screen->selection_count]; 3715d522f475Smrg } 3716d522f475Smrg } 3717d522f475Smrg 3718d522f475Smrg if (screen->selection_count == 0) 3719956cc18dSsnj TrackText(xw, &zeroCELL, &zeroCELL); 3720d522f475Smrg} 3721d522f475Smrg 3722d522f475Smrg/* ARGSUSED */ 3723d522f475Smrgstatic void 3724d522f475SmrgSelectionDone(Widget w GCC_UNUSED, 3725d522f475Smrg Atom * selection GCC_UNUSED, 3726d522f475Smrg Atom * target GCC_UNUSED) 3727d522f475Smrg{ 3728d522f475Smrg /* empty proc so Intrinsics know we want to keep storage */ 3729d522f475Smrg} 3730d522f475Smrg 3731d522f475Smrgstatic void 3732d522f475Smrg_OwnSelection(XtermWidget xw, 3733d522f475Smrg String * selections, 3734d522f475Smrg Cardinal count) 3735d522f475Smrg{ 3736956cc18dSsnj TScreen *screen = TScreenOf(xw); 3737d522f475Smrg Atom *atoms = screen->selection_atoms; 3738d522f475Smrg Cardinal i; 3739d522f475Smrg Bool have_selection = False; 3740d522f475Smrg 374120d2c4d2Smrg if (count == 0) 374220d2c4d2Smrg return; 37432eaa94a1Schristos if (screen->selection_length == 0) 3744d522f475Smrg return; 3745d522f475Smrg 3746956cc18dSsnj TRACE(("_OwnSelection count %d\n", count)); 3747d522f475Smrg selections = MapSelections(xw, selections, count); 3748d522f475Smrg 3749d522f475Smrg if (count > screen->sel_atoms_size) { 3750d522f475Smrg XtFree((char *) atoms); 3751956cc18dSsnj atoms = (Atom *) XtMalloc((Cardinal) (count * sizeof(Atom))); 3752d522f475Smrg screen->selection_atoms = atoms; 3753d522f475Smrg screen->sel_atoms_size = count; 3754d522f475Smrg } 3755d522f475Smrg XmuInternStrings(XtDisplay((Widget) xw), selections, count, atoms); 3756d522f475Smrg for (i = 0; i < count; i++) { 3757d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 3758d522f475Smrg if (cutbuffer >= 0) { 37592eaa94a1Schristos unsigned long limit = 37602eaa94a1Schristos (unsigned long) (4 * XMaxRequestSize(XtDisplay((Widget) xw)) - 32); 37612eaa94a1Schristos if (screen->selection_length > limit) { 376220d2c4d2Smrg TRACE(("selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 376320d2c4d2Smrg screen->selection_length, cutbuffer)); 3764d522f475Smrg fprintf(stderr, 3765956cc18dSsnj "%s: selection too big (%lu bytes), not storing in CUT_BUFFER%d\n", 3766d522f475Smrg xterm_name, screen->selection_length, cutbuffer); 3767d522f475Smrg } else { 3768d522f475Smrg /* This used to just use the UTF-8 data, which was totally 3769d522f475Smrg * broken as not even the corresponding paste code in Xterm 3770d522f475Smrg * understood this! So now it converts to Latin1 first. 3771d522f475Smrg * Robert Brady, 2000-09-05 3772d522f475Smrg */ 3773d522f475Smrg unsigned long length = screen->selection_length; 3774d522f475Smrg Char *data = screen->selection_data; 3775d522f475Smrg if_OPT_WIDE_CHARS((screen), { 3776956cc18dSsnj data = UTF8toLatin1(screen, data, length, &length); 3777d522f475Smrg }); 3778d522f475Smrg TRACE(("XStoreBuffer(%d)\n", cutbuffer)); 3779d522f475Smrg XStoreBuffer(XtDisplay((Widget) xw), 3780d522f475Smrg (char *) data, 3781d522f475Smrg (int) length, 3782d522f475Smrg cutbuffer); 3783d522f475Smrg } 3784d522f475Smrg } else if (!screen->replyToEmacs) { 3785d522f475Smrg have_selection |= 3786d522f475Smrg XtOwnSelection((Widget) xw, atoms[i], 3787d522f475Smrg screen->selection_time, 3788d522f475Smrg ConvertSelection, LoseSelection, SelectionDone); 3789d522f475Smrg } 3790d522f475Smrg } 3791d522f475Smrg if (!screen->replyToEmacs) 3792d522f475Smrg screen->selection_count = count; 3793d522f475Smrg if (!have_selection) 3794d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 3795d522f475Smrg} 3796d522f475Smrg 3797d522f475Smrgstatic void 3798d522f475SmrgResetSelectionState(TScreen * screen) 3799d522f475Smrg{ 3800d522f475Smrg screen->selection_count = 0; 3801d522f475Smrg screen->startH = zeroCELL; 3802d522f475Smrg screen->endH = zeroCELL; 3803d522f475Smrg} 3804d522f475Smrg 3805d522f475Smrgvoid 3806d522f475SmrgDisownSelection(XtermWidget xw) 3807d522f475Smrg{ 3808956cc18dSsnj TScreen *screen = TScreenOf(xw); 3809d522f475Smrg Atom *atoms = screen->selection_atoms; 3810d522f475Smrg Cardinal count = screen->selection_count; 3811d522f475Smrg Cardinal i; 3812d522f475Smrg 3813d522f475Smrg TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n", 3814d522f475Smrg count, 3815d522f475Smrg screen->startH.row, 3816d522f475Smrg screen->startH.col, 3817d522f475Smrg screen->endH.row, 3818d522f475Smrg screen->endH.col)); 3819d522f475Smrg 3820d522f475Smrg for (i = 0; i < count; i++) { 3821d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 3822d522f475Smrg if (cutbuffer < 0) { 3823d522f475Smrg XtDisownSelection((Widget) xw, atoms[i], 3824d522f475Smrg screen->selection_time); 3825d522f475Smrg } 3826d522f475Smrg } 3827d522f475Smrg /* 3828d522f475Smrg * If none of the callbacks via XtDisownSelection() reset highlighting 3829d522f475Smrg * do it now. 3830d522f475Smrg */ 3831d522f475Smrg if (ScrnHaveSelection(screen)) { 3832d522f475Smrg /* save data which will be reset */ 3833d522f475Smrg CELL first = screen->startH; 3834d522f475Smrg CELL last = screen->endH; 3835d522f475Smrg 3836d522f475Smrg ResetSelectionState(screen); 3837d522f475Smrg ReHiliteText(xw, &first, &last); 3838d522f475Smrg } else { 3839d522f475Smrg ResetSelectionState(screen); 3840d522f475Smrg } 3841d522f475Smrg} 3842d522f475Smrg 3843d522f475Smrgvoid 3844d522f475SmrgUnhiliteSelection(XtermWidget xw) 3845d522f475Smrg{ 3846956cc18dSsnj TScreen *screen = TScreenOf(xw); 3847d522f475Smrg 3848d522f475Smrg if (ScrnHaveSelection(screen)) { 3849d522f475Smrg CELL first = screen->startH; 3850d522f475Smrg CELL last = screen->endH; 3851d522f475Smrg 3852d522f475Smrg screen->startH = zeroCELL; 3853d522f475Smrg screen->endH = zeroCELL; 3854d522f475Smrg ReHiliteText(xw, &first, &last); 3855d522f475Smrg } 3856d522f475Smrg} 3857d522f475Smrg 3858d522f475Smrg/* returns number of chars in line from scol to ecol out */ 3859d522f475Smrg/* ARGSUSED */ 3860d522f475Smrgstatic int 3861956cc18dSsnjLength(TScreen * screen, 3862d522f475Smrg int row, 3863d522f475Smrg int scol, 3864d522f475Smrg int ecol) 3865d522f475Smrg{ 3866956cc18dSsnj LineData *ld = GET_LINEDATA(screen, row); 3867956cc18dSsnj int lastcol = LastTextCol(screen, ld, row); 3868d522f475Smrg 3869d522f475Smrg if (ecol > lastcol) 3870d522f475Smrg ecol = lastcol; 3871d522f475Smrg return (ecol - scol + 1); 3872d522f475Smrg} 3873d522f475Smrg 3874d522f475Smrg/* copies text into line, preallocated */ 3875d522f475Smrgstatic Char * 3876d522f475SmrgSaveText(TScreen * screen, 3877d522f475Smrg int row, 3878d522f475Smrg int scol, 3879d522f475Smrg int ecol, 3880d522f475Smrg Char * lp, /* pointer to where to put the text */ 3881d522f475Smrg int *eol) 3882d522f475Smrg{ 3883956cc18dSsnj LineData *ld; 3884d522f475Smrg int i = 0; 3885d522f475Smrg unsigned c; 3886d522f475Smrg Char *result = lp; 3887d522f475Smrg#if OPT_WIDE_CHARS 38882eaa94a1Schristos unsigned previous = 0; 3889d522f475Smrg#endif 3890d522f475Smrg 3891956cc18dSsnj ld = GET_LINEDATA(screen, row); 3892d522f475Smrg i = Length(screen, row, scol, ecol); 3893d522f475Smrg ecol = scol + i; 3894d522f475Smrg#if OPT_DEC_CHRSET 3895956cc18dSsnj if (CSET_DOUBLE(GetLineDblCS(ld))) { 3896d522f475Smrg scol = (scol + 0) / 2; 3897d522f475Smrg ecol = (ecol + 1) / 2; 3898d522f475Smrg } 3899d522f475Smrg#endif 3900956cc18dSsnj *eol = !LineTstWrapped(ld); 3901d522f475Smrg for (i = scol; i < ecol; i++) { 390220d2c4d2Smrg assert(i < ld->lineSize); 3903956cc18dSsnj c = E2A(ld->charData[i]); 3904d522f475Smrg#if OPT_WIDE_CHARS 3905d522f475Smrg /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a 3906d522f475Smrg * wide character. 3907d522f475Smrg */ 3908956cc18dSsnj if (c == HIDDEN_CHAR && isWide((int) previous)) { 3909d522f475Smrg previous = c; 3910d522f475Smrg /* Combining characters attached to double-width characters 3911d522f475Smrg are in memory attached to the HIDDEN_CHAR */ 3912d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3913d522f475Smrg if (screen->utf8_mode != uFalse) { 3914d522f475Smrg unsigned ch; 3915956cc18dSsnj size_t off; 3916956cc18dSsnj for_each_combData(off, ld) { 3917956cc18dSsnj ch = ld->combData[off][i]; 3918956cc18dSsnj if (ch == 0) 3919d522f475Smrg break; 3920d522f475Smrg lp = convertToUTF8(lp, ch); 3921d522f475Smrg } 3922d522f475Smrg } 3923d522f475Smrg }); 3924d522f475Smrg continue; 3925d522f475Smrg } 3926d522f475Smrg previous = c; 3927d522f475Smrg if (screen->utf8_mode != uFalse) { 3928d522f475Smrg lp = convertToUTF8(lp, (c != 0) ? c : ' '); 3929d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3930d522f475Smrg unsigned ch; 3931956cc18dSsnj size_t off; 3932956cc18dSsnj for_each_combData(off, ld) { 3933956cc18dSsnj ch = ld->combData[off][i]; 3934956cc18dSsnj if (ch == 0) 3935d522f475Smrg break; 3936d522f475Smrg lp = convertToUTF8(lp, ch); 3937d522f475Smrg } 3938d522f475Smrg }); 3939d522f475Smrg } else 3940d522f475Smrg#endif 3941d522f475Smrg { 3942d522f475Smrg if (c == 0) { 3943d522f475Smrg c = E2A(' '); 3944d522f475Smrg } else if (c < E2A(' ')) { 3945d522f475Smrg c = DECtoASCII(c); 3946d522f475Smrg } else if (c == 0x7f) { 3947d522f475Smrg c = 0x5f; 3948d522f475Smrg } 39492eaa94a1Schristos *lp++ = CharOf(A2E(c)); 3950d522f475Smrg } 3951d522f475Smrg if (c != E2A(' ')) 3952d522f475Smrg result = lp; 3953d522f475Smrg } 3954d522f475Smrg 3955d522f475Smrg /* 3956d522f475Smrg * If requested, trim trailing blanks from selected lines. Do not do this 3957d522f475Smrg * if the line is wrapped. 3958d522f475Smrg */ 3959d522f475Smrg if (!*eol || !screen->trim_selection) 3960d522f475Smrg result = lp; 3961d522f475Smrg 3962d522f475Smrg return (result); 3963d522f475Smrg} 3964d522f475Smrg 3965d522f475Smrg/* 32 + following 7-bit word: 3966d522f475Smrg 3967d522f475Smrg 1:0 Button no: 0, 1, 2. 3=release. 3968d522f475Smrg 2 shift 3969d522f475Smrg 3 meta 3970d522f475Smrg 4 ctrl 3971d522f475Smrg 5 set for motion notify 3972d522f475Smrg 6 set for wheel 3973d522f475Smrg*/ 3974d522f475Smrg 3975d522f475Smrg/* Position: 32 - 255. */ 3976d522f475Smrg 39772eaa94a1Schristosstatic Char 3978d522f475SmrgBtnCode(XButtonEvent * event, int button) 3979d522f475Smrg{ 39802eaa94a1Schristos int result = (int) (32 + (KeyState(event->state) << 2)); 3981d522f475Smrg 3982d522f475Smrg if (button < 0 || button > 5) { 3983d522f475Smrg result += 3; 3984d522f475Smrg } else { 3985d522f475Smrg if (button > 3) 3986d522f475Smrg result += (64 - 4); 3987d522f475Smrg if (event->type == MotionNotify) 3988d522f475Smrg result += 32; 3989d522f475Smrg result += button; 3990d522f475Smrg } 39912eaa94a1Schristos return CharOf(result); 3992d522f475Smrg} 3993d522f475Smrg 3994d522f475Smrg#define MOUSE_LIMIT (255 - 32) 3995d522f475Smrg 3996d522f475Smrgstatic void 3997d522f475SmrgEditorButton(XtermWidget xw, XButtonEvent * event) 3998d522f475Smrg{ 3999956cc18dSsnj TScreen *screen = TScreenOf(xw); 4000d522f475Smrg int pty = screen->respond; 4001d522f475Smrg Char line[6]; 4002d522f475Smrg int row, col; 4003d522f475Smrg int button; 4004d522f475Smrg unsigned count = 0; 4005d522f475Smrg Boolean changed = True; 4006d522f475Smrg 4007d522f475Smrg /* If button event, get button # adjusted for DEC compatibility */ 40082eaa94a1Schristos button = (int) (event->button - 1); 4009d522f475Smrg if (button >= 3) 4010d522f475Smrg button++; 4011d522f475Smrg 4012d522f475Smrg /* Compute character position of mouse pointer */ 4013d522f475Smrg row = (event->y - screen->border) / FontHeight(screen); 4014d522f475Smrg col = (event->x - OriginX(screen)) / FontWidth(screen); 4015d522f475Smrg 4016d522f475Smrg /* Limit to screen dimensions */ 4017d522f475Smrg if (row < 0) 4018d522f475Smrg row = 0; 4019d522f475Smrg else if (row > screen->max_row) 4020d522f475Smrg row = screen->max_row; 4021d522f475Smrg else if (row > MOUSE_LIMIT) 4022d522f475Smrg row = MOUSE_LIMIT; 4023d522f475Smrg 4024d522f475Smrg if (col < 0) 4025d522f475Smrg col = 0; 4026d522f475Smrg else if (col > screen->max_col) 4027d522f475Smrg col = screen->max_col; 4028d522f475Smrg else if (col > MOUSE_LIMIT) 4029d522f475Smrg col = MOUSE_LIMIT; 4030d522f475Smrg 4031d522f475Smrg /* Build key sequence starting with \E[M */ 4032d522f475Smrg if (screen->control_eight_bits) { 4033d522f475Smrg line[count++] = ANSI_CSI; 4034d522f475Smrg } else { 4035d522f475Smrg line[count++] = ANSI_ESC; 4036d522f475Smrg line[count++] = '['; 4037d522f475Smrg } 4038d522f475Smrg#if OPT_SCO_FUNC_KEYS 4039d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 4040d522f475Smrg /* 4041d522f475Smrg * SCO function key F1 is \E[M, which would conflict with xterm's 4042d522f475Smrg * normal kmous. 4043d522f475Smrg */ 4044d522f475Smrg line[count++] = '>'; 4045d522f475Smrg } 4046d522f475Smrg#endif 4047d522f475Smrg line[count++] = 'M'; 4048d522f475Smrg 4049d522f475Smrg /* Add event code to key sequence */ 4050d522f475Smrg if (screen->send_mouse_pos == X10_MOUSE) { 40512eaa94a1Schristos line[count++] = CharOf(' ' + button); 4052d522f475Smrg } else { 4053d522f475Smrg /* Button-Motion events */ 4054d522f475Smrg switch (event->type) { 4055d522f475Smrg case ButtonPress: 4056d522f475Smrg line[count++] = BtnCode(event, screen->mouse_button = button); 4057d522f475Smrg break; 4058d522f475Smrg case ButtonRelease: 4059d522f475Smrg /* 4060d522f475Smrg * Wheel mouse interface generates release-events for buttons 4061d522f475Smrg * 4 and 5, coded here as 3 and 4 respectively. We change the 4062d522f475Smrg * release for buttons 1..3 to a -1. 4063d522f475Smrg */ 4064d522f475Smrg if (button < 3) 4065d522f475Smrg button = -1; 4066d522f475Smrg line[count++] = BtnCode(event, screen->mouse_button = button); 4067d522f475Smrg break; 4068d522f475Smrg case MotionNotify: 4069d522f475Smrg /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion 4070d522f475Smrg * events only if character cell has changed. 4071d522f475Smrg */ 4072d522f475Smrg if ((row == screen->mouse_row) 4073d522f475Smrg && (col == screen->mouse_col)) { 4074d522f475Smrg changed = False; 4075d522f475Smrg } else { 4076d522f475Smrg line[count++] = BtnCode(event, screen->mouse_button); 4077d522f475Smrg } 4078d522f475Smrg break; 4079d522f475Smrg default: 4080d522f475Smrg changed = False; 4081d522f475Smrg break; 4082d522f475Smrg } 4083d522f475Smrg } 4084d522f475Smrg 4085d522f475Smrg if (changed) { 4086d522f475Smrg screen->mouse_row = row; 4087d522f475Smrg screen->mouse_col = col; 4088d522f475Smrg 4089d522f475Smrg /* Add pointer position to key sequence */ 40902eaa94a1Schristos line[count++] = CharOf(' ' + col + 1); 40912eaa94a1Schristos line[count++] = CharOf(' ' + row + 1); 4092d522f475Smrg 4093d522f475Smrg TRACE(("mouse at %d,%d button+mask = %#x\n", row, col, 4094d522f475Smrg (screen->control_eight_bits) ? line[2] : line[3])); 4095d522f475Smrg 4096d522f475Smrg /* Transmit key sequence to process running under xterm */ 4097d522f475Smrg v_write(pty, line, count); 4098d522f475Smrg } 4099d522f475Smrg return; 4100d522f475Smrg} 4101d522f475Smrg 4102d522f475Smrg#if OPT_FOCUS_EVENT 4103d522f475Smrgvoid 4104d522f475SmrgSendFocusButton(XtermWidget xw, XFocusChangeEvent * event) 4105d522f475Smrg{ 4106956cc18dSsnj TScreen *screen = TScreenOf(xw); 4107d522f475Smrg 4108d522f475Smrg if (screen->send_focus_pos) { 4109d522f475Smrg ANSI reply; 4110d522f475Smrg 4111d522f475Smrg memset(&reply, 0, sizeof(reply)); 4112d522f475Smrg reply.a_type = ANSI_CSI; 4113d522f475Smrg 4114d522f475Smrg#if OPT_SCO_FUNC_KEYS 4115d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 4116d522f475Smrg reply.a_pintro = '>'; 4117d522f475Smrg } 4118d522f475Smrg#endif 41192eaa94a1Schristos reply.a_final = CharOf((event->type == FocusIn) ? 'I' : 'O'); 4120d522f475Smrg unparseseq(xw, &reply); 4121d522f475Smrg } 4122d522f475Smrg return; 4123d522f475Smrg} 4124d522f475Smrg#endif /* OPT_FOCUS_EVENT */ 4125