Contents of release-21-2 at 1999-07-02-10.
[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, void (*markobj) (Lisp_Object))
61 {
62   struct toolbar_button *data = XTOOLBAR_BUTTON (obj);
63   markobj (data->next);
64   markobj (data->frame);
65   markobj (data->up_glyph);
66   markobj (data->down_glyph);
67   markobj (data->disabled_glyph);
68   markobj (data->cap_up_glyph);
69   markobj (data->cap_down_glyph);
70   markobj (data->cap_disabled_glyph);
71   markobj (data->callback);
72   markobj (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 specifier_vars_of_toolbar (void)
1316 {
1317   Lisp_Object fb;
1318
1319   DEFVAR_SPECIFIER ("default-toolbar", &Vdefault_toolbar /*
1320 Specifier for a fallback toolbar.
1321 Use `set-specifier' to change this.
1322
1323 The position of this toolbar is specified in the function
1324 `default-toolbar-position'.  If the corresponding position-specific
1325 toolbar (e.g. `top-toolbar' if `default-toolbar-position' is 'top)
1326 does not specify a toolbar in a particular domain (usually a window),
1327 then the value of `default-toolbar' in that domain, if any, will be
1328 used instead.
1329
1330 Note that the toolbar at any particular position will not be
1331 displayed unless its visibility flag is true and its thickness
1332 \(width or height, depending on orientation) is non-zero.  The
1333 visibility is controlled by the specifiers `top-toolbar-visible-p',
1334 `bottom-toolbar-visible-p', `left-toolbar-visible-p', and
1335 `right-toolbar-visible-p', and the thickness is controlled by the
1336 specifiers `top-toolbar-height', `bottom-toolbar-height',
1337 `left-toolbar-width', and `right-toolbar-width'.
1338
1339 Note that one of the four visibility specifiers inherits from
1340 `default-toolbar-visibility' and one of the four thickness
1341 specifiers inherits from either `default-toolbar-width' or
1342 `default-toolbar-height' (depending on orientation), just
1343 like for the toolbar description specifiers (e.g. `top-toolbar')
1344 mentioned above.
1345
1346 Therefore, if you are setting `default-toolbar', you should control
1347 the visibility and thickness using `default-toolbar-visible-p',
1348 `default-toolbar-width', and `default-toolbar-height', rather than
1349 using position-specific specifiers.  That way, you will get sane
1350 behavior if the user changes the default toolbar position.
1351
1352 The format of the instantiator for a toolbar is a list of
1353 toolbar-button-descriptors.  Each toolbar-button-descriptor
1354 is a vector in one of the following formats:
1355
1356   [GLYPH-LIST FUNCTION ENABLED-P HELP] or
1357   [:style 2D-OR-3D] or
1358   [:style 2D-OR-3D :size WIDTH-OR-HEIGHT] or
1359   [:size WIDTH-OR-HEIGHT :style 2D-OR-3D]
1360
1361 Optionally, one of the toolbar-button-descriptors may be nil
1362 instead of a vector; this signifies the division between
1363 the toolbar buttons that are to be displayed flush-left,
1364 and the buttons to be displayed flush-right.
1365
1366 The first vector format above specifies a normal toolbar button;
1367 the others specify blank areas in the toolbar.
1368
1369 For the first vector format:
1370
1371 -- GLYPH-LIST should be a list of one to six glyphs (as created by
1372    `make-glyph') or a symbol whose value is such a list.  The first
1373    glyph, which must be provided, is the glyph used to display the
1374    toolbar button when it is in the "up" (not pressed) state.  The
1375    optional second glyph is for displaying the button when it is in
1376    the "down" (pressed) state.  The optional third glyph is for when
1377    the button is disabled.  The optional fourth, fifth and sixth glyphs
1378    are used to specify captioned versions for the up, down and disabled
1379    states respectively.  The function `toolbar-make-button-list' is
1380    useful in creating these glyph lists.  The specifier variable
1381    `toolbar-buttons-captioned-p' controls which glyphs are actually used.
1382
1383 -- Even if you do not provide separate down-state and disabled-state
1384    glyphs, the user will still get visual feedback to indicate which
1385    state the button is in.  Buttons in the up-state are displayed
1386    with a shadowed border that gives a raised appearance to the
1387    button.  Buttons in the down-state are displayed with shadows that
1388    give a recessed appearance.  Buttons in the disabled state are
1389    displayed with no shadows, giving a 2-d effect.
1390
1391 -- If some of the toolbar glyphs are not provided, they inherit as follows:
1392
1393      UP:                up
1394      DOWN:              down -> up
1395      DISABLED:          disabled -> up
1396      CAP-UP:            cap-up -> up
1397      CAP-DOWN:          cap-down -> cap-up -> down -> up
1398      CAP-DISABLED:      cap-disabled -> cap-up -> disabled -> up
1399
1400 -- The second element FUNCTION is a function to be called when the
1401    toolbar button is activated (i.e. when the mouse is released over
1402    the toolbar button, if the press occurred in the toolbar).  It
1403    can be any form accepted by `call-interactively', since this is
1404    how it is invoked.
1405
1406 -- The third element ENABLED-P specifies whether the toolbar button
1407    is enabled (disabled buttons do nothing when they are activated,
1408    and are displayed differently; see above).  It should be either
1409    a boolean or a form that evaluates to a boolean.
1410
1411 -- The fourth element HELP, if non-nil, should be a string.  This
1412    string is displayed in the echo area when the mouse passes over
1413    the toolbar button.
1414
1415 For the other vector formats (specifying blank areas of the toolbar):
1416
1417 -- 2D-OR-3D should be one of the symbols '2d or '3d, indicating
1418    whether the area is displayed with shadows (giving it a raised,
1419    3-d appearance) or without shadows (giving it a flat appearance).
1420
1421 -- WIDTH-OR-HEIGHT specifies the length, in pixels, of the blank
1422    area.  If omitted, it defaults to a device-specific value
1423    (8 pixels for X devices).
1424 */ );
1425
1426   Vdefault_toolbar = Fmake_specifier (Qtoolbar);
1427   /* #### It would be even nicer if the specifier caching
1428      automatically knew about specifier fallbacks, so we didn't
1429      have to do it ourselves. */
1430   set_specifier_caching (Vdefault_toolbar,
1431                          slot_offset (struct window,
1432                                       default_toolbar),
1433                          default_toolbar_specs_changed,
1434                          0, 0);
1435
1436   DEFVAR_SPECIFIER ("top-toolbar",
1437                     &Vtoolbar[TOP_TOOLBAR] /*
1438 Specifier for the toolbar at the top of the frame.
1439 Use `set-specifier' to change this.
1440 See `default-toolbar' for a description of a valid toolbar instantiator.
1441 */ );
1442   Vtoolbar[TOP_TOOLBAR] = Fmake_specifier (Qtoolbar);
1443   set_specifier_caching (Vtoolbar[TOP_TOOLBAR],
1444                          slot_offset (struct window,
1445                                       toolbar[TOP_TOOLBAR]),
1446                          toolbar_specs_changed,
1447                          0, 0);
1448
1449   DEFVAR_SPECIFIER ("bottom-toolbar",
1450                     &Vtoolbar[BOTTOM_TOOLBAR] /*
1451 Specifier for the toolbar at the bottom of the frame.
1452 Use `set-specifier' to change this.
1453 See `default-toolbar' for a description of a valid toolbar instantiator.
1454
1455 Note that, unless the `default-toolbar-position' is `bottom', by
1456 default the height of the bottom toolbar (controlled by
1457 `bottom-toolbar-height') is 0; thus, a bottom toolbar will not be
1458 displayed even if you provide a value for `bottom-toolbar'.
1459 */ );
1460   Vtoolbar[BOTTOM_TOOLBAR] = Fmake_specifier (Qtoolbar);
1461   set_specifier_caching (Vtoolbar[BOTTOM_TOOLBAR],
1462                          slot_offset (struct window,
1463                                       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                          slot_offset (struct window,
1481                                       toolbar[LEFT_TOOLBAR]),
1482                          toolbar_specs_changed,
1483                          0, 0);
1484
1485   DEFVAR_SPECIFIER ("right-toolbar",
1486                     &Vtoolbar[RIGHT_TOOLBAR] /*
1487 Specifier for the toolbar at the right edge of the frame.
1488 Use `set-specifier' to change this.
1489 See `default-toolbar' for a description of a valid toolbar instantiator.
1490
1491 Note that, unless the `default-toolbar-position' is `right', by
1492 default the height of the right toolbar (controlled by
1493 `right-toolbar-width') is 0; thus, a right toolbar will not be
1494 displayed even if you provide a value for `right-toolbar'.
1495 */ );
1496   Vtoolbar[RIGHT_TOOLBAR] = Fmake_specifier (Qtoolbar);
1497   set_specifier_caching (Vtoolbar[RIGHT_TOOLBAR],
1498                          slot_offset (struct window,
1499                                       toolbar[RIGHT_TOOLBAR]),
1500                          toolbar_specs_changed,
1501                          0, 0);
1502
1503   /* initially, top inherits from default; this can be
1504      changed with `set-default-toolbar-position'. */
1505   fb = list1 (Fcons (Qnil, Qnil));
1506   set_specifier_fallback (Vdefault_toolbar, fb);
1507   set_specifier_fallback (Vtoolbar[TOP_TOOLBAR], Vdefault_toolbar);
1508   set_specifier_fallback (Vtoolbar[BOTTOM_TOOLBAR], fb);
1509   set_specifier_fallback (Vtoolbar[LEFT_TOOLBAR],   fb);
1510   set_specifier_fallback (Vtoolbar[RIGHT_TOOLBAR],  fb);
1511
1512   DEFVAR_SPECIFIER ("default-toolbar-height", &Vdefault_toolbar_height /*
1513 *Height of the default toolbar, if it's oriented horizontally.
1514 This is a specifier; use `set-specifier' to change it.
1515
1516 The position of the default toolbar is specified by the function
1517 `set-default-toolbar-position'.  If the corresponding position-specific
1518 toolbar thickness specifier (e.g. `top-toolbar-height' if
1519 `default-toolbar-position' is 'top) does not specify a thickness in a
1520 particular domain (a window or a frame), then the value of
1521 `default-toolbar-height' or `default-toolbar-width' (depending on the
1522 toolbar orientation) in that domain, if any, will be used instead.
1523
1524 Note that `default-toolbar-height' is only used when
1525 `default-toolbar-position' is 'top or 'bottom, and `default-toolbar-width'
1526 is only used when `default-toolbar-position' is 'left or 'right.
1527
1528 Note that all of the position-specific toolbar thickness specifiers
1529 have a fallback value of zero when they do not correspond to the
1530 default toolbar.  Therefore, you will have to set a non-zero thickness
1531 value if you want a position-specific toolbar to be displayed.
1532
1533 Internally, toolbar thickness specifiers are instantiated in both
1534 window and frame domains, for different purposes.  The value in the
1535 domain of a frame's selected window specifies the actual toolbar
1536 thickness that you will see in that frame.  The value in the domain of
1537 a frame itself specifies the toolbar thickness that is used in frame
1538 geometry calculations.
1539
1540 Thus, for example, if you set the frame width to 80 characters and the
1541 left toolbar width for that frame to 68 pixels, then the frame will
1542 be sized to fit 80 characters plus a 68-pixel left toolbar.  If you
1543 then set the left toolbar width to 0 for a particular buffer (or if
1544 that buffer does not specify a left toolbar or has a nil value
1545 specified for `left-toolbar-visible-p'), you will find that, when
1546 that buffer is displayed in the selected window, the window will have
1547 a width of 86 or 87 characters -- the frame is sized for a 68-pixel
1548 left toolbar but the selected window specifies that the left toolbar
1549 is not visible, so it is expanded to take up the slack.
1550 */ );
1551   Vdefault_toolbar_height = Fmake_specifier (Qnatnum);
1552   set_specifier_caching (Vdefault_toolbar_height,
1553                          slot_offset (struct window,
1554                                       default_toolbar_height),
1555                          default_toolbar_size_changed_in_window,
1556                          slot_offset (struct frame,
1557                                       default_toolbar_height),
1558                          default_toolbar_size_changed_in_frame);
1559
1560   DEFVAR_SPECIFIER ("default-toolbar-width", &Vdefault_toolbar_width /*
1561 *Width of the default toolbar, if it's oriented vertically.
1562 This is a specifier; use `set-specifier' to change it.
1563
1564 See `default-toolbar-height' for more information.
1565 */ );
1566   Vdefault_toolbar_width = Fmake_specifier (Qnatnum);
1567   set_specifier_caching (Vdefault_toolbar_width,
1568                          slot_offset (struct window,
1569                                       default_toolbar_width),
1570                          default_toolbar_size_changed_in_window,
1571                          slot_offset (struct frame,
1572                                       default_toolbar_width),
1573                          default_toolbar_size_changed_in_frame);
1574
1575   DEFVAR_SPECIFIER ("top-toolbar-height",
1576                     &Vtoolbar_size[TOP_TOOLBAR] /*
1577 *Height of the top toolbar.
1578 This is a specifier; use `set-specifier' to change it.
1579
1580 See `default-toolbar-height' for more information.
1581 */ );
1582   Vtoolbar_size[TOP_TOOLBAR] = Fmake_specifier (Qnatnum);
1583   set_specifier_caching (Vtoolbar_size[TOP_TOOLBAR],
1584                          slot_offset (struct window,
1585                                       toolbar_size[TOP_TOOLBAR]),
1586                          toolbar_geometry_changed_in_window,
1587                          slot_offset (struct frame,
1588                                       toolbar_size[TOP_TOOLBAR]),
1589                          frame_size_slipped);
1590
1591   DEFVAR_SPECIFIER ("bottom-toolbar-height",
1592                     &Vtoolbar_size[BOTTOM_TOOLBAR] /*
1593 *Height of the bottom toolbar.
1594 This is a specifier; use `set-specifier' to change it.
1595
1596 See `default-toolbar-height' for more information.
1597 */ );
1598   Vtoolbar_size[BOTTOM_TOOLBAR] = Fmake_specifier (Qnatnum);
1599   set_specifier_caching (Vtoolbar_size[BOTTOM_TOOLBAR],
1600                          slot_offset (struct window,
1601                                       toolbar_size[BOTTOM_TOOLBAR]),
1602                          toolbar_geometry_changed_in_window,
1603                          slot_offset (struct frame,
1604                                       toolbar_size[BOTTOM_TOOLBAR]),
1605                          frame_size_slipped);
1606
1607   DEFVAR_SPECIFIER ("left-toolbar-width",
1608                     &Vtoolbar_size[LEFT_TOOLBAR] /*
1609 *Width of left toolbar.
1610 This is a specifier; use `set-specifier' to change it.
1611
1612 See `default-toolbar-height' for more information.
1613 */ );
1614   Vtoolbar_size[LEFT_TOOLBAR] = Fmake_specifier (Qnatnum);
1615   set_specifier_caching (Vtoolbar_size[LEFT_TOOLBAR],
1616                          slot_offset (struct window,
1617                                       toolbar_size[LEFT_TOOLBAR]),
1618                          toolbar_geometry_changed_in_window,
1619                          slot_offset (struct frame,
1620                                       toolbar_size[LEFT_TOOLBAR]),
1621                          frame_size_slipped);
1622
1623   DEFVAR_SPECIFIER ("right-toolbar-width",
1624                     &Vtoolbar_size[RIGHT_TOOLBAR] /*
1625 *Width of right toolbar.
1626 This is a specifier; use `set-specifier' to change it.
1627
1628 See `default-toolbar-height' for more information.
1629 */ );
1630   Vtoolbar_size[RIGHT_TOOLBAR] = Fmake_specifier (Qnatnum);
1631   set_specifier_caching (Vtoolbar_size[RIGHT_TOOLBAR],
1632                          slot_offset (struct window,
1633                                       toolbar_size[RIGHT_TOOLBAR]),
1634                          toolbar_geometry_changed_in_window,
1635                          slot_offset (struct frame,
1636                                       toolbar_size[RIGHT_TOOLBAR]),
1637                          frame_size_slipped);
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_HEIGHT)), fb);
1645 #endif
1646 #ifdef HAVE_MS_WINDOWS
1647   fb = Fcons (Fcons (list1 (Qmswindows), 
1648                      make_int (MSWINDOWS_DEFAULT_TOOLBAR_HEIGHT)), fb);
1649 #endif
1650   if (!NILP (fb))
1651     set_specifier_fallback (Vdefault_toolbar_height, fb);
1652
1653   fb = Qnil;
1654 #ifdef HAVE_TTY
1655   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1656 #endif
1657 #ifdef HAVE_X_WINDOWS
1658   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_WIDTH)), fb);
1659 #endif
1660 #ifdef HAVE_MS_WINDOWS
1661   fb = Fcons (Fcons (list1 (Qmswindows), 
1662                      make_int (MSWINDOWS_DEFAULT_TOOLBAR_WIDTH)), fb);
1663 #endif
1664   if (!NILP (fb))
1665     set_specifier_fallback (Vdefault_toolbar_width, fb);
1666
1667   set_specifier_fallback (Vtoolbar_size[TOP_TOOLBAR], Vdefault_toolbar_height);
1668   fb = list1 (Fcons (Qnil, Qzero));
1669   set_specifier_fallback (Vtoolbar_size[BOTTOM_TOOLBAR], fb);
1670   set_specifier_fallback (Vtoolbar_size[LEFT_TOOLBAR],   fb);
1671   set_specifier_fallback (Vtoolbar_size[RIGHT_TOOLBAR],  fb);
1672
1673   DEFVAR_SPECIFIER ("default-toolbar-border-width",
1674                     &Vdefault_toolbar_border_width /*
1675 *Width of the border around the default toolbar.
1676 This is a specifier; use `set-specifier' to change it.
1677
1678 The position of the default toolbar is specified by the function
1679 `set-default-toolbar-position'.  If the corresponding position-specific
1680 toolbar border width specifier (e.g. `top-toolbar-border-width' if
1681 `default-toolbar-position' is 'top) does not specify a border width in a
1682 particular domain (a window or a frame), then the value of
1683 `default-toolbar-border-width' in that domain, if any, will be used
1684 instead.
1685
1686 Internally, toolbar border width specifiers are instantiated in both
1687 window and frame domains, for different purposes.  The value in the
1688 domain of a frame's selected window specifies the actual toolbar border
1689 width that you will see in that frame.  The value in the domain of a
1690 frame itself specifies the toolbar border width that is used in frame
1691 geometry calculations.  Changing the border width value in the frame
1692 domain will result in a size change in the frame itself, while changing
1693 the value in a window domain will not.
1694 */ );
1695   Vdefault_toolbar_border_width = Fmake_specifier (Qnatnum);
1696   set_specifier_caching (Vdefault_toolbar_border_width,
1697                          slot_offset (struct window,
1698                                       default_toolbar_border_width),
1699                          default_toolbar_border_width_changed_in_window,
1700                          slot_offset (struct frame,
1701                                       default_toolbar_border_width),
1702                          default_toolbar_border_width_changed_in_frame);
1703
1704   DEFVAR_SPECIFIER ("top-toolbar-border-width",
1705                     &Vtoolbar_border_width[TOP_TOOLBAR] /*
1706 *Border width of the top 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[TOP_TOOLBAR] = Fmake_specifier (Qnatnum);
1712   set_specifier_caching (Vtoolbar_border_width[TOP_TOOLBAR],
1713                          slot_offset (struct window,
1714                                       toolbar_border_width[TOP_TOOLBAR]),
1715                          toolbar_geometry_changed_in_window,
1716                          slot_offset (struct frame,
1717                                       toolbar_border_width[TOP_TOOLBAR]),
1718                          frame_size_slipped);
1719
1720   DEFVAR_SPECIFIER ("bottom-toolbar-border-width",
1721                     &Vtoolbar_border_width[BOTTOM_TOOLBAR] /*
1722 *Border width of the bottom 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[BOTTOM_TOOLBAR] = Fmake_specifier (Qnatnum);
1728   set_specifier_caching (Vtoolbar_border_width[BOTTOM_TOOLBAR],
1729                          slot_offset (struct window,
1730                                       toolbar_border_width[BOTTOM_TOOLBAR]),
1731                          toolbar_geometry_changed_in_window,
1732                          slot_offset (struct frame,
1733                                       toolbar_border_width[BOTTOM_TOOLBAR]),
1734                          frame_size_slipped);
1735
1736   DEFVAR_SPECIFIER ("left-toolbar-border-width",
1737                     &Vtoolbar_border_width[LEFT_TOOLBAR] /*
1738 *Border width of left 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[LEFT_TOOLBAR] = Fmake_specifier (Qnatnum);
1744   set_specifier_caching (Vtoolbar_border_width[LEFT_TOOLBAR],
1745                          slot_offset (struct window,
1746                                       toolbar_border_width[LEFT_TOOLBAR]),
1747                          toolbar_geometry_changed_in_window,
1748                          slot_offset (struct frame,
1749                                       toolbar_border_width[LEFT_TOOLBAR]),
1750                          frame_size_slipped);
1751
1752   DEFVAR_SPECIFIER ("right-toolbar-border-width",
1753                     &Vtoolbar_border_width[RIGHT_TOOLBAR] /*
1754 *Border width of right toolbar.
1755 This is a specifier; use `set-specifier' to change it.
1756
1757 See `default-toolbar-height' for more information.
1758 */ );
1759   Vtoolbar_border_width[RIGHT_TOOLBAR] = Fmake_specifier (Qnatnum);
1760   set_specifier_caching (Vtoolbar_border_width[RIGHT_TOOLBAR],
1761                          slot_offset (struct window,
1762                                       toolbar_border_width[RIGHT_TOOLBAR]),
1763                          toolbar_geometry_changed_in_window,
1764                          slot_offset (struct frame,
1765                                       toolbar_border_width[RIGHT_TOOLBAR]),
1766                          frame_size_slipped);
1767
1768   fb = Qnil;
1769 #ifdef HAVE_TTY
1770   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1771 #endif
1772 #ifdef HAVE_X_WINDOWS
1773   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_BORDER_WIDTH)), fb);
1774 #endif
1775 #ifdef HAVE_MS_WINDOWS
1776   fb = Fcons (Fcons (list1 (Qmswindows), make_int (MSWINDOWS_DEFAULT_TOOLBAR_BORDER_WIDTH)), fb);
1777 #endif
1778   if (!NILP (fb))
1779     set_specifier_fallback (Vdefault_toolbar_border_width, fb);
1780
1781   set_specifier_fallback (Vtoolbar_border_width[TOP_TOOLBAR], Vdefault_toolbar_border_width);
1782   fb = list1 (Fcons (Qnil, Qzero));
1783   set_specifier_fallback (Vtoolbar_border_width[BOTTOM_TOOLBAR], fb);
1784   set_specifier_fallback (Vtoolbar_border_width[LEFT_TOOLBAR],   fb);
1785   set_specifier_fallback (Vtoolbar_border_width[RIGHT_TOOLBAR],  fb);
1786
1787   DEFVAR_SPECIFIER ("default-toolbar-visible-p", &Vdefault_toolbar_visible_p /*
1788 *Whether the default toolbar is visible.
1789 This is a specifier; use `set-specifier' to change it.
1790
1791 The position of the default toolbar is specified by the function
1792 `set-default-toolbar-position'.  If the corresponding position-specific
1793 toolbar visibility specifier (e.g. `top-toolbar-visible-p' if
1794 `default-toolbar-position' is 'top) does not specify a visible-p value
1795 in a particular domain (a window or a frame), then the value of
1796 `default-toolbar-visible-p' in that domain, if any, will be used
1797 instead.
1798
1799 Both window domains and frame domains are used internally, for
1800 different purposes.  The distinction here is exactly the same as
1801 for thickness specifiers; see `default-toolbar-height' for more
1802 information.
1803
1804 `default-toolbar-visible-p' and all of the position-specific toolbar
1805 visibility specifiers have a fallback value of true.
1806 */ );
1807   Vdefault_toolbar_visible_p = Fmake_specifier (Qboolean);
1808   set_specifier_caching (Vdefault_toolbar_visible_p,
1809                          slot_offset (struct window,
1810                                       default_toolbar_visible_p),
1811                          default_toolbar_visible_p_changed_in_window,
1812                          slot_offset (struct frame,
1813                                       default_toolbar_visible_p),
1814                          default_toolbar_visible_p_changed_in_frame);
1815
1816   DEFVAR_SPECIFIER ("top-toolbar-visible-p",
1817                     &Vtoolbar_visible_p[TOP_TOOLBAR] /*
1818 *Whether the top toolbar is visible.
1819 This is a specifier; use `set-specifier' to change it.
1820
1821 See `default-toolbar-visible-p' for more information.
1822 */ );
1823   Vtoolbar_visible_p[TOP_TOOLBAR] = Fmake_specifier (Qboolean);
1824   set_specifier_caching (Vtoolbar_visible_p[TOP_TOOLBAR],
1825                          slot_offset (struct window,
1826                                       toolbar_visible_p[TOP_TOOLBAR]),
1827                          toolbar_geometry_changed_in_window,
1828                          slot_offset (struct frame,
1829                                       toolbar_visible_p[TOP_TOOLBAR]),
1830                          frame_size_slipped);
1831
1832   DEFVAR_SPECIFIER ("bottom-toolbar-visible-p",
1833                     &Vtoolbar_visible_p[BOTTOM_TOOLBAR] /*
1834 *Whether the bottom toolbar is visible.
1835 This is a specifier; use `set-specifier' to change it.
1836
1837 See `default-toolbar-visible-p' for more information.
1838 */ );
1839   Vtoolbar_visible_p[BOTTOM_TOOLBAR] = Fmake_specifier (Qboolean);
1840   set_specifier_caching (Vtoolbar_visible_p[BOTTOM_TOOLBAR],
1841                          slot_offset (struct window,
1842                                       toolbar_visible_p[BOTTOM_TOOLBAR]),
1843                          toolbar_geometry_changed_in_window,
1844                          slot_offset (struct frame,
1845                                       toolbar_visible_p[BOTTOM_TOOLBAR]),
1846                          frame_size_slipped);
1847
1848   DEFVAR_SPECIFIER ("left-toolbar-visible-p",
1849                     &Vtoolbar_visible_p[LEFT_TOOLBAR] /*
1850 *Whether the left toolbar is visible.
1851 This is a specifier; use `set-specifier' to change it.
1852
1853 See `default-toolbar-visible-p' for more information.
1854 */ );
1855   Vtoolbar_visible_p[LEFT_TOOLBAR] = Fmake_specifier (Qboolean);
1856   set_specifier_caching (Vtoolbar_visible_p[LEFT_TOOLBAR],
1857                          slot_offset (struct window,
1858                                       toolbar_visible_p[LEFT_TOOLBAR]),
1859                          toolbar_geometry_changed_in_window,
1860                          slot_offset (struct frame,
1861                                       toolbar_visible_p[LEFT_TOOLBAR]),
1862                          frame_size_slipped);
1863
1864   DEFVAR_SPECIFIER ("right-toolbar-visible-p",
1865                     &Vtoolbar_visible_p[RIGHT_TOOLBAR] /*
1866 *Whether the right toolbar is visible.
1867 This is a specifier; use `set-specifier' to change it.
1868
1869 See `default-toolbar-visible-p' for more information.
1870 */ );
1871   Vtoolbar_visible_p[RIGHT_TOOLBAR] = Fmake_specifier (Qboolean);
1872   set_specifier_caching (Vtoolbar_visible_p[RIGHT_TOOLBAR],
1873                          slot_offset (struct window,
1874                                       toolbar_visible_p[RIGHT_TOOLBAR]),
1875                          toolbar_geometry_changed_in_window,
1876                          slot_offset (struct frame,
1877                                       toolbar_visible_p[RIGHT_TOOLBAR]),
1878                          frame_size_slipped);
1879
1880   /* initially, top inherits from default; this can be
1881      changed with `set-default-toolbar-position'. */
1882   fb = list1 (Fcons (Qnil, Qt));
1883   set_specifier_fallback (Vdefault_toolbar_visible_p, fb);
1884   set_specifier_fallback (Vtoolbar_visible_p[TOP_TOOLBAR],
1885                           Vdefault_toolbar_visible_p);
1886   set_specifier_fallback (Vtoolbar_visible_p[BOTTOM_TOOLBAR], fb);
1887   set_specifier_fallback (Vtoolbar_visible_p[LEFT_TOOLBAR],   fb);
1888   set_specifier_fallback (Vtoolbar_visible_p[RIGHT_TOOLBAR],  fb);
1889
1890   DEFVAR_SPECIFIER ("toolbar-buttons-captioned-p",
1891                     &Vtoolbar_buttons_captioned_p /*
1892 *Whether the toolbar buttons are captioned.
1893 This will only have a visible effect for those toolbar buttons which had
1894 captioned versions specified.
1895 This is a specifier; use `set-specifier' to change it.
1896 */ );
1897   Vtoolbar_buttons_captioned_p = Fmake_specifier (Qboolean);
1898   set_specifier_caching (Vtoolbar_buttons_captioned_p,
1899                          slot_offset (struct window,
1900                                       toolbar_buttons_captioned_p),
1901                          toolbar_buttons_captioned_p_changed,
1902                          0, 0);
1903   set_specifier_fallback (Vtoolbar_buttons_captioned_p,
1904                           list1 (Fcons (Qnil, Qt)));
1905 }