XEmacs 21.2.34 "Molpe".
[chise/xemacs-chise.git-] / src / toolbar.c
1 /* Generic toolbar implementation.
2    Copyright (C) 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4    Copyright (C) 1995, 1996 Ben Wing.
5    Copyright (C) 1996 Chuck Thompson.
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 /* Original implementation by Chuck Thompson for 19.12.
27    Default-toolbar-position and specifier-related stuff by Ben Wing. */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "buffer.h"
33 #include "frame.h"
34 #include "device.h"
35 #include "glyphs.h"
36 #include "redisplay.h"
37 #include "toolbar.h"
38 #include "window.h"
39
40 Lisp_Object Vtoolbar[4];
41 Lisp_Object Vtoolbar_size[4];
42 Lisp_Object Vtoolbar_visible_p[4];
43 Lisp_Object Vtoolbar_border_width[4];
44
45 Lisp_Object Vdefault_toolbar, Vdefault_toolbar_visible_p;
46 Lisp_Object Vdefault_toolbar_width, Vdefault_toolbar_height;
47 Lisp_Object Vdefault_toolbar_border_width;
48
49 Lisp_Object Vdefault_toolbar_position;
50 Lisp_Object Vtoolbar_buttons_captioned_p;
51
52 Lisp_Object Qtoolbar_buttonp;
53 Lisp_Object Q2D, Q3D, Q2d, Q3d;
54 Lisp_Object Q_size;
55
56 Lisp_Object Qinit_toolbar_from_resources;
57
58 \f
59 static Lisp_Object
60 mark_toolbar_button (Lisp_Object obj)
61 {
62   struct toolbar_button *data = XTOOLBAR_BUTTON (obj);
63   mark_object (data->next);
64   mark_object (data->frame);
65   mark_object (data->up_glyph);
66   mark_object (data->down_glyph);
67   mark_object (data->disabled_glyph);
68   mark_object (data->cap_up_glyph);
69   mark_object (data->cap_down_glyph);
70   mark_object (data->cap_disabled_glyph);
71   mark_object (data->callback);
72   mark_object (data->enabled_p);
73   return data->help_string;
74 }
75
76 static void
77 print_toolbar_button (Lisp_Object obj, Lisp_Object printcharfun,
78                       int escapeflag)
79 {
80   struct toolbar_button *tb = XTOOLBAR_BUTTON (obj);
81   char buf[100];
82
83   if (print_readably)
84     error ("printing unreadable object #<toolbar-button 0x%x>",
85            tb->header.uid);
86
87   sprintf (buf, "#<toolbar-button 0x%x>", tb->header.uid);
88   write_c_string (buf, printcharfun);
89 }
90
91 DEFINE_LRECORD_IMPLEMENTATION ("toolbar-button", toolbar_button,
92                                mark_toolbar_button, print_toolbar_button,
93                                0, 0, 0, 0,
94                                struct toolbar_button);
95
96 DEFUN ("toolbar-button-p", Ftoolbar_button_p, 1, 1, 0, /*
97 Return non-nil if OBJECT is a toolbar button.
98 */
99        (object))
100 {
101   return TOOLBAR_BUTTONP (object) ? Qt : Qnil;
102 }
103
104 /* Only query functions are provided for toolbar buttons.  They are
105    generated and updated from a toolbar description list.  Any
106    directly made changes would be wiped out the first time the toolbar
107    was marked as dirty and was regenerated.  The exception to this is
108    set-toolbar-button-down-flag.  Having this allows us to control the
109    toolbar from elisp.  Since we only trigger the button callbacks on
110    up-mouse events and we reset the flag first, there shouldn't be any
111    way for this to get us in trouble (like if someone decides to
112    change the toolbar from a toolbar callback). */
113
114 DEFUN ("toolbar-button-callback", Ftoolbar_button_callback, 1, 1, 0, /*
115 Return the callback function associated with the toolbar BUTTON.
116 */
117        (button))
118 {
119   CHECK_TOOLBAR_BUTTON (button);
120
121   return XTOOLBAR_BUTTON (button)->callback;
122 }
123
124 DEFUN ("toolbar-button-help-string", Ftoolbar_button_help_string, 1, 1, 0, /*
125 Return the help string function associated with the toolbar BUTTON.
126 */
127        (button))
128 {
129   CHECK_TOOLBAR_BUTTON (button);
130
131   return XTOOLBAR_BUTTON (button)->help_string;
132 }
133
134 DEFUN ("toolbar-button-enabled-p", Ftoolbar_button_enabled_p, 1, 1, 0, /*
135 Return t if BUTTON is active.
136 */
137        (button))
138 {
139   CHECK_TOOLBAR_BUTTON (button);
140
141   return XTOOLBAR_BUTTON (button)->enabled ? Qt : Qnil;
142 }
143
144 DEFUN ("set-toolbar-button-down-flag", Fset_toolbar_button_down_flag, 2, 2, 0, /*
145 Don't touch.
146 */
147        (button, flag))
148 {
149   struct toolbar_button *tb;
150   char old_flag;
151
152   CHECK_TOOLBAR_BUTTON (button);
153   tb = XTOOLBAR_BUTTON (button);
154   old_flag = tb->down;
155
156   /* If the button is ignored, don't do anything. */
157   if (!tb->enabled)
158     return Qnil;
159
160   /* If flag is nil, unset the down flag, otherwise set it to true.
161      This also triggers an immediate redraw of the button if the flag
162      does change. */
163
164   if (NILP (flag))
165     tb->down = 0;
166   else
167     tb->down = 1;
168
169   if (tb->down != old_flag)
170     {
171       struct frame *f = XFRAME (tb->frame);
172       struct device *d;
173
174       if (DEVICEP (f->device))
175         {
176           d = XDEVICE (f->device);
177
178           if (DEVICE_LIVE_P (XDEVICE (f->device)))
179             {
180               tb->dirty = 1;
181               MAYBE_DEVMETH (d, output_toolbar_button, (f, button));
182             }
183         }
184     }
185
186   return Qnil;
187 }
188
189 Lisp_Object
190 get_toolbar_button_glyph (struct window *w, struct toolbar_button *tb)
191 {
192   Lisp_Object glyph = Qnil;
193
194   /* The selected glyph logic:
195
196      UP:                up
197      DOWN:              down -> up
198      DISABLED:  disabled -> up
199      CAP-UP:    cap-up -> up
200      CAP-DOWN:  cap-down -> cap-up -> down -> up
201      CAP-DISABLED:      cap-disabled -> cap-up -> disabled -> up
202      */
203
204   if (!NILP (w->toolbar_buttons_captioned_p))
205     {
206       if (tb->enabled && tb->down)
207         glyph = tb->cap_down_glyph;
208       else if (!tb->enabled)
209         glyph = tb->cap_disabled_glyph;
210
211       if (NILP (glyph))
212         glyph = tb->cap_up_glyph;
213     }
214
215   if (NILP (glyph))
216     {
217       if (tb->enabled && tb->down)
218         glyph = tb->down_glyph;
219       else if (!tb->enabled)
220         glyph = tb->disabled_glyph;
221     }
222
223   /* The non-captioned up button is the ultimate fallback.  It is
224      the only one we guarantee exists. */
225   if (NILP (glyph))
226     glyph = tb->up_glyph;
227
228   return glyph;
229 }
230
231 \f
232 static enum toolbar_pos
233 decode_toolbar_position (Lisp_Object position)
234 {
235   if (EQ (position, Qtop))    return TOP_TOOLBAR;
236   if (EQ (position, Qbottom)) return BOTTOM_TOOLBAR;
237   if (EQ (position, Qleft))   return LEFT_TOOLBAR;
238   if (EQ (position, Qright))  return RIGHT_TOOLBAR;
239   signal_simple_error ("Invalid toolbar position", position);
240
241   return TOP_TOOLBAR; /* not reached */
242 }
243
244 DEFUN ("set-default-toolbar-position", Fset_default_toolbar_position, 1, 1, 0, /*
245 Set the position that the `default-toolbar' will be displayed at.
246 Valid positions are 'top, 'bottom, 'left and 'right.
247 See `default-toolbar-position'.
248 */
249        (position))
250 {
251   enum toolbar_pos cur = decode_toolbar_position (Vdefault_toolbar_position);
252   enum toolbar_pos new = decode_toolbar_position (position);
253
254   if (cur != new)
255     {
256       /* The following calls will automatically cause the dirty
257          flags to be set; we delay frame size changes to avoid
258          lots of frame flickering. */
259       /* #### I think this should be GC protected. -sb */
260       hold_frame_size_changes ();
261       set_specifier_fallback (Vtoolbar[cur], list1 (Fcons (Qnil, Qnil)));
262       set_specifier_fallback (Vtoolbar[new], Vdefault_toolbar);
263       set_specifier_fallback (Vtoolbar_size[cur], list1 (Fcons (Qnil, Qzero)));
264       set_specifier_fallback (Vtoolbar_size[new],
265                               new == TOP_TOOLBAR || new == BOTTOM_TOOLBAR
266                               ? Vdefault_toolbar_height
267                               : Vdefault_toolbar_width);
268       set_specifier_fallback (Vtoolbar_border_width[cur],
269                               list1 (Fcons (Qnil, Qzero)));
270       set_specifier_fallback (Vtoolbar_border_width[new],
271                               Vdefault_toolbar_border_width);
272       set_specifier_fallback (Vtoolbar_visible_p[cur],
273                               list1 (Fcons (Qnil, Qt)));
274       set_specifier_fallback (Vtoolbar_visible_p[new],
275                               Vdefault_toolbar_visible_p);
276       Vdefault_toolbar_position = position;
277       unhold_frame_size_changes ();
278     }
279
280   return position;
281 }
282
283 DEFUN ("default-toolbar-position", Fdefault_toolbar_position, 0, 0, 0, /*
284 Return the position that the `default-toolbar' will be displayed at.
285 The `default-toolbar' will only be displayed here if the corresponding
286 position-specific toolbar specifier does not provide a value.
287 */
288        ())
289 {
290   return Vdefault_toolbar_position;
291 }
292
293 \f
294 static Lisp_Object
295 update_toolbar_button (struct frame *f, struct toolbar_button *tb,
296                        Lisp_Object desc, int pushright)
297 {
298   Lisp_Object *elt, glyphs, retval, buffer;
299   struct gcpro gcpro1, gcpro2;
300
301   elt = XVECTOR_DATA (desc);
302   buffer = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer;
303
304   if (!tb)
305     {
306       tb = alloc_lcrecord_type (struct toolbar_button, &lrecord_toolbar_button);
307       tb->next = Qnil;
308       XSETFRAME (tb->frame, f);
309       tb->up_glyph = Qnil;
310       tb->down_glyph = Qnil;
311       tb->disabled_glyph = Qnil;
312       tb->cap_up_glyph = Qnil;
313       tb->cap_down_glyph = Qnil;
314       tb->cap_disabled_glyph = Qnil;
315       tb->callback = Qnil;
316       tb->enabled_p = Qnil;
317       tb->help_string = Qnil;
318
319       tb->enabled = 0;
320       tb->down = 0;
321       tb->pushright = pushright;
322       tb->blank = 0;
323       tb->x = tb->y = tb->width = tb->height = -1;
324       tb->dirty = 1;
325     }
326   XSETTOOLBAR_BUTTON (retval, tb);
327
328   /* Let's make sure nothing gets mucked up by the potential call to
329      eval farther down. */
330   GCPRO2 (retval, desc);
331
332   glyphs = (CONSP (elt[0]) ? elt[0] : symbol_value_in_buffer (elt[0], buffer));
333
334   /* If this is true we have a blank, otherwise it is an actual
335      button. */
336   if (KEYWORDP (glyphs))
337     {
338       int pos;
339       int style_seen = 0;
340       int size_seen = 0;
341       int len = XVECTOR_LENGTH (desc);
342
343       if (!tb->blank)
344         {
345           tb->blank = 1;
346           tb->dirty = 1;
347         }
348
349       for (pos = 0; pos < len; pos += 2)
350         {
351           Lisp_Object key = elt[pos];
352           Lisp_Object val = elt[pos + 1];
353
354           if (EQ (key, Q_style))
355             {
356               style_seen = 1;
357
358               if (EQ (val, Q2D) || EQ (val, Q2d))
359                 {
360                   if (!EQ (Qnil, tb->up_glyph) || !EQ (Qt, tb->disabled_glyph))
361                     {
362                       tb->up_glyph = Qnil;
363                       tb->disabled_glyph = Qt;
364                       tb->dirty = 1;
365                     }
366                 }
367               else if (EQ (val, Q3D) || (EQ (val, Q3d)))
368                 {
369                   if (!EQ (Qt, tb->up_glyph) || !EQ (Qnil, tb->disabled_glyph))
370                     {
371                       tb->up_glyph = Qt;
372                       tb->disabled_glyph = Qnil;
373                       tb->dirty = 1;
374                     }
375                 }
376             }
377           else if (EQ (key, Q_size))
378             {
379               size_seen = 1;
380
381               if (!EQ (val, tb->down_glyph))
382                 {
383                   tb->down_glyph = val;
384                   tb->dirty = 1;
385                 }
386             }
387         }
388
389       if (!style_seen)
390         {
391           /* The default style is 3D. */
392           if (!EQ (Qt, tb->up_glyph) || !EQ (Qnil, tb->disabled_glyph))
393             {
394               tb->up_glyph = Qt;
395               tb->disabled_glyph = Qnil;
396               tb->dirty = 1;
397             }
398         }
399
400       if (!size_seen)
401         {
402           /* The default width is set to nil.  The device specific
403              code will fill it in at its discretion. */
404           if (!NILP (tb->down_glyph))
405             {
406               tb->down_glyph = Qnil;
407               tb->dirty = 1;
408             }
409         }
410
411       /* The rest of these fields are not used by blanks.  We make
412          sure they are nulled out in case this button object formerly
413          represented a real button. */
414       if (!NILP (tb->callback)
415           || !NILP (tb->enabled_p)
416           || !NILP (tb->help_string))
417         {
418           tb->cap_up_glyph = Qnil;
419           tb->cap_down_glyph = Qnil;
420           tb->cap_disabled_glyph = Qnil;
421           tb->callback = Qnil;
422           tb->enabled_p = Qnil;
423           tb->help_string = Qnil;
424           tb->dirty = 1;
425         }
426     }
427   else
428     {
429       if (tb->blank)
430         {
431           tb->blank = 0;
432           tb->dirty = 1;
433         }
434
435       /* We know that we at least have an up_glyph.  Well, no, we
436          don't.  The user may have changed the button glyph on us. */
437       if (CONSP (glyphs))
438         {
439           if (!EQ (XCAR (glyphs), tb->up_glyph))
440             {
441               tb->up_glyph = XCAR (glyphs);
442               tb->dirty = 1;
443             }
444           glyphs = XCDR (glyphs);
445         }
446       else
447         tb->up_glyph = Qnil;
448
449       /* We might have a down_glyph. */
450       if (CONSP (glyphs))
451         {
452           if (!EQ (XCAR (glyphs), tb->down_glyph))
453             {
454               tb->down_glyph = XCAR (glyphs);
455               tb->dirty = 1;
456             }
457           glyphs = XCDR (glyphs);
458         }
459       else
460         tb->down_glyph = Qnil;
461
462       /* We might have a disabled_glyph. */
463       if (CONSP (glyphs))
464         {
465           if (!EQ (XCAR (glyphs), tb->disabled_glyph))
466             {
467               tb->disabled_glyph = XCAR (glyphs);
468               tb->dirty = 1;
469             }
470           glyphs = XCDR (glyphs);
471         }
472       else
473         tb->disabled_glyph = Qnil;
474
475       /* We might have a cap_up_glyph. */
476       if (CONSP (glyphs))
477         {
478           if (!EQ (XCAR (glyphs), tb->cap_up_glyph))
479             {
480               tb->cap_up_glyph = XCAR (glyphs);
481               tb->dirty = 1;
482             }
483           glyphs = XCDR (glyphs);
484         }
485       else
486         tb->cap_up_glyph = Qnil;
487
488       /* We might have a cap_down_glyph. */
489       if (CONSP (glyphs))
490         {
491           if (!EQ (XCAR (glyphs), tb->cap_down_glyph))
492             {
493               tb->cap_down_glyph = XCAR (glyphs);
494               tb->dirty = 1;
495             }
496           glyphs = XCDR (glyphs);
497         }
498       else
499         tb->cap_down_glyph = Qnil;
500
501       /* We might have a cap_disabled_glyph. */
502       if (CONSP (glyphs))
503         {
504           if (!EQ (XCAR (glyphs), tb->cap_disabled_glyph))
505             {
506               tb->cap_disabled_glyph = XCAR (glyphs);
507               tb->dirty = 1;
508             }
509         }
510       else
511         tb->cap_disabled_glyph = Qnil;
512
513       /* Update the callback. */
514       if (!EQ (tb->callback, elt[1]))
515         {
516           tb->callback = elt[1];
517           /* This does not have an impact on the display properties of the
518              button so we do not mark it as dirty if it has changed. */
519         }
520
521       /* Update the enabled field. */
522       if (!EQ (tb->enabled_p, elt[2]))
523         {
524           tb->enabled_p = elt[2];
525           tb->dirty = 1;
526         }
527
528       /* We always do the following because if the enabled status is
529          determined by a function its decision may change without us being
530          able to detect it. */
531       {
532         int old_enabled = tb->enabled;
533
534         if (NILP (tb->enabled_p))
535           tb->enabled = 0;
536         else if (EQ (tb->enabled_p, Qt))
537           tb->enabled = 1;
538         else
539           {
540             if (NILP (tb->enabled_p) || EQ (tb->enabled_p, Qt))
541               /* short-circuit the common case for speed */
542               tb->enabled = !NILP (tb->enabled_p);
543             else
544               {
545                 Lisp_Object result =
546                   eval_in_buffer_trapping_errors
547                     ("Error in toolbar enabled-p form",
548                      XBUFFER
549                      (WINDOW_BUFFER
550                       (XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f)))),
551                      tb->enabled_p);
552                 if (UNBOUNDP (result))
553                   /* #### if there was an error in the enabled-p
554                      form, should we pretend like it's enabled
555                      or disabled? */
556                   tb->enabled = 0;
557                 else
558                   tb->enabled = !NILP (result);
559               }
560           }
561
562         if (old_enabled != tb->enabled)
563           tb->dirty = 1;
564       }
565
566       /* Update the help echo string. */
567       if (!EQ (tb->help_string, elt[3]))
568         {
569           tb->help_string = elt[3];
570           /* This does not have an impact on the display properties of the
571              button so we do not mark it as dirty if it has changed. */
572         }
573     }
574
575   /* If this flag changes, the position is changing for sure unless
576      some very unlikely geometry occurs. */
577   if (tb->pushright != pushright)
578     {
579       tb->pushright = pushright;
580       tb->dirty = 1;
581     }
582
583   /* The position and size fields are only manipulated in the
584      device-dependent code. */
585   UNGCPRO;
586   return retval;
587 }
588
589 void
590 mark_frame_toolbar_buttons_dirty (struct frame *f, enum toolbar_pos pos)
591 {
592   Lisp_Object button = FRAME_TOOLBAR_BUTTONS (f, pos);
593
594   while (!NILP (button))
595     {
596       struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
597       tb->dirty = 1;
598       button = tb->next;
599     }
600   return;
601 }
602
603 static Lisp_Object
604 compute_frame_toolbar_buttons (struct frame *f, enum toolbar_pos pos,
605                                Lisp_Object toolbar)
606 {
607   Lisp_Object buttons, prev_button, first_button;
608   Lisp_Object orig_toolbar = toolbar;
609   int pushright_seen = 0;
610   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
611
612   first_button = FRAME_TOOLBAR_BUTTONS (f, pos);
613   buttons = prev_button = first_button;
614
615   /* Yes, we're being paranoid. */
616   GCPRO5 (toolbar, buttons, prev_button, first_button, orig_toolbar);
617
618   if (NILP (toolbar))
619     {
620       /* The output mechanisms will take care of clearing the former
621          toolbar. */
622       UNGCPRO;
623       return Qnil;
624     }
625
626   if (!CONSP (toolbar))
627     signal_simple_error ("toolbar description must be a list", toolbar);
628
629   /* First synchronize any existing buttons. */
630   while (!NILP (toolbar) && !NILP (buttons))
631     {
632       struct toolbar_button *tb;
633
634       if (NILP (XCAR (toolbar)))
635         {
636           if (pushright_seen)
637             signal_simple_error
638               ("more than one partition (nil) in toolbar description",
639                orig_toolbar);
640           else
641             pushright_seen = 1;
642         }
643       else
644         {
645           tb = XTOOLBAR_BUTTON (buttons);
646           update_toolbar_button (f, tb, XCAR (toolbar), pushright_seen);
647           prev_button = buttons;
648           buttons = tb->next;
649         }
650
651       toolbar = XCDR (toolbar);
652     }
653
654   /* If we hit the end of the toolbar, then clean up any excess
655      buttons and return. */
656   if (NILP (toolbar))
657     {
658       if (!NILP (buttons))
659         {
660           /* If this is the case the only thing we saw was a
661              pushright marker. */
662           if (EQ (buttons, first_button))
663             {
664               UNGCPRO;
665               return Qnil;
666             }
667           else
668             XTOOLBAR_BUTTON (prev_button)->next = Qnil;
669         }
670       UNGCPRO;
671       return first_button;
672     }
673
674   /* At this point there are more buttons on the toolbar than we
675      actually have in existence. */
676   while (!NILP (toolbar))
677     {
678       Lisp_Object new_button;
679
680       if (NILP (XCAR (toolbar)))
681         {
682           if (pushright_seen)
683             signal_simple_error
684               ("more than one partition (nil) in toolbar description",
685                orig_toolbar);
686           else
687             pushright_seen = 1;
688         }
689       else
690         {
691           new_button = update_toolbar_button (f, NULL, XCAR (toolbar),
692                                               pushright_seen);
693
694           if (NILP (first_button))
695             {
696               first_button = prev_button = new_button;
697             }
698           else
699             {
700               XTOOLBAR_BUTTON (prev_button)->next = new_button;
701               prev_button = new_button;
702             }
703         }
704
705       toolbar = XCDR (toolbar);
706     }
707
708   UNGCPRO;
709   return first_button;
710 }
711
712 static void
713 set_frame_toolbar (struct frame *f, enum toolbar_pos pos)
714 {
715   struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f));
716   Lisp_Object toolbar = w->toolbar[pos];
717   f->toolbar_buttons[pos] = (FRAME_REAL_TOOLBAR_VISIBLE (f, pos)
718                              ? compute_frame_toolbar_buttons (f, pos, toolbar)
719                              : Qnil);
720 }
721
722 static void
723 compute_frame_toolbars_data (struct frame *f)
724 {
725   set_frame_toolbar (f, TOP_TOOLBAR);
726   set_frame_toolbar (f, BOTTOM_TOOLBAR);
727   set_frame_toolbar (f, LEFT_TOOLBAR);
728   set_frame_toolbar (f, RIGHT_TOOLBAR);
729 }
730
731 void
732 update_frame_toolbars (struct frame *f)
733 {
734   struct device *d = XDEVICE (f->device);
735
736   if (DEVICE_SUPPORTS_TOOLBARS_P (d)
737       && (f->toolbar_changed || f->frame_changed || f->clear))
738     {
739       int pos;
740
741       /* We're not officially "in redisplay", so we still have a
742          chance to re-layout toolbars and windows. This is done here,
743          because toolbar is the only thing which currently might
744          necessitate this layout, as it is outside any windows. We
745          take care not to change size if toolbar geometry is really
746          unchanged, as it will hose windows whose pixsizes are not
747          multiple of character sizes. */
748
749       for (pos = 0; pos < 4; pos++)
750         if (FRAME_REAL_TOOLBAR_SIZE (f, pos)
751             != FRAME_CURRENT_TOOLBAR_SIZE (f, pos))
752           {
753             int width, height;
754             pixel_to_char_size (f, FRAME_PIXWIDTH (f), FRAME_PIXHEIGHT (f),
755                                 &width, &height);
756             change_frame_size (f, height, width, 0);
757             break;
758           }
759
760       for (pos = 0; pos < 4; pos++)
761         f->current_toolbar_size[pos] = FRAME_REAL_TOOLBAR_SIZE (f, pos);
762
763       /* Removed the check for the minibuffer here.  We handle this
764          more correctly now by consistently using
765          FRAME_LAST_NONMINIBUF_WINDOW instead of FRAME_SELECTED_WINDOW
766          throughout the toolbar code. */
767       compute_frame_toolbars_data (f);
768
769       DEVMETH (d, output_frame_toolbars, (f));
770     }
771
772   f->toolbar_changed = 0;
773 }
774
775 void
776 init_frame_toolbars (struct frame *f)
777 {
778   struct device *d = XDEVICE (f->device);
779
780   if (DEVICE_SUPPORTS_TOOLBARS_P (d))
781     {
782       Lisp_Object frame;
783       int pos;
784
785       compute_frame_toolbars_data (f);
786       XSETFRAME (frame, f);
787       call_critical_lisp_code (XDEVICE (FRAME_DEVICE (f)),
788                                Qinit_toolbar_from_resources,
789                                frame);
790       MAYBE_DEVMETH (d, initialize_frame_toolbars, (f));
791
792       /* We are here as far in frame creation so cached specifiers are
793          already recomputed, and possibly modified by resource
794          initialization. Remember current toolbar geometry so next
795          redisplay will not needlessly relayout toolbars. */
796       for (pos = 0; pos < 4; pos++)
797         f->current_toolbar_size[pos] = FRAME_REAL_TOOLBAR_SIZE (f, pos);
798     }
799 }
800
801 void
802 init_device_toolbars (struct device *d)
803 {
804   Lisp_Object device;
805
806   XSETDEVICE (device, d);
807   if (DEVICE_SUPPORTS_TOOLBARS_P (d))
808     call_critical_lisp_code (d,
809                              Qinit_toolbar_from_resources,
810                              device);
811 }
812
813 void
814 init_global_toolbars (struct device *d)
815 {
816   if (DEVICE_SUPPORTS_TOOLBARS_P (d))
817     call_critical_lisp_code (d,
818                              Qinit_toolbar_from_resources,
819                              Qglobal);
820 }
821
822 void
823 free_frame_toolbars (struct frame *f)
824 {
825   /* If we had directly allocated any memory for the toolbars instead
826      of using all Lisp_Objects this is where we would now free it. */
827
828   MAYBE_FRAMEMETH (f, free_frame_toolbars, (f));
829 }
830
831 void
832 get_toolbar_coords (struct frame *f, enum toolbar_pos pos, int *x, int *y,
833                     int *width, int *height, int *vert, int for_layout)
834 {
835   int visible_top_toolbar_height, visible_bottom_toolbar_height;
836   int adjust = (for_layout ? 1 : 0);
837
838   /* The top and bottom toolbars take precedence over the left and
839      right. */
840   visible_top_toolbar_height = (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f)
841                                 ? FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) +
842                                   2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f)
843                                 : 0);
844   visible_bottom_toolbar_height = (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f)
845                                 ? FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) +
846                                   2 *
847                                    FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)
848                                 : 0);
849
850   /* We adjust the width and height by one to give us a narrow border
851      at the outside edges.  However, when we are simply determining
852      toolbar location we don't want to do that. */
853
854   switch (pos)
855     {
856     case TOP_TOOLBAR:
857       *x = 1;
858       *y = 0;   /* #### should be 1 if no menubar */
859       *width = FRAME_PIXWIDTH (f) - 2;
860       *height = FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) +
861         2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) - adjust;
862       *vert = 0;
863       break;
864     case BOTTOM_TOOLBAR:
865       *x = 1;
866       *y = FRAME_PIXHEIGHT (f) - FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
867         2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f);
868       *width = FRAME_PIXWIDTH (f) - 2;
869       *height = FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) +
870         2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f) - adjust;
871       *vert = 0;
872       break;
873     case LEFT_TOOLBAR:
874       *x = 1;
875       *y = visible_top_toolbar_height;
876       *width = FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) +
877         2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) - adjust;
878       *height = (FRAME_PIXHEIGHT (f) - visible_top_toolbar_height -
879                  visible_bottom_toolbar_height - 1);
880       *vert = 1;
881       break;
882     case RIGHT_TOOLBAR:
883       *x = FRAME_PIXWIDTH (f) - FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
884         2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f);
885       *y = visible_top_toolbar_height;
886       *width = FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) +
887         2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f) - adjust;
888       *height = (FRAME_PIXHEIGHT (f) - visible_top_toolbar_height -
889                  visible_bottom_toolbar_height);
890       *vert = 1;
891       break;
892     default:
893       abort ();
894     }
895 }
896
897 #define CHECK_TOOLBAR(pos) do {                                         \
898   if (FRAME_REAL_##pos##_VISIBLE (f))                                   \
899     {                                                                   \
900       int x, y, width, height, vert;                                    \
901                                                                         \
902       get_toolbar_coords (f, pos, &x, &y, &width, &height, &vert, 0);   \
903       if ((x_coord >= x) && (x_coord < (x + width)))                    \
904         {                                                               \
905           if ((y_coord >= y) && (y_coord < (y + height)))               \
906             return FRAME_TOOLBAR_BUTTONS (f, pos);                      \
907         }                                                               \
908     }                                                                   \
909 } while (0)
910
911 static Lisp_Object
912 toolbar_buttons_at_pixpos (struct frame *f, int x_coord, int y_coord)
913 {
914   CHECK_TOOLBAR (TOP_TOOLBAR);
915   CHECK_TOOLBAR (BOTTOM_TOOLBAR);
916   CHECK_TOOLBAR (LEFT_TOOLBAR);
917   CHECK_TOOLBAR (RIGHT_TOOLBAR);
918
919   return Qnil;
920 }
921 #undef CHECK_TOOLBAR
922
923 /* The device dependent code actually does the work of positioning the
924    buttons, but we are free to access that information at this
925    level. */
926 Lisp_Object
927 toolbar_button_at_pixpos (struct frame *f, int x_coord, int y_coord)
928 {
929   Lisp_Object buttons = toolbar_buttons_at_pixpos (f, x_coord, y_coord);
930
931   while (!NILP (buttons))
932     {
933       struct toolbar_button *tb = XTOOLBAR_BUTTON (buttons);
934
935       if ((x_coord >= tb->x) && (x_coord < (tb->x + tb->width)))
936         {
937           if ((y_coord >= tb->y) && (y_coord < (tb->y + tb->height)))
938             {
939               /* If we are over a blank, return nil. */
940               if (tb->blank)
941                 return Qnil;
942               else
943                 return buttons;
944             }
945         }
946
947       buttons = tb->next;
948     }
949
950   /* We are not over a toolbar or we are over a blank in the toolbar. */
951   return Qnil;
952 }
953
954 \f
955 /************************************************************************/
956 /*                        Toolbar specifier type                        */
957 /************************************************************************/
958
959 DEFINE_SPECIFIER_TYPE (toolbar);
960
961 #define CTB_ERROR(msg) do {                                     \
962   maybe_signal_simple_error (msg, button, Qtoolbar, errb);      \
963   RETURN_SANS_WARNINGS Qnil;                                    \
964 } while (0)
965
966 /* Returns Q_style if key was :style, Qt if ok otherwise, Qnil if error. */
967 static Lisp_Object
968 check_toolbar_button_keywords (Lisp_Object button, Lisp_Object key,
969                                Lisp_Object val, Error_behavior errb)
970 {
971   if (!KEYWORDP (key))
972     {
973       maybe_signal_simple_error_2 ("Not a keyword", key, button, Qtoolbar,
974                                    errb);
975       return Qnil;
976     }
977
978   if (EQ (key, Q_style))
979     {
980       if (!EQ (val, Q2D)
981           && !EQ (val, Q3D)
982           && !EQ (val, Q2d)
983           && !EQ (val, Q3d))
984         CTB_ERROR ("Unrecognized toolbar blank style");
985
986       return Q_style;
987     }
988   else if (EQ (key, Q_size))
989     {
990       if (!NATNUMP (val))
991         CTB_ERROR ("invalid toolbar blank size");
992     }
993   else
994     {
995       CTB_ERROR ("invalid toolbar blank keyword");
996     }
997
998   return Qt;
999 }
1000
1001 /* toolbar button spec is [pixmap-pair function enabled-p help]
1002                        or [:style 2d-or-3d :size width-or-height] */
1003
1004 DEFUN ("check-toolbar-button-syntax", Fcheck_toolbar_button_syntax, 1, 2, 0, /*
1005 Verify the syntax of entry BUTTON in a toolbar description list.
1006 If you want to verify the syntax of a toolbar description list as a
1007 whole, use `check-valid-instantiator' with a specifier type of 'toolbar.
1008 */
1009        (button, no_error))
1010 {
1011   Lisp_Object *elt, glyphs, value;
1012   int len;
1013   Error_behavior errb = decode_error_behavior_flag (no_error);
1014
1015   if (!VECTORP (button))
1016     CTB_ERROR ("toolbar button descriptors must be vectors");
1017   elt = XVECTOR_DATA (button);
1018
1019   if (XVECTOR_LENGTH (button) == 2)
1020     {
1021       if (!EQ (Q_style, check_toolbar_button_keywords (button, elt[0],
1022                                                        elt[1], errb)))
1023         CTB_ERROR ("must specify toolbar blank style");
1024
1025       return Qt;
1026     }
1027
1028   if (XVECTOR_LENGTH (button) != 4)
1029     CTB_ERROR ("toolbar button descriptors must be 2 or 4 long");
1030
1031   /* The first element must be a list of glyphs of length 1-6.  The
1032      first entry is the pixmap for the up state, the second for the
1033      down state, the third for the disabled state, the fourth for the
1034      captioned up state, the fifth for the captioned down state and
1035      the sixth for the captioned disabled state.  Only the up state is
1036      mandatory. */
1037   if (!CONSP (elt[0]))
1038     {
1039       /* We can't check the buffer-local here because we don't know
1040          which buffer to check in.  #### I think this is a bad thing.
1041          See if we can't get enough information to this function so
1042          that it can check.
1043          
1044          #### Wrong.  We shouldn't be checking the value at all here.
1045          The user might set or change the value at any time. */
1046       value = Fsymbol_value (elt[0]);
1047
1048       if (!CONSP (value))
1049         {
1050           if (KEYWORDP (elt[0]))
1051             {
1052               int fsty = 0;
1053
1054               if (EQ (Q_style, check_toolbar_button_keywords (button, elt[0],
1055                                                               elt[1],
1056                                                               errb)))
1057                 fsty++;
1058
1059               if (EQ (Q_style, check_toolbar_button_keywords (button, elt[2],
1060                                                               elt[3],
1061                                                               errb)))
1062                 fsty++;
1063
1064               if (!fsty)
1065                 CTB_ERROR ("must specify toolbar blank style");
1066               else if (EQ (elt[0], elt[2]))
1067                 CTB_ERROR
1068                   ("duplicate keywords in toolbar button blank description");
1069
1070               return Qt;
1071             }
1072           else
1073             CTB_ERROR ("first element of button must be a list (of glyphs)");
1074         }
1075     }
1076   else
1077     value = elt[0];
1078
1079   len = XINT (Flength (value));
1080   if (len < 1)
1081     CTB_ERROR ("toolbar button glyph list must have at least 1 entry");
1082
1083   if (len > 6)
1084     CTB_ERROR ("toolbar button glyph list can have at most 6 entries");
1085
1086   glyphs = value;
1087   while (!NILP (glyphs))
1088     {
1089       if (!GLYPHP (XCAR (glyphs)))
1090         {
1091           /* We allow nil for the down and disabled glyphs but not for
1092              the up glyph. */
1093           if (EQ (glyphs, value) || !NILP (XCAR (glyphs)))
1094             {
1095               CTB_ERROR
1096                 ("all elements of toolbar button glyph list must be glyphs.");
1097             }
1098         }
1099       glyphs = XCDR (glyphs);
1100     }
1101
1102   /* The second element is the function to run when the button is
1103      activated.  We do not do any checking on it because it is legal
1104      for the function to not be defined until after the toolbar is.
1105      It is the user's problem to get this right.
1106
1107      The third element is either a boolean indicating the enabled
1108      status or a function used to determine it.  Again, it is the
1109      user's problem if this is wrong.
1110
1111      The fourth element, if not nil, must be a string which will be
1112      displayed as the help echo. */
1113
1114   /* #### This should be allowed to be a function returning a string
1115      as well as just a string. */
1116   if (!NILP (elt[3]) && !STRINGP (elt[3]))
1117     CTB_ERROR ("toolbar button help echo string must be a string");
1118
1119   return Qt;
1120 }
1121 #undef CTB_ERROR
1122
1123 static void
1124 toolbar_validate (Lisp_Object instantiator)
1125 {
1126   int pushright_seen = 0;
1127   Lisp_Object rest;
1128
1129   if (NILP (instantiator))
1130     return;
1131
1132   if (!CONSP (instantiator))
1133     signal_simple_error ("Toolbar spec must be list or nil", instantiator);
1134
1135   for (rest = instantiator; !NILP (rest); rest = XCDR (rest))
1136     {
1137       if (!CONSP (rest))
1138         signal_simple_error ("Bad list in toolbar spec", instantiator);
1139
1140       if (NILP (XCAR (rest)))
1141         {
1142           if (pushright_seen)
1143             error
1144               ("More than one partition (nil) in instantiator description");
1145           else
1146             pushright_seen = 1;
1147         }
1148       else
1149         Fcheck_toolbar_button_syntax (XCAR (rest), Qnil);
1150     }
1151 }
1152
1153 static void
1154 toolbar_after_change (Lisp_Object specifier, Lisp_Object locale)
1155 {
1156   /* #### This is overkill.  I really need to rethink the after-change
1157      functions to make them easier to use. */
1158   MARK_TOOLBAR_CHANGED;
1159 }
1160
1161 DEFUN ("toolbar-specifier-p", Ftoolbar_specifier_p, 1, 1, 0, /*
1162 Return non-nil if OBJECT is a toolbar specifier.
1163
1164 See `make-toolbar-specifier' for a description of possible toolbar
1165 instantiators.
1166 */
1167        (object))
1168 {
1169   return TOOLBAR_SPECIFIERP (object) ? Qt : Qnil;
1170 }
1171
1172 \f
1173 /*
1174   Helper for invalidating the real specifier when default
1175   specifier caching changes
1176 */
1177 static void
1178 recompute_overlaying_specifier (Lisp_Object real_one[4])
1179 {
1180   enum toolbar_pos pos = decode_toolbar_position (Vdefault_toolbar_position);
1181   Fset_specifier_dirty_flag (real_one[pos]);
1182 }
1183
1184 static void
1185 toolbar_specs_changed (Lisp_Object specifier, struct window *w,
1186                        Lisp_Object oldval)
1187 {
1188   /* This could be smarter but I doubt that it would make any
1189      noticeable difference given the infrequency with which this is
1190      probably going to be called.
1191      */
1192   MARK_TOOLBAR_CHANGED;
1193 }
1194
1195 static void
1196 default_toolbar_specs_changed (Lisp_Object specifier, struct window *w,
1197                                Lisp_Object oldval)
1198 {
1199   recompute_overlaying_specifier (Vtoolbar);
1200 }
1201
1202 static void
1203 default_toolbar_size_changed_in_frame (Lisp_Object specifier, struct frame *f,
1204                                        Lisp_Object oldval)
1205 {
1206   recompute_overlaying_specifier (Vtoolbar_size);
1207 }
1208
1209 static void
1210 default_toolbar_border_width_changed_in_frame (Lisp_Object specifier,
1211                                                struct frame *f,
1212                                                Lisp_Object oldval)
1213 {
1214   recompute_overlaying_specifier (Vtoolbar_border_width);
1215 }
1216
1217 static void
1218 default_toolbar_visible_p_changed_in_frame (Lisp_Object specifier,
1219                                             struct frame *f,
1220                                             Lisp_Object oldval)
1221 {
1222   recompute_overlaying_specifier (Vtoolbar_visible_p);
1223 }
1224
1225 static void
1226 toolbar_geometry_changed_in_window (Lisp_Object specifier, struct window *w,
1227                                     Lisp_Object oldval)
1228 {
1229   MARK_TOOLBAR_CHANGED;
1230   MARK_WINDOWS_CHANGED (w);
1231 }
1232
1233 static void
1234 default_toolbar_size_changed_in_window (Lisp_Object specifier, struct window *w,
1235                                         Lisp_Object oldval)
1236 {
1237   recompute_overlaying_specifier (Vtoolbar_size);
1238 }
1239
1240 static void
1241 default_toolbar_border_width_changed_in_window (Lisp_Object specifier,
1242                                                 struct window *w,
1243                                                 Lisp_Object oldval)
1244 {
1245   recompute_overlaying_specifier (Vtoolbar_border_width);
1246 }
1247
1248 static void
1249 default_toolbar_visible_p_changed_in_window (Lisp_Object specifier,
1250                                              struct window *w,
1251                                              Lisp_Object oldval)
1252 {
1253   recompute_overlaying_specifier (Vtoolbar_visible_p);
1254 }
1255
1256 static void
1257 toolbar_buttons_captioned_p_changed (Lisp_Object specifier, struct window *w,
1258                                      Lisp_Object oldval)
1259 {
1260   /* This could be smarter but I doubt that it would make any
1261      noticeable difference given the infrequency with which this is
1262      probably going to be called. */
1263   MARK_TOOLBAR_CHANGED;
1264 }
1265
1266 \f
1267 void
1268 syms_of_toolbar (void)
1269 {
1270   INIT_LRECORD_IMPLEMENTATION (toolbar_button);
1271
1272   defsymbol (&Qtoolbar_buttonp, "toolbar-button-p");
1273   defsymbol (&Q2D, "2D");
1274   defsymbol (&Q3D, "3D");
1275   defsymbol (&Q2d, "2d");
1276   defsymbol (&Q3d, "3d");
1277   defsymbol (&Q_size, ":size"); Fset (Q_size, Q_size);
1278
1279   defsymbol (&Qinit_toolbar_from_resources, "init-toolbar-from-resources");
1280   DEFSUBR (Ftoolbar_button_p);
1281   DEFSUBR (Ftoolbar_button_callback);
1282   DEFSUBR (Ftoolbar_button_help_string);
1283   DEFSUBR (Ftoolbar_button_enabled_p);
1284   DEFSUBR (Fset_toolbar_button_down_flag);
1285   DEFSUBR (Fcheck_toolbar_button_syntax);
1286   DEFSUBR (Fset_default_toolbar_position);
1287   DEFSUBR (Fdefault_toolbar_position);
1288   DEFSUBR (Ftoolbar_specifier_p);
1289 }
1290
1291 void
1292 vars_of_toolbar (void)
1293 {
1294   staticpro (&Vdefault_toolbar_position);
1295   Vdefault_toolbar_position = Qtop;
1296
1297 #ifdef HAVE_WINDOW_SYSTEM
1298   Fprovide (Qtoolbar);
1299 #endif
1300 }
1301
1302 void
1303 specifier_type_create_toolbar (void)
1304 {
1305   INITIALIZE_SPECIFIER_TYPE (toolbar, "toolbar", "toolbar-specifier-p");
1306
1307   SPECIFIER_HAS_METHOD (toolbar, validate);
1308   SPECIFIER_HAS_METHOD (toolbar, after_change);
1309 }
1310
1311 void
1312 reinit_specifier_type_create_toolbar (void)
1313 {
1314   REINITIALIZE_SPECIFIER_TYPE (toolbar);
1315 }
1316
1317 void
1318 specifier_vars_of_toolbar (void)
1319 {
1320   Lisp_Object fb;
1321
1322   DEFVAR_SPECIFIER ("default-toolbar", &Vdefault_toolbar /*
1323 Specifier for a fallback toolbar.
1324 Use `set-specifier' to change this.
1325
1326 The position of this toolbar is specified in the function
1327 `default-toolbar-position'.  If the corresponding position-specific
1328 toolbar (e.g. `top-toolbar' if `default-toolbar-position' is 'top)
1329 does not specify a toolbar in a particular domain (usually a window),
1330 then the value of `default-toolbar' in that domain, if any, will be
1331 used instead.
1332
1333 Note that the toolbar at any particular position will not be
1334 displayed unless its visibility flag is true and its thickness
1335 \(width or height, depending on orientation) is non-zero.  The
1336 visibility is controlled by the specifiers `top-toolbar-visible-p',
1337 `bottom-toolbar-visible-p', `left-toolbar-visible-p', and
1338 `right-toolbar-visible-p', and the thickness is controlled by the
1339 specifiers `top-toolbar-height', `bottom-toolbar-height',
1340 `left-toolbar-width', and `right-toolbar-width'.
1341
1342 Note that one of the four visibility specifiers inherits from
1343 `default-toolbar-visibility' and one of the four thickness
1344 specifiers inherits from either `default-toolbar-width' or
1345 `default-toolbar-height' (depending on orientation), just
1346 like for the toolbar description specifiers (e.g. `top-toolbar')
1347 mentioned above.
1348
1349 Therefore, if you are setting `default-toolbar', you should control
1350 the visibility and thickness using `default-toolbar-visible-p',
1351 `default-toolbar-width', and `default-toolbar-height', rather than
1352 using position-specific specifiers.  That way, you will get sane
1353 behavior if the user changes the default toolbar position.
1354
1355 The format of the instantiator for a toolbar is a list of
1356 toolbar-button-descriptors.  Each toolbar-button-descriptor
1357 is a vector in one of the following formats:
1358
1359   [GLYPH-LIST FUNCTION ENABLED-P HELP] or
1360   [:style 2D-OR-3D] or
1361   [:style 2D-OR-3D :size WIDTH-OR-HEIGHT] or
1362   [:size WIDTH-OR-HEIGHT :style 2D-OR-3D]
1363
1364 Optionally, one of the toolbar-button-descriptors may be nil
1365 instead of a vector; this signifies the division between
1366 the toolbar buttons that are to be displayed flush-left,
1367 and the buttons to be displayed flush-right.
1368
1369 The first vector format above specifies a normal toolbar button;
1370 the others specify blank areas in the toolbar.
1371
1372 For the first vector format:
1373
1374 -- GLYPH-LIST should be a list of one to six glyphs (as created by
1375    `make-glyph') or a symbol whose value is such a list.  The first
1376    glyph, which must be provided, is the glyph used to display the
1377    toolbar button when it is in the "up" (not pressed) state.  The
1378    optional second glyph is for displaying the button when it is in
1379    the "down" (pressed) state.  The optional third glyph is for when
1380    the button is disabled.  The optional fourth, fifth and sixth glyphs
1381    are used to specify captioned versions for the up, down and disabled
1382    states respectively.  The function `toolbar-make-button-list' is
1383    useful in creating these glyph lists.  The specifier variable
1384    `toolbar-buttons-captioned-p' controls which glyphs are actually used.
1385
1386 -- Even if you do not provide separate down-state and disabled-state
1387    glyphs, the user will still get visual feedback to indicate which
1388    state the button is in.  Buttons in the up-state are displayed
1389    with a shadowed border that gives a raised appearance to the
1390    button.  Buttons in the down-state are displayed with shadows that
1391    give a recessed appearance.  Buttons in the disabled state are
1392    displayed with no shadows, giving a 2-d effect.
1393
1394 -- If some of the toolbar glyphs are not provided, they inherit as follows:
1395
1396      UP:                up
1397      DOWN:              down -> up
1398      DISABLED:          disabled -> up
1399      CAP-UP:            cap-up -> up
1400      CAP-DOWN:          cap-down -> cap-up -> down -> up
1401      CAP-DISABLED:      cap-disabled -> cap-up -> disabled -> up
1402
1403 -- The second element FUNCTION is a function to be called when the
1404    toolbar button is activated (i.e. when the mouse is released over
1405    the toolbar button, if the press occurred in the toolbar).  It
1406    can be any form accepted by `call-interactively', since this is
1407    how it is invoked.
1408
1409 -- The third element ENABLED-P specifies whether the toolbar button
1410    is enabled (disabled buttons do nothing when they are activated,
1411    and are displayed differently; see above).  It should be either
1412    a boolean or a form that evaluates to a boolean.
1413
1414 -- The fourth element HELP, if non-nil, should be a string.  This
1415    string is displayed in the echo area when the mouse passes over
1416    the toolbar button.
1417
1418 For the other vector formats (specifying blank areas of the toolbar):
1419
1420 -- 2D-OR-3D should be one of the symbols '2d or '3d, indicating
1421    whether the area is displayed with shadows (giving it a raised,
1422    3-d appearance) or without shadows (giving it a flat appearance).
1423
1424 -- WIDTH-OR-HEIGHT specifies the length, in pixels, of the blank
1425    area.  If omitted, it defaults to a device-specific value
1426    (8 pixels for X devices).
1427 */ );
1428
1429   Vdefault_toolbar = Fmake_specifier (Qtoolbar);
1430   /* #### It would be even nicer if the specifier caching
1431      automatically knew about specifier fallbacks, so we didn't
1432      have to do it ourselves. */
1433   set_specifier_caching (Vdefault_toolbar,
1434                          offsetof (struct window, default_toolbar),
1435                          default_toolbar_specs_changed,
1436                          0, 0);
1437
1438   DEFVAR_SPECIFIER ("top-toolbar",
1439                     &Vtoolbar[TOP_TOOLBAR] /*
1440 Specifier for the toolbar at the top of the frame.
1441 Use `set-specifier' to change this.
1442 See `default-toolbar' for a description of a valid toolbar instantiator.
1443 */ );
1444   Vtoolbar[TOP_TOOLBAR] = Fmake_specifier (Qtoolbar);
1445   set_specifier_caching (Vtoolbar[TOP_TOOLBAR],
1446                          offsetof (struct window, toolbar[TOP_TOOLBAR]),
1447                          toolbar_specs_changed,
1448                          0, 0);
1449
1450   DEFVAR_SPECIFIER ("bottom-toolbar",
1451                     &Vtoolbar[BOTTOM_TOOLBAR] /*
1452 Specifier for the toolbar at the bottom of the frame.
1453 Use `set-specifier' to change this.
1454 See `default-toolbar' for a description of a valid toolbar instantiator.
1455
1456 Note that, unless the `default-toolbar-position' is `bottom', by
1457 default the height of the bottom toolbar (controlled by
1458 `bottom-toolbar-height') is 0; thus, a bottom toolbar will not be
1459 displayed even if you provide a value for `bottom-toolbar'.
1460 */ );
1461   Vtoolbar[BOTTOM_TOOLBAR] = Fmake_specifier (Qtoolbar);
1462   set_specifier_caching (Vtoolbar[BOTTOM_TOOLBAR],
1463                          offsetof (struct window, toolbar[BOTTOM_TOOLBAR]),
1464                          toolbar_specs_changed,
1465                          0, 0);
1466
1467   DEFVAR_SPECIFIER ("left-toolbar",
1468                     &Vtoolbar[LEFT_TOOLBAR] /*
1469 Specifier for the toolbar at the left edge of the frame.
1470 Use `set-specifier' to change this.
1471 See `default-toolbar' for a description of a valid toolbar instantiator.
1472
1473 Note that, unless the `default-toolbar-position' is `left', by
1474 default the height of the left toolbar (controlled by
1475 `left-toolbar-width') is 0; thus, a left toolbar will not be
1476 displayed even if you provide a value for `left-toolbar'.
1477 */ );
1478   Vtoolbar[LEFT_TOOLBAR] = Fmake_specifier (Qtoolbar);
1479   set_specifier_caching (Vtoolbar[LEFT_TOOLBAR],
1480                          offsetof (struct window, toolbar[LEFT_TOOLBAR]),
1481                          toolbar_specs_changed,
1482                          0, 0);
1483
1484   DEFVAR_SPECIFIER ("right-toolbar",
1485                     &Vtoolbar[RIGHT_TOOLBAR] /*
1486 Specifier for the toolbar at the right edge of the frame.
1487 Use `set-specifier' to change this.
1488 See `default-toolbar' for a description of a valid toolbar instantiator.
1489
1490 Note that, unless the `default-toolbar-position' is `right', by
1491 default the height of the right toolbar (controlled by
1492 `right-toolbar-width') is 0; thus, a right toolbar will not be
1493 displayed even if you provide a value for `right-toolbar'.
1494 */ );
1495   Vtoolbar[RIGHT_TOOLBAR] = Fmake_specifier (Qtoolbar);
1496   set_specifier_caching (Vtoolbar[RIGHT_TOOLBAR],
1497                          offsetof (struct window, toolbar[RIGHT_TOOLBAR]),
1498                          toolbar_specs_changed,
1499                          0, 0);
1500
1501   /* initially, top inherits from default; this can be
1502      changed with `set-default-toolbar-position'. */
1503   fb = list1 (Fcons (Qnil, Qnil));
1504   set_specifier_fallback (Vdefault_toolbar, fb);
1505   set_specifier_fallback (Vtoolbar[TOP_TOOLBAR], Vdefault_toolbar);
1506   set_specifier_fallback (Vtoolbar[BOTTOM_TOOLBAR], fb);
1507   set_specifier_fallback (Vtoolbar[LEFT_TOOLBAR],   fb);
1508   set_specifier_fallback (Vtoolbar[RIGHT_TOOLBAR],  fb);
1509
1510   DEFVAR_SPECIFIER ("default-toolbar-height", &Vdefault_toolbar_height /*
1511 *Height of the default toolbar, if it's oriented horizontally.
1512 This is a specifier; use `set-specifier' to change it.
1513
1514 The position of the default toolbar is specified by the function
1515 `set-default-toolbar-position'.  If the corresponding position-specific
1516 toolbar thickness specifier (e.g. `top-toolbar-height' if
1517 `default-toolbar-position' is 'top) does not specify a thickness in a
1518 particular domain (a window or a frame), then the value of
1519 `default-toolbar-height' or `default-toolbar-width' (depending on the
1520 toolbar orientation) in that domain, if any, will be used instead.
1521
1522 Note that `default-toolbar-height' is only used when
1523 `default-toolbar-position' is 'top or 'bottom, and `default-toolbar-width'
1524 is only used when `default-toolbar-position' is 'left or 'right.
1525
1526 Note that all of the position-specific toolbar thickness specifiers
1527 have a fallback value of zero when they do not correspond to the
1528 default toolbar.  Therefore, you will have to set a non-zero thickness
1529 value if you want a position-specific toolbar to be displayed.
1530
1531 Internally, toolbar thickness specifiers are instantiated in both
1532 window and frame domains, for different purposes.  The value in the
1533 domain of a frame's selected window specifies the actual toolbar
1534 thickness that you will see in that frame.  The value in the domain of
1535 a frame itself specifies the toolbar thickness that is used in frame
1536 geometry calculations.
1537
1538 Thus, for example, if you set the frame width to 80 characters and the
1539 left toolbar width for that frame to 68 pixels, then the frame will
1540 be sized to fit 80 characters plus a 68-pixel left toolbar.  If you
1541 then set the left toolbar width to 0 for a particular buffer (or if
1542 that buffer does not specify a left toolbar or has a nil value
1543 specified for `left-toolbar-visible-p'), you will find that, when
1544 that buffer is displayed in the selected window, the window will have
1545 a width of 86 or 87 characters -- the frame is sized for a 68-pixel
1546 left toolbar but the selected window specifies that the left toolbar
1547 is not visible, so it is expanded to take up the slack.
1548 */ );
1549   Vdefault_toolbar_height = Fmake_specifier (Qnatnum);
1550   set_specifier_caching (Vdefault_toolbar_height,
1551                          offsetof (struct window, default_toolbar_height),
1552                          default_toolbar_size_changed_in_window,
1553                          offsetof (struct frame, default_toolbar_height),
1554                          default_toolbar_size_changed_in_frame);
1555
1556   DEFVAR_SPECIFIER ("default-toolbar-width", &Vdefault_toolbar_width /*
1557 *Width of the default toolbar, if it's oriented vertically.
1558 This is a specifier; use `set-specifier' to change it.
1559
1560 See `default-toolbar-height' for more information.
1561 */ );
1562   Vdefault_toolbar_width = Fmake_specifier (Qnatnum);
1563   set_specifier_caching (Vdefault_toolbar_width,
1564                          offsetof (struct window, default_toolbar_width),
1565                          default_toolbar_size_changed_in_window,
1566                          offsetof (struct frame, default_toolbar_width),
1567                          default_toolbar_size_changed_in_frame);
1568
1569   DEFVAR_SPECIFIER ("top-toolbar-height",
1570                     &Vtoolbar_size[TOP_TOOLBAR] /*
1571 *Height of the top toolbar.
1572 This is a specifier; use `set-specifier' to change it.
1573
1574 See `default-toolbar-height' for more information.
1575 */ );
1576   Vtoolbar_size[TOP_TOOLBAR] = Fmake_specifier (Qnatnum);
1577   set_specifier_caching (Vtoolbar_size[TOP_TOOLBAR],
1578                          offsetof (struct window, toolbar_size[TOP_TOOLBAR]),
1579                          toolbar_geometry_changed_in_window,
1580                          offsetof (struct frame, toolbar_size[TOP_TOOLBAR]),
1581                          frame_size_slipped);
1582
1583   DEFVAR_SPECIFIER ("bottom-toolbar-height",
1584                     &Vtoolbar_size[BOTTOM_TOOLBAR] /*
1585 *Height of the bottom toolbar.
1586 This is a specifier; use `set-specifier' to change it.
1587
1588 See `default-toolbar-height' for more information.
1589 */ );
1590   Vtoolbar_size[BOTTOM_TOOLBAR] = Fmake_specifier (Qnatnum);
1591   set_specifier_caching (Vtoolbar_size[BOTTOM_TOOLBAR],
1592                          offsetof (struct window, toolbar_size[BOTTOM_TOOLBAR]),
1593                          toolbar_geometry_changed_in_window,
1594                          offsetof (struct frame, toolbar_size[BOTTOM_TOOLBAR]),
1595                          frame_size_slipped);
1596
1597   DEFVAR_SPECIFIER ("left-toolbar-width",
1598                     &Vtoolbar_size[LEFT_TOOLBAR] /*
1599 *Width of left toolbar.
1600 This is a specifier; use `set-specifier' to change it.
1601
1602 See `default-toolbar-height' for more information.
1603 */ );
1604   Vtoolbar_size[LEFT_TOOLBAR] = Fmake_specifier (Qnatnum);
1605   set_specifier_caching (Vtoolbar_size[LEFT_TOOLBAR],
1606                          offsetof (struct window, toolbar_size[LEFT_TOOLBAR]),
1607                          toolbar_geometry_changed_in_window,
1608                          offsetof (struct frame, toolbar_size[LEFT_TOOLBAR]),
1609                          frame_size_slipped);
1610
1611   DEFVAR_SPECIFIER ("right-toolbar-width",
1612                     &Vtoolbar_size[RIGHT_TOOLBAR] /*
1613 *Width of right toolbar.
1614 This is a specifier; use `set-specifier' to change it.
1615
1616 See `default-toolbar-height' for more information.
1617 */ );
1618   Vtoolbar_size[RIGHT_TOOLBAR] = Fmake_specifier (Qnatnum);
1619   set_specifier_caching (Vtoolbar_size[RIGHT_TOOLBAR],
1620                          offsetof (struct window, toolbar_size[RIGHT_TOOLBAR]),
1621                          toolbar_geometry_changed_in_window,
1622                          offsetof (struct frame, toolbar_size[RIGHT_TOOLBAR]),
1623                          frame_size_slipped);
1624
1625   fb = Qnil;
1626 #ifdef HAVE_TTY
1627   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1628 #endif
1629 #ifdef HAVE_X_WINDOWS
1630   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_HEIGHT)), fb);
1631 #endif
1632 #ifdef HAVE_MS_WINDOWS
1633   fb = Fcons (Fcons (list1 (Qmswindows),
1634                      make_int (MSWINDOWS_DEFAULT_TOOLBAR_HEIGHT)), fb);
1635 #endif
1636   if (!NILP (fb))
1637     set_specifier_fallback (Vdefault_toolbar_height, fb);
1638
1639   fb = Qnil;
1640 #ifdef HAVE_TTY
1641   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1642 #endif
1643 #ifdef HAVE_X_WINDOWS
1644   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_WIDTH)), fb);
1645 #endif
1646 #ifdef HAVE_MS_WINDOWS
1647   fb = Fcons (Fcons (list1 (Qmswindows),
1648                      make_int (MSWINDOWS_DEFAULT_TOOLBAR_WIDTH)), fb);
1649 #endif
1650   if (!NILP (fb))
1651     set_specifier_fallback (Vdefault_toolbar_width, fb);
1652
1653   set_specifier_fallback (Vtoolbar_size[TOP_TOOLBAR], Vdefault_toolbar_height);
1654   fb = list1 (Fcons (Qnil, Qzero));
1655   set_specifier_fallback (Vtoolbar_size[BOTTOM_TOOLBAR], fb);
1656   set_specifier_fallback (Vtoolbar_size[LEFT_TOOLBAR],   fb);
1657   set_specifier_fallback (Vtoolbar_size[RIGHT_TOOLBAR],  fb);
1658
1659   DEFVAR_SPECIFIER ("default-toolbar-border-width",
1660                     &Vdefault_toolbar_border_width /*
1661 *Width of the border around the default toolbar.
1662 This is a specifier; use `set-specifier' to change it.
1663
1664 The position of the default toolbar is specified by the function
1665 `set-default-toolbar-position'.  If the corresponding position-specific
1666 toolbar border width specifier (e.g. `top-toolbar-border-width' if
1667 `default-toolbar-position' is 'top) does not specify a border width in a
1668 particular domain (a window or a frame), then the value of
1669 `default-toolbar-border-width' in that domain, if any, will be used
1670 instead.
1671
1672 Internally, toolbar border width specifiers are instantiated in both
1673 window and frame domains, for different purposes.  The value in the
1674 domain of a frame's selected window specifies the actual toolbar border
1675 width that you will see in that frame.  The value in the domain of a
1676 frame itself specifies the toolbar border width that is used in frame
1677 geometry calculations.  Changing the border width value in the frame
1678 domain will result in a size change in the frame itself, while changing
1679 the value in a window domain will not.
1680 */ );
1681   Vdefault_toolbar_border_width = Fmake_specifier (Qnatnum);
1682   set_specifier_caching (Vdefault_toolbar_border_width,
1683                          offsetof (struct window, default_toolbar_border_width),
1684                          default_toolbar_border_width_changed_in_window,
1685                          offsetof (struct frame, default_toolbar_border_width),
1686                          default_toolbar_border_width_changed_in_frame);
1687
1688   DEFVAR_SPECIFIER ("top-toolbar-border-width",
1689                     &Vtoolbar_border_width[TOP_TOOLBAR] /*
1690 *Border width of the top toolbar.
1691 This is a specifier; use `set-specifier' to change it.
1692
1693 See `default-toolbar-height' for more information.
1694 */ );
1695   Vtoolbar_border_width[TOP_TOOLBAR] = Fmake_specifier (Qnatnum);
1696   set_specifier_caching (Vtoolbar_border_width[TOP_TOOLBAR],
1697                          offsetof (struct window,
1698                                    toolbar_border_width[TOP_TOOLBAR]),
1699                          toolbar_geometry_changed_in_window,
1700                          offsetof (struct frame,
1701                                    toolbar_border_width[TOP_TOOLBAR]),
1702                          frame_size_slipped);
1703
1704   DEFVAR_SPECIFIER ("bottom-toolbar-border-width",
1705                     &Vtoolbar_border_width[BOTTOM_TOOLBAR] /*
1706 *Border width of the bottom toolbar.
1707 This is a specifier; use `set-specifier' to change it.
1708
1709 See `default-toolbar-height' for more information.
1710 */ );
1711   Vtoolbar_border_width[BOTTOM_TOOLBAR] = Fmake_specifier (Qnatnum);
1712   set_specifier_caching (Vtoolbar_border_width[BOTTOM_TOOLBAR],
1713                          offsetof (struct window,
1714                                    toolbar_border_width[BOTTOM_TOOLBAR]),
1715                          toolbar_geometry_changed_in_window,
1716                          offsetof (struct frame,
1717                                    toolbar_border_width[BOTTOM_TOOLBAR]),
1718                          frame_size_slipped);
1719
1720   DEFVAR_SPECIFIER ("left-toolbar-border-width",
1721                     &Vtoolbar_border_width[LEFT_TOOLBAR] /*
1722 *Border width of left toolbar.
1723 This is a specifier; use `set-specifier' to change it.
1724
1725 See `default-toolbar-height' for more information.
1726 */ );
1727   Vtoolbar_border_width[LEFT_TOOLBAR] = Fmake_specifier (Qnatnum);
1728   set_specifier_caching (Vtoolbar_border_width[LEFT_TOOLBAR],
1729                          offsetof (struct window,
1730                                    toolbar_border_width[LEFT_TOOLBAR]),
1731                          toolbar_geometry_changed_in_window,
1732                          offsetof (struct frame,
1733                                    toolbar_border_width[LEFT_TOOLBAR]),
1734                          frame_size_slipped);
1735
1736   DEFVAR_SPECIFIER ("right-toolbar-border-width",
1737                     &Vtoolbar_border_width[RIGHT_TOOLBAR] /*
1738 *Border width of right toolbar.
1739 This is a specifier; use `set-specifier' to change it.
1740
1741 See `default-toolbar-height' for more information.
1742 */ );
1743   Vtoolbar_border_width[RIGHT_TOOLBAR] = Fmake_specifier (Qnatnum);
1744   set_specifier_caching (Vtoolbar_border_width[RIGHT_TOOLBAR],
1745                          offsetof (struct window,
1746                                    toolbar_border_width[RIGHT_TOOLBAR]),
1747                          toolbar_geometry_changed_in_window,
1748                          offsetof (struct frame,
1749                                    toolbar_border_width[RIGHT_TOOLBAR]),
1750                          frame_size_slipped);
1751
1752   fb = Qnil;
1753 #ifdef HAVE_TTY
1754   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1755 #endif
1756 #ifdef HAVE_X_WINDOWS
1757   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_BORDER_WIDTH)), fb);
1758 #endif
1759 #ifdef HAVE_MS_WINDOWS
1760   fb = Fcons (Fcons (list1 (Qmswindows), make_int (MSWINDOWS_DEFAULT_TOOLBAR_BORDER_WIDTH)), fb);
1761 #endif
1762   if (!NILP (fb))
1763     set_specifier_fallback (Vdefault_toolbar_border_width, fb);
1764
1765   set_specifier_fallback (Vtoolbar_border_width[TOP_TOOLBAR], Vdefault_toolbar_border_width);
1766   fb = list1 (Fcons (Qnil, Qzero));
1767   set_specifier_fallback (Vtoolbar_border_width[BOTTOM_TOOLBAR], fb);
1768   set_specifier_fallback (Vtoolbar_border_width[LEFT_TOOLBAR],   fb);
1769   set_specifier_fallback (Vtoolbar_border_width[RIGHT_TOOLBAR],  fb);
1770
1771   DEFVAR_SPECIFIER ("default-toolbar-visible-p", &Vdefault_toolbar_visible_p /*
1772 *Whether the default toolbar is visible.
1773 This is a specifier; use `set-specifier' to change it.
1774
1775 The position of the default toolbar is specified by the function
1776 `set-default-toolbar-position'.  If the corresponding position-specific
1777 toolbar visibility specifier (e.g. `top-toolbar-visible-p' if
1778 `default-toolbar-position' is 'top) does not specify a visible-p value
1779 in a particular domain (a window or a frame), then the value of
1780 `default-toolbar-visible-p' in that domain, if any, will be used
1781 instead.
1782
1783 Both window domains and frame domains are used internally, for
1784 different purposes.  The distinction here is exactly the same as
1785 for thickness specifiers; see `default-toolbar-height' for more
1786 information.
1787
1788 `default-toolbar-visible-p' and all of the position-specific toolbar
1789 visibility specifiers have a fallback value of true.
1790 */ );
1791   Vdefault_toolbar_visible_p = Fmake_specifier (Qboolean);
1792   set_specifier_caching (Vdefault_toolbar_visible_p,
1793                          offsetof (struct window, default_toolbar_visible_p),
1794                          default_toolbar_visible_p_changed_in_window,
1795                          offsetof (struct frame, default_toolbar_visible_p),
1796                          default_toolbar_visible_p_changed_in_frame);
1797
1798   DEFVAR_SPECIFIER ("top-toolbar-visible-p",
1799                     &Vtoolbar_visible_p[TOP_TOOLBAR] /*
1800 *Whether the top toolbar is visible.
1801 This is a specifier; use `set-specifier' to change it.
1802
1803 See `default-toolbar-visible-p' for more information.
1804 */ );
1805   Vtoolbar_visible_p[TOP_TOOLBAR] = Fmake_specifier (Qboolean);
1806   set_specifier_caching (Vtoolbar_visible_p[TOP_TOOLBAR],
1807                          offsetof (struct window,
1808                                    toolbar_visible_p[TOP_TOOLBAR]),
1809                          toolbar_geometry_changed_in_window,
1810                          offsetof (struct frame,
1811                                    toolbar_visible_p[TOP_TOOLBAR]),
1812                          frame_size_slipped);
1813
1814   DEFVAR_SPECIFIER ("bottom-toolbar-visible-p",
1815                     &Vtoolbar_visible_p[BOTTOM_TOOLBAR] /*
1816 *Whether the bottom toolbar is visible.
1817 This is a specifier; use `set-specifier' to change it.
1818
1819 See `default-toolbar-visible-p' for more information.
1820 */ );
1821   Vtoolbar_visible_p[BOTTOM_TOOLBAR] = Fmake_specifier (Qboolean);
1822   set_specifier_caching (Vtoolbar_visible_p[BOTTOM_TOOLBAR],
1823                          offsetof (struct window,
1824                                    toolbar_visible_p[BOTTOM_TOOLBAR]),
1825                          toolbar_geometry_changed_in_window,
1826                          offsetof (struct frame,
1827                                    toolbar_visible_p[BOTTOM_TOOLBAR]),
1828                          frame_size_slipped);
1829
1830   DEFVAR_SPECIFIER ("left-toolbar-visible-p",
1831                     &Vtoolbar_visible_p[LEFT_TOOLBAR] /*
1832 *Whether the left toolbar is visible.
1833 This is a specifier; use `set-specifier' to change it.
1834
1835 See `default-toolbar-visible-p' for more information.
1836 */ );
1837   Vtoolbar_visible_p[LEFT_TOOLBAR] = Fmake_specifier (Qboolean);
1838   set_specifier_caching (Vtoolbar_visible_p[LEFT_TOOLBAR],
1839                          offsetof (struct window,
1840                                    toolbar_visible_p[LEFT_TOOLBAR]),
1841                          toolbar_geometry_changed_in_window,
1842                          offsetof (struct frame,
1843                                    toolbar_visible_p[LEFT_TOOLBAR]),
1844                          frame_size_slipped);
1845
1846   DEFVAR_SPECIFIER ("right-toolbar-visible-p",
1847                     &Vtoolbar_visible_p[RIGHT_TOOLBAR] /*
1848 *Whether the right toolbar is visible.
1849 This is a specifier; use `set-specifier' to change it.
1850
1851 See `default-toolbar-visible-p' for more information.
1852 */ );
1853   Vtoolbar_visible_p[RIGHT_TOOLBAR] = Fmake_specifier (Qboolean);
1854   set_specifier_caching (Vtoolbar_visible_p[RIGHT_TOOLBAR],
1855                          offsetof (struct window,
1856                                    toolbar_visible_p[RIGHT_TOOLBAR]),
1857                          toolbar_geometry_changed_in_window,
1858                          offsetof (struct frame,
1859                                    toolbar_visible_p[RIGHT_TOOLBAR]),
1860                          frame_size_slipped);
1861
1862   /* initially, top inherits from default; this can be
1863      changed with `set-default-toolbar-position'. */
1864   fb = list1 (Fcons (Qnil, Qt));
1865   set_specifier_fallback (Vdefault_toolbar_visible_p, fb);
1866   set_specifier_fallback (Vtoolbar_visible_p[TOP_TOOLBAR],
1867                           Vdefault_toolbar_visible_p);
1868   set_specifier_fallback (Vtoolbar_visible_p[BOTTOM_TOOLBAR], fb);
1869   set_specifier_fallback (Vtoolbar_visible_p[LEFT_TOOLBAR],   fb);
1870   set_specifier_fallback (Vtoolbar_visible_p[RIGHT_TOOLBAR],  fb);
1871
1872   DEFVAR_SPECIFIER ("toolbar-buttons-captioned-p",
1873                     &Vtoolbar_buttons_captioned_p /*
1874 *Whether the toolbar buttons are captioned.
1875 This will only have a visible effect for those toolbar buttons which had
1876 captioned versions specified.
1877 This is a specifier; use `set-specifier' to change it.
1878 */ );
1879   Vtoolbar_buttons_captioned_p = Fmake_specifier (Qboolean);
1880   set_specifier_caching (Vtoolbar_buttons_captioned_p,
1881                          offsetof (struct window, toolbar_buttons_captioned_p),
1882                          toolbar_buttons_captioned_p_changed,
1883                          0, 0);
1884   set_specifier_fallback (Vtoolbar_buttons_captioned_p,
1885                           list1 (Fcons (Qnil, Qt)));
1886 }