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