comparison src/toolbar.c @ 0:376386a54a3c r19-14

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