|
|
1.1 root 1: /* Copyright (C) 1986, 1988, 1990, 1991 Free Software Foundation, Inc.
2:
3: This file is part of GNU Emacs.
4:
5: GNU Emacs is free software; you can redistribute it and/or modify
6: it under the terms of the GNU General Public License as published by
7: the Free Software Foundation; either version 1, or (at your option)
8: any later version.
9:
10: GNU Emacs is distributed in the hope that it will be useful,
11: but WITHOUT ANY WARRANTY; without even the implied warranty of
12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: GNU General Public License for more details.
14:
15: You should have received a copy of the GNU General Public License
16: along with GNU Emacs; see the file COPYING. If not, write to
17: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
18:
19: /* For Emacs in SunView/Sun-Windows: (supported by Sun Unix v3.2 or greater)
20: * Insert a notifier filter-function to convert all useful input
21: * to "key" sequences that emacs can understand. See: Emacstool(1).
22: *
23: * Author: Jeff Peck, Sun Microsystems, Inc. <[email protected]>
24: *
25: * Original Idea: Ian Batten
26: * Updated 15-Mar-88, Jeff Peck: set IN_EMACSTOOL, TERM, TERMCAP
27: * Updated 10-Sep-88, Jeff Peck: add XVIEW and JLE support
28: * Updated 8-Oct-90, Jeff Peck: add Meta-bit for Xview
29: * Updated 6-Mar-91, Jeff Peck: Hack to detect -Wt invocation
30: * [note, TTYSW limitation means you must Click-To-Type in Openwin]
31: * [fixed in OW3 or use local/tty.o]
32: * for better results, this should move to using TERMSW.
33: * Updated 30-Mar-91, Jeff Peck, et al: Enable using TERMSW (-DTTERM)
34: * TERMSW understands point-to-type, even in OW2.
35: * Updated 5-Jun-91, Jeff Peck: Meta-key support fixed for OWv3
36: * Better event diagnostics for DEBUGEMACSTOOL
37: *
38: * [note: xvetool should be started with the "-nw" flag for emacs!]
39: */
40:
41: #ifdef XVIEW
42: #include <xview/xview.h>
43: #include <xview/panel.h>
44: #include <xview/attr.h>
45: #include <xview/tty.h>
46: #include <xview/ttysw.h> /* private defines */
47: #include <xview/termsw.h> /* -DTTERM */
48: #include <xview/font.h> /* for testing */
49: #else
50: #include <suntool/sunview.h>
51: #include <suntool/tty.h>
52: #include <suntool/ttysw.h>
53: #endif /* XVIEW */
54:
55: #ifdef JLE
56: # include <locale.h>
57: #endif /* JLE */
58:
59: #include <stdio.h>
60: #include <sys/file.h>
61:
62: #define BUFFER_SIZE 128 /* Size of all the buffers */
63:
64: /* define WANT_CAPS_LOCK to make f-key T1 (aka F1) behave as CapsLock */
65: #define WANT_CAPS_LOCK
66: #ifdef WANT_CAPS_LOCK
67: int caps_lock; /* toggle indicater for f-key T1 caps lock */
68: static char *Caps = "[CAPS] "; /* Caps Lock prefix string */
69: #define CAPS_LEN 7 /* strlen (Caps) */
70: #endif
71:
72: static char *mouse_prefix = "\030\000"; /* C-x C-@ */
73: static int m_prefix_length = 2; /* mouse_prefix length */
74:
75: static char *key_prefix = "\030*"; /* C-x * */
76: static int k_prefix_length = 2; /* key_prefix length */
77:
78: #ifdef JLE
79: static char *emacs_name = "nemacs"; /* default run command */
80: static char *title = "NEmacstool - "; /* initial title */
81: #else
82: static char *emacs_name = "emacs"; /* default run command */
83: static char *title = "Emacstool - "; /* initial title */
84: #endif /* JLE */
85:
86: static char buffer[BUFFER_SIZE]; /* send to ttysw_input */
87: static char *bold_name = 0; /* for -bold option */
88:
89: Frame frame; /* Base frame for system */
90:
91: #ifndef TTERM
92: #define SWTYPE TTY
93: Tty tty_win; /* Where emacs is reading */
94: #else
95: #define SWTYPE TERMSW
96: Termsw tty_win; /* Termsw does follow-mouse */
97: #endif /* TTERM */
98:
99: #ifdef XVIEW
100: Xv_Window tty_view; /* Where the events are in Xview*/
101: #else
102: Tty tty_view; /* SunView place filler */
103: #endif /* XVIEW */
104:
105: int font_width, font_height; /* For translating pixels to chars */
106: int left_margin = 0; /* default window -- frame offset */
107:
108: int console_fd = 0; /* for debugging: setenv DEBUGEMACSTOOL */
109: FILE *console; /* for debugging: setenv DEBUGEMACSTOOL */
110:
111: Icon frame_icon;
112: /* make an icon_image for the default frame_icon */
113: static short default_image[258] =
114: {
115: #include <images/terminal.icon>
116: };
117: mpr_static(icon_image, 64, 64, 1, default_image);
118:
119: /*
120: * Assign a value to a set of keys
121: */
122: int
123: button_value (event)
124: Event *event;
125: {
126: int retval = 0;
127: /*
128: * Code up the current situation:
129: *
130: * 1 = MS_LEFT;
131: * 2 = MS_MIDDLE;
132: * 4 = MS_RIGHT;
133: * 8 = SHIFT;
134: * 16 = CONTROL;
135: * 32 = META;
136: * 64 = DOUBLE;
137: * 128 = UP;
138: */
139:
140: if (MS_LEFT == (event_id (event))) retval = 1;
141: if (MS_MIDDLE == (event_id (event))) retval = 2;
142: if (MS_RIGHT == (event_id (event))) retval = 4;
143:
144: if (event_shift_is_down (event)) retval += 8;
145: if (event_ctrl_is_down (event)) retval += 16;
146: if (event_meta_is_down (event)) retval += 32;
147: if (event_is_up (event)) retval += 128;
148: return retval;
149: }
150:
151: /*
152: * Variables to store the time of the previous mouse event that was
153: * sent to emacs.
154: *
155: * The theory is that to time double clicks while ignoreing UP buttons,
156: * we must keep track of the accumulated time.
157: *
158: * If someone writes a SUN-SET-INPUT-MASK for emacstool,
159: * That could be used to selectively disable UP events,
160: * and then this cruft wouldn't be necessary.
161: */
162: static long prev_event_sec = 0;
163: static long prev_event_usec = 0;
164:
165: /*
166: * Give the time difference in milliseconds, where one second
167: * is considered infinite.
168: */
169: int
170: time_delta (now_sec, now_usec, prev_sec, prev_usec)
171: long now_sec, now_usec, prev_sec, prev_usec;
172: {
173: long sec_delta = now_sec - prev_sec;
174: long usec_delta = now_usec - prev_usec;
175:
176: if (usec_delta < 0) { /* "borrow" a second */
177: usec_delta += 1000000;
178: --sec_delta;
179: }
180:
181: if (sec_delta >= 10)
182: return (9999); /* Infinity */
183: else
184: return ((sec_delta * 1000) + (usec_delta / 1000));
185: }
186:
187:
188: /*
189: * Filter function to translate selected input events for emacs
190: * Mouse button events become ^X^@(button x-col y-line time-delta) .
191: * Function keys: ESC-*{c}{lrt} l,r,t for Left, Right, Top;
192: * {c} encodes the keynumber as a character [a-o]
193: */
194: static Notify_value
195: input_event_filter_function (window, event, arg, type)
196: #ifdef XVIEW
197: Xv_Window window;
198: #else /* not XVIEW */
199: Window window;
200: #endif /* XVIEW */
201: Event *event;
202: Notify_arg arg;
203: Notify_event_type type;
204: {
205: struct timeval time_stamp;
206:
207: /* if DEBUGEMACSTOOL is set, printout event information */
208: if (console_fd) {
209: fprintf(console, "Event: %s%s%c %d %d\n",
210: (event_ctrl_is_down(event) ? "C-" : " "),
211: (event_meta_is_down(event) ? "M-" : " "),
212: (((event_is_button (event)) ? 'M' :
213: ((event_is_key_left (event)) ? 'L' :
214: ((event_is_key_right (event)) ? 'R' :
215: ((event_is_key_top (event)) ? 'T' :
216: (((ASCII_FIRST <= event_id(event))
217: && (event_id(event) <= ASCII_LAST)) ?
218: (((127 & event_id(event)) < 32) ?
219: ((127 & event_id(event)) + 64) :
220: ((127 & event_id(event)))) : '?')))))),
221: event_id(event),
222: event_action(event));
223: }
224: /* UP L1 is the STOP key */
225: if (event_id(event) == WIN_STOP) {
226: ttysw_input(tty_win, "\007\007\007\007\007\007\007", 7);
227: return NOTIFY_IGNORED;
228: }
229:
230: /* UP L5 & L7 is Expose & Open, let them pass to sunview */
231: if (event_id(event) == KEY_LEFT(5) || event_id(event) == KEY_LEFT(7))
232: if (event_is_up (event))
233: return notify_next_event_func (window, event, arg, type);
234: else
235: return NOTIFY_IGNORED;
236:
237:
238: { /* Do the mouse == button events */
239: if (event_is_button (event)) { /* do Mouse Button events */
240: time_stamp = event_time (event);
241: ttysw_input (tty_win, mouse_prefix, m_prefix_length);
242: sprintf (buffer, "(%d %d %d %d)\015",
243: button_value (event),
244: (event_x (event) - left_margin) / font_width,
245: event_y (event) / font_height,
246: time_delta (time_stamp.tv_sec, time_stamp.tv_usec,
247: prev_event_sec, prev_event_usec)
248: );
249: ttysw_input (tty_win, buffer, strlen(buffer));
250: prev_event_sec = time_stamp.tv_sec;
251: prev_event_usec = time_stamp.tv_usec;
252: return NOTIFY_IGNORED;
253: }
254: }
255: { /* Do the function key events */
256: int d;
257: char c = (char) 0;
258: if ((event_is_key_left (event)) ?
259: ((d = event_id(event) - KEY_LEFT(1) + 'a'), c='l') :
260: ((event_is_key_right (event)) ?
261: ((d = event_id(event) - KEY_RIGHT(1) + 'a'), c='r') :
262: ((event_is_key_top (event)) ?
263: ((d = event_id(event) - KEY_TOP(1) + 'a'), c='t') : 0))) {
264: if (event_is_up(event)) return NOTIFY_IGNORED;
265: if (event_shift_is_down (event)) c = c - 32;
266: /* this will give a non-{lrt} for unshifted keys */
267: if (event_ctrl_is_down (event)) c = c - 64;
268: if (event_meta_is_down (event)) c = c + 128;
269: #ifdef WANT_CAPS_LOCK
270: /* set a toggle and relabel window so T1 can act like caps-lock */
271: if (event_id(event) == KEY_TOP(1)) {
272: /* make a frame label with and without CAPS */
273: strcpy (buffer, Caps);
274: title = &buffer[CAPS_LEN];
275: strncpy (title, (char *)window_get (frame, FRAME_LABEL),
276: BUFFER_SIZE - CAPS_LEN);
277: buffer[BUFFER_SIZE] = (char) 0;
278: if (strncmp (title, Caps, CAPS_LEN) == 0)
279: title += CAPS_LEN; /* already Caps */
280: caps_lock = (caps_lock ? 0 : CAPS_LEN);
281: window_set(frame, FRAME_LABEL, (title -= caps_lock), 0);
282: return NOTIFY_IGNORED;
283: }
284: #endif /* WANT_CAPS_LOCK */
285: ttysw_input (tty_win, key_prefix, k_prefix_length);
286: sprintf (buffer, "%c%c", d, c);
287: ttysw_input(tty_win, buffer, strlen(buffer));
288:
289: return NOTIFY_IGNORED;
290: }
291: }
292:
293: /* handle ascii keyboard events
294: * extract "event_is_ascii(event)" from the event_id, not the event_action
295: */
296: if ((ASCII_FIRST <= event_id(event)) && (event_id(event) <= ASCII_LAST)) {
297: /* ignore key-up events (button events have already been handled) */
298: if (event_is_up(event)) return NOTIFY_IGNORED;
299: #ifdef WANT_CAPS_LOCK
300: /* shift alpha chars to upper case if toggle is set */
301: if ((caps_lock) && (event_id(event) >= 'a') && (event_id(event) <= 'z'))
302: event_set_id(event, (event_id(event) - 32));
303: #endif /* WANT_CAPS_LOCK */
304:
305: #ifndef NO_META_BIT
306: /* under Openwindows/X, the meta bit is not set in the key event,
307: * emacs expects this so we add it in here:
308: */
309: if (event_meta_is_down(event))
310: event_set_id(event, 128 | event_id(event));
311: #endif /* NO_META_BIT */
312: }
313: return notify_next_event_func (window, event, arg, type);
314: }
315:
316: main (argc, argv)
317: int argc;
318: char **argv;
319: {
320: int error_code; /* Error codes */
321:
322: #ifdef JLE
323: setlocale(LC_ALL, "");
324: #endif /* JLE */
325:
326: if(getenv("DEBUGEMACSTOOL"))
327: console = fdopen (console_fd = open("/dev/console",O_WRONLY), "w");
328:
329: putenv("IN_EMACSTOOL=t"); /* notify subprocess that it is in emacstool */
330:
331: if (putenv("TERM=sun") != 0) /* TTY_WIN will be a TERM=sun window */
332: {fprintf (stderr, "%s: Could not set TERM=sun, using `%s'\n",
333: argv[0], (char *)getenv("TERM")) ;};
334: /*
335: * If TERMCAP starts with a slash, it is the pathname of the
336: * termcap file, not an entry extracted from it, so KEEP it!
337: * Otherwise, it may not relate to the new TERM, so Nuke-It.
338: * If there is no TERMCAP environment variable, don't make one.
339: */
340: {
341: char *termcap ; /* Current TERMCAP value */
342: termcap = (char *)getenv("TERMCAP") ;
343: if (termcap && (*termcap != '/'))
344: {
345: if (putenv("TERMCAP=") != 0)
346: {fprintf (stderr, "%s: Could not clear TERMCAP\n", argv[0]) ;} ;
347: } ;
348: } ;
349:
350: /* find command to run as subprocess in window */
351: if (!(argv[0] = (char *)getenv("EMACSTOOL"))) /* Set emacs command name */
352: argv[0] = emacs_name;
353: /* Emacstool recognizes two special args: -rc <file> and -bold <bold-name> */
354: for (argc = 1; argv[argc]; argc++) /* Use last one on line */
355: {
356: if(!(strcmp ("-rc", argv[argc]))) /* Override if -rc given */
357: {int i = argc;
358: argv[argc--]=0; /* kill the -rc argument */
359: if (argv[i+1]) { /* move to argv[0] and squeeze the rest */
360: argv[0]=argv[i+1];
361: for (; argv[i+2]; (argv[i]=argv[i+2],argv[++i]=0));
362: }
363: }
364:
365: if (!(strcmp ("-bold", argv[argc])))
366: {int i = argc;
367: argv[argc--]=0; /* kill the -bold argument */
368: if (argv[i+1]) { /* move to bold_name and squeeze the rest */
369: bold_name = argv[i+1];
370: for (; argv[i+2]; (argv[i]=argv[i+2],argv[++i]=0));
371: }
372: }
373: };
374:
375: strcpy (buffer, title);
376: strncat (buffer, argv[0], /* append run command name */
377: (BUFFER_SIZE - (strlen (buffer)) - (strlen (argv[0]))) - 1);
378:
379: error_code = interpose_on_window(argc,argv);
380: if (error_code != 0) { /* Barf */
381: fprintf (stderr, "notify_interpose_event_func returns %d.\n", error_code);
382: exit (1);
383: }
384:
385: #ifdef XVIEW
386: xv_main_loop (frame); /* And away we go */
387: #else
388: window_main_loop (frame);
389: #endif /* XVIEW */
390: }
391:
392: #ifdef XVIEW
393: int interpose_on_window(argc,argv)
394: int argc;
395: char **argv;
396: {
397: #ifndef TTERM
398: #ifdef FONT_WIDTH_ADJUST
399: int i, font_width_adjust = 1; /* hackery, and hueristics */
400: /* If -Wt is not supplied, OWv2 font defaults as lucidasans-12 (width=8)
401: * rather than the lucidasanstypewriter (width=7) actually used by ttysw.
402: * This hack attempts to workaround it.
403: */
404: for (i = 1; argv[i]; i++) {
405: if (!(strcmp ("-Wt", argv[i])) || !(strcmp ("-font", argv[i])))
406: {font_width_adjust = 0;
407: if (console_fd) fprintf(console, "-Wt = %d\n", font_width_adjust);
408: break;}
409: }
410: #endif /* FONT_WIDTH_ADJUST */
411: #endif /* not TTERM */
412: /* initialize Xview, and strip window args */
413: xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, 0);
414:
415: /* do this first, so arglist can override it */
416: frame_icon = icon_create (ICON_LABEL, "Emacstool",
417: ICON_IMAGE, &icon_image,
418: 0);
419:
420: /* Build a frame to run in */
421: frame = xv_create ((Xv_Window)NULL, FRAME,
422: FRAME_LABEL, buffer,
423: FRAME_ICON, frame_icon,
424: 0);
425:
426: /* Create a tty with emacs in it */
427: tty_win = xv_create (frame, SWTYPE, WIN_IS_CLIENT_PANE,
428: TTY_QUIT_ON_CHILD_DEATH, TRUE,
429: TTY_BOLDSTYLE, TTYSW_BOLD_INVERT,
430: TTY_ARGV, argv,
431: 0);
432:
433: if (bold_name) {
434: (void)xv_set(tty_win, TTY_BOLDSTYLE_NAME, bold_name, 0);
435: }
436:
437: {
438: Xv_font font; /* declare temp font variable */
439: font = (Xv_font)xv_get (tty_win, XV_FONT);
440: font_height = (int)xv_get (font, FONT_DEFAULT_CHAR_HEIGHT);
441: font_width = (int)xv_get (font, FONT_DEFAULT_CHAR_WIDTH);
442: }
443: if (console_fd) fprintf(console, "Width = %d\n", font_width);
444:
445: #ifndef TTERM
446: #ifdef FONT_WIDTH_ADJUST
447: font_width -= font_width_adjust; /* A guess! font cache bug in ttysw*/
448: #endif /* FONT_WIDTH_ADJUST */
449: #else
450: /* make the termsw act as a tty */
451: xv_set(tty_win, TERMSW_MODE, TTYSW_MODE_TYPE, 0);
452: /* termsw has variable offset depending on scrollbar size/location */
453: left_margin = (int)xv_get (tty_win, TEXTSW_LEFT_MARGIN);
454: #endif /* TTERM */
455:
456: tty_view = (Xv_Window) xv_get (tty_win, OPENWIN_NTH_VIEW, 0);
457: xv_set(tty_view,
458: WIN_CONSUME_EVENTS,
459: WIN_MOUSE_BUTTONS, WIN_UP_EVENTS,
460: ACTION_ADJUST, ACTION_MENU,
461: WIN_ASCII_EVENTS,
462: WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS,
463: 0,
464: 0);
465: /* Interpose my event function */
466: return (int) notify_interpose_event_func
467: (tty_view, input_event_filter_function, NOTIFY_SAFE);
468: }
469: #else /* not XVIEW */
470: int interpose_on_window (argc, argv)
471: int argc;
472: char **argv;
473: {
474: /* do this first, so arglist can override it */
475: frame_icon = icon_create (ICON_LABEL, "Emacstool",
476: ICON_IMAGE, &icon_image,
477: 0);
478:
479: /* Build a frame to run in */
480: frame = window_create ((Window)NULL, FRAME,
481: FRAME_LABEL, buffer,
482: FRAME_ICON, frame_icon,
483: FRAME_ARGC_PTR_ARGV, &argc, argv,
484: 0);
485:
486: /* Create a tty with emacs in it */
487: tty_win = window_create (frame, TTY,
488: TTY_QUIT_ON_CHILD_DEATH, TRUE,
489: TTY_BOLDSTYLE, TTYSW_BOLD_INVERT,
490: TTY_ARGV, argv,
491: 0);
492:
493: if (bold_name) {
494: (void)window_set(tty_win, TTY_BOLDSTYLE_NAME, bold_name, 0);
495: }
496:
497: /* ttysw uses pf_default, one must set WIN_FONT explicitly */
498: window_set (tty_win, WIN_FONT, pf_default(), 0);
499: font_height = (int)window_get (tty_win, WIN_ROW_HEIGHT);
500: font_width = (int)window_get (tty_win, WIN_COLUMN_WIDTH);
501:
502: tty_view = tty_win;
503: window_set(tty_view,
504: WIN_CONSUME_PICK_EVENTS,
505: WIN_STOP,
506: WIN_MOUSE_BUTTONS, WIN_UP_EVENTS,
507: /* LOC_WINENTER, LOC_WINEXIT, LOC_MOVE, */
508: 0,
509: WIN_CONSUME_KBD_EVENTS,
510: WIN_STOP,
511: WIN_ASCII_EVENTS,
512: WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS,
513: /* WIN_UP_ASCII_EVENTS, */
514: 0,
515: 0);
516: /* Interpose my event function */
517: return (int) notify_interpose_event_func
518: (tty_view, input_event_filter_function, NOTIFY_SAFE);
519: }
520: #endif /* XVIEW */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.