home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
jove-4.16-src.tgz
/
tar.out
/
bsd
/
jove
/
xjove
/
xjove.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
22KB
|
776 lines
/*
* Copyright (C) 1986 Free Software Foundation, Inc.
* Copyright (C) 1991-1996 C.H.Lindsey, University of Manchester
*
* This file is derived from the program emacstool, which is itself part of the
* GNU Emacs system.
*
* In the same way as GNU Emacs itself, this file is distributed in the hope
* that it will be useful, but without any warranty. No author or
* distributor accepts responsibility to anyone for the consequences of using
* it or for whether it serves any particular purpose or works at all, unless
* he says so in writing.
*
* Everyone is granted permission to copy, modify and redistribute this file,
* but only under the conditions described in the document "GNU Emacs copying
* permission notice". A copy of that document is distributed along with
* GNU Emacs and other GNU Products so that you can know how you may
* redistribute it all. In particular and among other things, this copyright
* notice must be preserved on all copies of this file and of files derived
* from it.
*
*
* For Jove in SunView/Sun-Windows: (supported by Sun Unix v3.2) Insert a
* notifier filter-function to convert all useful input to "key" sequences
* that jove can understand. See: Xjove(1).
*
* Author (of Jovetool/Xjove): C. H. Lindsey, University of Manchester
* <chl@clw.cs.man.ac.uk>
* Author (of Emacstool): Jeff Peck, Sun Microsystems, Inc. <peck@sun.com>
*
* Original Idea: Ian Batten
*
*/
#include <xview/defaults.h>
#include <xview/xview.h>
#include <xview/tty.h>
#include <xview/ttysw.h> /* is this missing on some systems? */
#include <xview/termsw.h>
#include <xview/cursor.h>
#include <xview/font.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Sunkeysym.h> /* for Suns only */
#include <stdio.h>
#include <string.h>
#include <sys/file.h>
#include <stdlib.h>
#include <unistd.h> /* is this missing on some systems? */
#include <fcntl.h>
#include <termios.h>
#include "exts.h"
#include "mousemsg.h"
#define BUFFER_SIZE 256 /* Size of all the buffers */
#define CLICK 400 /* max time in ms for click, or gap between
* double click */
/* define WANT_CAPS_LOCK to make f-key T1 (aka F1) behave as CapsLock */
/* #define WANT_CAPS_LOCK */
private const char mouse_prefix[] = "\030m"; /* ^x m */
private const char key_prefix[] = "\033["; /* ESC-[ */
private char *jove_name = "jove"; /* default run command */
private char buffer[BUFFER_SIZE]; /* send to ttysw_input */
private const char title[] = "XJove - "; /* initial title */
private Frame frame; /* Base frame for system */
Tty ttysw; /* Where jove is */
private Tty ttyview;
private int font_width, font_height; /* For translating pixels to
* chars */
private int left_margin, right_margin;
private FILE *console = NULL; /* for debugging: setenv DEBUGJOVETOOL */
private Icon frame_icon;
/* make an icon_image */
private unsigned short default_image[] =
{
#include "jove.icon"
};
mpr_static_static(icon_image, 64, 64, 1, default_image);
private Xv_Cursor current_cursor, jove_cursor, cut_cursor, copy_cursor, paste_cursor, default_cursor;
private unsigned short cursor_image[] = {
#include "jove.cursor"
};
mpr_static_static(cursor_pix, 16, 16, 1, cursor_image);
private unsigned short cut_image[] = {
#include "cut.cursor"
};
mpr_static_static(cut_pix, 16, 16, 1, cut_image);
private unsigned short copy_image[] = {
#include "copy.cursor"
};
mpr_static_static(copy_pix, 16, 16, 1, copy_image);
private unsigned short paste_image[] = {
#include "paste.cursor"
};
mpr_static_static(paste_pix, 16, 16, 1, paste_image);
Xv_Font font;
private void
set_cursor(cursor)
Xv_Cursor cursor;
{
if (current_cursor != cursor) {
xv_set(ttyview, WIN_CURSOR, cursor, 0);
current_cursor = cursor;
}
}
/*
* button_value: encode mouse event into an xjove event code (the return
* value) and a button state (stored in last_but). If the event ought to be
* ignored due to error, -1 is returned in place of the event code. If it is
* to be ignored silently, -2 is returned.
*/
private int
last_but = JT_UPEVENT, /* button state */
event_shift, /* shift state */
next_kdb_event_should_be_up;
private char
last_event_string[7]; /* string from last F-key down event,
* 6 being the longest string
* expected from an F-key */
private int
button_value(event)
Event *event;
{
static struct timeval
mouse_time = {0, 0},
prev_mouse_time;
static int multiclick_state = 0;
int
this_but = event_shift, /* button state, after this
* event */
mouse_code; /* event code for this event */
switch (event_id(event)) {
case LOC_DRAG:
if (last_but & JT_UPEVENT)
return -1;
else if (multiclick_state)
return -2;
last_but |= JT_DRAGEVENT;
{
/*
* Generate event code for leftmost depressed button.
* Currently, only one bit will be on, so this is
* overkill.
*/
static short DragCode[8] = {
-1, JTEC_LEFT, JTEC_MIDDLE, JTEC_LEFT,
JTEC_RIGHT, JTEC_LEFT, JTEC_MIDDLE, JTEC_LEFT};
return DragCode[last_but & JT_BUTMASK] + JTEC_DRAG;
}
case MS_LEFT:
this_but |= JT_LEFT;
mouse_code = JTEC_LEFT;
break;
case MS_MIDDLE:
this_but |= JT_MIDDLE;
mouse_code = JTEC_MIDDLE;
break;
case MS_RIGHT:
this_but |= JT_RIGHT;
mouse_code = JTEC_RIGHT;
break;
default:
return -1;
}
/*
* Clicking too fast can sometimes beat the system. Also, a user
* might manage to get two buttons down at the same time. The
* following tests detect such situations. Note that up events after
* JT_RIGHT are absorbed by the menu software.
*/
if (event_is_up(event)) {
/* ignore up not following a down or up of a different button */
if ((last_but & (JT_UPEVENT | JT_RIGHT)) == JT_UPEVENT
|| ((last_but ^ this_but) & JT_BUTMASK) != 0)
return -1;
this_but |= JT_UPEVENT;
mouse_code += JTEC_UP;
} else if (event_is_down(event)) {
if ((last_but & (JT_UPEVENT | JT_RIGHT)) == 0) {
/* down event not preceded by an up or right event */
return -1;
}
} else { /* drag event */
if ((last_but & (JT_DOWNEVENT | JT_DRAGEVENT)) == 0) {
/* drag event not preceded by a down or drag event */
return -1;
}
}
/*
* The only way to get back into sync is to supply whatever up or
* down event it was waiting for. Thus jove should always see a
* consistent picture
*/
/*-- Detect and encode multi-clicks.
*
* - a multiclick is a train of alternating mouse-down and mouse-up events
* - the first must be a mouse-down
* - Each mouse up and down must be of the same button
* - each of which happens within CLICK milliseconds of its predecessor
* - Drags are not taken into consideration.
*/
prev_mouse_time = mouse_time;
mouse_time = event_time(event);
multiclick_state += 1;
if (((multiclick_state & 1) == 0) == ((this_but & JT_UPEVENT) == 0)
&& ((last_but ^ this_but) & JT_BUTMASK) == 0
&& (mouse_time.tv_sec - prev_mouse_time.tv_sec) * 1000
+ (mouse_time.tv_usec - prev_mouse_time.tv_usec) / 1000 <= CLICK) {
switch (multiclick_state) {
case 1: /* first up */
break;
case 2: /* second down */
mouse_code += JTEC_CLICK2;
/* FALLTHROUGH */
case 3: /* second up */
this_but |= JT_CLICK2;
break;
case 4: /* third down */
mouse_code += JTEC_CLICK3;
/* FALLTHROUGH */
case 5: /* third up */
this_but |= JT_CLICK3;
break;
default: /* too many multi-clicks */
multiclick_state = 0;
break;
}
} else {
multiclick_state = 0;
}
last_but = this_but;
return mouse_code;
}
/*
* Filter function to translate selected input events for jove Mouse button
* events become ^XmC(button-state x-col y-line font-width) . - C is an
* eventcode (explained in mousemsg.h) - button-state is as described
* mousemsg.h for this_but - x-col is horizontal column, in pixels (for
* smooth scrollbar working) - y-col is height, in characters - font-width
* allows conversion of x-col to characters Sun function keys (left, top, and
* right) are converted to the ANSI sequence ESC [ P z, where P is a number
* above 192
*/
private Notify_value
input_event_filter_function(window, event, arg, type)
Xv_Window window;
Event *event;
Notify_arg arg;
Notify_event_type type;
{
int id = event_id(event);
int mouse_code = -3; /* not -1 and not -2 and not
* >=0 */
int fkey;
event_shift &= ~JT_CSMASK;
if (event_shift_is_down(event))
event_shift |= JT_SHIFT;
if (event_ctrl_is_down(event))
event_shift |= JT_CONTROL;
/*
* Under Xview (but not SunView) the answers to the above queries do
* not reflect the effect of the current event!
*/
{
int delta = 0;
switch (event_action(event)) {
case SHIFT_LEFT:
case SHIFT_RIGHT:
delta = JT_SHIFT;
break;
case SHIFT_CTRL:
delta = JT_CONTROL;
break;
case ACTION_PASTE:
delta = JT_PASTE;
break;
case ACTION_CUT:
delta = JT_CUT;
break;
}
if (event_is_up(event))
event_shift &= ~delta;
else
event_shift |= delta;
}
if (console != NULL) {
fprintf(console, "Ttyview Event %d", id);
if (event_shift != 0)
fprintf(console, "; shift %d", event_shift);
if (event_is_up(event))
fprintf(console, "; up");
if (event_is_button(event))
fprintf(console, "; button %d", id - BUT(0));
fprintf(console, "\n");
}
switch (id) {
case LOC_DRAG:
mouse_code = button_value(event);
/* no need to set cursor */
break;
case MS_LEFT:
case MS_MIDDLE:
case MS_RIGHT:
mouse_code = button_value(event);
if (last_but & JT_PASTEMASK)
last_event_string[0] = 0;
/*
* We do not wish to see Left keys (esp. PASTE & CUT)
* associated with buttons
*/
/* FALLTHROUGH */
case SHIFT_LEFT:
case SHIFT_RIGHT:
case SHIFT_CTRL:
/* set cursor appropriately */
if (event_shift == JT_SHIFT) {
set_cursor(default_cursor);
} else {
switch (event_shift | (last_but & (JT_UPEVENT | JT_BUTMASK))) {
case JT_SHIFT | JT_CONTROL | JT_MIDDLE:
set_cursor(cut_cursor);
break;
case JT_CONTROL | JT_MIDDLE:
set_cursor(copy_cursor);
break;
case JT_CONTROL | JT_LEFT:
set_cursor(paste_cursor);
break;
default:
set_cursor(jove_cursor);
break;
}
}
break;
case KEY_LEFT(5): /* EXPOSE or FRONT key */
case KEY_LEFT(7): /* OPEN key */
/*
* UP L5 & L7 are Expose & Open, let them pass to SunView.
* Apparently it only cares about up events. Actually, the
* down event never gets this far, but the up event seems to
* be needed to force a refresh.
*/
return event_is_up(event)
? notify_next_event_func(window, (Notify_event) event, arg, type)
: NOTIFY_IGNORED;
}
/* Treat shifted events as normal Shelltool events. */
if (event_shift == JT_SHIFT && id >= ISO_LAST) {
Notify_value result;
/* Translate well-known left keys. */
switch (id) {
case KEY_LEFT(6):
event->action = ACTION_COPY;
break;
case KEY_LEFT(8):
event->action = ACTION_PASTE;
break;
case KEY_LEFT(10):
event->action = ACTION_COPY; /* CUT is censored */
break;
}
event_shiftmask(event) &= ~SHIFTMASK; /* get rid of shift */
event_set_string(event, NULL); /* later versions of xview
* seem to output this string
* even when they have already
* interpreted the event as a
* copy/paste/cut
*/
result = notify_next_event_func(window, (Notify_event) event, arg, type);
return result;
}
/* do Mouse Button events */
if (mouse_code >= 0) {
int
this_x = event_x(event) - left_margin, this_y = event_y(event) / font_height;
static int last_x, last_y;
if (last_but & JT_RIGHT) {
/*
* ??? avoid passing up-event, if we catch it --
* would cause deadlock.
*/
if (last_but == JT_RIGHT)
menu_show(main_menu, window, event, 0);
} else {
if (this_x == last_x && this_y == last_y) {
if (id == LOC_DRAG)
return NOTIFY_IGNORED;
sprintf(buffer, "%s%d(%d)\015",
mouse_prefix, mouse_code, last_but);
} else {
sprintf(buffer, "%s%d(%d %d %d %d)\015",
mouse_prefix, mouse_code, last_but,
this_x, this_y, font_width);
last_x = this_x;
last_y = this_y;
}
ttysw_input(ttysw, buffer, strlen(buffer));
}
return NOTIFY_IGNORED;
} else if (mouse_code == -1) {
ttysw_output(ttysw, "\007", 1); /* beep */
return NOTIFY_IGNORED;
} else if (mouse_code == -2) {
return NOTIFY_IGNORED;
}
if (next_kdb_event_should_be_up && event_is_down(event)
&& event_is_iso(event)) {
ttysw_output(ttysw, "\007", 1); /* beep */
return NOTIFY_IGNORED;
}
next_kdb_event_should_be_up = 0;
if (event_is_string(event) /* it has been rebound with
* XRebindKeysym */
||event_is_key_left(event)) { /* For some reason, up events
* of PASTE and CUT do not
* appear as string events,
* but they must be caught
* here */
if (event_is_down(event)) {
if (event_is_string(event)) {
strcpy(last_event_string, event_string(event));
/*
* because XView does not seem to provide
* these strings on the up event
*/
} else {
last_event_string[0] = '\0';
/*
* Sometimes, even the down event of PASTE is
* not a string, as when Caps Lock is down.
* Forget it!
*/
}
}
if (!event_button_is_down(event)) {
/*
* we don't want any function keys (esp PASTE & CUT)
* seen when a button is down
*/
if (event_action(event) == ACTION_PASTE
|| event_action(event) == ACTION_CUT) {
if (event_is_down(event)) {
/*
* we see PASTE and CUT when they
* come up
*/
next_kdb_event_should_be_up = 1;
return NOTIFY_IGNORED;
}
} else if (event_is_up(event)) {
/* we see other F-keys when they go down */
return NOTIFY_IGNORED;
}
ttysw_input(ttysw, last_event_string, strlen(last_event_string));
}
return NOTIFY_IGNORED;
}
if (ISO_FIRST <= id && id <= ISO_LAST) {
/*
* Force bit 8 if meta key is down. But it will only be
* noticed by the controlled process if it does a stty
* -istrip, or equivalent.
*/
if (event_shiftmask(event) & META_SHIFT_MASK)
event->ie_code |= META_KEY_MASK;
}
/* If we get here, pass event off to next handler */
return notify_next_event_func(window, (Notify_event) event, arg, type);
}
private Notify_value
tty_event_filter_function(window, event, arg, type)
Xv_Window window;
Event *event;
Notify_arg arg;
Notify_event_type type;
{
if (console != NULL)
fprintf(console, "Ttysw Event: %d\n", event_id(event));
if (event_id(event) == KBD_USE) {
win_set_kbd_focus(ttyview, xv_get(ttyview, XV_XID));
return NOTIFY_IGNORED;
} else {
return notify_next_event_func(window, (Notify_event) event, arg, type);
}
}
void
bind_key(ksym, string)
KeySym ksym;
char *string;
{
Display *dpy;
static KeySym shift_list[] =
{XK_Shift_L, XK_Control_L, XK_Meta_L, XK_Alt_L, XK_Mode_switch};
int i;
dpy = (Display *) xv_get(frame, XV_DISPLAY);
XRebindKeysym(dpy, ksym, NULL, 0, (unsigned char *) string, strlen(string));
for (i = 0; i != sizeof(shift_list) / sizeof(*shift_list); i++)
XRebindKeysym(dpy, ksym, &shift_list[i], 1, (unsigned char *) string, strlen(string));
}
void
bind_function_keys(first, count, number)
KeySym first;
unsigned int count, number;
{
int i;
char buffer[6];
for (i = 0; i < count; i++) {
sprintf(buffer, "%s%3dz", key_prefix, number + i);
bind_key(first + i, buffer);
}
}
int
main(argc, argv)
int argc;
char **argv;
{
int error_code; /* Error codes */
int forking;
int argstart = 1;
char *debug;
int child_argc, i;
char **child_argv;
char *icon_label;
int tty_fd;
struct termios tty;
xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, 0);
if ((debug = getenv("DEBUGJOVETOOL")) != NULL) {
/*
* DEBUGJOVETOOL specifies the file or device to receive
* debugging output, if any. The null name signifies stderr.
*/
console = *debug == '\0' ? stderr : fopen(debug, "w");
forking = 0;
} else if (!isatty(0)) {
forking = 0;
} else {
forking = defaults_get_boolean("xjove.forking", "Xjove.Forking", 0);
}
if (argc>1 && !strcmp("-nf", argv[1])) {
forking = 0;
argstart = 2;
} else if (argc>1 && !strcmp("-f", argv[1])) {
forking = 1;
argstart = 2;
}
if (forking) {
switch (fork()) {
case -1:
fprintf(stderr, "fork failed");
exit(1);
/* NOTREACHED */
case 0: /* the child */
#ifdef SYSVR4
setsid(); /* so it doesn't get killed when
* parent dies */
#else
setpgid(0, 0); /* For some reason, setsid() hinders
* passing of SIGWINCH events to the
* controlled process in SUNOS4 */
#endif
break;
default: /* the parent */
exit(0);
/* NOTREACHED */
}
}
putenv("IN_JOVETOOL=t");/* notify subprocess that it is in jovetool */
font = (Xv_font) xv_find(ttysw, FONT, FONT_NAME,
defaults_get_string("font.name", "Font.Name", "lucidasanstypewriter-12"),
0);
child_argv = (char **) malloc((argc + 1) * sizeof(char *));
if (!(child_argv[0] = (char *) getenv("JOVETOOL"))) /* Set jove command name */
child_argv[0] = jove_name;
for (child_argc = 1, i = argstart; i < argc; i++) {
if (!strcmp("-rc", argv[i])) {
child_argv[0] = argv[++i];
child_argc = 1;
} else {
child_argv[child_argc++] = argv[i];
}
}
child_argv[child_argc] = NULL;
/*
* choose a "sensible" parameter to put in the icon label, preferably
* the file to be edited
*/
icon_label = child_argv[0];
for (i = 1; i < child_argc; i++)
if (child_argv[i][0] != '-')
icon_label = child_argv[i];
frame_icon = icon_create(XV_LABEL, icon_label,
ICON_IMAGE, &icon_image,
0);
/* construct the title of the window */
strcpy(buffer, title);
strncat(buffer, child_argv[0], /* append run command name */
(BUFFER_SIZE - (strlen(buffer)) - (strlen(argv[0]))) - 1);
/* Build a frame to run in */
frame = xv_create(XV_NULL, FRAME,
XV_LABEL, buffer,
FRAME_ICON, frame_icon,
0);
/* construct the command parameters to be shown to Save Workspace */
buffer[0] = '\0';
for (i = 1; i < argc; i++)
sprintf(&buffer[strlen(buffer)], "%s ", argv[i]);
xv_set(frame, WIN_CMD_LINE, buffer, 0);
/* Create a tty with jove in it */
ttysw = xv_create(frame, TERMSW,
TTY_ARGV, TTY_ARGV_DO_NOT_FORK,
XV_LEFT_MARGIN, defaults_get_integer(
"text.margin.left", "Text.Margin.Left", 4),
XV_RIGHT_MARGIN, defaults_get_integer(
"text.margin.right", "Text.Margin.Right", 0),
/* 0 because jove never uses the last column anyway */
TEXTSW_FONT, font,
0);
ttyview = xv_get(ttysw, OPENWIN_NTH_VIEW, 0);
left_margin = xv_get(ttysw, XV_LEFT_MARGIN);
right_margin = xv_get(ttysw, XV_RIGHT_MARGIN);
font_height = (int) xv_get(ttysw, WIN_ROW_HEIGHT);
font_width = (int) xv_get(ttysw, WIN_COLUMN_WIDTH);
tty_fd = (int) xv_get(ttysw, TTY_TTY_FD);
tcgetattr(tty_fd, &tty);
tty.c_iflag &= ~ISTRIP;
tcsetattr(tty_fd, TCSANOW, &tty);
/* "TTY_ARGV, child_argv" must not be set going before that tcsetattr */
xv_set(ttysw, TERMSW_MODE, TTYSW_MODE_TYPE,
TTY_QUIT_ON_CHILD_DEATH, TRUE,
TTY_ARGV, child_argv,
OPENWIN_ADJUST_FOR_VERTICAL_SCROLLBAR, 0,
XV_WIDTH, defaults_get_integer(
"window.columns", "Window.Columns", 80) * font_width
+ left_margin + right_margin + 2,
/*
* WIN_COLUMNS was not used here because it gets confused by the
* non-existent scrollbar; the '+ 2' is one pixel for each border
*/
WIN_ROWS, defaults_get_integer(
"window.rows", "Window.Rows", 35),
0);
xv_set(ttyview,
WIN_CONSUME_EVENTS,
WIN_ASCII_EVENTS, WIN_META_EVENTS,
WIN_MOUSE_BUTTONS, WIN_UP_EVENTS,
LOC_DRAG,
SHIFT_LEFT, SHIFT_RIGHT, SHIFT_CTRL, SHIFT_META,
WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS,
0,
WIN_COLLAPSE_EXPOSURES, FALSE,
0);
default_cursor = xv_get(ttyview, WIN_CURSOR);
jove_cursor = xv_create(XV_NULL, CURSOR,
CURSOR_IMAGE, &cursor_pix,
CURSOR_XHOT, 8,
CURSOR_YHOT, 8,
0);
cut_cursor = xv_create(XV_NULL, CURSOR,
CURSOR_IMAGE, &cut_pix,
CURSOR_XHOT, 8,
CURSOR_YHOT, 8,
0);
copy_cursor = xv_create(XV_NULL, CURSOR,
CURSOR_IMAGE, ©_pix,
CURSOR_XHOT, 8,
CURSOR_YHOT, 8,
0);
paste_cursor = xv_create(XV_NULL, CURSOR,
CURSOR_IMAGE, &paste_pix,
CURSOR_XHOT, 8,
CURSOR_YHOT, 8,
0);
set_cursor(jove_cursor);
/* Interpose my event function */
error_code =
(int) notify_interpose_event_func
(ttyview, input_event_filter_function, NOTIFY_SAFE) +
(int) notify_interpose_event_func
(ttysw, tty_event_filter_function, NOTIFY_SAFE);
if (error_code != 0) { /* Barf */
fprintf(stderr, "notify_interpose_event_func got %d.\n", error_code);
exit(1);
}
menu_init();
bind_function_keys((KeySym)XK_L1, 10, 192);
bind_function_keys((KeySym)XK_Help, 1, 202);
bind_function_keys((KeySym)XK_F1, 10, 224);
#ifdef SunXK_F36
bind_function_keys((KeySym)SunXK_F36, 2, 234); /* for Suns only */
#endif
bind_function_keys((KeySym)XK_R1, 15, 208);
/*
* But note that the keys R7-R15 are intercepted by XView which
* imposes its own bindings
*/
bind_function_keys((KeySym)XK_Insert, 1, 247);
bind_function_keys((KeySym)XK_KP_0, 1, 247);
bind_function_keys((KeySym)XK_KP_Decimal, 1, 249);
bind_function_keys((KeySym)XK_KP_Enter, 1, 250);
bind_function_keys((KeySym)XK_KP_Add, 1, 253);
bind_function_keys((KeySym)XK_KP_Subtract, 1, 254);
window_fit(frame);
window_main_loop(frame);/* And away we go */
return 0; /* if this is ever reached */
}