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