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