|
|
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 - metrics - 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⟧
└─⟦144d629ab⟧
└─⟦this⟧ »./button.c«
└─⟦5f3412b64⟧ Bits:30000745 8mm tape, Rational 1000, ENVIRONMENT 12_6_5 TOOLS
└─⟦91c658230⟧ »DATA«
└─⟦5d656759a⟧
└─⟦5cb9d2efd⟧
└─⟦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 */
#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>
#ifdef ultrix
#include <malloc.h>
#else
extern char *malloc();
#endif
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 );
}