Merge remote-tracking branch 'origin/master' into for-steve
[sxemacs] / src / events / events.c
1 /* Events: printing them, converting them to and from characters.
2    Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
3    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: Not in FSF. */
22
23 /* This file has been Mule-ized. */
24
25 #include <config.h>
26 #include "lisp.h"
27 #include "buffer.h"
28 #include "ui/console.h"
29 #include "ui/TTY/console-tty.h" /* for stuff in
30                                            character_to_event. needs
31                                            refactoring */
32 #include "ui/device.h"
33 #include "ui/X11/console-x.h"   /* for x_event_name prototype in
34                                    format_event_object. Needs refactoring */
35 #include "extents.h"            /* Just for the EXTENTP abort check... */
36 #define INCLUDE_EVENTS_H_PRIVATE_SPHERE
37 #include "events.h"
38 #include "ui/frame.h"
39 #include "ui/glyphs.h"
40 #include "ui/keymap.h"          /* for key_desc_list_to_event() */
41 #include "ui/redisplay.h"
42 #include "ui/window.h"
43 #include "events-mod.h"
44
45 /* Where old events go when they are explicitly deallocated.
46    The event chain here is cut loose before GC, so these will be freed
47    eventually.
48  */
49 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
50 static Lisp_Object Vevent_resource;
51 #ifdef EF_USE_ASYNEQ
52 static sxe_mutex_t Vevent_resource_mtx;
53 #endif  /* EF_USE_ASYNEQ */
54 #endif  /* BDWGC */
55
56 Lisp_Object Qeventp;
57 Lisp_Object Qevent_live_p;
58 Lisp_Object Qkey_press_event_p;
59 Lisp_Object Qbutton_event_p;
60 Lisp_Object Qmouse_event_p;
61 Lisp_Object Qprocess_event_p;
62
63 Lisp_Object Qkey_press, Qbutton_press, Qbutton_release, Qmisc_user;
64 Lisp_Object Qascii_character;
65
66 EXFUN(Fevent_x_pixel, 1);
67 EXFUN(Fevent_y_pixel, 1);
68
69 \f
70 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
71 static inline void
72 init_Vevent_resource(void)
73 {
74         return;
75 }
76
77 static inline void
78 fini_Vevent_resource(void)
79 {
80         return;
81 }
82
83 static inline void
84 lock_Vevent_resource(void)
85 {
86         return;
87 }
88
89 static inline void
90 unlock_Vevent_resource(void)
91 {
92         return;
93 }
94 #elif defined EF_USE_ASYNEQ
95 static inline void
96 init_Vevent_resource(void)
97 {
98         Vevent_resource = Qnil;
99         SXE_MUTEX_INIT(&Vevent_resource_mtx);
100 }
101
102 static inline void
103 fini_Vevent_resource(void)
104 {
105         SXE_MUTEX_FINI(&Vevent_resource_mtx);
106         Vevent_resource = Qnil;
107 }
108
109 static inline void
110 lock_Vevent_resource(void)
111 {
112         SXE_MUTEX_LOCK(&Vevent_resource_mtx);
113 }
114
115 static inline void
116 unlock_Vevent_resource(void)
117 {
118         SXE_MUTEX_UNLOCK(&Vevent_resource_mtx);
119 }
120
121 #else
122 static inline void
123 init_Vevent_resource(void)
124 {
125         Vevent_resource = Qnil;
126 }
127
128 static inline void
129 fini_Vevent_resource(void)
130 {
131         Vevent_resource = Qnil;
132 }
133
134 static inline void
135 lock_Vevent_resource(void)
136 {
137 }
138
139 static inline void
140 unlock_Vevent_resource(void)
141 {
142 }
143 #endif
144
145 /* #### Ad-hoc hack.  Should be part of define_lrecord_implementation */
146 void clear_event_resource(void)
147 {
148 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
149         lock_Vevent_resource();
150         Vevent_resource = Qnil;
151         unlock_Vevent_resource();
152 #endif  /* !BDWGC */
153 }
154
155 /* Make sure we lose quickly if we try to use this event */
156 static void deinitialize_event(Lisp_Object ev)
157 {
158         Lisp_Event *event = XEVENT(ev);
159
160         for (sxe_index_t i = 0; i < (sizeof(Lisp_Event) / sizeof(int)); i++) {
161                 ((int*)event)[i] = 0xdeadbeef;
162         }
163         event->event_type = dead_event;
164         event->channel = Qnil;
165         set_lheader_implementation(&event->lheader, &lrecord_event);
166         XSET_EVENT_NEXT(ev, Qnil);
167 }
168
169 /* Set everything to zero or nil so that it's predictable. */
170 void zero_event(Lisp_Event * e)
171 {
172         xzero(*e);
173         set_lheader_implementation(&e->lheader, &lrecord_event);
174         e->event_type = empty_event;
175         e->next = Qnil;
176         e->channel = Qnil;
177 }
178
179 static Lisp_Object mark_event(Lisp_Object obj)
180 {
181         Lisp_Event *event = XEVENT(obj);
182
183         switch (event->event_type) {
184         case key_press_event:
185                 mark_object(event->event.key.keysym);
186                 break;
187         case process_event:
188                 mark_object(event->event.process.process);
189                 break;
190         case timeout_event:
191                 mark_object(event->event.timeout.function);
192                 mark_object(event->event.timeout.object);
193                 break;
194         case eval_event:
195         case misc_user_event:
196                 mark_object(event->event.eval.function);
197                 mark_object(event->event.eval.object);
198                 break;
199         case magic_eval_event:
200                 mark_object(event->event.magic_eval.object);
201                 break;
202 #ifdef EF_USE_ASYNEQ
203         case work_started_event:
204                 if (event->event.work_started.job)
205                         mark_object(event->event.work_started.job);
206                 break;
207         case work_finished_event:
208                 if (event->event.work_finished.job)
209                         mark_object(event->event.work_finished.job);
210                 break;
211         case eaten_myself_event:
212 #endif
213         case button_press_event:
214         case button_release_event:
215         case pointer_motion_event:
216         case magic_event:
217         case empty_event:
218         case dead_event:
219                 break;
220         default:
221                 abort();
222         }
223         mark_object(event->channel);
224         return event->next;
225 }
226
227 static void
228 print_event_1(const char *str, Lisp_Object obj, Lisp_Object printcharfun)
229 {
230         char buf[255];
231         write_c_string(str, printcharfun);
232         format_event_object(buf, XEVENT(obj), 0);
233         write_c_string(buf, printcharfun);
234 }
235
236 static void
237 print_event(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
238 {
239         if (print_readably)
240                 error("Printing unreadable object #<event>");
241
242         switch (XEVENT(obj)->event_type) {
243         case key_press_event:
244                 print_event_1("#<keypress-event ", obj, printcharfun);
245                 break;
246         case button_press_event:
247                 print_event_1("#<buttondown-event ", obj, printcharfun);
248                 break;
249         case button_release_event:
250                 print_event_1("#<buttonup-event ", obj, printcharfun);
251                 break;
252         case magic_event:
253         case magic_eval_event:
254                 print_event_1("#<magic-event ", obj, printcharfun);
255                 break;
256         case pointer_motion_event: {
257                 Lisp_Object Vx, Vy;
258                 Vx = Fevent_x_pixel(obj);
259                 assert(INTP(Vx));
260                 Vy = Fevent_y_pixel(obj);
261                 assert(INTP(Vy));
262                 write_fmt_str(printcharfun, "#<motion-event %ld, %ld", (long)XINT(Vx),
263                               (long)XINT(Vy));
264                 break;
265         }
266         case process_event:
267                 write_c_string("#<process-event ", printcharfun);
268                 print_internal(XEVENT(obj)->event.process.process, printcharfun,
269                                1);
270                 break;
271         case timeout_event:
272                 write_c_string("#<timeout-event ", printcharfun);
273                 print_internal(XEVENT(obj)->event.timeout.object, printcharfun,
274                                1);
275                 break;
276         case empty_event:
277                 write_c_string("#<empty-event", printcharfun);
278                 break;
279         case misc_user_event:
280                 write_c_string("#<misc-user-event (", printcharfun);
281                 print_internal(XEVENT(obj)->event.misc.function, printcharfun,
282                                1);
283                 write_c_string(" ", printcharfun);
284                 print_internal(XEVENT(obj)->event.misc.object, printcharfun, 1);
285                 write_c_string(")", printcharfun);
286                 break;
287         case eval_event:
288                 write_c_string("#<eval-event (", printcharfun);
289                 print_internal(XEVENT(obj)->event.eval.function, printcharfun,
290                                1);
291                 write_c_string(" ", printcharfun);
292                 print_internal(XEVENT(obj)->event.eval.object, printcharfun, 1);
293                 write_c_string(")", printcharfun);
294                 break;
295         case dead_event:
296                 write_c_string("#<DEALLOCATED-EVENT", printcharfun);
297                 break;
298 #ifdef EF_USE_ASYNEQ
299         case eaten_myself_event:
300                 write_c_string("#<worker-suidice-event", printcharfun);
301                 break;
302         case work_started_event:
303                 write_c_string("#<worker-work-started-event", printcharfun);
304                 break;
305         case work_finished_event:
306                 write_c_string("#<worker-work-finished-event", printcharfun);
307                 break;
308 #endif  /* EF_USE_ASYNEQ */
309         default:
310                 write_c_string("#<UNKNOWN-EVENT-TYPE", printcharfun);
311                 break;
312         }
313         write_c_string(">", printcharfun);
314 }
315
316 static int
317 event_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
318 {
319         Lisp_Event *e1 = XEVENT(obj1);
320         Lisp_Event *e2 = XEVENT(obj2);
321
322         if (e1->event_type != e2->event_type)
323                 return 0;
324         if (!EQ(e1->channel, e2->channel))
325                 return 0;
326         /*  if (e1->timestamp != e2->timestamp) return 0; */
327         switch (e1->event_type) {
328         default:
329                 abort();
330                 break;
331
332         case process_event:
333                 return EQ(e1->event.process.process, e2->event.process.process);
334
335         case timeout_event:
336                 return (internal_equal(e1->event.timeout.function,
337                                        e2->event.timeout.function, 0) &&
338                         internal_equal(e1->event.timeout.object,
339                                        e2->event.timeout.object, 0));
340
341         case key_press_event:
342                 return (EQ(e1->event.key.keysym, e2->event.key.keysym) &&
343                         (e1->event.key.modifiers == e2->event.key.modifiers));
344
345         case button_press_event:
346         case button_release_event:
347                 return (e1->event.button.button == e2->event.button.button &&
348                         e1->event.button.modifiers ==
349                         e2->event.button.modifiers);
350
351         case pointer_motion_event:
352                 return (e1->event.motion.x == e2->event.motion.x &&
353                         e1->event.motion.y == e2->event.motion.y);
354
355         case misc_user_event:
356                 return (internal_equal(e1->event.eval.function,
357                                        e2->event.eval.function, 0) &&
358                         internal_equal(e1->event.eval.object,
359                                        e2->event.eval.object, 0) &&
360                         /* is this really needed for equality
361                            or is x and y also important? */
362                         e1->event.misc.button == e2->event.misc.button &&
363                         e1->event.misc.modifiers == e2->event.misc.modifiers);
364
365         case eval_event:
366                 return (internal_equal(e1->event.eval.function,
367                                        e2->event.eval.function, 0) &&
368                         internal_equal(e1->event.eval.object,
369                                        e2->event.eval.object, 0));
370
371         case magic_eval_event:
372                 return (e1->event.magic_eval.internal_function ==
373                         e2->event.magic_eval.internal_function &&
374                         internal_equal(e1->event.magic_eval.object,
375                                        e2->event.magic_eval.object, 0));
376
377         case magic_event: {
378                 struct console *con =
379                         XCONSOLE(CDFW_CONSOLE(e1->channel));
380
381 #ifdef HAVE_X_WINDOWS
382                 if (CONSOLE_X_P(con))
383                         return (e1->event.magic.underlying_x_event.xany.
384                                 serial ==
385                                 e2->event.magic.underlying_x_event.xany.
386                                 serial);
387 #endif
388 #ifdef HAVE_TTY
389                 if (CONSOLE_TTY_P(con))
390                         return (e1->event.magic.underlying_tty_event ==
391                                 e2->event.magic.underlying_tty_event);
392 #endif
393                 abort();
394                 return 1;       /* not reached */
395         }
396
397 #ifdef EF_USE_ASYNEQ
398                 /* worker thread mumbo jumbo is never equal */
399         case eaten_myself_event:
400         case work_started_event:
401         case work_finished_event:
402                 return 0;
403 #endif  /* EF_USE_ASYNEQ */
404
405                 /* Empty and deallocated events are equal. */
406         case empty_event:
407         case dead_event:
408                 return 1;
409         }
410 }
411
412 static unsigned long
413 event_hash(Lisp_Object obj, int depth)
414 {
415         Lisp_Event *e = XEVENT(obj);
416         unsigned long hash;
417
418         hash = HASH2(e->event_type, LISP_HASH(e->channel));
419         switch (e->event_type) {
420         case process_event:
421                 return HASH2(hash, LISP_HASH(e->event.process.process));
422
423         case timeout_event:
424                 return HASH3(hash,
425                              internal_hash(e->event.timeout.function,
426                                            depth + 1),
427                              internal_hash(e->event.timeout.object, depth + 1));
428
429         case key_press_event:
430                 return HASH3(hash, LISP_HASH(e->event.key.keysym),
431                              e->event.key.modifiers);
432
433         case button_press_event:
434         case button_release_event:
435                 return HASH3(hash, e->event.button.button,
436                              e->event.button.modifiers);
437
438         case pointer_motion_event:
439                 return HASH3(hash, e->event.motion.x, e->event.motion.y);
440
441         case misc_user_event:
442                 return HASH5(hash,
443                              internal_hash(e->event.misc.function, depth + 1),
444                              internal_hash(e->event.misc.object, depth + 1),
445                              e->event.misc.button, e->event.misc.modifiers);
446
447         case eval_event:
448                 return HASH3(hash,
449                              internal_hash(e->event.eval.function, depth + 1),
450                              internal_hash(e->event.eval.object, depth + 1));
451
452         case magic_eval_event:
453                 return HASH3(hash,
454                              (unsigned long)e->event.magic_eval.
455                              internal_function,
456                              internal_hash(e->event.magic_eval.object,
457                                            depth + 1));
458
459         case magic_event: {
460                 struct console *con =
461                         XCONSOLE(CDFW_CONSOLE(EVENT_CHANNEL(e)));
462 #ifdef HAVE_X_WINDOWS
463                 if (CONSOLE_X_P(con))
464                         return HASH2(hash,
465                                      e->event.magic.underlying_x_event.
466                                      xany.serial);
467 #endif
468 #ifdef HAVE_TTY
469                 if (CONSOLE_TTY_P(con))
470                         return HASH2(hash,
471                                      e->event.magic.
472                                      underlying_tty_event);
473 #endif
474                 abort();
475                 return 0;
476         }
477
478 #ifdef EF_USE_ASYNEQ
479         case eaten_myself_event:
480         case work_started_event:
481         case work_finished_event:
482                 return (long unsigned int)obj;
483 #endif  /* EF_USE_ASYNEQ */
484
485         case empty_event:
486         case dead_event:
487                 return hash;
488
489         default:
490                 abort();
491         }
492
493         return 0;               /* unreached */
494 }
495
496 DEFINE_BASIC_LRECORD_IMPLEMENTATION("event", event,
497                                     mark_event, print_event, 0, event_equal,
498                                     event_hash, 0, Lisp_Event);
499 \f
500 Lisp_Object
501 make_empty_event(void)
502 {
503         Lisp_Object event = Qnil;
504         Lisp_Event *e;
505
506 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
507 /* just allocate */
508         event = allocate_event();
509
510 #else  /* !BDWGC */
511         struct gcpro gcpro1;
512
513         GCPRO1(event);
514         lock_Vevent_resource();
515         if (!NILP(Vevent_resource)) {
516                 event = Vevent_resource;
517                 Vevent_resource = XEVENT_NEXT(event);
518         } else {
519                 event = allocate_event();
520         }
521         unlock_Vevent_resource();
522 #endif  /* BDWGC */
523         e = XEVENT(event);
524         zero_event(e);
525
526         e->event_type = empty_event;
527         e->next = Qnil;
528         EVENT_CHANNEL(e) = Qnil;
529
530         UNGCPRO;
531         return event;
532 }
533
534 sxe_event_t
535 make_noseeum_event(emacs_event_type event_type)
536 {
537         sxe_event_t res = xnew_and_zero(Lisp_Event);
538
539         res->event_type = event_type;
540         res->next = Qnil;
541         EVENT_CHANNEL(res) = Qnil;
542         return res;
543 }
544
545 DEFUN("make-event", Fmake_event, 0, 2, 0,       /*
546 Return a new event of type TYPE, with properties described by PLIST.
547
548 TYPE is a symbol, either `empty', `key-press', `button-press',
549 `button-release', `misc-user' or `motion'.  If TYPE is nil, it
550 defaults to `empty'.
551
552 PLIST is a property list, the properties being compatible to those
553 returned by `event-properties'.  The following properties are
554 allowed:
555
556 channel   -- The event channel, a frame or a console.  For
557 button-press, button-release, misc-user and motion events,
558 this must be a frame.  For key-press events, it must be
559 a console.  If channel is unspecified, it will be set to
560 the selected frame or selected console, as appropriate.
561 key               -- The event key, a symbol or character.  Allowed only for
562 keypress events.
563 button            -- The event button, integer 1, 2 or 3.  Allowed for
564 button-press, button-release and misc-user events.
565 modifiers -- The event modifiers, a list of modifier symbols.  Allowed
566 for key-press, button-press, button-release, motion and
567 misc-user events.
568 function       -- Function. Allowed for misc-user events only.
569 object         -- An object, function's parameter. Allowed for misc-user
570 events only.
571 x         -- The event X coordinate, an integer.  This is relative
572 to the left of CHANNEL's root window.  Allowed for
573 motion, button-press, button-release and misc-user events.
574 y         -- The event Y coordinate, an integer.  This is relative
575 to the top of CHANNEL's root window.  Allowed for
576 motion, button-press, button-release and misc-user events.
577 timestamp -- The event timestamp, a non-negative integer.  Allowed for
578 all types of events.  If unspecified, it will be set to 0
579 by default.
580
581 For event type `empty', PLIST must be nil.
582 `button-release', or `motion'.  If TYPE is left out, it defaults to
583 `empty'.
584 PLIST is a list of properties, as returned by `event-properties'.  Not
585 all properties are allowed for all kinds of events, and some are
586 required.
587
588 WARNING: the event object returned may be a reused one; see the function
589 `deallocate-event'.
590 */
591       (type, plist))
592 {
593         Lisp_Object event = Qnil;
594         Lisp_Event *e;
595         EMACS_INT coord_x = 0, coord_y = 0;
596         struct gcpro gcpro1;
597
598         if (NILP(type)) {
599                 /* common case */
600                 return make_empty_event();
601         }
602
603 #if defined HAVE_BDWGC && defined EF_USE_BDWGC
604         event = allocate_event();
605
606 #else  /* !BDWGC */
607         GCPRO1(event);
608         lock_Vevent_resource();
609         if (!NILP(Vevent_resource)) {
610                 event = Vevent_resource;
611                 Vevent_resource = XEVENT_NEXT(event);
612         } else {
613                 event = allocate_event();
614         }
615         unlock_Vevent_resource();
616 #endif  /* BDWGC */
617         e = XEVENT(event);
618         zero_event(e);
619
620         if (EQ(type, Qempty)) {
621                 /* For empty event, we return immediately, without processing
622                    PLIST.  In fact, processing PLIST would be wrong, because the
623                    sanitizing process would fill in the properties
624                    (e.g. CHANNEL), which we don't want in empty events.  */
625                 e->event_type = empty_event;
626                 if (!NILP(plist))
627                         syntax_error("Cannot set properties of empty event",
628                                      plist);
629                 UNGCPRO;
630                 return event;
631         } else if (EQ(type, Qkey_press)) {
632                 e->event_type = key_press_event;
633                 e->event.key.keysym = Qunbound;
634         } else if (EQ(type, Qbutton_press)) {
635                 e->event_type = button_press_event;
636         } else if (EQ(type, Qbutton_release)) {
637                 e->event_type = button_release_event;
638         } else if (EQ(type, Qmotion)) {
639                 e->event_type = pointer_motion_event;
640         } else if (EQ(type, Qmisc_user)) {
641                 e->event_type = misc_user_event;
642                 e->event.eval.function = e->event.eval.object = Qnil;
643         } else {
644                 /* Not allowed:
645                    Qprocess, Qtimeout, Qmagic, Qeval, Qmagic_eval.  */
646                 invalid_argument("Invalid event type", type);
647         }
648
649         EVENT_CHANNEL(e) = Qnil;
650
651         plist = Fcopy_sequence(plist);
652         Fcanonicalize_plist(plist, Qnil);
653
654 #define WRONG_EVENT_TYPE_FOR_PROPERTY(event_type, prop)                 \
655         syntax_error_2 ("Invalid property for event type", prop, event_type)
656
657         {
658                 EXTERNAL_PROPERTY_LIST_LOOP_3(keyword, value, plist) {
659                         if (EQ(keyword, Qchannel)) {
660                                 if (e->event_type == key_press_event) {
661                                         if (!CONSOLEP(value))
662                                                 value =
663                                                     wrong_type_argument
664                                                     (Qconsolep, value);
665                                 } else {
666                                         if (!FRAMEP(value))
667                                                 value =
668                                                     wrong_type_argument(Qframep,
669                                                                         value);
670                                 }
671                                 EVENT_CHANNEL(e) = value;
672                         } else if (EQ(keyword, Qkey)) {
673                                 switch (e->event_type) {
674                                 case key_press_event:
675                                         if (!SYMBOLP(value) && !CHARP(value))
676                                                 syntax_error
677                                                     ("Invalid event key",
678                                                      value);
679                                         e->event.key.keysym = value;
680                                         break;
681
682                                         /* rest goes here */
683                                 case empty_event:
684                                 case button_press_event:
685                                 case button_release_event:
686                                 case pointer_motion_event:
687                                 case process_event:
688                                 case timeout_event:
689                                 case magic_event:
690                                 case magic_eval_event:
691                                 case eval_event:
692                                 case misc_user_event:
693 #ifdef EF_USE_ASYNEQ
694                                 case eaten_myself_event:
695                                 case work_started_event:
696                                 case work_finished_event:
697 #endif  /* EF_USE_ASYNEQ */
698                                 case dead_event:
699                                 default:
700                                         WRONG_EVENT_TYPE_FOR_PROPERTY(type,
701                                                                       keyword);
702                                         break;
703                                 }
704                         } else if (EQ(keyword, Qbutton)) {
705                                 CHECK_NATNUM(value);
706                                 check_int_range(XINT(value), 0, 7);
707
708                                 switch (e->event_type) {
709                                 case button_press_event:
710                                 case button_release_event:
711                                         e->event.button.button = XINT(value);
712                                         break;
713                                 case misc_user_event:
714                                         e->event.misc.button = XINT(value);
715                                         break;
716
717                                         /* and the rest of that lot */
718                                 case empty_event:
719                                 case key_press_event:
720                                 case pointer_motion_event:
721                                 case process_event:
722                                 case timeout_event:
723                                 case magic_event:
724                                 case magic_eval_event:
725                                 case eval_event:
726 #ifdef EF_USE_ASYNEQ
727                                 case eaten_myself_event:
728                                 case work_started_event:
729                                 case work_finished_event:
730 #endif  /* EF_USE_ASYNEQ */
731                                 case dead_event:
732                                 default:
733                                         WRONG_EVENT_TYPE_FOR_PROPERTY(type,
734                                                                       keyword);
735                                         break;
736                                 }
737                         } else if (EQ(keyword, Qmodifiers)) {
738                                 int modifiers = 0;
739
740                                 EXTERNAL_LIST_LOOP_2(sym, value) {
741                                         if (EQ(sym, Qcontrol))
742                                                 modifiers |= XEMACS_MOD_CONTROL;
743                                         else if (EQ(sym, Qmeta))
744                                                 modifiers |= XEMACS_MOD_META;
745                                         else if (EQ(sym, Qsuper))
746                                                 modifiers |= XEMACS_MOD_SUPER;
747                                         else if (EQ(sym, Qhyper))
748                                                 modifiers |= XEMACS_MOD_HYPER;
749                                         else if (EQ(sym, Qalt))
750                                                 modifiers |= XEMACS_MOD_ALT;
751                                         else if (EQ(sym, Qsymbol))
752                                                 modifiers |= XEMACS_MOD_ALT;
753                                         else if (EQ(sym, Qshift))
754                                                 modifiers |= XEMACS_MOD_SHIFT;
755                                         else if (EQ(sym, Qbutton1))
756                                                 modifiers |= XEMACS_MOD_BUTTON1;
757                                         else if (EQ(sym, Qbutton2))
758                                                 modifiers |= XEMACS_MOD_BUTTON2;
759                                         else if (EQ(sym, Qbutton3))
760                                                 modifiers |= XEMACS_MOD_BUTTON3;
761                                         else if (EQ(sym, Qbutton4))
762                                                 modifiers |= XEMACS_MOD_BUTTON4;
763                                         else if (EQ(sym, Qbutton5))
764                                                 modifiers |= XEMACS_MOD_BUTTON5;
765                                         else
766                                                 syntax_error
767                                                     ("Invalid key modifier",
768                                                      sym);
769                                 }
770
771                                 switch (e->event_type) {
772                                 case key_press_event:
773                                         e->event.key.modifiers = modifiers;
774                                         break;
775                                 case button_press_event:
776                                 case button_release_event:
777                                         e->event.button.modifiers = modifiers;
778                                         break;
779                                 case pointer_motion_event:
780                                         e->event.motion.modifiers = modifiers;
781                                         break;
782                                 case misc_user_event:
783                                         e->event.misc.modifiers = modifiers;
784                                         break;
785
786                                         /* here come the rest */
787                                 case empty_event:
788                                 case process_event:
789                                 case timeout_event:
790                                 case magic_event:
791                                 case magic_eval_event:
792                                 case eval_event:
793 #ifdef EF_USE_ASYNEQ
794                                 case eaten_myself_event:
795                                 case work_started_event:
796                                 case work_finished_event:
797 #endif  /* EF_USE_ASYNEQ */
798                                 case dead_event:
799                                 default:
800                                         WRONG_EVENT_TYPE_FOR_PROPERTY(type,
801                                                                       keyword);
802                                         break;
803                                 }
804                         } else if (EQ(keyword, Qx)) {
805                                 switch (e->event_type) {
806                                 case pointer_motion_event:
807                                 case button_press_event:
808                                 case button_release_event:
809                                 case misc_user_event:
810                                         /* Allow negative values, so we can specify toolbar
811                                            positions.  */
812                                         CHECK_INT(value);
813                                         coord_x = XINT(value);
814                                         break;
815
816                                         /* rest goes here */
817                                 case empty_event:
818                                 case key_press_event:
819                                 case process_event:
820                                 case timeout_event:
821                                 case magic_event:
822                                 case magic_eval_event:
823                                 case eval_event:
824 #ifdef EF_USE_ASYNEQ
825                                 case eaten_myself_event:
826                                 case work_started_event:
827                                 case work_finished_event:
828 #endif  /* EF_USE_ASYNEQ */
829                                 case dead_event:
830                                 default:
831                                         WRONG_EVENT_TYPE_FOR_PROPERTY(type,
832                                                                       keyword);
833                                         break;
834                                 }
835                         } else if (EQ(keyword, Qy)) {
836                                 switch (e->event_type) {
837                                 case pointer_motion_event:
838                                 case button_press_event:
839                                 case button_release_event:
840                                 case misc_user_event:
841                                         /* Allow negative values; see above. */
842                                         CHECK_INT(value);
843                                         coord_y = XINT(value);
844                                         break;
845
846                                         /* et la reste */
847                                 case empty_event:
848                                 case key_press_event:
849                                 case process_event:
850                                 case timeout_event:
851                                 case magic_event:
852                                 case magic_eval_event:
853                                 case eval_event:
854 #ifdef EF_USE_ASYNEQ
855                                 case eaten_myself_event:
856                                 case work_started_event:
857                                 case work_finished_event:
858 #endif  /* EF_USE_ASYNEQ */
859                                 case dead_event:
860                                 default:
861                                         WRONG_EVENT_TYPE_FOR_PROPERTY(type,
862                                                                       keyword);
863                                         break;
864                                 }
865                         } else if (EQ(keyword, Qtimestamp)) {
866                                 CHECK_NATNUM(value);
867                                 e->timestamp = XINT(value);
868                         } else if (EQ(keyword, Qfunction)) {
869                                 switch (e->event_type) {
870                                 case misc_user_event:
871                                         e->event.eval.function = value;
872                                         break;
873
874                                         /* rest goes here */
875                                 case empty_event:
876                                 case key_press_event:
877                                 case button_press_event:
878                                 case button_release_event:
879                                 case pointer_motion_event:
880                                 case process_event:
881                                 case timeout_event:
882                                 case magic_event:
883                                 case magic_eval_event:
884                                 case eval_event:
885 #ifdef EF_USE_ASYNEQ
886                                 case eaten_myself_event:
887                                 case work_started_event:
888                                 case work_finished_event:
889 #endif  /* EF_USE_ASYNEQ */
890                                 case dead_event:
891                                 default:
892                                         WRONG_EVENT_TYPE_FOR_PROPERTY(type,
893                                                                       keyword);
894                                         break;
895                                 }
896                         } else if (EQ(keyword, Qobject)) {
897                                 switch (e->event_type) {
898                                 case misc_user_event:
899                                         e->event.eval.object = value;
900                                         break;
901
902                                         /* rest goes here */
903                                 case empty_event:
904                                 case key_press_event:
905                                 case button_press_event:
906                                 case button_release_event:
907                                 case pointer_motion_event:
908                                 case process_event:
909                                 case timeout_event:
910                                 case magic_event:
911                                 case magic_eval_event:
912                                 case eval_event:
913 #ifdef EF_USE_ASYNEQ
914                                 case eaten_myself_event:
915                                 case work_started_event:
916                                 case work_finished_event:
917 #endif  /* EF_USE_ASYNEQ */
918                                 case dead_event:
919                                 default:
920                                         WRONG_EVENT_TYPE_FOR_PROPERTY(type,
921                                                                       keyword);
922                                         break;
923                                 }
924                         } else
925                                 syntax_error_2("Invalid property", keyword,
926                                                value);
927                 }
928         }
929
930         /* Insert the channel, if missing. */
931         if (NILP(EVENT_CHANNEL(e))) {
932                 if (e->event_type == key_press_event)
933                         EVENT_CHANNEL(e) = Vselected_console;
934                 else
935                         EVENT_CHANNEL(e) = Fselected_frame(Qnil);
936         }
937
938         /* Fevent_properties, Fevent_x_pixel, etc. work with pixels relative
939            to the frame, so we must adjust accordingly.  */
940         if (FRAMEP(EVENT_CHANNEL(e))) {
941                 coord_x +=
942                     FRAME_REAL_LEFT_TOOLBAR_WIDTH(XFRAME(EVENT_CHANNEL(e)));
943                 coord_y +=
944                     FRAME_REAL_TOP_TOOLBAR_HEIGHT(XFRAME(EVENT_CHANNEL(e)));
945
946                 switch (e->event_type) {
947                 case pointer_motion_event:
948                         e->event.motion.x = coord_x;
949                         e->event.motion.y = coord_y;
950                         break;
951                 case button_press_event:
952                 case button_release_event:
953                         e->event.button.x = coord_x;
954                         e->event.button.y = coord_y;
955                         break;
956                 case misc_user_event:
957                         e->event.misc.x = coord_x;
958                         e->event.misc.y = coord_y;
959                         break;
960
961                         /* rest goes here */
962                 case empty_event:
963                 case key_press_event:
964                 case process_event:
965                 case timeout_event:
966                 case magic_event:
967                 case magic_eval_event:
968                 case eval_event:
969 #ifdef EF_USE_ASYNEQ
970                 case eaten_myself_event:
971                 case work_started_event:
972                 case work_finished_event:
973 #endif  /* EF_USE_ASYNEQ */
974                 case dead_event:
975                 default:
976                         abort();
977                 }
978         }
979
980         /* Finally, do some more validation.  */
981         switch (e->event_type) {
982         case key_press_event:
983                 if (UNBOUNDP(e->event.key.keysym))
984                         syntax_error
985                             ("A key must be specified to make a "
986                              "keypress event", plist);
987                 break;
988         case button_press_event:
989                 if (!e->event.button.button)
990                         syntax_error
991                             ("A button must be specified to make a "
992                              "button-press event", plist);
993                 break;
994         case button_release_event:
995                 if (!e->event.button.button)
996                         syntax_error
997                             ("A button must be specified to make a "
998                              "button-release event", plist);
999                 break;
1000         case misc_user_event:
1001                 if (NILP(e->event.misc.function))
1002                         syntax_error
1003                             ("A function must be specified to make a "
1004                              "misc-user event", plist);
1005                 break;
1006
1007         case empty_event:
1008         case pointer_motion_event:
1009         case process_event:
1010         case timeout_event:
1011         case magic_event:
1012         case magic_eval_event:
1013         case eval_event:
1014 #ifdef EF_USE_ASYNEQ
1015         case eaten_myself_event:
1016         case work_started_event:
1017         case work_finished_event:
1018 #endif  /* EF_USE_ASYNEQ */
1019         case dead_event:
1020         default:
1021                 break;
1022         }
1023
1024         UNGCPRO;
1025         return event;
1026 }
1027
1028 DEFUN("deallocate-event", Fdeallocate_event, 1, 1, 0,   /*
1029 Allow the given event structure to be reused.
1030 You MUST NOT use this event object after calling this function with it.
1031 You will lose.  It is not necessary to call this function, as event
1032 objects are garbage-collected like all other objects; however, it may
1033 be more efficient to explicitly deallocate events when you are sure
1034 that it is safe to do so.
1035 */
1036       (event))
1037 {
1038         CHECK_EVENT(event);
1039
1040         if (XEVENT_TYPE(event) == dead_event)
1041                 error("this event is already deallocated!");
1042
1043         assert(XEVENT_TYPE(event) <= last_event_type);
1044
1045 #if 0
1046         {
1047                 int i, len;
1048
1049                 if (EQ(event, Vlast_command_event) ||
1050                     EQ(event, Vlast_input_event) ||
1051                     EQ(event, Vunread_command_event))
1052                         abort();
1053
1054                 len = XVECTOR_LENGTH(Vthis_command_keys);
1055                 for (i = 0; i < len; i++)
1056                         if (EQ(event, XVECTOR_DATA(Vthis_command_keys)[i]))
1057                                 abort();
1058                 if (!NILP(Vrecent_keys_ring)) {
1059                         int recent_ring_len = XVECTOR_LENGTH(Vrecent_keys_ring);
1060                         for (i = 0; i < recent_ring_len; i++)
1061                                 if (EQ
1062                                     (event, XVECTOR_DATA(Vrecent_keys_ring)[i]))
1063                                         abort();
1064                 }
1065         }
1066 #endif                          /* 0 */
1067
1068 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
1069         lock_Vevent_resource();
1070         assert(!EQ(event, Vevent_resource));
1071         unlock_Vevent_resource();
1072 #endif  /* !BDWGC */
1073         deinitialize_event(event);
1074 #if !defined ALLOC_NO_POOLS && !(defined HAVE_BDWGC && defined EF_USE_BDWGC)
1075         lock_Vevent_resource();
1076         XSET_EVENT_NEXT(event, Vevent_resource);
1077         Vevent_resource = event;
1078         unlock_Vevent_resource();
1079 #endif
1080         return Qnil;
1081 }
1082
1083 DEFUN("copy-event", Fcopy_event, 1, 2, 0,       /*
1084 Make a copy of the event object EVENT1.
1085 If a second event argument EVENT2 is given, EVENT1 is copied into
1086 EVENT2 and EVENT2 is returned.  If EVENT2 is not supplied (or is nil)
1087 then a new event will be made as with `make-event'.  See also the
1088 function `deallocate-event'.
1089 */
1090       (event1, event2))
1091 {
1092         CHECK_LIVE_EVENT(event1);
1093         if (NILP(event2))
1094                 event2 = Fmake_event(Qnil, Qnil);
1095         else {
1096                 CHECK_LIVE_EVENT(event2);
1097                 if (EQ(event1, event2))
1098                         return signal_simple_continuable_error_2
1099                             ("copy-event called with `eq' events", event1,
1100                              event2);
1101         }
1102
1103         assert(XEVENT_TYPE(event1) <= last_event_type);
1104         assert(XEVENT_TYPE(event2) <= last_event_type);
1105
1106         {
1107                 Lisp_Event *ev2 = XEVENT(event2);
1108                 Lisp_Event *ev1 = XEVENT(event1);
1109
1110                 ev2->event_type = ev1->event_type;
1111                 ev2->channel = ev1->channel;
1112                 ev2->timestamp = ev1->timestamp;
1113                 ev2->event = ev1->event;
1114
1115                 return event2;
1116         }
1117 }
1118 \f
1119 /* Given a chain of events (or possibly nil), deallocate them all. */
1120
1121 void deallocate_event_chain(Lisp_Object event_chain)
1122 {
1123         while (!NILP(event_chain)) {
1124                 Lisp_Object next = XEVENT_NEXT(event_chain);
1125                 Fdeallocate_event(event_chain);
1126                 event_chain = next;
1127         }
1128 }
1129
1130 /* Return the last event in a chain.
1131    NOTE: You cannot pass nil as a value here!  The routine will
1132    abort if you do. */
1133
1134 Lisp_Object event_chain_tail(Lisp_Object event_chain)
1135 {
1136         while (1) {
1137                 Lisp_Object next = XEVENT_NEXT(event_chain);
1138                 if (NILP(next))
1139                         return event_chain;
1140                 event_chain = next;
1141         }
1142 }
1143
1144 /* Enqueue a single event onto the end of a chain of events.
1145    HEAD points to the first event in the chain, TAIL to the last event.
1146    If the chain is empty, both values should be nil. */
1147
1148 void enqueue_event(Lisp_Object event, Lisp_Object * head, Lisp_Object * tail)
1149 {
1150         assert(NILP(XEVENT_NEXT(event)));
1151         assert(!EQ(*tail, event));
1152
1153         if (!NILP(*tail))
1154                 XSET_EVENT_NEXT(*tail, event);
1155         else
1156                 *head = event;
1157         *tail = event;
1158
1159         assert(!EQ(event, XEVENT_NEXT(event)));
1160 }
1161
1162 /* Remove an event off the head of a chain of events and return it.
1163    HEAD points to the first event in the chain, TAIL to the last event. */
1164
1165 Lisp_Object dequeue_event(Lisp_Object * head, Lisp_Object * tail)
1166 {
1167         Lisp_Object event;
1168
1169         event = *head;
1170         *head = XEVENT_NEXT(event);
1171         XSET_EVENT_NEXT(event, Qnil);
1172         if (NILP(*head))
1173                 *tail = Qnil;
1174         return event;
1175 }
1176
1177 /* Enqueue a chain of events (or possibly nil) onto the end of another
1178    chain of events.  HEAD points to the first event in the chain being
1179    queued onto, TAIL to the last event.  If the chain is empty, both values
1180    should be nil. */
1181
1182 void
1183 enqueue_event_chain(Lisp_Object event_chain, Lisp_Object * head,
1184                     Lisp_Object * tail)
1185 {
1186         if (NILP(event_chain))
1187                 return;
1188
1189         if (NILP(*head)) {
1190                 *head = event_chain;
1191                 *tail = event_chain;
1192         } else {
1193                 XSET_EVENT_NEXT(*tail, event_chain);
1194                 *tail = event_chain_tail(event_chain);
1195         }
1196 }
1197
1198 /* Return the number of events (possibly 0) on an event chain. */
1199
1200 int event_chain_count(Lisp_Object event_chain)
1201 {
1202         Lisp_Object event;
1203         int n = 0;
1204
1205         EVENT_CHAIN_LOOP(event, event_chain) {
1206                 n++;
1207         }
1208
1209         return n;
1210 }
1211
1212 /* Find the event before EVENT in an event chain.  This aborts
1213    if the event is not in the chain. */
1214
1215 Lisp_Object
1216 event_chain_find_previous(Lisp_Object event_chain, Lisp_Object event)
1217 {
1218         Lisp_Object previous = Qnil;
1219
1220         while (!NILP(event_chain)) {
1221                 if (EQ(event_chain, event)) {
1222                         return previous;
1223                 }
1224                 previous = event_chain;
1225                 event_chain = XEVENT_NEXT(event_chain);
1226         }
1227
1228         abort();
1229         return Qnil;
1230 }
1231
1232 Lisp_Object event_chain_nth(Lisp_Object event_chain, int n)
1233 {
1234         Lisp_Object event;
1235         EVENT_CHAIN_LOOP(event, event_chain) {
1236                 if (!n) {
1237                         return event;
1238                 }
1239                 n--;
1240         }
1241         return Qnil;
1242 }
1243
1244 Lisp_Object copy_event_chain(Lisp_Object event_chain)
1245 {
1246         Lisp_Object new_chain = Qnil;
1247         Lisp_Object new_chain_tail = Qnil;
1248         Lisp_Object event;
1249
1250         EVENT_CHAIN_LOOP(event, event_chain) {
1251                 Lisp_Object copy = Fcopy_event(event, Qnil);
1252                 enqueue_event(copy, &new_chain, &new_chain_tail);
1253         }
1254
1255         return new_chain;
1256 }
1257 \f
1258 Lisp_Object QKbackspace, QKtab, QKlinefeed, QKreturn, QKescape,
1259     QKspace, QKdelete;
1260
1261 int command_event_p(Lisp_Object event)
1262 {
1263         switch (XEVENT_TYPE(event)) {
1264         case key_press_event:
1265         case button_press_event:
1266         case button_release_event:
1267         case misc_user_event:
1268                 return 1;
1269
1270         case empty_event:
1271         case pointer_motion_event:
1272         case process_event:
1273         case timeout_event:
1274         case magic_event:
1275         case magic_eval_event:
1276         case eval_event:
1277 #ifdef EF_USE_ASYNEQ
1278         case eaten_myself_event:
1279         case work_started_event:
1280         case work_finished_event:
1281 #endif  /* EF_USE_ASYNEQ */
1282         case dead_event:
1283         default:
1284                 return 0;
1285         }
1286 }
1287
1288 void
1289 character_to_event(Emchar c, Lisp_Event * event, struct console *con,
1290                    int use_console_meta_flag, int do_backspace_mapping)
1291 {
1292         Lisp_Object k = Qnil;
1293         int m = 0;
1294         if (event->event_type == dead_event)
1295                 error("character-to-event called with a deallocated event!");
1296
1297 #ifndef MULE
1298         c &= 255;
1299 #endif
1300         if (c > 127 && c <= 255) {
1301                 int meta_flag = 1;
1302
1303                 if (use_console_meta_flag && CONSOLE_TTY_P(con)) {
1304                         meta_flag = TTY_FLAGS(con).meta_key;
1305                 }
1306                 switch (meta_flag) {
1307                 case 0: /* ignore top bit; it's parity */
1308                         c -= 128;
1309                         break;
1310                 case 1: /* top bit is meta */
1311                         c -= 128;
1312                         m = XEMACS_MOD_META;
1313                         break;
1314                 default:        /* this is a real character */
1315                         break;
1316                 }
1317         }
1318         if (c < ' ')
1319                 c += '@', m |= XEMACS_MOD_CONTROL;
1320         if (m & XEMACS_MOD_CONTROL) {
1321                 switch (c) {
1322                 case 'I':
1323                         k = QKtab;
1324                         m &= ~XEMACS_MOD_CONTROL;
1325                         break;
1326                 case 'J':
1327                         k = QKlinefeed;
1328                         m &= ~XEMACS_MOD_CONTROL;
1329                         break;
1330                 case 'M':
1331                         k = QKreturn;
1332                         m &= ~XEMACS_MOD_CONTROL;
1333                         break;
1334                 case '[':
1335                         k = QKescape;
1336                         m &= ~XEMACS_MOD_CONTROL;
1337                         break;
1338                 default:
1339 #if defined(HAVE_TTY)
1340                         if (do_backspace_mapping &&
1341                             CHARP(con->tty_erase_char) &&
1342                             c - '@' == XCHAR(con->tty_erase_char)) {
1343                                 k = QKbackspace;
1344                                 m &= ~XEMACS_MOD_CONTROL;
1345                         }
1346 #endif                          /* defined(HAVE_TTY)  */
1347                         break;
1348                 }
1349                 if (c >= 'A' && c <= 'Z')
1350                         c -= 'A' - 'a';
1351         }
1352 #if defined(HAVE_TTY)
1353         else if (do_backspace_mapping &&
1354                  CHARP(con->tty_erase_char) && c == XCHAR(con->tty_erase_char))
1355                 k = QKbackspace;
1356 #endif                          /* defined(HAVE_TTY)  */
1357         else if (c == 127)
1358                 k = QKdelete;
1359         else if (c == ' ')
1360                 k = QKspace;
1361
1362         event->event_type = key_press_event;
1363         event->timestamp = 0;   /* #### */
1364         event->channel = make_console(con);
1365         event->event.key.keysym = (!NILP(k) ? k : make_char(c));
1366         event->event.key.modifiers = m;
1367 }
1368
1369 /* This variable controls what character name -> character code mapping
1370    we are using.  Window-system-specific code sets this to some symbol,
1371    and we use that symbol as the plist key to convert keysyms into 8-bit
1372    codes.  In this way one can have several character sets predefined and
1373    switch them by changing this.
1374
1375    #### This is utterly bogus and should be removed.
1376  */
1377 Lisp_Object Vcharacter_set_property;
1378
1379 Emchar
1380 event_to_character(Lisp_Event * event,
1381                    int allow_extra_modifiers,
1382                    int allow_meta, int allow_non_ascii)
1383 {
1384         Emchar c = 0;
1385         Lisp_Object code;
1386
1387         if (event->event_type != key_press_event) {
1388                 assert(event->event_type != dead_event);
1389                 return -1;
1390         }
1391         if (!allow_extra_modifiers &&
1392             event->event.key.
1393             modifiers & (XEMACS_MOD_SUPER | XEMACS_MOD_HYPER | XEMACS_MOD_ALT))
1394                 return -1;
1395         if (CHAR_OR_CHAR_INTP(event->event.key.keysym))
1396                 c = XCHAR_OR_CHAR_INT(event->event.key.keysym);
1397         else if (!SYMBOLP(event->event.key.keysym))
1398                 abort();
1399         else if (allow_non_ascii && !NILP(Vcharacter_set_property)
1400                  /* Allow window-system-specific extensibility of
1401                     keysym->code mapping */
1402                  && CHAR_OR_CHAR_INTP(code = Fget(event->event.key.keysym,
1403                                                   Vcharacter_set_property,
1404                                                   Qnil)))
1405                 c = XCHAR_OR_CHAR_INT(code);
1406         else if (CHAR_OR_CHAR_INTP(code = Fget(event->event.key.keysym,
1407                                                Qascii_character, Qnil)))
1408                 c = XCHAR_OR_CHAR_INT(code);
1409         else
1410                 return -1;
1411
1412         if (event->event.key.modifiers & XEMACS_MOD_CONTROL) {
1413                 if (c >= 'a' && c <= 'z')
1414                         c -= ('a' - 'A');
1415                 else
1416                         /* reject Control-Shift- keys */
1417                 if (c >= 'A' && c <= 'Z' && !allow_extra_modifiers)
1418                         return -1;
1419
1420                 if (c >= '@' && c <= '_')
1421                         c -= '@';
1422                 else if (c == ' ')      /* C-space and C-@ are the same. */
1423                         c = 0;
1424                 else
1425                         /* reject keys that can't take Control- modifiers */
1426                 if (!allow_extra_modifiers)
1427                         return -1;
1428         }
1429
1430         if (event->event.key.modifiers & XEMACS_MOD_META) {
1431                 if (!allow_meta)
1432                         return -1;
1433                 if (c & 0200)
1434                         return -1;      /* don't allow M-oslash (overlap) */
1435 #ifdef MULE
1436                 if (c >= 256)
1437                         return -1;
1438 #endif
1439                 c |= 0200;
1440         }
1441         return c;
1442 }
1443
1444 DEFUN("event-to-character", Fevent_to_character, 1, 4, 0,       /*
1445 Return the closest ASCII approximation to the given event object.
1446 If the event isn't a keypress, this returns nil.
1447 If the ALLOW-EXTRA-MODIFIERS argument is non-nil, then this is lenient in
1448 its translation; it will ignore modifier keys other than control and meta,
1449 and will ignore the shift modifier on those characters which have no
1450 shifted ASCII equivalent (Control-Shift-A for example, will be mapped to
1451 the same ASCII code as Control-A).
1452 If the ALLOW-META argument is non-nil, then the Meta modifier will be
1453 represented by turning on the high bit of the byte returned; otherwise, nil
1454 will be returned for events containing the Meta modifier.
1455 If the ALLOW-NON-ASCII argument is non-nil, then characters which are
1456 present in the prevailing character set (see the `character-set-property'
1457 variable) will be returned as their code in that character set, instead of
1458 the return value being restricted to ASCII.
1459 Note that specifying both ALLOW-META and ALLOW-NON-ASCII is ambiguous, as
1460 both use the high bit; `M-x' and `oslash' will be indistinguishable.
1461 */
1462       (event, allow_extra_modifiers, allow_meta, allow_non_ascii))
1463 {
1464         Emchar c;
1465         CHECK_LIVE_EVENT(event);
1466         c = event_to_character(XEVENT(event),
1467                                !NILP(allow_extra_modifiers),
1468                                !NILP(allow_meta), !NILP(allow_non_ascii));
1469         return c < 0 ? Qnil : make_char(c);
1470 }
1471
1472 DEFUN("character-to-event", Fcharacter_to_event, 1, 4, 0,       /*
1473 Convert KEY-DESCRIPTION into an event structure, replete with bucky bits.
1474
1475 KEY-DESCRIPTION is the first argument, and the event to fill in is the
1476 second.  This function contains knowledge about what various kinds of
1477 arguments ``mean'' -- for example, the number 9 is converted to the
1478 character ``Tab'', not the distinct character ``Control-I''.
1479
1480 KEY-DESCRIPTION can be an integer, a character, a symbol such as 'clear,
1481 or a list such as '(control backspace).
1482
1483 If the optional second argument EVENT is an event, it is modified and
1484 returned; otherwise, a new event object is created and returned.
1485
1486 Optional third arg CONSOLE is the console to store in the event, and
1487 defaults to the selected console.
1488
1489 If KEY-DESCRIPTION is an integer or character, the high bit may be
1490 interpreted as the meta key. (This is done for backward compatibility
1491 in lots of places.)  If USE-CONSOLE-META-FLAG is nil, this will always
1492 be the case.  If USE-CONSOLE-META-FLAG is non-nil, the `meta' flag for
1493 CONSOLE affects whether the high bit is interpreted as a meta
1494 key. (See `set-input-mode'.)  If you don't want this silly meta
1495 interpretation done, you should pass in a list containing the
1496 character.
1497
1498 Beware that character-to-event and event-to-character are not strictly
1499 inverse functions, since events contain much more information than the
1500 Lisp character object type can encode.
1501 */
1502       (keystroke, event, console, use_console_meta_flag))
1503 {
1504         struct console *con = decode_console(console);
1505         if (NILP(event))
1506                 event = Fmake_event(Qnil, Qnil);
1507         else
1508                 CHECK_LIVE_EVENT(event);
1509         if (CONSP(keystroke) || SYMBOLP(keystroke))
1510                 key_desc_list_to_event(keystroke, event, 1);
1511         else {
1512                 CHECK_CHAR_COERCE_INT(keystroke);
1513                 character_to_event(XCHAR(keystroke), XEVENT(event), con,
1514                                    !NILP(use_console_meta_flag), 1);
1515         }
1516         return event;
1517 }
1518
1519 void nth_of_key_sequence_as_event(Lisp_Object seq, int n, Lisp_Object event)
1520 {
1521         assert(STRINGP(seq) || VECTORP(seq));
1522         assert(n < XINT(Flength(seq)));
1523
1524         if (STRINGP(seq)) {
1525                 Emchar ch = string_char(XSTRING(seq), n);
1526                 Fcharacter_to_event(make_char(ch), event, Qnil, Qnil);
1527         } else {
1528                 Lisp_Object keystroke = XVECTOR_DATA(seq)[n];
1529                 if (EVENTP(keystroke))
1530                         Fcopy_event(keystroke, event);
1531                 else
1532                         Fcharacter_to_event(keystroke, event, Qnil, Qnil);
1533         }
1534 }
1535
1536 Lisp_Object key_sequence_to_event_chain(Lisp_Object seq)
1537 {
1538         int len = XINT(Flength(seq));
1539         int i;
1540         Lisp_Object head = Qnil, tail = Qnil;
1541
1542         for (i = 0; i < len; i++) {
1543                 Lisp_Object event = Fmake_event(Qnil, Qnil);
1544                 nth_of_key_sequence_as_event(seq, i, event);
1545                 enqueue_event(event, &head, &tail);
1546         }
1547
1548         return head;
1549 }
1550
1551 void format_event_object(char *buf, Lisp_Event * event, int brief)
1552 {
1553         int mouse_p = 0;
1554         int mod = 0;
1555         Lisp_Object key;
1556
1557         switch (event->event_type) {
1558         case key_press_event: {
1559                 mod = event->event.key.modifiers;
1560                 key = event->event.key.keysym;
1561                 /* Hack. */
1562                 if (!brief && CHARP(key) &&
1563                     mod & (XEMACS_MOD_CONTROL | XEMACS_MOD_META |
1564                            XEMACS_MOD_SUPER | XEMACS_MOD_HYPER)) {
1565                         int k = XCHAR(key);
1566                         if (k >= 'a' && k <= 'z')
1567                                 key = make_char(k - ('a' - 'A'));
1568                         else if (k >= 'A' && k <= 'Z')
1569                                 mod |= XEMACS_MOD_SHIFT;
1570                 }
1571                 break;
1572         }
1573         case button_release_event:
1574                 mouse_p++;
1575                 /* Fall through */
1576         case button_press_event: {
1577                 mouse_p++;
1578                 mod = event->event.button.modifiers;
1579                 key = make_char(event->event.button.button + '0');
1580                 break;
1581         }
1582         case magic_event: {
1583                 const char *name = NULL;
1584
1585 #ifdef HAVE_X_WINDOWS
1586                 Lisp_Object console = CDFW_CONSOLE(EVENT_CHANNEL(event));
1587                 if (CONSOLE_X_P(XCONSOLE(console))) {
1588                         name = x_event_name(event->event.magic.
1589                                             underlying_x_event.
1590                                             type);
1591                 }
1592 #endif                          /* HAVE_X_WINDOWS */
1593
1594                 if (name) {
1595                         strcpy(buf, name);
1596                 } else {
1597                         strcpy(buf, "???");
1598                 }
1599                 return;
1600         }
1601         case magic_eval_event:
1602                 strcpy(buf, "magic-eval");
1603                 return;
1604         case pointer_motion_event:
1605                 strcpy(buf, "motion");
1606                 return;
1607         case misc_user_event:
1608                 strcpy(buf, "misc-user");
1609                 return;
1610         case eval_event:
1611                 strcpy(buf, "eval");
1612                 return;
1613         case process_event:
1614                 strcpy(buf, "process");
1615                 return;
1616         case timeout_event:
1617                 strcpy(buf, "timeout");
1618                 return;
1619         case empty_event:
1620                 strcpy(buf, "empty");
1621                 return;
1622         case dead_event:
1623                 strcpy(buf, "DEAD-EVENT");
1624                 return;
1625 #ifdef EF_USE_ASYNEQ
1626         case eaten_myself_event:
1627                 strcpy(buf, "suicide");
1628                 return;
1629         case work_started_event:
1630                 strcpy(buf, "started-work");
1631                 return;
1632         case work_finished_event:
1633                 strcpy(buf, "finished-work");
1634                 return;
1635 #endif  /* EF_USE_ASYNEQ */
1636
1637         default:
1638                 abort();
1639                 return;
1640         }
1641 #define modprint1(x)  do { strcpy (buf, (x)); buf += sizeof (x)-1; } while (0)
1642 #define modprint(x,y) do { if (brief) modprint1 (y); else modprint1 (x); } while (0)
1643         if (mod & XEMACS_MOD_CONTROL)
1644                 modprint("control-", "C-");
1645         if (mod & XEMACS_MOD_META)
1646                 modprint("meta-", "M-");
1647         if (mod & XEMACS_MOD_SUPER)
1648                 modprint("super-", "S-");
1649         if (mod & XEMACS_MOD_HYPER)
1650                 modprint("hyper-", "H-");
1651         if (mod & XEMACS_MOD_ALT)
1652                 modprint("alt-", "A-");
1653         if (mod & XEMACS_MOD_SHIFT)
1654                 modprint("shift-", "Sh-");
1655         if (mouse_p) {
1656                 modprint1("button");
1657                 --mouse_p;
1658         }
1659 #undef modprint
1660 #undef modprint1
1661
1662         if (CHARP(key)) {
1663                 buf += set_charptr_emchar((Bufbyte *) buf, XCHAR(key));
1664                 *buf = 0;
1665         } else if (SYMBOLP(key)) {
1666                 const char *str = 0;
1667                 if (brief) {
1668                         if (EQ(key, QKlinefeed))
1669                                 str = "LFD";
1670                         else if (EQ(key, QKtab))
1671                                 str = "TAB";
1672                         else if (EQ(key, QKreturn))
1673                                 str = "RET";
1674                         else if (EQ(key, QKescape))
1675                                 str = "ESC";
1676                         else if (EQ(key, QKdelete))
1677                                 str = "DEL";
1678                         else if (EQ(key, QKspace))
1679                                 str = "SPC";
1680                         else if (EQ(key, QKbackspace))
1681                                 str = "BS";
1682                 }
1683                 if (str) {
1684                         int i = strlen(str);
1685                         memcpy(buf, str, i + 1);
1686                         str += i;
1687                 } else {
1688                         Lisp_String *name = XSYMBOL(key)->name;
1689                         memcpy(buf, string_data(name), string_length(name) + 1);
1690                         str += string_length(name);
1691                 }
1692         } else
1693                 abort();
1694         if (mouse_p)
1695                 strncpy(buf, "up", 4);
1696 }
1697
1698 DEFUN("eventp", Feventp, 1, 1, 0,       /*
1699 True if OBJECT is an event object.
1700 */
1701       (object))
1702 {
1703         return EVENTP(object) ? Qt : Qnil;
1704 }
1705
1706 DEFUN("event-live-p", Fevent_live_p, 1, 1, 0,   /*
1707 True if OBJECT is an event object that has not been deallocated.
1708 */
1709       (object))
1710 {
1711         return EVENTP(object) && XEVENT(object)->event_type != dead_event ?
1712             Qt : Qnil;
1713 }
1714
1715 #if 0                           /* debugging functions */
1716
1717 xxDEFUN("event-next", Fevent_next, 1, 1, 0,     /*
1718 Return the event object's `next' event, or nil if it has none.
1719 The `next-event' field is changed by calling `set-next-event'.
1720                                                  */
1721         (event))
1722 {
1723         Lisp_Event *e;
1724         CHECK_LIVE_EVENT(event);
1725
1726         return XEVENT_NEXT(event);
1727 }
1728
1729 xxDEFUN("set-event-next", Fset_event_next, 2, 2, 0,     /*
1730 Set the `next event' of EVENT to NEXT-EVENT.
1731 NEXT-EVENT must be an event object or nil.
1732                                                          */
1733         (event, next_event))
1734 {
1735         Lisp_Object ev;
1736
1737         CHECK_LIVE_EVENT(event);
1738         if (NILP(next_event)) {
1739                 XSET_EVENT_NEXT(event, Qnil);
1740                 return Qnil;
1741         }
1742
1743         CHECK_LIVE_EVENT(next_event);
1744
1745         EVENT_CHAIN_LOOP(ev, XEVENT_NEXT(event)) {
1746                 QUIT;
1747                 if (EQ(ev, event))
1748                         signal_error(Qerror,
1749                                      list3(build_string("Cyclic event-next"),
1750                                            event, next_event));
1751         }
1752         XSET_EVENT_NEXT(event, next_event);
1753         return next_event;
1754 }
1755
1756 #endif                          /* 0 */
1757
1758 DEFUN("event-type", Fevent_type, 1, 1, 0,       /*
1759 Return the type of EVENT.
1760 This will be a symbol; one of
1761
1762 key-press A key was pressed.
1763 button-press      A mouse button was pressed.
1764 button-release    A mouse button was released.
1765 misc-user Some other user action happened; typically, this is
1766 a menu selection or scrollbar action.
1767 motion            The mouse moved.
1768 process           Input is available from a subprocess.
1769 timeout           A timeout has expired.
1770 eval              This causes a specified action to occur when dispatched.
1771 magic             Some window-system-specific event has occurred.
1772 empty             The event has been allocated but not assigned.
1773
1774 */
1775       (event))
1776 {
1777         CHECK_LIVE_EVENT(event);
1778         switch (XEVENT(event)->event_type) {
1779         case key_press_event:
1780                 return Qkey_press;
1781         case button_press_event:
1782                 return Qbutton_press;
1783         case button_release_event:
1784                 return Qbutton_release;
1785         case misc_user_event:
1786                 return Qmisc_user;
1787         case pointer_motion_event:
1788                 return Qmotion;
1789         case process_event:
1790                 return Qprocess;
1791         case timeout_event:
1792                 return Qtimeout;
1793         case eval_event:
1794                 return Qeval;
1795         case magic_event:
1796         case magic_eval_event:
1797                 return Qmagic;
1798
1799 #ifdef EF_USE_ASYNEQ
1800         case eaten_myself_event:
1801                 return Qworker_suicide;
1802         case work_started_event:
1803                 return Qworker_started_work;
1804         case work_finished_event:
1805                 return Qworker_finished_work;
1806 #endif  /* EF_USE_ASYNEQ */
1807
1808         case empty_event:
1809                 return Qempty;
1810
1811         case dead_event:
1812         default:
1813                 abort();
1814                 return Qnil;
1815         }
1816 }
1817
1818 DEFUN("event-timestamp", Fevent_timestamp, 1, 1, 0,     /*
1819 Return the timestamp of the event object EVENT.
1820 Timestamps are measured in milliseconds since the start of the window system.
1821 They are NOT related to any current time measurement.
1822 They should be compared with `event-timestamp<'.
1823 See also `current-event-timestamp'.
1824 */
1825       (event))
1826 {
1827         CHECK_LIVE_EVENT(event);
1828         /* This junk is so that timestamps don't get to be negative, but contain
1829            as many bits as this particular emacs will allow.
1830          */
1831         return make_int(EMACS_INT_MAX & XEVENT(event)->timestamp);
1832 }
1833
1834 #define TIMESTAMP_HALFSPACE (1L << (INT_VALBITS - 2))
1835
1836 DEFUN("event-timestamp<", Fevent_timestamp_lessp, 2, 2, 0,      /*
1837 Return true if timestamp TIME1 is earlier than timestamp TIME2.
1838 This correctly handles timestamp wrap.
1839 See also `event-timestamp' and `current-event-timestamp'.
1840 */
1841       (time1, time2))
1842 {
1843         EMACS_INT t1, t2;
1844
1845         CHECK_NATNUM(time1);
1846         CHECK_NATNUM(time2);
1847         t1 = XINT(time1);
1848         t2 = XINT(time2);
1849
1850         if (t1 < t2)
1851                 return t2 - t1 < TIMESTAMP_HALFSPACE ? Qt : Qnil;
1852         else
1853                 return t1 - t2 < TIMESTAMP_HALFSPACE ? Qnil : Qt;
1854 }
1855
1856 #define CHECK_EVENT_TYPE(e,t1,sym) do {         \
1857   CHECK_LIVE_EVENT (e);                         \
1858   if (XEVENT(e)->event_type != (t1))            \
1859     e = wrong_type_argument (sym,e);            \
1860 } while (0)
1861
1862 #define CHECK_EVENT_TYPE2(e,t1,t2,sym) do {             \
1863   CHECK_LIVE_EVENT (e);                                 \
1864   {                                                     \
1865     emacs_event_type CET_type = XEVENT (e)->event_type; \
1866     if (CET_type != (t1) &&                             \
1867         CET_type != (t2))                               \
1868       e = wrong_type_argument (sym,e);                  \
1869   }                                                     \
1870 } while (0)
1871
1872 #define CHECK_EVENT_TYPE3(e,t1,t2,t3,sym) do {          \
1873   CHECK_LIVE_EVENT (e);                                 \
1874   {                                                     \
1875     emacs_event_type CET_type = XEVENT (e)->event_type; \
1876     if (CET_type != (t1) &&                             \
1877         CET_type != (t2) &&                             \
1878         CET_type != (t3))                               \
1879       e = wrong_type_argument (sym,e);                  \
1880   }                                                     \
1881 } while (0)
1882
1883 DEFUN("event-key", Fevent_key, 1, 1, 0, /*
1884 Return the Keysym of the key-press event EVENT.
1885 This will be a character if the event is associated with one, else a symbol.
1886 */
1887       (event))
1888 {
1889         CHECK_EVENT_TYPE(event, key_press_event, Qkey_press_event_p);
1890         return XEVENT(event)->event.key.keysym;
1891 }
1892
1893 DEFUN("event-button", Fevent_button, 1, 1, 0,   /*
1894 Return the button-number of the button-press or button-release event EVENT.
1895 */
1896       (event))
1897 {
1898
1899         CHECK_EVENT_TYPE3(event, button_press_event, button_release_event,
1900                           misc_user_event, Qbutton_event_p);
1901 #ifdef HAVE_WINDOW_SYSTEM
1902         if (XEVENT(event)->event_type == misc_user_event)
1903                 return make_int(XEVENT(event)->event.misc.button);
1904         else
1905                 return make_int(XEVENT(event)->event.button.button);
1906 #else                           /* !HAVE_WINDOW_SYSTEM */
1907         return Qzero;
1908 #endif                          /* !HAVE_WINDOW_SYSTEM */
1909
1910 }
1911
1912 DEFUN("event-modifier-bits", Fevent_modifier_bits, 1, 1, 0,     /*
1913 Return a number representing the modifier keys and buttons which were down
1914 when the given mouse or keyboard event was produced.
1915 See also the function `event-modifiers'.
1916 */
1917       (event))
1918 {
1919       again:
1920         CHECK_LIVE_EVENT(event);
1921         switch (XEVENT(event)->event_type) {
1922         case key_press_event:
1923                 return make_int(XEVENT(event)->event.key.modifiers);
1924         case button_press_event:
1925         case button_release_event:
1926                 return make_int(XEVENT(event)->event.button.modifiers);
1927         case pointer_motion_event:
1928                 return make_int(XEVENT(event)->event.motion.modifiers);
1929         case misc_user_event:
1930                 return make_int(XEVENT(event)->event.misc.modifiers);
1931
1932         case empty_event:
1933         case process_event:
1934         case timeout_event:
1935         case magic_event:
1936         case magic_eval_event:
1937         case eval_event:
1938 #ifdef EF_USE_ASYNEQ
1939         case eaten_myself_event:
1940         case work_started_event:
1941         case work_finished_event:
1942 #endif  /* EF_USE_ASYNEQ */
1943         case dead_event:
1944         default:
1945                 event = wrong_type_argument(
1946                         intern("key-or-mouse-event-p"), event);
1947                 goto again;
1948         }
1949 }
1950
1951 DEFUN("event-modifiers", Fevent_modifiers, 1, 1, 0,     /*
1952 Return a list of symbols, the names of the modifier keys and buttons
1953 which were down when the given mouse or keyboard event was produced.
1954 See also the function `event-modifier-bits'.
1955
1956 The possible symbols in the list are
1957
1958 `shift':     The Shift key.  Will not appear, in general, on key events
1959 where the keysym is an ASCII character, because using Shift
1960 on such a character converts it into another character rather
1961 than actually just adding a Shift modifier.
1962
1963 `control':   The Control key.
1964
1965 `meta':      The Meta key.  On PC's and PC-style keyboards, this is generally
1966 labelled \"Alt\"; Meta is a holdover from early Lisp Machines and
1967 such, propagated through the X Window System.  On Sun keyboards,
1968 this key is labelled with a diamond.
1969
1970 `alt':       The \"Alt\" key.  Alt is in quotes because this does not refer
1971 to what it obviously should refer to, namely the Alt key on PC
1972 keyboards.  Instead, it refers to the key labelled Alt on Sun
1973 keyboards, and to no key at all on PC keyboards.
1974
1975 `super':     The Super key.  Most keyboards don't have any such key, but
1976 under X Windows using `xmodmap' you can assign any key (such as
1977 an underused right-shift, right-control, or right-alt key) to
1978 this key modifier.
1979
1980 `hyper':     The Hyper key.  Works just like the Super key.
1981
1982 `button1':   The mouse buttons.  This means that the specified button was held
1983 `button2':   down at the time the event occurred.  NOTE: For button-press
1984 `button3':   events, the button that was just pressed down does NOT appear in
1985 `button4':   the modifiers.
1986 `button5':
1987
1988 Button modifiers are currently ignored when defining and looking up key and
1989 mouse strokes in keymaps.  This could be changed, which would allow a user to
1990 create button-chord actions, use a button as a key modifier and do other
1991 clever things.
1992 */
1993       (event))
1994 {
1995         int mod = XINT(Fevent_modifier_bits(event));
1996         Lisp_Object result = Qnil;
1997         struct gcpro gcpro1;
1998
1999         GCPRO1(result);
2000         if (mod & XEMACS_MOD_SHIFT)
2001                 result = Fcons(Qshift, result);
2002         if (mod & XEMACS_MOD_ALT)
2003                 result = Fcons(Qalt, result);
2004         if (mod & XEMACS_MOD_HYPER)
2005                 result = Fcons(Qhyper, result);
2006         if (mod & XEMACS_MOD_SUPER)
2007                 result = Fcons(Qsuper, result);
2008         if (mod & XEMACS_MOD_META)
2009                 result = Fcons(Qmeta, result);
2010         if (mod & XEMACS_MOD_CONTROL)
2011                 result = Fcons(Qcontrol, result);
2012         if (mod & XEMACS_MOD_BUTTON1)
2013                 result = Fcons(Qbutton1, result);
2014         if (mod & XEMACS_MOD_BUTTON2)
2015                 result = Fcons(Qbutton2, result);
2016         if (mod & XEMACS_MOD_BUTTON3)
2017                 result = Fcons(Qbutton3, result);
2018         if (mod & XEMACS_MOD_BUTTON4)
2019                 result = Fcons(Qbutton4, result);
2020         if (mod & XEMACS_MOD_BUTTON5)
2021                 result = Fcons(Qbutton5, result);
2022         RETURN_UNGCPRO(Fnreverse(result));
2023 }
2024
2025 static int
2026 event_x_y_pixel_internal(Lisp_Object event, int *x, int *y, int relative)
2027 {
2028         struct window *w;
2029         struct frame *f;
2030
2031         if (XEVENT(event)->event_type == pointer_motion_event) {
2032                 *x = XEVENT(event)->event.motion.x;
2033                 *y = XEVENT(event)->event.motion.y;
2034         } else if (XEVENT(event)->event_type == button_press_event ||
2035                    XEVENT(event)->event_type == button_release_event) {
2036                 *x = XEVENT(event)->event.button.x;
2037                 *y = XEVENT(event)->event.button.y;
2038         } else if (XEVENT(event)->event_type == misc_user_event) {
2039                 *x = XEVENT(event)->event.misc.x;
2040                 *y = XEVENT(event)->event.misc.y;
2041         } else
2042                 return 0;
2043
2044         f = XFRAME(EVENT_CHANNEL(XEVENT(event)));
2045
2046         if (relative) {
2047                 w = find_window_by_pixel_pos(*x, *y, f->root_window);
2048
2049                 if (!w)
2050                         return 1;       /* #### What should really happen here? */
2051
2052                 *x -= w->pixel_left;
2053                 *y -= w->pixel_top;
2054         } else {
2055                 *y -= FRAME_REAL_TOP_TOOLBAR_HEIGHT(f) -
2056                     FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH(f);
2057                 *x -= FRAME_REAL_LEFT_TOOLBAR_WIDTH(f) -
2058                     FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH(f);
2059         }
2060
2061         return 1;
2062 }
2063
2064 DEFUN("event-window-x-pixel", Fevent_window_x_pixel, 1, 1, 0,   /*
2065 Return the X position in pixels of mouse event EVENT.
2066 The value returned is relative to the window the event occurred in.
2067 This will signal an error if the event is not a mouse event.
2068 See also `mouse-event-p' and `event-x-pixel'.
2069 */
2070       (event))
2071 {
2072         int x, y;
2073
2074         CHECK_LIVE_EVENT(event);
2075
2076         if (!event_x_y_pixel_internal(event, &x, &y, 1))
2077                 return wrong_type_argument(Qmouse_event_p, event);
2078         else
2079                 return make_int(x);
2080 }
2081
2082 DEFUN("event-window-y-pixel", Fevent_window_y_pixel, 1, 1, 0,   /*
2083 Return the Y position in pixels of mouse event EVENT.
2084 The value returned is relative to the window the event occurred in.
2085 This will signal an error if the event is not a mouse event.
2086 See also `mouse-event-p' and `event-y-pixel'.
2087 */
2088       (event))
2089 {
2090         int x, y;
2091
2092         CHECK_LIVE_EVENT(event);
2093
2094         if (!event_x_y_pixel_internal(event, &x, &y, 1))
2095                 return wrong_type_argument(Qmouse_event_p, event);
2096         else
2097                 return make_int(y);
2098 }
2099
2100 DEFUN("event-x-pixel", Fevent_x_pixel, 1, 1, 0, /*
2101 Return the X position in pixels of mouse event EVENT.
2102 The value returned is relative to the frame the event occurred in.
2103 This will signal an error if the event is not a mouse event.
2104 See also `mouse-event-p' and `event-window-x-pixel'.
2105 */
2106       (event))
2107 {
2108         int x, y;
2109
2110         CHECK_LIVE_EVENT(event);
2111
2112         if (!event_x_y_pixel_internal(event, &x, &y, 0))
2113                 return wrong_type_argument(Qmouse_event_p, event);
2114         else
2115                 return make_int(x);
2116 }
2117
2118 DEFUN("event-y-pixel", Fevent_y_pixel, 1, 1, 0, /*
2119 Return the Y position in pixels of mouse event EVENT.
2120 The value returned is relative to the frame the event occurred in.
2121 This will signal an error if the event is not a mouse event.
2122 See also `mouse-event-p' `event-window-y-pixel'.
2123 */
2124       (event))
2125 {
2126         int x, y;
2127
2128         CHECK_LIVE_EVENT(event);
2129
2130         if (!event_x_y_pixel_internal(event, &x, &y, 0))
2131                 return wrong_type_argument(Qmouse_event_p, event);
2132         else
2133                 return make_int(y);
2134 }
2135
2136 /* Given an event, return a value:
2137
2138      OVER_TOOLBAR:      over one of the 4 frame toolbars
2139      OVER_MODELINE:     over a modeline
2140      OVER_BORDER:       over an internal border
2141      OVER_NOTHING:      over the text area, but not over text
2142      OVER_OUTSIDE:      outside of the frame border
2143      OVER_TEXT:         over text in the text area
2144      OVER_V_DIVIDER:    over windows vertical divider
2145
2146    and return:
2147
2148    The X char position in CHAR_X, if not a null pointer.
2149    The Y char position in CHAR_Y, if not a null pointer.
2150    (These last two values are relative to the window the event is over.)
2151    The window it's over in W, if not a null pointer.
2152    The buffer position it's over in BUFP, if not a null pointer.
2153    The closest buffer position in CLOSEST, if not a null pointer.
2154
2155    OBJ_X, OBJ_Y, OBJ1, and OBJ2 are as in pixel_to_glyph_translation().
2156 */
2157
2158 static int
2159 event_pixel_translation(Lisp_Object event, int *char_x, int *char_y,
2160                         int *obj_x, int *obj_y,
2161                         struct window **w, Bufpos * bufp, Bufpos * closest,
2162                         Charcount * modeline_closest,
2163                         Lisp_Object * obj1, Lisp_Object * obj2)
2164 {
2165         int pix_x = 0;
2166         int pix_y = 0;
2167         int result;
2168         Lisp_Object frame;
2169
2170         int ret_x, ret_y, ret_obj_x, ret_obj_y;
2171         struct window *ret_w;
2172         Bufpos ret_bufp, ret_closest;
2173         Charcount ret_modeline_closest;
2174         Lisp_Object ret_obj1, ret_obj2;
2175
2176         CHECK_LIVE_EVENT(event);
2177         frame = XEVENT(event)->channel;
2178         switch (XEVENT(event)->event_type) {
2179         case pointer_motion_event:
2180                 pix_x = XEVENT(event)->event.motion.x;
2181                 pix_y = XEVENT(event)->event.motion.y;
2182                 break;
2183         case button_press_event:
2184         case button_release_event:
2185                 pix_x = XEVENT(event)->event.button.x;
2186                 pix_y = XEVENT(event)->event.button.y;
2187                 break;
2188         case misc_user_event:
2189                 pix_x = XEVENT(event)->event.misc.x;
2190                 pix_y = XEVENT(event)->event.misc.y;
2191                 break;
2192
2193         case empty_event:
2194         case key_press_event:
2195         case process_event:
2196         case timeout_event:
2197         case magic_event:
2198         case magic_eval_event:
2199         case eval_event:
2200 #ifdef EF_USE_ASYNEQ
2201         case eaten_myself_event:
2202         case work_started_event:
2203         case work_finished_event:
2204 #endif  /* EF_USE_ASYNEQ */
2205         case dead_event:
2206         default:
2207                 dead_wrong_type_argument(Qmouse_event_p, event);
2208         }
2209
2210         result = pixel_to_glyph_translation(XFRAME(frame), pix_x, pix_y,
2211                                             &ret_x, &ret_y, &ret_obj_x,
2212                                             &ret_obj_y, &ret_w, &ret_bufp,
2213                                             &ret_closest, &ret_modeline_closest,
2214                                             &ret_obj1, &ret_obj2);
2215
2216         if (result == OVER_NOTHING || result == OVER_OUTSIDE)
2217                 ret_bufp = 0;
2218         else if (ret_w && NILP(ret_w->buffer))
2219                 /* Why does this happen?  (Does it still happen?)
2220                    I guess the window has gotten reused as a non-leaf... */
2221                 ret_w = 0;
2222
2223         /* #### pixel_to_glyph_translation() sometimes returns garbage...
2224            The word has type Lisp_Type_Record (presumably meaning `extent') but the
2225            pointer points to random memory, often filled with 0, sometimes not.
2226          */
2227         /* #### Chuck, do we still need this crap? */
2228         if (!NILP(ret_obj1) && !(GLYPHP(ret_obj1)
2229 #ifdef HAVE_TOOLBARS
2230                                  || TOOLBAR_BUTTONP(ret_obj1)
2231 #endif
2232             ))
2233                 abort();
2234         if (!NILP(ret_obj2) && !(EXTENTP(ret_obj2) || CONSP(ret_obj2)))
2235                 abort();
2236
2237         if (char_x)
2238                 *char_x = ret_x;
2239         if (char_y)
2240                 *char_y = ret_y;
2241         if (obj_x)
2242                 *obj_x = ret_obj_x;
2243         if (obj_y)
2244                 *obj_y = ret_obj_y;
2245         if (w)
2246                 *w = ret_w;
2247         if (bufp)
2248                 *bufp = ret_bufp;
2249         if (closest)
2250                 *closest = ret_closest;
2251         if (modeline_closest)
2252                 *modeline_closest = ret_modeline_closest;
2253         if (obj1)
2254                 *obj1 = ret_obj1;
2255         if (obj2)
2256                 *obj2 = ret_obj2;
2257
2258         return result;
2259 }
2260
2261 DEFUN("event-over-text-area-p", Fevent_over_text_area_p, 1, 1, 0,       /*
2262 Return t if the mouse event EVENT occurred over the text area of a window.
2263 The modeline is not considered to be part of the text area.
2264 */
2265       (event))
2266 {
2267         int result =
2268             event_pixel_translation(event, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2269
2270         return result == OVER_TEXT || result == OVER_NOTHING ? Qt : Qnil;
2271 }
2272
2273 DEFUN("event-over-modeline-p", Fevent_over_modeline_p, 1, 1, 0, /*
2274 Return t if the mouse event EVENT occurred over the modeline of a window.
2275 */
2276       (event))
2277 {
2278         int result =
2279             event_pixel_translation(event, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2280
2281         return result == OVER_MODELINE ? Qt : Qnil;
2282 }
2283
2284 DEFUN("event-over-border-p", Fevent_over_border_p, 1, 1, 0,     /*
2285 Return t if the mouse event EVENT occurred over an internal border.
2286 */
2287       (event))
2288 {
2289         int result =
2290             event_pixel_translation(event, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2291
2292         return result == OVER_BORDER ? Qt : Qnil;
2293 }
2294
2295 DEFUN("event-over-toolbar-p", Fevent_over_toolbar_p, 1, 1, 0,   /*
2296 Return t if the mouse event EVENT occurred over a toolbar.
2297 */
2298       (event))
2299 {
2300         int result =
2301             event_pixel_translation(event, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2302
2303         return result == OVER_TOOLBAR ? Qt : Qnil;
2304 }
2305
2306 DEFUN("event-over-vertical-divider-p", Fevent_over_vertical_divider_p, 1, 1, 0, /*
2307 Return t if the mouse event EVENT occurred over a window divider.
2308 */
2309       (event))
2310 {
2311         int result =
2312             event_pixel_translation(event, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2313
2314         return result == OVER_V_DIVIDER ? Qt : Qnil;
2315 }
2316
2317 struct console *event_console_or_selected(Lisp_Object event)
2318 {
2319         Lisp_Object channel = EVENT_CHANNEL(XEVENT(event));
2320         Lisp_Object console = CDFW_CONSOLE(channel);
2321
2322         if (NILP(console))
2323                 console = Vselected_console;
2324
2325         return XCONSOLE(console);
2326 }
2327
2328 DEFUN("event-channel", Fevent_channel, 1, 1, 0, /*
2329 Return the channel that the event EVENT occurred on.
2330 This will be a frame, device, console, or nil for some types
2331 of events (e.g. eval events).
2332 */
2333       (event))
2334 {
2335         CHECK_LIVE_EVENT(event);
2336         return EVENT_CHANNEL(XEVENT(event));
2337 }
2338
2339 DEFUN("event-window", Fevent_window, 1, 1, 0,   /*
2340 Return the window over which mouse event EVENT occurred.
2341 This may be nil if the event occurred in the border or over a toolbar.
2342 The modeline is considered to be within the window it describes.
2343 */
2344       (event))
2345 {
2346         struct window *w;
2347
2348         event_pixel_translation(event, 0, 0, 0, 0, &w, 0, 0, 0, 0, 0);
2349
2350         if (!w)
2351                 return Qnil;
2352         else {
2353                 Lisp_Object window;
2354
2355                 XSETWINDOW(window, w);
2356                 return window;
2357         }
2358 }
2359
2360 DEFUN("event-point", Fevent_point, 1, 1, 0,     /*
2361 Return the character position of the mouse event EVENT.
2362 If the event did not occur over a window, or did not occur over text,
2363 then this returns nil.  Otherwise, it returns a position in the buffer
2364 visible in the event's window.
2365 */
2366       (event))
2367 {
2368         Bufpos bufp;
2369         struct window *w;
2370
2371         event_pixel_translation(event, 0, 0, 0, 0, &w, &bufp, 0, 0, 0, 0);
2372
2373         return w && bufp ? make_int(bufp) : Qnil;
2374 }
2375
2376 DEFUN("event-closest-point", Fevent_closest_point, 1, 1, 0,     /*
2377 Return the character position closest to the mouse event EVENT.
2378 If the event did not occur over a window or over text, return the
2379 closest point to the location of the event.  If the Y pixel position
2380 overlaps a window and the X pixel position is to the left of that
2381 window, the closest point is the beginning of the line containing the
2382 Y position.  If the Y pixel position overlaps a window and the X pixel
2383 position is to the right of that window, the closest point is the end
2384 of the line containing the Y position.  If the Y pixel position is
2385 above a window, return 0.  If it is below the last character in a window,
2386 return the value of (window-end).
2387 */
2388       (event))
2389 {
2390         Bufpos bufp;
2391
2392         event_pixel_translation(event, 0, 0, 0, 0, 0, 0, &bufp, 0, 0, 0);
2393
2394         return bufp ? make_int(bufp) : Qnil;
2395 }
2396
2397 DEFUN("event-x", Fevent_x, 1, 1, 0,     /*
2398 Return the X position of the mouse event EVENT in characters.
2399 This is relative to the window the event occurred over.
2400 */
2401       (event))
2402 {
2403         int char_x;
2404
2405         event_pixel_translation(event, &char_x, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2406
2407         return make_int(char_x);
2408 }
2409
2410 DEFUN("event-y", Fevent_y, 1, 1, 0,     /*
2411 Return the Y position of the mouse event EVENT in characters.
2412 This is relative to the window the event occurred over.
2413 */
2414       (event))
2415 {
2416         int char_y;
2417
2418         event_pixel_translation(event, 0, &char_y, 0, 0, 0, 0, 0, 0, 0, 0);
2419
2420         return make_int(char_y);
2421 }
2422
2423 DEFUN("event-modeline-position", Fevent_modeline_position, 1, 1, 0,     /*
2424 Return the character position in the modeline that EVENT occurred over.
2425 EVENT should be a mouse event.  If EVENT did not occur over a modeline,
2426 nil is returned.  You can determine the actual character that the
2427 event occurred over by looking in `generated-modeline-string' at the
2428 returned character position.  Note that `generated-modeline-string'
2429 is buffer-local, and you must use EVENT's buffer when retrieving
2430 `generated-modeline-string' in order to get accurate results.
2431 */
2432       (event))
2433 {
2434         Charcount mbufp;
2435         int where;
2436
2437         where =
2438             event_pixel_translation(event, 0, 0, 0, 0, 0, 0, 0, &mbufp, 0, 0);
2439
2440         return (mbufp < 0 || where != OVER_MODELINE) ? Qnil : make_int(mbufp);
2441 }
2442
2443 DEFUN("event-glyph", Fevent_glyph, 1, 1, 0,     /*
2444 Return the glyph that the mouse event EVENT occurred over, or nil.
2445 */
2446       (event))
2447 {
2448         Lisp_Object glyph;
2449         struct window *w;
2450
2451         event_pixel_translation(event, 0, 0, 0, 0, &w, 0, 0, 0, &glyph, 0);
2452
2453         return w && GLYPHP(glyph) ? glyph : Qnil;
2454 }
2455
2456 DEFUN("event-glyph-extent", Fevent_glyph_extent, 1, 1, 0,       /*
2457 Return the extent of the glyph that the mouse event EVENT occurred over.
2458 If the event did not occur over a glyph, nil is returned.
2459 */
2460       (event))
2461 {
2462         Lisp_Object extent;
2463         struct window *w;
2464
2465         event_pixel_translation(event, 0, 0, 0, 0, &w, 0, 0, 0, 0, &extent);
2466
2467         return w && EXTENTP(extent) ? extent : Qnil;
2468 }
2469
2470 DEFUN("event-glyph-x-pixel", Fevent_glyph_x_pixel, 1, 1, 0,     /*
2471 Return the X pixel position of EVENT relative to the glyph it occurred over.
2472 EVENT should be a mouse event.  If the event did not occur over a glyph,
2473 nil is returned.
2474 */
2475       (event))
2476 {
2477         Lisp_Object extent;
2478         struct window *w;
2479         int obj_x;
2480
2481         event_pixel_translation(event, 0, 0, &obj_x, 0, &w, 0, 0, 0, 0,
2482                                 &extent);
2483
2484         return w && EXTENTP(extent) ? make_int(obj_x) : Qnil;
2485 }
2486
2487 DEFUN("event-glyph-y-pixel", Fevent_glyph_y_pixel, 1, 1, 0,     /*
2488 Return the Y pixel position of EVENT relative to the glyph it occurred over.
2489 EVENT should be a mouse event.  If the event did not occur over a glyph,
2490 nil is returned.
2491 */
2492       (event))
2493 {
2494         Lisp_Object extent;
2495         struct window *w;
2496         int obj_y;
2497
2498         event_pixel_translation(event, 0, 0, 0, &obj_y, &w, 0, 0, 0, 0,
2499                                 &extent);
2500
2501         return w && EXTENTP(extent) ? make_int(obj_y) : Qnil;
2502 }
2503
2504 DEFUN("event-toolbar-button", Fevent_toolbar_button, 1, 1, 0,   /*
2505 Return the toolbar button that the mouse event EVENT occurred over.
2506 If the event did not occur over a toolbar button, nil is returned.
2507 */
2508       (event))
2509 {
2510 #ifdef HAVE_TOOLBARS
2511         Lisp_Object button;
2512
2513         int result =
2514             event_pixel_translation(event, 0, 0, 0, 0, 0, 0, 0, 0, &button, 0);
2515
2516         return result == OVER_TOOLBAR
2517             && TOOLBAR_BUTTONP(button) ? button : Qnil;
2518 #else
2519         return Qnil;
2520 #endif
2521 }
2522
2523 DEFUN("event-process", Fevent_process, 1, 1, 0, /*
2524 Return the process of the process-output event EVENT.
2525 */
2526       (event))
2527 {
2528         CHECK_EVENT_TYPE(event, process_event, Qprocess_event_p);
2529         return XEVENT(event)->event.process.process;
2530 }
2531
2532 DEFUN("event-function", Fevent_function, 1, 1, 0,       /*
2533 Return the callback function of EVENT.
2534 EVENT should be a timeout, misc-user, or eval event.
2535 */
2536       (event))
2537 {
2538       again:
2539         CHECK_LIVE_EVENT(event);
2540         switch (XEVENT(event)->event_type) {
2541         case timeout_event:
2542                 return XEVENT(event)->event.timeout.function;
2543         case misc_user_event:
2544                 return XEVENT(event)->event.misc.function;
2545         case eval_event:
2546                 return XEVENT(event)->event.eval.function;
2547
2548         case empty_event:
2549         case key_press_event:
2550         case button_press_event:
2551         case button_release_event:
2552         case pointer_motion_event:
2553         case process_event:
2554         case magic_event:
2555         case magic_eval_event:
2556 #ifdef EF_USE_ASYNEQ
2557         case eaten_myself_event:
2558         case work_started_event:
2559         case work_finished_event:
2560 #endif  /* EF_USE_ASYNEQ */
2561         case dead_event:
2562         default:
2563                 event =
2564                     wrong_type_argument(intern("timeout-or-eval-event-p"),
2565                                         event);
2566                 goto again;
2567         }
2568 }
2569
2570 DEFUN("event-object", Fevent_object, 1, 1, 0,   /*
2571 Return the callback function argument of EVENT.
2572 EVENT should be a timeout, misc-user, or eval event.
2573 */
2574       (event))
2575 {
2576 again:
2577         CHECK_LIVE_EVENT(event);
2578         switch (XEVENT(event)->event_type) {
2579         case timeout_event:
2580                 return XEVENT(event)->event.timeout.object;
2581         case misc_user_event:
2582                 return XEVENT(event)->event.misc.object;
2583         case eval_event:
2584                 return XEVENT(event)->event.eval.object;
2585
2586         case empty_event:
2587         case key_press_event:
2588         case button_press_event:
2589         case button_release_event:
2590         case pointer_motion_event:
2591         case process_event:
2592         case magic_event:
2593         case magic_eval_event:
2594 #ifdef EF_USE_ASYNEQ
2595         case eaten_myself_event:
2596         case work_started_event:
2597         case work_finished_event:
2598 #endif  /* EF_USE_ASYNEQ */
2599         case dead_event:
2600         default:
2601                 event = wrong_type_argument(
2602                         intern("timeout-or-eval-event-p"), event);
2603                 goto again;
2604         }
2605 }
2606
2607 DEFUN("event-properties", Fevent_properties, 1, 1, 0,   /*
2608 Return a list of all of the properties of EVENT.
2609 This is in the form of a property list (alternating keyword/value pairs).
2610 */
2611       (event))
2612 {
2613         Lisp_Object props = Qnil;
2614         Lisp_Event *e;
2615         struct gcpro gcpro1;
2616
2617         CHECK_LIVE_EVENT(event);
2618         e = XEVENT(event);
2619         GCPRO1(props);
2620
2621         props = cons3(Qtimestamp, Fevent_timestamp(event), props);
2622
2623         switch (e->event_type) {
2624         default:
2625                 abort();
2626                 break;
2627
2628         case process_event:
2629                 props = cons3(Qprocess, e->event.process.process, props);
2630                 break;
2631
2632         case timeout_event:
2633                 props = cons3(Qobject, Fevent_object(event), props);
2634                 props = cons3(Qfunction, Fevent_function(event), props);
2635                 props = cons3(Qid, make_int(e->event.timeout.id_number), props);
2636                 break;
2637
2638         case key_press_event:
2639                 props = cons3(Qmodifiers, Fevent_modifiers(event), props);
2640                 props = cons3(Qkey, Fevent_key(event), props);
2641                 break;
2642
2643         case button_press_event:
2644         case button_release_event:
2645                 props = cons3(Qy, Fevent_y_pixel(event), props);
2646                 props = cons3(Qx, Fevent_x_pixel(event), props);
2647                 props = cons3(Qmodifiers, Fevent_modifiers(event), props);
2648                 props = cons3(Qbutton, Fevent_button(event), props);
2649                 break;
2650
2651         case pointer_motion_event:
2652                 props = cons3(Qmodifiers, Fevent_modifiers(event), props);
2653                 props = cons3(Qy, Fevent_y_pixel(event), props);
2654                 props = cons3(Qx, Fevent_x_pixel(event), props);
2655                 break;
2656
2657         case misc_user_event:
2658                 props = cons3(Qobject, Fevent_object(event), props);
2659                 props = cons3(Qfunction, Fevent_function(event), props);
2660                 props = cons3(Qy, Fevent_y_pixel(event), props);
2661                 props = cons3(Qx, Fevent_x_pixel(event), props);
2662                 props = cons3(Qmodifiers, Fevent_modifiers(event), props);
2663                 props = cons3(Qbutton, Fevent_button(event), props);
2664                 break;
2665
2666         case eval_event:
2667                 props = cons3(Qobject, Fevent_object(event), props);
2668                 props = cons3(Qfunction, Fevent_function(event), props);
2669                 break;
2670
2671 #ifdef EF_USE_ASYNEQ
2672                 /* are these right here? */
2673         case eaten_myself_event:
2674         case work_started_event:
2675         case work_finished_event:
2676 #endif  /* EF_USE_ASYNEQ */
2677         case dead_event:
2678
2679         case magic_eval_event:
2680         case magic_event:
2681                 break;
2682
2683         case empty_event:
2684                 RETURN_UNGCPRO(Qnil);
2685                 break;
2686         }
2687
2688         props = cons3(Qchannel, Fevent_channel(event), props);
2689         UNGCPRO;
2690
2691         return props;
2692 }
2693 \f
2694 /************************************************************************/
2695 /*                            initialization                            */
2696 /************************************************************************/
2697
2698 void syms_of_events(void)
2699 {
2700         INIT_LRECORD_IMPLEMENTATION(event);
2701
2702         DEFSUBR(Fcharacter_to_event);
2703         DEFSUBR(Fevent_to_character);
2704
2705         DEFSUBR(Fmake_event);
2706         DEFSUBR(Fdeallocate_event);
2707         DEFSUBR(Fcopy_event);
2708         DEFSUBR(Feventp);
2709         DEFSUBR(Fevent_live_p);
2710         DEFSUBR(Fevent_type);
2711         DEFSUBR(Fevent_properties);
2712
2713         DEFSUBR(Fevent_timestamp);
2714         DEFSUBR(Fevent_timestamp_lessp);
2715         DEFSUBR(Fevent_key);
2716         DEFSUBR(Fevent_button);
2717         DEFSUBR(Fevent_modifier_bits);
2718         DEFSUBR(Fevent_modifiers);
2719         DEFSUBR(Fevent_x_pixel);
2720         DEFSUBR(Fevent_y_pixel);
2721         DEFSUBR(Fevent_window_x_pixel);
2722         DEFSUBR(Fevent_window_y_pixel);
2723         DEFSUBR(Fevent_over_text_area_p);
2724         DEFSUBR(Fevent_over_modeline_p);
2725         DEFSUBR(Fevent_over_border_p);
2726         DEFSUBR(Fevent_over_toolbar_p);
2727         DEFSUBR(Fevent_over_vertical_divider_p);
2728         DEFSUBR(Fevent_channel);
2729         DEFSUBR(Fevent_window);
2730         DEFSUBR(Fevent_point);
2731         DEFSUBR(Fevent_closest_point);
2732         DEFSUBR(Fevent_x);
2733         DEFSUBR(Fevent_y);
2734         DEFSUBR(Fevent_modeline_position);
2735         DEFSUBR(Fevent_glyph);
2736         DEFSUBR(Fevent_glyph_extent);
2737         DEFSUBR(Fevent_glyph_x_pixel);
2738         DEFSUBR(Fevent_glyph_y_pixel);
2739         DEFSUBR(Fevent_toolbar_button);
2740         DEFSUBR(Fevent_process);
2741         DEFSUBR(Fevent_function);
2742         DEFSUBR(Fevent_object);
2743
2744         defsymbol(&Qeventp, "eventp");
2745         defsymbol(&Qevent_live_p, "event-live-p");
2746         defsymbol(&Qkey_press_event_p, "key-press-event-p");
2747         defsymbol(&Qbutton_event_p, "button-event-p");
2748         defsymbol(&Qmouse_event_p, "mouse-event-p");
2749         defsymbol(&Qprocess_event_p, "process-event-p");
2750         defsymbol(&Qkey_press, "key-press");
2751         defsymbol(&Qbutton_press, "button-press");
2752         defsymbol(&Qbutton_release, "button-release");
2753         defsymbol(&Qmisc_user, "misc-user");
2754         defsymbol(&Qascii_character, "ascii-character");
2755
2756         defsymbol(&QKbackspace, "backspace");
2757         defsymbol(&QKtab, "tab");
2758         defsymbol(&QKlinefeed, "linefeed");
2759         defsymbol(&QKreturn, "return");
2760         defsymbol(&QKescape, "escape");
2761         defsymbol(&QKspace, "space");
2762         defsymbol(&QKdelete, "delete");
2763 }
2764
2765 void reinit_vars_of_events(void)
2766 {
2767         init_Vevent_resource();
2768 }
2769
2770 void vars_of_events(void)
2771 {
2772         reinit_vars_of_events();
2773
2774         DEFVAR_LISP("character-set-property", &Vcharacter_set_property  /*
2775 A symbol used to look up the 8-bit character of a keysym.
2776 To convert a keysym symbol to an 8-bit code, as when that key is
2777 bound to self-insert-command, we will look up the property that this
2778 variable names on the property list of the keysym-symbol.  The window-
2779 system-specific code will set up appropriate properties and set this
2780 variable.
2781                                                                          */ );
2782         Vcharacter_set_property = Qnil;
2783 }