XEmacs 21.2.34 "Molpe".
[chise/xemacs-chise.git.1] / src / gui-x.c
1 /* General GUI code -- X-specific. (menubars, scrollbars, toolbars, dialogs)
2    Copyright (C) 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1995, 1996 Ben Wing.
4    Copyright (C) 1995 Sun Microsystems, Inc.
5    Copyright (C) 1998 Free Software Foundation, Inc.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Synched up with: Not in FSF. */
25
26 #include <config.h>
27 #include "lisp.h"
28
29 #include "console-x.h"
30 #ifdef LWLIB_USES_MOTIF
31 #include <Xm/Xm.h> /* for XmVersion */
32 #endif
33 #include "gui-x.h"
34 #include "buffer.h"
35 #include "device.h"
36 #include "events.h"
37 #include "frame.h"
38 #include "gui.h"
39 #include "glyphs.h"
40 #include "redisplay.h"
41 #include "opaque.h"
42
43 Lisp_Object Qmenu_no_selection_hook;
44
45 /* we need a unique id for each popup menu, dialog box, and scrollbar */
46 static unsigned int lwlib_id_tick;
47
48 LWLIB_ID
49 new_lwlib_id (void)
50 {
51   return ++lwlib_id_tick;
52 }
53
54 widget_value *
55 xmalloc_widget_value (void)
56 {
57   widget_value *tmp = malloc_widget_value ();
58   if (!tmp) memory_full ();
59   return tmp;
60 }
61
62 \f
63 static int
64 mark_widget_value_mapper (widget_value *val, void *closure)
65 {
66   Lisp_Object markee;
67   if (val->call_data)
68     {
69       VOID_TO_LISP (markee, val->call_data);
70       mark_object (markee);
71     }
72
73   if (val->accel)
74     {
75       VOID_TO_LISP (markee, val->accel);
76       mark_object (markee);
77     }
78   return 0;
79 }
80
81 static Lisp_Object
82 mark_popup_data (Lisp_Object obj)
83 {
84   struct popup_data *data = (struct popup_data *) XPOPUP_DATA (obj);
85
86   /* Now mark the callbacks and such that are hidden in the lwlib
87      call-data */
88
89   if (data->id)
90     lw_map_widget_values (data->id, mark_widget_value_mapper, 0);
91
92   return data->last_menubar_buffer;
93 }
94
95 DEFINE_LRECORD_IMPLEMENTATION ("popup-data", popup_data,
96                                mark_popup_data, internal_object_printer,
97                                0, 0, 0, 0, struct popup_data);
98 \f
99 /* This is like FRAME_MENUBAR_DATA (f), but contains an alist of
100    (id . popup-data) for GCPRO'ing the callbacks of the popup menus
101    and dialog boxes. */
102 static Lisp_Object Vpopup_callbacks;
103
104 void
105 gcpro_popup_callbacks (LWLIB_ID id)
106 {
107   struct popup_data *pdata;
108   Lisp_Object lid = make_int (id);
109   Lisp_Object lpdata;
110
111   assert (NILP (assq_no_quit (lid, Vpopup_callbacks)));
112   pdata = alloc_lcrecord_type (struct popup_data, &lrecord_popup_data);
113   pdata->id = id;
114   pdata->last_menubar_buffer = Qnil;
115   pdata->menubar_contents_up_to_date = 0;
116   XSETPOPUP_DATA (lpdata, pdata);
117   Vpopup_callbacks = Fcons (Fcons (lid, lpdata), Vpopup_callbacks);
118 }
119
120 void
121 ungcpro_popup_callbacks (LWLIB_ID id)
122 {
123   Lisp_Object lid = make_int (id);
124   Lisp_Object this = assq_no_quit (lid, Vpopup_callbacks);
125   assert (!NILP (this));
126   Vpopup_callbacks = delq_no_quit (this, Vpopup_callbacks);
127 }
128
129 int
130 popup_handled_p (LWLIB_ID id)
131 {
132   return NILP (assq_no_quit (make_int (id), Vpopup_callbacks));
133 }
134
135 /* menu_item_descriptor_to_widget_value() et al. mallocs a
136    widget_value, but then may signal lisp errors.  If an error does
137    not occur, the opaque ptr we have here has had its pointer set to 0
138    to tell us not to do anything.  Otherwise we free the widget value.
139    (This has nothing to do with GC, it's just about not dropping
140    pointers to malloc'd data when errors happen.) */
141
142 Lisp_Object
143 widget_value_unwind (Lisp_Object closure)
144 {
145   widget_value *wv = (widget_value *) get_opaque_ptr (closure);
146   free_opaque_ptr (closure);
147   if (wv)
148     free_widget_value_tree (wv);
149   return Qnil;
150 }
151
152 #if 0
153 static void
154 print_widget_value (widget_value *wv, int depth)
155 {
156   /* !!#### This function has not been Mule-ized */
157   char d [200];
158   int i;
159   for (i = 0; i < depth; i++) d[i] = ' ';
160   d[depth]=0;
161   /* #### - print type field */
162   printf ("%sname:    %s\n", d, (wv->name ? wv->name : "(null)"));
163   if (wv->value) printf ("%svalue:   %s\n", d, wv->value);
164   if (wv->key)   printf ("%skey:     %s\n", d, wv->key);
165   printf ("%senabled: %d\n", d, wv->enabled);
166   if (wv->contents)
167     {
168       printf ("\n%scontents: \n", d);
169       print_widget_value (wv->contents, depth + 5);
170     }
171   if (wv->next)
172     {
173       printf ("\n");
174       print_widget_value (wv->next, depth);
175     }
176 }
177 #endif
178
179 /* This recursively calls free_widget_value() on the tree of widgets.
180    It must free all data that was malloc'ed for these widget_values.
181
182    It used to be that emacs only allocated new storage for the `key' slot.
183    All other slots are pointers into the data of Lisp_Strings, and must be
184    left alone.  */
185 void
186 free_popup_widget_value_tree (widget_value *wv)
187 {
188   if (! wv) return;
189   if (wv->key) xfree (wv->key);
190   if (wv->value) xfree (wv->value);
191   if (wv->name) xfree (wv->name);
192
193   wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
194
195   if (wv->contents && (wv->contents != (widget_value*)1))
196     {
197       free_popup_widget_value_tree (wv->contents);
198       wv->contents = (widget_value *) 0xDEADBEEF;
199     }
200   if (wv->next)
201     {
202       free_popup_widget_value_tree (wv->next);
203       wv->next = (widget_value *) 0xDEADBEEF;
204     }
205   free_widget_value (wv);
206 }
207
208 /* The following is actually called from somewhere within XtDispatchEvent(),
209    called from XtAppProcessEvent() in event-Xt.c */
210
211 void
212 popup_selection_callback (Widget widget, LWLIB_ID ignored_id,
213                           XtPointer client_data)
214 {
215   Lisp_Object data, image_instance, callback, callback_ex;
216   Lisp_Object frame, event;
217   int update_subwindows_p = 0;
218   struct device *d = get_device_from_display (XtDisplay (widget));
219   struct frame *f = x_any_widget_or_parent_to_frame (d, widget);
220
221   /* set in lwlib to the time stamp associated with the most recent menu
222      operation */
223   extern Time x_focus_timestamp_really_sucks_fix_me_better;
224
225   if (!f)
226     return;
227   if (((EMACS_INT) client_data) == 0)
228     return;
229   VOID_TO_LISP (data, client_data);
230   XSETFRAME (frame, f);
231
232 #if 0
233   /* #### What the hell?  I can't understand why this call is here,
234      and doing it is really courting disaster in the new event
235      model, since popup_selection_callback is called from
236      within next_event_internal() and Faccept_process_output()
237      itself calls next_event_internal().  --Ben */
238
239   /* Flush the X and process input */
240   Faccept_process_output (Qnil, Qnil, Qnil);
241 #endif
242
243   if (((EMACS_INT) client_data) == -1)
244     {
245       event = Fmake_event (Qnil, Qnil);
246
247       XEVENT (event)->event_type = misc_user_event;
248       XEVENT (event)->channel = frame;
249       XEVENT (event)->event.eval.function = Qrun_hooks;
250       XEVENT (event)->event.eval.object = Qmenu_no_selection_hook;
251     }
252   else
253     {
254       image_instance = XCAR (data);
255       callback = XCAR (XCDR (data));
256       callback_ex = XCDR (XCDR (data));
257       update_subwindows_p = 1;
258
259       if (!NILP (callback_ex) && !UNBOUNDP (callback_ex))
260         {
261           event = Fmake_event (Qnil, Qnil);
262           
263           XEVENT (event)->event_type = misc_user_event;
264           XEVENT (event)->channel = frame;
265           XEVENT (event)->event.eval.function = Qeval;
266           XEVENT (event)->event.eval.object =
267             list4 (Qfuncall, callback_ex, image_instance, event);
268         }
269       else if (NILP (callback) || UNBOUNDP (callback))
270         event = Qnil;
271       else
272         {
273           Lisp_Object fn, arg;
274
275           event = Fmake_event (Qnil, Qnil);
276
277           get_gui_callback (callback, &fn, &arg);
278           XEVENT (event)->event_type = misc_user_event;
279           XEVENT (event)->channel = frame;
280           XEVENT (event)->event.eval.function = fn;
281           XEVENT (event)->event.eval.object = arg;
282         }
283     }
284
285   /* This is the timestamp used for asserting focus so we need to get an
286      up-to-date value event if no events has been dispatched to emacs
287      */
288 #if defined(HAVE_MENUBARS)
289   DEVICE_X_MOUSE_TIMESTAMP (d) = x_focus_timestamp_really_sucks_fix_me_better;
290 #else
291   DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d);
292 #endif
293   if (!NILP (event))
294     enqueue_Xt_dispatch_event (event);
295   /* The result of this evaluation could cause other instances to change so 
296      enqueue an update callback to check this. */
297   if (update_subwindows_p && !NILP (event))
298     enqueue_magic_eval_event (update_widget_instances, frame);
299 }
300
301 #if 1
302   /* Eval the activep slot of the menu item */
303 # define wv_set_evalable_slot(slot,form) do {   \
304   Lisp_Object wses_form = (form);               \
305   (slot) = (NILP (wses_form) ? 0 :              \
306             EQ (wses_form, Qt) ? 1 :            \
307             !NILP (Feval (wses_form)));         \
308 } while (0)
309 #else
310   /* Treat the activep slot of the menu item as a boolean */
311 # define wv_set_evalable_slot(slot,form)        \
312       ((void) (slot = (!NILP (form))))
313 #endif
314
315 char *
316 menu_separator_style (const char *s)
317 {
318   const char *p;
319   char first;
320
321   if (!s || s[0] == '\0')
322     return NULL;
323   first = s[0];
324   if (first != '-' && first != '=')
325     return NULL;
326   for (p = s; *p == first; p++)
327     DO_NOTHING;
328
329   /* #### - cannot currently specify a separator tag "--!tag" and a
330      separator style "--:style" at the same time. */
331   /* #### - Also, the motif menubar code doesn't deal with the
332      double etched style yet, so it's not good to get into the habit of
333      using "===" in menubars to get double-etched lines */
334   if (*p == '!' || *p == '\0')
335     return ((first == '-')
336             ? NULL                      /* single etched is the default */
337             : xstrdup ("shadowDoubleEtchedIn"));
338   else if (*p == ':')
339     return xstrdup (p+1);
340
341   return NULL;
342 }
343
344 char *
345 strdup_and_add_accel (char *name)
346 {
347   int i;
348   int found_accel = 0;
349
350   for (i=0; name[i]; ++i)
351     if (name[i] == '%' && name[i+1] == '_')
352       {
353         found_accel = 1;
354         break;
355       }
356
357   if (found_accel)
358     return xstrdup (name);
359   else
360     {
361       char *chars = (char *) alloca (strlen (name) + 3);
362       chars[0] = '%';
363       chars[1] = '_';
364       memcpy (chars+2, name, strlen (name) + 1);
365       return xstrdup (chars);
366     }
367 }
368
369 /* This does the dirty work.  gc_currently_forbidden is 1 when this is called.
370  */
371 int
372 button_item_to_widget_value (Lisp_Object gui_object_instance,
373                              Lisp_Object gui_item, widget_value *wv,
374                              int allow_text_field_p, int no_keys_p, 
375                              int menu_entry_p)
376 {
377   /* !!#### This function has not been Mule-ized */
378   /* This function cannot GC because gc_currently_forbidden is set when
379      it's called */
380   Lisp_Gui_Item* pgui = 0;
381
382   /* degenerate case */
383   if (STRINGP (gui_item))
384     {
385       wv->type = TEXT_TYPE;
386       wv->name = (char *) XSTRING_DATA (gui_item);
387       wv->name = strdup_and_add_accel (wv->name);
388       return 1;
389     }
390   else if (!GUI_ITEMP (gui_item))
391     signal_simple_error("need a string or a gui_item here", gui_item);
392
393   pgui = XGUI_ITEM (gui_item);
394
395   if (!NILP (pgui->filter))
396     signal_simple_error(":filter keyword not permitted on leaf nodes", gui_item);
397
398 #ifdef HAVE_MENUBARS
399   if (menu_entry_p && !gui_item_included_p (gui_item, Vmenubar_configuration))
400     {
401       /* the include specification says to ignore this item. */
402       return 0;
403     }
404 #endif /* HAVE_MENUBARS */
405
406   if (!STRINGP (pgui->name))
407     pgui->name = Feval (pgui->name);
408
409   CHECK_STRING (pgui->name);
410   wv->name = (char *) XSTRING_DATA (pgui->name);
411   wv->name = xstrdup (wv->name);
412   wv->accel = LISP_TO_VOID (gui_item_accelerator (gui_item));
413
414   if (!NILP (pgui->suffix))
415     {
416       const char *const_bogosity;
417       Lisp_Object suffix2;
418
419       /* Shortcut to avoid evaluating suffix each time */
420       if (STRINGP (pgui->suffix))
421         suffix2 = pgui->suffix;
422       else
423         {
424           suffix2 = Feval (pgui->suffix);
425           CHECK_STRING (suffix2);
426         }
427
428       TO_EXTERNAL_FORMAT (LISP_STRING, suffix2,
429                           C_STRING_ALLOCA, const_bogosity,
430                           Qfile_name);
431       wv->value = (char *) const_bogosity;
432       wv->value = xstrdup (wv->value);
433     }
434
435   wv_set_evalable_slot (wv->enabled, pgui->active);
436   wv_set_evalable_slot (wv->selected, pgui->selected);
437
438   if (!NILP (pgui->callback) || !NILP (pgui->callback_ex))
439     wv->call_data = LISP_TO_VOID (cons3 (gui_object_instance,
440                                          pgui->callback,
441                                          pgui->callback_ex));
442
443   if (no_keys_p
444 #ifdef HAVE_MENUBARS
445       || (menu_entry_p && !menubar_show_keybindings)
446 #endif
447       )
448     wv->key = 0;
449   else if (!NILP (pgui->keys))  /* Use this string to generate key bindings */
450     {
451       CHECK_STRING (pgui->keys);
452       pgui->keys = Fsubstitute_command_keys (pgui->keys);
453       if (XSTRING_LENGTH (pgui->keys) > 0)
454         wv->key = xstrdup ((char *) XSTRING_DATA (pgui->keys));
455       else
456         wv->key = 0;
457     }
458   else if (SYMBOLP (pgui->callback))    /* Show the binding of this command. */
459     {
460       char buf[1024]; /* #### */
461       /* #### Warning, dependency here on current_buffer and point */
462       where_is_to_char (pgui->callback, buf);
463       if (buf [0])
464         wv->key = xstrdup (buf);
465       else
466         wv->key = 0;
467     }
468
469   CHECK_SYMBOL (pgui->style);
470   if (NILP (pgui->style))
471     {
472       /* If the callback is nil, treat this item like unselectable text.
473          This way, dashes will show up as a separator. */
474       if (!wv->enabled)
475         wv->type = BUTTON_TYPE;
476       if (separator_string_p (wv->name))
477         {
478           wv->type = SEPARATOR_TYPE;
479           wv->value = menu_separator_style (wv->name);
480         }
481       else
482         {
483 #if 0
484           /* #### - this is generally desirable for menubars, but it breaks
485              a package that uses dialog boxes and next_command_event magic
486              to use the callback slot in dialog buttons for data instead of
487              a real callback.
488
489              Code is data, right?  The beauty of LISP abuse.   --Stig */
490           if (NILP (callback))
491             wv->type = TEXT_TYPE;
492           else
493 #endif
494             wv->type = BUTTON_TYPE;
495         }
496     }
497   else if (EQ (pgui->style, Qbutton))
498     wv->type = BUTTON_TYPE;
499   else if (EQ (pgui->style, Qtoggle))
500     wv->type = TOGGLE_TYPE;
501   else if (EQ (pgui->style, Qradio))
502     wv->type = RADIO_TYPE;
503   else if (EQ (pgui->style, Qtext))
504     {
505       wv->type = TEXT_TYPE;
506 #if 0
507       wv->value = wv->name;
508       wv->name = "value";
509 #endif
510     }
511   else
512     signal_simple_error_2 ("Unknown style", pgui->style, gui_item);
513
514   if (!allow_text_field_p && (wv->type == TEXT_TYPE))
515     signal_simple_error ("Text field not allowed in this context", gui_item);
516
517   if (!NILP (pgui->selected) && EQ (pgui->style, Qtext))
518     signal_simple_error (
519                          ":selected only makes sense with :style toggle, radio or button",
520                          gui_item);
521   return 1;
522 }
523
524 /* parse tree's of gui items into widget_value hierarchies */
525 static void gui_item_children_to_widget_values (Lisp_Object gui_object_instance,
526                                                 Lisp_Object items,
527                                                 widget_value* parent);
528
529 static widget_value *
530 gui_items_to_widget_values_1 (Lisp_Object gui_object_instance,
531                               Lisp_Object items, widget_value* parent,
532                               widget_value* prev)
533 {
534   widget_value* wv = 0;
535
536   assert ((parent || prev) && !(parent && prev));
537   /* now walk the tree creating widget_values as appropriate */
538   if (!CONSP (items))
539     {
540       wv = xmalloc_widget_value();
541       if (parent)
542         parent->contents = wv;
543       else
544         prev->next = wv;
545       if (!button_item_to_widget_value (gui_object_instance,
546                                         items, wv, 0, 1, 0))
547         {
548           free_widget_value_tree (wv);
549           if (parent)
550             parent->contents = 0;
551           else
552             prev->next = 0;
553         }
554       else
555         {
556           wv->value = xstrdup (wv->name);       /* what a mess... */
557         }
558     }
559   else
560     {
561       /* first one is the parent */
562       if (CONSP (XCAR (items)))
563         signal_simple_error ("parent item must not be a list", XCAR (items));
564
565       if (parent)
566         wv = gui_items_to_widget_values_1 (gui_object_instance,
567                                            XCAR (items), parent, 0);
568       else
569         wv = gui_items_to_widget_values_1 (gui_object_instance,
570                                            XCAR (items), 0, prev);
571       /* the rest are the children */
572       gui_item_children_to_widget_values (gui_object_instance,
573                                           XCDR (items), wv);
574     }
575   return wv;
576 }
577
578 static void
579 gui_item_children_to_widget_values (Lisp_Object gui_object_instance,
580                                     Lisp_Object items, widget_value* parent)
581 {
582   widget_value* wv = 0, *prev = 0;
583   Lisp_Object rest;
584   CHECK_CONS (items);
585
586   /* first one is master */
587   prev = gui_items_to_widget_values_1 (gui_object_instance, XCAR (items),
588                                        parent, 0);
589   /* the rest are the children */
590   LIST_LOOP (rest, XCDR (items))
591     {
592       Lisp_Object tab = XCAR (rest);
593       wv = gui_items_to_widget_values_1 (gui_object_instance, tab, 0, prev);
594       prev = wv;
595     }
596 }
597
598 widget_value *
599 gui_items_to_widget_values (Lisp_Object gui_object_instance, Lisp_Object items)
600 {
601   /* !!#### This function has not been Mule-ized */
602   /* This function can GC */
603   widget_value *control = 0, *tmp = 0;
604   int count = specpdl_depth ();
605   Lisp_Object wv_closure;
606
607   if (NILP (items))
608     signal_simple_error ("must have some items", items);
609
610   /* Inhibit GC during this conversion.  The reasons for this are
611      the same as in menu_item_descriptor_to_widget_value(); see
612      the large comment above that function. */
613   record_unwind_protect (restore_gc_inhibit,
614                          make_int (gc_currently_forbidden));
615   gc_currently_forbidden = 1;
616
617   /* Also make sure that we free the partially-created widget_value
618      tree on Lisp error. */
619   control = xmalloc_widget_value();
620   wv_closure = make_opaque_ptr (control);
621   record_unwind_protect (widget_value_unwind, wv_closure);
622
623   gui_items_to_widget_values_1 (gui_object_instance, items, control, 0);
624
625   /* mess about getting the data we really want */
626   tmp = control;
627   control = control->contents;
628   tmp->next = 0;
629   tmp->contents = 0;
630   free_widget_value_tree (tmp);
631
632   /* No more need to free the half-filled-in structures. */
633   set_opaque_ptr (wv_closure, 0);
634   unbind_to (count, Qnil);
635
636   return control;
637 }
638
639 /* This is a kludge to make sure emacs can only link against a version of
640    lwlib that was compiled in the right way.  Emacs references symbols which
641    correspond to the way it thinks lwlib was compiled, and if lwlib wasn't
642    compiled in that way, then somewhat meaningful link errors will result.
643    The alternatives to this range from obscure link errors, to obscure
644    runtime errors that look a lot like bugs.
645  */
646
647 static void
648 sanity_check_lwlib (void)
649 {
650 #define MACROLET(v) { extern int v; v = 1; }
651
652 #if (XlibSpecificationRelease == 4)
653   MACROLET (lwlib_uses_x11r4);
654 #elif (XlibSpecificationRelease == 5)
655   MACROLET (lwlib_uses_x11r5);
656 #elif (XlibSpecificationRelease == 6)
657   MACROLET (lwlib_uses_x11r6);
658 #else
659   MACROLET (lwlib_uses_unknown_x11);
660 #endif
661 #ifdef LWLIB_USES_MOTIF
662   MACROLET (lwlib_uses_motif);
663 #else
664   MACROLET (lwlib_does_not_use_motif);
665 #endif
666 #if (XmVersion >= 1002)
667   MACROLET (lwlib_uses_motif_1_2);
668 #else
669   MACROLET (lwlib_does_not_use_motif_1_2);
670 #endif
671 #ifdef LWLIB_MENUBARS_LUCID
672   MACROLET (lwlib_menubars_lucid);
673 #elif defined (HAVE_MENUBARS)
674   MACROLET (lwlib_menubars_motif);
675 #endif
676 #ifdef LWLIB_SCROLLBARS_LUCID
677   MACROLET (lwlib_scrollbars_lucid);
678 #elif defined (LWLIB_SCROLLBARS_MOTIF)
679   MACROLET (lwlib_scrollbars_motif);
680 #elif defined (HAVE_SCROLLBARS)
681   MACROLET (lwlib_scrollbars_athena);
682 #endif
683 #ifdef LWLIB_DIALOGS_MOTIF
684   MACROLET (lwlib_dialogs_motif);
685 #elif defined (HAVE_DIALOGS)
686   MACROLET (lwlib_dialogs_athena);
687 #endif
688 #ifdef LWLIB_WIDGETS_MOTIF
689   MACROLET (lwlib_widgets_motif);
690 #elif defined (HAVE_WIDGETS)
691   MACROLET (lwlib_widgets_athena);
692 #endif
693
694 #undef MACROLET
695 }
696
697 void
698 syms_of_gui_x (void)
699 {
700   INIT_LRECORD_IMPLEMENTATION (popup_data);
701
702   defsymbol (&Qmenu_no_selection_hook, "menu-no-selection-hook");
703 }
704
705 void
706 reinit_vars_of_gui_x (void)
707 {
708   lwlib_id_tick = (1<<16);      /* start big, to not conflict with Energize */
709 #ifdef HAVE_POPUPS
710   popup_up_p = 0;
711 #endif
712
713   /* this makes only safe calls as in emacs.c */
714   sanity_check_lwlib ();
715 }
716
717 void
718 vars_of_gui_x (void)
719 {
720   reinit_vars_of_gui_x ();
721
722   Vpopup_callbacks = Qnil;
723   staticpro (&Vpopup_callbacks);
724
725 #if 0
726   /* This DEFVAR_LISP is just for the benefit of make-docfile. */
727   /* #### misnamed */
728   DEFVAR_LISP ("menu-no-selection-hook", &Vmenu_no_selection_hook /*
729 Function or functions to call when a menu or dialog box is dismissed
730 without a selection having been made.
731 */ );
732 #endif
733   Fset (Qmenu_no_selection_hook, Qnil);
734 }