DataMuseum.dkPresents historical artifacts from the history of: Rational R1000/400 Tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Rational R1000/400 Tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - downloadIndex: ┃ T b ┃
Length: 63186 (0xf6d2) Types: TextFile Names: »button.c«
└─⟦5f3412b64⟧ Bits:30000745 8mm tape, Rational 1000, ENVIRONMENT 12_6_5 TOOLS └─ ⟦91c658230⟧ »DATA« └─⟦5d656759a⟧ └─⟦8fb0c967c⟧ └─⟦d10a02448⟧ Bits:30000409 8mm tape, Rational 1000, ENVIRONMENT, D_12_7_3 └─ ⟦fc9b38f02⟧ »DATA« └─⟦8e9e227a9⟧ └─⟦8fb0c967c⟧ └─ ⟦this⟧ »button.c«
/* * $XConsortium: button.c,v 1.32 89/01/05 12:47:45 swick Exp $ */ #include <X11/copyright.h> /* * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. * * All Rights Reserved * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation, and that the name of Digital Equipment * Corporation not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior permission. * * * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* button.c Handles button events in the terminal emulator. does cut/paste operations, change modes via menu, passes button events through to some applications. J. Gettys. */ #ifndef lint static char rcs_id[] = "$XConsortium: button.c,v 1.32 89/01/05 12:47:45 swick Exp $"; #endif /* lint */ #ifdef AIX #undef SYSV #define SYSV 1 #endif #include <X11/Xos.h> #include <X11/Xlib.h> #include <X11/Xatom.h> #include <X11/Xmu.h> #include <stdio.h> #include <signal.h> #include <setjmp.h> #include <ctype.h> #include <X11/Intrinsic.h> #include "ptyx.h" #include "data.h" #include "error.h" #include "menu.h" #define _RCG_MENU_ #include "rcg.h" #include "ratmenu.h" #define XK_LATIN1 #include <X11/keysymdef.h> extern char *malloc(); extern int v_write(); extern Pixmap make_gray(); extern int RecognitionValue; extern Widget RatMenu; static PointToRowCol(); extern void RationalButton(); extern void RatMenuPermanent(); extern void PopdownRatMenuChain(); /* Pop down everything that may be up*/ #define KeyState(x) (((x) & (ShiftMask|ControlMask)) + (((x) & Mod1Mask) ? 2 : 0)) /* adds together the bits: shift key -> 1 meta key -> 2 control key -> 4 */ #define TEXTMODES 4 #define NBUTS 3 #define DIRS 2 #define UP 1 #define DOWN 0 #define SHIFTS 8 /* three keys, so eight combinations */ #define Coordinate(r,c) ((r) * (term->screen.max_col+1) + (c)) char *SaveText(); extern EditorButton(); extern ModeMenu(); extern char *xterm_name; extern Bogus(); extern XtermWidget term; /* Selection/extension variables */ /* Raw char position where the selection started */ static int rawRow, rawCol; /* Selected area before CHAR, WORD, LINE selectUnit processing */ static int startRRow, startRCol, endRRow, endRCol = 0; /* Selected area after CHAR, WORD, LINE selectUnit processing */ static int startSRow, startSCol, endSRow, endSCol = 0; /* Valid rows for selection clipping */ static int firstValidRow, lastValidRow; /* Start, end of extension */ static int startERow, startECol, endERow, endECol; /* Saved values of raw selection for extend to restore to */ static int saveStartRRow, saveStartRCol, saveEndRRow, saveEndRCol; /* Multi-click handling */ static int numberOfClicks = 0; static long int lastButtonUpTime = 0; typedef int SelectUnit; #define SELECTCHAR 0 #define SELECTWORD 1 #define SELECTLINE 2 #define NSELECTUNITS 3 static SelectUnit selectUnit; /* Send emacs escape code when done selecting or extending? */ static int replyToEmacs; Boolean SendMousePosition(w, event) Widget w; XEvent* event; { register TScreen *screen = &((XtermWidget)w)->screen; static TrackDown(); if (screen->send_mouse_pos == 0) return False; if (event->type != ButtonPress && event->type != ButtonRelease) return False; #define KeyModifiers \ (event->xbutton.state & (ShiftMask | LockMask | ControlMask | Mod1Mask | \ Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask )) #define ButtonModifiers \ (event->xbutton.state & (ShiftMask | LockMask | ControlMask | Mod1Mask | \ Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask )) switch (screen->send_mouse_pos) { case 1: /* X10 compatibility sequences */ if (KeyModifiers == 0) { if (event->type == ButtonPress) EditorButton(event); return True; } return False; case 2: /* DEC vt200 compatible */ if (KeyModifiers == 0 || KeyModifiers == ControlMask) { EditorButton((XButtonEvent*)event); return True; } return False; case 3: /* DEC vt200 hilite tracking */ if ( event->type == ButtonPress && KeyModifiers == 0 && event->xbutton.button == Button1 ) { TrackDown((XButtonEvent*)event); return True; } if (KeyModifiers == 0 || KeyModifiers == ControlMask) { EditorButton((XButtonEvent*)event); return True; } /* fall through */ default: return False; } #undef KeyModifiers } /*ARGSUSED*/ void HandleSelectExtend(w, event, params, num_params) Widget w; XEvent *event; /* must be XMotionEvent */ String *params; /* unused */ Cardinal *num_params; /* unused */ { extern Boolean WindowMotion; /* TRUE when doing window dragging */ extern void WindowMotionAnalyze(); int row, col; CHECK_RATIONAL_MODE(); ((XtermWidget)w)->screen.selection_time = event->xmotion.time; switch (eventMode) { case LEFTEXTENSION : case RIGHTEXTENSION : PointToRowCol (event->xmotion.y, event->xmotion.x, &row, &col); ExtendExtend (row, col); break; case NORMAL : if (WindowMotion) { WindowMotionAnalyze( event->xmotion.x_root, event->xmotion.y_root ); return; } /* will get here if send_mouse_pos != 0 */ break; } } /*ARGSUSED*/ static void do_select_end (w, event, params, num_params, use_cursor_loc) Widget w; XEvent *event; /* must be XButtonEvent */ String *params; /* selections */ Cardinal *num_params; Bool use_cursor_loc; { register TScreen *screen = &((XtermWidget)w)->screen; CHECK_RATIONAL_MODE(); ((XtermWidget)w)->screen.selection_time = event->xbutton.time; switch (eventMode) { case NORMAL : (void) SendMousePosition(w, event); break; case LEFTEXTENSION : case RIGHTEXTENSION : EndExtend(event, params, *num_params, use_cursor_loc); break; } } void HandleSelectEnd(w, event, params, num_params) Widget w; XEvent *event; /* must be XButtonEvent */ String *params; /* selections */ Cardinal *num_params; { do_select_end (w, event, params, num_params, False); } void HandleKeyboardSelectEnd(w, event, params, num_params) Widget w; XEvent *event; /* must be XButtonEvent */ String *params; /* selections */ Cardinal *num_params; { do_select_end (w, event, params, num_params, True); } struct _SelectionList { String *params; Cardinal count; Time time; }; static void _GetSelection(w, time, params, num_params) Widget w; Time time; String *params; /* selections in precedence order */ Cardinal num_params; { static void SelectionReceived(); Atom selection; int buffer; XmuInternStrings(XtDisplay(w), params, (Cardinal)1, &selection); switch (selection) { case XA_CUT_BUFFER0: buffer = 0; break; case XA_CUT_BUFFER1: buffer = 1; break; case XA_CUT_BUFFER2: buffer = 2; break; case XA_CUT_BUFFER3: buffer = 3; break; case XA_CUT_BUFFER4: buffer = 4; break; case XA_CUT_BUFFER5: buffer = 5; break; case XA_CUT_BUFFER6: buffer = 6; break; case XA_CUT_BUFFER7: buffer = 7; break; default: buffer = -1; } if (buffer >= 0) { register TScreen *screen = &((XtermWidget)w)->screen; int inbytes; unsigned long nbytes; int fmt8 = 8; Atom type = XA_STRING; char *line = XFetchBuffer(screen->display, &inbytes, buffer); nbytes = (unsigned long) inbytes; if (nbytes > 0) SelectionReceived(w, (caddr_t)NULL, &selection, &type, (caddr_t)line, &nbytes, &fmt8); else if (num_params > 1) _GetSelection(w, time, params+1, num_params-1); } else { struct _SelectionList* list; if (--num_params) { list = XtNew(struct _SelectionList); list->params = params + 1; list->count = num_params; list->time = time; } else list = NULL; XtGetSelectionValue(w, selection, XA_STRING, SelectionReceived, (caddr_t)list, time); } } /* ARGSUSED */ static void SelectionReceived(w, client_data, selection, type, value, length, format) Widget w; caddr_t client_data; Atom *selection, *type; caddr_t value; unsigned long *length; int *format; { int pty = ((XtermWidget)w)->screen.respond; /* file descriptor of pty */ register char *lag, *cp, *end; char *line = (char*)value; if (*type == 0 /*XT_CONVERT_FAIL*/ || *length == 0) { struct _SelectionList* list = (struct _SelectionList*)client_data; if (list != NULL) { _GetSelection(w, list->time, list->params, list->count); XtFree(client_data); } return; } end = &line[*length]; if (!term->misc.rational) { lag = line; for (cp = line; cp != end; cp++) { if (*cp != '\n') continue; *cp = '\r'; v_write(pty, lag, cp - lag + 1); lag = cp + 1; } if (lag != end) v_write(pty, lag, end - lag); } else { extern char KeyCodeTable_Xlate[128][5]; /* Xltation for pasting */ for (cp = line; cp != end; cp++) { lag = &KeyCodeTable_Xlate[*cp & 0x7F][0]; (void)v_write( pty, &lag[1], (unsigned int)lag[0] ); } } XtFree(client_data); XtFree(value); } /* ARGSUSED */ void HandleInsertSelection(w, event, params, num_params) Widget w; XEvent *event; /* assumed to be XButtonEvent* */ String *params; /* selections in precedence order */ Cardinal *num_params; { CHECK_RATIONAL_MODE(); if (SendMousePosition(w, event)) return; _GetSelection(w, event->xbutton.time, params, *num_params); } SetSelectUnit(buttonDownTime, defaultUnit) unsigned long buttonDownTime; SelectUnit defaultUnit; { /* Do arithmetic as integers, but compare as unsigned solves clock wraparound */ if ((long unsigned)((long int)buttonDownTime - lastButtonUpTime) > term->screen.multiClickTime) { numberOfClicks = 1; selectUnit = defaultUnit; } else { ++numberOfClicks; selectUnit = ((selectUnit + 1) % NSELECTUNITS); } } static void do_select_start (w, event, startrow, startcol) Widget w; XEvent *event; /* must be XButtonEvent* */ int startrow, startcol; { if (SendMousePosition(w, event)) return; SetSelectUnit(event->xbutton.time, SELECTCHAR); replyToEmacs = FALSE; StartSelect(startrow, startcol); } /* ARGSUSED */ void HandleSelectStart(w, event, params, num_params) Widget w; XEvent *event; /* must be XButtonEvent* */ String *params; /* unused */ Cardinal *num_params; /* unused */ { register TScreen *screen = &((XtermWidget)w)->screen; int startrow, startcol; CHECK_RATIONAL_MODE(); firstValidRow = 0; lastValidRow = screen->max_row; PointToRowCol(event->xbutton.y, event->xbutton.x, &startrow, &startcol); do_select_start (w, event, startrow, startcol); } /* ARGSUSED */ HandleKeyboardSelectStart(w, event, params, num_params) Widget w; XEvent *event; /* must be XButtonEvent* */ String *params; /* unused */ Cardinal *num_params; /* unused */ { register TScreen *screen = &((XtermWidget)w)->screen; do_select_start (w, event, screen->cursor_row, screen->cursor_col); } static TrackDown(event) register XButtonEvent *event; { int startrow, startcol; SetSelectUnit(event->time, SELECTCHAR); if (numberOfClicks > 1 ) { PointToRowCol(event->y, event->x, &startrow, &startcol); replyToEmacs = TRUE; StartSelect(startrow, startcol); } else { waitingForTrackInfo = 1; EditorButton((XButtonEvent*)event); } } #define boundsCheck(x) if (x < 0) \ x = 0; \ else if (x >= screen->max_row) \ x = screen->max_row; TrackMouse(func, startrow, startcol, firstrow, lastrow) int func, startrow, startcol, firstrow, lastrow; { TScreen *screen = &term->screen; if (!waitingForTrackInfo) { /* Timed out, so ignore */ return; } waitingForTrackInfo = 0; if (func == 0) return; boundsCheck (startrow) boundsCheck (firstrow) boundsCheck (lastrow) firstValidRow = firstrow; lastValidRow = lastrow; replyToEmacs = TRUE; StartSelect(startrow, startcol); } StartSelect(startrow, startcol) int startrow, startcol; { TScreen *screen = &term->screen; if (screen->cursor_state) HideCursor (); if (numberOfClicks == 1) { /* set start of selection */ rawRow = startrow; rawCol = startcol; } /* else use old values in rawRow, Col */ saveStartRRow = startERow = rawRow; saveStartRCol = startECol = rawCol; saveEndRRow = endERow = rawRow; saveEndRCol = endECol = rawCol; if (Coordinate(startrow, startcol) < Coordinate(rawRow, rawCol)) { eventMode = LEFTEXTENSION; startERow = startrow; startECol = startcol; } else { eventMode = RIGHTEXTENSION; endERow = startrow; endECol = startcol; } ComputeSelect(startERow, startECol, endERow, endECol, False); } EndExtend(event, params, num_params, use_cursor_loc) XEvent *event; /* must be XButtonEvent */ String *params; /* selections */ Cardinal num_params; Bool use_cursor_loc; { int row, col; TScreen *screen = &term->screen; char line[9]; if (use_cursor_loc) { row = screen->cursor_row; col = screen->cursor_col; } else { PointToRowCol(event->xbutton.y, event->xbutton.x, &row, &col); } ExtendExtend (row, col); lastButtonUpTime = event->xbutton.time; /* Only do select stuff if non-null select */ if (startSRow != endSRow || startSCol != endSCol) { if (replyToEmacs) { if (rawRow == startSRow && rawCol == startSCol && row == endSRow && col == endSCol) { /* Use short-form emacs select */ strcpy(line, "\033[t"); line[3] = ' ' + endSCol + 1; line[4] = ' ' + endSRow + 1; v_write(screen->respond, line, 5); } else { /* long-form, specify everything */ strcpy(line, "\033[T"); line[3] = ' ' + startSCol + 1; line[4] = ' ' + startSRow + 1; line[5] = ' ' + endSCol + 1; line[6] = ' ' + endSRow + 1; line[7] = ' ' + col + 1; line[8] = ' ' + row + 1; v_write(screen->respond, line, 9); } TrackText(0, 0, 0, 0); } SaltTextAway(startSRow, startSCol, endSRow, endSCol, params, num_params); } else DisownSelection(term); /* TrackText(0, 0, 0, 0); */ eventMode = NORMAL; } #define Abs(x) ((x) < 0 ? -(x) : (x)) /* ARGSUSED */ static void do_start_extend (w, event, params, num_params, use_cursor_loc) Widget w; XEvent *event; /* must be XButtonEvent* */ String *params; /* unused */ Cardinal *num_params; /* unused */ Bool use_cursor_loc; { TScreen *screen = &((XtermWidget)w)->screen; int row, col, coord; if (SendMousePosition(w, event)) return; firstValidRow = 0; lastValidRow = screen->max_row; SetSelectUnit(event->xbutton.time, selectUnit); replyToEmacs = FALSE; if (numberOfClicks == 1) { /* Save existing selection so we can reestablish it if the guy extends past the other end of the selection */ saveStartRRow = startERow = startRRow; saveStartRCol = startECol = startRCol; saveEndRRow = endERow = endRRow; saveEndRCol = endECol = endRCol; } else { /* He just needed the selection mode changed, use old values. */ startERow = startRRow = saveStartRRow; startECol = startRCol = saveStartRCol; endERow = endRRow = saveEndRRow; endECol = endRCol = saveEndRCol; } if (use_cursor_loc) { row = screen->cursor_row; col = screen->cursor_col; } else { PointToRowCol(event->xbutton.y, event->xbutton.x, &row, &col); } coord = Coordinate(row, col); if (Abs(coord - Coordinate(startSRow, startSCol)) < Abs(coord - Coordinate(endSRow, endSCol)) || coord < Coordinate(startSRow, startSCol)) { /* point is close to left side of selection */ eventMode = LEFTEXTENSION; startERow = row; startECol = col; } else { /* point is close to left side of selection */ eventMode = RIGHTEXTENSION; endERow = row; endECol = col; } ComputeSelect(startERow, startECol, endERow, endECol, True); } ExtendExtend (row, col) int row, col; { int coord = Coordinate(row, col); if (eventMode == LEFTEXTENSION && (coord + (selectUnit!=SELECTCHAR)) > Coordinate(endSRow, endSCol)) { /* Whoops, he's changed his mind. Do RIGHTEXTENSION */ eventMode = RIGHTEXTENSION; startERow = saveStartRRow; startECol = saveStartRCol; } else if (eventMode == RIGHTEXTENSION && coord < Coordinate(startSRow, startSCol)) { /* Whoops, he's changed his mind. Do LEFTEXTENSION */ eventMode = LEFTEXTENSION; endERow = saveEndRRow; endECol = saveEndRCol; } if (eventMode == LEFTEXTENSION) { startERow = row; startECol = col; } else { endERow = row; endECol = col; } ComputeSelect(startERow, startECol, endERow, endECol, False); } void HandleStartExtend(w, event, params, num_params) Widget w; XEvent *event; /* must be XButtonEvent* */ String *params; /* unused */ Cardinal *num_params; /* unused */ { CHECK_RATIONAL_MODE(); do_start_extend (w, event, params, num_params, False); } void HandleKeyboardStartExtend(w, event, params, num_params) Widget w; XEvent *event; /* must be XButtonEvent* */ String *params; /* unused */ Cardinal *num_params; /* unused */ { do_start_extend (w, event, params, num_params, True); } ScrollSelection(screen, amount) register TScreen* screen; register int amount; { register int minrow = -screen->savedlines; /* Sent by scrollbar stuff, so amount never takes selection out of saved text */ /* XXX - the preceeding is false; cat /etc/termcap (or anything larger than the number of saved lines plus the screen height) and then hit extend select */ startRRow += amount; endRRow += amount; startSRow += amount; endSRow += amount; rawRow += amount; screen->startHRow += amount; screen->endHRow += amount; if (startRRow < minrow) { startRRow = minrow; startRCol = 0; } if (endRRow < minrow) { endRRow = minrow; endRCol = 0; } if (startSRow < minrow) { startSRow = minrow; startSCol = 0; } if (endSRow < minrow) { endSRow = minrow; endSCol = 0; } if (rawRow < minrow) { rawRow = minrow; rawCol = 0; } if (screen->startHRow < minrow) { screen->startHRow = minrow; screen->startHCol = 0; } if (screen->endHRow < minrow) { screen->endHRow = minrow; screen->endHCol = 0; } screen->startHCoord = Coordinate (screen->startHRow, screen->startHCol); screen->endHCoord = Coordinate (screen->endHRow, screen->endHCol); } /*ARGSUSED*/ ResizeSelection (screen, rows, cols) TScreen *screen; int rows, cols; { rows--; /* decr to get 0-max */ cols--; if (startRRow > rows) startRRow = rows; if (startSRow > rows) startSRow = rows; if (endRRow > rows) endRRow = rows; if (endSRow > rows) endSRow = rows; if (rawRow > rows) rawRow = rows; if (startRCol > cols) startRCol = cols; if (startSCol > cols) startSCol = cols; if (endRCol > cols) endRCol = cols; if (endSCol > cols) endSCol = cols; if (rawCol > cols) rawCol = cols; } static PointToRowCol(y, x, r, c) register int y, x; int *r, *c; /* Convert pixel coordinates to character coordinates. Rows are clipped between firstValidRow and lastValidRow. Columns are clipped between to be 0 or greater, but are not clipped to some maximum value. */ { register TScreen *screen = &term->screen; register row, col; row = (y - screen->border) / FontHeight(screen); if(row < firstValidRow) row = firstValidRow; else if(row > lastValidRow) row = lastValidRow; col = (x - screen->border - screen->scrollbar) / FontWidth(screen); if(col < 0) col = 0; else if(col > screen->max_col+1) { col = screen->max_col+1; } *r = row; *c = col; } int LastTextCol(row) register int row; { register TScreen *screen = &term->screen; register int i; register Char *ch; for(i = screen->max_col, ch = screen->buf[2 * (row + screen->topline)] + i ; i > 0 && (*ch == ' ' || *ch == 0); ch--, i--); return(i); } static int charClass[128] = { /* NUL SOH STX ETX EOT ENQ ACK BEL */ 32, 1, 1, 1, 1, 1, 1, 1, /* BS HT NL VT NP CR SO SI */ 1, 32, 1, 1, 1, 1, 1, 1, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 1, 1, 1, 1, 1, 1, 1, 1, /* CAN EM SUB ESC FS GS RS US */ 1, 1, 1, 1, 1, 1, 1, 1, /* SP ! " # $ % & ' */ 32, 33, 34, 35, 36, 37, 38, 39, /* ( ) * + , - . / */ 40, 41, 42, 43, 44, 45, 46, 47, /* 0 1 2 3 4 5 6 7 */ 48, 48, 48, 48, 48, 48, 48, 48, /* 8 9 : ; < = > ? */ 48, 48, 58, 59, 60, 61, 62, 63, /* @ A B C D E F G */ 64, 48, 48, 48, 48, 48, 48, 48, /* H I J K L M N O */ 48, 48, 48, 48, 48, 48, 48, 48, /* P Q R S T U V W */ 48, 48, 48, 48, 48, 48, 48, 48, /* X Y Z [ \ ] ^ _ */ 48, 48, 48, 91, 92, 93, 94, 48, /* ` a b c d e f g */ 96, 48, 48, 48, 48, 48, 48, 48, /* h i j k l m n o */ 48, 48, 48, 48, 48, 48, 48, 48, /* p q r s t u v w */ 48, 48, 48, 48, 48, 48, 48, 48, /* x y z { | } ~ DEL */ 48, 48, 48, 123, 124, 125, 126, 1}; int SetCharacterClassRange (low, high, value) register int low, high; /* in range of [0..127] */ register int value; /* arbitrary */ { if (low < 0 || high > 127 || high < low) return (-1); for (; low <= high; low++) charClass[low] = value; return (0); } ComputeSelect(startRow, startCol, endRow, endCol, extend) int startRow, startCol, endRow, endCol; Bool extend; { register TScreen *screen = &term->screen; register Char *ptr; register int length; register int class; int osc = startSCol; if (Coordinate(startRow, startCol) <= Coordinate(endRow, endCol)) { startSRow = startRRow = startRow; startSCol = startRCol = startCol; endSRow = endRRow = endRow; endSCol = endRCol = endCol; } else { /* Swap them */ startSRow = startRRow = endRow; startSCol = startRCol = endCol; endSRow = endRRow = startRow; endSCol = endRCol = startCol; } switch (selectUnit) { case SELECTCHAR : if (startSCol > (LastTextCol(startSRow) + 1)) { startSCol = 0; startSRow++; } if (endSCol > (LastTextCol(endSRow) + 1)) { endSCol = 0; endSRow++; } break; case SELECTWORD : if (startSCol > (LastTextCol(startSRow) + 1)) { startSCol = 0; startSRow++; } else { ptr = screen->buf[2*(startSRow+screen->topline)] + startSCol; class = charClass[*ptr]; do { --startSCol; --ptr; } while (startSCol >= 0 && charClass[*ptr] == class); ++startSCol; } if (endSCol > (LastTextCol(endSRow) + 1)) { endSCol = 0; endSRow++; } else { length = LastTextCol(endSRow); ptr = screen->buf[2*(endSRow+screen->topline)] + endSCol; class = charClass[*ptr]; do { ++endSCol; ++ptr; } while (endSCol <= length && charClass[*ptr] == class); /* Word select selects if pointing to any char in "word", especially in that it includes the last character in a word. So no --endSCol and do special eol handling */ if (endSCol > length+1) { endSCol = 0; ++endSRow; } } break; case SELECTLINE : if (term->screen.cutToBeginningOfLine) { startSCol = 0; } else if (!extend) { startSCol = osc; } if (term->screen.cutNewline) { endSCol = 0; ++endSRow; } else { endSCol = LastTextCol(endSRow) + 1; } break; } TrackText(startSRow, startSCol, endSRow, endSCol); return; } TrackText(frow, fcol, trow, tcol) register int frow, fcol, trow, tcol; /* Guaranteed (frow, fcol) <= (trow, tcol) */ { register int from, to; register TScreen *screen = &term->screen; int old_startrow, old_startcol, old_endrow, old_endcol; /* (frow, fcol) may have been scrolled off top of display */ if (frow < 0) frow = fcol = 0; /* (trow, tcol) may have been scrolled off bottom of display */ if (trow > screen->max_row+1) { trow = screen->max_row+1; tcol = 0; } old_startrow = screen->startHRow; old_startcol = screen->startHCol; old_endrow = screen->endHRow; old_endcol = screen->endHCol; if (frow == old_startrow && fcol == old_startcol && trow == old_endrow && tcol == old_endcol) return; screen->startHRow = frow; screen->startHCol = fcol; screen->endHRow = trow; screen->endHCol = tcol; from = Coordinate(frow, fcol); to = Coordinate(trow, tcol); if (to <= screen->startHCoord || from > screen->endHCoord) { /* No overlap whatsoever between old and new hilite */ ReHiliteText(old_startrow, old_startcol, old_endrow, old_endcol); ReHiliteText(frow, fcol, trow, tcol); } else { if (from < screen->startHCoord) { /* Extend left end */ ReHiliteText(frow, fcol, old_startrow, old_startcol); } else if (from > screen->startHCoord) { /* Shorten left end */ ReHiliteText(old_startrow, old_startcol, frow, fcol); } if (to > screen->endHCoord) { /* Extend right end */ ReHiliteText(old_endrow, old_endcol, trow, tcol); } else if (to < screen->endHCoord) { /* Shorten right end */ ReHiliteText(trow, tcol, old_endrow, old_endcol); } } screen->startHCoord = from; screen->endHCoord = to; } ReHiliteText(frow, fcol, trow, tcol) register int frow, fcol, trow, tcol; /* Guaranteed that (frow, fcol) <= (trow, tcol) */ { register TScreen *screen = &term->screen; register int i; if (frow < 0) frow = fcol = 0; else if (frow > screen->max_row) return; /* nothing to do, since trow >= frow */ if (trow < 0) return; /* nothing to do, since frow <= trow */ else if (trow > screen->max_row) { trow = screen->max_row; tcol = screen->max_col+1; } if (frow == trow && fcol == tcol) return; if(frow != trow) { /* do multiple rows */ if((i = screen->max_col - fcol + 1) > 0) { /* first row */ ScrnRefresh(screen, frow, fcol, 1, i, True); } if((i = trow - frow - 1) > 0) { /* middle rows*/ ScrnRefresh(screen, frow+1, 0,i, screen->max_col+1, True); } if(tcol > 0 && trow <= screen->max_row) { /* last row */ ScrnRefresh(screen, trow, 0, 1, tcol, True); } } else { /* do single row */ ScrnRefresh(screen, frow, fcol, 1, tcol - fcol, True); } } SaltTextAway(crow, ccol, row, col, params, num_params) /*register*/ int crow, ccol, row, col; String *params; /* selections */ Cardinal num_params; /* Guaranteed that (crow, ccol) <= (row, col), and that both points are valid (may have row = screen->max_row+1, col = 0) */ { register TScreen *screen = &term->screen; register int i, j = 0; char *line, *lp; static _OwnSelection(); if (crow == row && ccol > col) { int tmp = ccol; ccol = col; col = tmp; } --col; /* first we need to know how long the string is before we can save it*/ if ( row == crow ) j = Length(screen, crow, ccol, col); else { /* two cases, cut is on same line, cut spans multiple lines */ j += Length(screen, crow, ccol, screen->max_col) + 1; for(i = crow + 1; i < row; i++) j += Length(screen, i, 0, screen->max_col) + 1; if (col >= 0) j += Length(screen, row, 0, col); } /* now get some memory to save it in */ if (screen->selection_size <= j) { if((line = malloc((unsigned) j + 1)) == (char *)NULL) SysError(ERROR_BMALLOC2); XtFree(screen->selection); screen->selection = line; screen->selection_size = j + 1; } else line = screen->selection; if (!line || j < 0) return; line[j] = '\0'; /* make sure it is null terminated */ lp = line; /* lp points to where to save the text */ if ( row == crow ) lp = SaveText(screen, row, ccol, col, lp); else { lp = SaveText(screen, crow, ccol, screen->max_col, lp); *lp ++ = '\n'; /* put in newline at end of line */ for(i = crow +1; i < row; i++) { lp = SaveText(screen, i, 0, screen->max_col, lp); *lp ++ = '\n'; } if (col >= 0) lp = SaveText(screen, row, 0, col, lp); } *lp = '\0'; /* make sure we have end marked */ screen->selection_length = j; _OwnSelection(term, params, num_params); } static Boolean ConvertSelection(w, selection, target, type, value, length, format) Widget w; Atom *selection, *target, *type; caddr_t *value; unsigned long *length; int *format; { Display* d = XtDisplay(w); XtermWidget xterm = (XtermWidget)w; if (xterm->screen.selection == NULL) return False; /* can this happen? */ if (*target == XA_TARGETS(d)) { Atom* targetP; Atom* std_targets; unsigned long std_length; XmuConvertStandardSelection( w, xterm->screen.selection_time, selection, target, type, (caddr_t*)&std_targets, &std_length, format ); *length = std_length + 5; *value = (caddr_t)XtMalloc((Cardinal)(sizeof(Atom)*(*length))); targetP = *(Atom**)value; *targetP++ = XA_STRING; *targetP++ = XA_TEXT(d); *targetP++ = XA_COMPOUND_TEXT(d); *targetP++ = XA_LENGTH(d); *targetP++ = XA_LIST_LENGTH(d); bcopy((char*)std_targets, (char*)targetP, (int)(sizeof(Atom)*std_length)); XtFree((char*)std_targets); *type = XA_ATOM; *format = 32; return True; } if (*target == XA_STRING || *target == XA_TEXT(d) || *target == XA_COMPOUND_TEXT(d)) { if (*target == XA_COMPOUND_TEXT(d)) *type = *target; else *type = XA_STRING; *value = xterm->screen.selection; *length = xterm->screen.selection_length; *format = 8; return True; } if (*target == XA_LIST_LENGTH(d)) { *value = XtMalloc((Cardinal)4L); if (sizeof(long) == 4) *(long*)*value = 1; else { long temp = 1; bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4); } *type = XA_INTEGER; *length = 1; *format = 32; return True; } if (*target == XA_LENGTH(d)) { *value = XtMalloc((Cardinal)4L); if (sizeof(long) == 4) *(long*)*value = xterm->screen.selection_length; else { long temp = xterm->screen.selection_length; bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4); } *type = XA_INTEGER; *length = 1; *format = 32; return True; } if (XmuConvertStandardSelection(w, xterm->screen.selection_time, selection, target, type, value, length, format)) return True; /* else */ return False; } static void LoseSelection(w, selection) Widget w; Atom *selection; { register TScreen* screen = &((XtermWidget)w)->screen; register Atom* atomP; int i; for (i = 0, atomP = screen->selection_atoms; i < screen->selection_count; i++, atomP++) { if (*selection == *atomP) *atomP = (Atom)0; switch (*atomP) { case XA_CUT_BUFFER0: case XA_CUT_BUFFER1: case XA_CUT_BUFFER2: case XA_CUT_BUFFER3: case XA_CUT_BUFFER4: case XA_CUT_BUFFER5: case XA_CUT_BUFFER6: case XA_CUT_BUFFER7: *atomP = (Atom)0; } } for (i = screen->selection_count; i; i--) { if (screen->selection_atoms[i-1] != 0) break; } screen->selection_count = i; for (i = 0, atomP = screen->selection_atoms; i < screen->selection_count; i++, atomP++) { if (*atomP == (Atom)0) { *atomP = screen->selection_atoms[--screen->selection_count]; } } if (screen->selection_count == 0) TrackText(0, 0, 0, 0); } /* ARGSUSED */ static void SelectionDone(w, selection, target) Widget w; Atom *selection, *target; { /* empty proc so Intrinsics know we want to keep storage */ } static /* void */ _OwnSelection(term, selections, count) register XtermWidget term; String *selections; Cardinal count; { Atom* atoms = term->screen.selection_atoms; int i; Boolean have_selection = False; if (term->screen.selection_length < 0) return; if (count > term->screen.sel_atoms_size) { XtFree((char*)atoms); atoms = (Atom*)XtMalloc((Cardinal)(count*sizeof(Atom))); term->screen.selection_atoms = atoms; term->screen.sel_atoms_size = count; } XmuInternStrings( XtDisplay((Widget)term), selections, count, atoms ); for (i = 0; i < count; i++) { int buffer; switch (atoms[i]) { case XA_CUT_BUFFER0: buffer = 0; break; case XA_CUT_BUFFER1: buffer = 1; break; case XA_CUT_BUFFER2: buffer = 2; break; case XA_CUT_BUFFER3: buffer = 3; break; case XA_CUT_BUFFER4: buffer = 4; break; case XA_CUT_BUFFER5: buffer = 5; break; case XA_CUT_BUFFER6: buffer = 6; break; case XA_CUT_BUFFER7: buffer = 7; break; default: buffer = -1; } if (buffer >= 0) XStoreBuffer( XtDisplay((Widget)term), term->screen.selection, term->screen.selection_length, buffer ); else if (!replyToEmacs) { have_selection |= XtOwnSelection( (Widget)term, atoms[i], term->screen.selection_time, ConvertSelection, LoseSelection, SelectionDone ); } } if (!replyToEmacs) term->screen.selection_count = count; if (!have_selection) TrackText(0, 0, 0, 0); } /* void */ DisownSelection(term) register XtermWidget term; { Atom* atoms = term->screen.selection_atoms; Cardinal count = term->screen.selection_count; int i; for (i = 0; i < count; i++) { int buffer; switch (atoms[i]) { case XA_CUT_BUFFER0: buffer = 0; break; case XA_CUT_BUFFER1: buffer = 1; break; case XA_CUT_BUFFER2: buffer = 2; break; case XA_CUT_BUFFER3: buffer = 3; break; case XA_CUT_BUFFER4: buffer = 4; break; case XA_CUT_BUFFER5: buffer = 5; break; case XA_CUT_BUFFER6: buffer = 6; break; case XA_CUT_BUFFER7: buffer = 7; break; default: buffer = -1; } if (buffer < 0) XtDisownSelection( (Widget)term, atoms[i], term->screen.selection_time ); } term->screen.selection_count = 0; term->screen.startHRow = term->screen.startHCol = 0; term->screen.endHRow = term->screen.endHCol = 0; } /* returns number of chars in line from scol to ecol out */ int Length(screen, row, scol, ecol) register int row, scol, ecol; register TScreen *screen; { register Char *ch; ch = screen->buf[2 * (row + screen->topline)]; while (ecol >= scol && (ch[ecol] == ' ' || ch[ecol] == 0)) ecol--; return (ecol - scol + 1); } /* copies text into line, preallocated */ char *SaveText(screen, row, scol, ecol, lp) int row; int scol, ecol; TScreen *screen; register char *lp; /* pointer to where to put the text */ { register int i = 0; register Char *ch = screen->buf[2 * (row + screen->topline)]; register int c; if ((i = Length(screen, row, scol, ecol)) == 0) return(lp); ecol = scol + i; for (i = scol; i < ecol; i++) { if ((c = ch[i]) == 0) c = ' '; else if(c < ' ') { if(c == '\036') c = '#'; else c += 0x5f; } else if(c == 0x7f) c = 0x5f; *lp++ = c; } return(lp); } EditorButton(event) register XButtonEvent *event; { register TScreen *screen = &term->screen; int pty = screen->respond; char line[6]; register unsigned row, col; int button; button = event->button - 1; row = (event->y - screen->border) / FontHeight(screen); col = (event->x - screen->border - screen->scrollbar) / FontWidth(screen); (void) strcpy(line, "\033[M"); if (screen->send_mouse_pos == 1) { line[3] = ' ' + button; } else { line[3] = ' ' + (KeyState(event->state) << 2) + ((event->type == ButtonPress)? button:3); } line[4] = ' ' + col + 1; line[5] = ' ' + row + 1; v_write(pty, line, 6); } #define FIRSTMENU 0 #define XTERMMENU 0 #define VTMENU 1 #define RCGMENU 2 #define NMENUS 3 static Menu *menus[NMENUS]; static int type; /* ARGSUSED */ void HandleModeMenu(w, event, params, num_params) Widget w; XEvent *event; String *params; /* unused */ Cardinal *num_params; /* unused */ { extern int menu_grab; CHECK_RATIONAL_MODE(); ModeMenu((XButtonEvent*)event); menu_grab = TRUE; } ModeMenu(event) register XButtonEvent *event; { register TScreen *screen = &term->screen; register Menu *menu; register int item; static int inited = FALSE; extern Menu *setupmenu(), *rcgsetupmenu(), *xsetupmenu(); extern void InitRatCursor(); if(!inited) { Display *dpy; int DefScreen; Pixel Black, White; inited = TRUE; /*--The rearranging of the following code gets rid of a * segmentation fault that I can't track down. The code * produced is correct; the data at the time of the fault * is correct; but one register is trashed; the value it holds * was just calculated from a pointer+offset in another * register and the value is not the value i should be. * Presumably a Signal occurred and for some reason a0 is * trashed. It only happens on one machine and this fixes it. * I'd love to know why. GEB */ dpy = screen->display; DefScreen = DefaultScreen(dpy); Black = BlackPixel(dpy,DefScreen); White = WhitePixel(dpy,DefScreen); Gray_Tile = make_gray( Black, White, 1 ); /* End of code rearrangement to fix segmentation problem. */ InitRatCursor(); Menu_DefaultCursor = screen->arrow; /* if(XStrCmp(Menu_DefaultFont, f_t) == 0) Menu_DefaultFontInfo = screen->fnt_norm; */ } switch (event->button) { case Button1 : type = XTERMMENU; if ((menu = xsetupmenu( &menus[XTERMMENU] )) == NULL) return; break; case Button2 : type = VTMENU; if ((menu = setupmenu( &menus[VTMENU] )) == NULL) return; break; case Button3 : type = RCGMENU; if ((menu = rcgsetupmenu( &menus[RCGMENU] )) == NULL) return; break; default : Bell(); return; } /* * Set the select mode manually. */ TrackMenu(menu, event); /* MenuButtonReleased calls FinishModeMenu */ } FinishModeMenu(item, time) register int item; Time time; { TScreen *screen = &term->screen; extern void xdomenufunc(), domenufunc(), rcgdomenufunc(); menusync(); if (item < 0) { return; } switch(type) { case XTERMMENU : xdomenufunc( item, time ); break; case VTMENU : domenufunc( item ); break; case RCGMENU : rcgdomenufunc( item ); break; } } menusync() { XEvent event; TScreen *screen = &term->screen; /*--Sync with server. */ XSync(screen->display, 0); /*--Use up all events since we popped up the menu. */ while (QLength(screen->display) > 0) { XtNextEvent( &event ); XtDispatchEvent( &event ); } #if 0 TScreen *screen = &term->screen; XSync(screen->display, 0); if (QLength(screen->display) > 0) xevents(); #endif } \f Menu *rcgsetupmenu( menu ) register Menu **menu; /****************************************************************************** * menu - Specifies the menu slot to use to store the menu being created * * Called to create the RXI Recognition menu. We create it and we check-mark * the current recognition value. ******************************************************************************/ { register TScreen *screen = &term->screen; register char **cp; register int i; if (*menu == NULL) { if ((*menu = NewMenu("RXI Recognition")) == NULL) return(NULL); for(i = 0, cp = rcgtext ; *cp ; ++i,++cp) { AddMenuItem(*menu, *cp); if (RecognitionValue == rcgcode[i]) { CheckItem( *menu, i ); } } return(*menu); } for(i = 0, cp = rcgtext ; *cp ; ++i,++cp) { SetItemCheck( *menu, i, RecognitionValue == rcgcode[i] ); } return(*menu); } /* rcgsetupmenu */ \f void rcgdomenufunc( item ) int item; /****************************************************************************** * item - Specifies the menu item (0..N) that was selected * * Called when a menu item from the RXI Recognition menu is selected. We change * the current recognition value. ******************************************************************************/ { RecognitionValue = rcgcode[item]; } /* rcgdomenufunc */ \f #define XMENU_GRABKBD 0 #define XMENU_VISUALBELL (XMENU_GRABKBD+1) #define XMENU_LOG (XMENU_VISUALBELL+1) #define XMENU_REDRAW (XMENU_LOG+1) #define XMENU_LINE (XMENU_REDRAW+1) #define XMENU_SUSPEND (XMENU_LINE+1) #define XMENU_RESUME (XMENU_SUSPEND+1) #define XMENU_INTR (XMENU_RESUME+1) #define XMENU_HANGUP (XMENU_INTR+1) #define XMENU_TERM (XMENU_HANGUP+1) #define XMENU_KILL (XMENU_TERM+1) #define XMENU_LINE2 (XMENU_KILL+1) #define XMENU_EXIT (XMENU_LINE2+1) static char *xtext[] = { "Secure Keyboard", "Visual Bell", "Logging", "Redraw", "-", "Suspend program", "Continue program", "Interrupt program", "Hangup program", "Terminate program", "Kill program", "-", "Quit", 0, }; static int xbell; static int xlog; static int xkgrab; Menu *xsetupmenu(menu) register Menu **menu; { register TScreen *screen = &term->screen; register char **cp; register int i; if (*menu == NULL) { if ((*menu = NewMenu("RXI X11")) == NULL) return(NULL); for(cp = xtext ; *cp ; cp++) AddMenuItem(*menu, *cp); if(xkgrab = screen->grabbedKbd) CheckItem(*menu, XMENU_GRABKBD); if(xbell = screen->visualbell) CheckItem(*menu, XMENU_VISUALBELL); if(xlog = screen->logging) CheckItem(*menu, XMENU_LOG); DisableItem(*menu, XMENU_LINE); if((screen->inhibit & I_LOG)) DisableItem(*menu, XMENU_LOG); if(screen->inhibit & I_SIGNAL) for(i = XMENU_SUSPEND ; i <= XMENU_KILL ; i++) DisableItem(*menu, i); #if defined(SYSV) && !defined(JOBCONTROL) DisableItem(*menu, XMENU_RESUME); DisableItem(*menu, XMENU_SUSPEND); #endif /* defined(SYSV) && !defined(JOBCONTROL) */ return(*menu); } /* if login window, check for completed login */ if (!(screen->inhibit & I_LOG)) EnableItem(*menu, XMENU_LOG); if (xkgrab != screen->grabbedKbd) SetItemCheck(*menu, XMENU_GRABKBD, (xkgrab = screen->grabbedKbd)); if (xbell != screen->visualbell) SetItemCheck(*menu, XMENU_VISUALBELL, (xbell = screen->visualbell)); if (xlog != screen->logging) SetItemCheck(*menu, XMENU_LOG, (xlog = screen->logging)); return(*menu); } void xdomenufunc(item, time) int item; Time time; { register TScreen *screen = &term->screen; switch (item) { case XMENU_GRABKBD: if (screen->grabbedKbd) { XUngrabKeyboard(screen->display, time); ReverseVideo(term); screen->grabbedKbd = FALSE; } else { if (XGrabKeyboard(screen->display, term->core.parent->core.window, True, GrabModeAsync, GrabModeAsync, time) != GrabSuccess) { XBell(screen->display, 100); } else { ReverseVideo(term); screen->grabbedKbd = TRUE; } } break; case XMENU_VISUALBELL: screen->visualbell = !screen->visualbell; break; case XMENU_LOG: if(screen->logging) CloseLog(screen); else StartLog(screen); break; case XMENU_REDRAW: Redraw(); break; /* * The following cases use the pid instead of the process group so that we * don't get hosed by programs that change their process group */ case XMENU_RESUME: #if !defined(SYSV) || defined(JOBCONTROL) if(screen->pid > 1) killpg ((int)screen->pid, SIGCONT); #endif /* !defined(SYSV) || defined(JOBCONTROL) */ break; case XMENU_SUSPEND: #if !defined(SYSV) || defined(JOBCONTROL) if(screen->pid > 1) killpg ((int)screen->pid, SIGTSTP); #endif /* !defined(SYSV) || defined(JOBCONTROL) */ break; case XMENU_INTR: if(screen->pid > 1) killpg ((int)screen->pid, SIGINT); break; case XMENU_HANGUP: if(screen->pid > 1) killpg ((int)screen->pid, SIGHUP); break; case XMENU_TERM: if(screen->pid > 1) killpg ((int)screen->pid, SIGTERM); break; case XMENU_KILL: if(screen->pid > 1) killpg ((int)screen->pid, SIGKILL); break; case XMENU_EXIT: Cleanup (0); /* NOTREACHED */ } } MenuNewCursor(cur) register Cursor cur; { register Menu **menu; register int i; register TScreen *screen = &term->screen; Menu_DefaultCursor = cur; for(i = FIRSTMENU, menu = menus ; i < NMENUS ; menu++, i++) { if(!*menu) continue; (*menu)->menuCursor = cur; if((*menu)->menuWindow) XDefineCursor(screen->display, (*menu)->menuWindow, cur); } } ReverseVideoAllMenus () { int i; XtermWidget xw = term; Display *dpy = XtDisplay (xw); Pixel fg, bg; MenuResetGCs (&bg, &fg); for (i = FIRSTMENU; i < NMENUS; i++) { Menu *menu = menus[i]; if (menu) { menu->menuBgColor = bg; menu->menuFgColor = fg; XSetWindowBackground (dpy, menu->menuWindow, menu->menuBgColor); menu->menuFlags |= menuChanged; } } if (RatMenu) { XtDestroyWidget( RatMenu );/* We'll rebuild it with new bg/fg later.*/ RatMenu = 0; if (RatMenuDefaults.permanent) { RatMenuPermanent( FALSE ); } } return; } /*ARGSUSED*/ Bogus(event) XButtonEvent *event; { Bell(); } /* ARGSUSED */ void HandleSecure(w, event, params, param_count) Widget w; XEvent *event; /* unused */ String *params; /* [0] = volume */ Cardinal *param_count; /* 0 or 1 */ { Time time = CurrentTime; if ((event->xany.type == KeyPress) || (event->xany.type == KeyRelease)) time = event->xkey.time; else if ((event->xany.type == ButtonPress) || (event->xany.type == ButtonRelease)) time = event->xbutton.time; xdomenufunc(XMENU_GRABKBD, time); } \f /****************************************************************************** * R1000 Button Flags - what does each button do? * * - you cannot have a PopupMenu action with any form of Down/Up action * - if RButton2 is not going to be the PopupMenu button then you must also * change various things in ratmenu.c; eg. the <Btn2Down/Up> actions. ******************************************************************************/ #define DoNothing 0 /* do nothing at all */ #define CmdOnDown (1<< 0) /* xmit R1000 btn on press */ #define CmdOnUp (1<< 1) /* xmit R1000 btn on release */ #define CmdOnDblClick (1<< 2) /* xmit R1000 btn on double click */ #define MvCsrOnDown (1<< 3) /* move R1000 cursor on press */ #define MvCsrOnUp (1<< 4) /* move R1000 cursor on release */ #define MvCsrOnDblClick (1<< 5) /* move R1000 cursor on dbl click */ #define PopupMenu (1<< 6) /* pop up a menu */ #define WindowSnag (1<< 7) /* move R1000 window while pressed */ /*--Unshifted buttons */ #define RButton1 (CmdOnDown|CmdOnDblClick|MvCsrOnDown|MvCsrOnDblClick) #define RButton2 (PopupMenu|CmdOnDblClick|MvCsrOnDblClick) #define RButton3 (CmdOnDown|CmdOnDblClick|MvCsrOnDown|MvCsrOnDblClick) /*--Shifted buttons */ #define RSButton1 (CmdOnDown|CmdOnUp|MvCsrOnDown|MvCsrOnUp| \ CmdOnDblClick|MvCsrOnDblClick) #define RSButton2 (CmdOnDown|MvCsrOnDown| \ CmdOnDblClick|MvCsrOnDblClick) #define RSButton3 (WindowSnag| \ CmdOnDblClick|MvCsrOnDblClick) /*--If you have a menu on a button then you can have DoubleClick set but not * Down or Up. */ #define BadOptions(btn) \ ((((btn)&WindowSnag) && ((btn)&PopupMenu)) || \ (((btn)&(PopupMenu|WindowSnag)) && \ ((btn)&(CmdOnUp|CmdOnDown|MvCsrOnDown|MvCsrOnUp)))) #define ModifierMask (ShiftMask | LockMask | ControlMask | Mod1Mask | \ Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) /*--Our little double-click event queue. */ static XtIntervalId EventTimer; int EventCount = 0; static XButtonEvent Events[2]; static unsigned int ButtonMask[6]; /* when button N went down it had */ /* these modifiers; button up will */ /* be forced to be likewise */ /*--X_No_Op and XScreenRedraw key strokes. */ static char XNoOps[2] = { MOUSE_PREFIX, X_NO_OP }; static char XScreenRedraw[2] = { MOUSE_PREFIX, X_SCREEN_REDRAW }; /*--Our Window Motion data. */ Boolean WindowMotion = FALSE; /* Are we currently doing window it? */ int WindowX; /* Last X recorded. */ int WindowY; /* Last Y recorded. */ /*--Rational Environment Menu declarations. */ extern Boolean RatMenuMapped(); /*--Get the flags for the button in question. */ int ButtonFlags( event ) XButtonEvent *event; { if (BadOptions(RButton1) || BadOptions(RButton2) || BadOptions(RButton3) || BadOptions(RSButton1) || BadOptions(RSButton2) || BadOptions(RSButton3)){ /*--This should be compiled-out as the above expression will evaluate to * FALSE with a decent compiler. */ (void)fprintf( stderr, "Bad options on some button?\n" ); } if (event->state & ShiftMask) { if (event->button == Button1) return RSButton1; if (event->button == Button2) return RSButton2; return RSButton3; } if (event->button == Button1) return RButton1; if (event->button == Button2) return RButton2; return RButton3; } \f RGoTo( howfar, where ) int howfar; char where; /****************************************************************************** * Called to compose and transmit an individual DOWN/RIGHT command for the * R1000. Called with a +/- distance and a command character. * howfar must be in the range -9999..9999. ******************************************************************************/ { char buf[2*6]; register char *bp = &buf[0]; register KeySym key; /* Minus sign */ if (howfar < 0) { *bp++ = MOUSE_PREFIX; *bp++ = MOUSE_MINUS; howfar = -howfar; } /* Put out digits */ *bp++ = MOUSE_PREFIX; if (howfar < 10) { *bp++ = MOUSE_0 + howfar; } else if (howfar < 100) { *bp++ = MOUSE_0 + howfar/10; *bp++ = MOUSE_PREFIX; *bp++ = MOUSE_0 + howfar%10; } else if (howfar < 1000) { *bp++ = MOUSE_0 + howfar/100; *bp++ = MOUSE_PREFIX; *bp++ = MOUSE_0 + howfar/10%10; *bp++ = MOUSE_PREFIX; *bp++ = MOUSE_0 + howfar%10; } else { if (howfar > 9999) { howfar = 9999; } *bp++ = MOUSE_0 + howfar/1000; *bp++ = MOUSE_PREFIX; *bp++ = MOUSE_0 + howfar/100%10; *bp++ = MOUSE_PREFIX; *bp++ = MOUSE_0 + howfar/10%10; *bp++ = MOUSE_PREFIX; *bp++ = MOUSE_0 + howfar%10; } /* Go there */ *bp++ = MOUSE_PREFIX; *bp++ = where; (void)v_write( term->screen.respond, buf, bp-buf ); } /* RGoTo */ \f void RatResize() /****************************************************************************** * Called when the VT100 window gets resized. We tell the R1000 about it. ******************************************************************************/ { int col = term->screen.max_col+1; int row = term->screen.max_row+1; (void)v_write( term->screen.respond, XNoOps, XtNumber(XNoOps) ); RGoTo( (col < MIN_COLS ? MIN_COLS : col), X_SCREEN_WIDTH ); RGoTo( (row < MIN_ROWS ? MIN_ROWS : row), X_SCREEN_HEIGHT ); (void)v_write( term->screen.respond, XScreenRedraw, XtNumber(XScreenRedraw) ); } /* RatResize */ \f void MvCsr( event, noop ) XButtonEvent *event; int noop; /****************************************************************************** * Called to do the MVCSR action for a button. This means transmit commands to * the R1000 to move the R1000's cursor to the same position as the mouse. ******************************************************************************/ { int mrow; int mcol; int crow = term->screen.cur_row; int ccol = term->screen.cur_col; /*--If this is the first mouse operation for this button/mouse event then * send out an X_No_Op key stroke. */ if (noop == 0) { (void)v_write( term->screen.respond, XNoOps, XtNumber(XNoOps) ); } /*--Move the cursor to the location of the button press. */ firstValidRow = 0; lastValidRow = term->screen.max_row; PointToRowCol( event->y, event->x, &mrow, &mcol ); if (mrow != crow) RGoTo( mrow - crow, MOUSE_DOWN ); /* Go Down */ if (mcol != ccol) RGoTo( mcol - ccol, MOUSE_RIGHT ); /* Go Right */ } /* MvCsr */ \f void CmdOn( event, DblClick, noop ) XButtonEvent *event; Boolean DblClick; int noop; /****************************************************************************** * Called to do the CMD action for a button. This means transmit a "key" to * the R1000. ******************************************************************************/ { char buf[2]; char button; /*--If this is the first mouse operation for this button/mouse event then * send out an X_No_Op key stroke. */ if (noop == 0) { (void)v_write( term->screen.respond, XNoOps, XtNumber(XNoOps) ); } /*--Button Press/Releases send a key code. Button Press/Releases with Shift * send that code+3. */ switch (event->button) { case Button1 : button = MOUSE_BUTTON1; break; case Button2 : button = MOUSE_BUTTON2; break; case Button3 : button = MOUSE_BUTTON3; break; default : return; } if (event->state & ShiftMask) { button += 3; } if (event->type == ButtonRelease) { button += 6; } else if (DblClick) { button += 12; } /*--Transmit the button's key code. */ buf[0] = MOUSE_PREFIX; buf[1] = button; (void)v_write( term->screen.respond, buf, 2 ); } /* CmdOn */ \f void WindowMotionAnalyze( x, y ) int x; int y; /****************************************************************************** * Called when we get button-up or a motion event during window dragging. * Take the delta-x/y and put out window motion events corresponding to that. ******************************************************************************/ { extern int VerticalDragTrigger; extern int VerticalDragAmount; extern int HorizontalDragTrigger; extern int HorizontalDragAmount; /*--Compute the distance travelled since the last report. */ int deltax = x - WindowX; int deltay = y - WindowY; /*--We have travelled this many x/y "coordinates" or trigger-amounts. */ deltax /= HorizontalDragTrigger; deltay /= VerticalDragTrigger; /*--This many triggers corresponds to this effective new x/y. */ WindowX += deltax * HorizontalDragTrigger; WindowY += deltay * VerticalDragTrigger; /*--We want to move the image by this many x/y columns/lines. */ deltax *= HorizontalDragAmount; deltay *= VerticalDragAmount; /*--Do it. */ if (deltax || deltay) { (void)v_write( term->screen.respond, XNoOps, XtNumber(XNoOps) ); } if (deltax) RGoTo( deltax, MOUSE_IMAGE_RIGHT ); /* Go Right */ if (deltay) RGoTo( deltay, MOUSE_IMAGE_DOWN ); /* Go Down */ } /* WindowMotionAnalyze */ \f void DoEvent( flags, cancel_flags, event ) int flags; /* the button flags for this button */ int cancel_flags; /* button events to ignore this time around */ XButtonEvent *event; /* the event to process */ /****************************************************************************** * Called with an event. Pop up a menu or else do the Down/Up action(s) for * the button. Somebody else is responsible for double-clicks. ******************************************************************************/ { int once = -1; /*--If we are to do a Popup then do that and return. A press when the menu * is down brings the menu up. A press when the menu is up will take it * down. * A Popup button either has or does not have DoubleClick capability. If it * has DoubleClick then the only way we ever get here is during a Playback. * In that case; a Release will live in &Events[1] if the user clicked and * if will live in &Events[0] if the user pressed, waited, and released. * A Release on a click does nothing; a Release by itself pops the menu down. * If a button does not have DoubleClick then a Release does not live in * either Events slot and a release always drops the menu. */ flags &= ~cancel_flags; /* turn off certain flags */ if (flags & PopupMenu) { extern void PopupRatMenu(); if (event->type == ButtonRelease) { if (RatMenuMapped(RatMenu) && event != &Events[1]) { PopdownRatMenuChain( RatMenu, (XEvent*)NULL, (char**)NULL, (Cardinal*)NULL ); } return; } /* We must be a ButtonPress. */ if (RatMenuMapped(RatMenu)) { PopdownRatMenuChain( RatMenu, (XEvent*)NULL, (char**)NULL, (Cardinal*)NULL ); if (RatMenuDefaults.permanent) { /* Permanent menu's may need raising that XtPopup doesn't * provide. */ XRaiseWindow( XtDisplay(RatMenu), XtWindow(RatMenu) ); } } else { if (RatMenuDefaults.permanent) { RatMenuPermanent( FALSE ); } else { PopupRatMenu( RatMenu, (XEvent*)event, (String*)NULL, (Cardinal*)NULL ); } } return; } /*--Handle Presses. */ if (event->type == ButtonPress) { ButtonMask[event->button-1] = (event->state & ModifierMask); if (flags & MvCsrOnDown) MvCsr( event, ++once ); if (flags & CmdOnDown) CmdOn( event, FALSE, ++once ); if (flags & WindowSnag) { XGrabPointer( XtDisplay(term), XtWindow(term), FALSE, EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, Menu_Default.menuCursor, event->time ); WindowX = event->x_root; WindowY = event->y_root; WindowMotion = TRUE; } return; } /*--We can only be a Release. */ if ((event->state & ModifierMask) != ButtonMask[event->button-1]) { event->state = ButtonMask[event->button-1]; flags = ButtonFlags( event ); flags &= ~cancel_flags; /* turn off certain flags */ } if (flags & MvCsrOnUp) MvCsr( event, ++once ); if (flags & CmdOnUp) CmdOn( event, FALSE, ++once ); if (flags & WindowSnag) { XUngrabPointer( XtDisplay(term), event->time ); WindowMotionAnalyze( event->x_root, event->y_root ); WindowMotion = FALSE; } } /* DoEvent */ /*ARGSUSED*/ void PlaybackEvents( addr, timer ) caddr_t addr; XtIntervalId timer; /****************************************************************************** * Used on a time-out for a double-click. If we time out (or otherwise give up) * then call DoEvent on all stored events. ******************************************************************************/ { int i; int flags; Boolean moved = FALSE; for (i = 0; i < EventCount; i++) { flags = ButtonFlags( &Events[i] ); if (!moved) { DoEvent( flags, DoNothing, &Events[i] ); } else { /*--If we are playing back multiple events then only allow cursor * movement for the first one that wants it. Otherwise we will * be making multiple requests. And, since our requests are for * movement *relative* to the current position and since each * additional movement will be relative to an incorrect current * position (the R1000 hasn't been able to update our Vt100 cursor * yet) we would end up with a totally bogus screen position. If a * user is trying to be Speedie-The-Mouse then we won't always * be able to do what he wants but we will always do the right * thing for most users. */ DoEvent( flags, MvCsrOnDown|MvCsrOnUp|MvCsrOnDblClick, &Events[i] ); } if (flags & (MvCsrOnDown|MvCsrOnUp|MvCsrOnDblClick)) { moved = TRUE; } } XAllowEvents( term->screen.display, AsyncPointer, CurrentTime ); EventCount = 0; } /* PlaybackEvents */ /*ARGSUSED*/ Bool WaitForRelease( dpy, event, args ) Display *dpy; XEvent *event; char *args; /****************************************************************************** * Used with XIfEvent to wait (indefinitely) for a ButtonRelease of the same * button as started a double-click. ******************************************************************************/ { if (event->xany.type == ButtonRelease && event->xbutton.button == ((XButtonEvent*)args)->button) return TRUE; if (event->xany.type == ButtonPress) { XAllowEvents( dpy, AsyncPointer, event->xbutton.time ); } return FALSE; } \f void RationalButton(event) XButtonEvent *event; /****************************************************************************** * Called whenever a button event occurs for unshifted or shifted buttons * and we are in Rational mode. We figure out what to do and do it. We are * the one responsible for setting up double-clicks and such. ******************************************************************************/ { int once = -1; int flags; /*--Make sure that the menu exists. We only guarantee existence; not realized * or mapped. */ if (RatMenu == NULL) { extern void RationalMenuInit(); RationalMenuInit( (Widget)term ); } /*--EventCount > 0 means we are waiting for a double-click to happen; or not * to happen. If this isn't the same button as the one we are waiting for * then the double-click isn't coming and we play-back the pending Events * and then handle this event. */ if (EventCount > 0) { if (event->button != Events[0].button) { XtRemoveTimeOut( EventTimer ); PlaybackEvents( (caddr_t)NULL, (XtIntervalId)0 ); } else { /*--We are the same button as the one that is (about to; maybe) double-click. * Handle the event and be aware of errors that in-theory will never-happen.*/ switch (EventCount) { /*--We have 1 event; the press. The next event on this button should be a * release. Record it and continue to wait for the next press. */ case 1 : if (event->type != ButtonRelease) { (void)fprintf ( stderr, "RationalButton: EventCount==1&&Type!=Release [%d]?\n", event->type); EventCount = 0; return; } EventCount++; bcopy( (char*)event, (char*)&Events[1], sizeof(XButtonEvent) ); return; /*--We have 2 events. The next event on this button should be a press. * Wait for the following release and then do the DblClick action(s). */ case 2 : if (event->type != ButtonPress) { (void)fprintf ( stderr, "RationalButton: EventCount==2 && Type!=Press [%d]?\n", event->type ); EventCount = 0; return; } XtRemoveTimeOut( EventTimer ); { XEvent ev; XAllowEvents( term->screen.display, AsyncPointer, event->time ); XIfEvent( term->screen.display, &ev, WaitForRelease, (char*)event ); } flags = ButtonFlags( &Events[0] ); if (flags & MvCsrOnDblClick) MvCsr( &Events[0], ++once ); if (flags & CmdOnDblClick) CmdOn( &Events[0], TRUE, ++once ); EventCount = 0; return; /*--We are confused. */ default : (void)fprintf( stderr, "RationalButton: EventCount == 3?\n"); EventCount = 0; return; } } } /*--Either we aren't waiting for a double-click or it didn't happen. Handle * this event by itself. If he's a Press then see if he is allowed to be * a double-click. If so then set him up to wait. If not then just do him.*/ flags= ButtonFlags( event ); if (event->type == ButtonPress) { if (flags & (CmdOnDblClick|MvCsrOnDblClick)) { EventCount = 1; bcopy( (char*)event, (char*)&Events[0], sizeof(XButtonEvent) ); EventTimer = XtAddTimeOut( (unsigned long)term->screen.multiClickTime, PlaybackEvents, (caddr_t)NULL ); return; } } DoEvent( flags, DoNothing, event ); }