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