--- /dev/null
+/* Generic toolbar implementation.
+ Copyright (C) 1995 Board of Trustees, University of Illinois.
+ Copyright (C) 1995 Sun Microsystems, Inc.
+ Copyright (C) 1995, 1996 Ben Wing.
+ Copyright (C) 1996 Chuck Thompson.
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Synched up with: Not in FSF. */
+
+/* Original implementation by Chuck Thompson for 19.12.
+ Default-toolbar-position and specifier-related stuff by Ben Wing. */
+
+#include <config.h>
+#include "lisp.h"
+
+#include "buffer.h"
+#include "frame.h"
+#include "device.h"
+#include "glyphs.h"
+#include "redisplay.h"
+#include "toolbar.h"
+#include "window.h"
+
+Lisp_Object Vtoolbar[4];
+Lisp_Object Vtoolbar_size[4];
+Lisp_Object Vtoolbar_visible_p[4];
+Lisp_Object Vtoolbar_border_width[4];
+
+Lisp_Object Vdefault_toolbar, Vdefault_toolbar_visible_p;
+Lisp_Object Vdefault_toolbar_width, Vdefault_toolbar_height;
+Lisp_Object Vdefault_toolbar_border_width;
+
+Lisp_Object Vdefault_toolbar_position;
+Lisp_Object Vtoolbar_buttons_captioned_p;
+
+Lisp_Object Qtoolbar_buttonp;
+Lisp_Object Q2D, Q3D, Q2d, Q3d;
+Lisp_Object Q_size;
+
+Lisp_Object Qinit_toolbar_from_resources;
+
+\f
+static Lisp_Object
+mark_toolbar_button (Lisp_Object obj, void (*markobj) (Lisp_Object))
+{
+ struct toolbar_button *data = (struct toolbar_button *) XPNTR (obj);
+ ((markobj) (data->next));
+ ((markobj) (data->frame));
+ ((markobj) (data->up_glyph));
+ ((markobj) (data->down_glyph));
+ ((markobj) (data->disabled_glyph));
+ ((markobj) (data->cap_up_glyph));
+ ((markobj) (data->cap_down_glyph));
+ ((markobj) (data->cap_disabled_glyph));
+ ((markobj) (data->callback));
+ ((markobj) (data->enabled_p));
+ return data->help_string;
+}
+
+static void
+print_toolbar_button (Lisp_Object obj, Lisp_Object printcharfun,
+ int escapeflag)
+{
+ struct toolbar_button *tb = XTOOLBAR_BUTTON (obj);
+ char buf[100];
+
+ if (print_readably)
+ error ("printing unreadable object #<toolbar-button 0x%x>",
+ tb->header.uid);
+
+ sprintf (buf, "#<toolbar-button 0x%x>", tb->header.uid);
+ write_c_string (buf, printcharfun);
+}
+
+DEFINE_LRECORD_IMPLEMENTATION ("toolbar-button", toolbar_button,
+ mark_toolbar_button, print_toolbar_button,
+ 0, 0, 0,
+ struct toolbar_button);
+
+DEFUN ("toolbar-button-p", Ftoolbar_button_p, 1, 1, 0, /*
+Return non-nil if OBJECT is a toolbar button.
+*/
+ (object))
+{
+ return TOOLBAR_BUTTONP (object) ? Qt : Qnil;
+}
+
+/* Only query functions are provided for toolbar buttons. They are
+ generated and updated from a toolbar description list. Any
+ directly made changes would be wiped out the first time the toolbar
+ was marked as dirty and was regenerated. The exception to this is
+ set-toolbar-button-down-flag. Having this allows us to control the
+ toolbar from elisp. Since we only trigger the button callbacks on
+ up-mouse events and we reset the flag first, there shouldn't be any
+ way for this to get us in trouble (like if someone decides to
+ change the toolbar from a toolbar callback). */
+
+DEFUN ("toolbar-button-callback", Ftoolbar_button_callback, 1, 1, 0, /*
+Return the callback function associated with the toolbar BUTTON.
+*/
+ (button))
+{
+ CHECK_TOOLBAR_BUTTON (button);
+
+ return XTOOLBAR_BUTTON (button)->callback;
+}
+
+DEFUN ("toolbar-button-help-string", Ftoolbar_button_help_string, 1, 1, 0, /*
+Return the help string function associated with the toolbar BUTTON.
+*/
+ (button))
+{
+ CHECK_TOOLBAR_BUTTON (button);
+
+ return XTOOLBAR_BUTTON (button)->help_string;
+}
+
+DEFUN ("toolbar-button-enabled-p", Ftoolbar_button_enabled_p, 1, 1, 0, /*
+Return t if BUTTON is active.
+*/
+ (button))
+{
+ CHECK_TOOLBAR_BUTTON (button);
+
+ return XTOOLBAR_BUTTON (button)->enabled ? Qt : Qnil;
+}
+
+DEFUN ("set-toolbar-button-down-flag", Fset_toolbar_button_down_flag, 2, 2, 0, /*
+Don't touch.
+*/
+ (button, flag))
+{
+ struct toolbar_button *tb;
+ char old_flag;
+
+ CHECK_TOOLBAR_BUTTON (button);
+ tb = XTOOLBAR_BUTTON (button);
+ old_flag = tb->down;
+
+ /* If the button is ignored, don't do anything. */
+ if (!tb->enabled)
+ return Qnil;
+
+ /* If flag is nil, unset the down flag, otherwise set it to true.
+ This also triggers an immediate redraw of the button if the flag
+ does change. */
+
+ if (NILP (flag))
+ tb->down = 0;
+ else
+ tb->down = 1;
+
+ if (tb->down != old_flag)
+ {
+ struct frame *f = XFRAME (tb->frame);
+ struct device *d;
+
+ if (DEVICEP (f->device))
+ {
+ d = XDEVICE (f->device);
+
+ if (DEVICE_LIVE_P (XDEVICE (f->device)))
+ {
+ tb->dirty = 1;
+ MAYBE_DEVMETH (d, output_toolbar_button, (f, button));
+ }
+ }
+ }
+
+ return Qnil;
+}
+
+Lisp_Object
+get_toolbar_button_glyph (struct window *w, struct toolbar_button *tb)
+{
+ Lisp_Object glyph = Qnil;
+
+ /* The selected glyph logic:
+
+ UP: up
+ DOWN: down -> up
+ DISABLED: disabled -> up
+ CAP-UP: cap-up -> up
+ CAP-DOWN: cap-down -> cap-up -> down -> up
+ CAP-DISABLED: cap-disabled -> cap-up -> disabled -> up
+ */
+
+ if (!NILP (w->toolbar_buttons_captioned_p))
+ {
+ if (tb->enabled && tb->down)
+ glyph = tb->cap_down_glyph;
+ else if (!tb->enabled)
+ glyph = tb->cap_disabled_glyph;
+
+ if (NILP (glyph))
+ glyph = tb->cap_up_glyph;
+ }
+
+ if (NILP (glyph))
+ {
+ if (tb->enabled && tb->down)
+ glyph = tb->down_glyph;
+ else if (!tb->enabled)
+ glyph = tb->disabled_glyph;
+ }
+
+ /* The non-captioned up button is the ultimate fallback. It is
+ the only one we guarantee exists. */
+ if (NILP (glyph))
+ glyph = tb->up_glyph;
+
+ return glyph;
+}
+
+\f
+static enum toolbar_pos
+decode_toolbar_position (Lisp_Object position)
+{
+ if (EQ (position, Qtop)) return TOP_TOOLBAR;
+ if (EQ (position, Qbottom)) return BOTTOM_TOOLBAR;
+ if (EQ (position, Qleft)) return LEFT_TOOLBAR;
+ if (EQ (position, Qright)) return RIGHT_TOOLBAR;
+ signal_simple_error ("Invalid toolbar position", position);
+
+ return TOP_TOOLBAR; /* not reached */
+}
+
+DEFUN ("set-default-toolbar-position", Fset_default_toolbar_position, 1, 1, 0, /*
+Set the position that the `default-toolbar' will be displayed at.
+Valid positions are 'top, 'bottom, 'left and 'right.
+See `default-toolbar-position'.
+*/
+ (position))
+{
+ enum toolbar_pos cur = decode_toolbar_position (Vdefault_toolbar_position);
+ enum toolbar_pos new = decode_toolbar_position (position);
+
+ if (cur != new)
+ {
+ /* The following calls will automatically cause the dirty
+ flags to be set; we delay frame size changes to avoid
+ lots of frame flickering. */
+ /* #### I think this should be GC protected. -sb */
+ hold_frame_size_changes ();
+ set_specifier_fallback (Vtoolbar[cur], list1 (Fcons (Qnil, Qnil)));
+ set_specifier_fallback (Vtoolbar[new], Vdefault_toolbar);
+ set_specifier_fallback (Vtoolbar_size[cur], list1 (Fcons (Qnil, Qzero)));
+ set_specifier_fallback (Vtoolbar_size[new],
+ new == TOP_TOOLBAR || new == BOTTOM_TOOLBAR
+ ? Vdefault_toolbar_height
+ : Vdefault_toolbar_width);
+ set_specifier_fallback (Vtoolbar_border_width[cur],
+ list1 (Fcons (Qnil, Qzero)));
+ set_specifier_fallback (Vtoolbar_border_width[new],
+ Vdefault_toolbar_border_width);
+ set_specifier_fallback (Vtoolbar_visible_p[cur],
+ list1 (Fcons (Qnil, Qt)));
+ set_specifier_fallback (Vtoolbar_visible_p[new],
+ Vdefault_toolbar_visible_p);
+ Vdefault_toolbar_position = position;
+ unhold_frame_size_changes ();
+ }
+
+ return position;
+}
+
+DEFUN ("default-toolbar-position", Fdefault_toolbar_position, 0, 0, 0, /*
+Return the position that the `default-toolbar' will be displayed at.
+The `default-toolbar' will only be displayed here if the corresponding
+position-specific toolbar specifier does not provide a value.
+*/
+ ())
+{
+ return Vdefault_toolbar_position;
+}
+
+\f
+static Lisp_Object
+update_toolbar_button (struct frame *f, struct toolbar_button *tb,
+ Lisp_Object desc, int pushright)
+{
+ Lisp_Object *elt, glyphs, retval, buffer;
+ struct gcpro gcpro1, gcpro2;
+
+ elt = XVECTOR_DATA (desc);
+ buffer = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer;
+
+ if (!tb)
+ {
+ tb = alloc_lcrecord_type (struct toolbar_button, lrecord_toolbar_button);
+ tb->next = Qnil;
+ XSETFRAME (tb->frame, f);
+ tb->up_glyph = Qnil;
+ tb->down_glyph = Qnil;
+ tb->disabled_glyph = Qnil;
+ tb->cap_up_glyph = Qnil;
+ tb->cap_down_glyph = Qnil;
+ tb->cap_disabled_glyph = Qnil;
+ tb->callback = Qnil;
+ tb->enabled_p = Qnil;
+ tb->help_string = Qnil;
+
+ tb->enabled = 0;
+ tb->down = 0;
+ tb->pushright = pushright;
+ tb->blank = 0;
+ tb->x = tb->y = tb->width = tb->height = -1;
+ tb->dirty = 1;
+ }
+ XSETTOOLBAR_BUTTON (retval, tb);
+
+ /* Let's make sure nothing gets mucked up by the potential call to
+ eval farther down. */
+ GCPRO2 (retval, desc);
+
+ glyphs = (CONSP (elt[0]) ? elt[0] : symbol_value_in_buffer (elt[0], buffer));
+
+ /* If this is true we have a blank, otherwise it is an actual
+ button. */
+ if (KEYWORDP (glyphs))
+ {
+ int pos;
+ int style_seen = 0;
+ int size_seen = 0;
+ int len = XVECTOR_LENGTH (desc);
+
+ if (!tb->blank)
+ {
+ tb->blank = 1;
+ tb->dirty = 1;
+ }
+
+ for (pos = 0; pos < len; pos += 2)
+ {
+ Lisp_Object key = elt[pos];
+ Lisp_Object val = elt[pos + 1];
+
+ if (EQ (key, Q_style))
+ {
+ style_seen = 1;
+
+ if (EQ (val, Q2D) || EQ (val, Q2d))
+ {
+ if (!EQ (Qnil, tb->up_glyph) || !EQ (Qt, tb->disabled_glyph))
+ {
+ tb->up_glyph = Qnil;
+ tb->disabled_glyph = Qt;
+ tb->dirty = 1;
+ }
+ }
+ else if (EQ (val, Q3D) || (EQ (val, Q3d)))
+ {
+ if (!EQ (Qt, tb->up_glyph) || !EQ (Qnil, tb->disabled_glyph))
+ {
+ tb->up_glyph = Qt;
+ tb->disabled_glyph = Qnil;
+ tb->dirty = 1;
+ }
+ }
+ }
+ else if (EQ (key, Q_size))
+ {
+ size_seen = 1;
+
+ if (!EQ (val, tb->down_glyph))
+ {
+ tb->down_glyph = val;
+ tb->dirty = 1;
+ }
+ }
+ }
+
+ if (!style_seen)
+ {
+ /* The default style is 3D. */
+ if (!EQ (Qt, tb->up_glyph) || !EQ (Qnil, tb->disabled_glyph))
+ {
+ tb->up_glyph = Qt;
+ tb->disabled_glyph = Qnil;
+ tb->dirty = 1;
+ }
+ }
+
+ if (!size_seen)
+ {
+ /* The default width is set to nil. The device specific
+ code will fill it in at its discretion. */
+ if (!NILP (tb->down_glyph))
+ {
+ tb->down_glyph = Qnil;
+ tb->dirty = 1;
+ }
+ }
+
+ /* The rest of these fields are not used by blanks. We make
+ sure they are nulled out in case this button object formerly
+ represented a real button. */
+ if (!NILP (tb->callback)
+ || !NILP (tb->enabled_p)
+ || !NILP (tb->help_string))
+ {
+ tb->cap_up_glyph = Qnil;
+ tb->cap_down_glyph = Qnil;
+ tb->cap_disabled_glyph = Qnil;
+ tb->callback = Qnil;
+ tb->enabled_p = Qnil;
+ tb->help_string = Qnil;
+ tb->dirty = 1;
+ }
+ }
+ else
+ {
+ if (tb->blank)
+ {
+ tb->blank = 0;
+ tb->dirty = 1;
+ }
+
+ /* We know that we at least have an up_glyph. Well, no, we
+ don't. The user may have changed the button glyph on us. */
+ if (CONSP (glyphs))
+ {
+ if (!EQ (XCAR (glyphs), tb->up_glyph))
+ {
+ tb->up_glyph = XCAR (glyphs);
+ tb->dirty = 1;
+ }
+ glyphs = XCDR (glyphs);
+ }
+ else
+ tb->up_glyph = Qnil;
+
+ /* We might have a down_glyph. */
+ if (CONSP (glyphs))
+ {
+ if (!EQ (XCAR (glyphs), tb->down_glyph))
+ {
+ tb->down_glyph = XCAR (glyphs);
+ tb->dirty = 1;
+ }
+ glyphs = XCDR (glyphs);
+ }
+ else
+ tb->down_glyph = Qnil;
+
+ /* We might have a disabled_glyph. */
+ if (CONSP (glyphs))
+ {
+ if (!EQ (XCAR (glyphs), tb->disabled_glyph))
+ {
+ tb->disabled_glyph = XCAR (glyphs);
+ tb->dirty = 1;
+ }
+ glyphs = XCDR (glyphs);
+ }
+ else
+ tb->disabled_glyph = Qnil;
+
+ /* We might have a cap_up_glyph. */
+ if (CONSP (glyphs))
+ {
+ if (!EQ (XCAR (glyphs), tb->cap_up_glyph))
+ {
+ tb->cap_up_glyph = XCAR (glyphs);
+ tb->dirty = 1;
+ }
+ glyphs = XCDR (glyphs);
+ }
+ else
+ tb->cap_up_glyph = Qnil;
+
+ /* We might have a cap_down_glyph. */
+ if (CONSP (glyphs))
+ {
+ if (!EQ (XCAR (glyphs), tb->cap_down_glyph))
+ {
+ tb->cap_down_glyph = XCAR (glyphs);
+ tb->dirty = 1;
+ }
+ glyphs = XCDR (glyphs);
+ }
+ else
+ tb->cap_down_glyph = Qnil;
+
+ /* We might have a cap_disabled_glyph. */
+ if (CONSP (glyphs))
+ {
+ if (!EQ (XCAR (glyphs), tb->cap_disabled_glyph))
+ {
+ tb->cap_disabled_glyph = XCAR (glyphs);
+ tb->dirty = 1;
+ }
+ }
+ else
+ tb->cap_disabled_glyph = Qnil;
+
+ /* Update the callback. */
+ if (!EQ (tb->callback, elt[1]))
+ {
+ tb->callback = elt[1];
+ /* This does not have an impact on the display properties of the
+ button so we do not mark it as dirty if it has changed. */
+ }
+
+ /* Update the enabled field. */
+ if (!EQ (tb->enabled_p, elt[2]))
+ {
+ tb->enabled_p = elt[2];
+ tb->dirty = 1;
+ }
+
+ /* We always do the following because if the enabled status is
+ determined by a function its decision may change without us being
+ able to detect it. */
+ {
+ int old_enabled = tb->enabled;
+
+ if (NILP (tb->enabled_p))
+ tb->enabled = 0;
+ else if (EQ (tb->enabled_p, Qt))
+ tb->enabled = 1;
+ else
+ {
+ if (NILP (tb->enabled_p) || EQ (tb->enabled_p, Qt))
+ /* short-circuit the common case for speed */
+ tb->enabled = !NILP (tb->enabled_p);
+ else
+ {
+ Lisp_Object result =
+ eval_in_buffer_trapping_errors
+ ("Error in toolbar enabled-p form",
+ XBUFFER
+ (WINDOW_BUFFER
+ (XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f)))),
+ tb->enabled_p);
+ if (UNBOUNDP (result))
+ /* #### if there was an error in the enabled-p
+ form, should we pretend like it's enabled
+ or disabled? */
+ tb->enabled = 0;
+ else
+ tb->enabled = !NILP (result);
+ }
+ }
+
+ if (old_enabled != tb->enabled)
+ tb->dirty = 1;
+ }
+
+ /* Update the help echo string. */
+ if (!EQ (tb->help_string, elt[3]))
+ {
+ tb->help_string = elt[3];
+ /* This does not have an impact on the display properties of the
+ button so we do not mark it as dirty if it has changed. */
+ }
+ }
+
+ /* If this flag changes, the position is changing for sure unless
+ some very unlikely geometry occurs. */
+ if (tb->pushright != pushright)
+ {
+ tb->pushright = pushright;
+ tb->dirty = 1;
+ }
+
+ /* The position and size fields are only manipulated in the
+ device-dependent code. */
+ UNGCPRO;
+ return retval;
+}
+
+void
+mark_frame_toolbar_buttons_dirty (struct frame *f, enum toolbar_pos pos)
+{
+ Lisp_Object button = FRAME_TOOLBAR_BUTTONS (f, pos);
+
+ while (!NILP (button))
+ {
+ struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
+ tb->dirty = 1;
+ button = tb->next;
+ }
+ return;
+}
+
+static Lisp_Object
+compute_frame_toolbar_buttons (struct frame *f, enum toolbar_pos pos,
+ Lisp_Object toolbar)
+{
+ Lisp_Object buttons, prev_button, first_button;
+ Lisp_Object orig_toolbar = toolbar;
+ int pushright_seen = 0;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+
+ first_button = FRAME_TOOLBAR_BUTTONS (f, pos);
+ buttons = prev_button = first_button;
+
+ /* Yes, we're being paranoid. */
+ GCPRO5 (toolbar, buttons, prev_button, first_button, orig_toolbar);
+
+ if (NILP (toolbar))
+ {
+ /* The output mechanisms will take care of clearing the former
+ toolbar. */
+ UNGCPRO;
+ return Qnil;
+ }
+
+ if (!CONSP (toolbar))
+ signal_simple_error ("toolbar description must be a list", toolbar);
+
+ /* First synchronize any existing buttons. */
+ while (!NILP (toolbar) && !NILP (buttons))
+ {
+ struct toolbar_button *tb;
+
+ if (NILP (XCAR (toolbar)))
+ {
+ if (pushright_seen)
+ signal_simple_error
+ ("more than one partition (nil) in toolbar description",
+ orig_toolbar);
+ else
+ pushright_seen = 1;
+ }
+ else
+ {
+ tb = XTOOLBAR_BUTTON (buttons);
+ update_toolbar_button (f, tb, XCAR (toolbar), pushright_seen);
+ prev_button = buttons;
+ buttons = tb->next;
+ }
+
+ toolbar = XCDR (toolbar);
+ }
+
+ /* If we hit the end of the toolbar, then clean up any excess
+ buttons and return. */
+ if (NILP (toolbar))
+ {
+ if (!NILP (buttons))
+ {
+ /* If this is the case the only thing we saw was a
+ pushright marker. */
+ if (EQ (buttons, first_button))
+ {
+ UNGCPRO;
+ return Qnil;
+ }
+ else
+ XTOOLBAR_BUTTON (prev_button)->next = Qnil;
+ }
+ UNGCPRO;
+ return first_button;
+ }
+
+ /* At this point there are more buttons on the toolbar than we
+ actually have in existence. */
+ while (!NILP (toolbar))
+ {
+ Lisp_Object new_button;
+
+ if (NILP (XCAR (toolbar)))
+ {
+ if (pushright_seen)
+ signal_simple_error
+ ("more than one partition (nil) in toolbar description",
+ orig_toolbar);
+ else
+ pushright_seen = 1;
+ }
+ else
+ {
+ new_button = update_toolbar_button (f, NULL, XCAR (toolbar),
+ pushright_seen);
+
+ if (NILP (first_button))
+ {
+ first_button = prev_button = new_button;
+ }
+ else
+ {
+ XTOOLBAR_BUTTON (prev_button)->next = new_button;
+ prev_button = new_button;
+ }
+ }
+
+ toolbar = XCDR (toolbar);
+ }
+
+ UNGCPRO;
+ return first_button;
+}
+
+static void
+set_frame_toolbar (struct frame *f, enum toolbar_pos pos)
+{
+ struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f));
+ Lisp_Object toolbar = w->toolbar[pos];
+ f->toolbar_buttons[pos] = (FRAME_REAL_TOOLBAR_VISIBLE (f, pos)
+ ? compute_frame_toolbar_buttons (f, pos, toolbar)
+ : Qnil);
+}
+
+static void
+compute_frame_toolbars_data (struct frame *f)
+{
+ set_frame_toolbar (f, TOP_TOOLBAR);
+ set_frame_toolbar (f, BOTTOM_TOOLBAR);
+ set_frame_toolbar (f, LEFT_TOOLBAR);
+ set_frame_toolbar (f, RIGHT_TOOLBAR);
+}
+
+void
+update_frame_toolbars (struct frame *f)
+{
+ struct device *d = XDEVICE (f->device);
+
+ if (DEVICE_SUPPORTS_TOOLBARS_P (d)
+ && (f->toolbar_changed || f->frame_changed || f->clear))
+ {
+ int pos;
+
+ /* We're not officially "in redisplay", so we still have a
+ chance to re-layout toolbars and windows. This is done here,
+ because toolbar is the only thing which currently might
+ necesseritate this layout, as it is outside any windows. We
+ take care not to change size if toolbar geometry is really
+ unchanged, as it will hose windows whose pixsizes are not
+ multiple of character sizes */
+
+ for (pos = 0; pos < 4; pos++)
+ if (FRAME_REAL_TOOLBAR_SIZE (f, pos)
+ != FRAME_CURRENT_TOOLBAR_SIZE (f, pos))
+ {
+ int width, height;
+ pixel_to_char_size (f, FRAME_PIXWIDTH (f), FRAME_PIXHEIGHT (f),
+ &width, &height);
+ change_frame_size (f, height, width, 0);
+ break;
+ }
+
+ for (pos = 0; pos < 4; pos++)
+ f->current_toolbar_size[pos] = FRAME_REAL_TOOLBAR_SIZE (f, pos);
+
+ /* Removed the check for the minibuffer here. We handle this
+ more correctly now by consistently using
+ FRAME_LAST_NONMINIBUF_WINDOW instead of FRAME_SELECTED_WINDOW
+ throughout the toolbar code. */
+ compute_frame_toolbars_data (f);
+
+ DEVMETH (d, output_frame_toolbars, (f));
+ }
+
+ f->toolbar_changed = 0;
+}
+
+void
+init_frame_toolbars (struct frame *f)
+{
+ struct device *d = XDEVICE (f->device);
+
+ if (DEVICE_SUPPORTS_TOOLBARS_P (d))
+ {
+ Lisp_Object frame;
+ int pos;
+
+ compute_frame_toolbars_data (f);
+ XSETFRAME (frame, f);
+ call_critical_lisp_code (XDEVICE (FRAME_DEVICE (f)),
+ Qinit_toolbar_from_resources,
+ frame);
+ MAYBE_DEVMETH (d, initialize_frame_toolbars, (f));
+
+ /* We are here as far in frame creation so cached specifiers are
+ already recomputed, and possibly modified by resource
+ initialization. Remember current toolbar geometry so next
+ redisplay will not needlessly relayout toolbars. */
+ for (pos = 0; pos < 4; pos++)
+ f->current_toolbar_size[pos] = FRAME_REAL_TOOLBAR_SIZE (f, pos);
+ }
+}
+
+void
+init_device_toolbars (struct device *d)
+{
+ Lisp_Object device;
+
+ XSETDEVICE (device, d);
+ if (DEVICE_SUPPORTS_TOOLBARS_P (d))
+ call_critical_lisp_code (d,
+ Qinit_toolbar_from_resources,
+ device);
+}
+
+void
+init_global_toolbars (struct device *d)
+{
+ if (DEVICE_SUPPORTS_TOOLBARS_P (d))
+ call_critical_lisp_code (d,
+ Qinit_toolbar_from_resources,
+ Qglobal);
+}
+
+void
+free_frame_toolbars (struct frame *f)
+{
+ /* If we had directly allocated any memory for the toolbars instead
+ of using all Lisp_Objects this is where we would now free it. */
+
+ MAYBE_FRAMEMETH (f, free_frame_toolbars, (f));
+}
+
+void
+get_toolbar_coords (struct frame *f, enum toolbar_pos pos, int *x, int *y,
+ int *width, int *height, int *vert, int for_layout)
+{
+ int visible_top_toolbar_height, visible_bottom_toolbar_height;
+ int adjust = (for_layout ? 1 : 0);
+
+ /* The top and bottom toolbars take precedence over the left and
+ right. */
+ visible_top_toolbar_height = (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f)
+ ? FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) +
+ 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f)
+ : 0);
+ visible_bottom_toolbar_height = (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f)
+ ? FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) +
+ 2 *
+ FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)
+ : 0);
+
+ /* We adjust the width and height by one to give us a narrow border
+ at the outside edges. However, when we are simply determining
+ toolbar location we don't want to do that. */
+
+ switch (pos)
+ {
+ case TOP_TOOLBAR:
+ *x = 1;
+ *y = 0; /* #### should be 1 if no menubar */
+ *width = FRAME_PIXWIDTH (f) - 2;
+ *height = FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) +
+ 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) - adjust;
+ *vert = 0;
+ break;
+ case BOTTOM_TOOLBAR:
+ *x = 1;
+ *y = FRAME_PIXHEIGHT (f) - FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
+ 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f);
+ *width = FRAME_PIXWIDTH (f) - 2;
+ *height = FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) +
+ 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f) - adjust;
+ *vert = 0;
+ break;
+ case LEFT_TOOLBAR:
+ *x = 1;
+ *y = visible_top_toolbar_height;
+ *width = FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) +
+ 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) - adjust;
+ *height = (FRAME_PIXHEIGHT (f) - visible_top_toolbar_height -
+ visible_bottom_toolbar_height - 1);
+ *vert = 1;
+ break;
+ case RIGHT_TOOLBAR:
+ *x = FRAME_PIXWIDTH (f) - FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
+ 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f);
+ *y = visible_top_toolbar_height;
+ *width = FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) +
+ 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f) - adjust;
+ *height = (FRAME_PIXHEIGHT (f) - visible_top_toolbar_height -
+ visible_bottom_toolbar_height);
+ *vert = 1;
+ break;
+ default:
+ abort ();
+ }
+}
+
+#define CHECK_TOOLBAR(pos) \
+ do \
+ { \
+ get_toolbar_coords (f, pos, &x, &y, &width, &height, &vert, 0); \
+ if ((x_coord >= x) && (x_coord < (x + width))) \
+ { \
+ if ((y_coord >= y) && (y_coord < (y + height))) \
+ return FRAME_TOOLBAR_BUTTONS (f, pos); \
+ } \
+ } while (0)
+
+static Lisp_Object
+toolbar_buttons_at_pixpos (struct frame *f, int x_coord, int y_coord)
+{
+ int x, y, width, height, vert;
+
+ if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
+ CHECK_TOOLBAR (TOP_TOOLBAR);
+ if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
+ CHECK_TOOLBAR (BOTTOM_TOOLBAR);
+ if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
+ CHECK_TOOLBAR (LEFT_TOOLBAR);
+ if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
+ CHECK_TOOLBAR (RIGHT_TOOLBAR);
+
+ return Qnil;
+}
+#undef CHECK_TOOLBAR
+
+/* The device dependent code actually does the work of positioning the
+ buttons, but we are free to access that information at this
+ level. */
+Lisp_Object
+toolbar_button_at_pixpos (struct frame *f, int x_coord, int y_coord)
+{
+ Lisp_Object buttons = toolbar_buttons_at_pixpos (f, x_coord, y_coord);
+
+ if (NILP (buttons))
+ return Qnil;
+
+ while (!NILP (buttons))
+ {
+ struct toolbar_button *tb = XTOOLBAR_BUTTON (buttons);
+
+ if ((x_coord >= tb->x) && (x_coord < (tb->x + tb->width)))
+ {
+ if ((y_coord >= tb->y) && (y_coord < (tb->y + tb->height)))
+ {
+ /* If we are over a blank, return nil. */
+ if (tb->blank)
+ return Qnil;
+ else
+ return buttons;
+ }
+ }
+
+ buttons = tb->next;
+ }
+
+ /* We must be over a blank in the toolbar. */
+ return Qnil;
+}
+
+\f
+/************************************************************************/
+/* Toolbar specifier type */
+/************************************************************************/
+
+DEFINE_SPECIFIER_TYPE (toolbar);
+
+#define CTB_ERROR(msg) \
+ do \
+ { \
+ maybe_signal_simple_error (msg, button, Qtoolbar, errb); \
+ RETURN__ Qnil; \
+ } \
+ while (0)
+
+/* Returns Q_style if key was :style, Qt if ok otherwise, Qnil if error. */
+static Lisp_Object
+check_toolbar_button_keywords (Lisp_Object button, Lisp_Object key,
+ Lisp_Object val, Error_behavior errb)
+{
+ if (!KEYWORDP (key))
+ {
+ maybe_signal_simple_error_2 ("not a keyword", key, button, Qtoolbar,
+ errb);
+ return Qnil;
+ }
+
+ if (EQ (key, Q_style))
+ {
+ if (!EQ (val, Q2D)
+ && !EQ (val, Q3D)
+ && !EQ (val, Q2d)
+ && !EQ (val, Q3d))
+ CTB_ERROR ("unrecognized toolbar blank style");
+
+ return Q_style;
+ }
+ else if (EQ (key, Q_size))
+ {
+ if (!NATNUMP (val))
+ CTB_ERROR ("invalid toolbar blank size");
+ }
+ else
+ {
+ CTB_ERROR ("invalid toolbar blank keyword");
+ }
+
+ return Qt;
+}
+
+/* toolbar button spec is [pixmap-pair function enabled-p help]
+ or [:style 2d-or-3d :size width-or-height] */
+
+DEFUN ("check-toolbar-button-syntax", Fcheck_toolbar_button_syntax, 1, 2, 0, /*
+Verify the syntax of entry BUTTON in a toolbar description list.
+If you want to verify the syntax of a toolbar description list as a
+whole, use `check-valid-instantiator' with a specifier type of 'toolbar.
+*/
+ (button, no_error))
+{
+ Lisp_Object *elt, glyphs, value;
+ int len;
+ Error_behavior errb = decode_error_behavior_flag (no_error);
+
+ if (!VECTORP (button))
+ CTB_ERROR ("toolbar button descriptors must be vectors");
+ elt = XVECTOR_DATA (button);
+
+ if (XVECTOR_LENGTH (button) == 2)
+ {
+ if (!EQ (Q_style, check_toolbar_button_keywords (button, elt[0],
+ elt[1], errb)))
+ CTB_ERROR ("must specify toolbar blank style");
+
+ return Qt;
+ }
+
+ if (XVECTOR_LENGTH (button) != 4)
+ CTB_ERROR ("toolbar button descriptors must be 2 or 4 long");
+
+ /* The first element must be a list of glyphs of length 1-6. The
+ first entry is the pixmap for the up state, the second for the
+ down state, the third for the disabled state, the fourth for the
+ captioned up state, the fifth for the captioned down state and
+ the sixth for the captioned disabled state. Only the up state is
+ mandatory. */
+ if (!CONSP (elt[0]))
+ {
+ /* We can't check the buffer-local here because we don't know
+ which buffer to check in. #### I think this is a bad thing.
+ See if we can't get enough information to this function so
+ that it can check.
+
+ #### Wrong. We shouldn't be checking the value at all here.
+ The user might set or change the value at any time. */
+ value = Fsymbol_value (elt[0]);
+
+ if (!CONSP (value))
+ {
+ if (KEYWORDP (elt[0]))
+ {
+ int fsty = 0;
+
+ if (EQ (Q_style, check_toolbar_button_keywords (button, elt[0],
+ elt[1],
+ errb)))
+ fsty++;
+
+ if (EQ (Q_style, check_toolbar_button_keywords (button, elt[2],
+ elt[3],
+ errb)))
+ fsty++;
+
+ if (!fsty)
+ CTB_ERROR ("must specify toolbar blank style");
+ else if (EQ (elt[0], elt[2]))
+ CTB_ERROR
+ ("duplicate keywords in toolbar button blank description");
+
+ return Qt;
+ }
+ else
+ CTB_ERROR ("first element of button must be a list (of glyphs)");
+ }
+ }
+ else
+ value = elt[0];
+
+ len = XINT (Flength (value));
+ if (len < 1)
+ CTB_ERROR ("toolbar button glyph list must have at least 1 entry");
+
+ if (len > 6)
+ CTB_ERROR ("toolbar button glyph list can have at most 6 entries");
+
+ glyphs = value;
+ while (!NILP (glyphs))
+ {
+ if (!GLYPHP (XCAR (glyphs)))
+ {
+ /* We allow nil for the down and disabled glyphs but not for
+ the up glyph. */
+ if (EQ (glyphs, value) || !NILP (XCAR (glyphs)))
+ {
+ CTB_ERROR
+ ("all elements of toolbar button glyph list must be glyphs.");
+ }
+ }
+ glyphs = XCDR (glyphs);
+ }
+
+ /* The second element is the function to run when the button is
+ activated. We do not do any checking on it because it is legal
+ for the function to not be defined until after the toolbar is.
+ It is the user's problem to get this right.
+
+ The third element is either a boolean indicating the enabled
+ status or a function used to determine it. Again, it is the
+ user's problem if this is wrong.
+
+ The fourth element, if not nil, must be a string which will be
+ displayed as the help echo. */
+
+ /* #### This should be allowed to be a function returning a string
+ as well as just a string. */
+ if (!NILP (elt[3]) && !STRINGP (elt[3]))
+ CTB_ERROR ("toolbar button help echo string must be a string");
+
+ return Qt;
+}
+#undef CTB_ERROR
+
+static void
+toolbar_validate (Lisp_Object instantiator)
+{
+ int pushright_seen = 0;
+ Lisp_Object rest;
+
+ if (NILP (instantiator))
+ return;
+
+ if (!CONSP (instantiator))
+ signal_simple_error ("toolbar spec must be list or nil", instantiator);
+
+ for (rest = instantiator; !NILP (rest); rest = XCDR (rest))
+ {
+ if (!CONSP (rest))
+ signal_simple_error ("bad list in toolbar spec", instantiator);
+
+ if (NILP (XCAR (rest)))
+ {
+ if (pushright_seen)
+ error
+ ("more than one partition (nil) in instantiator description");
+ else
+ pushright_seen = 1;
+ }
+ else
+ Fcheck_toolbar_button_syntax (XCAR (rest), Qnil);
+ }
+}
+
+static void
+toolbar_after_change (Lisp_Object specifier, Lisp_Object locale)
+{
+ /* #### This is overkill. I really need to rethink the after-change
+ functions to make them easier to use. */
+ MARK_TOOLBAR_CHANGED;
+}
+
+DEFUN ("toolbar-specifier-p", Ftoolbar_specifier_p, 1, 1, 0, /*
+Return non-nil if OBJECT is a toolbar specifier.
+Toolbar specifiers are used to specify the format of a toolbar.
+The values of the variables `default-toolbar', `top-toolbar',
+`left-toolbar', `right-toolbar', and `bottom-toolbar' are always
+toolbar specifiers.
+
+Valid toolbar instantiators are called "toolbar descriptors"
+and are lists of vectors. See `default-toolbar' for a description
+of the exact format.
+*/
+ (object))
+{
+ return TOOLBAR_SPECIFIERP (object) ? Qt : Qnil;
+}
+
+\f
+/*
+ Helper for invalidating the real specifier when default
+ specifier caching changes
+*/
+static void
+recompute_overlaying_specifier (Lisp_Object real_one[4])
+{
+ enum toolbar_pos pos = decode_toolbar_position (Vdefault_toolbar_position);
+ Fset_specifier_dirty_flag (real_one[pos]);
+}
+
+static void
+toolbar_specs_changed (Lisp_Object specifier, struct window *w,
+ Lisp_Object oldval)
+{
+ /* This could be smarter but I doubt that it would make any
+ noticable difference given the infrequency with which this is
+ probably going to be called.
+ */
+ MARK_TOOLBAR_CHANGED;
+}
+
+static void
+default_toolbar_specs_changed (Lisp_Object specifier, struct window *w,
+ Lisp_Object oldval)
+{
+ recompute_overlaying_specifier (Vtoolbar);
+}
+
+static void
+default_toolbar_size_changed_in_frame (Lisp_Object specifier, struct frame *f,
+ Lisp_Object oldval)
+{
+ recompute_overlaying_specifier (Vtoolbar_size);
+}
+
+static void
+default_toolbar_border_width_changed_in_frame (Lisp_Object specifier,
+ struct frame *f,
+ Lisp_Object oldval)
+{
+ recompute_overlaying_specifier (Vtoolbar_border_width);
+}
+
+static void
+default_toolbar_visible_p_changed_in_frame (Lisp_Object specifier,
+ struct frame *f,
+ Lisp_Object oldval)
+{
+ recompute_overlaying_specifier (Vtoolbar_visible_p);
+}
+
+static void
+toolbar_geometry_changed_in_window (Lisp_Object specifier, struct window *w,
+ Lisp_Object oldval)
+{
+ MARK_TOOLBAR_CHANGED;
+ MARK_WINDOWS_CHANGED (w);
+}
+
+static void
+default_toolbar_size_changed_in_window (Lisp_Object specifier, struct window *w,
+ Lisp_Object oldval)
+{
+ recompute_overlaying_specifier (Vtoolbar_size);
+}
+
+static void
+default_toolbar_border_width_changed_in_window (Lisp_Object specifier,
+ struct window *w,
+ Lisp_Object oldval)
+{
+ recompute_overlaying_specifier (Vtoolbar_border_width);
+}
+
+static void
+default_toolbar_visible_p_changed_in_window (Lisp_Object specifier,
+ struct window *w,
+ Lisp_Object oldval)
+{
+ recompute_overlaying_specifier (Vtoolbar_visible_p);
+}
+
+static void
+toolbar_buttons_captioned_p_changed (Lisp_Object specifier, struct window *w,
+ Lisp_Object oldval)
+{
+ /* This could be smarter but I doubt that it would make any
+ noticable difference given the infrequency with which this is
+ probably going to be called. */
+ MARK_TOOLBAR_CHANGED;
+}
+
+\f
+void
+syms_of_toolbar (void)
+{
+ defsymbol (&Qtoolbar_buttonp, "toolbar-button-p");
+ defsymbol (&Q2D, "2D");
+ defsymbol (&Q3D, "3D");
+ defsymbol (&Q2d, "2d");
+ defsymbol (&Q3d, "3d");
+ defsymbol (&Q_size, ":size"); Fset (Q_size, Q_size);
+
+ defsymbol (&Qinit_toolbar_from_resources, "init-toolbar-from-resources");
+ DEFSUBR (Ftoolbar_button_p);
+ DEFSUBR (Ftoolbar_button_callback);
+ DEFSUBR (Ftoolbar_button_help_string);
+ DEFSUBR (Ftoolbar_button_enabled_p);
+ DEFSUBR (Fset_toolbar_button_down_flag);
+ DEFSUBR (Fcheck_toolbar_button_syntax);
+ DEFSUBR (Fset_default_toolbar_position);
+ DEFSUBR (Fdefault_toolbar_position);
+ DEFSUBR (Ftoolbar_specifier_p);
+}
+
+void
+vars_of_toolbar (void)
+{
+ staticpro (&Vdefault_toolbar_position);
+ Vdefault_toolbar_position = Qtop;
+
+#ifdef HAVE_WINDOW_SYSTEM
+ Fprovide (Qtoolbar);
+#endif
+}
+
+void
+specifier_type_create_toolbar (void)
+{
+ INITIALIZE_SPECIFIER_TYPE (toolbar, "toolbar", "toolbar-specifier-p");
+
+ SPECIFIER_HAS_METHOD (toolbar, validate);
+ SPECIFIER_HAS_METHOD (toolbar, after_change);
+}
+
+void
+specifier_vars_of_toolbar (void)
+{
+ Lisp_Object fb;
+
+ DEFVAR_SPECIFIER ("default-toolbar", &Vdefault_toolbar /*
+Specifier for a fallback toolbar.
+Use `set-specifier' to change this.
+
+The position of this toolbar is specified in the function
+`default-toolbar-position'. If the corresponding position-specific
+toolbar (e.g. `top-toolbar' if `default-toolbar-position' is 'top)
+does not specify a toolbar in a particular domain (usually a window),
+then the value of `default-toolbar' in that domain, if any, will be
+used instead.
+
+Note that the toolbar at any particular position will not be
+displayed unless its visibility flag is true and its thickness
+\(width or height, depending on orientation) is non-zero. The
+visibility is controlled by the specifiers `top-toolbar-visible-p',
+`bottom-toolbar-visible-p', `left-toolbar-visible-p', and
+`right-toolbar-visible-p', and the thickness is controlled by the
+specifiers `top-toolbar-height', `bottom-toolbar-height',
+`left-toolbar-width', and `right-toolbar-width'.
+
+Note that one of the four visibility specifiers inherits from
+`default-toolbar-visibility' and one of the four thickness
+specifiers inherits from either `default-toolbar-width' or
+`default-toolbar-height' (depending on orientation), just
+like for the toolbar description specifiers (e.g. `top-toolbar')
+mentioned above.
+
+Therefore, if you are setting `default-toolbar', you should control
+the visibility and thickness using `default-toolbar-visible-p',
+`default-toolbar-width', and `default-toolbar-height', rather than
+using position-specific specifiers. That way, you will get sane
+behavior if the user changes the default toolbar position.
+
+The format of the instantiator for a toolbar is a list of
+toolbar-button-descriptors. Each toolbar-button-descriptor
+is a vector in one of the following formats:
+
+ [GLYPH-LIST FUNCTION ENABLED-P HELP] or
+ [:style 2D-OR-3D] or
+ [:style 2D-OR-3D :size WIDTH-OR-HEIGHT] or
+ [:size WIDTH-OR-HEIGHT :style 2D-OR-3D]
+
+Optionally, one of the toolbar-button-descriptors may be nil
+instead of a vector; this signifies the division between
+the toolbar buttons that are to be displayed flush-left,
+and the buttons to be displayed flush-right.
+
+The first vector format above specifies a normal toolbar button;
+the others specify blank areas in the toolbar.
+
+For the first vector format:
+
+-- GLYPH-LIST should be a list of one to six glyphs (as created by
+ `make-glyph') or a symbol whose value is such a list. The first
+ glyph, which must be provided, is the glyph used to display the
+ toolbar button when it is in the "up" (not pressed) state. The
+ optional second glyph is for displaying the button when it is in
+ the "down" (pressed) state. The optional third glyph is for when
+ the button is disabled. The optional fourth, fifth and sixth glyphs
+ are used to specify captioned versions for the up, down and disabled
+ states respectively. The function `toolbar-make-button-list' is
+ useful in creating these glyph lists. The specifier variable
+ `toolbar-buttons-captioned-p' controls which glyphs are actually used.
+
+-- Even if you do not provide separate down-state and disabled-state
+ glyphs, the user will still get visual feedback to indicate which
+ state the button is in. Buttons in the up-state are displayed
+ with a shadowed border that gives a raised appearance to the
+ button. Buttons in the down-state are displayed with shadows that
+ give a recessed appearance. Buttons in the disabled state are
+ displayed with no shadows, giving a 2-d effect.
+
+-- If some of the toolbar glyphs are not provided, they inherit as follows:
+
+ UP: up
+ DOWN: down -> up
+ DISABLED: disabled -> up
+ CAP-UP: cap-up -> up
+ CAP-DOWN: cap-down -> cap-up -> down -> up
+ CAP-DISABLED: cap-disabled -> cap-up -> disabled -> up
+
+-- The second element FUNCTION is a function to be called when the
+ toolbar button is activated (i.e. when the mouse is released over
+ the toolbar button, if the press occurred in the toolbar). It
+ can be any form accepted by `call-interactively', since this is
+ how it is invoked.
+
+-- The third element ENABLED-P specifies whether the toolbar button
+ is enabled (disabled buttons do nothing when they are activated,
+ and are displayed differently; see above). It should be either
+ a boolean or a form that evaluates to a boolean.
+
+-- The fourth element HELP, if non-nil, should be a string. This
+ string is displayed in the echo area when the mouse passes over
+ the toolbar button.
+
+For the other vector formats (specifying blank areas of the toolbar):
+
+-- 2D-OR-3D should be one of the symbols '2d or '3d, indicating
+ whether the area is displayed with shadows (giving it a raised,
+ 3-d appearance) or without shadows (giving it a flat appearance).
+
+-- WIDTH-OR-HEIGHT specifies the length, in pixels, of the blank
+ area. If omitted, it defaults to a device-specific value
+ (8 pixels for X devices).
+*/ );
+
+ Vdefault_toolbar = Fmake_specifier (Qtoolbar);
+ /* #### It would be even nicer if the specifier caching
+ automatically knew about specifier fallbacks, so we didn't
+ have to do it ourselves. */
+ set_specifier_caching (Vdefault_toolbar,
+ slot_offset (struct window,
+ default_toolbar),
+ default_toolbar_specs_changed,
+ 0, 0);
+
+ DEFVAR_SPECIFIER ("top-toolbar",
+ &Vtoolbar[TOP_TOOLBAR] /*
+Specifier for the toolbar at the top of the frame.
+Use `set-specifier' to change this.
+See `default-toolbar' for a description of a valid toolbar instantiator.
+*/ );
+ Vtoolbar[TOP_TOOLBAR] = Fmake_specifier (Qtoolbar);
+ set_specifier_caching (Vtoolbar[TOP_TOOLBAR],
+ slot_offset (struct window,
+ toolbar[TOP_TOOLBAR]),
+ toolbar_specs_changed,
+ 0, 0);
+
+ DEFVAR_SPECIFIER ("bottom-toolbar",
+ &Vtoolbar[BOTTOM_TOOLBAR] /*
+Specifier for the toolbar at the bottom of the frame.
+Use `set-specifier' to change this.
+See `default-toolbar' for a description of a valid toolbar instantiator.
+
+Note that, unless the `default-toolbar-position' is `bottom', by
+default the height of the bottom toolbar (controlled by
+`bottom-toolbar-height') is 0; thus, a bottom toolbar will not be
+displayed even if you provide a value for `bottom-toolbar'.
+*/ );
+ Vtoolbar[BOTTOM_TOOLBAR] = Fmake_specifier (Qtoolbar);
+ set_specifier_caching (Vtoolbar[BOTTOM_TOOLBAR],
+ slot_offset (struct window,
+ toolbar[BOTTOM_TOOLBAR]),
+ toolbar_specs_changed,
+ 0, 0);
+
+ DEFVAR_SPECIFIER ("left-toolbar",
+ &Vtoolbar[LEFT_TOOLBAR] /*
+Specifier for the toolbar at the left edge of the frame.
+Use `set-specifier' to change this.
+See `default-toolbar' for a description of a valid toolbar instantiator.
+
+Note that, unless the `default-toolbar-position' is `left', by
+default the height of the left toolbar (controlled by
+`left-toolbar-width') is 0; thus, a left toolbar will not be
+displayed even if you provide a value for `left-toolbar'.
+*/ );
+ Vtoolbar[LEFT_TOOLBAR] = Fmake_specifier (Qtoolbar);
+ set_specifier_caching (Vtoolbar[LEFT_TOOLBAR],
+ slot_offset (struct window,
+ toolbar[LEFT_TOOLBAR]),
+ toolbar_specs_changed,
+ 0, 0);
+
+ DEFVAR_SPECIFIER ("right-toolbar",
+ &Vtoolbar[RIGHT_TOOLBAR] /*
+Specifier for the toolbar at the right edge of the frame.
+Use `set-specifier' to change this.
+See `default-toolbar' for a description of a valid toolbar instantiator.
+
+Note that, unless the `default-toolbar-position' is `right', by
+default the height of the right toolbar (controlled by
+`right-toolbar-width') is 0; thus, a right toolbar will not be
+displayed even if you provide a value for `right-toolbar'.
+*/ );
+ Vtoolbar[RIGHT_TOOLBAR] = Fmake_specifier (Qtoolbar);
+ set_specifier_caching (Vtoolbar[RIGHT_TOOLBAR],
+ slot_offset (struct window,
+ toolbar[RIGHT_TOOLBAR]),
+ toolbar_specs_changed,
+ 0, 0);
+
+ /* initially, top inherits from default; this can be
+ changed with `set-default-toolbar-position'. */
+ fb = list1 (Fcons (Qnil, Qnil));
+ set_specifier_fallback (Vdefault_toolbar, fb);
+ set_specifier_fallback (Vtoolbar[TOP_TOOLBAR], Vdefault_toolbar);
+ set_specifier_fallback (Vtoolbar[BOTTOM_TOOLBAR], fb);
+ set_specifier_fallback (Vtoolbar[LEFT_TOOLBAR], fb);
+ set_specifier_fallback (Vtoolbar[RIGHT_TOOLBAR], fb);
+
+ DEFVAR_SPECIFIER ("default-toolbar-height", &Vdefault_toolbar_height /*
+*Height of the default toolbar, if it's oriented horizontally.
+This is a specifier; use `set-specifier' to change it.
+
+The position of the default toolbar is specified by the function
+`set-default-toolbar-position'. If the corresponding position-specific
+toolbar thickness specifier (e.g. `top-toolbar-height' if
+`default-toolbar-position' is 'top) does not specify a thickness in a
+particular domain (a window or a frame), then the value of
+`default-toolbar-height' or `default-toolbar-width' (depending on the
+toolbar orientation) in that domain, if any, will be used instead.
+
+Note that `default-toolbar-height' is only used when
+`default-toolbar-position' is 'top or 'bottom, and `default-toolbar-width'
+is only used when `default-toolbar-position' is 'left or 'right.
+
+Note that all of the position-specific toolbar thickness specifiers
+have a fallback value of zero when they do not correspond to the
+default toolbar. Therefore, you will have to set a non-zero thickness
+value if you want a position-specific toolbar to be displayed.
+
+Internally, toolbar thickness specifiers are instantiated in both
+window and frame domains, for different purposes. The value in the
+domain of a frame's selected window specifies the actual toolbar
+thickness that you will see in that frame. The value in the domain of
+a frame itself specifies the toolbar thickness that is used in frame
+geometry calculations.
+
+Thus, for example, if you set the frame width to 80 characters and the
+left toolbar width for that frame to 68 pixels, then the frame will
+be sized to fit 80 characters plus a 68-pixel left toolbar. If you
+then set the left toolbar width to 0 for a particular buffer (or if
+that buffer does not specify a left toolbar or has a nil value
+specified for `left-toolbar-visible-p'), you will find that, when
+that buffer is displayed in the selected window, the window will have
+a width of 86 or 87 characters -- the frame is sized for a 68-pixel
+left toolbar but the selected window specifies that the left toolbar
+is not visible, so it is expanded to take up the slack.
+*/ );
+ Vdefault_toolbar_height = Fmake_specifier (Qnatnum);
+ set_specifier_caching (Vdefault_toolbar_height,
+ slot_offset (struct window,
+ default_toolbar_height),
+ default_toolbar_size_changed_in_window,
+ slot_offset (struct frame,
+ default_toolbar_height),
+ default_toolbar_size_changed_in_frame);
+
+ DEFVAR_SPECIFIER ("default-toolbar-width", &Vdefault_toolbar_width /*
+*Width of the default toolbar, if it's oriented vertically.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-height' for more information.
+*/ );
+ Vdefault_toolbar_width = Fmake_specifier (Qnatnum);
+ set_specifier_caching (Vdefault_toolbar_width,
+ slot_offset (struct window,
+ default_toolbar_width),
+ default_toolbar_size_changed_in_window,
+ slot_offset (struct frame,
+ default_toolbar_width),
+ default_toolbar_size_changed_in_frame);
+
+ DEFVAR_SPECIFIER ("top-toolbar-height",
+ &Vtoolbar_size[TOP_TOOLBAR] /*
+*Height of the top toolbar.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-height' for more information.
+*/ );
+ Vtoolbar_size[TOP_TOOLBAR] = Fmake_specifier (Qnatnum);
+ set_specifier_caching (Vtoolbar_size[TOP_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_size[TOP_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_size[TOP_TOOLBAR]),
+ frame_size_slipped);
+
+ DEFVAR_SPECIFIER ("bottom-toolbar-height",
+ &Vtoolbar_size[BOTTOM_TOOLBAR] /*
+*Height of the bottom toolbar.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-height' for more information.
+*/ );
+ Vtoolbar_size[BOTTOM_TOOLBAR] = Fmake_specifier (Qnatnum);
+ set_specifier_caching (Vtoolbar_size[BOTTOM_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_size[BOTTOM_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_size[BOTTOM_TOOLBAR]),
+ frame_size_slipped);
+
+ DEFVAR_SPECIFIER ("left-toolbar-width",
+ &Vtoolbar_size[LEFT_TOOLBAR] /*
+*Width of left toolbar.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-height' for more information.
+*/ );
+ Vtoolbar_size[LEFT_TOOLBAR] = Fmake_specifier (Qnatnum);
+ set_specifier_caching (Vtoolbar_size[LEFT_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_size[LEFT_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_size[LEFT_TOOLBAR]),
+ frame_size_slipped);
+
+ DEFVAR_SPECIFIER ("right-toolbar-width",
+ &Vtoolbar_size[RIGHT_TOOLBAR] /*
+*Width of right toolbar.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-height' for more information.
+*/ );
+ Vtoolbar_size[RIGHT_TOOLBAR] = Fmake_specifier (Qnatnum);
+ set_specifier_caching (Vtoolbar_size[RIGHT_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_size[RIGHT_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_size[RIGHT_TOOLBAR]),
+ frame_size_slipped);
+
+ fb = Qnil;
+#ifdef HAVE_TTY
+ fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
+#endif
+#ifdef HAVE_X_WINDOWS
+ fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_HEIGHT)), fb);
+#endif
+#ifdef HAVE_MS_WINDOWS
+ fb = Fcons (Fcons (list1 (Qmswindows),
+ make_int (MSWINDOWS_DEFAULT_TOOLBAR_HEIGHT)), fb);
+#endif
+ if (!NILP (fb))
+ set_specifier_fallback (Vdefault_toolbar_height, fb);
+
+ fb = Qnil;
+#ifdef HAVE_TTY
+ fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
+#endif
+#ifdef HAVE_X_WINDOWS
+ fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_WIDTH)), fb);
+#endif
+#ifdef HAVE_MS_WINDOWS
+ fb = Fcons (Fcons (list1 (Qmswindows),
+ make_int (MSWINDOWS_DEFAULT_TOOLBAR_WIDTH)), fb);
+#endif
+ if (!NILP (fb))
+ set_specifier_fallback (Vdefault_toolbar_width, fb);
+
+ set_specifier_fallback (Vtoolbar_size[TOP_TOOLBAR], Vdefault_toolbar_height);
+ fb = list1 (Fcons (Qnil, Qzero));
+ set_specifier_fallback (Vtoolbar_size[BOTTOM_TOOLBAR], fb);
+ set_specifier_fallback (Vtoolbar_size[LEFT_TOOLBAR], fb);
+ set_specifier_fallback (Vtoolbar_size[RIGHT_TOOLBAR], fb);
+
+ DEFVAR_SPECIFIER ("default-toolbar-border-width",
+ &Vdefault_toolbar_border_width /*
+*Width of the border around the default toolbar.
+This is a specifier; use `set-specifier' to change it.
+
+The position of the default toolbar is specified by the function
+`set-default-toolbar-position'. If the corresponding position-specific
+toolbar border width specifier (e.g. `top-toolbar-border-width' if
+`default-toolbar-position' is 'top) does not specify a border width in a
+particular domain (a window or a frame), then the value of
+`default-toolbar-border-width' in that domain, if any, will be used
+instead.
+
+Internally, toolbar border width specifiers are instantiated in both
+window and frame domains, for different purposes. The value in the
+domain of a frame's selected window specifies the actual toolbar border
+width that you will see in that frame. The value in the domain of a
+frame itself specifies the toolbar border width that is used in frame
+geometry calculations. Changing the border width value in the frame
+domain will result in a size change in the frame itself, while changing
+the value in a window domain will not.
+*/ );
+ Vdefault_toolbar_border_width = Fmake_specifier (Qnatnum);
+ set_specifier_caching (Vdefault_toolbar_border_width,
+ slot_offset (struct window,
+ default_toolbar_border_width),
+ default_toolbar_border_width_changed_in_window,
+ slot_offset (struct frame,
+ default_toolbar_border_width),
+ default_toolbar_border_width_changed_in_frame);
+
+ DEFVAR_SPECIFIER ("top-toolbar-border-width",
+ &Vtoolbar_border_width[TOP_TOOLBAR] /*
+*Border width of the top toolbar.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-height' for more information.
+*/ );
+ Vtoolbar_border_width[TOP_TOOLBAR] = Fmake_specifier (Qnatnum);
+ set_specifier_caching (Vtoolbar_border_width[TOP_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_border_width[TOP_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_border_width[TOP_TOOLBAR]),
+ frame_size_slipped);
+
+ DEFVAR_SPECIFIER ("bottom-toolbar-border-width",
+ &Vtoolbar_border_width[BOTTOM_TOOLBAR] /*
+*Border width of the bottom toolbar.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-height' for more information.
+*/ );
+ Vtoolbar_border_width[BOTTOM_TOOLBAR] = Fmake_specifier (Qnatnum);
+ set_specifier_caching (Vtoolbar_border_width[BOTTOM_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_border_width[BOTTOM_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_border_width[BOTTOM_TOOLBAR]),
+ frame_size_slipped);
+
+ DEFVAR_SPECIFIER ("left-toolbar-border-width",
+ &Vtoolbar_border_width[LEFT_TOOLBAR] /*
+*Border width of left toolbar.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-height' for more information.
+*/ );
+ Vtoolbar_border_width[LEFT_TOOLBAR] = Fmake_specifier (Qnatnum);
+ set_specifier_caching (Vtoolbar_border_width[LEFT_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_border_width[LEFT_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_border_width[LEFT_TOOLBAR]),
+ frame_size_slipped);
+
+ DEFVAR_SPECIFIER ("right-toolbar-border-width",
+ &Vtoolbar_border_width[RIGHT_TOOLBAR] /*
+*Border width of right toolbar.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-height' for more information.
+*/ );
+ Vtoolbar_border_width[RIGHT_TOOLBAR] = Fmake_specifier (Qnatnum);
+ set_specifier_caching (Vtoolbar_border_width[RIGHT_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_border_width[RIGHT_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_border_width[RIGHT_TOOLBAR]),
+ frame_size_slipped);
+
+ fb = Qnil;
+#ifdef HAVE_TTY
+ fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
+#endif
+#ifdef HAVE_X_WINDOWS
+ fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_TOOLBAR_BORDER_WIDTH)), fb);
+#endif
+#ifdef HAVE_MS_WINDOWS
+ fb = Fcons (Fcons (list1 (Qmswindows), make_int (MSWINDOWS_DEFAULT_TOOLBAR_BORDER_WIDTH)), fb);
+#endif
+ if (!NILP (fb))
+ set_specifier_fallback (Vdefault_toolbar_border_width, fb);
+
+ set_specifier_fallback (Vtoolbar_border_width[TOP_TOOLBAR], Vdefault_toolbar_border_width);
+ fb = list1 (Fcons (Qnil, Qzero));
+ set_specifier_fallback (Vtoolbar_border_width[BOTTOM_TOOLBAR], fb);
+ set_specifier_fallback (Vtoolbar_border_width[LEFT_TOOLBAR], fb);
+ set_specifier_fallback (Vtoolbar_border_width[RIGHT_TOOLBAR], fb);
+
+ DEFVAR_SPECIFIER ("default-toolbar-visible-p", &Vdefault_toolbar_visible_p /*
+*Whether the default toolbar is visible.
+This is a specifier; use `set-specifier' to change it.
+
+The position of the default toolbar is specified by the function
+`set-default-toolbar-position'. If the corresponding position-specific
+toolbar visibility specifier (e.g. `top-toolbar-visible-p' if
+`default-toolbar-position' is 'top) does not specify a visible-p value
+in a particular domain (a window or a frame), then the value of
+`default-toolbar-visible-p' in that domain, if any, will be used
+instead.
+
+Both window domains and frame domains are used internally, for
+different purposes. The distinction here is exactly the same as
+for thickness specifiers; see `default-toolbar-height' for more
+information.
+
+`default-toolbar-visible-p' and all of the position-specific toolbar
+visibility specifiers have a fallback value of true.
+*/ );
+ Vdefault_toolbar_visible_p = Fmake_specifier (Qboolean);
+ set_specifier_caching (Vdefault_toolbar_visible_p,
+ slot_offset (struct window,
+ default_toolbar_visible_p),
+ default_toolbar_visible_p_changed_in_window,
+ slot_offset (struct frame,
+ default_toolbar_visible_p),
+ default_toolbar_visible_p_changed_in_frame);
+
+ DEFVAR_SPECIFIER ("top-toolbar-visible-p",
+ &Vtoolbar_visible_p[TOP_TOOLBAR] /*
+*Whether the top toolbar is visible.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-visible-p' for more information.
+*/ );
+ Vtoolbar_visible_p[TOP_TOOLBAR] = Fmake_specifier (Qboolean);
+ set_specifier_caching (Vtoolbar_visible_p[TOP_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_visible_p[TOP_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_visible_p[TOP_TOOLBAR]),
+ frame_size_slipped);
+
+ DEFVAR_SPECIFIER ("bottom-toolbar-visible-p",
+ &Vtoolbar_visible_p[BOTTOM_TOOLBAR] /*
+*Whether the bottom toolbar is visible.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-visible-p' for more information.
+*/ );
+ Vtoolbar_visible_p[BOTTOM_TOOLBAR] = Fmake_specifier (Qboolean);
+ set_specifier_caching (Vtoolbar_visible_p[BOTTOM_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_visible_p[BOTTOM_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_visible_p[BOTTOM_TOOLBAR]),
+ frame_size_slipped);
+
+ DEFVAR_SPECIFIER ("left-toolbar-visible-p",
+ &Vtoolbar_visible_p[LEFT_TOOLBAR] /*
+*Whether the left toolbar is visible.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-visible-p' for more information.
+*/ );
+ Vtoolbar_visible_p[LEFT_TOOLBAR] = Fmake_specifier (Qboolean);
+ set_specifier_caching (Vtoolbar_visible_p[LEFT_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_visible_p[LEFT_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_visible_p[LEFT_TOOLBAR]),
+ frame_size_slipped);
+
+ DEFVAR_SPECIFIER ("right-toolbar-visible-p",
+ &Vtoolbar_visible_p[RIGHT_TOOLBAR] /*
+*Whether the right toolbar is visible.
+This is a specifier; use `set-specifier' to change it.
+
+See `default-toolbar-visible-p' for more information.
+*/ );
+ Vtoolbar_visible_p[RIGHT_TOOLBAR] = Fmake_specifier (Qboolean);
+ set_specifier_caching (Vtoolbar_visible_p[RIGHT_TOOLBAR],
+ slot_offset (struct window,
+ toolbar_visible_p[RIGHT_TOOLBAR]),
+ toolbar_geometry_changed_in_window,
+ slot_offset (struct frame,
+ toolbar_visible_p[RIGHT_TOOLBAR]),
+ frame_size_slipped);
+
+ /* initially, top inherits from default; this can be
+ changed with `set-default-toolbar-position'. */
+ fb = list1 (Fcons (Qnil, Qt));
+ set_specifier_fallback (Vdefault_toolbar_visible_p, fb);
+ set_specifier_fallback (Vtoolbar_visible_p[TOP_TOOLBAR],
+ Vdefault_toolbar_visible_p);
+ set_specifier_fallback (Vtoolbar_visible_p[BOTTOM_TOOLBAR], fb);
+ set_specifier_fallback (Vtoolbar_visible_p[LEFT_TOOLBAR], fb);
+ set_specifier_fallback (Vtoolbar_visible_p[RIGHT_TOOLBAR], fb);
+
+ DEFVAR_SPECIFIER ("toolbar-buttons-captioned-p",
+ &Vtoolbar_buttons_captioned_p /*
+*Whether the toolbar buttons are captioned.
+This will only have a visible effect for those toolbar buttons which had
+captioned versions specified.
+This is a specifier; use `set-specifier' to change it.
+*/ );
+ Vtoolbar_buttons_captioned_p = Fmake_specifier (Qboolean);
+ set_specifier_caching (Vtoolbar_buttons_captioned_p,
+ slot_offset (struct window,
+ toolbar_buttons_captioned_p),
+ toolbar_buttons_captioned_p_changed,
+ 0, 0);
+ set_specifier_fallback (Vtoolbar_buttons_captioned_p,
+ list1 (Fcons (Qnil, Qt)));
+}