button.c revision 2eaa94a1
12eaa94a1Schristos/* $XTermId: button.c,v 1.297 2008/10/05 23:32:52 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4d522f475Smrg * Copyright 1999-2007,2008 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> 65d522f475Smrg 66d522f475Smrg#include <X11/Xatom.h> 67d522f475Smrg#include <X11/Xmu/Atoms.h> 68d522f475Smrg#include <X11/Xmu/StdSel.h> 69d522f475Smrg 70d522f475Smrg#include <xutf8.h> 71d522f475Smrg#include <fontutils.h> 72d522f475Smrg 73d522f475Smrg#include <data.h> 74d522f475Smrg#include <error.h> 75d522f475Smrg#include <menu.h> 76d522f475Smrg#include <xcharmouse.h> 77d522f475Smrg#include <charclass.h> 78d522f475Smrg#include <xstrings.h> 79d522f475Smrg 80d522f475Smrg#if OPT_SELECT_REGEX 81d522f475Smrg#ifdef HAVE_PCREPOSIX_H 82d522f475Smrg#include <pcreposix.h> 83d522f475Smrg#else /* POSIX regex.h */ 84d522f475Smrg#include <sys/types.h> 85d522f475Smrg#include <regex.h> 86d522f475Smrg#endif 87d522f475Smrg#endif 88d522f475Smrg 89d522f475Smrg#if OPT_WIDE_CHARS 90d522f475Smrg#include <ctype.h> 91d522f475Smrg#include <wcwidth.h> 92d522f475Smrg#else 93d522f475Smrg#define CharacterClass(value) \ 94d522f475Smrg charClass[value & ((sizeof(charClass)/sizeof(charClass[0]))-1)] 95d522f475Smrg#endif 96d522f475Smrg 97d522f475Smrg /* 98d522f475Smrg * We reserve shift modifier for cut/paste operations. In principle we 99d522f475Smrg * can pass through control and meta modifiers, but in practice, the 100d522f475Smrg * popup menu uses control, and the window manager is likely to use meta, 101d522f475Smrg * so those events are not delivered to SendMousePosition. 102d522f475Smrg */ 103d522f475Smrg#define OurModifiers (ShiftMask | ControlMask | Mod1Mask) 104d522f475Smrg#define AllModifiers (ShiftMask | LockMask | ControlMask | Mod1Mask | \ 105d522f475Smrg Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) 106d522f475Smrg 107d522f475Smrg#define KeyModifiers (event->xbutton.state & OurModifiers) 108d522f475Smrg 1092eaa94a1Schristos#define KeyState(x) (((int) ((x) & (ShiftMask|ControlMask))) \ 1102eaa94a1Schristos + (((x) & Mod1Mask) ? 2 : 0)) 111d522f475Smrg /* adds together the bits: 112d522f475Smrg shift key -> 1 113d522f475Smrg meta key -> 2 114d522f475Smrg control key -> 4 */ 115d522f475Smrg 116d522f475Smrg#define Coordinate(s,c) ((c)->row * MaxCols(s) + (c)->col) 117d522f475Smrg 118d522f475Smrgstatic const CELL zeroCELL = 119d522f475Smrg{0, 0}; 120d522f475Smrg 121d522f475Smrg#if OPT_DEC_LOCATOR 122d522f475Smrgstatic Bool SendLocatorPosition(XtermWidget xw, XEvent * event); 123d522f475Smrgstatic void CheckLocatorPosition(XtermWidget xw, XEvent * event); 124d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 125d522f475Smrg 126d522f475Smrg/* Multi-click handling */ 127d522f475Smrg#if OPT_READLINE 128d522f475Smrgstatic Time lastButtonDownTime = 0; 129d522f475Smrgstatic int ExtendingSelection = 0; 130d522f475Smrgstatic Time lastButton3UpTime = 0; 131d522f475Smrgstatic Time lastButton3DoubleDownTime = 0; 132d522f475Smrgstatic CELL lastButton3; /* At the release time */ 133d522f475Smrg#endif /* OPT_READLINE */ 134d522f475Smrg 135d522f475Smrgstatic Char *SaveText(TScreen * screen, int row, int scol, int ecol, 136d522f475Smrg Char * lp, int *eol); 137d522f475Smrgstatic int Length(TScreen * screen, int row, int scol, int ecol); 138d522f475Smrgstatic void ComputeSelect(XtermWidget xw, CELL * startc, CELL * endc, Bool extend); 139d522f475Smrgstatic void EditorButton(XtermWidget xw, XButtonEvent * event); 140d522f475Smrgstatic void EndExtend(XtermWidget w, XEvent * event, String * params, Cardinal 141d522f475Smrg num_params, Bool use_cursor_loc); 142d522f475Smrgstatic void ExtendExtend(XtermWidget xw, const CELL * cell); 143d522f475Smrgstatic void PointToCELL(TScreen * screen, int y, int x, CELL * cell); 144d522f475Smrgstatic void ReHiliteText(XtermWidget xw, CELL * first, CELL * last); 145d522f475Smrgstatic void SaltTextAway(XtermWidget xw, CELL * cellc, CELL * cell, 146d522f475Smrg String * params, Cardinal num_params); 147d522f475Smrgstatic void SelectSet(XtermWidget xw, XEvent * event, String * params, Cardinal num_params); 148d522f475Smrgstatic void SelectionReceived PROTO_XT_SEL_CB_ARGS; 149d522f475Smrgstatic void StartSelect(XtermWidget xw, const CELL * cell); 150d522f475Smrgstatic void TrackDown(XtermWidget xw, XButtonEvent * event); 151d522f475Smrgstatic void TrackText(XtermWidget xw, const CELL * first, const CELL * last); 152d522f475Smrgstatic void _OwnSelection(XtermWidget xw, String * selections, Cardinal count); 153d522f475Smrgstatic void do_select_end(XtermWidget xw, XEvent * event, String * params, 154d522f475Smrg Cardinal *num_params, Bool use_cursor_loc); 155d522f475Smrg 156d522f475SmrgBool 157d522f475SmrgSendMousePosition(XtermWidget xw, XEvent * event) 158d522f475Smrg{ 159d522f475Smrg TScreen *screen = &(xw->screen); 160d522f475Smrg 161d522f475Smrg /* If send_mouse_pos mode isn't on, we shouldn't be here */ 162d522f475Smrg if (screen->send_mouse_pos == MOUSE_OFF) 163d522f475Smrg return False; 164d522f475Smrg 165d522f475Smrg#if OPT_DEC_LOCATOR 166d522f475Smrg if (screen->send_mouse_pos == DEC_LOCATOR) { 167d522f475Smrg return (SendLocatorPosition(xw, event)); 168d522f475Smrg } 169d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 170d522f475Smrg 171d522f475Smrg /* Make sure the event is an appropriate type */ 172d522f475Smrg if ((screen->send_mouse_pos != BTN_EVENT_MOUSE) 173d522f475Smrg && (screen->send_mouse_pos != ANY_EVENT_MOUSE) 174d522f475Smrg && event->type != ButtonPress 175d522f475Smrg && event->type != ButtonRelease) 176d522f475Smrg return False; 177d522f475Smrg 178d522f475Smrg switch (screen->send_mouse_pos) { 179d522f475Smrg case X10_MOUSE: /* X10 compatibility sequences */ 180d522f475Smrg 181d522f475Smrg if (KeyModifiers == 0) { 182d522f475Smrg if (event->type == ButtonPress) 183d522f475Smrg EditorButton(xw, (XButtonEvent *) event); 184d522f475Smrg return True; 185d522f475Smrg } 186d522f475Smrg return False; 187d522f475Smrg 188d522f475Smrg case VT200_HIGHLIGHT_MOUSE: /* DEC vt200 hilite tracking */ 189d522f475Smrg if (event->type == ButtonPress && 190d522f475Smrg KeyModifiers == 0 && 191d522f475Smrg event->xbutton.button == Button1) { 192d522f475Smrg TrackDown(xw, (XButtonEvent *) event); 193d522f475Smrg return True; 194d522f475Smrg } 195d522f475Smrg if (KeyModifiers == 0 || KeyModifiers == ControlMask) { 196d522f475Smrg EditorButton(xw, (XButtonEvent *) event); 197d522f475Smrg return True; 198d522f475Smrg } 199d522f475Smrg return False; 200d522f475Smrg 201d522f475Smrg case VT200_MOUSE: /* DEC vt200 compatible */ 202d522f475Smrg 203d522f475Smrg /* xterm extension for motion reporting. June 1998 */ 204d522f475Smrg /* EditorButton() will distinguish between the modes */ 205d522f475Smrg case BTN_EVENT_MOUSE: 206d522f475Smrg case ANY_EVENT_MOUSE: 207d522f475Smrg if (KeyModifiers == 0 || KeyModifiers == ControlMask) { 2082eaa94a1Schristos if (event->type == MotionNotify) { 2092eaa94a1Schristos ((XButtonEvent *) event)->button = 0; 2102eaa94a1Schristos } 211d522f475Smrg EditorButton(xw, (XButtonEvent *) event); 212d522f475Smrg return True; 213d522f475Smrg } 214d522f475Smrg return False; 215d522f475Smrg 216d522f475Smrg default: 217d522f475Smrg return False; 218d522f475Smrg } 219d522f475Smrg} 220d522f475Smrg 221d522f475Smrg#if OPT_DEC_LOCATOR 222d522f475Smrg 223d522f475Smrg#define LocatorCoords( row, col, x, y, oor ) \ 224d522f475Smrg if( screen->locator_pixels ) { \ 225d522f475Smrg (oor)=False; (row) = (y)+1; (col) = (x)+1; \ 226d522f475Smrg /* Limit to screen dimensions */ \ 227d522f475Smrg if ((row) < 1) (row) = 1,(oor)=True; \ 228d522f475Smrg else if ((row) > screen->border*2+Height(screen)) \ 229d522f475Smrg (row) = screen->border*2+Height(screen),(oor)=True; \ 230d522f475Smrg if ((col) < 1) (col) = 1,(oor)=True; \ 231d522f475Smrg else if ((col) > OriginX(screen)*2+Width(screen)) \ 232d522f475Smrg (col) = OriginX(screen)*2+Width(screen),(oor)=True; \ 233d522f475Smrg } else { \ 234d522f475Smrg (oor)=False; \ 235d522f475Smrg /* Compute character position of mouse pointer */ \ 236d522f475Smrg (row) = ((y) - screen->border) / FontHeight(screen); \ 237d522f475Smrg (col) = ((x) - OriginX(screen)) / FontWidth(screen); \ 238d522f475Smrg /* Limit to screen dimensions */ \ 239d522f475Smrg if ((row) < 0) (row) = 0,(oor)=True; \ 240d522f475Smrg else if ((row) > screen->max_row) \ 241d522f475Smrg (row) = screen->max_row,(oor)=True; \ 242d522f475Smrg if ((col) < 0) (col) = 0,(oor)=True; \ 243d522f475Smrg else if ((col) > screen->max_col) \ 244d522f475Smrg (col) = screen->max_col,(oor)=True; \ 245d522f475Smrg (row)++; (col)++; \ 246d522f475Smrg } 247d522f475Smrg 248d522f475Smrgstatic Bool 249d522f475SmrgSendLocatorPosition(XtermWidget xw, XEvent * event) 250d522f475Smrg{ 251d522f475Smrg ANSI reply; 252d522f475Smrg TScreen *screen = &(xw->screen); 253d522f475Smrg int row, col; 254d522f475Smrg Bool oor; 255d522f475Smrg int button; 2562eaa94a1Schristos unsigned state; 257d522f475Smrg 258d522f475Smrg /* Make sure the event is an appropriate type */ 259d522f475Smrg if ((event->type != ButtonPress && 260d522f475Smrg event->type != ButtonRelease && 261d522f475Smrg !screen->loc_filter) || 262d522f475Smrg (KeyModifiers != 0 && KeyModifiers != ControlMask)) 263d522f475Smrg return (False); 264d522f475Smrg 265d522f475Smrg if ((event->type == ButtonPress && 266d522f475Smrg !(screen->locator_events & LOC_BTNS_DN)) || 267d522f475Smrg (event->type == ButtonRelease && 268d522f475Smrg !(screen->locator_events & LOC_BTNS_UP))) 269d522f475Smrg return (True); 270d522f475Smrg 271d522f475Smrg if (event->type == MotionNotify) { 272d522f475Smrg CheckLocatorPosition(xw, event); 273d522f475Smrg return (True); 274d522f475Smrg } 275d522f475Smrg 276d522f475Smrg /* get button # */ 2772eaa94a1Schristos button = (int) event->xbutton.button - 1; 278d522f475Smrg 279d522f475Smrg LocatorCoords(row, col, event->xbutton.x, event->xbutton.y, oor); 280d522f475Smrg 281d522f475Smrg /* 282d522f475Smrg * DECterm mouse: 283d522f475Smrg * 284d522f475Smrg * ESCAPE '[' event ; mask ; row ; column '&' 'w' 285d522f475Smrg */ 286d522f475Smrg memset(&reply, 0, sizeof(reply)); 287d522f475Smrg reply.a_type = ANSI_CSI; 288d522f475Smrg 289d522f475Smrg if (oor) { 290d522f475Smrg reply.a_nparam = 1; 291d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 292d522f475Smrg reply.a_inters = '&'; 293d522f475Smrg reply.a_final = 'w'; 294d522f475Smrg unparseseq(xw, &reply); 295d522f475Smrg 296d522f475Smrg if (screen->locator_reset) { 297d522f475Smrg MotionOff(screen, xw); 298d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 299d522f475Smrg } 300d522f475Smrg return (True); 301d522f475Smrg } 302d522f475Smrg 303d522f475Smrg /* 304d522f475Smrg * event: 305d522f475Smrg * 1 no buttons 306d522f475Smrg * 2 left button down 307d522f475Smrg * 3 left button up 308d522f475Smrg * 4 middle button down 309d522f475Smrg * 5 middle button up 310d522f475Smrg * 6 right button down 311d522f475Smrg * 7 right button up 312d522f475Smrg * 8 M4 down 313d522f475Smrg * 9 M4 up 314d522f475Smrg */ 315d522f475Smrg reply.a_nparam = 4; 316d522f475Smrg switch (event->type) { 317d522f475Smrg case ButtonPress: 3182eaa94a1Schristos reply.a_param[0] = (ParmType) (2 + (button << 1)); 319d522f475Smrg break; 320d522f475Smrg case ButtonRelease: 3212eaa94a1Schristos reply.a_param[0] = (ParmType) (3 + (button << 1)); 322d522f475Smrg break; 323d522f475Smrg default: 324d522f475Smrg return (True); 325d522f475Smrg } 326d522f475Smrg /* 327d522f475Smrg * mask: 328d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 329d522f475Smrg * M4 down left down middle down right down 330d522f475Smrg * 331d522f475Smrg * Notice that Button1 (left) and Button3 (right) are swapped in the mask. 332d522f475Smrg * Also, mask should be the state after the button press/release, 333d522f475Smrg * X provides the state not including the button press/release. 334d522f475Smrg */ 335d522f475Smrg state = (event->xbutton.state 336d522f475Smrg & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8; 337d522f475Smrg state ^= 1 << button; /* update mask to "after" state */ 338d522f475Smrg state = (state & ~(4 | 1)) | ((state & 1) ? 4 : 0) | ((state & 4) ? 1 : 0); /* swap Button1 & Button3 */ 339d522f475Smrg 3402eaa94a1Schristos reply.a_param[1] = (ParmType) state; 3412eaa94a1Schristos reply.a_param[2] = (ParmType) row; 3422eaa94a1Schristos reply.a_param[3] = (ParmType) col; 343d522f475Smrg reply.a_inters = '&'; 344d522f475Smrg reply.a_final = 'w'; 345d522f475Smrg 346d522f475Smrg unparseseq(xw, &reply); 347d522f475Smrg 348d522f475Smrg if (screen->locator_reset) { 349d522f475Smrg MotionOff(screen, xw); 350d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 351d522f475Smrg } 352d522f475Smrg 353d522f475Smrg /* 354d522f475Smrg * DECterm turns the Locator off if a button is pressed while a filter rectangle 355d522f475Smrg * is active. This might be a bug, but I don't know, so I'll emulate it anyways. 356d522f475Smrg */ 357d522f475Smrg if (screen->loc_filter) { 358d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 359d522f475Smrg screen->loc_filter = False; 360d522f475Smrg screen->locator_events = 0; 361d522f475Smrg MotionOff(screen, xw); 362d522f475Smrg } 363d522f475Smrg 364d522f475Smrg return (True); 365d522f475Smrg} 366d522f475Smrg 367d522f475Smrg/* 368d522f475Smrg * mask: 369d522f475Smrg * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 370d522f475Smrg * M4 down left down middle down right down 371d522f475Smrg * 372d522f475Smrg * Button1 (left) and Button3 (right) are swapped in the mask relative to X. 373d522f475Smrg */ 374d522f475Smrg#define ButtonState(state, mask) \ 3752eaa94a1Schristos{ (state) = (int) (((mask) & (Button1Mask | Button2Mask | Button3Mask | Button4Mask)) >> 8); \ 376d522f475Smrg /* swap Button1 & Button3 */ \ 377d522f475Smrg (state) = ((state) & ~(4|1)) | (((state)&1)?4:0) | (((state)&4)?1:0); \ 378d522f475Smrg} 379d522f475Smrg 380d522f475Smrgvoid 381d522f475SmrgGetLocatorPosition(XtermWidget xw) 382d522f475Smrg{ 383d522f475Smrg ANSI reply; 384d522f475Smrg TScreen *screen = &xw->screen; 385d522f475Smrg Window root, child; 386d522f475Smrg int rx, ry, x, y; 387d522f475Smrg unsigned int mask; 388d522f475Smrg int row = 0, col = 0; 389d522f475Smrg Bool oor = False; 390d522f475Smrg Bool ret = False; 391d522f475Smrg int state; 392d522f475Smrg 393d522f475Smrg /* 394d522f475Smrg * DECterm turns the Locator off if the position is requested while a filter rectangle 395d522f475Smrg * is active. This might be a bug, but I don't know, so I'll emulate it anyways. 396d522f475Smrg */ 397d522f475Smrg if (screen->loc_filter) { 398d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 399d522f475Smrg screen->loc_filter = False; 400d522f475Smrg screen->locator_events = 0; 401d522f475Smrg MotionOff(screen, xw); 402d522f475Smrg } 403d522f475Smrg 404d522f475Smrg memset(&reply, 0, sizeof(reply)); 405d522f475Smrg reply.a_type = ANSI_CSI; 406d522f475Smrg 407d522f475Smrg if (screen->send_mouse_pos == DEC_LOCATOR) { 408d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), &root, 409d522f475Smrg &child, &rx, &ry, &x, &y, &mask); 410d522f475Smrg if (ret) { 411d522f475Smrg LocatorCoords(row, col, x, y, oor); 412d522f475Smrg } 413d522f475Smrg } 414d522f475Smrg if (ret == False || oor) { 415d522f475Smrg reply.a_nparam = 1; 416d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 417d522f475Smrg reply.a_inters = '&'; 418d522f475Smrg reply.a_final = 'w'; 419d522f475Smrg unparseseq(xw, &reply); 420d522f475Smrg 421d522f475Smrg if (screen->locator_reset) { 422d522f475Smrg MotionOff(screen, xw); 423d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 424d522f475Smrg } 425d522f475Smrg return; 426d522f475Smrg } 427d522f475Smrg 428d522f475Smrg ButtonState(state, mask); 429d522f475Smrg 430d522f475Smrg reply.a_nparam = 4; 431d522f475Smrg reply.a_param[0] = 1; /* Event - 1 = response to locator request */ 4322eaa94a1Schristos reply.a_param[1] = (ParmType) state; 4332eaa94a1Schristos reply.a_param[2] = (ParmType) row; 4342eaa94a1Schristos reply.a_param[3] = (ParmType) col; 435d522f475Smrg reply.a_inters = '&'; 436d522f475Smrg reply.a_final = 'w'; 437d522f475Smrg unparseseq(xw, &reply); 438d522f475Smrg 439d522f475Smrg if (screen->locator_reset) { 440d522f475Smrg MotionOff(screen, xw); 441d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 442d522f475Smrg } 443d522f475Smrg} 444d522f475Smrg 445d522f475Smrgvoid 446d522f475SmrgInitLocatorFilter(XtermWidget xw) 447d522f475Smrg{ 448d522f475Smrg ANSI reply; 449d522f475Smrg TScreen *screen = &xw->screen; 450d522f475Smrg Window root, child; 451d522f475Smrg int rx, ry, x, y; 452d522f475Smrg unsigned int mask; 453d522f475Smrg int row = 0, col = 0; 454d522f475Smrg Bool oor = 0; 455d522f475Smrg Bool ret; 456d522f475Smrg int state; 457d522f475Smrg 458d522f475Smrg ret = XQueryPointer(screen->display, VWindow(screen), 459d522f475Smrg &root, &child, &rx, &ry, &x, &y, &mask); 460d522f475Smrg if (ret) { 461d522f475Smrg LocatorCoords(row, col, x, y, oor); 462d522f475Smrg } 463d522f475Smrg if (ret == False || oor) { 464d522f475Smrg /* Locator is unavailable */ 465d522f475Smrg 466d522f475Smrg if (screen->loc_filter_top != LOC_FILTER_POS || 467d522f475Smrg screen->loc_filter_left != LOC_FILTER_POS || 468d522f475Smrg screen->loc_filter_bottom != LOC_FILTER_POS || 469d522f475Smrg screen->loc_filter_right != LOC_FILTER_POS) { 470d522f475Smrg /* 471d522f475Smrg * If any explicit coordinates were received, 472d522f475Smrg * report immediately with no coordinates. 473d522f475Smrg */ 474d522f475Smrg memset(&reply, 0, sizeof(reply)); 475d522f475Smrg reply.a_type = ANSI_CSI; 476d522f475Smrg reply.a_nparam = 1; 477d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 478d522f475Smrg reply.a_inters = '&'; 479d522f475Smrg reply.a_final = 'w'; 480d522f475Smrg unparseseq(xw, &reply); 481d522f475Smrg 482d522f475Smrg if (screen->locator_reset) { 483d522f475Smrg MotionOff(screen, xw); 484d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 485d522f475Smrg } 486d522f475Smrg } else { 487d522f475Smrg /* 488d522f475Smrg * No explicit coordinates were received, and the pointer is 489d522f475Smrg * unavailable. Report when the pointer re-enters the window. 490d522f475Smrg */ 491d522f475Smrg screen->loc_filter = True; 492d522f475Smrg MotionOn(screen, xw); 493d522f475Smrg } 494d522f475Smrg return; 495d522f475Smrg } 496d522f475Smrg 497d522f475Smrg /* 498d522f475Smrg * Adjust rectangle coordinates: 499d522f475Smrg * 1. Replace "LOC_FILTER_POS" with current coordinates 500d522f475Smrg * 2. Limit coordinates to screen size 501d522f475Smrg * 3. make sure top and left are less than bottom and right, resp. 502d522f475Smrg */ 503d522f475Smrg if (screen->locator_pixels) { 504d522f475Smrg rx = OriginX(screen) * 2 + Width(screen); 505d522f475Smrg ry = screen->border * 2 + Height(screen); 506d522f475Smrg } else { 507d522f475Smrg rx = screen->max_col; 508d522f475Smrg ry = screen->max_row; 509d522f475Smrg } 510d522f475Smrg 511d522f475Smrg#define Adjust( coord, def, max ) \ 512d522f475Smrg if( (coord) == LOC_FILTER_POS ) (coord) = (def); \ 513d522f475Smrg else if ((coord) < 1) (coord) = 1; \ 514d522f475Smrg else if ((coord) > (max)) (coord) = (max) 515d522f475Smrg 516d522f475Smrg Adjust(screen->loc_filter_top, row, ry); 517d522f475Smrg Adjust(screen->loc_filter_left, col, rx); 518d522f475Smrg Adjust(screen->loc_filter_bottom, row, ry); 519d522f475Smrg Adjust(screen->loc_filter_right, col, rx); 520d522f475Smrg 521d522f475Smrg if (screen->loc_filter_top > screen->loc_filter_bottom) { 522d522f475Smrg ry = screen->loc_filter_top; 523d522f475Smrg screen->loc_filter_top = screen->loc_filter_bottom; 524d522f475Smrg screen->loc_filter_bottom = ry; 525d522f475Smrg } 526d522f475Smrg 527d522f475Smrg if (screen->loc_filter_left > screen->loc_filter_right) { 528d522f475Smrg rx = screen->loc_filter_left; 529d522f475Smrg screen->loc_filter_left = screen->loc_filter_right; 530d522f475Smrg screen->loc_filter_right = rx; 531d522f475Smrg } 532d522f475Smrg 533d522f475Smrg if ((col < screen->loc_filter_left) || 534d522f475Smrg (col > screen->loc_filter_right) || 535d522f475Smrg (row < screen->loc_filter_top) || 536d522f475Smrg (row > screen->loc_filter_bottom)) { 537d522f475Smrg /* Pointer is already outside the rectangle - report immediately */ 538d522f475Smrg ButtonState(state, mask); 539d522f475Smrg 540d522f475Smrg memset(&reply, 0, sizeof(reply)); 541d522f475Smrg reply.a_type = ANSI_CSI; 542d522f475Smrg reply.a_nparam = 4; 543d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 5442eaa94a1Schristos reply.a_param[1] = (ParmType) state; 5452eaa94a1Schristos reply.a_param[2] = (ParmType) row; 5462eaa94a1Schristos reply.a_param[3] = (ParmType) col; 547d522f475Smrg reply.a_inters = '&'; 548d522f475Smrg reply.a_final = 'w'; 549d522f475Smrg unparseseq(xw, &reply); 550d522f475Smrg 551d522f475Smrg if (screen->locator_reset) { 552d522f475Smrg MotionOff(screen, xw); 553d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 554d522f475Smrg } 555d522f475Smrg return; 556d522f475Smrg } 557d522f475Smrg 558d522f475Smrg /* 559d522f475Smrg * Rectangle is set up. Allow pointer tracking 560d522f475Smrg * to detect if the mouse leaves the rectangle. 561d522f475Smrg */ 562d522f475Smrg screen->loc_filter = True; 563d522f475Smrg MotionOn(screen, xw); 564d522f475Smrg} 565d522f475Smrg 566d522f475Smrgstatic void 567d522f475SmrgCheckLocatorPosition(XtermWidget xw, XEvent * event) 568d522f475Smrg{ 569d522f475Smrg ANSI reply; 570d522f475Smrg TScreen *screen = &(xw->screen); 571d522f475Smrg int row, col; 572d522f475Smrg Bool oor; 573d522f475Smrg int state; 574d522f475Smrg 575d522f475Smrg LocatorCoords(row, col, event->xbutton.x, event->xbutton.y, oor); 576d522f475Smrg 577d522f475Smrg /* 578d522f475Smrg * Send report if the pointer left the filter rectangle, if 579d522f475Smrg * the pointer left the window, or if the filter rectangle 580d522f475Smrg * had no coordinates and the pointer re-entered the window. 581d522f475Smrg */ 582d522f475Smrg if (oor || (screen->loc_filter_top == LOC_FILTER_POS) || 583d522f475Smrg (col < screen->loc_filter_left) || 584d522f475Smrg (col > screen->loc_filter_right) || 585d522f475Smrg (row < screen->loc_filter_top) || 586d522f475Smrg (row > screen->loc_filter_bottom)) { 587d522f475Smrg /* Filter triggered - disable it */ 588d522f475Smrg screen->loc_filter = False; 589d522f475Smrg MotionOff(screen, xw); 590d522f475Smrg 591d522f475Smrg memset(&reply, 0, sizeof(reply)); 592d522f475Smrg reply.a_type = ANSI_CSI; 593d522f475Smrg if (oor) { 594d522f475Smrg reply.a_nparam = 1; 595d522f475Smrg reply.a_param[0] = 0; /* Event - 0 = locator unavailable */ 596d522f475Smrg } else { 597d522f475Smrg ButtonState(state, event->xbutton.state); 598d522f475Smrg 599d522f475Smrg reply.a_nparam = 4; 600d522f475Smrg reply.a_param[0] = 10; /* Event - 10 = locator outside filter */ 6012eaa94a1Schristos reply.a_param[1] = (ParmType) state; 6022eaa94a1Schristos reply.a_param[2] = (ParmType) row; 6032eaa94a1Schristos reply.a_param[3] = (ParmType) col; 604d522f475Smrg } 605d522f475Smrg 606d522f475Smrg reply.a_inters = '&'; 607d522f475Smrg reply.a_final = 'w'; 608d522f475Smrg unparseseq(xw, &reply); 609d522f475Smrg 610d522f475Smrg if (screen->locator_reset) { 611d522f475Smrg MotionOff(screen, xw); 612d522f475Smrg screen->send_mouse_pos = MOUSE_OFF; 613d522f475Smrg } 614d522f475Smrg } 615d522f475Smrg} 616d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 617d522f475Smrg 618d522f475Smrg#if OPT_READLINE 619d522f475Smrgstatic int 620d522f475SmrgisClick1_clean(TScreen * screen, XEvent * event) 621d522f475Smrg{ 622d522f475Smrg int delta; 623d522f475Smrg 624d522f475Smrg if (!(event->type == ButtonPress || event->type == ButtonRelease) 625d522f475Smrg /* Disable on Shift-Click-1, including the application-mouse modes */ 626d522f475Smrg || (KeyModifiers & ShiftMask) 627d522f475Smrg || (screen->send_mouse_pos != MOUSE_OFF) /* Kinda duplicate... */ 628d522f475Smrg ||ExtendingSelection) /* Was moved */ 629d522f475Smrg return 0; 630d522f475Smrg 631d522f475Smrg if (event->type != ButtonRelease) 632d522f475Smrg return 0; 633d522f475Smrg 634d522f475Smrg if (lastButtonDownTime == (Time) 0) { 635d522f475Smrg /* first time or once in a blue moon */ 636d522f475Smrg delta = screen->multiClickTime + 1; 637d522f475Smrg } else if (event->xbutton.time > lastButtonDownTime) { 638d522f475Smrg /* most of the time */ 6392eaa94a1Schristos delta = (int) (event->xbutton.time - lastButtonDownTime); 640d522f475Smrg } else { 641d522f475Smrg /* time has rolled over since lastButtonUpTime */ 6422eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time); 643d522f475Smrg } 644d522f475Smrg 645d522f475Smrg return delta <= screen->multiClickTime; 646d522f475Smrg} 647d522f475Smrg 648d522f475Smrgstatic int 649d522f475SmrgisDoubleClick3(TScreen * screen, XEvent * event) 650d522f475Smrg{ 651d522f475Smrg int delta; 652d522f475Smrg 653d522f475Smrg if (event->type != ButtonRelease 654d522f475Smrg || (KeyModifiers & ShiftMask) 655d522f475Smrg || event->xbutton.button != Button3) { 656d522f475Smrg lastButton3UpTime = 0; /* Disable the cached info */ 657d522f475Smrg return 0; 658d522f475Smrg } 659d522f475Smrg /* Process Btn3Release. */ 660d522f475Smrg if (lastButton3DoubleDownTime == (Time) 0) { 661d522f475Smrg /* No previous click or once in a blue moon */ 662d522f475Smrg delta = screen->multiClickTime + 1; 663d522f475Smrg } else if (event->xbutton.time > lastButton3DoubleDownTime) { 664d522f475Smrg /* most of the time */ 6652eaa94a1Schristos delta = (int) (event->xbutton.time - lastButton3DoubleDownTime); 666d522f475Smrg } else { 667d522f475Smrg /* time has rolled over since lastButton3DoubleDownTime */ 6682eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButton3DoubleDownTime) + event->xbutton.time); 669d522f475Smrg } 670d522f475Smrg if (delta <= screen->multiClickTime) { 671d522f475Smrg /* Double click */ 672d522f475Smrg CELL cell; 673d522f475Smrg 674d522f475Smrg /* Cannot check ExtendingSelection, since mouse-3 always sets it */ 675d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 676d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 677d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the third click */ 678d522f475Smrg return 1; 679d522f475Smrg } 680d522f475Smrg } 681d522f475Smrg /* Not a double click, memorize for future check. */ 682d522f475Smrg lastButton3UpTime = event->xbutton.time; 683d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &lastButton3); 684d522f475Smrg return 0; 685d522f475Smrg} 686d522f475Smrg 687d522f475Smrgstatic int 688d522f475SmrgCheckSecondPress3(TScreen * screen, XEvent * event) 689d522f475Smrg{ 690d522f475Smrg int delta; 691d522f475Smrg 692d522f475Smrg if (event->type != ButtonPress 693d522f475Smrg || (KeyModifiers & ShiftMask) 694d522f475Smrg || event->xbutton.button != Button3) { 695d522f475Smrg lastButton3DoubleDownTime = 0; /* Disable the cached info */ 696d522f475Smrg return 0; 697d522f475Smrg } 698d522f475Smrg /* Process Btn3Press. */ 699d522f475Smrg if (lastButton3UpTime == (Time) 0) { 700d522f475Smrg /* No previous click or once in a blue moon */ 701d522f475Smrg delta = screen->multiClickTime + 1; 702d522f475Smrg } else if (event->xbutton.time > lastButton3UpTime) { 703d522f475Smrg /* most of the time */ 7042eaa94a1Schristos delta = (int) (event->xbutton.time - lastButton3UpTime); 705d522f475Smrg } else { 706d522f475Smrg /* time has rolled over since lastButton3UpTime */ 7072eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButton3UpTime) + event->xbutton.time); 708d522f475Smrg } 709d522f475Smrg if (delta <= screen->multiClickTime) { 710d522f475Smrg CELL cell; 711d522f475Smrg 712d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 713d522f475Smrg if (isSameCELL(&cell, &lastButton3)) { 714d522f475Smrg /* A candidate for a double-click */ 715d522f475Smrg lastButton3DoubleDownTime = event->xbutton.time; 716d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &lastButton3); 717d522f475Smrg return 1; 718d522f475Smrg } 719d522f475Smrg lastButton3UpTime = 0; /* Disable the info about the previous click */ 720d522f475Smrg } 721d522f475Smrg /* Either too long, or moved, disable. */ 722d522f475Smrg lastButton3DoubleDownTime = 0; 723d522f475Smrg return 0; 724d522f475Smrg} 725d522f475Smrg 726d522f475Smrgstatic int 727d522f475SmrgrowOnCurrentLine(TScreen * screen, 728d522f475Smrg int line, 729d522f475Smrg int *deltap) /* must be XButtonEvent */ 730d522f475Smrg{ 731d522f475Smrg int l1, l2; 732d522f475Smrg 733d522f475Smrg *deltap = 0; 734d522f475Smrg if (line == screen->cur_row) 735d522f475Smrg return 1; 736d522f475Smrg 737d522f475Smrg if (line < screen->cur_row) 738d522f475Smrg l1 = line, l2 = screen->cur_row; 739d522f475Smrg else 740d522f475Smrg l2 = line, l1 = screen->cur_row; 741d522f475Smrg l1--; 742d522f475Smrg while (++l1 < l2) 743d522f475Smrg if (!ScrnTstWrapped(screen, l1)) 744d522f475Smrg return 0; 745d522f475Smrg /* Everything is on one "wrapped line" now */ 746d522f475Smrg *deltap = line - screen->cur_row; 747d522f475Smrg return 1; 748d522f475Smrg} 749d522f475Smrg 750d522f475Smrgstatic int 751d522f475SmrgeventRow(TScreen * screen, XEvent * event) /* must be XButtonEvent */ 752d522f475Smrg{ 753d522f475Smrg return (event->xbutton.y - screen->border) / FontHeight(screen); 754d522f475Smrg} 755d522f475Smrg 756d522f475Smrgstatic int 757d522f475SmrgeventColBetween(TScreen * screen, XEvent * event) /* must be XButtonEvent */ 758d522f475Smrg{ 759d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 760d522f475Smrg return ((event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) / 2) 761d522f475Smrg / FontWidth(screen)); 762d522f475Smrg} 763d522f475Smrg 764d522f475Smrgstatic int 765d522f475SmrgReadLineMovePoint(TScreen * screen, int col, int ldelta) 766d522f475Smrg{ 767d522f475Smrg Char line[6]; 768d522f475Smrg unsigned count = 0; 769d522f475Smrg 770d522f475Smrg col += ldelta * MaxCols(screen) - screen->cur_col; 771d522f475Smrg if (col == 0) 772d522f475Smrg return 0; 773d522f475Smrg if (screen->control_eight_bits) { 774d522f475Smrg line[count++] = ANSI_CSI; 775d522f475Smrg } else { 776d522f475Smrg line[count++] = ANSI_ESC; 777d522f475Smrg line[count++] = '['; /* XXX maybe sometimes O is better? */ 778d522f475Smrg } 7792eaa94a1Schristos line[count++] = CharOf(col > 0 ? 'C' : 'D'); 780d522f475Smrg if (col < 0) 781d522f475Smrg col = -col; 782d522f475Smrg while (col--) 783d522f475Smrg v_write(screen->respond, line, 3); 784d522f475Smrg return 1; 785d522f475Smrg} 786d522f475Smrg 787d522f475Smrgstatic int 788d522f475SmrgReadLineDelete(TScreen * screen, CELL * cell1, CELL * cell2) 789d522f475Smrg{ 790d522f475Smrg int del; 791d522f475Smrg 792d522f475Smrg del = (cell2->col - cell1->col) + ((cell2->row - cell1->row) * MaxCols(screen)); 793d522f475Smrg if (del <= 0) /* Just in case... */ 794d522f475Smrg return 0; 795d522f475Smrg while (del--) 796d522f475Smrg v_write(screen->respond, (Char *) "\177", 1); 797d522f475Smrg return 1; 798d522f475Smrg} 799d522f475Smrg#endif /* OPT_READLINE */ 800d522f475Smrg 801d522f475Smrg/* ^XM-G<line+' '><col+' '> */ 802d522f475Smrgvoid 803d522f475SmrgDiredButton(Widget w, 804d522f475Smrg XEvent * event, /* must be XButtonEvent */ 805d522f475Smrg String * params GCC_UNUSED, /* selections */ 806d522f475Smrg Cardinal *num_params GCC_UNUSED) 807d522f475Smrg{ 808d522f475Smrg if (IsXtermWidget(w)) { 809d522f475Smrg XtermWidget xw = (XtermWidget) w; 810d522f475Smrg TScreen *screen = &(xw->screen); 811d522f475Smrg Char Line[6]; 812d522f475Smrg unsigned line, col; 813d522f475Smrg 8142eaa94a1Schristos if ((event->type == ButtonPress || event->type == ButtonRelease) 8152eaa94a1Schristos && (event->xbutton.y >= screen->border) 8162eaa94a1Schristos && (event->xbutton.x >= OriginX(screen))) { 8172eaa94a1Schristos line = ((unsigned) (event->xbutton.y - screen->border) 8182eaa94a1Schristos / FontHeight(screen)); 8192eaa94a1Schristos col = ((unsigned) (event->xbutton.x - OriginX(screen)) 8202eaa94a1Schristos / FontWidth(screen)); 821d522f475Smrg Line[0] = CONTROL('X'); 822d522f475Smrg Line[1] = ANSI_ESC; 823d522f475Smrg Line[2] = 'G'; 8242eaa94a1Schristos Line[3] = CharOf(' ' + col); 8252eaa94a1Schristos Line[4] = CharOf(' ' + line); 826d522f475Smrg v_write(screen->respond, Line, 5); 827d522f475Smrg } 828d522f475Smrg } 829d522f475Smrg} 830d522f475Smrg 831d522f475Smrg#if OPT_READLINE 832d522f475Smrgvoid 833d522f475SmrgReadLineButton(Widget w, 834d522f475Smrg XEvent * event, /* must be XButtonEvent */ 835d522f475Smrg String * params GCC_UNUSED, /* selections */ 836d522f475Smrg Cardinal *num_params GCC_UNUSED) 837d522f475Smrg{ 838d522f475Smrg if (IsXtermWidget(w)) { 839d522f475Smrg XtermWidget xw = (XtermWidget) w; 840d522f475Smrg TScreen *screen = &(xw->screen); 841d522f475Smrg Char Line[6]; 842d522f475Smrg int line, col, ldelta = 0; 843d522f475Smrg 844d522f475Smrg if (!(event->type == ButtonPress || event->type == ButtonRelease) 845d522f475Smrg || (screen->send_mouse_pos != MOUSE_OFF) || ExtendingSelection) 846d522f475Smrg goto finish; 847d522f475Smrg if (event->type == ButtonRelease) { 848d522f475Smrg int delta; 849d522f475Smrg 850d522f475Smrg if (lastButtonDownTime == (Time) 0) { 851d522f475Smrg /* first time and once in a blue moon */ 852d522f475Smrg delta = screen->multiClickTime + 1; 853d522f475Smrg } else if (event->xbutton.time > lastButtonDownTime) { 854d522f475Smrg /* most of the time */ 8552eaa94a1Schristos delta = (int) (event->xbutton.time - lastButtonDownTime); 856d522f475Smrg } else { 857d522f475Smrg /* time has rolled over since lastButtonUpTime */ 8582eaa94a1Schristos delta = (int) ((((Time) ~ 0) - lastButtonDownTime) + event->xbutton.time); 859d522f475Smrg } 860d522f475Smrg if (delta > screen->multiClickTime) 861d522f475Smrg goto finish; /* All this work for this... */ 862d522f475Smrg } 863d522f475Smrg line = (event->xbutton.y - screen->border) / FontHeight(screen); 864d522f475Smrg if (line != screen->cur_row) { 865d522f475Smrg int l1, l2; 866d522f475Smrg 867d522f475Smrg if (line < screen->cur_row) 868d522f475Smrg l1 = line, l2 = screen->cur_row; 869d522f475Smrg else 870d522f475Smrg l2 = line, l1 = screen->cur_row; 871d522f475Smrg l1--; 872d522f475Smrg while (++l1 < l2) 873d522f475Smrg if (!ScrnTstWrapped(screen, l1)) 874d522f475Smrg goto finish; 875d522f475Smrg /* Everything is on one "wrapped line" now */ 876d522f475Smrg ldelta = line - screen->cur_row; 877d522f475Smrg } 878d522f475Smrg /* Correct by half a width - we are acting on a boundary, not on a cell. */ 879d522f475Smrg col = (event->xbutton.x - OriginX(screen) + (FontWidth(screen) - 1) 880d522f475Smrg / 2) 881d522f475Smrg / FontWidth(screen) - screen->cur_col + ldelta * MaxCols(screen); 882d522f475Smrg if (col == 0) 883d522f475Smrg goto finish; 884d522f475Smrg Line[0] = ANSI_ESC; 885d522f475Smrg /* XXX: sometimes it is better to send '['? */ 886d522f475Smrg Line[1] = 'O'; 8872eaa94a1Schristos Line[2] = CharOf(col > 0 ? 'C' : 'D'); 888d522f475Smrg if (col < 0) 889d522f475Smrg col = -col; 890d522f475Smrg while (col--) 891d522f475Smrg v_write(screen->respond, Line, 3); 892d522f475Smrg finish: 893d522f475Smrg if (event->type == ButtonRelease) 894d522f475Smrg do_select_end(xw, event, params, num_params, False); 895d522f475Smrg } 896d522f475Smrg} 897d522f475Smrg#endif /* OPT_READLINE */ 898d522f475Smrg 899d522f475Smrg/* repeats <ESC>n or <ESC>p */ 900d522f475Smrgvoid 901d522f475SmrgViButton(Widget w, 902d522f475Smrg XEvent * event, /* must be XButtonEvent */ 903d522f475Smrg String * params GCC_UNUSED, /* selections */ 904d522f475Smrg Cardinal *num_params GCC_UNUSED) 905d522f475Smrg{ 906d522f475Smrg if (IsXtermWidget(w)) { 907d522f475Smrg XtermWidget xw = (XtermWidget) w; 908d522f475Smrg TScreen *screen = &(xw->screen); 909d522f475Smrg int pty = screen->respond; 910d522f475Smrg Char Line[6]; 911d522f475Smrg int line; 912d522f475Smrg 913d522f475Smrg if (event->type == ButtonPress || event->type == ButtonRelease) { 914d522f475Smrg 915d522f475Smrg line = screen->cur_row - 916d522f475Smrg ((event->xbutton.y - screen->border) / FontHeight(screen)); 917d522f475Smrg if (line != 0) { 918d522f475Smrg Line[0] = ANSI_ESC; /* force an exit from insert-mode */ 919d522f475Smrg v_write(pty, Line, 1); 920d522f475Smrg 921d522f475Smrg if (line < 0) { 922d522f475Smrg line = -line; 923d522f475Smrg Line[0] = CONTROL('n'); 924d522f475Smrg } else { 925d522f475Smrg Line[0] = CONTROL('p'); 926d522f475Smrg } 927d522f475Smrg while (--line >= 0) 928d522f475Smrg v_write(pty, Line, 1); 929d522f475Smrg } 930d522f475Smrg } 931d522f475Smrg } 932d522f475Smrg} 933d522f475Smrg 934d522f475Smrg/* 935d522f475Smrg * This function handles button-motion events 936d522f475Smrg */ 937d522f475Smrg/*ARGSUSED*/ 938d522f475Smrgvoid 939d522f475SmrgHandleSelectExtend(Widget w, 940d522f475Smrg XEvent * event, /* must be XMotionEvent */ 941d522f475Smrg String * params GCC_UNUSED, 942d522f475Smrg Cardinal *num_params GCC_UNUSED) 943d522f475Smrg{ 944d522f475Smrg if (IsXtermWidget(w)) { 945d522f475Smrg XtermWidget xw = (XtermWidget) w; 946d522f475Smrg TScreen *screen = &(xw->screen); 947d522f475Smrg CELL cell; 948d522f475Smrg 949d522f475Smrg screen->selection_time = event->xmotion.time; 950d522f475Smrg switch (screen->eventMode) { 951d522f475Smrg /* If not in one of the DEC mouse-reporting modes */ 952d522f475Smrg case LEFTEXTENSION: 953d522f475Smrg case RIGHTEXTENSION: 954d522f475Smrg PointToCELL(screen, event->xmotion.y, event->xmotion.x, &cell); 955d522f475Smrg ExtendExtend(xw, &cell); 956d522f475Smrg break; 957d522f475Smrg 958d522f475Smrg /* If in motion reporting mode, send mouse position to 959d522f475Smrg character process as a key sequence \E[M... */ 960d522f475Smrg case NORMAL: 961d522f475Smrg /* will get here if send_mouse_pos != MOUSE_OFF */ 962d522f475Smrg if (screen->send_mouse_pos == BTN_EVENT_MOUSE 963d522f475Smrg || screen->send_mouse_pos == ANY_EVENT_MOUSE) { 964d522f475Smrg (void) SendMousePosition(xw, event); 965d522f475Smrg } 966d522f475Smrg break; 967d522f475Smrg } 968d522f475Smrg } 969d522f475Smrg} 970d522f475Smrg 971d522f475Smrgvoid 972d522f475SmrgHandleKeyboardSelectExtend(Widget w, 973d522f475Smrg XEvent * event GCC_UNUSED, /* must be XButtonEvent */ 974d522f475Smrg String * params GCC_UNUSED, 975d522f475Smrg Cardinal *num_params GCC_UNUSED) 976d522f475Smrg{ 977d522f475Smrg if (IsXtermWidget(w)) { 978d522f475Smrg XtermWidget xw = (XtermWidget) w; 979d522f475Smrg TScreen *screen = &xw->screen; 980d522f475Smrg ExtendExtend(xw, &screen->cursorp); 981d522f475Smrg } 982d522f475Smrg} 983d522f475Smrg 984d522f475Smrgstatic void 985d522f475Smrgdo_select_end(XtermWidget xw, 986d522f475Smrg XEvent * event, /* must be XButtonEvent */ 987d522f475Smrg String * params, /* selections */ 988d522f475Smrg Cardinal *num_params, 989d522f475Smrg Bool use_cursor_loc) 990d522f475Smrg{ 991d522f475Smrg#if OPT_READLINE 992d522f475Smrg int ldelta1, ldelta2; 993d522f475Smrg#endif 994d522f475Smrg TScreen *screen = &xw->screen; 995d522f475Smrg 996d522f475Smrg screen->selection_time = event->xbutton.time; 997d522f475Smrg switch (screen->eventMode) { 998d522f475Smrg case NORMAL: 999d522f475Smrg (void) SendMousePosition(xw, event); 1000d522f475Smrg break; 1001d522f475Smrg case LEFTEXTENSION: 1002d522f475Smrg case RIGHTEXTENSION: 1003d522f475Smrg EndExtend(xw, event, params, *num_params, use_cursor_loc); 1004d522f475Smrg#if OPT_READLINE 1005d522f475Smrg if (isClick1_clean(screen, event) 1006d522f475Smrg && SCREEN_FLAG(screen, click1_moves) 1007d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta1)) { 1008d522f475Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta1); 1009d522f475Smrg } 1010d522f475Smrg if (isDoubleClick3(screen, event) 1011d522f475Smrg && SCREEN_FLAG(screen, dclick3_deletes) 1012d522f475Smrg && rowOnCurrentLine(screen, screen->startSel.row, &ldelta1) 1013d522f475Smrg && rowOnCurrentLine(screen, screen->endSel.row, &ldelta2)) { 1014d522f475Smrg ReadLineMovePoint(screen, screen->endSel.col, ldelta2); 1015d522f475Smrg ReadLineDelete(screen, &screen->startSel, &(screen->endSel)); 1016d522f475Smrg } 1017d522f475Smrg#endif /* OPT_READLINE */ 1018d522f475Smrg break; 1019d522f475Smrg } 1020d522f475Smrg} 1021d522f475Smrg 1022d522f475Smrgvoid 1023d522f475SmrgHandleSelectEnd(Widget w, 1024d522f475Smrg XEvent * event, /* must be XButtonEvent */ 1025d522f475Smrg String * params, /* selections */ 1026d522f475Smrg Cardinal *num_params) 1027d522f475Smrg{ 1028d522f475Smrg if (IsXtermWidget(w)) 1029d522f475Smrg do_select_end((XtermWidget) w, event, params, num_params, False); 1030d522f475Smrg} 1031d522f475Smrg 1032d522f475Smrgvoid 1033d522f475SmrgHandleKeyboardSelectEnd(Widget w, 1034d522f475Smrg XEvent * event, /* must be XButtonEvent */ 1035d522f475Smrg String * params, /* selections */ 1036d522f475Smrg Cardinal *num_params) 1037d522f475Smrg{ 1038d522f475Smrg if (IsXtermWidget(w)) 1039d522f475Smrg do_select_end((XtermWidget) w, event, params, num_params, True); 1040d522f475Smrg} 1041d522f475Smrg 1042d522f475Smrgstruct _SelectionList { 1043d522f475Smrg String *params; 1044d522f475Smrg Cardinal count; 1045d522f475Smrg Atom *targets; 1046d522f475Smrg Time time; 1047d522f475Smrg}; 1048d522f475Smrg 1049d522f475Smrgstatic unsigned 1050d522f475SmrgDECtoASCII(unsigned ch) 1051d522f475Smrg{ 1052d522f475Smrg if (xtermIsDecGraphic(ch)) { 10532eaa94a1Schristos ch = CharOf("###########+++++##-##++++|######"[ch]); 10542eaa94a1Schristos /* 01234567890123456789012345678901 */ 1055d522f475Smrg } 1056d522f475Smrg return ch; 1057d522f475Smrg} 1058d522f475Smrg/* 1059d522f475Smrg * Convert a UTF-8 string to Latin-1, replacing non Latin-1 characters by `#', 1060d522f475Smrg * or ASCII/Latin-1 equivalents for special cases. 1061d522f475Smrg */ 1062d522f475Smrg#if OPT_WIDE_CHARS 1063d522f475Smrgstatic Char * 1064d522f475SmrgUTF8toLatin1(Char * s, unsigned len, unsigned long *result) 1065d522f475Smrg{ 1066d522f475Smrg static Char *buffer; 1067d522f475Smrg static size_t used; 1068d522f475Smrg 1069d522f475Smrg Char *q; 1070d522f475Smrg 1071d522f475Smrg if (used == 0) { 1072d522f475Smrg buffer = (Char *) XtMalloc(1 + (used = len)); 1073d522f475Smrg } else if (len > used) { 1074d522f475Smrg buffer = (Char *) XtRealloc((char *) buffer, 1 + (used = len)); 1075d522f475Smrg } 1076d522f475Smrg 1077d522f475Smrg if (buffer != 0) { 1078d522f475Smrg PtyData data; 1079d522f475Smrg 1080d522f475Smrg q = buffer; 1081d522f475Smrg fakePtyData(&data, s, s + len); 1082d522f475Smrg while (decodeUtf8(&data)) { 1083d522f475Smrg IChar value = skipPtyData(&data); 1084d522f475Smrg if (value == UCS_REPL) { 1085d522f475Smrg *q++ = '#'; 1086d522f475Smrg } else if (value < 256) { 10872eaa94a1Schristos *q++ = CharOf(value); 1088d522f475Smrg } else { 1089d522f475Smrg unsigned eqv = ucs2dec(value); 1090d522f475Smrg if (xtermIsDecGraphic(eqv)) { 10912eaa94a1Schristos *q++ = (Char) DECtoASCII(eqv); 1092d522f475Smrg } else { 1093d522f475Smrg eqv = AsciiEquivs(value); 1094d522f475Smrg if (eqv == value) 1095d522f475Smrg eqv = '#'; 10962eaa94a1Schristos *q++ = (Char) eqv; 1097d522f475Smrg if (iswide((wchar_t) value)) 1098d522f475Smrg *q++ = ' '; 1099d522f475Smrg } 1100d522f475Smrg } 1101d522f475Smrg } 1102d522f475Smrg *q = 0; 11032eaa94a1Schristos *result = (unsigned long) (q - buffer); 1104d522f475Smrg } else { 1105d522f475Smrg *result = 0; 1106d522f475Smrg } 1107d522f475Smrg return buffer; 1108d522f475Smrg} 1109d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1110d522f475Smrg 1111d522f475Smrgstatic Atom * 1112d522f475Smrg_SelectionTargets(Widget w) 1113d522f475Smrg{ 1114d522f475Smrg static Atom *eightBitSelectionTargets = NULL; 1115d522f475Smrg TScreen *screen; 1116d522f475Smrg int n; 1117d522f475Smrg 1118d522f475Smrg if (!IsXtermWidget(w)) 1119d522f475Smrg return NULL; 1120d522f475Smrg 1121d522f475Smrg screen = TScreenOf((XtermWidget) w); 1122d522f475Smrg 1123d522f475Smrg#if OPT_WIDE_CHARS 1124d522f475Smrg if (screen->wide_chars) { 1125d522f475Smrg static Atom *utf8SelectionTargets = NULL; 1126d522f475Smrg 1127d522f475Smrg if (utf8SelectionTargets == NULL) { 1128d522f475Smrg utf8SelectionTargets = (Atom *) XtMalloc(5 * sizeof(Atom)); 1129d522f475Smrg if (utf8SelectionTargets == NULL) { 1130d522f475Smrg TRACE(("Couldn't allocate utf8SelectionTargets\n")); 1131d522f475Smrg return NULL; 1132d522f475Smrg } 1133d522f475Smrg n = 0; 1134d522f475Smrg utf8SelectionTargets[n++] = XA_UTF8_STRING(XtDisplay(w)); 1135d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1136d522f475Smrg if (screen->i18nSelections) { 1137d522f475Smrg utf8SelectionTargets[n++] = XA_TEXT(XtDisplay(w)); 1138d522f475Smrg utf8SelectionTargets[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1139d522f475Smrg } 1140d522f475Smrg#endif 1141d522f475Smrg utf8SelectionTargets[n++] = XA_STRING; 1142d522f475Smrg utf8SelectionTargets[n] = None; 1143d522f475Smrg } 1144d522f475Smrg return utf8SelectionTargets; 1145d522f475Smrg } 1146d522f475Smrg#endif 1147d522f475Smrg 1148d522f475Smrg /* not screen->wide_chars */ 1149d522f475Smrg if (eightBitSelectionTargets == NULL) { 1150d522f475Smrg eightBitSelectionTargets = (Atom *) XtMalloc(5 * sizeof(Atom)); 1151d522f475Smrg if (eightBitSelectionTargets == NULL) { 1152d522f475Smrg TRACE(("Couldn't allocate eightBitSelectionTargets\n")); 1153d522f475Smrg return NULL; 1154d522f475Smrg } 1155d522f475Smrg n = 0; 1156d522f475Smrg#ifdef X_HAVE_UTF8_STRING 1157d522f475Smrg eightBitSelectionTargets[n++] = XA_UTF8_STRING(XtDisplay(w)); 1158d522f475Smrg#endif 1159d522f475Smrg if (screen->i18nSelections) { 1160d522f475Smrg eightBitSelectionTargets[n++] = XA_TEXT(XtDisplay(w)); 1161d522f475Smrg eightBitSelectionTargets[n++] = XA_COMPOUND_TEXT(XtDisplay(w)); 1162d522f475Smrg } 1163d522f475Smrg eightBitSelectionTargets[n++] = XA_STRING; 1164d522f475Smrg eightBitSelectionTargets[n] = None; 1165d522f475Smrg } 1166d522f475Smrg return eightBitSelectionTargets; 1167d522f475Smrg} 1168d522f475Smrg 1169d522f475Smrg#define isSELECT(value) (!strcmp(value, "SELECT")) 1170d522f475Smrg 1171d522f475Smrgstatic void 1172d522f475SmrgUnmapSelections(XtermWidget xw) 1173d522f475Smrg{ 1174d522f475Smrg TScreen *screen = &(xw->screen); 1175d522f475Smrg Cardinal n; 1176d522f475Smrg 1177d522f475Smrg if (screen->mappedSelect) { 1178d522f475Smrg for (n = 0; screen->mappedSelect[n] != 0; ++n) 1179d522f475Smrg free(screen->mappedSelect[n]); 1180d522f475Smrg free(screen->mappedSelect); 1181d522f475Smrg screen->mappedSelect = 0; 1182d522f475Smrg } 1183d522f475Smrg} 1184d522f475Smrg 1185d522f475Smrg/* 1186d522f475Smrg * xterm generally uses the primary selection. Some applications prefer 1187d522f475Smrg * (or are limited to) the clipboard. Since the translations resource is 1188d522f475Smrg * complicated, users seldom change the way it affects selection. But it 1189d522f475Smrg * is simple to remap the choice between primary and clipboard before the 1190d522f475Smrg * call to XmuInternStrings(). 1191d522f475Smrg */ 1192d522f475Smrgstatic String * 1193d522f475SmrgMapSelections(XtermWidget xw, String * params, Cardinal num_params) 1194d522f475Smrg{ 1195d522f475Smrg String *result = params; 1196d522f475Smrg 1197d522f475Smrg if (num_params > 0) { 1198d522f475Smrg Cardinal j; 1199d522f475Smrg Boolean map = False; 1200d522f475Smrg 1201d522f475Smrg for (j = 0; j < num_params; ++j) { 1202d522f475Smrg TRACE(("param[%d]:%s\n", j, params[j])); 1203d522f475Smrg if (isSELECT(params[j])) { 1204d522f475Smrg map = True; 1205d522f475Smrg break; 1206d522f475Smrg } 1207d522f475Smrg } 1208d522f475Smrg if (map) { 1209d522f475Smrg const char *mapTo = (xw->screen.selectToClipboard 1210d522f475Smrg ? "CLIPBOARD" 1211d522f475Smrg : "PRIMARY"); 1212d522f475Smrg 1213d522f475Smrg UnmapSelections(xw); 1214d522f475Smrg if ((result = TypeMallocN(String, num_params + 1)) != 0) { 1215d522f475Smrg result[num_params] = 0; 1216d522f475Smrg for (j = 0; j < num_params; ++j) { 1217d522f475Smrg result[j] = x_strdup((isSELECT(params[j]) 1218d522f475Smrg ? mapTo 1219d522f475Smrg : params[j])); 1220d522f475Smrg if (result[j] == 0) { 1221d522f475Smrg UnmapSelections(xw); 1222d522f475Smrg result = 0; 1223d522f475Smrg break; 1224d522f475Smrg } 1225d522f475Smrg } 1226d522f475Smrg xw->screen.mappedSelect = result; 1227d522f475Smrg } 1228d522f475Smrg } 1229d522f475Smrg } 1230d522f475Smrg return result; 1231d522f475Smrg} 1232d522f475Smrg 1233d522f475Smrg/* 1234d522f475Smrg * Lookup the cut-buffer number, which will be in the range 0-7. 1235d522f475Smrg * If it is not a cut-buffer, it is the primary selection (-1). 1236d522f475Smrg */ 1237d522f475Smrgstatic int 1238d522f475SmrgCutBuffer(unsigned code) 1239d522f475Smrg{ 1240d522f475Smrg int cutbuffer; 1241d522f475Smrg switch (code) { 1242d522f475Smrg case XA_CUT_BUFFER0: 1243d522f475Smrg cutbuffer = 0; 1244d522f475Smrg break; 1245d522f475Smrg case XA_CUT_BUFFER1: 1246d522f475Smrg cutbuffer = 1; 1247d522f475Smrg break; 1248d522f475Smrg case XA_CUT_BUFFER2: 1249d522f475Smrg cutbuffer = 2; 1250d522f475Smrg break; 1251d522f475Smrg case XA_CUT_BUFFER3: 1252d522f475Smrg cutbuffer = 3; 1253d522f475Smrg break; 1254d522f475Smrg case XA_CUT_BUFFER4: 1255d522f475Smrg cutbuffer = 4; 1256d522f475Smrg break; 1257d522f475Smrg case XA_CUT_BUFFER5: 1258d522f475Smrg cutbuffer = 5; 1259d522f475Smrg break; 1260d522f475Smrg case XA_CUT_BUFFER6: 1261d522f475Smrg cutbuffer = 6; 1262d522f475Smrg break; 1263d522f475Smrg case XA_CUT_BUFFER7: 1264d522f475Smrg cutbuffer = 7; 1265d522f475Smrg break; 1266d522f475Smrg default: 1267d522f475Smrg cutbuffer = -1; 1268d522f475Smrg break; 1269d522f475Smrg } 1270d522f475Smrg return cutbuffer; 1271d522f475Smrg} 1272d522f475Smrg 1273d522f475Smrg#if OPT_PASTE64 1274d522f475Smrgstatic void 1275d522f475SmrgFinishPaste64(XtermWidget xw) 1276d522f475Smrg{ 1277d522f475Smrg TRACE(("FinishPaste64(%d)\n", xw->screen.base64_paste)); 1278d522f475Smrg if (xw->screen.base64_paste) { 1279d522f475Smrg xw->screen.base64_paste = 0; 1280d522f475Smrg unparseputc1(xw, xw->screen.base64_final); 1281d522f475Smrg unparse_end(xw); 1282d522f475Smrg } 1283d522f475Smrg} 1284d522f475Smrg#endif 1285d522f475Smrg 1286d522f475Smrg#if !OPT_PASTE64 1287d522f475Smrgstatic 1288d522f475Smrg#endif 1289d522f475Smrgvoid 1290d522f475SmrgxtermGetSelection(Widget w, 1291d522f475Smrg Time ev_time, 1292d522f475Smrg String * params, /* selections in precedence order */ 1293d522f475Smrg Cardinal num_params, 1294d522f475Smrg Atom * targets) 1295d522f475Smrg{ 1296d522f475Smrg Atom selection; 1297d522f475Smrg int cutbuffer; 1298d522f475Smrg Atom target; 1299d522f475Smrg 1300d522f475Smrg if (!IsXtermWidget(w)) 1301d522f475Smrg return; 1302d522f475Smrg 1303d522f475Smrg TRACE(("xtermGetSelection\n")); 1304d522f475Smrg params = MapSelections((XtermWidget) w, params, num_params); 1305d522f475Smrg 1306d522f475Smrg XmuInternStrings(XtDisplay(w), params, (Cardinal) 1, &selection); 1307d522f475Smrg cutbuffer = CutBuffer(selection); 1308d522f475Smrg 1309d522f475Smrg TRACE(("Cutbuffer: %d, target: %lu\n", cutbuffer, 1310d522f475Smrg targets ? (unsigned long) targets[0] : 0)); 1311d522f475Smrg 1312d522f475Smrg if (cutbuffer >= 0) { 1313d522f475Smrg int inbytes; 1314d522f475Smrg unsigned long nbytes; 1315d522f475Smrg int fmt8 = 8; 1316d522f475Smrg Atom type = XA_STRING; 1317d522f475Smrg char *line; 1318d522f475Smrg 1319d522f475Smrg /* 'line' is freed in SelectionReceived */ 1320d522f475Smrg line = XFetchBuffer(XtDisplay(w), &inbytes, cutbuffer); 1321d522f475Smrg nbytes = (unsigned long) inbytes; 1322d522f475Smrg 1323d522f475Smrg if (nbytes > 0) 1324d522f475Smrg SelectionReceived(w, NULL, &selection, &type, (XtPointer) line, 1325d522f475Smrg &nbytes, &fmt8); 1326d522f475Smrg else if (num_params > 1) { 1327d522f475Smrg xtermGetSelection(w, ev_time, params + 1, num_params - 1, NULL); 1328d522f475Smrg } 1329d522f475Smrg#if OPT_PASTE64 1330d522f475Smrg else { 1331d522f475Smrg FinishPaste64((XtermWidget) w); 1332d522f475Smrg } 1333d522f475Smrg#endif 1334d522f475Smrg return; 1335d522f475Smrg } else { 1336d522f475Smrg struct _SelectionList *list; 1337d522f475Smrg 1338d522f475Smrg if (targets == NULL || targets[0] == None) { 1339d522f475Smrg targets = _SelectionTargets(w); 1340d522f475Smrg } 1341d522f475Smrg 1342d522f475Smrg if (targets != 0) { 1343d522f475Smrg target = targets[0]; 1344d522f475Smrg 1345d522f475Smrg if (targets[1] == None) { /* last target in list */ 1346d522f475Smrg params++; 1347d522f475Smrg num_params--; 1348d522f475Smrg targets = _SelectionTargets(w); 1349d522f475Smrg } else { 1350d522f475Smrg targets = &(targets[1]); 1351d522f475Smrg } 1352d522f475Smrg 1353d522f475Smrg if (num_params) { 1354d522f475Smrg /* 'list' is freed in SelectionReceived */ 1355d522f475Smrg list = XtNew(struct _SelectionList); 1356d522f475Smrg if (list != 0) { 1357d522f475Smrg list->params = params; 1358d522f475Smrg list->count = num_params; 1359d522f475Smrg list->targets = targets; 1360d522f475Smrg list->time = ev_time; 1361d522f475Smrg } 1362d522f475Smrg } else { 1363d522f475Smrg list = NULL; 1364d522f475Smrg } 1365d522f475Smrg 1366d522f475Smrg XtGetSelectionValue(w, selection, 1367d522f475Smrg target, 1368d522f475Smrg SelectionReceived, 1369d522f475Smrg (XtPointer) list, ev_time); 1370d522f475Smrg } 1371d522f475Smrg } 1372d522f475Smrg} 1373d522f475Smrg 1374d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 1375d522f475Smrgstatic void 1376d522f475SmrgGettingSelection(Display * dpy, Atom type, Char * line, unsigned long len) 1377d522f475Smrg{ 1378d522f475Smrg Char *cp; 1379d522f475Smrg char *name; 1380d522f475Smrg 1381d522f475Smrg name = XGetAtomName(dpy, type); 1382d522f475Smrg 1383d522f475Smrg TRACE(("Getting %s (%ld)\n", name, (long int) type)); 1384d522f475Smrg for (cp = line; cp < line + len; cp++) { 1385d522f475Smrg TRACE(("[%d:%lu]", cp + 1 - line, len)); 1386d522f475Smrg if (isprint(*cp)) { 1387d522f475Smrg TRACE(("%c\n", *cp)); 1388d522f475Smrg } else { 1389d522f475Smrg TRACE(("\\x%02x\n", *cp)); 1390d522f475Smrg } 1391d522f475Smrg } 1392d522f475Smrg} 1393d522f475Smrg#else 1394d522f475Smrg#define GettingSelection(dpy,type,line,len) /* nothing */ 1395d522f475Smrg#endif 1396d522f475Smrg 1397d522f475Smrg#ifdef VMS 1398d522f475Smrg# define tty_vwrite(pty,lag,l) tt_write(lag,l) 1399d522f475Smrg#else /* !( VMS ) */ 1400d522f475Smrg# define tty_vwrite(pty,lag,l) v_write(pty,lag,l) 1401d522f475Smrg#endif /* defined VMS */ 1402d522f475Smrg 1403d522f475Smrg#if OPT_PASTE64 1404d522f475Smrg/* Return base64 code character given 6-bit number */ 1405d522f475Smrgstatic const char base64_code[] = "\ 1406d522f475SmrgABCDEFGHIJKLMNOPQRSTUVWXYZ\ 1407d522f475Smrgabcdefghijklmnopqrstuvwxyz\ 1408d522f475Smrg0123456789+/"; 1409d522f475Smrgstatic void 1410d522f475Smrgbase64_flush(TScreen * screen) 1411d522f475Smrg{ 1412d522f475Smrg Char x; 1413d522f475Smrg switch (screen->base64_count) { 1414d522f475Smrg case 0: 1415d522f475Smrg break; 1416d522f475Smrg case 2: 14172eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 4]); 1418d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1419d522f475Smrg break; 1420d522f475Smrg case 4: 14212eaa94a1Schristos x = CharOf(base64_code[screen->base64_accu << 2]); 1422d522f475Smrg tty_vwrite(screen->respond, &x, 1); 1423d522f475Smrg break; 1424d522f475Smrg } 1425d522f475Smrg if (screen->base64_pad & 3) 1426d522f475Smrg tty_vwrite(screen->respond, 1427d522f475Smrg (Char *) "===", 1428d522f475Smrg (unsigned) (4 - (screen->base64_pad & 3))); 1429d522f475Smrg screen->base64_count = 0; 1430d522f475Smrg screen->base64_accu = 0; 1431d522f475Smrg screen->base64_pad = 0; 1432d522f475Smrg} 1433d522f475Smrg#endif /* OPT_PASTE64 */ 1434d522f475Smrg 1435d522f475Smrgstatic void 1436d522f475Smrg_qWriteSelectionData(TScreen * screen, Char * lag, unsigned length) 1437d522f475Smrg{ 1438d522f475Smrg#if OPT_PASTE64 1439d522f475Smrg if (screen->base64_paste) { 1440d522f475Smrg /* Send data as base64 */ 1441d522f475Smrg Char *p = lag; 1442d522f475Smrg Char buf[64]; 1443d522f475Smrg unsigned x = 0; 1444d522f475Smrg while (length--) { 1445d522f475Smrg switch (screen->base64_count) { 1446d522f475Smrg case 0: 14472eaa94a1Schristos buf[x++] = CharOf(base64_code[*p >> 2]); 14482eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0x3); 1449d522f475Smrg screen->base64_count = 2; 1450d522f475Smrg ++p; 1451d522f475Smrg break; 1452d522f475Smrg case 2: 14532eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 4) + 14542eaa94a1Schristos (*p >> 4)]); 14552eaa94a1Schristos screen->base64_accu = (unsigned) (*p & 0xF); 1456d522f475Smrg screen->base64_count = 4; 1457d522f475Smrg ++p; 1458d522f475Smrg break; 1459d522f475Smrg case 4: 14602eaa94a1Schristos buf[x++] = CharOf(base64_code[(screen->base64_accu << 2) + 14612eaa94a1Schristos (*p >> 6)]); 14622eaa94a1Schristos buf[x++] = CharOf(base64_code[*p & 0x3F]); 1463d522f475Smrg screen->base64_accu = 0; 1464d522f475Smrg screen->base64_count = 0; 1465d522f475Smrg ++p; 1466d522f475Smrg break; 1467d522f475Smrg } 1468d522f475Smrg if (x >= 63) { 1469d522f475Smrg /* Write 63 or 64 characters */ 1470d522f475Smrg screen->base64_pad += x; 1471d522f475Smrg tty_vwrite(screen->respond, buf, x); 1472d522f475Smrg x = 0; 1473d522f475Smrg } 1474d522f475Smrg } 1475d522f475Smrg if (x != 0) { 1476d522f475Smrg screen->base64_pad += x; 1477d522f475Smrg tty_vwrite(screen->respond, buf, x); 1478d522f475Smrg } 1479d522f475Smrg } else 1480d522f475Smrg#endif /* OPT_PASTE64 */ 1481d522f475Smrg#if OPT_READLINE 1482d522f475Smrg if (SCREEN_FLAG(screen, paste_quotes)) { 1483d522f475Smrg while (length--) { 1484d522f475Smrg tty_vwrite(screen->respond, (Char *) "\026", 1); /* Control-V */ 1485d522f475Smrg tty_vwrite(screen->respond, lag++, 1); 1486d522f475Smrg } 1487d522f475Smrg } else 1488d522f475Smrg#endif 1489d522f475Smrg tty_vwrite(screen->respond, lag, length); 1490d522f475Smrg} 1491d522f475Smrg 1492d522f475Smrgstatic void 14932eaa94a1Schristos_WriteSelectionData(TScreen * screen, Char * line, unsigned length) 1494d522f475Smrg{ 1495d522f475Smrg /* Write data to pty a line at a time. */ 1496d522f475Smrg /* Doing this one line at a time may no longer be necessary 1497d522f475Smrg because v_write has been re-written. */ 1498d522f475Smrg 1499d522f475Smrg Char *lag, *end; 1500d522f475Smrg 1501d522f475Smrg /* in the VMS version, if tt_pasting isn't set to True then qio 1502d522f475Smrg reads aren't blocked and an infinite loop is entered, where the 1503d522f475Smrg pasted text shows up as new input, goes in again, shows up 1504d522f475Smrg again, ad nauseum. */ 1505d522f475Smrg#ifdef VMS 1506d522f475Smrg tt_pasting = True; 1507d522f475Smrg#endif 1508d522f475Smrg 1509d522f475Smrg end = &line[length]; 1510d522f475Smrg lag = line; 1511d522f475Smrg 1512d522f475Smrg#if OPT_PASTE64 1513d522f475Smrg if (screen->base64_paste) { 1514d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (end - lag)); 1515d522f475Smrg base64_flush(screen); 1516d522f475Smrg } else 1517d522f475Smrg#endif 1518d522f475Smrg { 1519d522f475Smrg if (!SCREEN_FLAG(screen, paste_literal_nl)) { 1520d522f475Smrg Char *cp; 1521d522f475Smrg for (cp = line; cp != end; cp++) { 1522d522f475Smrg if (*cp == '\n') { 1523d522f475Smrg *cp = '\r'; 1524d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (cp - lag + 1)); 1525d522f475Smrg lag = cp + 1; 1526d522f475Smrg } 1527d522f475Smrg } 1528d522f475Smrg } 1529d522f475Smrg 1530d522f475Smrg if (lag != end) { 1531d522f475Smrg _qWriteSelectionData(screen, lag, (unsigned) (end - lag)); 1532d522f475Smrg } 1533d522f475Smrg } 1534d522f475Smrg#ifdef VMS 1535d522f475Smrg tt_pasting = False; 1536d522f475Smrg tt_start_read(); /* reenable reads or a character may be lost */ 1537d522f475Smrg#endif 1538d522f475Smrg} 1539d522f475Smrg 1540d522f475Smrg#if OPT_READLINE 1541d522f475Smrgstatic void 1542d522f475Smrg_WriteKey(TScreen * screen, Char * in) 1543d522f475Smrg{ 1544d522f475Smrg Char line[16]; 1545d522f475Smrg unsigned count = 0; 1546d522f475Smrg unsigned length = strlen((char *) in); 1547d522f475Smrg 1548d522f475Smrg if (screen->control_eight_bits) { 1549d522f475Smrg line[count++] = ANSI_CSI; 1550d522f475Smrg } else { 1551d522f475Smrg line[count++] = ANSI_ESC; 1552d522f475Smrg line[count++] = '['; 1553d522f475Smrg } 1554d522f475Smrg while (length--) 1555d522f475Smrg line[count++] = *in++; 1556d522f475Smrg line[count++] = '~'; 1557d522f475Smrg tty_vwrite(screen->respond, line, count); 1558d522f475Smrg} 1559d522f475Smrg#endif /* OPT_READLINE */ 1560d522f475Smrg 1561d522f475Smrg/* SelectionReceived: stuff received selection text into pty */ 1562d522f475Smrg 1563d522f475Smrg/* ARGSUSED */ 1564d522f475Smrgstatic void 1565d522f475SmrgSelectionReceived(Widget w, 1566d522f475Smrg XtPointer client_data, 1567d522f475Smrg Atom * selection GCC_UNUSED, 1568d522f475Smrg Atom * type, 1569d522f475Smrg XtPointer value, 1570d522f475Smrg unsigned long *length, 1571d522f475Smrg int *format) 1572d522f475Smrg{ 1573d522f475Smrg char **text_list = NULL; 1574d522f475Smrg int text_list_count; 1575d522f475Smrg XTextProperty text_prop; 1576d522f475Smrg TScreen *screen; 1577d522f475Smrg Display *dpy; 1578d522f475Smrg#if OPT_TRACE && OPT_WIDE_CHARS 1579d522f475Smrg Char *line = (Char *) value; 1580d522f475Smrg#endif 1581d522f475Smrg 1582d522f475Smrg if (!IsXtermWidget(w)) 1583d522f475Smrg return; 1584d522f475Smrg screen = TScreenOf((XtermWidget) w); 1585d522f475Smrg dpy = XtDisplay(w); 1586d522f475Smrg 1587d522f475Smrg if (*type == 0 /*XT_CONVERT_FAIL */ 1588d522f475Smrg || *length == 0 1589d522f475Smrg || value == NULL) 1590d522f475Smrg goto fail; 1591d522f475Smrg 1592d522f475Smrg text_prop.value = (unsigned char *) value; 1593d522f475Smrg text_prop.encoding = *type; 1594d522f475Smrg text_prop.format = *format; 1595d522f475Smrg text_prop.nitems = *length; 1596d522f475Smrg 1597d522f475Smrg#if OPT_WIDE_CHARS 1598d522f475Smrg if (screen->wide_chars) { 1599d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 1600d522f475Smrg *type == XA_STRING || 1601d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 1602d522f475Smrg GettingSelection(dpy, *type, line, *length); 1603d522f475Smrg if (Xutf8TextPropertyToTextList(dpy, &text_prop, 1604d522f475Smrg &text_list, 1605d522f475Smrg &text_list_count) < 0) { 1606d522f475Smrg TRACE(("Conversion failed\n")); 1607d522f475Smrg text_list = NULL; 1608d522f475Smrg } 1609d522f475Smrg } 1610d522f475Smrg } else 1611d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1612d522f475Smrg { 1613d522f475Smrg /* Convert the selection to locale's multibyte encoding. */ 1614d522f475Smrg 1615d522f475Smrg if (*type == XA_UTF8_STRING(dpy) || 1616d522f475Smrg *type == XA_STRING || 1617d522f475Smrg *type == XA_COMPOUND_TEXT(dpy)) { 1618d522f475Smrg Status rc; 1619d522f475Smrg 1620d522f475Smrg GettingSelection(dpy, *type, line, *length); 1621d522f475Smrg 1622d522f475Smrg#if OPT_WIDE_CHARS 1623d522f475Smrg if (*type == XA_UTF8_STRING(dpy) && 1624d522f475Smrg !(screen->wide_chars || screen->c1_printable)) { 1625d522f475Smrg rc = Xutf8TextPropertyToTextList(dpy, &text_prop, 1626d522f475Smrg &text_list, &text_list_count); 1627d522f475Smrg if (text_list != NULL && text_list_count != 0) { 1628d522f475Smrg int i; 1629d522f475Smrg Char *data; 16302eaa94a1Schristos char **new_text_list, *tmp; 16312eaa94a1Schristos unsigned long size, new_size; 16322eaa94a1Schristos /* XLib StringList actually uses only two 16332eaa94a1Schristos * pointers, one for the list itself, and one for 16342eaa94a1Schristos * the data. Pointer to the data is the first 16352eaa94a1Schristos * element of the list, the rest (if any) list 16362eaa94a1Schristos * elements point to the same memory block as the 16372eaa94a1Schristos * first element 16382eaa94a1Schristos */ 16392eaa94a1Schristos new_size = 0; 16402eaa94a1Schristos for (i = 0; i < text_list_count; ++i) { 16412eaa94a1Schristos data = (Char *) text_list[i]; 16422eaa94a1Schristos size = strlen(text_list[i]) + 1; 16432eaa94a1Schristos data = UTF8toLatin1(data, size, &size); 16442eaa94a1Schristos new_size += size + 1; 16452eaa94a1Schristos } 16462eaa94a1Schristos new_text_list = 16472eaa94a1Schristos (char **) XtMalloc(sizeof(char *) * (unsigned) text_list_count); 16482eaa94a1Schristos new_text_list[0] = tmp = XtMalloc(new_size); 1649d522f475Smrg for (i = 0; i < text_list_count; ++i) { 1650d522f475Smrg data = (Char *) text_list[i]; 16512eaa94a1Schristos size = strlen(text_list[i]) + 1; 1652d522f475Smrg data = UTF8toLatin1(data, size, &size); 16532eaa94a1Schristos memcpy(tmp, data, size + 1); 16542eaa94a1Schristos new_text_list[i] = tmp; 16552eaa94a1Schristos tmp += size + 1; 1656d522f475Smrg } 16572eaa94a1Schristos XFreeStringList(text_list); 16582eaa94a1Schristos text_list = new_text_list; 1659d522f475Smrg } 1660d522f475Smrg } else 1661d522f475Smrg#endif 1662d522f475Smrg if (*type == XA_STRING && screen->brokenSelections) { 1663d522f475Smrg rc = XTextPropertyToStringList(&text_prop, 1664d522f475Smrg &text_list, &text_list_count); 1665d522f475Smrg } else { 1666d522f475Smrg rc = XmbTextPropertyToTextList(dpy, &text_prop, 1667d522f475Smrg &text_list, 1668d522f475Smrg &text_list_count); 1669d522f475Smrg } 1670d522f475Smrg if (rc < 0) { 1671d522f475Smrg TRACE(("Conversion failed\n")); 1672d522f475Smrg text_list = NULL; 1673d522f475Smrg } 1674d522f475Smrg } 1675d522f475Smrg } 1676d522f475Smrg 1677d522f475Smrg if (text_list != NULL && text_list_count != 0) { 1678d522f475Smrg int i; 1679d522f475Smrg 1680d522f475Smrg#if OPT_PASTE64 1681d522f475Smrg if (screen->base64_paste) { 1682d522f475Smrg ; 1683d522f475Smrg } else 1684d522f475Smrg#endif 1685d522f475Smrg#if OPT_READLINE 1686d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 1687d522f475Smrg _WriteKey(screen, (Char *) "200"); 1688d522f475Smrg } 1689d522f475Smrg#endif 1690d522f475Smrg for (i = 0; i < text_list_count; i++) { 16912eaa94a1Schristos unsigned len = strlen(text_list[i]); 1692d522f475Smrg _WriteSelectionData(screen, (Char *) text_list[i], len); 1693d522f475Smrg } 1694d522f475Smrg#if OPT_PASTE64 1695d522f475Smrg if (screen->base64_paste) { 1696d522f475Smrg FinishPaste64((XtermWidget) w); 1697d522f475Smrg } else 1698d522f475Smrg#endif 1699d522f475Smrg#if OPT_READLINE 1700d522f475Smrg if (SCREEN_FLAG(screen, paste_brackets)) { 1701d522f475Smrg _WriteKey(screen, (Char *) "201"); 1702d522f475Smrg } 1703d522f475Smrg#endif 1704d522f475Smrg XFreeStringList(text_list); 1705d522f475Smrg } else 1706d522f475Smrg goto fail; 1707d522f475Smrg 1708d522f475Smrg XtFree((char *) client_data); 1709d522f475Smrg XtFree((char *) value); 1710d522f475Smrg 1711d522f475Smrg return; 1712d522f475Smrg 1713d522f475Smrg fail: 1714d522f475Smrg if (client_data != 0) { 1715d522f475Smrg struct _SelectionList *list = (struct _SelectionList *) client_data; 1716d522f475Smrg xtermGetSelection(w, list->time, 1717d522f475Smrg list->params, list->count, list->targets); 1718d522f475Smrg XtFree((char *) client_data); 1719d522f475Smrg#if OPT_PASTE64 1720d522f475Smrg } else { 1721d522f475Smrg FinishPaste64((XtermWidget) w); 1722d522f475Smrg#endif 1723d522f475Smrg } 1724d522f475Smrg return; 1725d522f475Smrg} 1726d522f475Smrg 1727d522f475Smrgvoid 1728d522f475SmrgHandleInsertSelection(Widget w, 1729d522f475Smrg XEvent * event, /* assumed to be XButtonEvent* */ 1730d522f475Smrg String * params, /* selections in precedence order */ 1731d522f475Smrg Cardinal *num_params) 1732d522f475Smrg{ 1733d522f475Smrg if (IsXtermWidget(w)) { 1734d522f475Smrg XtermWidget xw = (XtermWidget) w; 1735d522f475Smrg 1736d522f475Smrg if (!SendMousePosition(xw, event)) { 1737d522f475Smrg#if OPT_READLINE 1738d522f475Smrg int ldelta; 1739d522f475Smrg TScreen *screen = &(xw->screen); 1740d522f475Smrg if ((event->type == ButtonPress || event->type == ButtonRelease) 1741d522f475Smrg /* Disable on Shift-mouse, including the application-mouse modes */ 1742d522f475Smrg && !(KeyModifiers & ShiftMask) 1743d522f475Smrg && (screen->send_mouse_pos == MOUSE_OFF) 1744d522f475Smrg && SCREEN_FLAG(screen, paste_moves) 1745d522f475Smrg && rowOnCurrentLine(screen, eventRow(screen, event), &ldelta)) 1746d522f475Smrg ReadLineMovePoint(screen, eventColBetween(screen, event), ldelta); 1747d522f475Smrg#endif /* OPT_READLINE */ 1748d522f475Smrg 1749d522f475Smrg xtermGetSelection(w, event->xbutton.time, params, *num_params, NULL); 1750d522f475Smrg } 1751d522f475Smrg } 1752d522f475Smrg} 1753d522f475Smrg 1754d522f475Smrgstatic SelectUnit 1755d522f475SmrgEvalSelectUnit(TScreen * screen, 1756d522f475Smrg Time buttonDownTime, 1757d522f475Smrg SelectUnit defaultUnit, 1758d522f475Smrg unsigned int button) 1759d522f475Smrg{ 1760d522f475Smrg SelectUnit result; 1761d522f475Smrg int delta; 1762d522f475Smrg 1763d522f475Smrg if (button != screen->lastButton) { 1764d522f475Smrg delta = term->screen.multiClickTime + 1; 1765d522f475Smrg } else if (screen->lastButtonUpTime == (Time) 0) { 1766d522f475Smrg /* first time and once in a blue moon */ 1767d522f475Smrg delta = screen->multiClickTime + 1; 1768d522f475Smrg } else if (buttonDownTime > screen->lastButtonUpTime) { 1769d522f475Smrg /* most of the time */ 17702eaa94a1Schristos delta = (int) (buttonDownTime - screen->lastButtonUpTime); 1771d522f475Smrg } else { 1772d522f475Smrg /* time has rolled over since lastButtonUpTime */ 17732eaa94a1Schristos delta = (int) ((((Time) ~ 0) - screen->lastButtonUpTime) + buttonDownTime); 1774d522f475Smrg } 1775d522f475Smrg 1776d522f475Smrg if (delta > screen->multiClickTime) { 1777d522f475Smrg screen->numberOfClicks = 1; 1778d522f475Smrg result = defaultUnit; 1779d522f475Smrg } else { 1780d522f475Smrg result = screen->selectMap[screen->numberOfClicks % screen->maxClicks]; 1781d522f475Smrg screen->numberOfClicks += 1; 1782d522f475Smrg } 1783d522f475Smrg TRACE(("EvalSelectUnit(%d) = %d\n", screen->numberOfClicks, result)); 1784d522f475Smrg return result; 1785d522f475Smrg} 1786d522f475Smrg 1787d522f475Smrgstatic void 1788d522f475Smrgdo_select_start(XtermWidget xw, 1789d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 1790d522f475Smrg CELL * cell) 1791d522f475Smrg{ 1792d522f475Smrg TScreen *screen = &(xw->screen); 1793d522f475Smrg 1794d522f475Smrg if (SendMousePosition(xw, event)) 1795d522f475Smrg return; 1796d522f475Smrg screen->selectUnit = EvalSelectUnit(screen, 1797d522f475Smrg event->xbutton.time, 1798d522f475Smrg Select_CHAR, 1799d522f475Smrg event->xbutton.button); 1800d522f475Smrg screen->replyToEmacs = False; 1801d522f475Smrg 1802d522f475Smrg#if OPT_READLINE 1803d522f475Smrg lastButtonDownTime = event->xbutton.time; 1804d522f475Smrg#endif 1805d522f475Smrg 1806d522f475Smrg StartSelect(xw, cell); 1807d522f475Smrg} 1808d522f475Smrg 1809d522f475Smrg/* ARGSUSED */ 1810d522f475Smrgvoid 1811d522f475SmrgHandleSelectStart(Widget w, 1812d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 1813d522f475Smrg String * params GCC_UNUSED, 1814d522f475Smrg Cardinal *num_params GCC_UNUSED) 1815d522f475Smrg{ 1816d522f475Smrg if (IsXtermWidget(w)) { 1817d522f475Smrg XtermWidget xw = (XtermWidget) w; 1818d522f475Smrg TScreen *screen = &(xw->screen); 1819d522f475Smrg CELL cell; 1820d522f475Smrg 1821d522f475Smrg screen->firstValidRow = 0; 1822d522f475Smrg screen->lastValidRow = screen->max_row; 1823d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 1824d522f475Smrg 1825d522f475Smrg#if OPT_READLINE 1826d522f475Smrg ExtendingSelection = 0; 1827d522f475Smrg#endif 1828d522f475Smrg 1829d522f475Smrg do_select_start(xw, event, &cell); 1830d522f475Smrg } 1831d522f475Smrg} 1832d522f475Smrg 1833d522f475Smrg/* ARGSUSED */ 1834d522f475Smrgvoid 1835d522f475SmrgHandleKeyboardSelectStart(Widget w, 1836d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 1837d522f475Smrg String * params GCC_UNUSED, 1838d522f475Smrg Cardinal *num_params GCC_UNUSED) 1839d522f475Smrg{ 1840d522f475Smrg if (IsXtermWidget(w)) { 1841d522f475Smrg XtermWidget xw = (XtermWidget) w; 1842d522f475Smrg TScreen *screen = &(xw->screen); 1843d522f475Smrg do_select_start(xw, event, &screen->cursorp); 1844d522f475Smrg } 1845d522f475Smrg} 1846d522f475Smrg 1847d522f475Smrgstatic void 1848d522f475SmrgTrackDown(XtermWidget xw, XButtonEvent * event) 1849d522f475Smrg{ 1850d522f475Smrg TScreen *screen = &(xw->screen); 1851d522f475Smrg CELL cell; 1852d522f475Smrg 1853d522f475Smrg screen->selectUnit = EvalSelectUnit(screen, 1854d522f475Smrg event->time, 1855d522f475Smrg Select_CHAR, 1856d522f475Smrg event->button); 1857d522f475Smrg if (screen->numberOfClicks > 1) { 1858d522f475Smrg PointToCELL(screen, event->y, event->x, &cell); 1859d522f475Smrg screen->replyToEmacs = True; 1860d522f475Smrg StartSelect(xw, &cell); 1861d522f475Smrg } else { 1862d522f475Smrg screen->waitingForTrackInfo = True; 1863d522f475Smrg EditorButton(xw, (XButtonEvent *) event); 1864d522f475Smrg } 1865d522f475Smrg} 1866d522f475Smrg 1867d522f475Smrg#define boundsCheck(x) if (x < 0) \ 1868d522f475Smrg x = 0; \ 1869d522f475Smrg else if (x >= screen->max_row) \ 1870d522f475Smrg x = screen->max_row 1871d522f475Smrg 1872d522f475Smrgvoid 1873d522f475SmrgTrackMouse(XtermWidget xw, 1874d522f475Smrg int func, 1875d522f475Smrg CELL * start, 1876d522f475Smrg int firstrow, 1877d522f475Smrg int lastrow) 1878d522f475Smrg{ 1879d522f475Smrg TScreen *screen = &(xw->screen); 1880d522f475Smrg 1881d522f475Smrg if (screen->waitingForTrackInfo) { /* if Timed, ignore */ 1882d522f475Smrg screen->waitingForTrackInfo = False; 1883d522f475Smrg 1884d522f475Smrg if (func != 0) { 1885d522f475Smrg CELL first = *start; 1886d522f475Smrg 1887d522f475Smrg boundsCheck(first.row); 1888d522f475Smrg boundsCheck(firstrow); 1889d522f475Smrg boundsCheck(lastrow); 1890d522f475Smrg screen->firstValidRow = firstrow; 1891d522f475Smrg screen->lastValidRow = lastrow; 1892d522f475Smrg screen->replyToEmacs = True; 1893d522f475Smrg StartSelect(xw, &first); 1894d522f475Smrg } 1895d522f475Smrg } 1896d522f475Smrg} 1897d522f475Smrg 1898d522f475Smrgstatic void 1899d522f475SmrgStartSelect(XtermWidget xw, const CELL * cell) 1900d522f475Smrg{ 1901d522f475Smrg TScreen *screen = &(xw->screen); 1902d522f475Smrg 1903d522f475Smrg TRACE(("StartSelect row=%d, col=%d\n", cell->row, cell->col)); 1904d522f475Smrg if (screen->cursor_state) 1905d522f475Smrg HideCursor(); 1906d522f475Smrg if (screen->numberOfClicks == 1) { 1907d522f475Smrg /* set start of selection */ 1908d522f475Smrg screen->rawPos = *cell; 1909d522f475Smrg } 1910d522f475Smrg /* else use old values in rawPos */ 1911d522f475Smrg screen->saveStartR = screen->startExt = screen->rawPos; 1912d522f475Smrg screen->saveEndR = screen->endExt = screen->rawPos; 1913d522f475Smrg if (Coordinate(screen, cell) < Coordinate(screen, &(screen->rawPos))) { 1914d522f475Smrg screen->eventMode = LEFTEXTENSION; 1915d522f475Smrg screen->startExt = *cell; 1916d522f475Smrg } else { 1917d522f475Smrg screen->eventMode = RIGHTEXTENSION; 1918d522f475Smrg screen->endExt = *cell; 1919d522f475Smrg } 1920d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 1921d522f475Smrg} 1922d522f475Smrg 1923d522f475Smrgstatic void 1924d522f475SmrgEndExtend(XtermWidget xw, 1925d522f475Smrg XEvent * event, /* must be XButtonEvent */ 1926d522f475Smrg String * params, /* selections */ 1927d522f475Smrg Cardinal num_params, 1928d522f475Smrg Bool use_cursor_loc) 1929d522f475Smrg{ 1930d522f475Smrg CELL cell; 1931d522f475Smrg unsigned count; 1932d522f475Smrg TScreen *screen = &xw->screen; 1933d522f475Smrg Char line[9]; 1934d522f475Smrg 1935d522f475Smrg if (use_cursor_loc) { 1936d522f475Smrg cell = screen->cursorp; 1937d522f475Smrg } else { 1938d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 1939d522f475Smrg } 1940d522f475Smrg ExtendExtend(xw, &cell); 1941d522f475Smrg screen->lastButtonUpTime = event->xbutton.time; 1942d522f475Smrg screen->lastButton = event->xbutton.button; 1943d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 1944d522f475Smrg if (screen->replyToEmacs) { 1945d522f475Smrg count = 0; 1946d522f475Smrg if (screen->control_eight_bits) { 1947d522f475Smrg line[count++] = ANSI_CSI; 1948d522f475Smrg } else { 1949d522f475Smrg line[count++] = ANSI_ESC; 1950d522f475Smrg line[count++] = '['; 1951d522f475Smrg } 1952d522f475Smrg if (isSameCELL(&(screen->rawPos), &(screen->startSel)) 1953d522f475Smrg && isSameCELL(&cell, &(screen->endSel))) { 1954d522f475Smrg /* Use short-form emacs select */ 1955d522f475Smrg line[count++] = 't'; 19562eaa94a1Schristos line[count++] = CharOf(' ' + screen->endSel.col + 1); 19572eaa94a1Schristos line[count++] = CharOf(' ' + screen->endSel.row + 1); 1958d522f475Smrg } else { 1959d522f475Smrg /* long-form, specify everything */ 1960d522f475Smrg line[count++] = 'T'; 19612eaa94a1Schristos line[count++] = CharOf(' ' + screen->startSel.col + 1); 19622eaa94a1Schristos line[count++] = CharOf(' ' + screen->startSel.row + 1); 19632eaa94a1Schristos line[count++] = CharOf(' ' + screen->endSel.col + 1); 19642eaa94a1Schristos line[count++] = CharOf(' ' + screen->endSel.row + 1); 19652eaa94a1Schristos line[count++] = CharOf(' ' + cell.col + 1); 19662eaa94a1Schristos line[count++] = CharOf(' ' + cell.row + 1); 1967d522f475Smrg } 1968d522f475Smrg v_write(screen->respond, line, count); 1969d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 1970d522f475Smrg } 1971d522f475Smrg } 1972d522f475Smrg SelectSet(xw, event, params, num_params); 1973d522f475Smrg screen->eventMode = NORMAL; 1974d522f475Smrg} 1975d522f475Smrg 1976d522f475Smrgvoid 1977d522f475SmrgHandleSelectSet(Widget w, 1978d522f475Smrg XEvent * event, 1979d522f475Smrg String * params, 1980d522f475Smrg Cardinal *num_params) 1981d522f475Smrg{ 1982d522f475Smrg if (IsXtermWidget(w)) { 1983d522f475Smrg SelectSet((XtermWidget) w, event, params, *num_params); 1984d522f475Smrg } 1985d522f475Smrg} 1986d522f475Smrg 1987d522f475Smrg/* ARGSUSED */ 1988d522f475Smrgstatic void 1989d522f475SmrgSelectSet(XtermWidget xw, 1990d522f475Smrg XEvent * event GCC_UNUSED, 1991d522f475Smrg String * params, 1992d522f475Smrg Cardinal num_params) 1993d522f475Smrg{ 1994d522f475Smrg TScreen *screen = &(xw->screen); 1995d522f475Smrg 1996d522f475Smrg TRACE(("SelectSet\n")); 1997d522f475Smrg /* Only do select stuff if non-null select */ 1998d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) { 1999d522f475Smrg SaltTextAway(xw, &(screen->startSel), &(screen->endSel), params, num_params); 2000d522f475Smrg } else { 2001d522f475Smrg DisownSelection(xw); 2002d522f475Smrg } 2003d522f475Smrg} 2004d522f475Smrg 2005d522f475Smrg#define Abs(x) ((x) < 0 ? -(x) : (x)) 2006d522f475Smrg 2007d522f475Smrg/* ARGSUSED */ 2008d522f475Smrgstatic void 2009d522f475Smrgdo_start_extend(XtermWidget xw, 2010d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2011d522f475Smrg String * params GCC_UNUSED, 2012d522f475Smrg Cardinal *num_params GCC_UNUSED, 2013d522f475Smrg Bool use_cursor_loc) 2014d522f475Smrg{ 2015d522f475Smrg TScreen *screen = &(xw->screen); 2016d522f475Smrg int coord; 2017d522f475Smrg CELL cell; 2018d522f475Smrg 2019d522f475Smrg if (!IsXtermWidget(xw)) 2020d522f475Smrg return; 2021d522f475Smrg 2022d522f475Smrg if (SendMousePosition(xw, event)) 2023d522f475Smrg return; 2024d522f475Smrg 2025d522f475Smrg screen->firstValidRow = 0; 2026d522f475Smrg screen->lastValidRow = screen->max_row; 2027d522f475Smrg#if OPT_READLINE 2028d522f475Smrg if ((KeyModifiers & ShiftMask) 2029d522f475Smrg || event->xbutton.button != Button3 2030d522f475Smrg || !(SCREEN_FLAG(screen, dclick3_deletes))) 2031d522f475Smrg#endif 2032d522f475Smrg screen->selectUnit = EvalSelectUnit(screen, 2033d522f475Smrg event->xbutton.time, 2034d522f475Smrg screen->selectUnit, 2035d522f475Smrg event->xbutton.button); 2036d522f475Smrg screen->replyToEmacs = False; 2037d522f475Smrg 2038d522f475Smrg#if OPT_READLINE 2039d522f475Smrg CheckSecondPress3(screen, event); 2040d522f475Smrg#endif 2041d522f475Smrg 2042d522f475Smrg if (screen->numberOfClicks == 1 2043d522f475Smrg || (SCREEN_FLAG(screen, dclick3_deletes) /* Dclick special */ 2044d522f475Smrg &&!(KeyModifiers & ShiftMask))) { 2045d522f475Smrg /* Save existing selection so we can reestablish it if the guy 2046d522f475Smrg extends past the other end of the selection */ 2047d522f475Smrg screen->saveStartR = screen->startExt = screen->startRaw; 2048d522f475Smrg screen->saveEndR = screen->endExt = screen->endRaw; 2049d522f475Smrg } else { 2050d522f475Smrg /* He just needed the selection mode changed, use old values. */ 2051d522f475Smrg screen->startExt = screen->startRaw = screen->saveStartR; 2052d522f475Smrg screen->endExt = screen->endRaw = screen->saveEndR; 2053d522f475Smrg } 2054d522f475Smrg if (use_cursor_loc) { 2055d522f475Smrg cell = screen->cursorp; 2056d522f475Smrg } else { 2057d522f475Smrg PointToCELL(screen, event->xbutton.y, event->xbutton.x, &cell); 2058d522f475Smrg } 2059d522f475Smrg coord = Coordinate(screen, &cell); 2060d522f475Smrg 2061d522f475Smrg if (Abs(coord - Coordinate(screen, &(screen->startSel))) 2062d522f475Smrg < Abs(coord - Coordinate(screen, &(screen->endSel))) 2063d522f475Smrg || coord < Coordinate(screen, &(screen->startSel))) { 2064d522f475Smrg /* point is close to left side of selection */ 2065d522f475Smrg screen->eventMode = LEFTEXTENSION; 2066d522f475Smrg screen->startExt = cell; 2067d522f475Smrg } else { 2068d522f475Smrg /* point is close to left side of selection */ 2069d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2070d522f475Smrg screen->endExt = cell; 2071d522f475Smrg } 2072d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), True); 2073d522f475Smrg 2074d522f475Smrg#if OPT_READLINE 2075d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2076d522f475Smrg ExtendingSelection = 1; 2077d522f475Smrg#endif 2078d522f475Smrg} 2079d522f475Smrg 2080d522f475Smrgstatic void 2081d522f475SmrgExtendExtend(XtermWidget xw, const CELL * cell) 2082d522f475Smrg{ 2083d522f475Smrg TScreen *screen = &(xw->screen); 2084d522f475Smrg int coord = Coordinate(screen, cell); 2085d522f475Smrg 2086d522f475Smrg TRACE(("ExtendExtend row=%d, col=%d\n", cell->row, cell->col)); 2087d522f475Smrg if (screen->eventMode == LEFTEXTENSION 2088d522f475Smrg && ((coord + (screen->selectUnit != Select_CHAR)) 2089d522f475Smrg > Coordinate(screen, &(screen->endSel)))) { 2090d522f475Smrg /* Whoops, he's changed his mind. Do RIGHTEXTENSION */ 2091d522f475Smrg screen->eventMode = RIGHTEXTENSION; 2092d522f475Smrg screen->startExt = screen->saveStartR; 2093d522f475Smrg } else if (screen->eventMode == RIGHTEXTENSION 2094d522f475Smrg && coord < Coordinate(screen, &(screen->startSel))) { 2095d522f475Smrg /* Whoops, he's changed his mind. Do LEFTEXTENSION */ 2096d522f475Smrg screen->eventMode = LEFTEXTENSION; 2097d522f475Smrg screen->endExt = screen->saveEndR; 2098d522f475Smrg } 2099d522f475Smrg if (screen->eventMode == LEFTEXTENSION) { 2100d522f475Smrg screen->startExt = *cell; 2101d522f475Smrg } else { 2102d522f475Smrg screen->endExt = *cell; 2103d522f475Smrg } 2104d522f475Smrg ComputeSelect(xw, &(screen->startExt), &(screen->endExt), False); 2105d522f475Smrg 2106d522f475Smrg#if OPT_READLINE 2107d522f475Smrg if (!isSameCELL(&(screen->startSel), &(screen->endSel))) 2108d522f475Smrg ExtendingSelection = 1; 2109d522f475Smrg#endif 2110d522f475Smrg} 2111d522f475Smrg 2112d522f475Smrgvoid 2113d522f475SmrgHandleStartExtend(Widget w, 2114d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2115d522f475Smrg String * params, /* unused */ 2116d522f475Smrg Cardinal *num_params) /* unused */ 2117d522f475Smrg{ 2118d522f475Smrg if (IsXtermWidget(w)) 2119d522f475Smrg do_start_extend((XtermWidget) w, event, params, num_params, False); 2120d522f475Smrg} 2121d522f475Smrg 2122d522f475Smrgvoid 2123d522f475SmrgHandleKeyboardStartExtend(Widget w, 2124d522f475Smrg XEvent * event, /* must be XButtonEvent* */ 2125d522f475Smrg String * params, /* unused */ 2126d522f475Smrg Cardinal *num_params) /* unused */ 2127d522f475Smrg{ 2128d522f475Smrg if (IsXtermWidget(w)) 2129d522f475Smrg do_start_extend((XtermWidget) w, event, params, num_params, True); 2130d522f475Smrg} 2131d522f475Smrg 2132d522f475Smrgvoid 2133d522f475SmrgScrollSelection(TScreen * screen, int amount, Bool always) 2134d522f475Smrg{ 2135d522f475Smrg int minrow = INX2ROW(screen, -screen->savedlines); 2136d522f475Smrg int maxrow = INX2ROW(screen, screen->max_row); 2137d522f475Smrg int maxcol = screen->max_col; 2138d522f475Smrg 2139d522f475Smrg#define scroll_update_one(cell) \ 2140d522f475Smrg (cell)->row += amount; \ 2141d522f475Smrg if ((cell)->row < minrow) { \ 2142d522f475Smrg (cell)->row = minrow; \ 2143d522f475Smrg (cell)->col = 0; \ 2144d522f475Smrg } \ 2145d522f475Smrg if ((cell)->row > maxrow) { \ 2146d522f475Smrg (cell)->row = maxrow; \ 2147d522f475Smrg (cell)->col = maxcol; \ 2148d522f475Smrg } 2149d522f475Smrg 2150d522f475Smrg scroll_update_one(&(screen->startRaw)); 2151d522f475Smrg scroll_update_one(&(screen->endRaw)); 2152d522f475Smrg scroll_update_one(&(screen->startSel)); 2153d522f475Smrg scroll_update_one(&(screen->endSel)); 2154d522f475Smrg 2155d522f475Smrg scroll_update_one(&(screen->rawPos)); 2156d522f475Smrg 2157d522f475Smrg /* 2158d522f475Smrg * If we are told to scroll the selection but it lies outside the scrolling 2159d522f475Smrg * margins, then that could cause the selection to move (bad). It is not 2160d522f475Smrg * simple to fix, because this function is called both for the scrollbar 2161d522f475Smrg * actions as well as application scrolling. The 'always' flag is set in 2162d522f475Smrg * the former case. The rest of the logic handles the latter. 2163d522f475Smrg */ 2164d522f475Smrg if (ScrnHaveSelection(screen)) { 2165d522f475Smrg int adjust; 2166d522f475Smrg 2167d522f475Smrg adjust = ROW2INX(screen, screen->startH.row); 2168d522f475Smrg if (always 2169d522f475Smrg || !ScrnHaveLineMargins(screen) 2170d522f475Smrg || ScrnIsLineInMargins(screen, adjust)) { 2171d522f475Smrg scroll_update_one(&screen->startH); 2172d522f475Smrg } 2173d522f475Smrg adjust = ROW2INX(screen, screen->endH.row); 2174d522f475Smrg if (always 2175d522f475Smrg || !ScrnHaveLineMargins(screen) 2176d522f475Smrg || ScrnIsLineInMargins(screen, adjust)) { 2177d522f475Smrg scroll_update_one(&screen->endH); 2178d522f475Smrg } 2179d522f475Smrg } 2180d522f475Smrg 2181d522f475Smrg screen->startHCoord = Coordinate(screen, &screen->startH); 2182d522f475Smrg screen->endHCoord = Coordinate(screen, &screen->endH); 2183d522f475Smrg} 2184d522f475Smrg 2185d522f475Smrg/*ARGSUSED*/ 2186d522f475Smrgvoid 2187d522f475SmrgResizeSelection(TScreen * screen GCC_UNUSED, int rows, int cols) 2188d522f475Smrg{ 2189d522f475Smrg rows--; /* decr to get 0-max */ 2190d522f475Smrg cols--; 2191d522f475Smrg 2192d522f475Smrg if (screen->startRaw.row > rows) 2193d522f475Smrg screen->startRaw.row = rows; 2194d522f475Smrg if (screen->startSel.row > rows) 2195d522f475Smrg screen->startSel.row = rows; 2196d522f475Smrg if (screen->endRaw.row > rows) 2197d522f475Smrg screen->endRaw.row = rows; 2198d522f475Smrg if (screen->endSel.row > rows) 2199d522f475Smrg screen->endSel.row = rows; 2200d522f475Smrg if (screen->rawPos.row > rows) 2201d522f475Smrg screen->rawPos.row = rows; 2202d522f475Smrg 2203d522f475Smrg if (screen->startRaw.col > cols) 2204d522f475Smrg screen->startRaw.col = cols; 2205d522f475Smrg if (screen->startSel.col > cols) 2206d522f475Smrg screen->startSel.col = cols; 2207d522f475Smrg if (screen->endRaw.col > cols) 2208d522f475Smrg screen->endRaw.col = cols; 2209d522f475Smrg if (screen->endSel.col > cols) 2210d522f475Smrg screen->endSel.col = cols; 2211d522f475Smrg if (screen->rawPos.col > cols) 2212d522f475Smrg screen->rawPos.col = cols; 2213d522f475Smrg} 2214d522f475Smrg 2215d522f475Smrg#if OPT_WIDE_CHARS 2216d522f475SmrgBool 2217d522f475Smrgiswide(int i) 2218d522f475Smrg{ 2219d522f475Smrg return (i == HIDDEN_CHAR) || (my_wcwidth(i) == 2); 2220d522f475Smrg} 2221d522f475Smrg 2222d522f475Smrg#define isWideCell(row, col) iswide((int)XTERM_CELL(row, col)) 2223d522f475Smrg#endif 2224d522f475Smrg 2225d522f475Smrgstatic void 2226d522f475SmrgPointToCELL(TScreen * screen, 2227d522f475Smrg int y, 2228d522f475Smrg int x, 2229d522f475Smrg CELL * cell) 2230d522f475Smrg/* Convert pixel coordinates to character coordinates. 2231d522f475Smrg Rows are clipped between firstValidRow and lastValidRow. 2232d522f475Smrg Columns are clipped between to be 0 or greater, but are not clipped to some 2233d522f475Smrg maximum value. */ 2234d522f475Smrg{ 2235d522f475Smrg cell->row = (y - screen->border) / FontHeight(screen); 2236d522f475Smrg if (cell->row < screen->firstValidRow) 2237d522f475Smrg cell->row = screen->firstValidRow; 2238d522f475Smrg else if (cell->row > screen->lastValidRow) 2239d522f475Smrg cell->row = screen->lastValidRow; 2240d522f475Smrg cell->col = (x - OriginX(screen)) / FontWidth(screen); 2241d522f475Smrg if (cell->col < 0) 2242d522f475Smrg cell->col = 0; 2243d522f475Smrg else if (cell->col > MaxCols(screen)) { 2244d522f475Smrg cell->col = MaxCols(screen); 2245d522f475Smrg } 2246d522f475Smrg#if OPT_WIDE_CHARS 2247d522f475Smrg /* 2248d522f475Smrg * If we got a click on the right half of a doublewidth character, 2249d522f475Smrg * pretend it happened on the left half. 2250d522f475Smrg */ 2251d522f475Smrg if (cell->col > 0 2252d522f475Smrg && isWideCell(cell->row, cell->col - 1) 2253d522f475Smrg && (XTERM_CELL(cell->row, cell->col) == HIDDEN_CHAR)) { 2254d522f475Smrg cell->col -= 1; 2255d522f475Smrg } 2256d522f475Smrg#endif 2257d522f475Smrg} 2258d522f475Smrg 2259d522f475Smrg/* 2260d522f475Smrg * Find the last column at which text was drawn on the given row. 2261d522f475Smrg */ 2262d522f475Smrgstatic int 2263d522f475SmrgLastTextCol(TScreen * screen, int row) 2264d522f475Smrg{ 2265d522f475Smrg int inx = ROW2INX(screen, row); 2266d522f475Smrg int i; 2267d522f475Smrg Char *ch; 2268d522f475Smrg 2269d522f475Smrg if (inx + screen->savedlines >= 0) { 2270d522f475Smrg for (i = screen->max_col, 2271d522f475Smrg ch = SCRN_BUF_ATTRS(screen, inx) + i; 2272d522f475Smrg i >= 0 && !(*ch & CHARDRAWN); 2273d522f475Smrg ch--, i--) ; 2274d522f475Smrg#if OPT_DEC_CHRSET 2275d522f475Smrg if (CSET_DOUBLE(SCRN_BUF_CSETS(screen, inx)[0])) { 2276d522f475Smrg i *= 2; 2277d522f475Smrg } 2278d522f475Smrg#endif 2279d522f475Smrg } else { 2280d522f475Smrg i = -1; 2281d522f475Smrg } 2282d522f475Smrg return (i); 2283d522f475Smrg} 2284d522f475Smrg 2285d522f475Smrg#if !OPT_WIDE_CHARS 2286d522f475Smrg/* 2287d522f475Smrg** double click table for cut and paste in 8 bits 2288d522f475Smrg** 2289d522f475Smrg** This table is divided in four parts : 2290d522f475Smrg** 2291d522f475Smrg** - control characters [0,0x1f] U [0x80,0x9f] 2292d522f475Smrg** - separators [0x20,0x3f] U [0xa0,0xb9] 2293d522f475Smrg** - binding characters [0x40,0x7f] U [0xc0,0xff] 2294d522f475Smrg** - exceptions 2295d522f475Smrg*/ 2296d522f475Smrg/* *INDENT-OFF* */ 2297d522f475Smrgstatic int charClass[256] = 2298d522f475Smrg{ 2299d522f475Smrg/* NUL SOH STX ETX EOT ENQ ACK BEL */ 2300d522f475Smrg 32, 1, 1, 1, 1, 1, 1, 1, 2301d522f475Smrg/* BS HT NL VT NP CR SO SI */ 2302d522f475Smrg 1, 32, 1, 1, 1, 1, 1, 1, 2303d522f475Smrg/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 2304d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2305d522f475Smrg/* CAN EM SUB ESC FS GS RS US */ 2306d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2307d522f475Smrg/* SP ! " # $ % & ' */ 2308d522f475Smrg 32, 33, 34, 35, 36, 37, 38, 39, 2309d522f475Smrg/* ( ) * + , - . / */ 2310d522f475Smrg 40, 41, 42, 43, 44, 45, 46, 47, 2311d522f475Smrg/* 0 1 2 3 4 5 6 7 */ 2312d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2313d522f475Smrg/* 8 9 : ; < = > ? */ 2314d522f475Smrg 48, 48, 58, 59, 60, 61, 62, 63, 2315d522f475Smrg/* @ A B C D E F G */ 2316d522f475Smrg 64, 48, 48, 48, 48, 48, 48, 48, 2317d522f475Smrg/* H I J K L M N O */ 2318d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2319d522f475Smrg/* P Q R S T U V W */ 2320d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2321d522f475Smrg/* X Y Z [ \ ] ^ _ */ 2322d522f475Smrg 48, 48, 48, 91, 92, 93, 94, 48, 2323d522f475Smrg/* ` a b c d e f g */ 2324d522f475Smrg 96, 48, 48, 48, 48, 48, 48, 48, 2325d522f475Smrg/* h i j k l m n o */ 2326d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2327d522f475Smrg/* p q r s t u v w */ 2328d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2329d522f475Smrg/* x y z { | } ~ DEL */ 2330d522f475Smrg 48, 48, 48, 123, 124, 125, 126, 1, 2331d522f475Smrg/* x80 x81 x82 x83 IND NEL SSA ESA */ 2332d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2333d522f475Smrg/* HTS HTJ VTS PLD PLU RI SS2 SS3 */ 2334d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2335d522f475Smrg/* DCS PU1 PU2 STS CCH MW SPA EPA */ 2336d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2337d522f475Smrg/* x98 x99 x9A CSI ST OSC PM APC */ 2338d522f475Smrg 1, 1, 1, 1, 1, 1, 1, 1, 2339d522f475Smrg/* - i c/ L ox Y- | So */ 2340d522f475Smrg 160, 161, 162, 163, 164, 165, 166, 167, 2341d522f475Smrg/* .. c0 ip << _ R0 - */ 2342d522f475Smrg 168, 169, 170, 171, 172, 173, 174, 175, 2343d522f475Smrg/* o +- 2 3 ' u q| . */ 2344d522f475Smrg 176, 177, 178, 179, 180, 181, 182, 183, 2345d522f475Smrg/* , 1 2 >> 1/4 1/2 3/4 ? */ 2346d522f475Smrg 184, 185, 186, 187, 188, 189, 190, 191, 2347d522f475Smrg/* A` A' A^ A~ A: Ao AE C, */ 2348d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2349d522f475Smrg/* E` E' E^ E: I` I' I^ I: */ 2350d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2351d522f475Smrg/* D- N~ O` O' O^ O~ O: X */ 2352d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 215, 2353d522f475Smrg/* O/ U` U' U^ U: Y' P B */ 2354d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2355d522f475Smrg/* a` a' a^ a~ a: ao ae c, */ 2356d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2357d522f475Smrg/* e` e' e^ e: i` i' i^ i: */ 2358d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48, 2359d522f475Smrg/* d n~ o` o' o^ o~ o: -: */ 2360d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 247, 2361d522f475Smrg/* o/ u` u' u^ u: y' P y: */ 2362d522f475Smrg 48, 48, 48, 48, 48, 48, 48, 48}; 2363d522f475Smrg/* *INDENT-ON* */ 2364d522f475Smrg 2365d522f475Smrgint 2366d522f475SmrgSetCharacterClassRange(int low, /* in range of [0..255] */ 2367d522f475Smrg int high, 2368d522f475Smrg int value) /* arbitrary */ 2369d522f475Smrg{ 2370d522f475Smrg 2371d522f475Smrg if (low < 0 || high > 255 || high < low) 2372d522f475Smrg return (-1); 2373d522f475Smrg 2374d522f475Smrg for (; low <= high; low++) 2375d522f475Smrg charClass[low] = value; 2376d522f475Smrg 2377d522f475Smrg return (0); 2378d522f475Smrg} 2379d522f475Smrg#endif 2380d522f475Smrg 2381d522f475Smrg#if OPT_WIDE_CHARS 2382d522f475Smrgstatic int 2383d522f475Smrgclass_of(TScreen * screen, CELL * cell) 2384d522f475Smrg{ 2385d522f475Smrg CELL temp = *cell; 2386d522f475Smrg int value; 2387d522f475Smrg 2388d522f475Smrg#if OPT_DEC_CHRSET 2389d522f475Smrg if (CSET_DOUBLE(SCRN_BUF_CSETS(screen, ROW2INX(screen, temp.row))[0])) { 2390d522f475Smrg temp.col /= 2; 2391d522f475Smrg } 2392d522f475Smrg#endif 2393d522f475Smrg 23942eaa94a1Schristos value = (int) XTERM_CELL(temp.row, temp.col); 2395d522f475Smrg if_OPT_WIDE_CHARS(screen, { 2396d522f475Smrg return CharacterClass(value); 2397d522f475Smrg }); 2398d522f475Smrg return CharacterClass(value); 2399d522f475Smrg} 2400d522f475Smrg#define ClassSelects(screen, cell, cclass) \ 2401d522f475Smrg (class_of(screen, cell) == cclass \ 2402d522f475Smrg || XTERM_CELL((cell)->row, (cell)->col) == HIDDEN_CHAR) 2403d522f475Smrg#else 2404d522f475Smrg#define class_of(screen, cell) charClass[XTERM_CELL((cell)->row, (cell)->col)] 2405d522f475Smrg#define ClassSelects(screen, cell, cclass) \ 2406d522f475Smrg (class_of(screen, (cell)) == cclass) 2407d522f475Smrg#endif 2408d522f475Smrg 2409d522f475Smrg/* 2410d522f475Smrg * If the given column is past the end of text on the given row, bump to the 2411d522f475Smrg * beginning of the next line. 2412d522f475Smrg */ 2413d522f475Smrgstatic Boolean 2414d522f475SmrgokPosition(TScreen * screen, 2415d522f475Smrg CELL * cell) 2416d522f475Smrg{ 2417d522f475Smrg if (cell->col > (LastTextCol(screen, cell->row) + 1)) { 2418d522f475Smrg cell->col = 0; 2419d522f475Smrg cell->row += 1; 2420d522f475Smrg return False; 2421d522f475Smrg } 2422d522f475Smrg return True; 2423d522f475Smrg} 2424d522f475Smrg 2425d522f475Smrgstatic void 2426d522f475SmrgtrimLastLine(TScreen * screen, CELL * last) 2427d522f475Smrg{ 2428d522f475Smrg if (screen->cutNewline) { 2429d522f475Smrg last->col = 0; 2430d522f475Smrg ++last->row; 2431d522f475Smrg } else { 2432d522f475Smrg last->col = LastTextCol(screen, last->row) + 1; 2433d522f475Smrg } 2434d522f475Smrg} 2435d522f475Smrg 2436d522f475Smrg#if OPT_SELECT_REGEX 2437d522f475Smrg/* 2438d522f475Smrg * Returns the first row of a wrapped line. 2439d522f475Smrg */ 2440d522f475Smrgstatic int 2441d522f475SmrgfirstRowOfLine(TScreen * screen, int row, Bool visible) 2442d522f475Smrg{ 2443d522f475Smrg int limit = visible ? 0 : -screen->savedlines; 2444d522f475Smrg 2445d522f475Smrg while (row > limit && 2446d522f475Smrg ScrnTstWrapped(screen, row - 1)) 2447d522f475Smrg --row; 2448d522f475Smrg return row; 2449d522f475Smrg} 2450d522f475Smrg 2451d522f475Smrg/* 2452d522f475Smrg * Returns the last row of a wrapped line. 2453d522f475Smrg */ 2454d522f475Smrgstatic int 2455d522f475SmrglastRowOfLine(TScreen * screen, int row) 2456d522f475Smrg{ 2457d522f475Smrg while (row < screen->max_row && 2458d522f475Smrg ScrnTstWrapped(screen, row)) 2459d522f475Smrg ++row; 2460d522f475Smrg return row; 2461d522f475Smrg} 2462d522f475Smrg 2463d522f475Smrg/* 2464d522f475Smrg * Returns the number of cells on the range of rows. 2465d522f475Smrg */ 2466d522f475Smrgstatic unsigned 2467d522f475SmrglengthOfLines(TScreen * screen, int firstRow, int lastRow) 2468d522f475Smrg{ 2469d522f475Smrg unsigned length = 0; 2470d522f475Smrg int n; 2471d522f475Smrg 2472d522f475Smrg for (n = firstRow; n <= lastRow; ++n) { 2473d522f475Smrg int value = LastTextCol(screen, n); 2474d522f475Smrg if (value >= 0) 24752eaa94a1Schristos length += (unsigned) (value + 1); 2476d522f475Smrg } 2477d522f475Smrg return length; 2478d522f475Smrg} 2479d522f475Smrg 2480d522f475Smrg/* 2481d522f475Smrg * Make a copy of the wrapped-line which corresponds to the given row as a 2482d522f475Smrg * string of bytes. Construct an index for the columns from the beginning of 2483d522f475Smrg * the line. 2484d522f475Smrg */ 2485d522f475Smrgstatic char * 2486d522f475Smrgmake_indexed_text(TScreen * screen, int row, unsigned length, int *indexed) 2487d522f475Smrg{ 2488d522f475Smrg Char *result = 0; 2489d522f475Smrg unsigned need = (length + 1); 2490d522f475Smrg 2491d522f475Smrg /* 2492d522f475Smrg * Get a quick upper bound to the number of bytes needed, if the whole 2493d522f475Smrg * string were UTF-8. 2494d522f475Smrg */ 2495d522f475Smrg if_OPT_WIDE_CHARS(screen, { 24962eaa94a1Schristos need *= (unsigned) (MAX_PTRS * 6); 2497d522f475Smrg }); 2498d522f475Smrg 2499d522f475Smrg if ((result = TypeCallocN(Char, need + 1)) != 0) { 2500d522f475Smrg unsigned used = 0; 2501d522f475Smrg Char *last = result; 2502d522f475Smrg 2503d522f475Smrg do { 2504d522f475Smrg int col = 0; 2505d522f475Smrg int limit = LastTextCol(screen, row); 2506d522f475Smrg 2507d522f475Smrg while (col <= limit) { 2508d522f475Smrg Char *next = last; 2509d522f475Smrg unsigned data = XTERM_CELL(row, col); 2510d522f475Smrg 2511d522f475Smrg /* some internal points may not be drawn */ 2512d522f475Smrg if (data == 0) 2513d522f475Smrg data = ' '; 2514d522f475Smrg 2515d522f475Smrg if_WIDE_OR_NARROW(screen, { 2516d522f475Smrg next = convertToUTF8(last, data); 2517d522f475Smrg } 2518d522f475Smrg , { 2519d522f475Smrg *next++ = CharOf(data); 2520d522f475Smrg }); 2521d522f475Smrg 2522d522f475Smrg if_OPT_WIDE_CHARS(screen, { 2523d522f475Smrg int off; 2524d522f475Smrg for (off = OFF_FINAL; off < MAX_PTRS; off += 2) { 2525d522f475Smrg if ((data = XTERM_CELLC(row, col, off)) == 0) 2526d522f475Smrg break; 2527d522f475Smrg next = convertToUTF8(next, data); 2528d522f475Smrg } 2529d522f475Smrg }); 2530d522f475Smrg 2531d522f475Smrg indexed[used] = last - result; 2532d522f475Smrg *next = 0; 2533d522f475Smrg /* TRACE(("index[%d.%d] %d:%s\n", row, used, indexed[used], last)); */ 2534d522f475Smrg last = next; 2535d522f475Smrg ++used; 2536d522f475Smrg ++col; 2537d522f475Smrg indexed[used] = next - result; 2538d522f475Smrg } 2539d522f475Smrg } while (used < length && 2540d522f475Smrg ScrnTstWrapped(screen, row) && 2541d522f475Smrg ++row < screen->max_row); 2542d522f475Smrg } 2543d522f475Smrg /* TRACE(("result:%s\n", result)); */ 2544d522f475Smrg return (char *) result; 2545d522f475Smrg} 2546d522f475Smrg 2547d522f475Smrg/* 2548d522f475Smrg * Find the column given an offset into the character string by using the 2549d522f475Smrg * index constructed in make_indexed_text(). 2550d522f475Smrg */ 2551d522f475Smrgstatic int 2552d522f475SmrgindexToCol(int *indexed, int len, int off) 2553d522f475Smrg{ 2554d522f475Smrg int col = 0; 2555d522f475Smrg while (indexed[col] < len) { 2556d522f475Smrg if (indexed[col] >= off) 2557d522f475Smrg break; 2558d522f475Smrg ++col; 2559d522f475Smrg } 2560d522f475Smrg return col; 2561d522f475Smrg} 2562d522f475Smrg 2563d522f475Smrg/* 2564d522f475Smrg * Given a row number, and a column offset from that (which may be wrapped), 2565d522f475Smrg * set the cell to the actual row/column values. 2566d522f475Smrg */ 2567d522f475Smrgstatic void 2568d522f475SmrgcolumnToCell(TScreen * screen, int row, int col, CELL * cell) 2569d522f475Smrg{ 2570d522f475Smrg while (row < screen->max_row) { 2571d522f475Smrg int last = LastTextCol(screen, row); 2572d522f475Smrg 2573d522f475Smrg /* TRACE(("last(%d) = %d, have %d\n", row, last, col)); */ 2574d522f475Smrg if (col <= last) { 2575d522f475Smrg break; 2576d522f475Smrg } 2577d522f475Smrg /* 2578d522f475Smrg * Stop if the current row does not wrap (does not continue the current 2579d522f475Smrg * line). 2580d522f475Smrg */ 2581d522f475Smrg if (!ScrnTstWrapped(screen, row)) { 2582d522f475Smrg col = last + 1; 2583d522f475Smrg break; 2584d522f475Smrg } 2585d522f475Smrg col -= (last + 1); 2586d522f475Smrg ++row; 2587d522f475Smrg } 2588d522f475Smrg if (col < 0) 2589d522f475Smrg col = 0; 2590d522f475Smrg cell->row = row; 2591d522f475Smrg cell->col = col; 2592d522f475Smrg} 2593d522f475Smrg 2594d522f475Smrg/* 2595d522f475Smrg * Given a cell, find the corresponding column offset. 2596d522f475Smrg */ 2597d522f475Smrgstatic int 2598d522f475SmrgcellToColumn(TScreen * screen, CELL * cell) 2599d522f475Smrg{ 2600d522f475Smrg int col = cell->col; 2601d522f475Smrg int row = firstRowOfLine(screen, cell->row, False); 2602d522f475Smrg while (row < cell->row) { 2603d522f475Smrg col += LastTextCol(screen, row++); 2604d522f475Smrg } 2605d522f475Smrg return col; 2606d522f475Smrg} 2607d522f475Smrg 2608d522f475Smrgstatic void 2609d522f475Smrgdo_select_regex(TScreen * screen, CELL * startc, CELL * endc) 2610d522f475Smrg{ 2611d522f475Smrg int inx = ((screen->numberOfClicks - 1) % screen->maxClicks); 2612d522f475Smrg char *expr = screen->selectExpr[inx]; 2613d522f475Smrg regex_t preg; 2614d522f475Smrg regmatch_t match; 2615d522f475Smrg char *search; 2616d522f475Smrg int *indexed; 2617d522f475Smrg 2618d522f475Smrg TRACE(("Select_REGEX:%s\n", NonNull(expr))); 2619d522f475Smrg if (okPosition(screen, startc) && expr != 0) { 2620d522f475Smrg if (regcomp(&preg, expr, REG_EXTENDED) == 0) { 2621d522f475Smrg int firstRow = firstRowOfLine(screen, startc->row, True); 2622d522f475Smrg int lastRow = lastRowOfLine(screen, firstRow); 2623d522f475Smrg unsigned size = lengthOfLines(screen, firstRow, lastRow); 2624d522f475Smrg int actual = cellToColumn(screen, startc); 2625d522f475Smrg 2626d522f475Smrg TRACE(("regcomp ok rows %d..%d bytes %d\n", 2627d522f475Smrg firstRow, lastRow, size)); 2628d522f475Smrg 2629d522f475Smrg if ((indexed = TypeCallocN(int, size + 1)) != 0) { 2630d522f475Smrg if ((search = make_indexed_text(screen, 2631d522f475Smrg firstRow, 2632d522f475Smrg size, 2633d522f475Smrg indexed)) != 0) { 26342eaa94a1Schristos int len = (int) strlen(search); 2635d522f475Smrg int col; 2636d522f475Smrg int best_col = -1; 2637d522f475Smrg int best_len = -1; 2638d522f475Smrg 2639d522f475Smrg for (col = 0; indexed[col] < len; ++col) { 2640d522f475Smrg if (regexec(&preg, 2641d522f475Smrg search + indexed[col], 2642d522f475Smrg 1, &match, 0) == 0) { 2643d522f475Smrg int start_inx = match.rm_so + indexed[col]; 2644d522f475Smrg int finis_inx = match.rm_eo + indexed[col]; 2645d522f475Smrg int start_col = indexToCol(indexed, len, start_inx); 2646d522f475Smrg int finis_col = indexToCol(indexed, len, finis_inx); 2647d522f475Smrg 2648d522f475Smrg if (start_col <= actual && 2649d522f475Smrg actual < finis_col) { 2650d522f475Smrg int test = finis_col - start_col; 2651d522f475Smrg if (best_len < test) { 2652d522f475Smrg best_len = test; 2653d522f475Smrg best_col = start_col; 2654d522f475Smrg TRACE(("match column %d len %d\n", 2655d522f475Smrg best_col, 2656d522f475Smrg best_len)); 2657d522f475Smrg } 2658d522f475Smrg } 2659d522f475Smrg } 2660d522f475Smrg } 2661d522f475Smrg if (best_col >= 0) { 2662d522f475Smrg int best_nxt = best_col + best_len; 2663d522f475Smrg columnToCell(screen, firstRow, best_col, startc); 2664d522f475Smrg columnToCell(screen, firstRow, best_nxt, endc); 2665d522f475Smrg TRACE(("search::%s\n", search)); 2666d522f475Smrg TRACE(("indexed:%d..%d -> %d..%d\n", 2667d522f475Smrg best_col, best_nxt, 2668d522f475Smrg indexed[best_col], 2669d522f475Smrg indexed[best_nxt])); 2670d522f475Smrg TRACE(("matched:%d:%s\n", 2671d522f475Smrg indexed[best_nxt] + 1 - 2672d522f475Smrg indexed[best_col], 2673d522f475Smrg visibleChars(PAIRED_CHARS((Char *) (search + 2674d522f475Smrg indexed[best_col]), 2675d522f475Smrg 0), 2676d522f475Smrg (unsigned) (indexed[best_nxt] + 2677d522f475Smrg 1 - 2678d522f475Smrg indexed[best_col])))); 2679d522f475Smrg } 2680d522f475Smrg free(search); 2681d522f475Smrg } 2682d522f475Smrg free(indexed); 2683d522f475Smrg } 2684d522f475Smrg regfree(&preg); 2685d522f475Smrg } 2686d522f475Smrg } 2687d522f475Smrg} 2688d522f475Smrg#endif /* OPT_SELECT_REGEX */ 2689d522f475Smrg 2690d522f475Smrg/* 2691d522f475Smrg * sets startSel endSel 2692d522f475Smrg * ensuring that they have legal values 2693d522f475Smrg */ 2694d522f475Smrgstatic void 2695d522f475SmrgComputeSelect(XtermWidget xw, 2696d522f475Smrg CELL * startc, 2697d522f475Smrg CELL * endc, 2698d522f475Smrg Bool extend) 2699d522f475Smrg{ 2700d522f475Smrg TScreen *screen = &(xw->screen); 2701d522f475Smrg int length; 2702d522f475Smrg int cclass; 2703d522f475Smrg CELL first = *startc; 2704d522f475Smrg CELL last = *endc; 2705d522f475Smrg 2706d522f475Smrg TRACE(("ComputeSelect(startRow=%d, startCol=%d, endRow=%d, endCol=%d, %sextend)\n", 2707d522f475Smrg first.row, first.col, 2708d522f475Smrg last.row, last.col, 2709d522f475Smrg extend ? "" : "no")); 2710d522f475Smrg 2711d522f475Smrg#if OPT_WIDE_CHARS 2712d522f475Smrg if (first.col > 1 2713d522f475Smrg && isWideCell(first.row, first.col - 1) 2714d522f475Smrg && XTERM_CELL(first.row, first.col - 0) == HIDDEN_CHAR) { 2715d522f475Smrg fprintf(stderr, "Adjusting start. Changing downwards from %i.\n", first.col); 2716d522f475Smrg first.col -= 1; 2717d522f475Smrg if (last.col == (first.col + 1)) 2718d522f475Smrg last.col--; 2719d522f475Smrg } 2720d522f475Smrg 2721d522f475Smrg if (last.col > 1 2722d522f475Smrg && isWideCell(last.row, last.col - 1) 2723d522f475Smrg && XTERM_CELL(last.row, last.col) == HIDDEN_CHAR) { 2724d522f475Smrg last.col += 1; 2725d522f475Smrg } 2726d522f475Smrg#endif 2727d522f475Smrg 2728d522f475Smrg if (Coordinate(screen, &first) <= Coordinate(screen, &last)) { 2729d522f475Smrg screen->startSel = screen->startRaw = first; 2730d522f475Smrg screen->endSel = screen->endRaw = last; 2731d522f475Smrg } else { /* Swap them */ 2732d522f475Smrg screen->startSel = screen->startRaw = last; 2733d522f475Smrg screen->endSel = screen->endRaw = first; 2734d522f475Smrg } 2735d522f475Smrg 2736d522f475Smrg switch (screen->selectUnit) { 2737d522f475Smrg case Select_CHAR: 2738d522f475Smrg (void) okPosition(screen, &(screen->startSel)); 2739d522f475Smrg (void) okPosition(screen, &(screen->endSel)); 2740d522f475Smrg break; 2741d522f475Smrg 2742d522f475Smrg case Select_WORD: 2743d522f475Smrg TRACE(("Select_WORD\n")); 2744d522f475Smrg if (okPosition(screen, &(screen->startSel))) { 2745d522f475Smrg cclass = class_of(screen, &(screen->startSel)); 2746d522f475Smrg do { 2747d522f475Smrg --screen->startSel.col; 2748d522f475Smrg if (screen->startSel.row > 0 2749d522f475Smrg && screen->startSel.col < 0 2750d522f475Smrg && ScrnTstWrapped(screen, screen->startSel.row - 1)) { 2751d522f475Smrg --screen->startSel.row; 2752d522f475Smrg screen->startSel.col = LastTextCol(screen, screen->startSel.row); 2753d522f475Smrg } 2754d522f475Smrg } while (screen->startSel.col >= 0 2755d522f475Smrg && ClassSelects(screen, &(screen->startSel), cclass)); 2756d522f475Smrg ++screen->startSel.col; 2757d522f475Smrg } 2758d522f475Smrg#if OPT_WIDE_CHARS 2759d522f475Smrg if (screen->startSel.col 2760d522f475Smrg && XTERM_CELL(screen->startSel.row, 2761d522f475Smrg screen->startSel.col) == HIDDEN_CHAR) 2762d522f475Smrg screen->startSel.col++; 2763d522f475Smrg#endif 2764d522f475Smrg 2765d522f475Smrg if (okPosition(screen, &(screen->endSel))) { 2766d522f475Smrg length = LastTextCol(screen, screen->endSel.row); 2767d522f475Smrg cclass = class_of(screen, &(screen->endSel)); 2768d522f475Smrg do { 2769d522f475Smrg ++screen->endSel.col; 2770d522f475Smrg if (screen->endSel.col > length 2771d522f475Smrg && ScrnTstWrapped(screen, screen->endSel.row)) { 2772d522f475Smrg screen->endSel.col = 0; 2773d522f475Smrg ++screen->endSel.row; 2774d522f475Smrg length = LastTextCol(screen, screen->endSel.row); 2775d522f475Smrg } 2776d522f475Smrg } while (screen->endSel.col <= length 2777d522f475Smrg && ClassSelects(screen, &(screen->endSel), cclass)); 2778d522f475Smrg /* Word-select selects if pointing to any char in "word", 2779d522f475Smrg * especially note that it includes the last character in a word. 2780d522f475Smrg * So we do no --endSel.col and do special eol handling. 2781d522f475Smrg */ 2782d522f475Smrg if (screen->endSel.col > length + 1) { 2783d522f475Smrg screen->endSel.col = 0; 2784d522f475Smrg ++screen->endSel.row; 2785d522f475Smrg } 2786d522f475Smrg } 2787d522f475Smrg#if OPT_WIDE_CHARS 2788d522f475Smrg if (screen->endSel.col 2789d522f475Smrg && XTERM_CELL(screen->endSel.row, 2790d522f475Smrg screen->endSel.col) == HIDDEN_CHAR) 2791d522f475Smrg screen->endSel.col++; 2792d522f475Smrg#endif 2793d522f475Smrg 2794d522f475Smrg screen->saveStartW = screen->startSel; 2795d522f475Smrg break; 2796d522f475Smrg 2797d522f475Smrg case Select_LINE: 2798d522f475Smrg TRACE(("Select_LINE\n")); 2799d522f475Smrg while (ScrnTstWrapped(screen, screen->endSel.row)) { 2800d522f475Smrg ++screen->endSel.row; 2801d522f475Smrg } 2802d522f475Smrg if (screen->cutToBeginningOfLine 2803d522f475Smrg || screen->startSel.row < screen->saveStartW.row) { 2804d522f475Smrg screen->startSel.col = 0; 2805d522f475Smrg while (screen->startSel.row > 0 2806d522f475Smrg && ScrnTstWrapped(screen, screen->startSel.row - 1)) { 2807d522f475Smrg --screen->startSel.row; 2808d522f475Smrg } 2809d522f475Smrg } else if (!extend) { 2810d522f475Smrg if ((first.row < screen->saveStartW.row) 2811d522f475Smrg || (isSameRow(&first, &(screen->saveStartW)) 2812d522f475Smrg && first.col < screen->saveStartW.col)) { 2813d522f475Smrg screen->startSel.col = 0; 2814d522f475Smrg while (screen->startSel.row > 0 2815d522f475Smrg && ScrnTstWrapped(screen, screen->startSel.row - 1)) { 2816d522f475Smrg --screen->startSel.row; 2817d522f475Smrg } 2818d522f475Smrg } else { 2819d522f475Smrg screen->startSel = screen->saveStartW; 2820d522f475Smrg } 2821d522f475Smrg } 2822d522f475Smrg trimLastLine(screen, &(screen->endSel)); 2823d522f475Smrg break; 2824d522f475Smrg 2825d522f475Smrg case Select_GROUP: /* paragraph */ 2826d522f475Smrg TRACE(("Select_GROUP\n")); 2827d522f475Smrg if (okPosition(screen, &(screen->startSel))) { 2828d522f475Smrg /* scan backward for beginning of group */ 2829d522f475Smrg while (screen->startSel.row > 0 && 2830d522f475Smrg (LastTextCol(screen, screen->startSel.row - 1) > 0 || 2831d522f475Smrg ScrnTstWrapped(screen, screen->startSel.row - 1))) { 2832d522f475Smrg --screen->startSel.row; 2833d522f475Smrg } 2834d522f475Smrg screen->startSel.col = 0; 2835d522f475Smrg /* scan forward for end of group */ 2836d522f475Smrg while (screen->endSel.row < screen->max_row && 2837d522f475Smrg (LastTextCol(screen, screen->endSel.row + 1) > 0 || 2838d522f475Smrg ScrnTstWrapped(screen, screen->endSel.row))) { 2839d522f475Smrg ++screen->endSel.row; 2840d522f475Smrg } 2841d522f475Smrg trimLastLine(screen, &(screen->endSel)); 2842d522f475Smrg } 2843d522f475Smrg break; 2844d522f475Smrg 2845d522f475Smrg case Select_PAGE: /* everything one can see */ 2846d522f475Smrg TRACE(("Select_PAGE\n")); 2847d522f475Smrg screen->startSel.row = 0; 2848d522f475Smrg screen->startSel.col = 0; 2849d522f475Smrg screen->endSel.row = screen->max_row + 1; 2850d522f475Smrg screen->endSel.col = 0; 2851d522f475Smrg break; 2852d522f475Smrg 2853d522f475Smrg case Select_ALL: /* counts scrollback if in normal screen */ 2854d522f475Smrg TRACE(("Select_ALL\n")); 2855d522f475Smrg screen->startSel.row = -screen->savedlines; 2856d522f475Smrg screen->startSel.col = 0; 2857d522f475Smrg screen->endSel.row = screen->max_row + 1; 2858d522f475Smrg screen->endSel.col = 0; 2859d522f475Smrg break; 2860d522f475Smrg 2861d522f475Smrg#if OPT_SELECT_REGEX 2862d522f475Smrg case Select_REGEX: 2863d522f475Smrg do_select_regex(screen, &(screen->startSel), &(screen->endSel)); 2864d522f475Smrg break; 2865d522f475Smrg#endif 2866d522f475Smrg 2867d522f475Smrg case NSELECTUNITS: /* always ignore */ 2868d522f475Smrg return; 2869d522f475Smrg } 2870d522f475Smrg 2871d522f475Smrg /* check boundaries */ 2872d522f475Smrg ScrollSelection(screen, 0, False); 2873d522f475Smrg 2874d522f475Smrg TrackText(xw, &(screen->startSel), &(screen->endSel)); 2875d522f475Smrg return; 2876d522f475Smrg} 2877d522f475Smrg 2878d522f475Smrg/* Guaranteed (first.row, first.col) <= (last.row, last.col) */ 2879d522f475Smrgstatic void 2880d522f475SmrgTrackText(XtermWidget xw, 2881d522f475Smrg const CELL * firstp, 2882d522f475Smrg const CELL * lastp) 2883d522f475Smrg{ 2884d522f475Smrg TScreen *screen = &(xw->screen); 2885d522f475Smrg int from, to; 2886d522f475Smrg CELL old_start, old_end; 2887d522f475Smrg CELL first = *firstp; 2888d522f475Smrg CELL last = *lastp; 2889d522f475Smrg 2890d522f475Smrg TRACE(("TrackText(first=%d,%d, last=%d,%d)\n", 2891d522f475Smrg first.row, first.col, last.row, last.col)); 2892d522f475Smrg 2893d522f475Smrg old_start = screen->startH; 2894d522f475Smrg old_end = screen->endH; 2895d522f475Smrg if (isSameCELL(&first, &old_start) && 2896d522f475Smrg isSameCELL(&last, &old_end)) 2897d522f475Smrg return; 2898d522f475Smrg screen->startH = first; 2899d522f475Smrg screen->endH = last; 2900d522f475Smrg from = Coordinate(screen, &screen->startH); 2901d522f475Smrg to = Coordinate(screen, &screen->endH); 2902d522f475Smrg if (to <= screen->startHCoord || from > screen->endHCoord) { 2903d522f475Smrg /* No overlap whatsoever between old and new hilite */ 2904d522f475Smrg ReHiliteText(xw, &old_start, &old_end); 2905d522f475Smrg ReHiliteText(xw, &first, &last); 2906d522f475Smrg } else { 2907d522f475Smrg if (from < screen->startHCoord) { 2908d522f475Smrg /* Extend left end */ 2909d522f475Smrg ReHiliteText(xw, &first, &old_start); 2910d522f475Smrg } else if (from > screen->startHCoord) { 2911d522f475Smrg /* Shorten left end */ 2912d522f475Smrg ReHiliteText(xw, &old_start, &first); 2913d522f475Smrg } 2914d522f475Smrg if (to > screen->endHCoord) { 2915d522f475Smrg /* Extend right end */ 2916d522f475Smrg ReHiliteText(xw, &old_end, &last); 2917d522f475Smrg } else if (to < screen->endHCoord) { 2918d522f475Smrg /* Shorten right end */ 2919d522f475Smrg ReHiliteText(xw, &last, &old_end); 2920d522f475Smrg } 2921d522f475Smrg } 2922d522f475Smrg screen->startHCoord = from; 2923d522f475Smrg screen->endHCoord = to; 2924d522f475Smrg} 2925d522f475Smrg 2926d522f475Smrg/* Guaranteed that (first->row, first->col) <= (last->row, last->col) */ 2927d522f475Smrgstatic void 2928d522f475SmrgReHiliteText(XtermWidget xw, 2929d522f475Smrg CELL * firstp, 2930d522f475Smrg CELL * lastp) 2931d522f475Smrg{ 2932d522f475Smrg TScreen *screen = &(xw->screen); 2933d522f475Smrg int i; 2934d522f475Smrg CELL first = *firstp; 2935d522f475Smrg CELL last = *lastp; 2936d522f475Smrg 2937d522f475Smrg TRACE(("ReHiliteText from %d.%d to %d.%d\n", 2938d522f475Smrg first.row, first.col, last.row, last.col)); 2939d522f475Smrg 2940d522f475Smrg if (first.row < 0) 2941d522f475Smrg first.row = first.col = 0; 2942d522f475Smrg else if (first.row > screen->max_row) 2943d522f475Smrg return; /* nothing to do, since last.row >= first.row */ 2944d522f475Smrg 2945d522f475Smrg if (last.row < 0) 2946d522f475Smrg return; /* nothing to do, since first.row <= last.row */ 2947d522f475Smrg else if (last.row > screen->max_row) { 2948d522f475Smrg last.row = screen->max_row; 2949d522f475Smrg last.col = MaxCols(screen); 2950d522f475Smrg } 2951d522f475Smrg if (isSameCELL(&first, &last)) 2952d522f475Smrg return; 2953d522f475Smrg 2954d522f475Smrg if (!isSameRow(&first, &last)) { /* do multiple rows */ 2955d522f475Smrg if ((i = screen->max_col - first.col + 1) > 0) { /* first row */ 2956d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, i, True); 2957d522f475Smrg } 2958d522f475Smrg if ((i = last.row - first.row - 1) > 0) { /* middle rows */ 2959d522f475Smrg ScrnRefresh(xw, first.row + 1, 0, i, MaxCols(screen), True); 2960d522f475Smrg } 2961d522f475Smrg if (last.col > 0 && last.row <= screen->max_row) { /* last row */ 2962d522f475Smrg ScrnRefresh(xw, last.row, 0, 1, last.col, True); 2963d522f475Smrg } 2964d522f475Smrg } else { /* do single row */ 2965d522f475Smrg ScrnRefresh(xw, first.row, first.col, 1, last.col - first.col, True); 2966d522f475Smrg } 2967d522f475Smrg} 2968d522f475Smrg 2969d522f475Smrg/* 2970d522f475Smrg * Guaranteed that (cellc->row, cellc->col) <= (cell->row, cell->col), and that both points are valid 2971d522f475Smrg * (may have cell->row = screen->max_row+1, cell->col = 0). 2972d522f475Smrg */ 2973d522f475Smrgstatic void 2974d522f475SmrgSaltTextAway(XtermWidget xw, 2975d522f475Smrg CELL * cellc, 2976d522f475Smrg CELL * cell, 2977d522f475Smrg String * params, /* selections */ 2978d522f475Smrg Cardinal num_params) 2979d522f475Smrg{ 2980d522f475Smrg TScreen *screen = &(xw->screen); 2981d522f475Smrg int i, j = 0; 2982d522f475Smrg int eol; 2983d522f475Smrg Char *line; 2984d522f475Smrg Char *lp; 2985d522f475Smrg CELL first = *cellc; 2986d522f475Smrg CELL last = *cell; 2987d522f475Smrg 2988d522f475Smrg if (isSameRow(&first, &last) && first.col > last.col) { 2989d522f475Smrg int tmp = first.col; 2990d522f475Smrg first.col = last.col; 2991d522f475Smrg last.col = tmp; 2992d522f475Smrg } 2993d522f475Smrg 2994d522f475Smrg --last.col; 2995d522f475Smrg /* first we need to know how long the string is before we can save it */ 2996d522f475Smrg 2997d522f475Smrg if (isSameRow(&last, &first)) { 2998d522f475Smrg j = Length(screen, first.row, first.col, last.col); 2999d522f475Smrg } else { /* two cases, cut is on same line, cut spans multiple lines */ 3000d522f475Smrg j += Length(screen, first.row, first.col, screen->max_col) + 1; 3001d522f475Smrg for (i = first.row + 1; i < last.row; i++) 3002d522f475Smrg j += Length(screen, i, 0, screen->max_col) + 1; 3003d522f475Smrg if (last.col >= 0) 3004d522f475Smrg j += Length(screen, last.row, 0, last.col); 3005d522f475Smrg } 3006d522f475Smrg 3007d522f475Smrg /* UTF-8 may require more space */ 3008d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3009d522f475Smrg j *= 4; 3010d522f475Smrg }); 3011d522f475Smrg 3012d522f475Smrg /* now get some memory to save it in */ 3013d522f475Smrg 3014d522f475Smrg if (screen->selection_size <= j) { 3015d522f475Smrg if ((line = (Char *) malloc((unsigned) j + 1)) == 0) 3016d522f475Smrg SysError(ERROR_BMALLOC2); 3017d522f475Smrg XtFree((char *) screen->selection_data); 3018d522f475Smrg screen->selection_data = line; 3019d522f475Smrg screen->selection_size = j + 1; 3020d522f475Smrg } else { 3021d522f475Smrg line = screen->selection_data; 3022d522f475Smrg } 3023d522f475Smrg 3024d522f475Smrg if ((line == 0) 3025d522f475Smrg || (j < 0)) 3026d522f475Smrg return; 3027d522f475Smrg 3028d522f475Smrg line[j] = '\0'; /* make sure it is null terminated */ 3029d522f475Smrg lp = line; /* lp points to where to save the text */ 3030d522f475Smrg if (isSameRow(&last, &first)) { 3031d522f475Smrg lp = SaveText(screen, last.row, first.col, last.col, lp, &eol); 3032d522f475Smrg } else { 3033d522f475Smrg lp = SaveText(screen, first.row, first.col, screen->max_col, lp, &eol); 3034d522f475Smrg if (eol) 3035d522f475Smrg *lp++ = '\n'; /* put in newline at end of line */ 3036d522f475Smrg for (i = first.row + 1; i < last.row; i++) { 3037d522f475Smrg lp = SaveText(screen, i, 0, screen->max_col, lp, &eol); 3038d522f475Smrg if (eol) 3039d522f475Smrg *lp++ = '\n'; 3040d522f475Smrg } 3041d522f475Smrg if (last.col >= 0) 3042d522f475Smrg lp = SaveText(screen, last.row, 0, last.col, lp, &eol); 3043d522f475Smrg } 3044d522f475Smrg *lp = '\0'; /* make sure we have end marked */ 3045d522f475Smrg 3046d522f475Smrg TRACE(("Salted TEXT:%d:%s\n", lp - line, 3047d522f475Smrg visibleChars(PAIRED_CHARS(line, 0), (unsigned) (lp - line)))); 3048d522f475Smrg 30492eaa94a1Schristos screen->selection_length = (unsigned long) (lp - line); 3050d522f475Smrg _OwnSelection(xw, params, num_params); 3051d522f475Smrg} 3052d522f475Smrg 3053d522f475Smrg#if OPT_PASTE64 3054d522f475Smrgvoid 3055d522f475SmrgClearSelectionBuffer(TScreen * screen) 3056d522f475Smrg{ 3057d522f475Smrg screen->selection_length = 0; 3058d522f475Smrg screen->base64_count = 0; 3059d522f475Smrg} 3060d522f475Smrg 3061d522f475Smrgstatic void 3062d522f475SmrgAppendStrToSelectionBuffer(TScreen * screen, Char * text, unsigned len) 3063d522f475Smrg{ 3064d522f475Smrg if (len != 0) { 30652eaa94a1Schristos int j = (int) (screen->selection_length + len); /* New length */ 3066d522f475Smrg int k = j + (j >> 2) + 80; /* New size if we grow buffer: grow by ~50% */ 3067d522f475Smrg if (j + 1 >= screen->selection_size) { 3068d522f475Smrg if (!screen->selection_length) { 3069d522f475Smrg /* New buffer */ 3070d522f475Smrg Char *line; 3071d522f475Smrg if ((line = (Char *) malloc((unsigned) k)) == 0) 3072d522f475Smrg SysError(ERROR_BMALLOC2); 3073d522f475Smrg XtFree((char *) screen->selection_data); 3074d522f475Smrg screen->selection_data = line; 3075d522f475Smrg } else { 3076d522f475Smrg /* Realloc buffer */ 3077d522f475Smrg screen->selection_data = (Char *) 3078d522f475Smrg realloc(screen->selection_data, 3079d522f475Smrg (unsigned) k); 3080d522f475Smrg if (screen->selection_data == 0) 3081d522f475Smrg SysError(ERROR_BMALLOC2); 3082d522f475Smrg } 3083d522f475Smrg screen->selection_size = k; 3084d522f475Smrg } 3085d522f475Smrg memcpy(screen->selection_data + screen->selection_length, text, len); 3086d522f475Smrg screen->selection_length += len; 3087d522f475Smrg screen->selection_data[screen->selection_length] = 0; 3088d522f475Smrg } 3089d522f475Smrg} 3090d522f475Smrg 3091d522f475Smrgvoid 3092d522f475SmrgAppendToSelectionBuffer(TScreen * screen, unsigned c) 3093d522f475Smrg{ 30942eaa94a1Schristos unsigned six; 3095d522f475Smrg Char ch; 3096d522f475Smrg 3097d522f475Smrg /* Decode base64 character */ 3098d522f475Smrg if (c >= 'A' && c <= 'Z') 3099d522f475Smrg six = c - 'A'; 3100d522f475Smrg else if (c >= 'a' && c <= 'z') 3101d522f475Smrg six = c - 'a' + 26; 3102d522f475Smrg else if (c >= '0' && c <= '9') 3103d522f475Smrg six = c - '0' + 52; 3104d522f475Smrg else if (c == '+') 3105d522f475Smrg six = 62; 3106d522f475Smrg else if (c == '/') 3107d522f475Smrg six = 63; 3108d522f475Smrg else 3109d522f475Smrg return; 3110d522f475Smrg 3111d522f475Smrg /* Accumulate bytes */ 3112d522f475Smrg switch (screen->base64_count) { 3113d522f475Smrg case 0: 3114d522f475Smrg screen->base64_accu = six; 3115d522f475Smrg screen->base64_count = 6; 3116d522f475Smrg break; 3117d522f475Smrg 3118d522f475Smrg case 2: 31192eaa94a1Schristos ch = CharOf((screen->base64_accu << 6) + six); 3120d522f475Smrg screen->base64_count = 0; 3121d522f475Smrg AppendStrToSelectionBuffer(screen, &ch, 1); 3122d522f475Smrg break; 3123d522f475Smrg 3124d522f475Smrg case 4: 31252eaa94a1Schristos ch = CharOf((screen->base64_accu << 4) + (six >> 2)); 3126d522f475Smrg screen->base64_accu = (six & 0x3); 3127d522f475Smrg screen->base64_count = 2; 3128d522f475Smrg AppendStrToSelectionBuffer(screen, &ch, 1); 3129d522f475Smrg break; 3130d522f475Smrg 3131d522f475Smrg case 6: 31322eaa94a1Schristos ch = CharOf((screen->base64_accu << 2) + (six >> 4)); 3133d522f475Smrg screen->base64_accu = (six & 0xF); 3134d522f475Smrg screen->base64_count = 4; 3135d522f475Smrg AppendStrToSelectionBuffer(screen, &ch, 1); 3136d522f475Smrg break; 3137d522f475Smrg } 3138d522f475Smrg} 3139d522f475Smrg 3140d522f475Smrgvoid 3141d522f475SmrgCompleteSelection(XtermWidget xw, char **args, Cardinal len) 3142d522f475Smrg{ 3143d522f475Smrg xw->screen.base64_count = 0; 3144d522f475Smrg xw->screen.base64_accu = 0; 3145d522f475Smrg _OwnSelection(xw, args, len); 3146d522f475Smrg} 3147d522f475Smrg#endif /* OPT_PASTE64 */ 3148d522f475Smrg 3149d522f475Smrgstatic Bool 3150d522f475Smrg_ConvertSelectionHelper(Widget w, 3151d522f475Smrg Atom * type, 3152d522f475Smrg XtPointer *value, 3153d522f475Smrg unsigned long *length, 3154d522f475Smrg int *format, 3155d522f475Smrg int (*conversion_function) (Display *, 3156d522f475Smrg char **, int, 3157d522f475Smrg XICCEncodingStyle, 3158d522f475Smrg XTextProperty *), 3159d522f475Smrg XICCEncodingStyle conversion_style) 3160d522f475Smrg{ 3161d522f475Smrg if (IsXtermWidget(w)) { 3162d522f475Smrg Display *dpy = XtDisplay(w); 3163d522f475Smrg TScreen *screen = TScreenOf((XtermWidget) w); 3164d522f475Smrg XTextProperty textprop; 3165d522f475Smrg char *the_data = (char *) screen->selection_data; 3166d522f475Smrg 3167d522f475Smrg if (conversion_function(dpy, &the_data, 1, 3168d522f475Smrg conversion_style, 3169d522f475Smrg &textprop) >= Success) { 3170d522f475Smrg *value = (XtPointer) textprop.value; 3171d522f475Smrg *length = textprop.nitems; 3172d522f475Smrg *type = textprop.encoding; 3173d522f475Smrg *format = textprop.format; 3174d522f475Smrg return True; 3175d522f475Smrg } 3176d522f475Smrg } 3177d522f475Smrg return False; 3178d522f475Smrg} 3179d522f475Smrg 31802eaa94a1Schristosstatic Boolean 31812eaa94a1SchristosSaveConvertedLength(XtPointer *target, unsigned long source) 31822eaa94a1Schristos{ 31832eaa94a1Schristos Boolean result = False; 31842eaa94a1Schristos 31852eaa94a1Schristos *target = XtMalloc(4); 31862eaa94a1Schristos if (*target != 0) { 31872eaa94a1Schristos result = True; 31882eaa94a1Schristos if (sizeof(unsigned long) == 4) { 31892eaa94a1Schristos *(unsigned long *) *target = source; 31902eaa94a1Schristos } else if (sizeof(unsigned) == 4) { 31912eaa94a1Schristos *(unsigned *) *target = source; 31922eaa94a1Schristos } else if (sizeof(unsigned short) == 4) { 31932eaa94a1Schristos *(unsigned short *) *target = (unsigned short) source; 31942eaa94a1Schristos } else { 31952eaa94a1Schristos /* FIXME - does this depend on byte-order? */ 31962eaa94a1Schristos unsigned long temp = source; 31972eaa94a1Schristos memcpy((char *) *target, ((char *) &temp) + sizeof(temp) - 4, 4); 31982eaa94a1Schristos } 31992eaa94a1Schristos } 32002eaa94a1Schristos return result; 32012eaa94a1Schristos} 32022eaa94a1Schristos 3203d522f475Smrgstatic Boolean 3204d522f475SmrgConvertSelection(Widget w, 3205d522f475Smrg Atom * selection, 3206d522f475Smrg Atom * target, 3207d522f475Smrg Atom * type, 3208d522f475Smrg XtPointer *value, 3209d522f475Smrg unsigned long *length, 3210d522f475Smrg int *format) 3211d522f475Smrg{ 3212d522f475Smrg Display *dpy = XtDisplay(w); 3213d522f475Smrg TScreen *screen; 3214d522f475Smrg Bool result = False; 3215d522f475Smrg 3216d522f475Smrg if (!IsXtermWidget(w)) 3217d522f475Smrg return False; 3218d522f475Smrg 3219d522f475Smrg screen = TScreenOf((XtermWidget) w); 3220d522f475Smrg 3221d522f475Smrg if (screen->selection_data == NULL) 3222d522f475Smrg return False; /* can this happen? */ 3223d522f475Smrg 3224d522f475Smrg if (*target == XA_TARGETS(dpy)) { 3225d522f475Smrg Atom *allocP; 3226d522f475Smrg Atom *targetP; 3227d522f475Smrg Atom *std_targets; 3228d522f475Smrg XPointer std_return = 0; 3229d522f475Smrg unsigned long std_length; 3230d522f475Smrg 3231d522f475Smrg TRACE(("ConvertSelection XA_TARGETS(dpy)\n")); 3232d522f475Smrg if (XmuConvertStandardSelection(w, screen->selection_time, selection, 3233d522f475Smrg target, type, &std_return, 3234d522f475Smrg &std_length, format)) { 3235d522f475Smrg std_targets = (Atom *) (std_return); 3236d522f475Smrg *length = std_length + 6; 3237d522f475Smrg 3238d522f475Smrg targetP = (Atom *) XtMalloc(sizeof(Atom) * (*length)); 3239d522f475Smrg allocP = targetP; 3240d522f475Smrg 3241d522f475Smrg *value = (XtPointer) targetP; 3242d522f475Smrg 3243d522f475Smrg *targetP++ = XA_STRING; 3244d522f475Smrg *targetP++ = XA_TEXT(dpy); 3245d522f475Smrg#ifdef X_HAVE_UTF8_STRING 3246d522f475Smrg *targetP++ = XA_COMPOUND_TEXT(dpy); 3247d522f475Smrg *targetP++ = XA_UTF8_STRING(dpy); 3248d522f475Smrg#else 3249d522f475Smrg *targetP = XA_COMPOUND_TEXT(dpy); 3250d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3251d522f475Smrg *targetP = XA_UTF8_STRING(dpy); 3252d522f475Smrg }); 3253d522f475Smrg targetP++; 3254d522f475Smrg#endif 3255d522f475Smrg *targetP++ = XA_LENGTH(dpy); 3256d522f475Smrg *targetP++ = XA_LIST_LENGTH(dpy); 3257d522f475Smrg 32582eaa94a1Schristos *length = std_length + (unsigned long) (targetP - allocP); 3259d522f475Smrg 3260d522f475Smrg memcpy(targetP, std_targets, sizeof(Atom) * std_length); 3261d522f475Smrg XtFree((char *) std_targets); 3262d522f475Smrg *type = XA_ATOM; 3263d522f475Smrg *format = 32; 3264d522f475Smrg result = True; 3265d522f475Smrg } 3266d522f475Smrg } 3267d522f475Smrg#if OPT_WIDE_CHARS 3268d522f475Smrg else if (screen->wide_chars && *target == XA_STRING) { 3269d522f475Smrg TRACE(("ConvertSelection XA_STRING - wide\n")); 3270d522f475Smrg result = 3271d522f475Smrg _ConvertSelectionHelper(w, 3272d522f475Smrg type, value, length, format, 3273d522f475Smrg Xutf8TextListToTextProperty, 3274d522f475Smrg XStringStyle); 3275d522f475Smrg } else if (screen->wide_chars && *target == XA_UTF8_STRING(dpy)) { 3276d522f475Smrg TRACE(("ConvertSelection XA_UTF8_STRING(dpy) - wide\n")); 3277d522f475Smrg result = 3278d522f475Smrg _ConvertSelectionHelper(w, 3279d522f475Smrg type, value, length, format, 3280d522f475Smrg Xutf8TextListToTextProperty, 3281d522f475Smrg XUTF8StringStyle); 3282d522f475Smrg } else if (screen->wide_chars && *target == XA_TEXT(dpy)) { 3283d522f475Smrg TRACE(("ConvertSelection XA_TEXT(dpy) - wide\n")); 3284d522f475Smrg result = 3285d522f475Smrg _ConvertSelectionHelper(w, 3286d522f475Smrg type, value, length, format, 3287d522f475Smrg Xutf8TextListToTextProperty, 3288d522f475Smrg XStdICCTextStyle); 3289d522f475Smrg } else if (screen->wide_chars && *target == XA_COMPOUND_TEXT(dpy)) { 3290d522f475Smrg TRACE(("ConvertSelection XA_COMPOUND_TEXT(dpy) - wide\n")); 3291d522f475Smrg result = 3292d522f475Smrg _ConvertSelectionHelper(w, 3293d522f475Smrg type, value, length, format, 3294d522f475Smrg Xutf8TextListToTextProperty, 3295d522f475Smrg XCompoundTextStyle); 3296d522f475Smrg } 3297d522f475Smrg#endif 3298d522f475Smrg 3299d522f475Smrg else if (*target == XA_STRING) { /* not wide_chars */ 3300d522f475Smrg /* We can only reach this point if the selection requestor 3301d522f475Smrg requested STRING before any of TEXT, COMPOUND_TEXT or 3302d522f475Smrg UTF8_STRING. We therefore assume that the requestor is not 3303d522f475Smrg properly internationalised, and dump raw eight-bit data 3304d522f475Smrg with no conversion into the selection. Yes, this breaks 3305d522f475Smrg the ICCCM in non-Latin-1 locales. */ 3306d522f475Smrg TRACE(("ConvertSelection XA_STRING\n")); 3307d522f475Smrg *type = XA_STRING; 3308d522f475Smrg *value = (XtPointer) screen->selection_data; 3309d522f475Smrg *length = screen->selection_length; 3310d522f475Smrg *format = 8; 3311d522f475Smrg result = True; 3312d522f475Smrg } else if (*target == XA_TEXT(dpy)) { /* not wide_chars */ 3313d522f475Smrg TRACE(("ConvertSelection XA_TEXT(dpy)\n")); 3314d522f475Smrg result = 3315d522f475Smrg _ConvertSelectionHelper(w, 3316d522f475Smrg type, value, length, format, 3317d522f475Smrg XmbTextListToTextProperty, 3318d522f475Smrg XStdICCTextStyle); 3319d522f475Smrg } else if (*target == XA_COMPOUND_TEXT(dpy)) { /* not wide_chars */ 3320d522f475Smrg TRACE(("ConvertSelection XA_COMPOUND_TEXT(dpy)\n")); 3321d522f475Smrg result = 3322d522f475Smrg _ConvertSelectionHelper(w, 3323d522f475Smrg type, value, length, format, 3324d522f475Smrg XmbTextListToTextProperty, 3325d522f475Smrg XCompoundTextStyle); 3326d522f475Smrg } 3327d522f475Smrg#ifdef X_HAVE_UTF8_STRING 3328d522f475Smrg else if (*target == XA_UTF8_STRING(dpy)) { /* not wide_chars */ 3329d522f475Smrg TRACE(("ConvertSelection XA_UTF8_STRING(dpy)\n")); 3330d522f475Smrg result = 3331d522f475Smrg _ConvertSelectionHelper(w, 3332d522f475Smrg type, value, length, format, 3333d522f475Smrg XmbTextListToTextProperty, 3334d522f475Smrg XUTF8StringStyle); 3335d522f475Smrg } 3336d522f475Smrg#endif 3337d522f475Smrg else if (*target == XA_LIST_LENGTH(dpy)) { 3338d522f475Smrg TRACE(("ConvertSelection XA_LIST_LENGTH(dpy)\n")); 33392eaa94a1Schristos result = SaveConvertedLength(value, 1); 3340d522f475Smrg *type = XA_INTEGER; 3341d522f475Smrg *length = 1; 3342d522f475Smrg *format = 32; 3343d522f475Smrg } else if (*target == XA_LENGTH(dpy)) { 3344d522f475Smrg TRACE(("ConvertSelection XA_LENGTH(dpy)\n")); 3345d522f475Smrg /* This value is wrong if we have UTF-8 text */ 33462eaa94a1Schristos result = SaveConvertedLength(value, screen->selection_length); 3347d522f475Smrg *type = XA_INTEGER; 3348d522f475Smrg *length = 1; 3349d522f475Smrg *format = 32; 3350d522f475Smrg } else if (XmuConvertStandardSelection(w, 3351d522f475Smrg screen->selection_time, selection, 3352d522f475Smrg target, type, (XPointer *) value, 3353d522f475Smrg length, format)) { 3354d522f475Smrg TRACE(("ConvertSelection XmuConvertStandardSelection\n")); 3355d522f475Smrg result = True; 3356d522f475Smrg } 3357d522f475Smrg 3358d522f475Smrg /* else */ 33592eaa94a1Schristos return (Boolean) result; 3360d522f475Smrg} 3361d522f475Smrg 3362d522f475Smrgstatic void 3363d522f475SmrgLoseSelection(Widget w, Atom * selection) 3364d522f475Smrg{ 3365d522f475Smrg TScreen *screen; 3366d522f475Smrg Atom *atomP; 3367d522f475Smrg Cardinal i; 3368d522f475Smrg 3369d522f475Smrg if (!IsXtermWidget(w)) 3370d522f475Smrg return; 3371d522f475Smrg 3372d522f475Smrg screen = TScreenOf((XtermWidget) w); 3373d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 3374d522f475Smrg i < screen->selection_count; i++, atomP++) { 3375d522f475Smrg if (*selection == *atomP) 3376d522f475Smrg *atomP = (Atom) 0; 3377d522f475Smrg if (CutBuffer(*atomP) >= 0) { 3378d522f475Smrg *atomP = (Atom) 0; 3379d522f475Smrg } 3380d522f475Smrg } 3381d522f475Smrg 3382d522f475Smrg for (i = screen->selection_count; i; i--) { 3383d522f475Smrg if (screen->selection_atoms[i - 1] != 0) 3384d522f475Smrg break; 3385d522f475Smrg } 3386d522f475Smrg screen->selection_count = i; 3387d522f475Smrg 3388d522f475Smrg for (i = 0, atomP = screen->selection_atoms; 3389d522f475Smrg i < screen->selection_count; i++, atomP++) { 3390d522f475Smrg if (*atomP == (Atom) 0) { 3391d522f475Smrg *atomP = screen->selection_atoms[--screen->selection_count]; 3392d522f475Smrg } 3393d522f475Smrg } 3394d522f475Smrg 3395d522f475Smrg if (screen->selection_count == 0) 3396d522f475Smrg TrackText((XtermWidget) w, &zeroCELL, &zeroCELL); 3397d522f475Smrg} 3398d522f475Smrg 3399d522f475Smrg/* ARGSUSED */ 3400d522f475Smrgstatic void 3401d522f475SmrgSelectionDone(Widget w GCC_UNUSED, 3402d522f475Smrg Atom * selection GCC_UNUSED, 3403d522f475Smrg Atom * target GCC_UNUSED) 3404d522f475Smrg{ 3405d522f475Smrg /* empty proc so Intrinsics know we want to keep storage */ 3406d522f475Smrg} 3407d522f475Smrg 3408d522f475Smrgstatic void 3409d522f475Smrg_OwnSelection(XtermWidget xw, 3410d522f475Smrg String * selections, 3411d522f475Smrg Cardinal count) 3412d522f475Smrg{ 3413d522f475Smrg TScreen *screen = &(xw->screen); 3414d522f475Smrg Atom *atoms = screen->selection_atoms; 3415d522f475Smrg Cardinal i; 3416d522f475Smrg Bool have_selection = False; 3417d522f475Smrg 34182eaa94a1Schristos if (screen->selection_length == 0) 3419d522f475Smrg return; 3420d522f475Smrg 3421d522f475Smrg TRACE(("_OwnSelection\n")); 3422d522f475Smrg selections = MapSelections(xw, selections, count); 3423d522f475Smrg 3424d522f475Smrg if (count > screen->sel_atoms_size) { 3425d522f475Smrg XtFree((char *) atoms); 3426d522f475Smrg atoms = (Atom *) XtMalloc(count * sizeof(Atom)); 3427d522f475Smrg screen->selection_atoms = atoms; 3428d522f475Smrg screen->sel_atoms_size = count; 3429d522f475Smrg } 3430d522f475Smrg XmuInternStrings(XtDisplay((Widget) xw), selections, count, atoms); 3431d522f475Smrg for (i = 0; i < count; i++) { 3432d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 3433d522f475Smrg if (cutbuffer >= 0) { 34342eaa94a1Schristos unsigned long limit = 34352eaa94a1Schristos (unsigned long) (4 * XMaxRequestSize(XtDisplay((Widget) xw)) - 32); 34362eaa94a1Schristos if (screen->selection_length > limit) { 3437d522f475Smrg fprintf(stderr, 34382eaa94a1Schristos "%s: selection too big (%ld bytes), not storing in CUT_BUFFER%d\n", 3439d522f475Smrg xterm_name, screen->selection_length, cutbuffer); 3440d522f475Smrg } else { 3441d522f475Smrg /* This used to just use the UTF-8 data, which was totally 3442d522f475Smrg * broken as not even the corresponding paste code in Xterm 3443d522f475Smrg * understood this! So now it converts to Latin1 first. 3444d522f475Smrg * Robert Brady, 2000-09-05 3445d522f475Smrg */ 3446d522f475Smrg unsigned long length = screen->selection_length; 3447d522f475Smrg Char *data = screen->selection_data; 3448d522f475Smrg if_OPT_WIDE_CHARS((screen), { 3449d522f475Smrg data = UTF8toLatin1(data, length, &length); 3450d522f475Smrg }); 3451d522f475Smrg TRACE(("XStoreBuffer(%d)\n", cutbuffer)); 3452d522f475Smrg XStoreBuffer(XtDisplay((Widget) xw), 3453d522f475Smrg (char *) data, 3454d522f475Smrg (int) length, 3455d522f475Smrg cutbuffer); 3456d522f475Smrg } 3457d522f475Smrg } else if (!screen->replyToEmacs) { 3458d522f475Smrg have_selection |= 3459d522f475Smrg XtOwnSelection((Widget) xw, atoms[i], 3460d522f475Smrg screen->selection_time, 3461d522f475Smrg ConvertSelection, LoseSelection, SelectionDone); 3462d522f475Smrg } 3463d522f475Smrg } 3464d522f475Smrg if (!screen->replyToEmacs) 3465d522f475Smrg screen->selection_count = count; 3466d522f475Smrg if (!have_selection) 3467d522f475Smrg TrackText(xw, &zeroCELL, &zeroCELL); 3468d522f475Smrg} 3469d522f475Smrg 3470d522f475Smrgstatic void 3471d522f475SmrgResetSelectionState(TScreen * screen) 3472d522f475Smrg{ 3473d522f475Smrg screen->selection_count = 0; 3474d522f475Smrg screen->startH = zeroCELL; 3475d522f475Smrg screen->endH = zeroCELL; 3476d522f475Smrg} 3477d522f475Smrg 3478d522f475Smrgvoid 3479d522f475SmrgDisownSelection(XtermWidget xw) 3480d522f475Smrg{ 3481d522f475Smrg TScreen *screen = &(xw->screen); 3482d522f475Smrg Atom *atoms = screen->selection_atoms; 3483d522f475Smrg Cardinal count = screen->selection_count; 3484d522f475Smrg Cardinal i; 3485d522f475Smrg 3486d522f475Smrg TRACE(("DisownSelection count %d, start %d.%d, end %d.%d\n", 3487d522f475Smrg count, 3488d522f475Smrg screen->startH.row, 3489d522f475Smrg screen->startH.col, 3490d522f475Smrg screen->endH.row, 3491d522f475Smrg screen->endH.col)); 3492d522f475Smrg 3493d522f475Smrg for (i = 0; i < count; i++) { 3494d522f475Smrg int cutbuffer = CutBuffer(atoms[i]); 3495d522f475Smrg if (cutbuffer < 0) { 3496d522f475Smrg XtDisownSelection((Widget) xw, atoms[i], 3497d522f475Smrg screen->selection_time); 3498d522f475Smrg } 3499d522f475Smrg } 3500d522f475Smrg /* 3501d522f475Smrg * If none of the callbacks via XtDisownSelection() reset highlighting 3502d522f475Smrg * do it now. 3503d522f475Smrg */ 3504d522f475Smrg if (ScrnHaveSelection(screen)) { 3505d522f475Smrg /* save data which will be reset */ 3506d522f475Smrg CELL first = screen->startH; 3507d522f475Smrg CELL last = screen->endH; 3508d522f475Smrg 3509d522f475Smrg ResetSelectionState(screen); 3510d522f475Smrg ReHiliteText(xw, &first, &last); 3511d522f475Smrg } else { 3512d522f475Smrg ResetSelectionState(screen); 3513d522f475Smrg } 3514d522f475Smrg} 3515d522f475Smrg 3516d522f475Smrgvoid 3517d522f475SmrgUnhiliteSelection(XtermWidget xw) 3518d522f475Smrg{ 3519d522f475Smrg TScreen *screen = &(xw->screen); 3520d522f475Smrg 3521d522f475Smrg if (ScrnHaveSelection(screen)) { 3522d522f475Smrg CELL first = screen->startH; 3523d522f475Smrg CELL last = screen->endH; 3524d522f475Smrg 3525d522f475Smrg screen->startH = zeroCELL; 3526d522f475Smrg screen->endH = zeroCELL; 3527d522f475Smrg ReHiliteText(xw, &first, &last); 3528d522f475Smrg } 3529d522f475Smrg} 3530d522f475Smrg 3531d522f475Smrg/* returns number of chars in line from scol to ecol out */ 3532d522f475Smrg/* ARGSUSED */ 3533d522f475Smrgstatic int 3534d522f475SmrgLength(TScreen * screen GCC_UNUSED, 3535d522f475Smrg int row, 3536d522f475Smrg int scol, 3537d522f475Smrg int ecol) 3538d522f475Smrg{ 3539d522f475Smrg int lastcol = LastTextCol(screen, row); 3540d522f475Smrg 3541d522f475Smrg if (ecol > lastcol) 3542d522f475Smrg ecol = lastcol; 3543d522f475Smrg return (ecol - scol + 1); 3544d522f475Smrg} 3545d522f475Smrg 3546d522f475Smrg/* copies text into line, preallocated */ 3547d522f475Smrgstatic Char * 3548d522f475SmrgSaveText(TScreen * screen, 3549d522f475Smrg int row, 3550d522f475Smrg int scol, 3551d522f475Smrg int ecol, 3552d522f475Smrg Char * lp, /* pointer to where to put the text */ 3553d522f475Smrg int *eol) 3554d522f475Smrg{ 3555d522f475Smrg int i = 0; 3556d522f475Smrg unsigned c; 3557d522f475Smrg Char *result = lp; 3558d522f475Smrg#if OPT_WIDE_CHARS 35592eaa94a1Schristos unsigned previous = 0; 3560d522f475Smrg#endif 3561d522f475Smrg 3562d522f475Smrg i = Length(screen, row, scol, ecol); 3563d522f475Smrg ecol = scol + i; 3564d522f475Smrg#if OPT_DEC_CHRSET 3565d522f475Smrg if (CSET_DOUBLE(SCRN_BUF_CSETS(screen, ROW2INX(screen, row))[0])) { 3566d522f475Smrg scol = (scol + 0) / 2; 3567d522f475Smrg ecol = (ecol + 1) / 2; 3568d522f475Smrg } 3569d522f475Smrg#endif 3570d522f475Smrg *eol = !ScrnTstWrapped(screen, row); 3571d522f475Smrg for (i = scol; i < ecol; i++) { 3572d522f475Smrg c = E2A(XTERM_CELL(row, i)); 3573d522f475Smrg#if OPT_WIDE_CHARS 3574d522f475Smrg /* We want to strip out every occurrence of HIDDEN_CHAR AFTER a 3575d522f475Smrg * wide character. 3576d522f475Smrg */ 35772eaa94a1Schristos if (c == HIDDEN_CHAR && iswide((int) previous)) { 3578d522f475Smrg previous = c; 3579d522f475Smrg /* Combining characters attached to double-width characters 3580d522f475Smrg are in memory attached to the HIDDEN_CHAR */ 3581d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3582d522f475Smrg if (screen->utf8_mode != uFalse) { 3583d522f475Smrg unsigned ch; 3584d522f475Smrg int off; 3585d522f475Smrg for (off = OFF_FINAL; off < MAX_PTRS; off += 2) { 3586d522f475Smrg if ((ch = XTERM_CELLC(row, i, off)) == 0) 3587d522f475Smrg break; 3588d522f475Smrg lp = convertToUTF8(lp, ch); 3589d522f475Smrg } 3590d522f475Smrg } 3591d522f475Smrg }); 3592d522f475Smrg continue; 3593d522f475Smrg } 3594d522f475Smrg previous = c; 3595d522f475Smrg if (screen->utf8_mode != uFalse) { 3596d522f475Smrg lp = convertToUTF8(lp, (c != 0) ? c : ' '); 3597d522f475Smrg if_OPT_WIDE_CHARS(screen, { 3598d522f475Smrg unsigned ch; 3599d522f475Smrg int off; 3600d522f475Smrg for (off = OFF_FINAL; off < MAX_PTRS; off += 2) { 3601d522f475Smrg if ((ch = XTERM_CELLC(row, i, off)) == 0) 3602d522f475Smrg break; 3603d522f475Smrg lp = convertToUTF8(lp, ch); 3604d522f475Smrg } 3605d522f475Smrg }); 3606d522f475Smrg } else 3607d522f475Smrg#endif 3608d522f475Smrg { 3609d522f475Smrg if (c == 0) { 3610d522f475Smrg c = E2A(' '); 3611d522f475Smrg } else if (c < E2A(' ')) { 3612d522f475Smrg c = DECtoASCII(c); 3613d522f475Smrg } else if (c == 0x7f) { 3614d522f475Smrg c = 0x5f; 3615d522f475Smrg } 36162eaa94a1Schristos *lp++ = CharOf(A2E(c)); 3617d522f475Smrg } 3618d522f475Smrg if (c != E2A(' ')) 3619d522f475Smrg result = lp; 3620d522f475Smrg } 3621d522f475Smrg 3622d522f475Smrg /* 3623d522f475Smrg * If requested, trim trailing blanks from selected lines. Do not do this 3624d522f475Smrg * if the line is wrapped. 3625d522f475Smrg */ 3626d522f475Smrg if (!*eol || !screen->trim_selection) 3627d522f475Smrg result = lp; 3628d522f475Smrg 3629d522f475Smrg return (result); 3630d522f475Smrg} 3631d522f475Smrg 3632d522f475Smrg/* 32 + following 7-bit word: 3633d522f475Smrg 3634d522f475Smrg 1:0 Button no: 0, 1, 2. 3=release. 3635d522f475Smrg 2 shift 3636d522f475Smrg 3 meta 3637d522f475Smrg 4 ctrl 3638d522f475Smrg 5 set for motion notify 3639d522f475Smrg 6 set for wheel 3640d522f475Smrg*/ 3641d522f475Smrg 3642d522f475Smrg/* Position: 32 - 255. */ 3643d522f475Smrg 36442eaa94a1Schristosstatic Char 3645d522f475SmrgBtnCode(XButtonEvent * event, int button) 3646d522f475Smrg{ 36472eaa94a1Schristos int result = (int) (32 + (KeyState(event->state) << 2)); 3648d522f475Smrg 3649d522f475Smrg if (button < 0 || button > 5) { 3650d522f475Smrg result += 3; 3651d522f475Smrg } else { 3652d522f475Smrg if (button > 3) 3653d522f475Smrg result += (64 - 4); 3654d522f475Smrg if (event->type == MotionNotify) 3655d522f475Smrg result += 32; 3656d522f475Smrg result += button; 3657d522f475Smrg } 36582eaa94a1Schristos return CharOf(result); 3659d522f475Smrg} 3660d522f475Smrg 3661d522f475Smrg#define MOUSE_LIMIT (255 - 32) 3662d522f475Smrg 3663d522f475Smrgstatic void 3664d522f475SmrgEditorButton(XtermWidget xw, XButtonEvent * event) 3665d522f475Smrg{ 3666d522f475Smrg TScreen *screen = &(xw->screen); 3667d522f475Smrg int pty = screen->respond; 3668d522f475Smrg Char line[6]; 3669d522f475Smrg int row, col; 3670d522f475Smrg int button; 3671d522f475Smrg unsigned count = 0; 3672d522f475Smrg Boolean changed = True; 3673d522f475Smrg 3674d522f475Smrg /* If button event, get button # adjusted for DEC compatibility */ 36752eaa94a1Schristos button = (int) (event->button - 1); 3676d522f475Smrg if (button >= 3) 3677d522f475Smrg button++; 3678d522f475Smrg 3679d522f475Smrg /* Compute character position of mouse pointer */ 3680d522f475Smrg row = (event->y - screen->border) / FontHeight(screen); 3681d522f475Smrg col = (event->x - OriginX(screen)) / FontWidth(screen); 3682d522f475Smrg 3683d522f475Smrg /* Limit to screen dimensions */ 3684d522f475Smrg if (row < 0) 3685d522f475Smrg row = 0; 3686d522f475Smrg else if (row > screen->max_row) 3687d522f475Smrg row = screen->max_row; 3688d522f475Smrg else if (row > MOUSE_LIMIT) 3689d522f475Smrg row = MOUSE_LIMIT; 3690d522f475Smrg 3691d522f475Smrg if (col < 0) 3692d522f475Smrg col = 0; 3693d522f475Smrg else if (col > screen->max_col) 3694d522f475Smrg col = screen->max_col; 3695d522f475Smrg else if (col > MOUSE_LIMIT) 3696d522f475Smrg col = MOUSE_LIMIT; 3697d522f475Smrg 3698d522f475Smrg /* Build key sequence starting with \E[M */ 3699d522f475Smrg if (screen->control_eight_bits) { 3700d522f475Smrg line[count++] = ANSI_CSI; 3701d522f475Smrg } else { 3702d522f475Smrg line[count++] = ANSI_ESC; 3703d522f475Smrg line[count++] = '['; 3704d522f475Smrg } 3705d522f475Smrg#if OPT_SCO_FUNC_KEYS 3706d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 3707d522f475Smrg /* 3708d522f475Smrg * SCO function key F1 is \E[M, which would conflict with xterm's 3709d522f475Smrg * normal kmous. 3710d522f475Smrg */ 3711d522f475Smrg line[count++] = '>'; 3712d522f475Smrg } 3713d522f475Smrg#endif 3714d522f475Smrg line[count++] = 'M'; 3715d522f475Smrg 3716d522f475Smrg /* Add event code to key sequence */ 3717d522f475Smrg if (screen->send_mouse_pos == X10_MOUSE) { 37182eaa94a1Schristos line[count++] = CharOf(' ' + button); 3719d522f475Smrg } else { 3720d522f475Smrg /* Button-Motion events */ 3721d522f475Smrg switch (event->type) { 3722d522f475Smrg case ButtonPress: 3723d522f475Smrg line[count++] = BtnCode(event, screen->mouse_button = button); 3724d522f475Smrg break; 3725d522f475Smrg case ButtonRelease: 3726d522f475Smrg /* 3727d522f475Smrg * Wheel mouse interface generates release-events for buttons 3728d522f475Smrg * 4 and 5, coded here as 3 and 4 respectively. We change the 3729d522f475Smrg * release for buttons 1..3 to a -1. 3730d522f475Smrg */ 3731d522f475Smrg if (button < 3) 3732d522f475Smrg button = -1; 3733d522f475Smrg line[count++] = BtnCode(event, screen->mouse_button = button); 3734d522f475Smrg break; 3735d522f475Smrg case MotionNotify: 3736d522f475Smrg /* BTN_EVENT_MOUSE and ANY_EVENT_MOUSE modes send motion 3737d522f475Smrg * events only if character cell has changed. 3738d522f475Smrg */ 3739d522f475Smrg if ((row == screen->mouse_row) 3740d522f475Smrg && (col == screen->mouse_col)) { 3741d522f475Smrg changed = False; 3742d522f475Smrg } else { 3743d522f475Smrg line[count++] = BtnCode(event, screen->mouse_button); 3744d522f475Smrg } 3745d522f475Smrg break; 3746d522f475Smrg default: 3747d522f475Smrg changed = False; 3748d522f475Smrg break; 3749d522f475Smrg } 3750d522f475Smrg } 3751d522f475Smrg 3752d522f475Smrg if (changed) { 3753d522f475Smrg screen->mouse_row = row; 3754d522f475Smrg screen->mouse_col = col; 3755d522f475Smrg 3756d522f475Smrg /* Add pointer position to key sequence */ 37572eaa94a1Schristos line[count++] = CharOf(' ' + col + 1); 37582eaa94a1Schristos line[count++] = CharOf(' ' + row + 1); 3759d522f475Smrg 3760d522f475Smrg TRACE(("mouse at %d,%d button+mask = %#x\n", row, col, 3761d522f475Smrg (screen->control_eight_bits) ? line[2] : line[3])); 3762d522f475Smrg 3763d522f475Smrg /* Transmit key sequence to process running under xterm */ 3764d522f475Smrg v_write(pty, line, count); 3765d522f475Smrg } 3766d522f475Smrg return; 3767d522f475Smrg} 3768d522f475Smrg 3769d522f475Smrg#if OPT_FOCUS_EVENT 3770d522f475Smrgvoid 3771d522f475SmrgSendFocusButton(XtermWidget xw, XFocusChangeEvent * event) 3772d522f475Smrg{ 3773d522f475Smrg TScreen *screen = &(xw->screen); 3774d522f475Smrg 3775d522f475Smrg if (screen->send_focus_pos) { 3776d522f475Smrg ANSI reply; 3777d522f475Smrg 3778d522f475Smrg memset(&reply, 0, sizeof(reply)); 3779d522f475Smrg reply.a_type = ANSI_CSI; 3780d522f475Smrg 3781d522f475Smrg#if OPT_SCO_FUNC_KEYS 3782d522f475Smrg if (xw->keyboard.type == keyboardIsSCO) { 3783d522f475Smrg reply.a_pintro = '>'; 3784d522f475Smrg } 3785d522f475Smrg#endif 37862eaa94a1Schristos reply.a_final = CharOf((event->type == FocusIn) ? 'I' : 'O'); 3787d522f475Smrg unparseseq(xw, &reply); 3788d522f475Smrg } 3789d522f475Smrg return; 3790d522f475Smrg} 3791d522f475Smrg#endif /* OPT_FOCUS_EVENT */ 3792