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 >
C/C++ Source or Header  |  1996-09-28  |  22KB  |  776 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 v3.2) Insert a
  24.  * notifier filter-function to convert all useful input to "key" sequences
  25.  * that jove can understand.  See: Xjove(1).
  26.  *
  27.  * Author (of Jovetool/Xjove): 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 <xview/defaults.h>
  36. #include <xview/xview.h>
  37. #include <xview/tty.h>
  38. #include <xview/ttysw.h>    /* is this missing on some systems? */
  39. #include <xview/termsw.h>
  40. #include <xview/cursor.h>
  41. #include <xview/font.h>
  42. #include <X11/Xlib.h>
  43. #include <X11/keysym.h>
  44. #include <X11/Sunkeysym.h>    /* for Suns only */
  45. #include <stdio.h>
  46. #include <string.h>
  47. #include <sys/file.h>
  48. #include <stdlib.h>
  49. #include <unistd.h>    /* is this missing on some systems? */
  50. #include <fcntl.h>
  51. #include <termios.h>
  52.  
  53. #include "exts.h"
  54. #include "mousemsg.h"
  55.  
  56. #define BUFFER_SIZE 256        /* Size of all the buffers */
  57.  
  58. #define CLICK    400        /* max time in ms for click, or gap between
  59.                  * double click */
  60.  
  61. /* define WANT_CAPS_LOCK to make f-key T1 (aka F1) behave as CapsLock */
  62. /* #define WANT_CAPS_LOCK */
  63.  
  64. private const char mouse_prefix[] = "\030m";    /* ^x m */
  65. private const char key_prefix[] = "\033[";    /* ESC-[ */
  66.  
  67. private char   *jove_name = "jove";    /* default run command */
  68. private char    buffer[BUFFER_SIZE];    /* send to ttysw_input */
  69. private const char title[] = "XJove - ";    /* initial title */
  70.  
  71. private Frame   frame;        /* Base frame for system */
  72. Tty             ttysw;        /* Where jove is */
  73. private Tty     ttyview;
  74. private int     font_width, font_height;    /* For translating pixels to
  75.                          * chars */
  76. private int     left_margin, right_margin;
  77.  
  78. private FILE   *console = NULL;    /* for debugging: setenv DEBUGJOVETOOL */
  79.  
  80. private Icon    frame_icon;
  81. /* make an icon_image */
  82. private unsigned short default_image[] =
  83. {
  84. #include "jove.icon"
  85. };
  86. mpr_static_static(icon_image, 64, 64, 1, default_image);
  87.  
  88. private Xv_Cursor current_cursor, jove_cursor, cut_cursor, copy_cursor, paste_cursor, default_cursor;
  89.  
  90. private unsigned short cursor_image[] = {
  91. #include "jove.cursor"
  92. };
  93. mpr_static_static(cursor_pix, 16, 16, 1, cursor_image);
  94.  
  95. private unsigned short cut_image[] = {
  96. #include "cut.cursor"
  97. };
  98. mpr_static_static(cut_pix, 16, 16, 1, cut_image);
  99.  
  100. private unsigned short copy_image[] = {
  101. #include "copy.cursor"
  102. };
  103. mpr_static_static(copy_pix, 16, 16, 1, copy_image);
  104.  
  105. private unsigned short paste_image[] = {
  106. #include "paste.cursor"
  107. };
  108. mpr_static_static(paste_pix, 16, 16, 1, paste_image);
  109.  
  110. Xv_Font         font;
  111.  
  112.  
  113.  
  114. private void
  115. set_cursor(cursor)
  116.     Xv_Cursor       cursor;
  117. {
  118.     if (current_cursor != cursor) {
  119.         xv_set(ttyview, WIN_CURSOR, cursor, 0);
  120.         current_cursor = cursor;
  121.     }
  122. }
  123.  
  124.  
  125. /*
  126.  * button_value: encode mouse event into an xjove event code (the return
  127.  * value) and a button state (stored in last_but).  If the event ought to be
  128.  * ignored due to error, -1 is returned in place of the event code. If it is
  129.  * to be ignored silently, -2 is returned.
  130.  */
  131. private int
  132.                 last_but = JT_UPEVENT,    /* button state */
  133.                 event_shift,    /* shift state */
  134.                 next_kdb_event_should_be_up;
  135. private char
  136.                 last_event_string[7];    /* string from last F-key down event,
  137.                      * 6 being the longest string
  138.                      * expected from an F-key */
  139.  
  140. private int
  141. button_value(event)
  142.     Event          *event;
  143. {
  144.     static struct timeval
  145.                     mouse_time = {0, 0},
  146.                     prev_mouse_time;
  147.  
  148.     static int      multiclick_state = 0;
  149.  
  150.     int
  151.                     this_but = event_shift,    /* button state, after this
  152.                          * event */
  153.                     mouse_code;    /* event code for this event */
  154.  
  155.     switch (event_id(event)) {
  156.     case LOC_DRAG:
  157.         if (last_but & JT_UPEVENT)
  158.             return -1;
  159.         else if (multiclick_state)
  160.             return -2;
  161.         last_but |= JT_DRAGEVENT;
  162.         {
  163.             /*
  164.              * Generate event code for leftmost depressed button.
  165.              * Currently, only one bit will be on, so this is
  166.              * overkill.
  167.              */
  168.             static short    DragCode[8] = {
  169.                 -1, JTEC_LEFT, JTEC_MIDDLE, JTEC_LEFT,
  170.             JTEC_RIGHT, JTEC_LEFT, JTEC_MIDDLE, JTEC_LEFT};
  171.  
  172.             return DragCode[last_but & JT_BUTMASK] + JTEC_DRAG;
  173.         }
  174.     case MS_LEFT:
  175.         this_but |= JT_LEFT;
  176.         mouse_code = JTEC_LEFT;
  177.         break;
  178.     case MS_MIDDLE:
  179.         this_but |= JT_MIDDLE;
  180.         mouse_code = JTEC_MIDDLE;
  181.         break;
  182.     case MS_RIGHT:
  183.         this_but |= JT_RIGHT;
  184.         mouse_code = JTEC_RIGHT;
  185.         break;
  186.     default:
  187.         return -1;
  188.     }
  189.  
  190.     /*
  191.      * Clicking too fast can sometimes beat the system. Also, a user
  192.      * might manage to get two buttons down at the same time.  The
  193.      * following tests detect such situations. Note that up events after
  194.      * JT_RIGHT are absorbed by the menu software.
  195.      */
  196.     if (event_is_up(event)) {
  197.         /* ignore up not following a down or up of a different button */
  198.         if ((last_but & (JT_UPEVENT | JT_RIGHT)) == JT_UPEVENT
  199.             || ((last_but ^ this_but) & JT_BUTMASK) != 0)
  200.             return -1;
  201.         this_but |= JT_UPEVENT;
  202.         mouse_code += JTEC_UP;
  203.     } else if (event_is_down(event)) {
  204.         if ((last_but & (JT_UPEVENT | JT_RIGHT)) == 0) {
  205.             /* down event not preceded by an up or right event */
  206.             return -1;
  207.         }
  208.     } else {        /* drag event */
  209.         if ((last_but & (JT_DOWNEVENT | JT_DRAGEVENT)) == 0) {
  210.             /* drag event not preceded by a down or drag event */
  211.             return -1;
  212.         }
  213.     }
  214.     /*
  215.      * The only way to get back into sync is to supply whatever up or
  216.      * down event it was waiting for. Thus jove should always see a
  217.      * consistent picture
  218.      */
  219.  
  220.     /*-- Detect and encode multi-clicks.
  221.      *
  222.      * - a multiclick is a train of alternating mouse-down and mouse-up events
  223.      * - the first must be a mouse-down
  224.      * - Each mouse up and down must be of the same button
  225.      * - each of which happens within CLICK milliseconds of its predecessor
  226.      * - Drags are not taken into consideration.
  227.      */
  228.  
  229.     prev_mouse_time = mouse_time;
  230.     mouse_time = event_time(event);
  231.  
  232.     multiclick_state += 1;
  233.     if (((multiclick_state & 1) == 0) == ((this_but & JT_UPEVENT) == 0)
  234.         && ((last_but ^ this_but) & JT_BUTMASK) == 0
  235.         && (mouse_time.tv_sec - prev_mouse_time.tv_sec) * 1000
  236.      + (mouse_time.tv_usec - prev_mouse_time.tv_usec) / 1000 <= CLICK) {
  237.         switch (multiclick_state) {
  238.         case 1:    /* first up */
  239.             break;
  240.         case 2:    /* second down */
  241.             mouse_code += JTEC_CLICK2;
  242.             /* FALLTHROUGH */
  243.         case 3:    /* second up */
  244.             this_but |= JT_CLICK2;
  245.             break;
  246.         case 4:    /* third down */
  247.             mouse_code += JTEC_CLICK3;
  248.             /* FALLTHROUGH */
  249.         case 5:    /* third up */
  250.             this_but |= JT_CLICK3;
  251.             break;
  252.         default:    /* too many multi-clicks */
  253.             multiclick_state = 0;
  254.             break;
  255.         }
  256.     } else {
  257.         multiclick_state = 0;
  258.     }
  259.  
  260.     last_but = this_but;
  261.     return mouse_code;
  262. }
  263.  
  264.  
  265. /*
  266.  * Filter function to translate selected input events for jove Mouse button
  267.  * events become ^XmC(button-state x-col y-line font-width) . - C is an
  268.  * eventcode (explained in mousemsg.h) - button-state is as described
  269.  * mousemsg.h for this_but - x-col is horizontal column, in pixels (for
  270.  * smooth scrollbar working) - y-col is height, in characters - font-width
  271.  * allows conversion of x-col to characters Sun function keys (left, top, and
  272.  * right) are converted to the ANSI sequence ESC [ P z, where P is a number
  273.  * above 192
  274.  */
  275.  
  276. private Notify_value
  277. input_event_filter_function(window, event, arg, type)
  278.     Xv_Window       window;
  279.     Event          *event;
  280.     Notify_arg      arg;
  281.     Notify_event_type type;
  282. {
  283.     int             id = event_id(event);
  284.     int             mouse_code = -3;    /* not -1 and not -2 and not
  285.                          * >=0 */
  286.     int             fkey;
  287.  
  288.     event_shift &= ~JT_CSMASK;
  289.     if (event_shift_is_down(event))
  290.         event_shift |= JT_SHIFT;
  291.     if (event_ctrl_is_down(event))
  292.         event_shift |= JT_CONTROL;
  293.     /*
  294.      * Under Xview (but not SunView) the answers to the above queries do
  295.      * not reflect the effect of the current event!
  296.      */
  297.     {
  298.         int             delta = 0;
  299.  
  300.         switch (event_action(event)) {
  301.         case SHIFT_LEFT:
  302.         case SHIFT_RIGHT:
  303.             delta = JT_SHIFT;
  304.             break;
  305.         case SHIFT_CTRL:
  306.             delta = JT_CONTROL;
  307.             break;
  308.         case ACTION_PASTE:
  309.             delta = JT_PASTE;
  310.             break;
  311.         case ACTION_CUT:
  312.             delta = JT_CUT;
  313.             break;
  314.         }
  315.         if (event_is_up(event))
  316.             event_shift &= ~delta;
  317.         else
  318.             event_shift |= delta;
  319.     }
  320.  
  321.     if (console != NULL) {
  322.         fprintf(console, "Ttyview Event %d", id);
  323.         if (event_shift != 0)
  324.             fprintf(console, "; shift %d", event_shift);
  325.         if (event_is_up(event))
  326.             fprintf(console, "; up");
  327.         if (event_is_button(event))
  328.             fprintf(console, "; button %d", id - BUT(0));
  329.         fprintf(console, "\n");
  330.     }
  331.     switch (id) {
  332.     case LOC_DRAG:
  333.         mouse_code = button_value(event);
  334.         /* no need to set cursor */
  335.         break;
  336.     case MS_LEFT:
  337.     case MS_MIDDLE:
  338.     case MS_RIGHT:
  339.         mouse_code = button_value(event);
  340.         if (last_but & JT_PASTEMASK)
  341.             last_event_string[0] = 0;
  342.         /*
  343.          * We do not wish to see Left keys (esp. PASTE & CUT)
  344.          * associated with buttons
  345.          */
  346.         /* FALLTHROUGH */
  347.     case SHIFT_LEFT:
  348.     case SHIFT_RIGHT:
  349.     case SHIFT_CTRL:
  350.         /* set cursor appropriately */
  351.         if (event_shift == JT_SHIFT) {
  352.             set_cursor(default_cursor);
  353.         } else {
  354.             switch (event_shift | (last_but & (JT_UPEVENT | JT_BUTMASK))) {
  355.             case JT_SHIFT | JT_CONTROL | JT_MIDDLE:
  356.                 set_cursor(cut_cursor);
  357.                 break;
  358.             case JT_CONTROL | JT_MIDDLE:
  359.                 set_cursor(copy_cursor);
  360.                 break;
  361.             case JT_CONTROL | JT_LEFT:
  362.                 set_cursor(paste_cursor);
  363.                 break;
  364.             default:
  365.                 set_cursor(jove_cursor);
  366.                 break;
  367.             }
  368.         }
  369.         break;
  370.     case KEY_LEFT(5):    /* EXPOSE or FRONT key */
  371.     case KEY_LEFT(7):    /* OPEN key */
  372.         /*
  373.          * UP L5 & L7 are Expose & Open, let them pass to SunView.
  374.          * Apparently it only cares about up events. Actually, the
  375.          * down event never gets this far, but the up event seems to
  376.          * be needed to force a refresh.
  377.          */
  378.         return event_is_up(event)
  379.             ? notify_next_event_func(window, (Notify_event) event, arg, type)
  380.             : NOTIFY_IGNORED;
  381.     }
  382.  
  383.     /* Treat shifted events as normal Shelltool events. */
  384.     if (event_shift == JT_SHIFT && id >= ISO_LAST) {
  385.         Notify_value    result;
  386.  
  387.         /* Translate well-known left keys. */
  388.         switch (id) {
  389.         case KEY_LEFT(6):
  390.             event->action = ACTION_COPY;
  391.             break;
  392.         case KEY_LEFT(8):
  393.             event->action = ACTION_PASTE;
  394.             break;
  395.         case KEY_LEFT(10):
  396.             event->action = ACTION_COPY;    /* CUT is censored */
  397.             break;
  398.         }
  399.  
  400.         event_shiftmask(event) &= ~SHIFTMASK;    /* get rid of shift */
  401.         event_set_string(event, NULL);    /* later versions of xview
  402.                          * seem to output this string
  403.                          * even when they have already
  404.                          * interpreted the event as a
  405.                          * copy/paste/cut
  406.                          */
  407.  
  408.         result = notify_next_event_func(window, (Notify_event) event, arg, type);
  409.         return result;
  410.     }
  411.     /* do Mouse Button events */
  412.  
  413.     if (mouse_code >= 0) {
  414.         int
  415.                         this_x = event_x(event) - left_margin, this_y = event_y(event) / font_height;
  416.         static int      last_x, last_y;
  417.  
  418.         if (last_but & JT_RIGHT) {
  419.             /*
  420.              * ??? avoid passing up-event, if we catch it --
  421.              * would cause deadlock.
  422.              */
  423.             if (last_but == JT_RIGHT)
  424.                 menu_show(main_menu, window, event, 0);
  425.         } else {
  426.             if (this_x == last_x && this_y == last_y) {
  427.                 if (id == LOC_DRAG)
  428.                     return NOTIFY_IGNORED;
  429.                 sprintf(buffer, "%s%d(%d)\015",
  430.                     mouse_prefix, mouse_code, last_but);
  431.             } else {
  432.                 sprintf(buffer, "%s%d(%d %d %d %d)\015",
  433.                     mouse_prefix, mouse_code, last_but,
  434.                     this_x, this_y, font_width);
  435.                 last_x = this_x;
  436.                 last_y = this_y;
  437.             }
  438.             ttysw_input(ttysw, buffer, strlen(buffer));
  439.         }
  440.         return NOTIFY_IGNORED;
  441.     } else if (mouse_code == -1) {
  442.         ttysw_output(ttysw, "\007", 1);    /* beep */
  443.         return NOTIFY_IGNORED;
  444.     } else if (mouse_code == -2) {
  445.         return NOTIFY_IGNORED;
  446.     }
  447.     if (next_kdb_event_should_be_up && event_is_down(event)
  448.         && event_is_iso(event)) {
  449.         ttysw_output(ttysw, "\007", 1);    /* beep */
  450.         return NOTIFY_IGNORED;
  451.     }
  452.     next_kdb_event_should_be_up = 0;
  453.  
  454.     if (event_is_string(event)    /* it has been rebound with
  455.                      * XRebindKeysym */
  456.         ||event_is_key_left(event)) {    /* For some reason, up events
  457.                          * of PASTE and CUT do not
  458.                          * appear as string events,
  459.                          * but they must be caught
  460.                          * here */
  461.         if (event_is_down(event)) {
  462.             if (event_is_string(event)) {
  463.                 strcpy(last_event_string, event_string(event));
  464.                 /*
  465.                  * because XView does not seem to provide
  466.                  * these strings on the up event
  467.                  */
  468.             } else {
  469.                 last_event_string[0] = '\0';
  470.                 /*
  471.                  * Sometimes, even the down event of PASTE is
  472.                  * not a string, as when Caps Lock is down.
  473.                  * Forget it!
  474.                  */
  475.             }
  476.         }
  477.         if (!event_button_is_down(event)) {
  478.             /*
  479.              * we don't want any function keys (esp PASTE & CUT)
  480.              * seen when a button is down
  481.              */
  482.             if (event_action(event) == ACTION_PASTE
  483.                 || event_action(event) == ACTION_CUT) {
  484.                 if (event_is_down(event)) {
  485.                     /*
  486.                      * we see PASTE and CUT when they
  487.                      * come up
  488.                      */
  489.                     next_kdb_event_should_be_up = 1;
  490.                     return NOTIFY_IGNORED;
  491.                 }
  492.             } else if (event_is_up(event)) {
  493.                 /* we see other F-keys when they go down */
  494.                 return NOTIFY_IGNORED;
  495.             }
  496.             ttysw_input(ttysw, last_event_string, strlen(last_event_string));
  497.         }
  498.         return NOTIFY_IGNORED;
  499.     }
  500.     if (ISO_FIRST <= id && id <= ISO_LAST) {
  501.         /*
  502.          * Force bit 8 if meta key is down. But it will only be
  503.          * noticed by the controlled process if it does a stty
  504.          * -istrip, or equivalent.
  505.          */
  506.         if (event_shiftmask(event) & META_SHIFT_MASK)
  507.             event->ie_code |= META_KEY_MASK;
  508.     }
  509.     /* If we get here, pass event off to next handler */
  510.     return notify_next_event_func(window, (Notify_event) event, arg, type);
  511. }
  512.  
  513. private         Notify_value
  514. tty_event_filter_function(window, event, arg, type)
  515.     Xv_Window       window;
  516.     Event          *event;
  517.     Notify_arg      arg;
  518.     Notify_event_type type;
  519. {
  520.     if (console != NULL)
  521.         fprintf(console, "Ttysw Event: %d\n", event_id(event));
  522.  
  523.     if (event_id(event) == KBD_USE) {
  524.         win_set_kbd_focus(ttyview, xv_get(ttyview, XV_XID));
  525.         return NOTIFY_IGNORED;
  526.     } else {
  527.         return notify_next_event_func(window, (Notify_event) event, arg, type);
  528.     }
  529. }
  530.  
  531.  
  532. void
  533. bind_key(ksym, string)
  534.     KeySym          ksym;
  535.     char           *string;
  536. {
  537.     Display        *dpy;
  538.     static KeySym   shift_list[] =
  539.     {XK_Shift_L, XK_Control_L, XK_Meta_L, XK_Alt_L, XK_Mode_switch};
  540.     int             i;
  541.  
  542.     dpy = (Display *) xv_get(frame, XV_DISPLAY);
  543.     XRebindKeysym(dpy, ksym, NULL, 0, (unsigned char *) string, strlen(string));
  544.     for (i = 0; i != sizeof(shift_list) / sizeof(*shift_list); i++)
  545.         XRebindKeysym(dpy, ksym, &shift_list[i], 1, (unsigned char *) string, strlen(string));
  546. }
  547.  
  548. void
  549. bind_function_keys(first, count, number)
  550.     KeySym          first;
  551.     unsigned int    count, number;
  552. {
  553.     int             i;
  554.     char            buffer[6];
  555.  
  556.     for (i = 0; i < count; i++) {
  557.         sprintf(buffer, "%s%3dz", key_prefix, number + i);
  558.         bind_key(first + i, buffer);
  559.     }
  560. }
  561.  
  562. int
  563. main(argc, argv)
  564.     int             argc;
  565.     char          **argv;
  566. {
  567.     int             error_code;    /* Error codes */
  568.     int             forking;
  569.     int             argstart = 1;
  570.     char           *debug;
  571.     int             child_argc, i;
  572.     char          **child_argv;
  573.     char           *icon_label;
  574.     int             tty_fd;
  575.     struct termios  tty;
  576.  
  577.     xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, 0);
  578.  
  579.     if ((debug = getenv("DEBUGJOVETOOL")) != NULL) {
  580.         /*
  581.          * DEBUGJOVETOOL specifies the file or device to receive
  582.          * debugging output, if any.  The null name signifies stderr.
  583.          */
  584.         console = *debug == '\0' ? stderr : fopen(debug, "w");
  585.         forking = 0;
  586.     } else if (!isatty(0)) {
  587.         forking = 0;
  588.     } else {
  589.         forking = defaults_get_boolean("xjove.forking", "Xjove.Forking", 0);
  590.     }
  591.  
  592.     if (argc>1 && !strcmp("-nf", argv[1])) {
  593.         forking = 0;
  594.         argstart = 2;
  595.     } else if (argc>1 && !strcmp("-f", argv[1])) {
  596.         forking = 1;
  597.         argstart = 2;
  598.     }
  599.  
  600.     if (forking) {
  601.         switch (fork()) {
  602.         case -1:
  603.             fprintf(stderr, "fork failed");
  604.             exit(1);
  605.             /* NOTREACHED */
  606.         case 0:    /* the child */
  607. #ifdef SYSVR4
  608.             setsid();    /* so it doesn't get killed when
  609.                      * parent dies */
  610. #else
  611.             setpgid(0, 0);    /* For some reason, setsid() hinders
  612.                      * passing of SIGWINCH events to the
  613.                      * controlled process in SUNOS4 */
  614. #endif
  615.             break;
  616.         default:    /* the parent */
  617.             exit(0);
  618.             /* NOTREACHED */
  619.         }
  620.     }
  621.  
  622.     putenv("IN_JOVETOOL=t");/* notify subprocess that it is in jovetool */
  623.  
  624.     font = (Xv_font) xv_find(ttysw, FONT, FONT_NAME,
  625.                  defaults_get_string("font.name", "Font.Name", "lucidasanstypewriter-12"),
  626.                  0);
  627.  
  628.     child_argv = (char **) malloc((argc + 1) * sizeof(char *));
  629.     if (!(child_argv[0] = (char *) getenv("JOVETOOL")))    /* Set jove command name */
  630.         child_argv[0] = jove_name;
  631.     for (child_argc = 1, i = argstart; i < argc; i++) {
  632.         if (!strcmp("-rc", argv[i])) {
  633.             child_argv[0] = argv[++i];
  634.             child_argc = 1;
  635.         } else {
  636.             child_argv[child_argc++] = argv[i];
  637.         }
  638.     }
  639.     child_argv[child_argc] = NULL;
  640.  
  641.     /*
  642.      * choose a "sensible" parameter to put in the icon label, preferably
  643.      * the file to be edited
  644.      */
  645.     icon_label = child_argv[0];
  646.     for (i = 1; i < child_argc; i++)
  647.         if (child_argv[i][0] != '-')
  648.             icon_label = child_argv[i];
  649.     frame_icon = icon_create(XV_LABEL, icon_label,
  650.                  ICON_IMAGE, &icon_image,
  651.                  0);
  652.  
  653.     /* construct the title of the window */
  654.     strcpy(buffer, title);
  655.     strncat(buffer, child_argv[0],    /* append run command name */
  656.         (BUFFER_SIZE - (strlen(buffer)) - (strlen(argv[0]))) - 1);
  657.  
  658.     /* Build a frame to run in */
  659.     frame = xv_create(XV_NULL, FRAME,
  660.               XV_LABEL, buffer,
  661.               FRAME_ICON, frame_icon,
  662.               0);
  663.     /* construct the command parameters to be shown to Save Workspace */
  664.     buffer[0] = '\0';
  665.     for (i = 1; i < argc; i++)
  666.         sprintf(&buffer[strlen(buffer)], "%s ", argv[i]);
  667.     xv_set(frame, WIN_CMD_LINE, buffer, 0);
  668.  
  669.     /* Create a tty with jove in it */
  670.     ttysw = xv_create(frame, TERMSW,
  671.               TTY_ARGV, TTY_ARGV_DO_NOT_FORK,
  672.               XV_LEFT_MARGIN, defaults_get_integer(
  673.                  "text.margin.left", "Text.Margin.Left", 4),
  674.               XV_RIGHT_MARGIN, defaults_get_integer(
  675.                    "text.margin.right", "Text.Margin.Right", 0),
  676.     /* 0 because jove never uses the last column anyway */
  677.               TEXTSW_FONT, font,
  678.               0);
  679.  
  680.     ttyview = xv_get(ttysw, OPENWIN_NTH_VIEW, 0);
  681.     left_margin = xv_get(ttysw, XV_LEFT_MARGIN);
  682.     right_margin = xv_get(ttysw, XV_RIGHT_MARGIN);
  683.     font_height = (int) xv_get(ttysw, WIN_ROW_HEIGHT);
  684.     font_width = (int) xv_get(ttysw, WIN_COLUMN_WIDTH);
  685.  
  686.     tty_fd = (int) xv_get(ttysw, TTY_TTY_FD);
  687.     tcgetattr(tty_fd, &tty);
  688.     tty.c_iflag &= ~ISTRIP;
  689.     tcsetattr(tty_fd, TCSANOW, &tty);
  690.     /* "TTY_ARGV, child_argv" must not be set going before that tcsetattr */
  691.  
  692.     xv_set(ttysw, TERMSW_MODE, TTYSW_MODE_TYPE,
  693.            TTY_QUIT_ON_CHILD_DEATH, TRUE,
  694.            TTY_ARGV, child_argv,
  695.            OPENWIN_ADJUST_FOR_VERTICAL_SCROLLBAR, 0,
  696.            XV_WIDTH, defaults_get_integer(
  697.             "window.columns", "Window.Columns", 80) * font_width
  698.            + left_margin + right_margin + 2,
  699.     /*
  700.      * WIN_COLUMNS was not used here because it gets confused by the
  701.      * non-existent scrollbar; the '+ 2' is one pixel for each border
  702.      */
  703.            WIN_ROWS, defaults_get_integer(
  704.                       "window.rows", "Window.Rows", 35),
  705.            0);
  706.  
  707.  
  708.     xv_set(ttyview,
  709.            WIN_CONSUME_EVENTS,
  710.         WIN_ASCII_EVENTS, WIN_META_EVENTS,
  711.         WIN_MOUSE_BUTTONS, WIN_UP_EVENTS,
  712.         LOC_DRAG,
  713.         SHIFT_LEFT, SHIFT_RIGHT, SHIFT_CTRL, SHIFT_META,
  714.         WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS,
  715.         0,
  716.            WIN_COLLAPSE_EXPOSURES, FALSE,
  717.            0);
  718.  
  719.     default_cursor = xv_get(ttyview, WIN_CURSOR);
  720.     jove_cursor = xv_create(XV_NULL, CURSOR,
  721.                 CURSOR_IMAGE, &cursor_pix,
  722.                 CURSOR_XHOT, 8,
  723.                 CURSOR_YHOT, 8,
  724.                 0);
  725.     cut_cursor = xv_create(XV_NULL, CURSOR,
  726.                    CURSOR_IMAGE, &cut_pix,
  727.                    CURSOR_XHOT, 8,
  728.                    CURSOR_YHOT, 8,
  729.                    0);
  730.     copy_cursor = xv_create(XV_NULL, CURSOR,
  731.                 CURSOR_IMAGE, ©_pix,
  732.                 CURSOR_XHOT, 8,
  733.                 CURSOR_YHOT, 8,
  734.                 0);
  735.     paste_cursor = xv_create(XV_NULL, CURSOR,
  736.                  CURSOR_IMAGE, &paste_pix,
  737.                  CURSOR_XHOT, 8,
  738.                  CURSOR_YHOT, 8,
  739.                  0);
  740.     set_cursor(jove_cursor);
  741.  
  742.     /* Interpose my event function */
  743.     error_code =
  744.         (int) notify_interpose_event_func
  745.         (ttyview, input_event_filter_function, NOTIFY_SAFE) +
  746.         (int) notify_interpose_event_func
  747.         (ttysw, tty_event_filter_function, NOTIFY_SAFE);
  748.     if (error_code != 0) {    /* Barf */
  749.         fprintf(stderr, "notify_interpose_event_func got %d.\n", error_code);
  750.         exit(1);
  751.     }
  752.     menu_init();
  753.  
  754.     bind_function_keys((KeySym)XK_L1, 10, 192);
  755.     bind_function_keys((KeySym)XK_Help, 1, 202);
  756.     bind_function_keys((KeySym)XK_F1, 10, 224);
  757. #ifdef SunXK_F36
  758.     bind_function_keys((KeySym)SunXK_F36, 2, 234);    /* for Suns only */
  759. #endif
  760.     bind_function_keys((KeySym)XK_R1, 15, 208);
  761.     /*
  762.      * But note that the keys R7-R15 are intercepted by XView which
  763.      * imposes its own bindings
  764.      */
  765.     bind_function_keys((KeySym)XK_Insert, 1, 247);
  766.     bind_function_keys((KeySym)XK_KP_0, 1, 247);
  767.     bind_function_keys((KeySym)XK_KP_Decimal, 1, 249);
  768.     bind_function_keys((KeySym)XK_KP_Enter, 1, 250);
  769.     bind_function_keys((KeySym)XK_KP_Add, 1, 253);
  770.     bind_function_keys((KeySym)XK_KP_Subtract, 1, 254);
  771.  
  772.     window_fit(frame);
  773.     window_main_loop(frame);/* And away we go */
  774.     return 0;        /* if this is ever reached */
  775. }
  776.