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