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