home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cweb28.zip / examples / oemacs.w < prev    next >
Text File  |  1992-10-03  |  38KB  |  898 lines

  1. \datethis
  2.  
  3. @* Introduction.
  4. This program provides an interface between the GNU Emacs editor and the
  5. OpenWindows environment, using the XView toolkit for interactive graphics.
  6. It is based on \.{emacstool}, a SunView interface written by Jeff Peck
  7. of Sun Microsystems in 1986 and adapted by him in 1988 to \.{xvetool},
  8. an early XView interface. The present code, by Don Knuth, is designed to work
  9. with OpenWindows Version~3 as distributed in 1992, using a Sun Type~4
  10. keyboard.
  11.  
  12. GNU Emacs is a highly portable and versatile program, which does most
  13. of the hard work involved in editing files. Our job is simply twofold:
  14. To get \.{emacs} started in an appropriate window, and to transmit
  15. keyboard and mouse events as sequences of characters that \.{emacs}
  16. can happily consume.  These simple tasks do, however, require us to
  17. get a lot of fussy details right. In fact, this program could not have been
  18. written without a good deal more knowledge about XView than can be found
  19. in the manuals. Fortunately Jeff Peck works for Sun, and his
  20. inside knowledge has provided the necessary clues. (All complaints below
  21. about the XView documentation are based on the reference manuals and
  22. programming manuals available from Sun and from O'Reilly \AM\ Associates, in
  23. the summer of 1992. Let us hope that such problems will not persist;
  24. computer programming should be fun, but some of the code below was
  25. written only after a bitter struggle!)
  26.  
  27. The command-line arguments to \.{oemacs} are either standard XView
  28. arguments, which specify the font and the size and position of the window,
  29. the icon, the colors, etc.; or they are standard arguments of \.{emacs},
  30. which typically specify the file to be edited and a position in that file.
  31. If I decide later to make certain things in \.{oemacs} less hardwired,
  32. I will look for options in the X resource database instead of on the
  33. command line.
  34.  
  35. An important note about using \.{xmodmap} to change the behavior of
  36. certain keys appears below. It makes \.{emacs} more powerful, unless you
  37. have other good uses for those keys. (See the entry for \.{xmodmap}
  38. in the index.)
  39.  
  40. Before using \.{oemacs}, you must compile \.{emacs} with the
  41. \.{sunfns} module (which the \.{Makefile} will do for you if you've
  42. configured it correctly), and you should include the lines
  43. $$\vbox{\halign{\.{#}\hfil\cr
  44. (load-library "sun-mouse")\cr
  45. (load-library "sun-fns")\cr}}$$
  46. in Emacs's file \.{lisp/site-init.el}.
  47.  
  48. Caution: This program was developed and tested with Peck's improved
  49. versions of sun-mouse and sun-fns; these are available from
  50. \.{peck@@sun.com} if not yet part of the GNU distribution.
  51.  
  52. @i xview_types.w
  53.  
  54. @ We follow the traditional structure of XView applications. The |exit|
  55. statement at the end is important, because \.{oemacs} can be invoked by
  56. the \.{system} command in \TeX\ (when the user has typed \.e in response
  57. to an error message); without |exit(0)|, \TeX\ would complain of trouble
  58. executing this program, although we would simply be terminating the program
  59. without returning any particular value.
  60.  
  61. @c
  62. @<Include header files@>@;
  63. @#
  64. Frame frame; /* the base frame where we will live */
  65. @<Global variables@>@; /* additional globals besides |frame| */
  66. @#
  67. @<Event-handling procedures@>@;
  68. @#
  69. main(argc,argv)
  70.   int argc;@+char *argv[]; /* typical \UNIX\ setup */
  71. {
  72.   @<Special initialization@>;
  73.   @<Install the components and controls of |frame|@>;
  74.   xv_main_loop(frame);
  75.   exit(0);
  76. }
  77.  
  78. @ Including the header file \.{<xview/xview.h>} also causes other
  79. basic header files like \.{<xview/frame.h>}, \.{<xview/icon.h>}, etc.,
  80. to be loaded. We must call the \Cee\ compiler with the flag
  81. \.{-I\$(OPENWINHOME)/include} so that the \Cee\ preprocessor will
  82. find the OpenWindows header files.
  83.  
  84. Some \UNIX\ systems define string functions in \.{<string.h>}, some in
  85. \.{<strings.h>}; the Sun documentation calls for \.{<string.h>}. My
  86. experiments indicate that Sun's compiler and loader work perfectly
  87. well with string functions even when no header files are given, so the
  88. programmer doesn't really have to remember the right name. Similarly,
  89. \.{<stdio.h>} isn't really needed with Sun's \Cee, unless certain macros
  90. are used. I'll include \.{<string.h>} and \.{<stdio.h>} anyway, in the
  91. spirit of being obedient to the stated rules.
  92.  
  93. @<Include...@>=
  94. #include <string.h>
  95. #include <stdio.h>
  96. #include <xview/xview.h>
  97.  
  98. @* The icon and frame.
  99. First we attach an icon that will appear if the user closes the \.{oemacs}
  100. window later.
  101.  
  102. There are two reasons for doing this first. One is that we might as well
  103. begin with an easy task, in order to get warmed up. The other is that
  104. if we specify the icon {\it after\/} creating the frame, we will unconditionally
  105. override an icon that the user may have specified with the \.{-WI}
  106. option on the command line. (This is one of the little things a
  107. programmer has to turn by trial and error, since the XView documentation
  108. leaves much unsaid.)
  109.  
  110. The colors used in the icon will be inherited from the frame, so they will
  111. be reversed if the user asks for reverse video. I~prefer to have the icon
  112. always in black on a yellow background, so I'm making the color explicit.
  113. (I hope this will work on monochrome displays; it works fine on my
  114. grayscale monitor.)
  115.  
  116. @<Create a frame with the gnu icon@>=
  117. {@+Server_image icon_image=(Server_image)xv_create(NULL,SERVER_IMAGE,@|
  118.        XV_WIDTH,64,XV_HEIGHT,64,SERVER_IMAGE_BITS,icon_bits,NULL);
  119.   Server_image mask_image=(Server_image)xv_create(NULL,SERVER_IMAGE,@|
  120.        XV_WIDTH,64,XV_HEIGHT,64,SERVER_IMAGE_BITS,mask_bits,NULL);
  121.   Cms cms=(Cms)xv_create(NULL,CMS,CMS_SIZE,2,@|
  122.         CMS_NAMED_COLORS,"yellow","black",NULL,NULL);
  123.   Icon icon=(Icon)xv_create(NULL,ICON,@|
  124.        ICON_IMAGE,icon_image,ICON_MASK_IMAGE,mask_image,@|
  125.        WIN_CMS,cms,NULL);
  126.   frame=xv_create(NULL,FRAME,FRAME_ICON,icon,NULL);
  127. }
  128.  
  129. @ @<Include...@>=
  130. #include <xview/cms.h>
  131.  
  132. @ If the user hasn't specified a label with the \.{-Wl} option, we turn off
  133. the header line at the top of the frame. That gives us a chance to see
  134. two more lines of the file \.{emacs} is editing. However, we add a
  135. label of our own; it will show up in the virtual window manager display.
  136.  
  137. @<Remove the frame header, unless the user has specifically requested it@>=
  138. if (xv_get(frame,XV_LABEL)==NULL) /* no label specified */
  139.   xv_set(frame,FRAME_SHOW_HEADER,FALSE,XV_LABEL,"OEMACS",NULL);
  140.  
  141. @ The following icon and mask are derived from the ``what's gnu'' image on the
  142. back cover of the GNU Emacs manual. (This accounts for my black-on-yellow
  143. preference.)
  144.  
  145. @<Global...@>=
  146. unsigned short icon_bits[]={@|
  147.     0x0000,    0x0000,    0x0000,    0x1E00,
  148.     0x0000,    0x0000,    0x0000,    0x0900,@|
  149.     0x001E,    0x0000,    0x0000,    0x0880,
  150.     0x0064,    0x0000,    0x0000,    0x0440,@|
  151.     0x0088,    0x0000,    0x0000,    0x0420,
  152.     0x0110,    0x0000,    0x0000,    0x0210,@|
  153.     0x0220,    0x0000,    0x0000,    0x0210,
  154.     0x0420,    0x0FCF,    0x01C0,    0x0108,@|
  155.     0x0840,    0x1030,    0x8620,    0x0088,
  156.     0x1080,    0x00C0,    0x5810,    0x0084,@|
  157.     0x1080,    0x1F00,    0x2008,    0x0044,
  158.     0x2100,    0xE200,    0x1004,    0x0044,@|
  159.     0x4103,    0x0400,    0x0002,    0x0042,
  160.     0x4204,    0x080E,    0x0001,    0x0042,@|
  161.     0x8200,    0x7830,    0x0020,    0x8082,
  162.     0x8203,    0x9040,    0x0018,    0x4102,@|
  163.     0x8204,    0x2080,    0x07C6,    0x3E04,
  164.     0x8108,    0x410C,    0x0021,    0x8004,@|
  165.     0x8080,    0x8210,    0x03D0,    0x6008,
  166.     0x4041,    0x0420,    0x0008,    0x1810,@|
  167.     0x403E,    0x0820,    0x0FFC,    0x0620,
  168.     0x2000,    0x1040,    0x0002,    0x01C0,@|
  169.     0x1000,    0x608C,    0x0FFF,    0x0060,
  170.     0x0801,    0x8110,    0x0080,    0x8118,@|
  171.     0x0406,    0x0220,    0x1FFF,    0x66E0,
  172.     0x0238,    0x044F,    0x0000,    0xD800,@|
  173.     0x01C0,    0x0890,    0x8FFF,    0x4000,
  174.     0x0300,    0x10A6,    0x4041,    0x6000,@|
  175.     0x1C00,    0x2026,    0x4FFF,    0x6000,
  176.     0x60CC,    0x4026,    0x4001,    0x6000,@|
  177.     0x1F33,    0x8010,    0x8FFF,    0x4000,
  178.     0x0012,    0x000F,    0x0040,    0xC000,@|
  179.     0x0022,    0x4000,    0x07FF,    0x4000,
  180.     0x0024,    0x4000,    0x0000,    0x2000,@|
  181.     0x0024,    0x4818,    0x8FFF,    0xE000,
  182.     0x0024,    0x4907,    0x0040,    0x2000,@|
  183.     0x0044,    0x4900,    0x1FFF,    0xE000,
  184.     0x0044,    0x4900,    0x0000,    0x2000,@|
  185.     0x0044,    0x4900,    0x07FF,    0xE000,
  186.     0x0044,    0x4880,    0x0020,    0x2000,@|
  187.     0x0044,    0x4880,    0x07FF,    0xE000,
  188.     0x0044,    0x4840,    0x0000,    0x2000,@|
  189.     0x0044,    0x2A20,    0x07FF,    0xE000,
  190.     0x0044,    0x2410,    0x0020,    0x2000,@|
  191.     0x0042,    0x2448,    0x0FFF,    0xE000,
  192.     0x0042,    0x2948,    0x0000,    0x2000,@|
  193.     0x0041,    0x1144,    0x07FF,    0xA000,
  194.     0x0041,    0x1144,    0x2010,    0x1000,@|
  195.     0x0021,    0x1126,    0x20FA,    0x1000,
  196.     0x0024,    0x8925,    0x2600,    0x1000,@|
  197.     0x0014,    0x8924,    0xA138,    0x7000,
  198.     0x0016,    0x88A4,    0x9090,    0x6000,@|
  199.     0x000A,    0x44A4,    0x4880,    0xA000,
  200.     0x0002,    0x44A2,    0x4401,    0x2000,@|
  201.     0x0003,    0x4492,    0x2001,    0x4000,
  202.     0x0001,    0x2451,    0x3002,    0x8000,@|
  203.     0x0000,    0xA251,    0x1E05,    0x0000,
  204.     0x0000,    0x2248,    0xA1F9,    0x8000,@|
  205.     0x0000,    0x1648,    0x9002,    0x8000,
  206.     0x0000,    0x1A28,    0x4C02,    0x8000,@|
  207.     0x0000,    0x1220,    0x43FC,    0x8000,
  208.     0x0000,    0x0120,    0x2000,    0x8000,@|
  209.     0x0000,    0x0120,    0x2003,    0x0000,
  210.     0x0000,    0x0150,    0x1FFC,    0x0000
  211. };
  212. unsigned short mask_bits[]={@|
  213.     0x0000,    0x0000,    0x0000,    0x1E00,
  214.     0x0000,    0x0000,    0x0000,    0x0F00,@|
  215.     0x001E,    0x0000,    0x0000,    0x0F80,
  216.     0x007C,    0x0000,    0x0000,    0x07C0,@|
  217.     0x00F8,    0x0000,    0x0000,    0x07E0,
  218.     0x01F0,    0x0000,    0x0000,    0x03F0,@|
  219.     0x03E0,    0x0000,    0x0000,    0x03F0,
  220.     0x07E0,    0x0FCF,    0x01C0,    0x01F8,@|
  221.     0x0FC0,    0x103F,    0x87F0,    0x00F8,
  222.     0x1F80,    0x00FF,    0xDFF0,    0x00FC,@|
  223.     0x1F80,    0x1FFF,    0xFFF8,    0x007C,
  224.     0x3F00,    0xE3FF,    0xFFFC,    0x007C,@|
  225.     0x7F03,    0x07FF,    0xFFFE,    0x007E,
  226.     0x7E04,    0x0FFF,    0xFFFF,    0x007E,@|
  227.     0xFE00,    0x7FFF,    0xFFFF,    0x80FE,
  228.     0xFE03,    0x9FFF,    0xFFFF,    0xC1FE,@|
  229.     0xFE04,    0x3FFF,    0xFFFF,    0xFFFC,
  230.     0xFF08,    0x7FFF,    0xFFFF,    0xFFFC,@|
  231.     0xFF80,    0xFFFF,    0xFFFF,    0xFFF8,
  232.     0x7FC1,    0xFFFF,    0xFFFF,    0xFFF0,@|
  233.     0x7FFF,    0xFFFF,    0xFFFF,    0xFFE0,
  234.     0x3FFF,    0xFFFF,    0xFFFF,    0xFFC0,@|
  235.     0x1FFF,    0xFFFF,    0xFFFF,    0xFFE0,
  236.     0x0FFF,    0xFFFF,    0xFFFF,    0xFFF8,@|
  237.     0x07FF,    0xFFFF,    0xFFFF,    0xFEE0,
  238.     0x03FF,    0xFFFF,    0xFFFF,    0xF800,@|
  239.     0x01FF,    0xFFFF,    0xFFFF,    0xE000,
  240.     0x03FF,    0xFFFF,    0xFFFF,    0xE000,@|
  241.     0x1FFF,    0xFFFF,    0xFFFF,    0xE000,
  242.     0x7FFF,    0xFFFF,    0xFFFF,    0xE000,@|
  243.     0x1F7F,    0xFFFF,    0xFFFF,    0xC000,
  244.     0x001F,    0xFFFF,    0xFFFF,    0xC000,@|
  245.     0x003F,    0xFFFF,    0xFFFF,    0xC000,
  246.     0x003F,    0xFFFF,    0xFFFF,    0xE000,@|
  247.     0x003F,    0xFFFF,    0xFFFF,    0xE000,
  248.     0x003F,    0xFFFF,    0xFFFF,    0xE000,@|
  249.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  250.     0x007F,    0xFFFF,    0xFFFF,    0xE000,@|
  251.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  252.     0x007F,    0xFFFF,    0xFFFF,    0xE000,@|
  253.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  254.     0x007F,    0xFFFF,    0xFFFF,    0xE000,@|
  255.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  256.     0x007F,    0xFFFF,    0xFFFF,    0xE000,@|
  257.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  258.     0x007F,    0xFFFF,    0xFFFF,    0xE000,@|
  259.     0x007F,    0xFFFF,    0xFFFF,    0xE000,
  260.     0x007F,    0xFFFF,    0xFFFF,    0xF000,@|
  261.     0x003F,    0xFFFF,    0xFFFF,    0xF000,
  262.     0x003F,    0xFFFF,    0xFFFF,    0xF000,@|
  263.     0x001F,    0xFFFF,    0xFFFF,    0xF000,
  264.     0x001F,    0xFFFF,    0xFFFF,    0xE000,@|
  265.     0x000B,    0xFFFF,    0xFFFF,    0xE000,
  266.     0x0003,    0xFFFF,    0xFFFF,    0xE000,@|
  267.     0x0003,    0xFFFF,    0xFFFF,    0xC000,
  268.     0x0001,    0xFFFF,    0xFFFF,    0x8000,@|
  269.     0x0000,    0xBFF1,    0xFFFF,    0x0000,
  270.     0x0000,    0x3FF8,    0xFFFF,    0x8000,@|
  271.     0x0000,    0x1FF8,    0xFFFF,    0x8000,
  272.     0x0000,    0x1FF8,    0x7FFF,    0x8000,@|
  273.     0x0000,    0x13E0,    0x7FFF,    0x8000,
  274.     0x0000,    0x01E0,    0x3FFF,    0x8000,@|
  275.     0x0000,    0x01E0,    0x3FFF,    0x0000,
  276.     0x0000,    0x0150,    0x1FFC,    0x0000
  277. };
  278.  
  279. @* Emulating a terminal.
  280. We will run \.{emacs} in a ``tty subwindow,'' named after the teletype
  281. terminals of ancient yore.
  282.  
  283. The |argv| array will be a command line that invokes
  284. \.{emacs} with all arguments not removed by |xv_init|, i.e., all arguments
  285. that remain after generic XView arguments have been removed.
  286.  
  287. We have to say |WIN_IS_CLIENT_PANE|, otherwise fonts specified on the
  288. command line will be ignored. (This cryptic instruction is mentioned briefly
  289. in the XView reference manual, but not in the XView programming manual;
  290. I~would never have discovered it without Jeff Peck's help.)
  291.  
  292. We also have to set |TTY_QUIT_ON_CHILD_DEATH| to |TRUE|. Otherwise when
  293. \.{emacs} exits (via control-X, control-C) there still will be a terminal
  294. window (into which we can type but not access the shell).
  295.  
  296. Before starting \.{emacs} we set the environment variable
  297. \.{TERM} equal to \.{sun}.
  298. This will tell \.{emacs} to initialize itself with the
  299. programs in its source file \.{lisp/term/sun.el}, where special
  300. adaptations for Sun-style terminals have been recorded.
  301.  
  302. @<Put a tty subwindow into the frame@>=
  303. argv[0]="emacs";
  304. putenv("TERM=sun");
  305. tty=(Tty)xv_create(frame,TTY,WIN_IS_CLIENT_PANE,@|
  306.       TTY_QUIT_ON_CHILD_DEATH,TRUE,@|
  307.       TTY_ARGV,argv,NULL);
  308.  
  309. @ @<Global...@>=
  310. Tty tty;
  311.  
  312. @ @<Include...@>=
  313. #include <xview/tty.h>
  314.  
  315. @ The XView manual doesn't tell us that tty subwindows have a view part
  316. and a pseudo-terminal part. (The manual does mention briefly that text
  317. subwindows have views---at the beginning of section 6.3, and indirectly in
  318. one of the examples in the chapter on color.)
  319.  
  320. The view window of an emulated tty will receive keyboard and
  321. mouse events. We need to know its ``handle,'' because we want to
  322. modify XView's default interpretation of many of those events.
  323.  
  324. For example, we want to grab the keyboard focus (i.e., to begin receiving
  325. keyboard input) as soon as the user moves the mouse into the \.{emacs}
  326. window. The normal OpenLook default requires a user to click in the window
  327. first, but that is inefficient in a production book-writing environment.
  328. Us \.{emacs} users would rather type than point.
  329.  
  330. A secret incantation makes the view window accessible. Dear reader,
  331. would you have guessed how to do this, from reading the manuals only,
  332. without looking at Jeff Peck's code? Be honest now.
  333.  
  334. We don't have to enable the notification of other kinds of events;
  335. tty subwindows already do that.
  336.  
  337. @<Prepare to be notified when the mouse enters the window@>=
  338. window=(Xv_window)xv_get(tty,OPENWIN_NTH_VIEW,0);
  339. xv_set(window,WIN_CONSUME_EVENT,LOC_WINENTER,NULL);
  340.  
  341. @ @<Global...@>=
  342. Xv_window window; /* the view window of |tty| */
  343.  
  344. @ If the user has specified reverse video with the \.{-rv} option,
  345. we will reverse black and white in the mouse cursor. This will make it
  346. more visible against a black background.
  347.  
  348. Changing the cursor is another undocumented reason why we need to know
  349. about the tty's view window; nothing changes if we try to attach
  350. the new cursor to |frame| or to |tty| instead of to |window|.
  351.  
  352. @<Change the cursor, to avoid black-on-black@>=
  353. if (rv) {Xv_singlecolor white,black;
  354.   Xv_cursor cursor;
  355.   white.red=white.green=white.blue=255;
  356.   black.red=black.green=black.blue=0;
  357.   cursor=(Xv_cursor)xv_create(NULL,CURSOR,@|
  358.     CURSOR_SRC_CHAR,OLC_BASIC_PTR,CURSOR_MASK_CHAR,OLC_BASIC_MASK_PTR,@|
  359.     CURSOR_FOREGROUND_COLOR,&white,CURSOR_BACKGROUND_COLOR,&black,NULL);
  360.   xv_set(window,WIN_CURSOR,cursor,NULL);
  361. }
  362.  
  363. @ @<Include...@>=
  364. #include <xview/cursor.h> /* we're using the cursor package */
  365.  
  366. @ What is the variable |rv| that was tested in the code above? Good question.
  367. We have to scan for \.{-rv} before |xv_init| looks at the command arguments.
  368.  
  369. @<Scan the command line, setting |rv| nonzero if \.{-rv} is present@>=
  370. rv=0;
  371. {@+int k=argc;
  372.   while (--k>0) if (strcmp(argv[k],"-rv")==0 ||
  373.                      strcmp(argv[k],"-reverse")==0) rv=1;
  374. }
  375.  
  376. @ @<Global...@>=
  377. int rv;
  378.  
  379. @ We need to know the height and width of characters in the font, in order
  380. to convert mouse positions into coordinates that \.{emacs} will like.
  381. If the user has specified a font explicitly, the font will presumably have
  382. a fixed width for all characters; we can learn the relevant dimensions
  383. by calling |xv_get|. But if the user has not specified a font, the
  384. situation is trickier; |xv_get| will report the width of the default
  385. {\it non\/}-fixed-width font, and this will probably differ from the width of
  386. the actual fixed-width font the tty subwindow will choose.
  387.  
  388. Curiously, if we call |xv_find(NULL,FONT,FONT_FAMILY,
  389. FONT_FAMILY_DEFAULT_FIXEDWIDTH,NULL)| {\it before\/} calling |xv_init|,
  390. without even doing anything with the result returned by |xv_find|,
  391. |xv_init| will not install any fonts specified on the command line.
  392. The trick we used for icons---installing the default gnu icon on the first
  393. call to |xv_create|---will therefore fail.
  394.  
  395. Thus, we have to work around two distinct bugs in XView. The solution
  396. is to discover the effects of the user's command line after |xv_init|
  397. has acted and the frame has been set up; we can determine by brute force what
  398. font will go into the tty window. The program below works correctly
  399. even if the command line specifies \.{-scale} \.{large}, say, instead of
  400. specifying a new font explicitly by something like \.{-font} \.{9x15}.
  401.  
  402. While we are cataloguing peculiarities of XView, we might as well mention
  403. that the default character dimensions of the default font (Lucida) are
  404. reported to be $8\times13$ in the 12-point (medium) size, $8\times15$ in the
  405. 14-point (large) size, and $12\times20$ in the 19-point (extralarge) size.
  406. The actual character dimensions in the window come, however, from the
  407. default fixed-width font (Lucida typewriter), and they are $7\times13$,
  408. $9\times15$, and $11\times23$ in the same three sizes. No logical progression
  409. is evident in either the variable-width or the fixed-width dimensions,
  410. although Lucida is a ``scalable font family.''
  411.  
  412. @<Compute the height and width of characters in the font@>=
  413. {
  414.   Xv_font font=(Xv_font)xv_get(frame,XV_FONT);
  415.   Xv_font dfont=(Xv_font)xv_find(NULL,FONT,FONT_FAMILY,
  416.      FONT_FAMILY_DEFAULT,NULL);
  417.   if (strcmp((char*)xv_get(font,FONT_NAME),
  418.              (char*)xv_get(dfont,FONT_NAME))==0) {
  419.     /* the user didn't specify a new font by name */
  420.     dfont=(Xv_font)xv_find(NULL,FONT,FONT_FAMILY,
  421.       FONT_FAMILY_DEFAULT_FIXEDWIDTH,NULL);
  422.         /* this one will be used by the tty window */
  423.   } else dfont=font;
  424.   char_width=(int)xv_get(dfont,FONT_DEFAULT_CHAR_WIDTH);
  425.   char_height=(int)xv_get(dfont,FONT_DEFAULT_CHAR_HEIGHT);
  426. }
  427.  
  428. @ @<Global...@>=
  429. int char_width, char_height; /* character dimensions in the font */
  430.  
  431. @ @<Include...@>=
  432. #include <xview/font.h> /* header for the font package */
  433.  
  434. @ OK, we've figured out how to install a tty subwindow with the right
  435. event mask and the right cursor, and how to calculate the sizes of the
  436. characters it will contain. All that remains is for us to do these
  437. operations in the proper order, and to specify a filter routine that
  438. will monitor and edit all communications between the keyboard and the
  439. Emacs processor in the window.
  440.  
  441. The new ingredient is the filter specification. We tell the XView
  442. notifier to call |filter| when a window event occurs, instead of
  443. letting it call the tty subroutine event handler directly. The parameter
  444. |NOTIFY_SAFE| implies that the window's event handler is
  445. part of XView, not an alien routine.
  446.  
  447. @<Install the components...@>=
  448. @<Scan the command line, setting |rv| nonzero if \.{-rv} is present@>;
  449. xv_init(XV_INIT_ARGC_PTR_ARGV,&argc,argv,NULL);
  450.       /* start XViewing; strip and remember the OpenWin arguments */
  451. @<Create a frame with the gnu icon@>;
  452. @<Remove the frame header...@>;
  453. @<Put a tty subwindow into the frame@>;
  454. @<Prepare to be notified when the mouse enters the window@>;
  455. @<Change the cursor, to avoid black-on-black@>;
  456. @<Compute the height and width of characters in the font@>;
  457. notify_interpose_event_func(window,filter,NOTIFY_SAFE);
  458.  
  459. @* Keyboard events.
  460. The job of an interposed filter function is to look at an event and
  461. either process it ourselves or pass it through (possibly modified)
  462. to its normal recipient. In the first case we return the code
  463. value |NOTIFY_DONE|, since we aren't reporting any errors;
  464. in the second case we call the normal event handler and return the value
  465. it returns to us.
  466.  
  467. An XView event is a data structure that has been partially
  468. interpreted by the XView routines, which add semantic sugar to
  469. the complex union type of X~Window events. We need not look
  470. too far inside an event structure to do the things that concern us.
  471.  
  472. And what is our job? We are looking for three different kinds of events:
  473.  
  474. \smallskip
  475. \itemitem{(1)} When the mouse enters the window,
  476. we want to grab the keyboard focus.
  477.  
  478. \itemitem{(2)} When a mouse button goes up or down, and we have the keyboard
  479. focus, we want to send a coded sequence of characters to \.{emacs}.
  480.  
  481. \itemitem{(3)} When a key goes down, and we have the keyboard focus, we
  482. want to send an appropriate sequence of characters to \.{emacs}.
  483.  
  484. \itemitem{(4)} When the status of the Num Lock indicator light changes, we
  485. will send emacs the command {\tt turn-numlock-on} or {\tt turn-numlock-off},
  486. for reasons described below.
  487.  
  488. \smallskip\noindent Other events, like instructions to repaint or
  489. resize the window, will be passed through without change to the tty window.
  490.  
  491. @<Event-handling...@>=
  492. Notify_value filter(window,event,arg,type)
  493.   Xv_window window; /* the ``client'' on whom we interposed */
  494.   Event *event; /* the data we are filtering */
  495.   Notify_arg arg; /* optional communication parameter between clients */
  496.   Notify_event_type type; /* |NOTIFY_SAFE| or |NOTIFY_IMMEDIATE| */
  497. {@+register int id=event_id(event);
  498. #ifdef DEBUG
  499.   printf("event %d%s, action %d, shift %x, mouse(%d,%d)\n",
  500.     event_id(event),event_is_up(event)?"UP":"DOWN",event->action,
  501.          event_shiftmask(event),event_x(event),event_y(event));
  502. #endif
  503.   @<Update the Num Lock status@>;
  504.   if (id==LOC_WINENTER) @<Grab the keyboard focus and return@>;
  505.   if (event_is_button(event)) @<Translate a mouse event and return@>;
  506.   if (event_is_up(event)) return NOTIFY_DONE; /* key has been released */
  507.   @<Translate a function key into a special escape sequence@>;
  508.   @<Sanitize a keypress event so that unusual semantic actions are removed@>;
  509.   return notify_next_event_func(window,event,arg,type); /* pass it through */
  510. }
  511.  
  512. @ It's easy to take charge of the keyboard and mouse, as soon as the mouse
  513. enters our territory.
  514.  
  515. @<Grab...@>=
  516. {
  517.   win_set_kbd_focus(window,xv_get(window,XV_XID));
  518.   return NOTIFY_DONE;
  519. }
  520.  
  521. @ If the event is not related to mouse buttons or special function keys,
  522. we want to pass it on unchanged, unless its |event_id| is less than 128.
  523. In that case, it represents a character code, and we want to nuke any
  524. semantic ``keyboard acceleration'' actions it might have been assigned
  525. by OpenWindows.
  526.  
  527. We also make the Meta key add 128 here. An undocumented macro
  528. called |event_set_id|, found in \.{<xview/win\_input.h>},
  529. clears the |action| code as desired.
  530.  
  531. @<Sanitize...@>=
  532. if (id<128)
  533.   if (event_meta_is_down(event)) event_set_id(event,id+128);
  534.   else event_set_action(event,ACTION_NULL_EVENT);
  535.  
  536. @* Function keys.
  537. The Sun Type 4 keyboard has lots of keys, and these can be bound to lots
  538. of useful functions when we are \.{emacs}ing to the max. Besides the
  539. letters and punctuation marks of a normal typewriter, there are ten
  540. ``left'' function keys, L1--L10; twelve ``top'' function keys, F1--F12;
  541. fifteen ``right'' function keys, R1--R15; and eight additional keys
  542. labeled Help, Alt, AltGraph, Ins, Del, Enter, $+$, $-$, which we will
  543. pretend have been labeled B1--B8.
  544.  
  545. The L5 key, also known as Front, is controlled by the Open Look
  546. window manager; it makes a window rise above any that might overlap it,
  547. or shoves the window underneath in case it already was on top.
  548.  
  549. The L7 key, aka Open, is likewise preempted by the
  550. window manager. It closes a frame to an icon, or opens an icon.
  551.  
  552. The window manager traps the R2 key and calls it the ``language'' key;
  553. but I have no use for that feature. So I have remapped R2 to the comparatively
  554. useless character $3\over4$, and I will translate it back to R2 below. (The
  555. \.{xmodmap} program allows users to reassign the interpretation of key codes.)
  556. I could have recovered the L5 and L7 keys in the same way, but I like
  557. their functions as they stand. (L5 and L7 still come through if a
  558. Shift, Control, and/or Meta key is down.)
  559.  
  560. I can never remember the difference between Delete and BackSpace, so I
  561. have mapped them both into control-?, ASCII code 127.
  562.  
  563. There are two Shift keys, one at the left and one at the right, which
  564. are best kept indistinguishable from each other. Similarly, the left
  565. and right Meta keys (`\.{\char27}') are essentially identical. There's a
  566. Control key too. These three types of modifier keys generate keypress
  567. events, but we ignore them; the only thing that matters to us is whether
  568. they are currently up or down, when other keys are pressed.
  569.  
  570. \font\ttit=cmitt10
  571. There also are three special keys that do not generate events, so we
  572. never see them. The CapsLock key toggles the Caps Lock light and
  573. changes lowercase letters to uppercase when the light is on. The
  574. NumLock key toggles the Num Lock light and changes the interpretation
  575. of R4--R15 and B4--B8 when that light is on. The Compose key turns the
  576. Compose light on until you type two characters, then it produces a
  577. special symbol if those two characters match a pattern. For example,
  578. when Compose is followed by either \.{a"} or \.{"a} you get the 8-bit
  579. ISO code for {\tt \"a}; when Compose is followed by either \.{th} or
  580. \.{ht} you get the Icelandic thorn; when it's followed by \.{??} you get {\tt
  581. ?`}; \.{c/} and \.{L-} give \rlap{\./}\.c and {\ttit\char`\$}
  582. and so on. (A list of all composition patterns
  583. appears in \.{<X11/Suncompose.h>}, but not in any of the manuals
  584. I've seen.) The light goes off after two characters have been
  585. typed, or if your first character is not composable, or if
  586. you hit Compose again prematurely. If no proper two-character pattern
  587. was specified, only ``up'' events (key releases) are transmitted, and
  588. nothing will pass through to \.{emacs}.
  589.  
  590. One other feature is worth noting: The key between F12 and Delete
  591. produces a backslash `\.\\', or a vertical line `\.{\char125}' when
  592. shifted.  Everybody knows that, but even more is true. If you hold the
  593. AltGraph key down and press this key, it turns out that you get the
  594. broken-bar character `{\tt\hbox to1em{\hss\vbox{\hrule width 1pt height
  595. 3pt\vskip1.5pt\hrule height2pt depth1pt}\hss}}'.  This is the only key that the
  596. engineers chose to endow with three different graphic symbols.
  597.  
  598. A few other anomalies occur; for example, AltGraph-R1 gives ASCII null,
  599. while AltGraph does not affect R4. But I didn't discover any additional
  600. combinations that are either useful or harmful.
  601.  
  602. Once upon a time the Caps Lock key might have affected the |event_shiftmask|
  603. field of an event, but it has no effect now. The shiftmask is always an
  604. even number, contrary to the implications of \.{<xview/win\_input.h>}.
  605.  
  606. @ The function keys will be translated into a four-character code.
  607. First comes control-X; then an asterisk; then a letter, \.{a}--\.{o}
  608. for function numbers 1--15, respectively; and then another letter,
  609. identifying left, right, top, or bottom. The final letter is
  610. ordinarily `\.l', `\.r', `\.t', or `\.b', respectively. But it is `\.L', `\.R',
  611. `\.T', or `\.B' if a Shift key is down. Furthermore the Control key
  612. subtracts 64 from the ASCII code, so you get `\.,', `\.2', `\.4', or
  613. `\."' with Control and no Shift. With both Control and Shift you get
  614. \.{\\C-L}, \.{\\C-R}, \.{\\C-T}, \.{\\C-B}. A Meta key adds another 128
  615. to the code.  Thus, each function key leads to eight possibilities.
  616.  
  617. For example, if F4 is pressed when Control and Shift are down, but not
  618. Meta, the four-letter code is \.{\\C-X*d\\C-T}. The user could type
  619. that sequence of four characters and get the same effect.
  620.  
  621. Shifted function keys sometimes have a nice mnemonic significance.
  622. For example, key R14, also labeled PgDn, is usually bound to the Emacs
  623. operation `\.{scroll-up}', which moves the window down [sic] by one
  624. screenful; we can then bind Shift-R14 to \.{forward-page}, which advances
  625. down to the next page boundary. In \.{cweb-mode}, the next page boundary
  626. is the next \.{@@*}, beginning a major part of the program. Similarly,
  627. it's convenient to bind B7, the keypad `\.+' key, to \.{forward-paragraph}.
  628. Then in \.{cweb-mode}, Shift-B7 goes to the next module (the next
  629. \.{@@\ } or \.{@@*}).
  630.  
  631. A Composed character will be preceded by \.{\\C-Q}, the Emacs `quote'
  632. character, to distinguish it from a character that was generated with the
  633. Meta key down. This also applies to the broken-bar character, which
  634. will incidentally be preceded by AltGraph, which is B3; you'll probably
  635. want to bind B3 to a no-op if broken bars are important to you.
  636.  
  637. @ This program assumes that several key codes have been rebound from
  638. their normal values. Namely, the commands
  639. $$\vbox{\halign{\.{#}\hfil\cr
  640. keysym R2 = threequarters\cr
  641. keysym KP\_Subtract = onehalf\cr
  642. keysym KP\_Add = onequarter\cr
  643. keysym KP\_Enter = threesuperior\cr
  644. keysym KP\_Decimal = twosuperior\cr
  645. keysym KP\_0 = onesuperior\cr}}$$
  646. should be executed by \.{xmodmap}, preferably in the user's \.{.xinitrc} file.
  647. This makes the keys act as $3\over4$, $1\over2$, $1\over4$, $^3$, $^2$, and
  648. $^1$, respectively. The corresponding 8-bit codes are respectively
  649. 190, 189, 188, 179, 178, 185. (By the way, can anybody explain why the ISO
  650. LATIN-1 code has $^0$, $^2$, and $^3$ in the positions of meta-0, meta-2,
  651. and meta-3, while $^1$ is in the position of meta-9?)
  652. @.xmodmap@>
  653.  
  654. We haven't actually bound the keys this way to use them in editing.
  655. We did it to provide linguistically unimportant codes that OpenWindows
  656. wouldn't mess up; its normal conventions make those valuable keys
  657. unusable for editing, except as duplicates for other existing keys.
  658.  
  659. We send \.{turn-numlock-on/off} commands so that \.{emacs} can keep in
  660. synch with the keyboard state. Namely, it will rebind the function
  661. keys B4--B8 to their numeric-keypad equivalents while the Num Lock light is on.
  662.  
  663. On the other hand, our remapping does make the Num Lock
  664. feature useless in other (non-Emacs) applications.  If you don't
  665. rebind the keys as stated, you lose the functionality of R2 and B4--B8,
  666. but \.{oemacs} will still work.
  667.  
  668. The Help key is another special case. We don't want to remap it,
  669. because it gives useful help information with other OpenWindows
  670. applications.  If Help is pressed without the shift or control key,
  671. the |event_id| is zero and the |event_action| is |ACTION_HELP|.
  672. Control-Help is similar, but with |ACTION_TEXT_HELP|. Shift-Help is
  673. more complicated; it invokes `helpopen: starting new Viewer', after
  674. generating an event that has |event_action=WIN_VISIBILITY_NOTIFY|. The
  675. program below considers the Help key B1 to be characterized by any
  676. event with |event_id=0| and either |event_action!=0| or
  677. |event_shiftmask!=CTRLMASK|.
  678.  
  679. @<Translate a function key into a special escape sequence@>=
  680. {@+register int bank='b'; /* |'l'|, |'r'|, |'t'|, or |'b'| */
  681.   register int n; /* function key serial number, |1<=n<=15| */
  682.   if (id>=KEY_LEFT(1)) @<Translate an ordinary function key@>@;
  683.   else if (id>=256) @<Look for Alt or AltGraph@>@;
  684.   else if (id>=128)
  685.     @<Translate a special function key or composed character@>@;
  686.   else if (id>0 ||
  687.           (event_action(event)==0 && event_shiftmask(event)==CTRLMASK))
  688.     goto non_function;
  689.   else n=1; /* Help key */
  690. emit_function_key:@<Emit the code for a function key and |return|@>;
  691. non_function:;
  692. }
  693.  
  694. @ I'm assuming here that the event id codes occur in the order left, right,
  695. top, bottom, and that no higher event codes exist.
  696.  
  697. @<Translate an ordinary function key@>=
  698. {
  699.   if (id<KEY_RIGHT(1)) { /* on the left bank */
  700.     bank='l';@+n=id-KEY_LEFT(0);
  701.   } else if (id<KEY_TOP(1)) { /* on the right bank */
  702.     bank='r';@+n=id-KEY_RIGHT(0);
  703.   } else if (id<KEY_BOTTOM(1)) {
  704.     bank='t';@+n=id-KEY_TOP(0);
  705.   } else n=id-KEY_BOTTOM(0);
  706.   goto emit_function_key;
  707. }
  708.  
  709. @ The event codes examined here appear in \.{<xview/win\_event.h>}
  710. but not in the XView reference manual.
  711.  
  712. @<Look for Alt or AltGraph@>=
  713. if (id==SHIFT_ALT) {
  714.   n=2;@+goto emit_function_key;
  715. } else if (id==SHIFT_ALTG) {
  716.   n=3;@+goto emit_function_key;
  717. } else goto non_function;
  718.  
  719. @ The |ttysw_input| routine sends text to a tty's view window.
  720. The second parameter is a string, not necessarily terminated by
  721. |'\0'| or anything else; the third parameter is the string length.
  722.  
  723. @<Emit the code for a function key and |return|@>=
  724. {
  725.   if (event_shift_is_down(event)) bank-=32;
  726.   if (event_ctrl_is_down(event)) bank-=64;
  727.   if (event_meta_is_down(event)) bank+=128;
  728.   buf[2]=n+'a'-1;
  729.   buf[3]=bank;
  730.   ttysw_input(window,buf,4);
  731.   return NOTIFY_DONE;
  732. }
  733.  
  734. @ @<Global...@>=
  735. char buf[]="\030*??\021"; /* |030| and |021| give control-X, control-Q */
  736.  
  737. @ @<Translate a special function key or composed character@>=
  738. switch (id) {
  739. case 190: bank='r';@+n=2;@+goto emit_function_key;
  740. case 189: n=8;@+goto emit_function_key;
  741. case 188: n=7;@+goto emit_function_key;
  742. case 179: n=6;@+goto emit_function_key;
  743. case 178: n=5;@+goto emit_function_key;
  744. case 185: n=4;@+goto emit_function_key;
  745. default: buf[5]=id; /* composed character or broken-bar */
  746.   ttysw_input(window,buf+4,2);
  747.   return NOTIFY_DONE;
  748. }
  749.  
  750. @* The NumLock key.
  751. The global variable |num_lock_state| will be 0 if the Num Lock indicator
  752. light is off, 1 if it is on. Whenever an event occurs, we check to see
  753. if |num_lock_state| should change; if so, we change it and send an
  754. appropriate command to \.{emacs}.
  755.  
  756. To read the state of the keyboard LED indicator lights, we need an I/O
  757. control command called the |KIOCGLED| ioctl, described on the
  758. man page for \.{kb(4m)}.
  759.  
  760. @<Global...@>=
  761. int num_lock_state;
  762. char turnon[]="\370turn-numlock-on\r", turnoff[]="\370turn-numlock-off\r";
  763. int keyboard; /* file descriptor of \.{/dev/kbd} */
  764.  
  765. @ @<Include...@>=
  766. #include <sys/file.h> /* definition of |O_RDWR| for |open| */
  767. #include <sundev/kbio.h> /* definition of |KIOCGLED| for |ioctl| */
  768.  
  769. @ @d LED_NUM_LOCK 0x1 /* the official definition is in \.{<server/sunevq.h>},
  770.     but that header file includes huge gobs of other stuff */
  771.  
  772. @<Update the Num Lock status@>=
  773. {@+char leds; /* binary encoding of LED lights */
  774.   ioctl(keyboard,KIOCGLED,&leds);
  775.   if ((leds&LED_NUM_LOCK)!=num_lock_state) {
  776.     num_lock_state=leds&LED_NUM_LOCK;
  777.     if (num_lock_state) ttysw_input(window,turnon,17);
  778.     else ttysw_input(window,turnoff,18);
  779.   }
  780. }
  781.  
  782. @ Any ordinary user can apparently open the keyboard as a file. I would
  783. have tried read-only access if read-write had failed; but read-write access
  784. gives a sense of power even though I won't be writing anything.
  785.  
  786. @<Special initialization@>=
  787. keyboard=open("/dev/kbd",O_RDWR);
  788. if (keyboard<0) {
  789.   fprintf(stderr,"%s: Can't open /dev/kbd!\n",argv[0]);
  790.   exit(1);
  791. }
  792.  
  793. @* Mouse events.
  794. When a mouse button is pressed or released, we send \.{emacs} the
  795. codes control-X and ASCII null, followed by a parenthesized list
  796. of four numbers and carriage-return.
  797. For example, as I was typing this paragraph, I
  798. clicked the left mouse button on the screen just for fun; \.{emacs}
  799. received the characters
  800. $$\.{\\030\\0(1 18 28 9999)\\r\\030\\0(129 18 28 141)\\r}$$
  801. as a result (according to `\.{view-lossage}'). I would have received
  802. the same response if I had typed these characters myself, instead
  803. of clicking the mouse.
  804.  
  805. The first of the four numbers identifies the mouse button itself
  806. as the code number 1, 2, or 4 (for left, middle, right), plus 8 if
  807. a Shift key is down, plus 16 if the Control key is down, plus 32
  808. if a Meta key is down, plus 128 if the mouse key is being released
  809. instead of pressed.
  810.  
  811. The second number is the row number in the frame, the top row being
  812. considered row~0.
  813.  
  814. The third number is the column number in the frame, the left column being
  815. considered column~0.
  816.  
  817. The fourth number is the elapsed time between this mouse event and the
  818. previous one, in milliseconds. If the elapsed time was 10 seconds or
  819. more, 9999 is substituted.
  820.  
  821. Macros inside \.{emacs} can use the second and third numbers to
  822. position the cursor. The fourth number can be used to determine if the
  823. user is ``double clicking'' or using ``chords.'' Examples of such
  824. macros appear in the Emacs source file \.{lisp/sun-mouse.el}.
  825.  
  826. Incidentally, the ASCII null character in mouse sequence makes us happy that
  827. the string parameter to |ttysw_input| is not null-terminated.
  828.  
  829. @<Translate a mouse event...@>=
  830. {@+register int button_code,elapsed_time;
  831.   button_code=(id==MS_LEFT? 1: id==MS_MIDDLE? 2: 4);
  832.   if (event_shift_is_down(event)) button_code += 8;
  833.   if (event_ctrl_is_down(event)) button_code += 16;
  834.   if (event_meta_is_down(event)) button_code += 32;
  835.   if (event_is_up(event)) button_code += 128;
  836.   @<Compute the time elapsed since the previous mouse event@>;
  837.   sprintf(mouse_buf+2,"(%d %d %d %d)\r",button_code,@|
  838.       event_x(event)/char_width, event_y(event)/char_height,@|
  839.       elapsed_time);
  840.   ttysw_input(window,mouse_buf,12+strlen(mouse_buf+12)); /* length is at least 12 */
  841.   return NOTIFY_DONE;
  842. }
  843.  
  844. @ @<Global...@>=
  845. char mouse_buf[24]="\030";
  846.  
  847. @ XView's event structure includes |event_time(event)|, which has
  848. type |struct timeval|; this data type is declared in \.{<sys/time.h>},
  849. which is one of the files included automatically as a result of
  850. including \.{<xview/xview.h>}.
  851. A |timeval| structure consists of two |long| integers, |tv_sec| and |tv_usec|,
  852. denoting clock time in seconds and microseconds, respectively.
  853.  
  854. @<Compute the time...@>=
  855. {@+struct timeval now; /* current time */
  856.   long delta_sec, delta_usec; /* difference between current and
  857.                                  previous time */
  858.   now=event_time(event);
  859.   delta_sec=now.tv_sec-prev_mouse_time.tv_sec;
  860.   delta_usec=now.tv_usec-prev_mouse_time.tv_usec;
  861.   if (delta_usec<0) delta_usec+=1000000,delta_sec--;
  862.   if (delta_sec>=10) elapsed_time=9999; /* infinity (or close enough) */
  863.   else elapsed_time=(delta_sec*1000)+(delta_usec/1000);
  864.   prev_mouse_time=now;
  865. }
  866.  
  867. @ @<Global...@>=
  868. struct timeval prev_mouse_time;
  869.  
  870. @* Remaining problems. There's a terribly unfortunate bug in the
  871. present implementation of XView, causing characters of tty subwindows
  872. to be badly painted at crucial times; the rightmost column of pixels
  873. in a character is often clobbered. If I could figure out how to
  874. generate repaint events for the tty subwindow, I might build a mechanism
  875. into \.{oemacs} that does this after the keyboard has been idle for 10
  876. seconds, say.  This would blink the screen; maybe I'll get used to that,
  877. or maybe I'll prefer to refresh the window manually by binding
  878. \.{redraw-display} to the L2 and R1 keys.  In any case a lot of screen
  879. refreshing is necessary at the moment, alas.
  880.  
  881. (Note added later: I doubt if I'll get used to blinking, and the present
  882. method of manual refresh is tolerable so I won't pursue the 10-second
  883. timer idea. I have meanwhile noticed a procedure |wmgr_refreshwindow(window)|
  884. mentioned in \.{<xview/wmgr.h>}; it will presumably refresh any
  885. given window.
  886.  
  887. Another bug, much less serious, occurs when the window is resized.
  888. If the window gets smaller, \.{emacs} isn't told to correct its
  889. assumptions; so it puts information in strange places or offscreen.
  890. (Internally, emacs uses the \.{TIOCGWINSZ} or \.{TIOCSWINSZ} ioctl,
  891. described in the man page for \.{termio}.)
  892. You can work around this by first making the window very small, then
  893. making it large.
  894.  
  895. @* Index.
  896.  
  897.  
  898.