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 / jovetool.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  18KB  |  641 lines

  1. /*
  2.  * Copyright (C) 1986 Free Software Foundation, Inc.
  3.  * Copyright (C) 1991-1996 C.H.Lindsey, University of Manchester
  4.  *
  5.  * This file is derived from the program emacstool, which is itself part of the
  6.  * GNU Emacs system.
  7.  *
  8.  * In the same way as GNU Emacs itself, this file is distributed in the hope
  9.  * that it will be useful, but without any warranty.  No author or
  10.  * distributor accepts responsibility to anyone for the consequences of using
  11.  * it or for whether it serves any particular purpose or works at all, unless
  12.  * he says so in writing.
  13.  *
  14.  * Everyone is granted permission to copy, modify and redistribute this file,
  15.  * but only under the conditions described in the document "GNU Emacs copying
  16.  * permission notice".   A copy of that document is distributed along with
  17.  * GNU Emacs and other GNU Products so that you can know how you may
  18.  * redistribute it all. In particular and among other things, this copyright
  19.  * notice must be preserved on all copies of this file and of files derived
  20.  * from it.
  21.  *
  22.  *
  23.  * For Jove in SunView/Sun-Windows: (supported by Sun Unix) Insert a notifier
  24.  * filter-function to convert all useful input to "key" sequences that jove
  25.  * can understand.  See: Jovetool(1).
  26.  *
  27.  * Author (of Jovetool): C. H. Lindsey, University of Manchester
  28.  * <chl@clw.cs.man.ac.uk>
  29.  * Author (of Emacstool): Jeff Peck, Sun Microsystems, Inc. <peck@sun.com>
  30.  *
  31.  * Original Idea: Ian Batten
  32.  *
  33.  */
  34.  
  35. #include <suntool/sunview.h>
  36. #include <suntool/tty.h>
  37. #include <suntool/ttysw.h>
  38. #include <stdio.h>
  39. #include <sys/file.h>
  40. #ifdef    __STDC__
  41. #include <stdlib.h>
  42. #endif
  43. #include <string.h>
  44.  
  45. #include "exts.h"
  46. #include "mousemsg.h"
  47.  
  48. #define BUFFER_SIZE 128        /* Size of all the buffers */
  49.  
  50. #define CLICK    400        /* max time in ms for click, or gap between
  51.                  * double click */
  52.  
  53. /* define WANT_CAPS_LOCK to make f-key T1 (aka F1) behave as CapsLock */
  54. /* #define WANT_CAPS_LOCK */
  55.  
  56. private const char mouse_prefix[] = "\030m";    /* ^x m */
  57. private const char key_prefix[] = "\033[";    /* ESC-[ */
  58.  
  59. private char    jove_name[] = "jove";    /* default run command */
  60. private char    buffer[BUFFER_SIZE];    /* send to ttysw_input */
  61. private const char title[] = "Jovetool - ";    /* initial title */
  62.  
  63. private Frame   frame;        /* Base frame for system */
  64. Tty             ttysw;        /* Where jove is */
  65. private int     font_width, font_height;    /* For translating pixels to
  66.                          * chars */
  67.  
  68. private FILE   *console = NULL;    /* for debugging: setenv DEBUGJOVETOOL */
  69.  
  70. private Icon    frame_icon;
  71. /* make an icon_image */
  72. private unsigned short default_image[] =
  73. {
  74. #include "jove.icon"
  75. };
  76. mpr_static_static(icon_image, 64, 64, 1, default_image);
  77.  
  78. private Cursor  current_cursor, jove_cursor, cut_cursor, copy_cursor, paste_cursor, default_cursor;
  79.  
  80. private short   cursor_image[] = {
  81. #include "jove.cursor"
  82. };
  83. mpr_static_static(cursor_pix, 16, 16, 1, cursor_image);
  84.  
  85. private unsigned short cut_image[] = {
  86. #include "cut.cursor"
  87. };
  88. mpr_static_static(cut_pix, 16, 16, 1, cut_image);
  89.  
  90. private unsigned short copy_image[] = {
  91. #include "copy.cursor"
  92. };
  93. mpr_static_static(copy_pix, 16, 16, 1, copy_image);
  94.  
  95. private unsigned short paste_image[] = {
  96. #include "paste.cursor"
  97. };
  98. mpr_static_static(paste_pix, 16, 16, 1, paste_image);
  99.  
  100.  
  101.  
  102. private void
  103. set_cursor(cursor)
  104.     Cursor          cursor;
  105. {
  106.     if (current_cursor != cursor) {
  107.         window_set(ttysw, WIN_CURSOR, cursor, 0);
  108.         current_cursor = cursor;
  109.     }
  110. }
  111.  
  112.  
  113. /*
  114.  * button_value: encode mouse event into a jovetool event code (the return
  115.  * value) and a button state (stored in last_but).  If the event ought to be
  116.  * ignored due to error, -1 is returned in place of the event code. If it is
  117.  * to be ignored silently, -2 is returned.
  118.  */
  119. private int
  120.                 last_but = JT_UPEVENT,    /* button state */
  121.                 event_shift;    /* shift state */
  122. private char
  123.                 last_event_string[7];    /* string from last F-key down event,
  124.                      * 6 being the longest string
  125.                      * expected from an F-key */
  126.  
  127. private int
  128. button_value(event)
  129.     Event          *event;
  130. {
  131.     static struct timeval
  132.                     mouse_time = {0, 0},
  133.                     prev_mouse_time;
  134.  
  135.     static int      multiclick_state = 0;
  136.  
  137.     int
  138.                     this_but = event_shift,    /* button state, after this
  139.                          * event */
  140.                     mouse_code;    /* event code for this event */
  141.  
  142.     switch (event_id(event)) {
  143.     case LOC_MOVEWHILEBUTDOWN:
  144.         if (last_but & JT_UPEVENT)
  145.             return -1;
  146.         else if (multiclick_state)
  147.             return -2;
  148.         last_but |= JT_DRAGEVENT;
  149.         {
  150.             /*
  151.              * Generate event code for leftmost depressed button.
  152.              * Currently, only one bit will be on, so this is
  153.              * overkill.
  154.              */
  155.             static short    DragCode[8] = {
  156.                 -1, JTEC_LEFT, JTEC_MIDDLE, JTEC_LEFT,
  157.             JTEC_RIGHT, JTEC_LEFT, JTEC_MIDDLE, JTEC_LEFT};
  158.  
  159.             return DragCode[last_but & JT_BUTMASK] + JTEC_DRAG;
  160.         }
  161.     case MS_LEFT:
  162.         this_but |= JT_LEFT;
  163.         mouse_code = JTEC_LEFT;
  164.         break;
  165.     case MS_MIDDLE:
  166.         this_but |= JT_MIDDLE;
  167.         mouse_code = JTEC_MIDDLE;
  168.         break;
  169.     case MS_RIGHT:
  170.         this_but |= JT_RIGHT;
  171.         mouse_code = JTEC_RIGHT;
  172.         break;
  173.     default:
  174.         return -1;
  175.     }
  176.  
  177.     /*
  178.      * Clicking too fast can sometimes beat the system. Also, a user
  179.      * might manage to get two buttons down at the same time.  The
  180.      * following tests detect such situations. Note that up events after
  181.      * JT_RIGHT are absorbed by the menu software.
  182.      */
  183.     if (event_is_up(event)) {
  184.         /* ignore up not following a down or up of a different button */
  185.         if ((last_but & JT_UPEVENT) != 0
  186.             || ((last_but ^ this_but) & JT_BUTMASK) != 0)
  187.             return -1;
  188.         this_but |= JT_UPEVENT;
  189.         mouse_code += JTEC_UP;
  190.     } else if (event_is_down(event)) {
  191.         if ((last_but & (JT_UPEVENT | JT_RIGHT)) == 0) {
  192.             /* down event not preceded by an up event */
  193.             return -1;
  194.         }
  195.     } else {        /* drag event */
  196.         if ((last_but & (JT_DOWNEVENT | JT_DRAGEVENT)) == 0) {
  197.             /* drag event not preceded by a down or drag event */
  198.             return -1;
  199.         }
  200.     }
  201.  
  202.     /*
  203.      * The only way to get back into sync is to supply whatever up or
  204.      * down event it was waiting for.  Thus jove should always see a
  205.      * consistent picture. ??? Good theory.  How is this implemented? --
  206.      * DHR
  207.      */
  208.  
  209.     /*
  210.      * Detect and encode multi-clicks.
  211.      *
  212.      * - a multiclick is a train of alternating mouse-down and mouse-up
  213.      * events - the first must be a mouse-down - Each mouse up and down
  214.      * must be of the same button - each of which happens within CLICK
  215.      * milliseconds of its predecessor - Drags are not taken into
  216.      * consideration.
  217.      */
  218.  
  219.     prev_mouse_time = mouse_time;
  220.     mouse_time = event_time(event);
  221.  
  222.     multiclick_state += 1;
  223.     if (((multiclick_state & 1) == 0) == ((this_but & JT_UPEVENT) == 0)
  224.         && ((last_but ^ this_but) & JT_BUTMASK) == 0
  225.         && (mouse_time.tv_sec - prev_mouse_time.tv_sec) * 1000
  226.      + (mouse_time.tv_usec - prev_mouse_time.tv_usec) / 1000 <= CLICK) {
  227.         switch (multiclick_state) {
  228.         case 1:    /* first up */
  229.             break;
  230.         case 2:    /* second down */
  231.             mouse_code += JTEC_CLICK2;
  232.             /* FALLTHROUGH */
  233.         case 3:    /* second up */
  234.             this_but |= JT_CLICK2;
  235.             break;
  236.         case 4:    /* third down */
  237.             mouse_code += JTEC_CLICK3;
  238.             /* FALLTHROUGH */
  239.         case 5:    /* third up */
  240.             this_but |= JT_CLICK3;
  241.             break;
  242.         default:    /* too many multi-clicks */
  243.             multiclick_state = 0;
  244.             break;
  245.         }
  246.     } else {
  247.         multiclick_state = 0;
  248.     }
  249.  
  250.     last_but = this_but;
  251.     return mouse_code;
  252. }
  253.  
  254.  
  255.  
  256. /*
  257.  * Filter function to translate selected input events for jove Mouse button
  258.  * events become ^XmC(button-state x-col y-line font-width) . - C is an
  259.  * eventcode (explained in mousemsg.h) - button-state is as described in
  260.  * mousemsg.h for this_but - x-col is horizontal column, in pixels (for
  261.  * smooth scrollbar working) - y-col is height, in characters - font-width
  262.  * allows conversion of x-col to characters Sun function keys (left, top, and
  263.  * right) are converted to the ANSI sequence ESC [ P z, where P is a number
  264.  * above 192
  265.  */
  266.  
  267. private Notify_value
  268. input_event_filter_function(window, event, arg, type)
  269.     Window          window;
  270.     Event          *event;
  271.     Notify_arg      arg;
  272.     Notify_event_type type;
  273. {
  274. #ifdef WANT_CAPS_LOCK
  275.     static int      caps_lock = 0;    /* toggle indicater for f-key T1 caps
  276.                      * lock */
  277. #endif
  278.     int             id = event_id(event);
  279.     int             mouse_code = -3;    /* not -1 and not -2 and not
  280.                          * >=0 */
  281.     int             fkey;
  282.  
  283.     event_shift &= ~JT_CSMASK;
  284.     if (event_shift_is_down(event))
  285.         event_shift |= JT_SHIFT;
  286.     if (event_ctrl_is_down(event))
  287.         event_shift |= JT_CONTROL;
  288.     if (event_action(event) == ACTION_PASTE || event_action(event) == ACTION_CUT) {
  289.         if (event_is_up(event))
  290.             event_shift &= ~(event_action(event) == ACTION_PASTE ?
  291.                      JT_PASTE : JT_CUT);
  292.         else
  293.             event_shift |= (event_action(event) == ACTION_PASTE ?
  294.                     JT_PASTE : JT_CUT);
  295.     }
  296.     if (console != NULL) {
  297.         fprintf(console, "Event %d", id);
  298.         if (event_shift != 0)
  299.             fprintf(console, "; shift %d", event_shift);
  300.         if (event_is_up(event))
  301.             fprintf(console, "; up");
  302.         if (event_is_button(event))
  303.             fprintf(console, "; button %d", id - BUT(0));
  304.         fprintf(console, "\n");
  305.     }
  306.     switch (id) {
  307.     case LOC_MOVEWHILEBUTDOWN:
  308.         mouse_code = button_value(event);
  309.         /* no need to set cursor */
  310.         break;
  311.     case MS_LEFT:
  312.     case MS_MIDDLE:
  313.     case MS_RIGHT:
  314.         mouse_code = button_value(event);
  315.         if (last_but & JT_PASTEMASK)
  316.             last_event_string[0] = 0;
  317.         /*
  318.          * We do not wish to see Left keys (esp. PASTE & CUT)
  319.          * associated with buttons
  320.          */
  321.         /* FALLTHROUGH */
  322.     case SHIFT_LEFT:
  323.     case SHIFT_RIGHT:
  324.     case SHIFT_CTRL:
  325.         /* set cursor appropriately */
  326.         if (event_shift == JT_SHIFT) {
  327.             set_cursor(default_cursor);
  328.         } else {
  329.             switch (event_shift | (last_but & (JT_UPEVENT | JT_BUTMASK))) {
  330.             case JT_SHIFT | JT_CONTROL | JT_MIDDLE:
  331.                 set_cursor(cut_cursor);
  332.                 break;
  333.             case JT_CONTROL | JT_MIDDLE:
  334.                 set_cursor(copy_cursor);
  335.                 break;
  336.             case JT_CONTROL | JT_LEFT:
  337.                 set_cursor(paste_cursor);
  338.                 break;
  339.             default:
  340.                 set_cursor(jove_cursor);
  341.                 break;
  342.             }
  343.         }
  344.         break;
  345.     case KEY_LEFT(5):    /* EXPOSE key */
  346.     case KEY_LEFT(7):    /* OPEN key */
  347.         /*
  348.          * UP L5 & L7 is Expose & Open, let them pass to SunView. ???
  349.          * Apparently it only cares about up events.
  350.          */
  351.         return event_is_up(event)
  352.             ? notify_next_event_func(window, event, arg, type)
  353.             : NOTIFY_IGNORED;
  354.     }
  355.  
  356.     /*
  357.      * Treat shifted events as normal Shelltool events. This includes
  358.      * shifted characters which is a bit naughty (xjove must deal with
  359.      * them separately because it needs to clear the shiftmask for
  360.      * non-characters).
  361.      */
  362.     if (event_shift == JT_SHIFT) {
  363.         /*
  364.          * NOTE: at least under SunOS4.0.3, the shelltool routine
  365.          * turns off LOC_MOVEWHILEBUTDOWN, so we must restore it.
  366.          */
  367.         Notify_value    result = notify_next_event_func(window, event, arg, type);
  368.  
  369.         window_set(ttysw, WIN_CONSUME_PICK_EVENT, LOC_MOVEWHILEBUTDOWN, 0);
  370.         return result;
  371.     }
  372.     /* do Mouse Button events */
  373.  
  374.     if (mouse_code >= 0) {
  375.         int
  376.                         this_x = event_x(event), this_y = event_y(event) / font_height;
  377.         static int      last_x, last_y;
  378.  
  379.         if (last_but & JT_RIGHT) {
  380.             /*
  381.              * ??? avoid passing up-event, if we catch it --
  382.              * would cause deadlock.
  383.              */
  384.             if (last_but == JT_RIGHT)
  385.                 menu_show(main_menu, window, event, 0);
  386.         } else {
  387.             if (this_x == last_x && this_y == last_y) {
  388.                 if (id == LOC_MOVEWHILEBUTDOWN)
  389.                     return NOTIFY_IGNORED;
  390.                 sprintf(buffer, "%s%d(%d)\015",
  391.                     mouse_prefix, mouse_code, last_but);
  392.             } else {
  393.                 sprintf(buffer, "%s%d(%d %d %d %d)\015",
  394.                     mouse_prefix, mouse_code, last_but,
  395.                     this_x, this_y, font_width);
  396.                 last_x = this_x;
  397.                 last_y = this_y;
  398.             }
  399.             ttysw_input(ttysw, buffer, strlen(buffer));
  400.         }
  401.         return NOTIFY_IGNORED;
  402.     } else if (mouse_code == -1) {
  403.         ttysw_output(ttysw, "\007", 1);    /* beep */
  404.         return NOTIFY_IGNORED;
  405.     } else if (mouse_code == -2) {
  406.         return NOTIFY_IGNORED;
  407.     }
  408.     /* process event if it was a function key stroke */
  409.  
  410.     fkey = 0;
  411.  
  412.     /* In JoveTool, WIN_STOP is handled separately, as a synonym for L1. */
  413.     if (id == WIN_STOP)
  414.         fkey = 192;
  415.     else if (event_is_key_left(event))
  416.         fkey = id - KEY_LEFT(1) + 192;
  417.     else if (event_is_key_right(event))
  418.         fkey = id - KEY_RIGHT(1) + 208;
  419.     else if (event_is_key_top(event))
  420.         fkey = id - KEY_TOP(1) + 224;
  421.  
  422.     if (fkey != 0) {
  423.         if (event_is_down(event) || id == WIN_STOP)
  424.             sprintf(last_event_string, "%s%dz", key_prefix, fkey);
  425.         /* test should be !event_button_is_down(event) */
  426.         if (last_but & JT_UPEVENT) {
  427.             /*
  428.              * we don't want any function keys (esp PASTE & CUT)
  429.              * seen when a button is down
  430.              */
  431.             if (event_action(event) == ACTION_PASTE
  432.                 || event_action(event) == ACTION_CUT
  433.                 || id == WIN_STOP) {
  434.                 if (event_is_down(event)) {
  435.                     /*
  436.                      * we see PASTE and CUT and WIN_STOP
  437.                      * when they come up
  438.                      */
  439.                     return NOTIFY_IGNORED;
  440.                 }
  441.             } else if (event_is_up(event)) {
  442.                 /* we see other F-keys when they go down */
  443.                 return NOTIFY_IGNORED;
  444.             }
  445. #ifdef WANT_CAPS_LOCK
  446.             /*
  447.              * set a toggle and relabel window so T1 can act like
  448.              * caps-lock
  449.              */
  450.             if (id == KEY_TOP(1)) {
  451.                 /* make a frame label with and without CAPS */
  452.                 static const char Caps[] = "[CAPS] ";
  453.                 char           *p = (char *) window_get(frame, FRAME_LABEL);
  454.  
  455.                 strcpy(buffer, Caps);
  456.                 strncpy(buffer + sizeof(Caps) - 1,
  457.                     strncmp(p, Caps, sizeof(Caps) - 1) == 0 ? p + sizeof(Caps) - 1 : p,
  458.                     BUFFERSIZE - (sizeof(Caps)));
  459.                 buffer[BUFFER_SIZE - 1] = '\0';
  460.                 caps_lock = !caps_lock;
  461.                 window_set(frame, FRAME_LABEL,
  462.                        buffer + (caps_lock ? 0 : sizeof(Caps) - 1), 0);
  463.                 return NOTIFY_IGNORED;
  464.             }
  465. #endif
  466.             ttysw_input(ttysw, last_event_string, strlen(last_event_string));
  467.         }
  468.         return NOTIFY_IGNORED;
  469.     }
  470.     /* Discard key-up ascii or meta events */
  471.     /*
  472.      * ??? is this needed?  Will the someone down the line not do this?
  473.      * We aren't even catching ascii up-events.
  474.      */
  475.     if ((event_is_ascii(event) || event_is_meta(event))
  476.         && event_is_up(event))
  477.         return NOTIFY_IGNORED;
  478.  
  479. #ifdef WANT_CAPS_LOCK
  480.     /* shift alpha chars to upper case if capslock is set */
  481.     if (caps_lock && event_is_ascii(event) && isupper(id))
  482.         event_set_id(event, tolower(id));
  483. #endif
  484.  
  485.     if (event_is_ascii(event)) {
  486.         /*
  487.          * Force bit 8 if meta key is down. But it will only be
  488.          * noticed by the controlled process if it does a stty
  489.          * -istrip, or equivalent.
  490.          */
  491.         if (event_shiftmask(event) & META_SHIFT_MASK)
  492.             event->ie_code |= META_FIRST;    /* ??? META_KEY_MASK not
  493.                              * in SunView */
  494.     }
  495.     /* If we get here, pass event off to next handler */
  496.     return notify_next_event_func(window, event, arg, type);
  497. }
  498.  
  499.  
  500. extern char    *getenv proto((const char *));    /* fudge -- must be in some
  501.                          * header */
  502.  
  503. int
  504. main(argc, argv)
  505.     int             argc;
  506.     char          **argv;
  507. {
  508.     int             error_code;    /* Error codes */
  509.     int             forking;
  510.     char           *debug;
  511.  
  512.     if ((debug = getenv("DEBUGJOVETOOL")) != NULL) {
  513.         /*
  514.          * DEBUGJOVETOOL specifies the file or device to receive
  515.          * debugging output, if any.  The null name signifies stderr.
  516.          */
  517.         console = *debug == '\0' ? stderr : fopen(debug, "w");
  518.         forking = 0;
  519.     } else {
  520.         forking = isatty(0);
  521.     }
  522.  
  523.     if (argc>1 && (!strcmp("-f", argv[1]) || !strcmp("-nf", argv[1]))) {
  524.         char    **p = &argv[1];
  525.  
  526.         forking = strcmp("-f", *p) == 0;
  527.         do ; while ((p[0] = p[1]) != NULL);
  528.     }
  529.  
  530.     if (forking) {
  531.         switch (fork()) {
  532.         case -1:
  533.             fprintf(stderr, "fork failed");
  534.             exit(1);
  535.             /* NOTREACHED */
  536.         case 0:    /* the child */
  537.             setpgrp(0, 0);    /* so it doesn't get killed when
  538.                      * parent dies */
  539.             break;
  540.         default:    /* the parent */
  541.             exit(0);
  542.             /* NOTREACHED */
  543.         }
  544.     }
  545.  
  546.     putenv("IN_JOVETOOL=t");/* notify subprocess that it is in jovetool */
  547.     putenv("TERMCAP=");
  548.     putenv("TERM=sun");    /* the TTYSW will be a sun terminal to
  549.                  * override these, try % jovetool -rc script */
  550.     if ((argv[0] = getenv("JOVETOOL")) == NULL)    /* Set jove command name */
  551.         argv[0] = jove_name;
  552.     for (argc = 1; argv[argc]; argc++)    /* Use last one on line */
  553.         if (!(strcmp("-rc", argv[argc]))) {    /* Override if -rc given */
  554.             int             i = argc;
  555.             argv[argc--] = 0;    /* kill the -rc argument */
  556.             if (argv[i + 1]) {    /* move to argv[0] and
  557.                          * squeeze the rest */
  558.                 argv[0] = argv[i + 1];
  559.                 for (; argv[i + 2]; (argv[i] = argv[i + 2], argv[++i] = 0));
  560.             }
  561.         }
  562.     frame_icon = icon_create(ICON_LABEL, argv[0],
  563.                  ICON_IMAGE, &icon_image,
  564.                  0);
  565.  
  566.  
  567.     strcpy(buffer, title);
  568.     strncat(buffer, argv[0],/* append run command name */
  569.         (BUFFER_SIZE - (strlen(buffer)) - (strlen(argv[0]))) - 1);
  570.  
  571.     /* Build a frame to run in */
  572.     frame = window_create((Window) NULL, FRAME,
  573.                   FRAME_LABEL, buffer,
  574.                   FRAME_ICON, frame_icon,
  575.                   FRAME_ARGC_PTR_ARGV, &argc, argv,
  576.                   0);
  577.  
  578.     /* Create a tty with jove in it */
  579.     ttysw = window_create(frame, TTY,
  580.                   TTY_QUIT_ON_CHILD_DEATH, TRUE,
  581.     /* TTY_BOLDSTYLE, 4, */
  582.                   TTY_ARGV, argv,
  583.                   0);
  584.  
  585.     window_set(ttysw,
  586.            WIN_CONSUME_PICK_EVENTS,
  587.            WIN_STOP,
  588.            WIN_MOUSE_BUTTONS, WIN_UP_EVENTS,
  589.     /* LOC_WINENTER, LOC_WINEXIT, LOC_MOVE, */
  590.            LOC_MOVEWHILEBUTDOWN,
  591.            0,
  592.  
  593.            WIN_CONSUME_KBD_EVENTS,
  594.            WIN_STOP, SHIFT_LEFT, SHIFT_RIGHT, SHIFT_CTRL,
  595.            WIN_ASCII_EVENTS,
  596.            WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS,
  597.     /* WIN_UP_ASCII_EVENTS, */
  598.            0,
  599.  
  600.            0);
  601.  
  602.     default_cursor = window_get(ttysw, WIN_CURSOR);
  603.     jove_cursor = cursor_create(
  604.                     CURSOR_IMAGE, &cursor_pix,
  605.                     CURSOR_XHOT, 8,
  606.                     CURSOR_YHOT, 8,
  607.                     0);
  608.     cut_cursor = cursor_create(
  609.                    CURSOR_IMAGE, &cut_pix,
  610.                    CURSOR_XHOT, 8,
  611.                    CURSOR_YHOT, 8,
  612.                    0);
  613.     copy_cursor = cursor_create(
  614.                     CURSOR_IMAGE, ©_pix,
  615.                     CURSOR_XHOT, 8,
  616.                     CURSOR_YHOT, 8,
  617.                     0);
  618.     paste_cursor = cursor_create(
  619.                      CURSOR_IMAGE, &paste_pix,
  620.                      CURSOR_XHOT, 8,
  621.                      CURSOR_YHOT, 8,
  622.                      0);
  623.     set_cursor(jove_cursor);
  624.  
  625.     font_height = (int) window_get(ttysw, WIN_ROW_HEIGHT);
  626.     font_width = (int) window_get(ttysw, WIN_COLUMN_WIDTH);
  627.  
  628.     /* Interpose my event function */
  629.     error_code = (int) notify_interpose_event_func
  630.         (ttysw, input_event_filter_function, NOTIFY_SAFE);
  631.  
  632.     if (error_code != 0) {    /* Barf */
  633.         fprintf(stderr, "notify_interpose_event_func got %d.\n", error_code);
  634.         exit(1);
  635.     }
  636.     menu_init();
  637.     window_main_loop(frame);/* And away we go */
  638.     exit(0);        /* if this is ever reached */
  639.     /* NOTREACHED */
  640. }
  641.