XEmacs 21.2.20 "Yoko".
[chise/xemacs-chise.git.1] / 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 Toolbar specifiers are used to specify the format of a toolbar.
1164 The values of the variables `default-toolbar', `top-toolbar',
1165 `left-toolbar', `right-toolbar', and `bottom-toolbar' are always
1166 toolbar specifiers.
1167
1168 Valid toolbar instantiators are called "toolbar descriptors"
1169 and are lists of vectors.  See `default-toolbar' for a description
1170 of the exact format.
1171 */
1172        (object))
1173 {
1174   return TOOLBAR_SPECIFIERP (object) ? Qt : Qnil;
1175 }
1176
1177 \f
1178 /*
1179   Helper for invalidating the real specifier when default
1180   specifier caching changes
1181 */
1182 static void
1183 recompute_overlaying_specifier (Lisp_Object real_one[4])
1184 {
1185   enum toolbar_pos pos = decode_toolbar_position (Vdefault_toolbar_position);
1186   Fset_specifier_dirty_flag (real_one[pos]);
1187 }
1188
1189 static void
1190 toolbar_specs_changed (Lisp_Object specifier, struct window *w,
1191                        Lisp_Object oldval)
1192 {
1193   /* This could be smarter but I doubt that it would make any
1194      noticeable difference given the infrequency with which this is
1195      probably going to be called.
1196      */
1197   MARK_TOOLBAR_CHANGED;
1198 }
1199
1200 static void
1201 default_toolbar_specs_changed (Lisp_Object specifier, struct window *w,
1202                                Lisp_Object oldval)
1203 {
1204   recompute_overlaying_specifier (Vtoolbar);
1205 }
1206
1207 static void
1208 default_toolbar_size_changed_in_frame (Lisp_Object specifier, struct frame *f,
1209                                        Lisp_Object oldval)
1210 {
1211   recompute_overlaying_specifier (Vtoolbar_size);
1212 }
1213
1214 static void
1215 default_toolbar_border_width_changed_in_frame (Lisp_Object specifier,
1216                                                struct frame *f,
1217                                                Lisp_Object oldval)
1218 {
1219   recompute_overlaying_specifier (Vtoolbar_border_width);
1220 }
1221
1222 static void
1223 default_toolbar_visible_p_changed_in_frame (Lisp_Object specifier,
1224                                             struct frame *f,
1225                                             Lisp_Object oldval)
1226 {
1227   recompute_overlaying_specifier (Vtoolbar_visible_p);
1228 }
1229
1230 static void
1231 toolbar_geometry_changed_in_window (Lisp_Object specifier, struct window *w,
1232                                     Lisp_Object oldval)
1233 {
1234   MARK_TOOLBAR_CHANGED;
1235   MARK_WINDOWS_CHANGED (w);
1236 }
1237
1238 static void
1239 default_toolbar_size_changed_in_window (Lisp_Object specifier, struct window *w,
1240                                         Lisp_Object oldval)
1241 {
1242   recompute_overlaying_specifier (Vtoolbar_size);
1243 }
1244
1245 static void
1246 default_toolbar_border_width_changed_in_window (Lisp_Object specifier,
1247                                                 struct window *w,
1248                                                 Lisp_Object oldval)
1249 {
1250   recompute_overlaying_specifier (Vtoolbar_border_width);
1251 }
1252
1253 static void
1254 default_toolbar_visible_p_changed_in_window (Lisp_Object specifier,
1255                                              struct window *w,
1256                                              Lisp_Object oldval)
1257 {
1258   recompute_overlaying_specifier (Vtoolbar_visible_p);
1259 }
1260
1261 static void
1262 toolbar_buttons_captioned_p_changed (Lisp_Object specifier, struct window *w,
1263                                      Lisp_Object oldval)
1264 {
1265   /* This could be smarter but I doubt that it would make any
1266      noticeable difference given the infrequency with which this is
1267      probably going to be called. */
1268   MARK_TOOLBAR_CHANGED;
1269 }
1270
1271 \f
1272 void
1273 syms_of_toolbar (void)
1274 {
1275   defsymbol (&Qtoolbar_buttonp, "toolbar-button-p");
1276   defsymbol (&Q2D, "2D");
1277   defsymbol (&Q3D, "3D");
1278   defsymbol (&Q2d, "2d");
1279   defsymbol (&Q3d, "3d");
1280   defsymbol (&Q_size, ":size"); Fset (Q_size, Q_size);
1281
1282   defsymbol (&Qinit_toolbar_from_resources, "init-toolbar-from-resources");
1283   DEFSUBR (Ftoolbar_button_p);
1284   DEFSUBR (Ftoolbar_button_callback);
1285   DEFSUBR (Ftoolbar_button_help_string);
1286   DEFSUBR (Ftoolbar_button_enabled_p);
1287   DEFSUBR (Fset_toolbar_button_down_flag);
1288   DEFSUBR (Fcheck_toolbar_button_syntax);
1289   DEFSUBR (Fset_default_toolbar_position);
1290   DEFSUBR (Fdefault_toolbar_position);
1291   DEFSUBR (Ftoolbar_specifier_p);
1292 }
1293
1294 void
1295 vars_of_toolbar (void)
1296 {
1297   staticpro (&Vdefault_toolbar_position);
1298   Vdefault_toolbar_position = Qtop;
1299
1300 #ifdef HAVE_WINDOW_SYSTEM
1301   Fprovide (Qtoolbar);
1302 #endif
1303 }
1304
1305 void
1306 specifier_type_create_toolbar (void)
1307 {
1308   INITIALIZE_SPECIFIER_TYPE (toolbar, "toolbar", "toolbar-specifier-p");
1309
1310   SPECIFIER_HAS_METHOD (toolbar, validate);
1311   SPECIFIER_HAS_METHOD (toolbar, after_change);
1312 }
1313
1314 void
1315 reinit_specifier_type_create_toolbar (void)
1316 {
1317   REINITIALIZE_SPECIFIER_TYPE (toolbar);
1318 }
1319
1320 void
1321 specifier_vars_of_toolbar (void)
1322 {
1323   Lisp_Object fb;
1324
1325   DEFVAR_SPECIFIER ("default-toolbar", &Vdefault_toolbar /*
1326 Specifier for a fallback toolbar.
1327 Use `set-specifier' to change this.
1328
1329 The position of this toolbar is specified in the function
1330 `default-toolbar-position'.  If the corresponding position-specific
1331 toolbar (e.g. `top-toolbar' if `default-toolbar-position' is 'top)
1332 does not specify a toolbar in a particular domain (usually a window),
1333 then the value of `default-toolbar' in that domain, if any, will be
1334 used instead.
1335
1336 Note that the toolbar at any particular position will not be
1337 displayed unless its visibility flag is true and its thickness
1338 \(width or height, depending on orientation) is non-zero.  The
1339 visibility is controlled by the specifiers `top-toolbar-visible-p',
1340 `bottom-toolbar-visible-p', `left-toolbar-visible-p', and
1341 `right-toolbar-visible-p', and the thickness is controlled by the
1342 specifiers `top-toolbar-height', `bottom-toolbar-height',
1343 `left-toolbar-width', and `right-toolbar-width'.
1344
1345 Note that one of the four visibility specifiers inherits from
1346 `default-toolbar-visibility' and one of the four thickness
1347 specifiers inherits from either `default-toolbar-width' or
1348 `default-toolbar-height' (depending on orientation), just
1349 like for the toolbar description specifiers (e.g. `top-toolbar')
1350 mentioned above.
1351
1352 Therefore, if you are setting `default-toolbar', you should control
1353 the visibility and thickness using `default-toolbar-visible-p',
1354 `default-toolbar-width', and `default-toolbar-height', rather than
1355 using position-specific specifiers.  That way, you will get sane
1356 behavior if the user changes the default toolbar position.
1357
1358 The format of the instantiator for a toolbar is a list of
1359 toolbar-button-descriptors.  Each toolbar-button-descriptor
1360 is a vector in one of the following formats:
1361
1362   [GLYPH-LIST FUNCTION ENABLED-P HELP] or
1363   [:style 2D-OR-3D] or
1364   [:style 2D-OR-3D :size WIDTH-OR-HEIGHT] or
1365   [:size WIDTH-OR-HEIGHT :style 2D-OR-3D]
1366
1367 Optionally, one of the toolbar-button-descriptors may be nil
1368 instead of a vector; this signifies the division between
1369 the toolbar buttons that are to be displayed flush-left,
1370 and the buttons to be displayed flush-right.
1371
1372 The first vector format above specifies a normal toolbar button;
1373 the others specify blank areas in the toolbar.
1374
1375 For the first vector format:
1376
1377 -- GLYPH-LIST should be a list of one to six glyphs (as created by
1378    `make-glyph') or a symbol whose value is such a list.  The first
1379    glyph, which must be provided, is the glyph used to display the
1380    toolbar button when it is in the "up" (not pressed) state.  The
1381    optional second glyph is for displaying the button when it is in
1382    the "down" (pressed) state.  The optional third glyph is for when
1383    the button is disabled.  The optional fourth, fifth and sixth glyphs
1384    are used to specify captioned versions for the up, down and disabled
1385    states respectively.  The function `toolbar-make-button-list' is
1386    useful in creating these glyph lists.  The specifier variable
1387    `toolbar-buttons-captioned-p' controls which glyphs are actually used.
1388
1389 -- Even if you do not provide separate down-state and disabled-state
1390    glyphs, the user will still get visual feedback to indicate which
1391    state the button is in.  Buttons in the up-state are displayed
1392    with a shadowed border that gives a raised appearance to the
1393    button.  Buttons in the down-state are displayed with shadows that
1394    give a recessed appearance.  Buttons in the disabled state are
1395    displayed with no shadows, giving a 2-d effect.
1396
1397 -- If some of the toolbar glyphs are not provided, they inherit as follows:
1398
1399      UP:                up
1400      DOWN:              down -> up
1401      DISABLED:          disabled -> up
1402      CAP-UP:            cap-up -> up
1403      CAP-DOWN:          cap-down -> cap-up -> down -> up
1404      CAP-DISABLED:      cap-disabled -> cap-up -> disabled -> up
1405
1406 -- The second element FUNCTION is a function to be called when the
1407    toolbar button is activated (i.e. when the mouse is released over
1408    the toolbar button, if the press occurred in the toolbar).  It
1409    can be any form accepted by `call-interactively', since this is
1410    how it is invoked.
1411
1412 -- The third element ENABLED-P specifies whether the toolbar button
1413    is enabled (disabled buttons do nothing when they are activated,
1414    and are displayed differently; see above).  It should be either
1415    a boolean or a form that evaluates to a boolean.
1416
1417 -- The fourth element HELP, if non-nil, should be a string.  This
1418    string is displayed in the echo area when the mouse passes over
1419    the toolbar button.
1420
1421 For the other vector formats (specifying blank areas of the toolbar):
1422
1423 -- 2D-OR-3D should be one of the symbols '2d or '3d, indicating
1424    whether the area is displayed with shadows (giving it a raised,
1425    3-d appearance) or without shadows (giving it a flat appearance).
1426
1427 -- WIDTH-OR-HEIGHT specifies the length, in pixels, of the blank
1428    area.  If omitted, it defaults to a device-specific value
1429    (8 pixels for X devices).
1430 */ );
1431
1432   Vdefault_toolbar = Fmake_specifier (Qtoolbar);
1433   /* #### It would be even nicer if the specifier caching
1434      automatically knew about specifier fallbacks, so we didn't
1435      have to do it ourselves. */
1436   set_specifier_caching (Vdefault_toolbar,
1437                          slot_offset (struct window,
1438                                       default_toolbar),
1439                          default_toolbar_specs_changed,
1440                          0, 0);
1441
1442   DEFVAR_SPECIFIER ("top-toolbar",
1443                     &Vtoolbar[TOP_TOOLBAR] /*
1444 Specifier for the toolbar at the top of the frame.
1445 Use `set-specifier' to change this.
1446 See `default-toolbar' for a description of a valid toolbar instantiator.
1447 */ );
1448   Vtoolbar[TOP_TOOLBAR] = Fmake_specifier (Qtoolbar);
1449   set_specifier_caching (Vtoolbar[TOP_TOOLBAR],
1450                          slot_offset (struct window,
1451                                       toolbar[TOP_TOOLBAR]),
1452                          toolbar_specs_changed,
1453                          0, 0);
1454
1455   DEFVAR_SPECIFIER ("bottom-toolbar",
1456                     &Vtoolbar[BOTTOM_TOOLBAR] /*
1457 Specifier for the toolbar at the bottom of the frame.
1458 Use `set-specifier' to change this.
1459 See `default-toolbar' for a description of a valid toolbar instantiator.
1460
1461 Note that, unless the `default-toolbar-position' is `bottom', by
1462 default the height of the bottom toolbar (controlled by
1463 `bottom-toolbar-height') is 0; thus, a bottom toolbar will not be
1464 displayed even if you provide a value for `bottom-toolbar'.
1465 */ );
1466   Vtoolbar[BOTTOM_TOOLBAR] = Fmake_specifier (Qtoolbar);
1467   set_specifier_caching (Vtoolbar[BOTTOM_TOOLBAR],
1468                          slot_offset (struct window,
1469                                       toolbar[BOTTOM_TOOLBAR]),
1470                          toolbar_specs_changed,
1471                          0, 0);
1472
1473   DEFVAR_SPECIFIER ("left-toolbar",
1474                     &Vtoolbar[LEFT_TOOLBAR] /*
1475 Specifier for the toolbar at the left edge of the frame.
1476 Use `set-specifier' to change this.
1477 See `default-toolbar' for a description of a valid toolbar instantiator.
1478
1479 Note that, unless the `default-toolbar-position' is `left', by
1480 default the height of the left toolbar (controlled by
1481 `left-toolbar-width') is 0; thus, a left toolbar will not be
1482 displayed even if you provide a value for `left-toolbar'.
1483 */ );
1484   Vtoolbar[LEFT_TOOLBAR] = Fmake_specifier (Qtoolbar);
1485   set_specifier_caching (Vtoolbar[LEFT_TOOLBAR],
1486                          slot_offset (struct window,
1487                                       toolbar[LEFT_TOOLBAR]),
1488                          toolbar_specs_changed,
1489                          0, 0);
1490
1491   DEFVAR_SPECIFIER ("right-toolbar",
1492                     &Vtoolbar[RIGHT_TOOLBAR] /*
1493 Specifier for the toolbar at the right edge of the frame.
1494 Use `set-specifier' to change this.
1495 See `default-toolbar' for a description of a valid toolbar instantiator.
1496
1497 Note that, unless the `default-toolbar-position' is `right', by
1498 default the height of the right toolbar (controlled by
1499 `right-toolbar-width') is 0; thus, a right toolbar will not be
1500 displayed even if you provide a value for `right-toolbar'.
1501 */ );
1502   Vtoolbar[RIGHT_TOOLBAR] = Fmake_specifier (Qtoolbar);
1503   set_specifier_caching (Vtoolbar[RIGHT_TOOLBAR],
1504                          slot_offset (struct window,
1505                                       toolbar[RIGHT_TOOLBAR]),
1506                          toolbar_specs_changed,
1507                          0, 0);
1508
1509   /* initially, top inherits from default; this can be
1510      changed with `set-default-toolbar-position'. */
1511   fb = list1 (Fcons (Qnil, Qnil));
1512   set_specifier_fallback (Vdefault_toolbar, fb);
1513   set_specifier_fallback (Vtoolbar[TOP_TOOLBAR], Vdefault_toolbar);
1514   set_specifier_fallback (Vtoolbar[BOTTOM_TOOLBAR], fb);
1515   set_specifier_fallback (Vtoolbar[LEFT_TOOLBAR],   fb);
1516   set_specifier_fallback (Vtoolbar[RIGHT_TOOLBAR],  fb);
1517
1518   DEFVAR_SPECIFIER ("default-toolbar-height", &Vdefault_toolbar_height /*
1519 *Height of the default toolbar, if it's oriented horizontally.
1520 This is a specifier; use `set-specifier' to change it.
1521
1522 The position of the default toolbar is specified by the function
1523 `set-default-toolbar-position'.  If the corresponding position-specific
1524 toolbar thickness specifier (e.g. `top-toolbar-height' if
1525 `default-toolbar-position' is 'top) does not specify a thickness in a
1526 particular domain (a window or a frame), then the value of
1527 `default-toolbar-height' or `default-toolbar-width' (depending on the
1528 toolbar orientation) in that domain, if any, will be used instead.
1529
1530 Note that `default-toolbar-height' is only used when
1531 `default-toolbar-position' is 'top or 'bottom, and `default-toolbar-width'
1532 is only used when `default-toolbar-position' is 'left or 'right.
1533
1534 Note that all of the position-specific toolbar thickness specifiers
1535 have a fallback value of zero when they do not correspond to the
1536 default toolbar.  Therefore, you will have to set a non-zero thickness
1537 value if you want a position-specific toolbar to be displayed.
1538
1539 Internally, toolbar thickness specifiers are instantiated in both
1540 window and frame domains, for different purposes.  The value in the
1541 domain of a frame's selected window specifies the actual toolbar
1542 thickness that you will see in that frame.  The value in the domain of
1543 a frame itself specifies the toolbar thickness that is used in frame
1544 geometry calculations.
1545
1546 Thus, for example, if you set the frame width to 80 characters and the
1547 left toolbar width for that frame to 68 pixels, then the frame will
1548 be sized to fit 80 characters plus a 68-pixel left toolbar.  If you
1549 then set the left toolbar width to 0 for a particular buffer (or if
1550 that buffer does not specify a left toolbar or has a nil value
1551 specified for `left-toolbar-visible-p'), you will find that, when
1552 that buffer is displayed in the selected window, the window will have
1553 a width of 86 or 87 characters -- the frame is sized for a 68-pixel
1554 left toolbar but the selected window specifies that the left toolbar
1555 is not visible, so it is expanded to take up the slack.
1556 */ );
1557   Vdefault_toolbar_height = Fmake_specifier (Qnatnum);
1558   set_specifier_caching (Vdefault_toolbar_height,
1559                          slot_offset (struct window,
1560                                       default_toolbar_height),
1561                          default_toolbar_size_changed_in_window,
1562                          slot_offset (struct frame,
1563                                       default_toolbar_height),
1564                          default_toolbar_size_changed_in_frame);
1565
1566   DEFVAR_SPECIFIER ("default-toolbar-width", &Vdefault_toolbar_width /*
1567 *Width of the default toolbar, if it's oriented vertically.
1568 This is a specifier; use `set-specifier' to change it.
1569
1570 See `default-toolbar-height' for more information.
1571 */ );
1572   Vdefault_toolbar_width = Fmake_specifier (Qnatnum);
1573   set_specifier_caching (Vdefault_toolbar_width,
1574                          slot_offset (struct window,
1575                                       default_toolbar_width),
1576                          default_toolbar_size_changed_in_window,
1577                          slot_offset (struct frame,
1578                                       default_toolbar_width),
1579                          default_toolbar_size_changed_in_frame);
1580
1581   DEFVAR_SPECIFIER ("top-toolbar-height",
1582                     &Vtoolbar_size[TOP_TOOLBAR] /*
1583 *Height of the top toolbar.
1584 This is a specifier; use `set-specifier' to change it.
1585
1586 See `default-toolbar-height' for more information.
1587 */ );
1588   Vtoolbar_size[TOP_TOOLBAR] = Fmake_specifier (Qnatnum);
1589   set_specifier_caching (Vtoolbar_size[TOP_TOOLBAR],
1590                          slot_offset (struct window,
1591                                       toolbar_size[TOP_TOOLBAR]),
1592                          toolbar_geometry_changed_in_window,
1593                          slot_offset (struct frame,
1594                                       toolbar_size[TOP_TOOLBAR]),
1595                          frame_size_slipped);
1596
1597   DEFVAR_SPECIFIER ("bottom-toolbar-height",
1598                     &Vtoolbar_size[BOTTOM_TOOLBAR] /*
1599 *Height of the bottom 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[BOTTOM_TOOLBAR] = Fmake_specifier (Qnatnum);
1605   set_specifier_caching (Vtoolbar_size[BOTTOM_TOOLBAR],
1606                          slot_offset (struct window,
1607                                       toolbar_size[BOTTOM_TOOLBAR]),
1608                          toolbar_geometry_changed_in_window,
1609                          slot_offset (struct frame,
1610                                       toolbar_size[BOTTOM_TOOLBAR]),
1611                          frame_size_slipped);
1612
1613   DEFVAR_SPECIFIER ("left-toolbar-width",
1614                     &Vtoolbar_size[LEFT_TOOLBAR] /*
1615 *Width of left toolbar.
1616 This is a specifier; use `set-specifier' to change it.
1617
1618 See `default-toolbar-height' for more information.
1619 */ );
1620   Vtoolbar_size[LEFT_TOOLBAR] = Fmake_specifier (Qnatnum);
1621   set_specifier_caching (Vtoolbar_size[LEFT_TOOLBAR],
1622                          slot_offset (struct window,
1623                                       toolbar_size[LEFT_TOOLBAR]),
1624                          toolbar_geometry_changed_in_window,
1625                          slot_offset (struct frame,
1626                                       toolbar_size[LEFT_TOOLBAR]),
1627                          frame_size_slipped);
1628
1629   DEFVAR_SPECIFIER ("right-toolbar-width",
1630                     &Vtoolbar_size[RIGHT_TOOLBAR] /*
1631 *Width of right toolbar.
1632 This is a specifier; use `set-specifier' to change it.
1633
1634 See `default-toolbar-height' for more information.
1635 */ );
1636   Vtoolbar_size[RIGHT_TOOLBAR] = Fmake_specifier (Qnatnum);
1637   set_specifier_caching (Vtoolbar_size[RIGHT_TOOLBAR],
1638                          slot_offset (struct window,
1639                                       toolbar_size[RIGHT_TOOLBAR]),
1640                          toolbar_geometry_changed_in_window,
1641                          slot_offset (struct frame,
1642                                       toolbar_size[RIGHT_TOOLBAR]),
1643                          frame_size_slipped);
1644
1645   fb = Qnil;
1646 #ifdef HAVE_TTY
1647   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1648 #endif
1649 #ifdef HAVE_X_WINDOWS
1650   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_HEIGHT)), fb);
1651 #endif
1652 #ifdef HAVE_MS_WINDOWS
1653   fb = Fcons (Fcons (list1 (Qmswindows), 
1654                      make_int (MSWINDOWS_DEFAULT_TOOLBAR_HEIGHT)), fb);
1655 #endif
1656   if (!NILP (fb))
1657     set_specifier_fallback (Vdefault_toolbar_height, fb);
1658
1659   fb = Qnil;
1660 #ifdef HAVE_TTY
1661   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1662 #endif
1663 #ifdef HAVE_X_WINDOWS
1664   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_WIDTH)), fb);
1665 #endif
1666 #ifdef HAVE_MS_WINDOWS
1667   fb = Fcons (Fcons (list1 (Qmswindows), 
1668                      make_int (MSWINDOWS_DEFAULT_TOOLBAR_WIDTH)), fb);
1669 #endif
1670   if (!NILP (fb))
1671     set_specifier_fallback (Vdefault_toolbar_width, fb);
1672
1673   set_specifier_fallback (Vtoolbar_size[TOP_TOOLBAR], Vdefault_toolbar_height);
1674   fb = list1 (Fcons (Qnil, Qzero));
1675   set_specifier_fallback (Vtoolbar_size[BOTTOM_TOOLBAR], fb);
1676   set_specifier_fallback (Vtoolbar_size[LEFT_TOOLBAR],   fb);
1677   set_specifier_fallback (Vtoolbar_size[RIGHT_TOOLBAR],  fb);
1678
1679   DEFVAR_SPECIFIER ("default-toolbar-border-width",
1680                     &Vdefault_toolbar_border_width /*
1681 *Width of the border around the default toolbar.
1682 This is a specifier; use `set-specifier' to change it.
1683
1684 The position of the default toolbar is specified by the function
1685 `set-default-toolbar-position'.  If the corresponding position-specific
1686 toolbar border width specifier (e.g. `top-toolbar-border-width' if
1687 `default-toolbar-position' is 'top) does not specify a border width in a
1688 particular domain (a window or a frame), then the value of
1689 `default-toolbar-border-width' in that domain, if any, will be used
1690 instead.
1691
1692 Internally, toolbar border width specifiers are instantiated in both
1693 window and frame domains, for different purposes.  The value in the
1694 domain of a frame's selected window specifies the actual toolbar border
1695 width that you will see in that frame.  The value in the domain of a
1696 frame itself specifies the toolbar border width that is used in frame
1697 geometry calculations.  Changing the border width value in the frame
1698 domain will result in a size change in the frame itself, while changing
1699 the value in a window domain will not.
1700 */ );
1701   Vdefault_toolbar_border_width = Fmake_specifier (Qnatnum);
1702   set_specifier_caching (Vdefault_toolbar_border_width,
1703                          slot_offset (struct window,
1704                                       default_toolbar_border_width),
1705                          default_toolbar_border_width_changed_in_window,
1706                          slot_offset (struct frame,
1707                                       default_toolbar_border_width),
1708                          default_toolbar_border_width_changed_in_frame);
1709
1710   DEFVAR_SPECIFIER ("top-toolbar-border-width",
1711                     &Vtoolbar_border_width[TOP_TOOLBAR] /*
1712 *Border width of the top toolbar.
1713 This is a specifier; use `set-specifier' to change it.
1714
1715 See `default-toolbar-height' for more information.
1716 */ );
1717   Vtoolbar_border_width[TOP_TOOLBAR] = Fmake_specifier (Qnatnum);
1718   set_specifier_caching (Vtoolbar_border_width[TOP_TOOLBAR],
1719                          slot_offset (struct window,
1720                                       toolbar_border_width[TOP_TOOLBAR]),
1721                          toolbar_geometry_changed_in_window,
1722                          slot_offset (struct frame,
1723                                       toolbar_border_width[TOP_TOOLBAR]),
1724                          frame_size_slipped);
1725
1726   DEFVAR_SPECIFIER ("bottom-toolbar-border-width",
1727                     &Vtoolbar_border_width[BOTTOM_TOOLBAR] /*
1728 *Border width of the bottom toolbar.
1729 This is a specifier; use `set-specifier' to change it.
1730
1731 See `default-toolbar-height' for more information.
1732 */ );
1733   Vtoolbar_border_width[BOTTOM_TOOLBAR] = Fmake_specifier (Qnatnum);
1734   set_specifier_caching (Vtoolbar_border_width[BOTTOM_TOOLBAR],
1735                          slot_offset (struct window,
1736                                       toolbar_border_width[BOTTOM_TOOLBAR]),
1737                          toolbar_geometry_changed_in_window,
1738                          slot_offset (struct frame,
1739                                       toolbar_border_width[BOTTOM_TOOLBAR]),
1740                          frame_size_slipped);
1741
1742   DEFVAR_SPECIFIER ("left-toolbar-border-width",
1743                     &Vtoolbar_border_width[LEFT_TOOLBAR] /*
1744 *Border width of left toolbar.
1745 This is a specifier; use `set-specifier' to change it.
1746
1747 See `default-toolbar-height' for more information.
1748 */ );
1749   Vtoolbar_border_width[LEFT_TOOLBAR] = Fmake_specifier (Qnatnum);
1750   set_specifier_caching (Vtoolbar_border_width[LEFT_TOOLBAR],
1751                          slot_offset (struct window,
1752                                       toolbar_border_width[LEFT_TOOLBAR]),
1753                          toolbar_geometry_changed_in_window,
1754                          slot_offset (struct frame,
1755                                       toolbar_border_width[LEFT_TOOLBAR]),
1756                          frame_size_slipped);
1757
1758   DEFVAR_SPECIFIER ("right-toolbar-border-width",
1759                     &Vtoolbar_border_width[RIGHT_TOOLBAR] /*
1760 *Border width of right toolbar.
1761 This is a specifier; use `set-specifier' to change it.
1762
1763 See `default-toolbar-height' for more information.
1764 */ );
1765   Vtoolbar_border_width[RIGHT_TOOLBAR] = Fmake_specifier (Qnatnum);
1766   set_specifier_caching (Vtoolbar_border_width[RIGHT_TOOLBAR],
1767                          slot_offset (struct window,
1768                                       toolbar_border_width[RIGHT_TOOLBAR]),
1769                          toolbar_geometry_changed_in_window,
1770                          slot_offset (struct frame,
1771                                       toolbar_border_width[RIGHT_TOOLBAR]),
1772                          frame_size_slipped);
1773
1774   fb = Qnil;
1775 #ifdef HAVE_TTY
1776   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1777 #endif
1778 #ifdef HAVE_X_WINDOWS
1779   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_BORDER_WIDTH)), fb);
1780 #endif
1781 #ifdef HAVE_MS_WINDOWS
1782   fb = Fcons (Fcons (list1 (Qmswindows), make_int (MSWINDOWS_DEFAULT_TOOLBAR_BORDER_WIDTH)), fb);
1783 #endif
1784   if (!NILP (fb))
1785     set_specifier_fallback (Vdefault_toolbar_border_width, fb);
1786
1787   set_specifier_fallback (Vtoolbar_border_width[TOP_TOOLBAR], Vdefault_toolbar_border_width);
1788   fb = list1 (Fcons (Qnil, Qzero));
1789   set_specifier_fallback (Vtoolbar_border_width[BOTTOM_TOOLBAR], fb);
1790   set_specifier_fallback (Vtoolbar_border_width[LEFT_TOOLBAR],   fb);
1791   set_specifier_fallback (Vtoolbar_border_width[RIGHT_TOOLBAR],  fb);
1792
1793   DEFVAR_SPECIFIER ("default-toolbar-visible-p", &Vdefault_toolbar_visible_p /*
1794 *Whether the default toolbar is visible.
1795 This is a specifier; use `set-specifier' to change it.
1796
1797 The position of the default toolbar is specified by the function
1798 `set-default-toolbar-position'.  If the corresponding position-specific
1799 toolbar visibility specifier (e.g. `top-toolbar-visible-p' if
1800 `default-toolbar-position' is 'top) does not specify a visible-p value
1801 in a particular domain (a window or a frame), then the value of
1802 `default-toolbar-visible-p' in that domain, if any, will be used
1803 instead.
1804
1805 Both window domains and frame domains are used internally, for
1806 different purposes.  The distinction here is exactly the same as
1807 for thickness specifiers; see `default-toolbar-height' for more
1808 information.
1809
1810 `default-toolbar-visible-p' and all of the position-specific toolbar
1811 visibility specifiers have a fallback value of true.
1812 */ );
1813   Vdefault_toolbar_visible_p = Fmake_specifier (Qboolean);
1814   set_specifier_caching (Vdefault_toolbar_visible_p,
1815                          slot_offset (struct window,
1816                                       default_toolbar_visible_p),
1817                          default_toolbar_visible_p_changed_in_window,
1818                          slot_offset (struct frame,
1819                                       default_toolbar_visible_p),
1820                          default_toolbar_visible_p_changed_in_frame);
1821
1822   DEFVAR_SPECIFIER ("top-toolbar-visible-p",
1823                     &Vtoolbar_visible_p[TOP_TOOLBAR] /*
1824 *Whether the top toolbar is visible.
1825 This is a specifier; use `set-specifier' to change it.
1826
1827 See `default-toolbar-visible-p' for more information.
1828 */ );
1829   Vtoolbar_visible_p[TOP_TOOLBAR] = Fmake_specifier (Qboolean);
1830   set_specifier_caching (Vtoolbar_visible_p[TOP_TOOLBAR],
1831                          slot_offset (struct window,
1832                                       toolbar_visible_p[TOP_TOOLBAR]),
1833                          toolbar_geometry_changed_in_window,
1834                          slot_offset (struct frame,
1835                                       toolbar_visible_p[TOP_TOOLBAR]),
1836                          frame_size_slipped);
1837
1838   DEFVAR_SPECIFIER ("bottom-toolbar-visible-p",
1839                     &Vtoolbar_visible_p[BOTTOM_TOOLBAR] /*
1840 *Whether the bottom toolbar is visible.
1841 This is a specifier; use `set-specifier' to change it.
1842
1843 See `default-toolbar-visible-p' for more information.
1844 */ );
1845   Vtoolbar_visible_p[BOTTOM_TOOLBAR] = Fmake_specifier (Qboolean);
1846   set_specifier_caching (Vtoolbar_visible_p[BOTTOM_TOOLBAR],
1847                          slot_offset (struct window,
1848                                       toolbar_visible_p[BOTTOM_TOOLBAR]),
1849                          toolbar_geometry_changed_in_window,
1850                          slot_offset (struct frame,
1851                                       toolbar_visible_p[BOTTOM_TOOLBAR]),
1852                          frame_size_slipped);
1853
1854   DEFVAR_SPECIFIER ("left-toolbar-visible-p",
1855                     &Vtoolbar_visible_p[LEFT_TOOLBAR] /*
1856 *Whether the left toolbar is visible.
1857 This is a specifier; use `set-specifier' to change it.
1858
1859 See `default-toolbar-visible-p' for more information.
1860 */ );
1861   Vtoolbar_visible_p[LEFT_TOOLBAR] = Fmake_specifier (Qboolean);
1862   set_specifier_caching (Vtoolbar_visible_p[LEFT_TOOLBAR],
1863                          slot_offset (struct window,
1864                                       toolbar_visible_p[LEFT_TOOLBAR]),
1865                          toolbar_geometry_changed_in_window,
1866                          slot_offset (struct frame,
1867                                       toolbar_visible_p[LEFT_TOOLBAR]),
1868                          frame_size_slipped);
1869
1870   DEFVAR_SPECIFIER ("right-toolbar-visible-p",
1871                     &Vtoolbar_visible_p[RIGHT_TOOLBAR] /*
1872 *Whether the right toolbar is visible.
1873 This is a specifier; use `set-specifier' to change it.
1874
1875 See `default-toolbar-visible-p' for more information.
1876 */ );
1877   Vtoolbar_visible_p[RIGHT_TOOLBAR] = Fmake_specifier (Qboolean);
1878   set_specifier_caching (Vtoolbar_visible_p[RIGHT_TOOLBAR],
1879                          slot_offset (struct window,
1880                                       toolbar_visible_p[RIGHT_TOOLBAR]),
1881                          toolbar_geometry_changed_in_window,
1882                          slot_offset (struct frame,
1883                                       toolbar_visible_p[RIGHT_TOOLBAR]),
1884                          frame_size_slipped);
1885
1886   /* initially, top inherits from default; this can be
1887      changed with `set-default-toolbar-position'. */
1888   fb = list1 (Fcons (Qnil, Qt));
1889   set_specifier_fallback (Vdefault_toolbar_visible_p, fb);
1890   set_specifier_fallback (Vtoolbar_visible_p[TOP_TOOLBAR],
1891                           Vdefault_toolbar_visible_p);
1892   set_specifier_fallback (Vtoolbar_visible_p[BOTTOM_TOOLBAR], fb);
1893   set_specifier_fallback (Vtoolbar_visible_p[LEFT_TOOLBAR],   fb);
1894   set_specifier_fallback (Vtoolbar_visible_p[RIGHT_TOOLBAR],  fb);
1895
1896   DEFVAR_SPECIFIER ("toolbar-buttons-captioned-p",
1897                     &Vtoolbar_buttons_captioned_p /*
1898 *Whether the toolbar buttons are captioned.
1899 This will only have a visible effect for those toolbar buttons which had
1900 captioned versions specified.
1901 This is a specifier; use `set-specifier' to change it.
1902 */ );
1903   Vtoolbar_buttons_captioned_p = Fmake_specifier (Qboolean);
1904   set_specifier_caching (Vtoolbar_buttons_captioned_p,
1905                          slot_offset (struct window,
1906                                       toolbar_buttons_captioned_p),
1907                          toolbar_buttons_captioned_p_changed,
1908                          0, 0);
1909   set_specifier_fallback (Vtoolbar_buttons_captioned_p,
1910                           list1 (Fcons (Qnil, Qt)));
1911 }