home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / emacs-18.59-src.tgz / emacs-18.59-src.tar / fsf / emacs18 / etc / emacstool.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  17KB  |  521 lines

  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. <peck@eng.sun.com>
  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 */
  521.