oemacs.w
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:38k
源码类别:

通讯编程

开发平台:

Visual C++

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