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

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