XEmacs 21.4.9 "Informed Management".
[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 /* Update the toolbar geometry separately from actually displaying the
716    toolbar. This is necessary because both the gutter and the toolbar
717    are competing for redisplay cycles and, unfortunately, gutter
718    updates happen late in the game. Firstly they are done inside of
719    redisplay proper and secondly subcontrols may not get moved until
720    the next screen refresh. Only after subcontrols have been moved to
721    their final destinations can we be certain of updating the
722    toolbar. Under X this probably is exacerbated by the toolbar button
723    dirty flags which prevent updates happening when they possibly
724    should. */
725 void
726 update_frame_toolbars_geometry (struct frame *f)
727 {
728   struct device *d = XDEVICE (f->device);
729
730   if (DEVICE_SUPPORTS_TOOLBARS_P (d)
731       && (f->toolbar_changed 
732           || f->frame_layout_changed
733           || f->frame_changed
734           || f->clear))
735     {
736       int pos;
737
738       /* We're not officially "in redisplay", so we still have a
739          chance to re-layout toolbars and windows. This is done here,
740          because toolbar is the only thing which currently might
741          necessitate this layout, as it is outside any windows. We
742          take care not to change size if toolbar geometry is really
743          unchanged, as it will hose windows whose pixsizes are not
744          multiple of character sizes. */
745
746       for (pos = 0; pos < 4; pos++)
747         if (FRAME_REAL_TOOLBAR_SIZE (f, pos)
748             != FRAME_CURRENT_TOOLBAR_SIZE (f, pos))
749           {
750             int width, height;
751             pixel_to_char_size (f, FRAME_PIXWIDTH (f), FRAME_PIXHEIGHT (f),
752                                 &width, &height);
753             change_frame_size (f, height, width, 0);
754             MARK_FRAME_LAYOUT_CHANGED (f);
755             break;
756           }
757
758       for (pos = 0; pos < 4; pos++) {
759         f->current_toolbar_size[pos] = FRAME_REAL_TOOLBAR_SIZE (f, pos);
760       }
761
762       /* Removed the check for the minibuffer here.  We handle this
763          more correctly now by consistently using
764          FRAME_LAST_NONMINIBUF_WINDOW instead of FRAME_SELECTED_WINDOW
765          throughout the toolbar code. */
766       compute_frame_toolbars_data (f);
767       
768       /* Clear the previous toolbar locations. If we do it later
769          (after redisplay) we end up clearing what we have just
770          displayed. */
771       MAYBE_DEVMETH (d, clear_frame_toolbars, (f));
772     }
773 }
774
775 /* Actually redisplay the toolbar buttons. */
776 void
777 update_frame_toolbars (struct frame *f)
778 {
779   struct device *d = XDEVICE (f->device);
780
781   if (DEVICE_SUPPORTS_TOOLBARS_P (d)
782       && (f->toolbar_changed 
783           || f->frame_layout_changed
784           || f->frame_changed 
785           || f->clear))
786     {
787       DEVMETH (d, output_frame_toolbars, (f));
788     }
789
790   f->toolbar_changed = 0;
791 }
792
793 void
794 init_frame_toolbars (struct frame *f)
795 {
796   struct device *d = XDEVICE (f->device);
797
798   if (DEVICE_SUPPORTS_TOOLBARS_P (d))
799     {
800       Lisp_Object frame;
801       int pos;
802
803       compute_frame_toolbars_data (f);
804       XSETFRAME (frame, f);
805       call_critical_lisp_code (XDEVICE (FRAME_DEVICE (f)),
806                                Qinit_toolbar_from_resources,
807                                frame);
808       MAYBE_DEVMETH (d, initialize_frame_toolbars, (f));
809
810       /* We are here as far in frame creation so cached specifiers are
811          already recomputed, and possibly modified by resource
812          initialization. Remember current toolbar geometry so next
813          redisplay will not needlessly relayout toolbars. */
814       for (pos = 0; pos < 4; pos++)
815         f->current_toolbar_size[pos] = FRAME_REAL_TOOLBAR_SIZE (f, pos);
816     }
817 }
818
819 void
820 init_device_toolbars (struct device *d)
821 {
822   Lisp_Object device;
823
824   XSETDEVICE (device, d);
825   if (DEVICE_SUPPORTS_TOOLBARS_P (d))
826     call_critical_lisp_code (d,
827                              Qinit_toolbar_from_resources,
828                              device);
829 }
830
831 void
832 init_global_toolbars (struct device *d)
833 {
834   if (DEVICE_SUPPORTS_TOOLBARS_P (d))
835     call_critical_lisp_code (d,
836                              Qinit_toolbar_from_resources,
837                              Qglobal);
838 }
839
840 void
841 free_frame_toolbars (struct frame *f)
842 {
843   /* If we had directly allocated any memory for the toolbars instead
844      of using all Lisp_Objects this is where we would now free it. */
845
846   MAYBE_FRAMEMETH (f, free_frame_toolbars, (f));
847 }
848
849 void
850 get_toolbar_coords (struct frame *f, enum toolbar_pos pos, int *x, int *y,
851                     int *width, int *height, int *vert, int for_layout)
852 {
853   int visible_top_toolbar_height, visible_bottom_toolbar_height;
854   int adjust = (for_layout ? 1 : 0);
855
856   /* The top and bottom toolbars take precedence over the left and
857      right. */
858   visible_top_toolbar_height = (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f)
859                                 ? FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) +
860                                   2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f)
861                                 : 0);
862   visible_bottom_toolbar_height = (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f)
863                                 ? FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) +
864                                   2 *
865                                    FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)
866                                 : 0);
867
868   /* We adjust the width and height by one to give us a narrow border
869      at the outside edges.  However, when we are simply determining
870      toolbar location we don't want to do that. */
871
872   switch (pos)
873     {
874     case TOP_TOOLBAR:
875       *x = 1;
876       *y = 0;   /* #### should be 1 if no menubar */
877       *width = FRAME_PIXWIDTH (f) - 2;
878       *height = FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) +
879         2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) - adjust;
880       *vert = 0;
881       break;
882     case BOTTOM_TOOLBAR:
883       *x = 1;
884       *y = FRAME_PIXHEIGHT (f) - FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
885         2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f);
886       *width = FRAME_PIXWIDTH (f) - 2;
887       *height = FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) +
888         2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f) - adjust;
889       *vert = 0;
890       break;
891     case LEFT_TOOLBAR:
892       *x = 1;
893       *y = visible_top_toolbar_height;
894       *width = FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) +
895         2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) - adjust;
896       *height = (FRAME_PIXHEIGHT (f) - visible_top_toolbar_height -
897                  visible_bottom_toolbar_height - 1);
898       *vert = 1;
899       break;
900     case RIGHT_TOOLBAR:
901       *x = FRAME_PIXWIDTH (f) - FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
902         2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f);
903       *y = visible_top_toolbar_height;
904       *width = FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) +
905         2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f) - adjust;
906       *height = (FRAME_PIXHEIGHT (f) - visible_top_toolbar_height -
907                  visible_bottom_toolbar_height);
908       *vert = 1;
909       break;
910     default:
911       abort ();
912     }
913 }
914
915 #define CHECK_TOOLBAR(pos) do {                                         \
916   if (FRAME_REAL_##pos##_VISIBLE (f))                                   \
917     {                                                                   \
918       int x, y, width, height, vert;                                    \
919                                                                         \
920       get_toolbar_coords (f, pos, &x, &y, &width, &height, &vert, 0);   \
921       if ((x_coord >= x) && (x_coord < (x + width)))                    \
922         {                                                               \
923           if ((y_coord >= y) && (y_coord < (y + height)))               \
924             return FRAME_TOOLBAR_BUTTONS (f, pos);                      \
925         }                                                               \
926     }                                                                   \
927 } while (0)
928
929 static Lisp_Object
930 toolbar_buttons_at_pixpos (struct frame *f, int x_coord, int y_coord)
931 {
932   CHECK_TOOLBAR (TOP_TOOLBAR);
933   CHECK_TOOLBAR (BOTTOM_TOOLBAR);
934   CHECK_TOOLBAR (LEFT_TOOLBAR);
935   CHECK_TOOLBAR (RIGHT_TOOLBAR);
936
937   return Qnil;
938 }
939 #undef CHECK_TOOLBAR
940
941 /* The device dependent code actually does the work of positioning the
942    buttons, but we are free to access that information at this
943    level. */
944 Lisp_Object
945 toolbar_button_at_pixpos (struct frame *f, int x_coord, int y_coord)
946 {
947   Lisp_Object buttons = toolbar_buttons_at_pixpos (f, x_coord, y_coord);
948
949   while (!NILP (buttons))
950     {
951       struct toolbar_button *tb = XTOOLBAR_BUTTON (buttons);
952
953       if ((x_coord >= tb->x) && (x_coord < (tb->x + tb->width)))
954         {
955           if ((y_coord >= tb->y) && (y_coord < (tb->y + tb->height)))
956             {
957               /* If we are over a blank, return nil. */
958               if (tb->blank)
959                 return Qnil;
960               else
961                 return buttons;
962             }
963         }
964
965       buttons = tb->next;
966     }
967
968   /* We are not over a toolbar or we are over a blank in the toolbar. */
969   return Qnil;
970 }
971
972 \f
973 /************************************************************************/
974 /*                        Toolbar specifier type                        */
975 /************************************************************************/
976
977 DEFINE_SPECIFIER_TYPE (toolbar);
978
979 #define CTB_ERROR(msg) do {                                     \
980   maybe_signal_simple_error (msg, button, Qtoolbar, errb);      \
981   RETURN_SANS_WARNINGS Qnil;                                    \
982 } while (0)
983
984 /* Returns Q_style if key was :style, Qt if ok otherwise, Qnil if error. */
985 static Lisp_Object
986 check_toolbar_button_keywords (Lisp_Object button, Lisp_Object key,
987                                Lisp_Object val, Error_behavior errb)
988 {
989   if (!KEYWORDP (key))
990     {
991       maybe_signal_simple_error_2 ("Not a keyword", key, button, Qtoolbar,
992                                    errb);
993       return Qnil;
994     }
995
996   if (EQ (key, Q_style))
997     {
998       if (!EQ (val, Q2D)
999           && !EQ (val, Q3D)
1000           && !EQ (val, Q2d)
1001           && !EQ (val, Q3d))
1002         CTB_ERROR ("Unrecognized toolbar blank style");
1003
1004       return Q_style;
1005     }
1006   else if (EQ (key, Q_size))
1007     {
1008       if (!NATNUMP (val))
1009         CTB_ERROR ("invalid toolbar blank size");
1010     }
1011   else
1012     {
1013       CTB_ERROR ("invalid toolbar blank keyword");
1014     }
1015
1016   return Qt;
1017 }
1018
1019 /* toolbar button spec is [pixmap-pair function enabled-p help]
1020                        or [:style 2d-or-3d :size width-or-height] */
1021
1022 DEFUN ("check-toolbar-button-syntax", Fcheck_toolbar_button_syntax, 1, 2, 0, /*
1023 Verify the syntax of entry BUTTON in a toolbar description list.
1024 If you want to verify the syntax of a toolbar description list as a
1025 whole, use `check-valid-instantiator' with a specifier type of 'toolbar.
1026 */
1027        (button, noerror))
1028 {
1029   Lisp_Object *elt, glyphs, value;
1030   int len;
1031   Error_behavior errb = decode_error_behavior_flag (noerror);
1032
1033   if (!VECTORP (button))
1034     CTB_ERROR ("toolbar button descriptors must be vectors");
1035   elt = XVECTOR_DATA (button);
1036
1037   if (XVECTOR_LENGTH (button) == 2)
1038     {
1039       if (!EQ (Q_style, check_toolbar_button_keywords (button, elt[0],
1040                                                        elt[1], errb)))
1041         CTB_ERROR ("must specify toolbar blank style");
1042
1043       return Qt;
1044     }
1045
1046   if (XVECTOR_LENGTH (button) != 4)
1047     CTB_ERROR ("toolbar button descriptors must be 2 or 4 long");
1048
1049   /* The first element must be a list of glyphs of length 1-6.  The
1050      first entry is the pixmap for the up state, the second for the
1051      down state, the third for the disabled state, the fourth for the
1052      captioned up state, the fifth for the captioned down state and
1053      the sixth for the captioned disabled state.  Only the up state is
1054      mandatory. */
1055   if (!CONSP (elt[0]))
1056     {
1057       /* We can't check the buffer-local here because we don't know
1058          which buffer to check in.  #### I think this is a bad thing.
1059          See if we can't get enough information to this function so
1060          that it can check.
1061
1062          #### Wrong.  We shouldn't be checking the value at all here.
1063          The user might set or change the value at any time. */
1064       value = Fsymbol_value (elt[0]);
1065
1066       if (!CONSP (value))
1067         {
1068           if (KEYWORDP (elt[0]))
1069             {
1070               int fsty = 0;
1071
1072               if (EQ (Q_style, check_toolbar_button_keywords (button, elt[0],
1073                                                               elt[1],
1074                                                               errb)))
1075                 fsty++;
1076
1077               if (EQ (Q_style, check_toolbar_button_keywords (button, elt[2],
1078                                                               elt[3],
1079                                                               errb)))
1080                 fsty++;
1081
1082               if (!fsty)
1083                 CTB_ERROR ("must specify toolbar blank style");
1084               else if (EQ (elt[0], elt[2]))
1085                 CTB_ERROR
1086                   ("duplicate keywords in toolbar button blank description");
1087
1088               return Qt;
1089             }
1090           else
1091             CTB_ERROR ("first element of button must be a list (of glyphs)");
1092         }
1093     }
1094   else
1095     value = elt[0];
1096
1097   len = XINT (Flength (value));
1098   if (len < 1)
1099     CTB_ERROR ("toolbar button glyph list must have at least 1 entry");
1100
1101   if (len > 6)
1102     CTB_ERROR ("toolbar button glyph list can have at most 6 entries");
1103
1104   glyphs = value;
1105   while (!NILP (glyphs))
1106     {
1107       if (!GLYPHP (XCAR (glyphs)))
1108         {
1109           /* We allow nil for the down and disabled glyphs but not for
1110              the up glyph. */
1111           if (EQ (glyphs, value) || !NILP (XCAR (glyphs)))
1112             {
1113               CTB_ERROR
1114                 ("all elements of toolbar button glyph list must be glyphs.");
1115             }
1116         }
1117       glyphs = XCDR (glyphs);
1118     }
1119
1120   /* The second element is the function to run when the button is
1121      activated.  We do not do any checking on it because it is legal
1122      for the function to not be defined until after the toolbar is.
1123      It is the user's problem to get this right.
1124
1125      The third element is either a boolean indicating the enabled
1126      status or a function used to determine it.  Again, it is the
1127      user's problem if this is wrong.
1128
1129      The fourth element, if not nil, must be a string which will be
1130      displayed as the help echo. */
1131
1132   /* #### This should be allowed to be a function returning a string
1133      as well as just a string. */
1134   if (!NILP (elt[3]) && !STRINGP (elt[3]))
1135     CTB_ERROR ("toolbar button help echo string must be a string");
1136
1137   return Qt;
1138 }
1139 #undef CTB_ERROR
1140
1141 static void
1142 toolbar_validate (Lisp_Object instantiator)
1143 {
1144   int pushright_seen = 0;
1145   Lisp_Object rest;
1146
1147   if (NILP (instantiator))
1148     return;
1149
1150   if (!CONSP (instantiator))
1151     signal_simple_error ("Toolbar spec must be list or nil", instantiator);
1152
1153   for (rest = instantiator; !NILP (rest); rest = XCDR (rest))
1154     {
1155       if (!CONSP (rest))
1156         signal_simple_error ("Bad list in toolbar spec", instantiator);
1157
1158       if (NILP (XCAR (rest)))
1159         {
1160           if (pushright_seen)
1161             error
1162               ("More than one partition (nil) in instantiator description");
1163           else
1164             pushright_seen = 1;
1165         }
1166       else
1167         Fcheck_toolbar_button_syntax (XCAR (rest), Qnil);
1168     }
1169 }
1170
1171 static void
1172 toolbar_after_change (Lisp_Object specifier, Lisp_Object locale)
1173 {
1174   /* #### This is overkill.  I really need to rethink the after-change
1175      functions to make them easier to use. */
1176   MARK_TOOLBAR_CHANGED;
1177 }
1178
1179 DEFUN ("toolbar-specifier-p", Ftoolbar_specifier_p, 1, 1, 0, /*
1180 Return non-nil if OBJECT is a toolbar specifier.
1181
1182 See `make-toolbar-specifier' for a description of possible toolbar
1183 instantiators.
1184 */
1185        (object))
1186 {
1187   return TOOLBAR_SPECIFIERP (object) ? Qt : Qnil;
1188 }
1189
1190 \f
1191 /*
1192   Helper for invalidating the real specifier when default
1193   specifier caching changes
1194 */
1195 static void
1196 recompute_overlaying_specifier (Lisp_Object real_one[4])
1197 {
1198   enum toolbar_pos pos = decode_toolbar_position (Vdefault_toolbar_position);
1199   Fset_specifier_dirty_flag (real_one[pos]);
1200 }
1201
1202 static void
1203 toolbar_specs_changed (Lisp_Object specifier, struct window *w,
1204                        Lisp_Object oldval)
1205 {
1206   /* This could be smarter but I doubt that it would make any
1207      noticeable difference given the infrequency with which this is
1208      probably going to be called.
1209      */
1210   MARK_TOOLBAR_CHANGED;
1211 }
1212
1213 static void
1214 default_toolbar_specs_changed (Lisp_Object specifier, struct window *w,
1215                                Lisp_Object oldval)
1216 {
1217   recompute_overlaying_specifier (Vtoolbar);
1218 }
1219
1220 static void
1221 default_toolbar_size_changed_in_frame (Lisp_Object specifier, struct frame *f,
1222                                        Lisp_Object oldval)
1223 {
1224   recompute_overlaying_specifier (Vtoolbar_size);
1225 }
1226
1227 static void
1228 default_toolbar_border_width_changed_in_frame (Lisp_Object specifier,
1229                                                struct frame *f,
1230                                                Lisp_Object oldval)
1231 {
1232   recompute_overlaying_specifier (Vtoolbar_border_width);
1233 }
1234
1235 static void
1236 default_toolbar_visible_p_changed_in_frame (Lisp_Object specifier,
1237                                             struct frame *f,
1238                                             Lisp_Object oldval)
1239 {
1240   recompute_overlaying_specifier (Vtoolbar_visible_p);
1241 }
1242
1243 static void
1244 toolbar_geometry_changed_in_window (Lisp_Object specifier, struct window *w,
1245                                     Lisp_Object oldval)
1246 {
1247   MARK_TOOLBAR_CHANGED;
1248   MARK_WINDOWS_CHANGED (w);
1249 }
1250
1251 static void
1252 default_toolbar_size_changed_in_window (Lisp_Object specifier, struct window *w,
1253                                         Lisp_Object oldval)
1254 {
1255   recompute_overlaying_specifier (Vtoolbar_size);
1256 }
1257
1258 static void
1259 default_toolbar_border_width_changed_in_window (Lisp_Object specifier,
1260                                                 struct window *w,
1261                                                 Lisp_Object oldval)
1262 {
1263   recompute_overlaying_specifier (Vtoolbar_border_width);
1264 }
1265
1266 static void
1267 default_toolbar_visible_p_changed_in_window (Lisp_Object specifier,
1268                                              struct window *w,
1269                                              Lisp_Object oldval)
1270 {
1271   recompute_overlaying_specifier (Vtoolbar_visible_p);
1272 }
1273
1274 static void
1275 toolbar_buttons_captioned_p_changed (Lisp_Object specifier, struct window *w,
1276                                      Lisp_Object oldval)
1277 {
1278   /* This could be smarter but I doubt that it would make any
1279      noticeable difference given the infrequency with which this is
1280      probably going to be called. */
1281   MARK_TOOLBAR_CHANGED;
1282 }
1283
1284 \f
1285 void
1286 syms_of_toolbar (void)
1287 {
1288   INIT_LRECORD_IMPLEMENTATION (toolbar_button);
1289
1290   defsymbol (&Qtoolbar_buttonp, "toolbar-button-p");
1291   defsymbol (&Q2D, "2D");
1292   defsymbol (&Q3D, "3D");
1293   defsymbol (&Q2d, "2d");
1294   defsymbol (&Q3d, "3d");
1295   defsymbol (&Q_size, ":size"); Fset (Q_size, Q_size);
1296
1297   defsymbol (&Qinit_toolbar_from_resources, "init-toolbar-from-resources");
1298   DEFSUBR (Ftoolbar_button_p);
1299   DEFSUBR (Ftoolbar_button_callback);
1300   DEFSUBR (Ftoolbar_button_help_string);
1301   DEFSUBR (Ftoolbar_button_enabled_p);
1302   DEFSUBR (Fset_toolbar_button_down_flag);
1303   DEFSUBR (Fcheck_toolbar_button_syntax);
1304   DEFSUBR (Fset_default_toolbar_position);
1305   DEFSUBR (Fdefault_toolbar_position);
1306   DEFSUBR (Ftoolbar_specifier_p);
1307 }
1308
1309 void
1310 vars_of_toolbar (void)
1311 {
1312   staticpro (&Vdefault_toolbar_position);
1313   Vdefault_toolbar_position = Qtop;
1314
1315 #ifdef HAVE_WINDOW_SYSTEM
1316   Fprovide (Qtoolbar);
1317 #endif
1318 }
1319
1320 void
1321 specifier_type_create_toolbar (void)
1322 {
1323   INITIALIZE_SPECIFIER_TYPE (toolbar, "toolbar", "toolbar-specifier-p");
1324
1325   SPECIFIER_HAS_METHOD (toolbar, validate);
1326   SPECIFIER_HAS_METHOD (toolbar, after_change);
1327 }
1328
1329 void
1330 reinit_specifier_type_create_toolbar (void)
1331 {
1332   REINITIALIZE_SPECIFIER_TYPE (toolbar);
1333 }
1334
1335 void
1336 specifier_vars_of_toolbar (void)
1337 {
1338   Lisp_Object fb;
1339
1340   DEFVAR_SPECIFIER ("default-toolbar", &Vdefault_toolbar /*
1341 Specifier for a fallback toolbar.
1342 Use `set-specifier' to change this.
1343
1344 The position of this toolbar is specified in the function
1345 `default-toolbar-position'.  If the corresponding position-specific
1346 toolbar (e.g. `top-toolbar' if `default-toolbar-position' is 'top)
1347 does not specify a toolbar in a particular domain (usually a window),
1348 then the value of `default-toolbar' in that domain, if any, will be
1349 used instead.
1350
1351 Note that the toolbar at any particular position will not be
1352 displayed unless its visibility flag is true and its thickness
1353 \(width or height, depending on orientation) is non-zero.  The
1354 visibility is controlled by the specifiers `top-toolbar-visible-p',
1355 `bottom-toolbar-visible-p', `left-toolbar-visible-p', and
1356 `right-toolbar-visible-p', and the thickness is controlled by the
1357 specifiers `top-toolbar-height', `bottom-toolbar-height',
1358 `left-toolbar-width', and `right-toolbar-width'.
1359
1360 Note that one of the four visibility specifiers inherits from
1361 `default-toolbar-visibility' and one of the four thickness
1362 specifiers inherits from either `default-toolbar-width' or
1363 `default-toolbar-height' (depending on orientation), just
1364 like for the toolbar description specifiers (e.g. `top-toolbar')
1365 mentioned above.
1366
1367 Therefore, if you are setting `default-toolbar', you should control
1368 the visibility and thickness using `default-toolbar-visible-p',
1369 `default-toolbar-width', and `default-toolbar-height', rather than
1370 using position-specific specifiers.  That way, you will get sane
1371 behavior if the user changes the default toolbar position.
1372
1373 The format of the instantiator for a toolbar is a list of
1374 toolbar-button-descriptors.  Each toolbar-button-descriptor
1375 is a vector in one of the following formats:
1376
1377   [GLYPH-LIST FUNCTION ENABLED-P HELP] or
1378   [:style 2D-OR-3D] or
1379   [:style 2D-OR-3D :size WIDTH-OR-HEIGHT] or
1380   [:size WIDTH-OR-HEIGHT :style 2D-OR-3D]
1381
1382 Optionally, one of the toolbar-button-descriptors may be nil
1383 instead of a vector; this signifies the division between
1384 the toolbar buttons that are to be displayed flush-left,
1385 and the buttons to be displayed flush-right.
1386
1387 The first vector format above specifies a normal toolbar button;
1388 the others specify blank areas in the toolbar.
1389
1390 For the first vector format:
1391
1392 -- GLYPH-LIST should be a list of one to six glyphs (as created by
1393    `make-glyph') or a symbol whose value is such a list.  The first
1394    glyph, which must be provided, is the glyph used to display the
1395    toolbar button when it is in the "up" (not pressed) state.  The
1396    optional second glyph is for displaying the button when it is in
1397    the "down" (pressed) state.  The optional third glyph is for when
1398    the button is disabled.  The optional fourth, fifth and sixth glyphs
1399    are used to specify captioned versions for the up, down and disabled
1400    states respectively.  The function `toolbar-make-button-list' is
1401    useful in creating these glyph lists.  The specifier variable
1402    `toolbar-buttons-captioned-p' controls which glyphs are actually used.
1403
1404 -- Even if you do not provide separate down-state and disabled-state
1405    glyphs, the user will still get visual feedback to indicate which
1406    state the button is in.  Buttons in the up-state are displayed
1407    with a shadowed border that gives a raised appearance to the
1408    button.  Buttons in the down-state are displayed with shadows that
1409    give a recessed appearance.  Buttons in the disabled state are
1410    displayed with no shadows, giving a 2-d effect.
1411
1412 -- If some of the toolbar glyphs are not provided, they inherit as follows:
1413
1414      UP:                up
1415      DOWN:              down -> up
1416      DISABLED:          disabled -> up
1417      CAP-UP:            cap-up -> up
1418      CAP-DOWN:          cap-down -> cap-up -> down -> up
1419      CAP-DISABLED:      cap-disabled -> cap-up -> disabled -> up
1420
1421 -- The second element FUNCTION is a function to be called when the
1422    toolbar button is activated (i.e. when the mouse is released over
1423    the toolbar button, if the press occurred in the toolbar).  It
1424    can be any form accepted by `call-interactively', since this is
1425    how it is invoked.
1426
1427 -- The third element ENABLED-P specifies whether the toolbar button
1428    is enabled (disabled buttons do nothing when they are activated,
1429    and are displayed differently; see above).  It should be either
1430    a boolean or a form that evaluates to a boolean.
1431
1432 -- The fourth element HELP, if non-nil, should be a string.  This
1433    string is displayed in the echo area when the mouse passes over
1434    the toolbar button.
1435
1436 For the other vector formats (specifying blank areas of the toolbar):
1437
1438 -- 2D-OR-3D should be one of the symbols '2d or '3d, indicating
1439    whether the area is displayed with shadows (giving it a raised,
1440    3-d appearance) or without shadows (giving it a flat appearance).
1441
1442 -- WIDTH-OR-HEIGHT specifies the length, in pixels, of the blank
1443    area.  If omitted, it defaults to a device-specific value
1444    (8 pixels for X devices).
1445 */ );
1446
1447   Vdefault_toolbar = Fmake_specifier (Qtoolbar);
1448   /* #### It would be even nicer if the specifier caching
1449      automatically knew about specifier fallbacks, so we didn't
1450      have to do it ourselves. */
1451   set_specifier_caching (Vdefault_toolbar,
1452                          offsetof (struct window, default_toolbar),
1453                          default_toolbar_specs_changed,
1454                          0, 0, 0);
1455
1456   DEFVAR_SPECIFIER ("top-toolbar",
1457                     &Vtoolbar[TOP_TOOLBAR] /*
1458 Specifier for the toolbar at the top of the frame.
1459 Use `set-specifier' to change this.
1460 See `default-toolbar' for a description of a valid toolbar instantiator.
1461 */ );
1462   Vtoolbar[TOP_TOOLBAR] = Fmake_specifier (Qtoolbar);
1463   set_specifier_caching (Vtoolbar[TOP_TOOLBAR],
1464                          offsetof (struct window, toolbar[TOP_TOOLBAR]),
1465                          toolbar_specs_changed,
1466                          0, 0, 0);
1467
1468   DEFVAR_SPECIFIER ("bottom-toolbar",
1469                     &Vtoolbar[BOTTOM_TOOLBAR] /*
1470 Specifier for the toolbar at the bottom 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 `bottom', by
1475 default the height of the bottom toolbar (controlled by
1476 `bottom-toolbar-height') is 0; thus, a bottom toolbar will not be
1477 displayed even if you provide a value for `bottom-toolbar'.
1478 */ );
1479   Vtoolbar[BOTTOM_TOOLBAR] = Fmake_specifier (Qtoolbar);
1480   set_specifier_caching (Vtoolbar[BOTTOM_TOOLBAR],
1481                          offsetof (struct window, toolbar[BOTTOM_TOOLBAR]),
1482                          toolbar_specs_changed,
1483                          0, 0, 0);
1484
1485   DEFVAR_SPECIFIER ("left-toolbar",
1486                     &Vtoolbar[LEFT_TOOLBAR] /*
1487 Specifier for the toolbar at the left edge of the frame.
1488 Use `set-specifier' to change this.
1489 See `default-toolbar' for a description of a valid toolbar instantiator.
1490
1491 Note that, unless the `default-toolbar-position' is `left', by
1492 default the height of the left toolbar (controlled by
1493 `left-toolbar-width') is 0; thus, a left toolbar will not be
1494 displayed even if you provide a value for `left-toolbar'.
1495 */ );
1496   Vtoolbar[LEFT_TOOLBAR] = Fmake_specifier (Qtoolbar);
1497   set_specifier_caching (Vtoolbar[LEFT_TOOLBAR],
1498                          offsetof (struct window, toolbar[LEFT_TOOLBAR]),
1499                          toolbar_specs_changed,
1500                          0, 0, 0);
1501
1502   DEFVAR_SPECIFIER ("right-toolbar",
1503                     &Vtoolbar[RIGHT_TOOLBAR] /*
1504 Specifier for the toolbar at the right edge of the frame.
1505 Use `set-specifier' to change this.
1506 See `default-toolbar' for a description of a valid toolbar instantiator.
1507
1508 Note that, unless the `default-toolbar-position' is `right', by
1509 default the height of the right toolbar (controlled by
1510 `right-toolbar-width') is 0; thus, a right toolbar will not be
1511 displayed even if you provide a value for `right-toolbar'.
1512 */ );
1513   Vtoolbar[RIGHT_TOOLBAR] = Fmake_specifier (Qtoolbar);
1514   set_specifier_caching (Vtoolbar[RIGHT_TOOLBAR],
1515                          offsetof (struct window, toolbar[RIGHT_TOOLBAR]),
1516                          toolbar_specs_changed,
1517                          0, 0, 0);
1518
1519   /* initially, top inherits from default; this can be
1520      changed with `set-default-toolbar-position'. */
1521   fb = list1 (Fcons (Qnil, Qnil));
1522   set_specifier_fallback (Vdefault_toolbar, fb);
1523   set_specifier_fallback (Vtoolbar[TOP_TOOLBAR], Vdefault_toolbar);
1524   set_specifier_fallback (Vtoolbar[BOTTOM_TOOLBAR], fb);
1525   set_specifier_fallback (Vtoolbar[LEFT_TOOLBAR],   fb);
1526   set_specifier_fallback (Vtoolbar[RIGHT_TOOLBAR],  fb);
1527
1528   DEFVAR_SPECIFIER ("default-toolbar-height", &Vdefault_toolbar_height /*
1529 *Height of the default toolbar, if it's oriented horizontally.
1530 This is a specifier; use `set-specifier' to change it.
1531
1532 The position of the default toolbar is specified by the function
1533 `set-default-toolbar-position'.  If the corresponding position-specific
1534 toolbar thickness specifier (e.g. `top-toolbar-height' if
1535 `default-toolbar-position' is 'top) does not specify a thickness in a
1536 particular domain (a window or a frame), then the value of
1537 `default-toolbar-height' or `default-toolbar-width' (depending on the
1538 toolbar orientation) in that domain, if any, will be used instead.
1539
1540 Note that `default-toolbar-height' is only used when
1541 `default-toolbar-position' is 'top or 'bottom, and `default-toolbar-width'
1542 is only used when `default-toolbar-position' is 'left or 'right.
1543
1544 Note that all of the position-specific toolbar thickness specifiers
1545 have a fallback value of zero when they do not correspond to the
1546 default toolbar.  Therefore, you will have to set a non-zero thickness
1547 value if you want a position-specific toolbar to be displayed.
1548
1549 Internally, toolbar thickness specifiers are instantiated in both
1550 window and frame domains, for different purposes.  The value in the
1551 domain of a frame's selected window specifies the actual toolbar
1552 thickness that you will see in that frame.  The value in the domain of
1553 a frame itself specifies the toolbar thickness that is used in frame
1554 geometry calculations.
1555
1556 Thus, for example, if you set the frame width to 80 characters and the
1557 left toolbar width for that frame to 68 pixels, then the frame will
1558 be sized to fit 80 characters plus a 68-pixel left toolbar.  If you
1559 then set the left toolbar width to 0 for a particular buffer (or if
1560 that buffer does not specify a left toolbar or has a nil value
1561 specified for `left-toolbar-visible-p'), you will find that, when
1562 that buffer is displayed in the selected window, the window will have
1563 a width of 86 or 87 characters -- the frame is sized for a 68-pixel
1564 left toolbar but the selected window specifies that the left toolbar
1565 is not visible, so it is expanded to take up the slack.
1566 */ );
1567   Vdefault_toolbar_height = Fmake_specifier (Qnatnum);
1568   set_specifier_caching (Vdefault_toolbar_height,
1569                          offsetof (struct window, default_toolbar_height),
1570                          default_toolbar_size_changed_in_window,
1571                          offsetof (struct frame, default_toolbar_height),
1572                          default_toolbar_size_changed_in_frame, 0);
1573
1574   DEFVAR_SPECIFIER ("default-toolbar-width", &Vdefault_toolbar_width /*
1575 *Width of the default toolbar, if it's oriented vertically.
1576 This is a specifier; use `set-specifier' to change it.
1577
1578 See `default-toolbar-height' for more information.
1579 */ );
1580   Vdefault_toolbar_width = Fmake_specifier (Qnatnum);
1581   set_specifier_caching (Vdefault_toolbar_width,
1582                          offsetof (struct window, default_toolbar_width),
1583                          default_toolbar_size_changed_in_window,
1584                          offsetof (struct frame, default_toolbar_width),
1585                          default_toolbar_size_changed_in_frame, 0);
1586
1587   DEFVAR_SPECIFIER ("top-toolbar-height",
1588                     &Vtoolbar_size[TOP_TOOLBAR] /*
1589 *Height of the top toolbar.
1590 This is a specifier; use `set-specifier' to change it.
1591
1592 See `default-toolbar-height' for more information.
1593 */ );
1594   Vtoolbar_size[TOP_TOOLBAR] = Fmake_specifier (Qnatnum);
1595   set_specifier_caching (Vtoolbar_size[TOP_TOOLBAR],
1596                          offsetof (struct window, toolbar_size[TOP_TOOLBAR]),
1597                          toolbar_geometry_changed_in_window,
1598                          offsetof (struct frame, toolbar_size[TOP_TOOLBAR]),
1599                          frame_size_slipped, 0);
1600
1601   DEFVAR_SPECIFIER ("bottom-toolbar-height",
1602                     &Vtoolbar_size[BOTTOM_TOOLBAR] /*
1603 *Height of the bottom toolbar.
1604 This is a specifier; use `set-specifier' to change it.
1605
1606 See `default-toolbar-height' for more information.
1607 */ );
1608   Vtoolbar_size[BOTTOM_TOOLBAR] = Fmake_specifier (Qnatnum);
1609   set_specifier_caching (Vtoolbar_size[BOTTOM_TOOLBAR],
1610                          offsetof (struct window, toolbar_size[BOTTOM_TOOLBAR]),
1611                          toolbar_geometry_changed_in_window,
1612                          offsetof (struct frame, toolbar_size[BOTTOM_TOOLBAR]),
1613                          frame_size_slipped, 0);
1614
1615   DEFVAR_SPECIFIER ("left-toolbar-width",
1616                     &Vtoolbar_size[LEFT_TOOLBAR] /*
1617 *Width of left toolbar.
1618 This is a specifier; use `set-specifier' to change it.
1619
1620 See `default-toolbar-height' for more information.
1621 */ );
1622   Vtoolbar_size[LEFT_TOOLBAR] = Fmake_specifier (Qnatnum);
1623   set_specifier_caching (Vtoolbar_size[LEFT_TOOLBAR],
1624                          offsetof (struct window, toolbar_size[LEFT_TOOLBAR]),
1625                          toolbar_geometry_changed_in_window,
1626                          offsetof (struct frame, toolbar_size[LEFT_TOOLBAR]),
1627                          frame_size_slipped, 0);
1628
1629   DEFVAR_SPECIFIER ("right-toolbar-width",
1630                     &Vtoolbar_size[RIGHT_TOOLBAR] /*
1631 *Width of right toolbar.
1632 This is a specifier; use `set-specifier' to change it.
1633
1634 See `default-toolbar-height' for more information.
1635 */ );
1636   Vtoolbar_size[RIGHT_TOOLBAR] = Fmake_specifier (Qnatnum);
1637   set_specifier_caching (Vtoolbar_size[RIGHT_TOOLBAR],
1638                          offsetof (struct window, toolbar_size[RIGHT_TOOLBAR]),
1639                          toolbar_geometry_changed_in_window,
1640                          offsetof (struct frame, toolbar_size[RIGHT_TOOLBAR]),
1641                          frame_size_slipped, 0);
1642
1643   fb = Qnil;
1644 #ifdef HAVE_TTY
1645   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1646 #endif
1647 #ifdef HAVE_GTK
1648   fb = Fcons (Fcons (list1 (Qgtk), make_int (DEFAULT_TOOLBAR_HEIGHT)), fb);
1649 #endif
1650 #ifdef HAVE_X_WINDOWS
1651   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_HEIGHT)), fb);
1652 #endif
1653 #ifdef HAVE_MS_WINDOWS
1654   fb = Fcons (Fcons (list1 (Qmswindows),
1655                      make_int (MSWINDOWS_DEFAULT_TOOLBAR_HEIGHT)), fb);
1656 #endif
1657   if (!NILP (fb))
1658     set_specifier_fallback (Vdefault_toolbar_height, fb);
1659
1660   fb = Qnil;
1661 #ifdef HAVE_TTY
1662   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1663 #endif
1664 #ifdef HAVE_GTK
1665   fb = Fcons (Fcons (list1 (Qgtk), make_int (DEFAULT_TOOLBAR_WIDTH)), fb);
1666 #endif
1667 #ifdef HAVE_X_WINDOWS
1668   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_WIDTH)), fb);
1669 #endif
1670 #ifdef HAVE_MS_WINDOWS
1671   fb = Fcons (Fcons (list1 (Qmswindows),
1672                      make_int (MSWINDOWS_DEFAULT_TOOLBAR_WIDTH)), fb);
1673 #endif
1674   if (!NILP (fb))
1675     set_specifier_fallback (Vdefault_toolbar_width, fb);
1676
1677   set_specifier_fallback (Vtoolbar_size[TOP_TOOLBAR], Vdefault_toolbar_height);
1678   fb = list1 (Fcons (Qnil, Qzero));
1679   set_specifier_fallback (Vtoolbar_size[BOTTOM_TOOLBAR], fb);
1680   set_specifier_fallback (Vtoolbar_size[LEFT_TOOLBAR],   fb);
1681   set_specifier_fallback (Vtoolbar_size[RIGHT_TOOLBAR],  fb);
1682
1683   DEFVAR_SPECIFIER ("default-toolbar-border-width",
1684                     &Vdefault_toolbar_border_width /*
1685 *Width of the border around the default toolbar.
1686 This is a specifier; use `set-specifier' to change it.
1687
1688 The position of the default toolbar is specified by the function
1689 `set-default-toolbar-position'.  If the corresponding position-specific
1690 toolbar border width specifier (e.g. `top-toolbar-border-width' if
1691 `default-toolbar-position' is 'top) does not specify a border width in a
1692 particular domain (a window or a frame), then the value of
1693 `default-toolbar-border-width' in that domain, if any, will be used
1694 instead.
1695
1696 Internally, toolbar border width specifiers are instantiated in both
1697 window and frame domains, for different purposes.  The value in the
1698 domain of a frame's selected window specifies the actual toolbar border
1699 width that you will see in that frame.  The value in the domain of a
1700 frame itself specifies the toolbar border width that is used in frame
1701 geometry calculations.  Changing the border width value in the frame
1702 domain will result in a size change in the frame itself, while changing
1703 the value in a window domain will not.
1704 */ );
1705   Vdefault_toolbar_border_width = Fmake_specifier (Qnatnum);
1706   set_specifier_caching (Vdefault_toolbar_border_width,
1707                          offsetof (struct window, default_toolbar_border_width),
1708                          default_toolbar_border_width_changed_in_window,
1709                          offsetof (struct frame, default_toolbar_border_width),
1710                          default_toolbar_border_width_changed_in_frame, 0);
1711
1712   DEFVAR_SPECIFIER ("top-toolbar-border-width",
1713                     &Vtoolbar_border_width[TOP_TOOLBAR] /*
1714 *Border width of the top toolbar.
1715 This is a specifier; use `set-specifier' to change it.
1716
1717 See `default-toolbar-height' for more information.
1718 */ );
1719   Vtoolbar_border_width[TOP_TOOLBAR] = Fmake_specifier (Qnatnum);
1720   set_specifier_caching (Vtoolbar_border_width[TOP_TOOLBAR],
1721                          offsetof (struct window,
1722                                    toolbar_border_width[TOP_TOOLBAR]),
1723                          toolbar_geometry_changed_in_window,
1724                          offsetof (struct frame,
1725                                    toolbar_border_width[TOP_TOOLBAR]),
1726                          frame_size_slipped, 0);
1727
1728   DEFVAR_SPECIFIER ("bottom-toolbar-border-width",
1729                     &Vtoolbar_border_width[BOTTOM_TOOLBAR] /*
1730 *Border width of the bottom toolbar.
1731 This is a specifier; use `set-specifier' to change it.
1732
1733 See `default-toolbar-height' for more information.
1734 */ );
1735   Vtoolbar_border_width[BOTTOM_TOOLBAR] = Fmake_specifier (Qnatnum);
1736   set_specifier_caching (Vtoolbar_border_width[BOTTOM_TOOLBAR],
1737                          offsetof (struct window,
1738                                    toolbar_border_width[BOTTOM_TOOLBAR]),
1739                          toolbar_geometry_changed_in_window,
1740                          offsetof (struct frame,
1741                                    toolbar_border_width[BOTTOM_TOOLBAR]),
1742                          frame_size_slipped, 0);
1743
1744   DEFVAR_SPECIFIER ("left-toolbar-border-width",
1745                     &Vtoolbar_border_width[LEFT_TOOLBAR] /*
1746 *Border width of left toolbar.
1747 This is a specifier; use `set-specifier' to change it.
1748
1749 See `default-toolbar-height' for more information.
1750 */ );
1751   Vtoolbar_border_width[LEFT_TOOLBAR] = Fmake_specifier (Qnatnum);
1752   set_specifier_caching (Vtoolbar_border_width[LEFT_TOOLBAR],
1753                          offsetof (struct window,
1754                                    toolbar_border_width[LEFT_TOOLBAR]),
1755                          toolbar_geometry_changed_in_window,
1756                          offsetof (struct frame,
1757                                    toolbar_border_width[LEFT_TOOLBAR]),
1758                          frame_size_slipped, 0);
1759
1760   DEFVAR_SPECIFIER ("right-toolbar-border-width",
1761                     &Vtoolbar_border_width[RIGHT_TOOLBAR] /*
1762 *Border width of right toolbar.
1763 This is a specifier; use `set-specifier' to change it.
1764
1765 See `default-toolbar-height' for more information.
1766 */ );
1767   Vtoolbar_border_width[RIGHT_TOOLBAR] = Fmake_specifier (Qnatnum);
1768   set_specifier_caching (Vtoolbar_border_width[RIGHT_TOOLBAR],
1769                          offsetof (struct window,
1770                                    toolbar_border_width[RIGHT_TOOLBAR]),
1771                          toolbar_geometry_changed_in_window,
1772                          offsetof (struct frame,
1773                                    toolbar_border_width[RIGHT_TOOLBAR]),
1774                          frame_size_slipped, 0);
1775
1776   fb = Qnil;
1777 #ifdef HAVE_TTY
1778   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1779 #endif
1780 #ifdef HAVE_X_WINDOWS
1781   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_BORDER_WIDTH)), fb);
1782 #endif
1783 #ifdef HAVE_GTK
1784   fb = Fcons (Fcons (list1 (Qgtk), make_int (DEFAULT_TOOLBAR_BORDER_WIDTH)), fb);
1785 #endif
1786 #ifdef HAVE_MS_WINDOWS
1787   fb = Fcons (Fcons (list1 (Qmswindows), make_int (MSWINDOWS_DEFAULT_TOOLBAR_BORDER_WIDTH)), fb);
1788 #endif
1789   if (!NILP (fb))
1790     set_specifier_fallback (Vdefault_toolbar_border_width, fb);
1791
1792   set_specifier_fallback (Vtoolbar_border_width[TOP_TOOLBAR], Vdefault_toolbar_border_width);
1793   fb = list1 (Fcons (Qnil, Qzero));
1794   set_specifier_fallback (Vtoolbar_border_width[BOTTOM_TOOLBAR], fb);
1795   set_specifier_fallback (Vtoolbar_border_width[LEFT_TOOLBAR],   fb);
1796   set_specifier_fallback (Vtoolbar_border_width[RIGHT_TOOLBAR],  fb);
1797
1798   DEFVAR_SPECIFIER ("default-toolbar-visible-p", &Vdefault_toolbar_visible_p /*
1799 *Whether the default toolbar is visible.
1800 This is a specifier; use `set-specifier' to change it.
1801
1802 The position of the default toolbar is specified by the function
1803 `set-default-toolbar-position'.  If the corresponding position-specific
1804 toolbar visibility specifier (e.g. `top-toolbar-visible-p' if
1805 `default-toolbar-position' is 'top) does not specify a visible-p value
1806 in a particular domain (a window or a frame), then the value of
1807 `default-toolbar-visible-p' in that domain, if any, will be used
1808 instead.
1809
1810 Both window domains and frame domains are used internally, for
1811 different purposes.  The distinction here is exactly the same as
1812 for thickness specifiers; see `default-toolbar-height' for more
1813 information.
1814
1815 `default-toolbar-visible-p' and all of the position-specific toolbar
1816 visibility specifiers have a fallback value of true.
1817 */ );
1818   Vdefault_toolbar_visible_p = Fmake_specifier (Qboolean);
1819   set_specifier_caching (Vdefault_toolbar_visible_p,
1820                          offsetof (struct window, default_toolbar_visible_p),
1821                          default_toolbar_visible_p_changed_in_window,
1822                          offsetof (struct frame, default_toolbar_visible_p),
1823                          default_toolbar_visible_p_changed_in_frame, 0);
1824
1825   DEFVAR_SPECIFIER ("top-toolbar-visible-p",
1826                     &Vtoolbar_visible_p[TOP_TOOLBAR] /*
1827 *Whether the top toolbar is visible.
1828 This is a specifier; use `set-specifier' to change it.
1829
1830 See `default-toolbar-visible-p' for more information.
1831 */ );
1832   Vtoolbar_visible_p[TOP_TOOLBAR] = Fmake_specifier (Qboolean);
1833   set_specifier_caching (Vtoolbar_visible_p[TOP_TOOLBAR],
1834                          offsetof (struct window,
1835                                    toolbar_visible_p[TOP_TOOLBAR]),
1836                          toolbar_geometry_changed_in_window,
1837                          offsetof (struct frame,
1838                                    toolbar_visible_p[TOP_TOOLBAR]),
1839                          frame_size_slipped, 0);
1840
1841   DEFVAR_SPECIFIER ("bottom-toolbar-visible-p",
1842                     &Vtoolbar_visible_p[BOTTOM_TOOLBAR] /*
1843 *Whether the bottom toolbar is visible.
1844 This is a specifier; use `set-specifier' to change it.
1845
1846 See `default-toolbar-visible-p' for more information.
1847 */ );
1848   Vtoolbar_visible_p[BOTTOM_TOOLBAR] = Fmake_specifier (Qboolean);
1849   set_specifier_caching (Vtoolbar_visible_p[BOTTOM_TOOLBAR],
1850                          offsetof (struct window,
1851                                    toolbar_visible_p[BOTTOM_TOOLBAR]),
1852                          toolbar_geometry_changed_in_window,
1853                          offsetof (struct frame,
1854                                    toolbar_visible_p[BOTTOM_TOOLBAR]),
1855                          frame_size_slipped, 0);
1856
1857   DEFVAR_SPECIFIER ("left-toolbar-visible-p",
1858                     &Vtoolbar_visible_p[LEFT_TOOLBAR] /*
1859 *Whether the left toolbar is visible.
1860 This is a specifier; use `set-specifier' to change it.
1861
1862 See `default-toolbar-visible-p' for more information.
1863 */ );
1864   Vtoolbar_visible_p[LEFT_TOOLBAR] = Fmake_specifier (Qboolean);
1865   set_specifier_caching (Vtoolbar_visible_p[LEFT_TOOLBAR],
1866                          offsetof (struct window,
1867                                    toolbar_visible_p[LEFT_TOOLBAR]),
1868                          toolbar_geometry_changed_in_window,
1869                          offsetof (struct frame,
1870                                    toolbar_visible_p[LEFT_TOOLBAR]),
1871                          frame_size_slipped, 0);
1872
1873   DEFVAR_SPECIFIER ("right-toolbar-visible-p",
1874                     &Vtoolbar_visible_p[RIGHT_TOOLBAR] /*
1875 *Whether the right toolbar is visible.
1876 This is a specifier; use `set-specifier' to change it.
1877
1878 See `default-toolbar-visible-p' for more information.
1879 */ );
1880   Vtoolbar_visible_p[RIGHT_TOOLBAR] = Fmake_specifier (Qboolean);
1881   set_specifier_caching (Vtoolbar_visible_p[RIGHT_TOOLBAR],
1882                          offsetof (struct window,
1883                                    toolbar_visible_p[RIGHT_TOOLBAR]),
1884                          toolbar_geometry_changed_in_window,
1885                          offsetof (struct frame,
1886                                    toolbar_visible_p[RIGHT_TOOLBAR]),
1887                          frame_size_slipped, 0);
1888
1889   /* initially, top inherits from default; this can be
1890      changed with `set-default-toolbar-position'. */
1891   fb = list1 (Fcons (Qnil, Qt));
1892   set_specifier_fallback (Vdefault_toolbar_visible_p, fb);
1893   set_specifier_fallback (Vtoolbar_visible_p[TOP_TOOLBAR],
1894                           Vdefault_toolbar_visible_p);
1895   set_specifier_fallback (Vtoolbar_visible_p[BOTTOM_TOOLBAR], fb);
1896   set_specifier_fallback (Vtoolbar_visible_p[LEFT_TOOLBAR],   fb);
1897   set_specifier_fallback (Vtoolbar_visible_p[RIGHT_TOOLBAR],  fb);
1898
1899   DEFVAR_SPECIFIER ("toolbar-buttons-captioned-p",
1900                     &Vtoolbar_buttons_captioned_p /*
1901 *Whether the toolbar buttons are captioned.
1902 This will only have a visible effect for those toolbar buttons which had
1903 captioned versions specified.
1904 This is a specifier; use `set-specifier' to change it.
1905 */ );
1906   Vtoolbar_buttons_captioned_p = Fmake_specifier (Qboolean);
1907   set_specifier_caching (Vtoolbar_buttons_captioned_p,
1908                          offsetof (struct window, toolbar_buttons_captioned_p),
1909                          toolbar_buttons_captioned_p_changed,
1910                          0, 0, 0);
1911   set_specifier_fallback (Vtoolbar_buttons_captioned_p,
1912                           list1 (Fcons (Qnil, Qt)));
1913 }