1 /* Widget-specific glyph objects.
2 Copyright (C) 1998, 1999, 2000, 2002 Andy Piper.
4 This file is part of XEmacs.
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Synched up with: Not in FSF. */
23 /* written by Andy Piper <andy@xemacs.org> */
40 DEFINE_IMAGE_INSTANTIATOR_FORMAT (button);
41 DEFINE_IMAGE_INSTANTIATOR_FORMAT (combo_box);
42 Lisp_Object Qcombo_box;
43 DEFINE_IMAGE_INSTANTIATOR_FORMAT (edit_field);
44 Lisp_Object Qedit_field;
45 DEFINE_IMAGE_INSTANTIATOR_FORMAT (scrollbar);
46 Lisp_Object Qscrollbar;
47 DEFINE_IMAGE_INSTANTIATOR_FORMAT (widget);
48 DEFINE_IMAGE_INSTANTIATOR_FORMAT (label);
50 DEFINE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge);
51 Lisp_Object Qprogress_gauge;
52 DEFINE_IMAGE_INSTANTIATOR_FORMAT (tree_view);
53 Lisp_Object Qtree_view;
54 DEFINE_IMAGE_INSTANTIATOR_FORMAT (tab_control);
55 Lisp_Object Qtab_control;
56 DEFINE_IMAGE_INSTANTIATOR_FORMAT (layout);
58 DEFINE_IMAGE_INSTANTIATOR_FORMAT (native_layout);
59 Lisp_Object Qnative_layout;
61 Lisp_Object Qetched_in, Qetched_out, Qbevel_in, Qbevel_out;
62 Lisp_Object Qmake_glyph;
63 Lisp_Object Vwidget_border_width;
66 widget_border_width (Lisp_Object domain);
68 widget_spacing (Lisp_Object domain);
69 #define BORDER_FIDDLE_FACTOR 10
71 int debug_widget_instances;
75 - tooltips for controls, especially buttons.
77 - lisp configurable layout.
80 /* In MS-Windows normal windows work in pixels, dialog boxes work in
81 dialog box units. Why? sigh. We could reuse the metrics for dialogs
82 if this were not the case. As it is we have to position things
83 pixel wise. I'm not even sure that X has this problem at least for
86 widget_possible_dest_types (void)
88 return IMAGE_WIDGET_MASK;
92 check_valid_instantiator (Lisp_Object data)
94 Lisp_Object glyph = data;
96 glyph = XSYMBOL (data)->value;
98 if (!CONSP (glyph) && !VECTORP (glyph))
99 invalid_argument ("instantiator item must be a vector", data);
103 check_valid_orientation (Lisp_Object data)
105 if (!EQ (data, Qhorizontal)
107 !EQ (data, Qvertical))
108 invalid_argument ("unknown orientation for layout", data);
112 check_valid_tab_orientation (Lisp_Object data)
121 invalid_argument ("unknown orientation for tab control", data);
125 check_valid_justification (Lisp_Object data)
127 if (!EQ (data, Qleft)
136 invalid_argument ("unknown justification for layout", data);
140 check_valid_border (Lisp_Object data)
142 if (!EQ (data, Qt) && !EQ (data, Qetched_in) && !EQ (data, Qetched_out)
143 && !EQ (data, Qbevel_in) && !EQ (data, Qbevel_out)
144 && !GLYPHP (data) && !VECTORP (data))
145 invalid_argument ("unknown border style for layout", data);
149 check_valid_anything (Lisp_Object data)
154 check_valid_callback (Lisp_Object data)
157 && !COMPILED_FUNCTIONP (data)
160 invalid_argument (":callback must be a function or expression", data);
165 check_valid_int_or_function (Lisp_Object data)
167 if (!INTP (data) && !CONSP (data) && !SYMBOLP (data))
168 invalid_argument ("must be an integer or expresssion", data);
172 check_valid_symbol (Lisp_Object data)
178 check_valid_string_or_vector (Lisp_Object data)
180 if (!STRINGP (data) && !VECTORP (data))
181 invalid_argument (":descriptor must be a string or a vector", data);
185 check_valid_item_list (Lisp_Object items)
190 EXTERNAL_LIST_LOOP (rest, items)
192 if (STRINGP (XCAR (rest)))
193 CHECK_STRING (XCAR (rest));
194 else if (VECTORP (XCAR (rest)))
195 gui_parse_item_keywords (XCAR (rest));
196 else if (LISTP (XCAR (rest)))
197 check_valid_item_list (XCAR (rest));
199 invalid_argument ("Items must be vectors, lists or strings", items);
204 check_valid_instantiator_list (Lisp_Object data)
209 EXTERNAL_LIST_LOOP (rest, data)
211 check_valid_instantiator (XCAR (rest));
216 glyph_instantiator_to_glyph (Lisp_Object sym)
218 /* This function calls lisp. */
219 Lisp_Object glyph = sym;
223 /* if we have a symbol get at the actual data */
225 glyph = XSYMBOL (glyph)->value;
228 glyph = Feval (glyph);
230 /* Be really helpful to the user. */
233 glyph = call1 (Qmake_glyph, glyph);
236 /* substitute the new glyph */
237 RETURN_UNGCPRO (glyph);
241 substitute_keyword_value (Lisp_Object inst, Lisp_Object key, Lisp_Object val)
244 /* substitute the new glyph */
245 for (i = 0; i < XVECTOR_LENGTH (inst); i++)
247 if (EQ (key, XVECTOR_DATA (inst)[i]))
249 XVECTOR_DATA (inst)[i+1] = val;
255 /* Determine the border with of the widget. */
257 widget_border_width (Lisp_Object domain)
259 /* #### FIXME -- need to use specifiers (Vwidget_border_width) for
260 some portion of this. */
261 if (HAS_DEVMETH_P (DOMAIN_XDEVICE (domain),
262 widget_border_width))
263 return DEVMETH (DOMAIN_XDEVICE (domain), widget_border_width, ());
265 return DEFAULT_WIDGET_BORDER_WIDTH;
269 widget_instance_border_width (Lisp_Image_Instance* ii)
271 return widget_border_width (IMAGE_INSTANCE_DOMAIN (ii));
274 /* #### Its not clear to me what the value of logical_unit_height should
275 be, or whether it should even depend on the current
276 image_instance. It really should probably only depend on the
277 default widget face and the domain, however you can envisage users
278 wanting different logical units for nested layouts - so using the
279 properties of the current lahyout is probably not so dumb. */
281 logical_unit_height (Lisp_Object text, Lisp_Object face, Lisp_Object domain)
284 query_string_geometry (text, face,
285 0, &charheight, 0, domain);
286 /* For the returned value to be useful it needs to be big enough to
287 accomodate the largest single-height widget. This is currently
289 return charheight + 2 * widget_spacing (domain)
290 + 4 * widget_border_width (domain);
294 widget_logical_unit_height (Lisp_Image_Instance* ii)
296 return logical_unit_height (NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)) ?
297 NILP (IMAGE_INSTANCE_NAME (ii)) ?
298 Fsymbol_name (Qwidget)
299 : IMAGE_INSTANCE_NAME (ii)
300 : IMAGE_INSTANCE_WIDGET_TEXT (ii),
301 IMAGE_INSTANCE_WIDGET_FACE (ii),
302 IMAGE_INSTANCE_DOMAIN (ii));
305 /* Wire widget property invocations to specific widgets. The problem
306 we are solving here is that when instantiators get converted to
307 instances they lose some type information (they just become
308 subwindows or widgets for example). For widgets we need to preserve
309 this type information so that we can do widget specific operations
310 on the instances. This is encoded in the widget type
311 field. widget_property gets invoked by decoding the primary type
312 (Qwidget), <widget>_property then invokes based on the secondary
313 type (Qedit_field for example). It is debatable whether we should
314 wire things in this generalised way rather than treating widgets
315 specially in image_instance_property. */
317 widget_property (Lisp_Object image_instance, Lisp_Object prop)
319 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
320 struct image_instantiator_methods* meths;
321 #if 0 /* The usefulness of this is dubious. */
322 /* first see if its a general property ... */
323 if (!NILP (Fplist_member (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop)))
324 return Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, Qnil);
326 /* .. then try device specific methods ... */
327 meths = decode_device_ii_format (image_instance_device (image_instance),
328 IMAGE_INSTANCE_WIDGET_TYPE (ii),
330 if (meths && HAS_IIFORMAT_METH_P (meths, property))
331 return IIFORMAT_METH (meths, property, (image_instance, prop));
332 /* ... then format specific methods ... */
333 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
335 if (meths && HAS_IIFORMAT_METH_P (meths, property))
336 return IIFORMAT_METH (meths, property, (image_instance, prop));
341 /* Update the displayed properties of a widget.
343 #### This has been adapted from the original set_property functions
344 and thus reuses the state management of that. A better solution is
345 to simply re-parse the instantiator when items need updating. This
346 make comparing differences much simpler and obviates the need for a
347 lot of the state variables.
349 #### property is still a valid function since we have to be able to
350 extract information from the actual widget.
352 #### update_widget should probably be re-written to use the
353 instantiator. We probably want to keep a record of the differences
354 also to make this easy. We would also need a pending_instantiator
355 so that changes could be delayed. */
357 widget_update (Lisp_Object image_instance, Lisp_Object instantiator)
359 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
360 struct image_instantiator_methods* meths;
363 Lisp_Object text = find_keyword_in_vector (instantiator, Q_text);
364 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
365 Lisp_Object items = find_keyword_in_vector (instantiator, Q_items);
366 Lisp_Object descriptor_item = Qnil;
368 GCPRO1 (descriptor_item);
370 /* Pick up any generic properties that we might need to keep hold
372 #### This is potentially bogus because it is changing the items
373 in place rather than in the pending items. */
376 IMAGE_INSTANCE_WIDGET_TEXT (ii) = text;
377 IMAGE_INSTANCE_TEXT_CHANGED (ii) = 1;
380 /* Retrieve the gui item information. This is easy if we have been
381 provided with a vector, more difficult if we have just been given
384 #### This is inconsistent with instantiation in that you have to
385 have the :descriptor keyword for updates in order to recognise
389 descriptor_item = gui_parse_item_keywords_no_errors (desc);
393 /* Since we are updating the instantiator could be incomplete
394 and hence the gui item descriptor not well formed. We
395 therefore try updating and discard the results if nothing
397 descriptor_item = copy_gui_item (IMAGE_INSTANCE_WIDGET_ITEM (ii));
398 if (!update_gui_item_keywords (descriptor_item, instantiator))
399 descriptor_item = Qnil;
402 /* Record new items for update. *_redisplay will do the
404 if (!EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout)
406 !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qnative_layout))
410 if (NILP (descriptor_item))
411 descriptor_item = IMAGE_INSTANCE_WIDGET_ITEM (ii);
413 check_valid_item_list (items);
414 #ifdef DEBUG_WIDGET_OUTPUT
415 stderr_out ("items for widget %p updated\n",
416 IMAGE_INSTANCE_SUBWINDOW_ID (ii));
418 /* Don't set the actual items since we might decide not to use
419 the new ones (because nothing has really changed). If we did
420 set them and didn't use them then we would get into whole
421 heaps of trouble when the old items get GC'd. */
422 descriptor_item = Fcons (descriptor_item, parse_gui_item_tree_children (items));
424 /* If the descriptor was updated but not the items we need to fill
425 in the `new' items. */
426 else if (!NILP (descriptor_item)
428 CONSP (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
430 descriptor_item = Fcons
432 copy_gui_item_tree (XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii))));
436 if (!NILP (descriptor_item))
438 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = descriptor_item;
439 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 1;
444 /* Now try device specific methods first ... */
445 meths = decode_device_ii_format (image_instance_device (image_instance),
446 IMAGE_INSTANCE_WIDGET_TYPE (ii),
448 MAYBE_IIFORMAT_METH (meths, update, (image_instance, instantiator));
449 /* ... then format specific methods ... */
450 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
452 MAYBE_IIFORMAT_METH (meths, update, (image_instance, instantiator));
453 #if 0 /* The usefulness of this is dubious. */
454 /* we didn't do any device specific properties, so shove the property in our plist. */
455 IMAGE_INSTANCE_WIDGET_PROPS (ii)
456 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
460 /* Like the rest of redisplay, we want widget updates to occur
461 asynchronously. Thus toolkit specific methods for setting
462 properties must be called by redisplay instead of by *_update. Thus
463 *_update records the change and this function actually implements
464 it. We want to be slightly clever about this however by supplying
465 format specific functions for the updates instead of lumping them
466 all into this function. Note that there is no need for format
467 generic functions. This is not the same as widget_update! */
469 redisplay_widget (Lisp_Object widget)
471 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (widget);
472 struct image_instantiator_methods* meths;
474 if (!WIDGET_IMAGE_INSTANCEP (widget)
475 || EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout)
476 || EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qnative_layout))
479 /* Device-format specific methods - e.g. x_tab_control_redisplay () */
480 meths = decode_device_ii_format (image_instance_device (widget),
481 IMAGE_INSTANCE_WIDGET_TYPE (ii),
483 MAYBE_IIFORMAT_METH (meths, redisplay, (widget));
485 /* Device generic methods - e.g. x_redisplay_widget (). We must
486 update the widget's size as it may have been changed by the the
487 layout routines. We also do this here so that explicit resizing
488 from lisp does not result in synchronous updates. Do this last so
489 that format-specific methods have an opportunity to prevent
490 wholesale changes - e.g. rebuilding tabs. */
491 MAYBE_DEVMETH (DOMAIN_XDEVICE (IMAGE_INSTANCE_DOMAIN (ii)),
492 redisplay_widget, (ii));
494 /* Pick up the items we recorded earlier. */
495 if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii))
497 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
498 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii);
499 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil;
503 /* Determine the spacing of the widget. */
505 widget_spacing (Lisp_Object domain)
507 if (HAS_DEVMETH_P (DOMAIN_XDEVICE (domain), widget_spacing))
508 return DEVMETH (DOMAIN_XDEVICE (domain),
509 widget_spacing, (0));
511 return DEFAULT_WIDGET_SPACING;
514 /* Query for a widgets desired geometry. If no type specific method is
515 provided then use the widget text to calculate sizes. */
517 widget_query_geometry (Lisp_Object image_instance,
518 int* width, int* height,
519 enum image_instance_geometry disp, Lisp_Object domain)
521 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
522 struct image_instantiator_methods* meths;
523 Lisp_Object dynamic_width = Qnil;
524 Lisp_Object dynamic_height = Qnil;
526 /* First just set up what we already have. */
527 if (width) *width = IMAGE_INSTANCE_WIDTH (ii);
528 if (height) *height = IMAGE_INSTANCE_HEIGHT (ii);
530 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)
532 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
534 /* .. then try device specific methods ... */
535 meths = decode_device_ii_format (image_instance_device (image_instance),
536 IMAGE_INSTANCE_WIDGET_TYPE (ii),
538 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
539 IIFORMAT_METH (meths, query_geometry, (image_instance,
544 /* ... then format specific methods ... */
545 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
547 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
548 IIFORMAT_METH (meths, query_geometry, (image_instance,
555 /* Then if we are allowed to resize the widget, make the
556 size the same as the text dimensions. */
557 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
558 IMAGE_INSTANCE_WIDGET_FACE (ii),
560 /* Adjust the size for borders. */
561 if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
562 *width = w + 2 * widget_instance_border_width (ii);
563 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
564 *height = h + 2 * widget_instance_border_width (ii);
567 /* Finish off with dynamic sizing. */
568 if (!NILP (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii)))
570 dynamic_width = Feval (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii));
571 if (INTP (dynamic_width))
572 *width = XINT (dynamic_width);
574 if (!NILP (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii)))
576 dynamic_height = Feval (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii));
577 if (INTP (dynamic_height))
578 *height = XINT (dynamic_height);
584 widget_layout (Lisp_Object image_instance,
585 int width, int height, int xoffset, int yoffset,
588 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
589 struct image_instantiator_methods* meths;
591 /* .. then try device specific methods ... */
592 meths = decode_device_ii_format (image_instance_device (image_instance),
593 IMAGE_INSTANCE_WIDGET_TYPE (ii),
595 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
596 return IIFORMAT_METH (meths, layout, (image_instance,
597 width, height, xoffset, yoffset,
601 /* ... then format specific methods ... */
602 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
604 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
605 return IIFORMAT_METH (meths, layout, (image_instance,
606 width, height, xoffset, yoffset,
613 widget_validate (Lisp_Object instantiator)
615 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
618 syntax_error ("Must supply :descriptor", instantiator);
621 gui_parse_item_keywords (desc);
623 if (!NILP (find_keyword_in_vector (instantiator, Q_width))
624 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width)))
625 syntax_error ("Must supply only one of :width and :pixel-width", instantiator);
627 if (!NILP (find_keyword_in_vector (instantiator, Q_height))
628 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height)))
629 syntax_error ("Must supply only one of :height and :pixel-height", instantiator);
633 combo_box_validate (Lisp_Object instantiator)
635 widget_validate (instantiator);
636 if (NILP (find_keyword_in_vector (instantiator, Q_items)))
637 syntax_error ("Must supply item list", instantiator);
640 /* we need to convert things like glyphs to images, eval expressions
643 widget_normalize (Lisp_Object inst, Lisp_Object console_type,
644 Lisp_Object dest_mask)
646 /* This function can call lisp */
647 Lisp_Object glyph = find_keyword_in_vector (inst, Q_image);
649 /* we need to eval glyph if its an expression, we do this for the
650 same reasons we normalize file to data.
652 #### should just normalize the data. */
655 substitute_keyword_value (inst, Q_image, glyph_instantiator_to_glyph (glyph));
662 initialize_widget_image_instance (Lisp_Image_Instance *ii, Lisp_Object type)
664 /* initialize_subwindow_image_instance (ii);*/
665 IMAGE_INSTANCE_WIDGET_TYPE (ii) = type;
666 IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil;
667 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Qnil);
668 IMAGE_INSTANCE_WIDGET_ITEMS (ii) = allocate_gui_item ();
669 IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = Qnil;
670 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil;
671 IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii) = Qnil;
672 IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii) = Qnil;
673 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 1;
674 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 1;
675 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_HORIZONTAL;
676 IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = 0;
677 IMAGE_INSTANCE_SUBWINDOW_V_JUSTIFY (ii) = 0;
680 /* Instantiate a button widget. Unfortunately instantiated widgets are
681 particular to a frame since they need to have a parent. It's not
682 like images where you just select the image into the context you
683 want to display it in and BitBlt it. So image instances can have a
684 many-to-one relationship with things you see, whereas widgets can
685 only be one-to-one (i.e. per frame) */
687 widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
688 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
689 int dest_mask, Lisp_Object domain)
691 /* #### practically all of this should be moved to widget_update()
692 so that users can dynamically change all possible widget
694 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
695 Lisp_Object face = find_keyword_in_vector (instantiator, Q_face);
696 Lisp_Object height = find_keyword_in_vector (instantiator, Q_height);
697 Lisp_Object width = find_keyword_in_vector (instantiator, Q_width);
698 Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width);
699 Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height);
700 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
701 Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image);
702 Lisp_Object items = find_keyword_in_vector (instantiator, Q_items);
703 Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
704 Lisp_Object mwidth = find_keyword_in_vector (instantiator, Q_margin_width);
705 Lisp_Object ifocus = find_keyword_in_vector (instantiator, Q_initial_focus);
706 int pw=0, ph=0, tw=0, th=0;
708 /* this just does pixel type sizing */
709 subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
712 if (!(dest_mask & IMAGE_WIDGET_MASK))
713 incompatible_image_types (instantiator, dest_mask, IMAGE_WIDGET_MASK);
715 initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]);
717 IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
719 /* retrieve the fg and bg colors */
721 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Fget_face (face));
723 /* Retrieve the gui item information. This is easy if we have been
724 provided with a vector, more difficult if we have just been given
725 keywords. Note that standard gui descriptor shortcuts will not work
726 because of keyword parsing.
728 #### This is bogus in that descriptor and items share the same slot,
729 we should rationalize. */
732 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
733 gui_parse_item_keywords_no_errors (desc);
737 /* big cheat - we rely on the fact that a gui item looks like an instantiator */
738 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
739 widget_gui_parse_item_keywords (instantiator);
742 /* Pick up the orientation before we do our first layout. */
743 if (EQ (orient, Qleft) || EQ (orient, Qright) || EQ (orient, Qvertical))
744 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_VERTICAL;
746 /* parse more gui items out of the properties */
747 if (!NILP (items) && !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout)
748 && !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qnative_layout))
750 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
751 Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii),
752 parse_gui_item_tree_children (items));
755 /* Normalize size information. We now only assign sizes if the user
756 gives us some explicitly, or there are some constraints that we
757 can't change later on. Otherwise we postpone sizing until query
758 geometry gets called. */
759 if (!NILP (pixwidth)) /* pixwidth takes precendent */
761 if (!INTP (pixwidth))
762 IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii) = pixwidth;
765 pw = XINT (pixwidth);
766 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
769 else if (!NILP (width))
772 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
775 if (!NILP (pixheight))
777 if (!INTP (pixheight))
778 IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii) = pixheight;
781 ph = XINT (pixheight);
782 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
785 else if (!NILP (height) && XINT (height) > 1)
788 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
791 /* Taking the default face information when the user has specified
792 size in characters is probably as good as any since the widget
793 face is more likely to be proportional and thus give inadequate
794 results. Using character sizes can only ever be approximate
795 anyway. :height is measured in logical characters which take into
796 account the borders and spacing on widgets. */
800 default_face_font_info (domain, 0, 0, 0, &charwidth, 0);
801 pw = ROUND_UP (charwidth * tw + 4 * widget_instance_border_width (ii), charwidth);
804 /* For heights the widget face is more appropriate. */
808 if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
810 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
811 IMAGE_INSTANCE_WIDGET_FACE (ii),
812 0, &charheight, 0, domain);
816 default_face_font_info (domain, 0, 0, &charheight, 0, 0);
818 ph = (charheight + 2 * widget_instance_border_width (ii)) * th;
820 /* For heights > 1 use logical units. */
823 ph = widget_logical_unit_height (ii) * th;
826 /* for a widget with an image pick up the dimensions from that */
830 pw = glyph_width (glyph, image_instance) + 2 * widget_instance_border_width (ii);
832 ph = glyph_height (glyph, image_instance) + 2 * widget_instance_border_width (ii);
833 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
834 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
837 /* Pick up the margin width. */
839 IMAGE_INSTANCE_MARGIN_WIDTH (ii) = XINT (mwidth);
841 IMAGE_INSTANCE_WANTS_INITIAL_FOCUS (ii) = !NILP (ifocus);
843 /* Layout for the layout widget is premature at this point since the
844 children will not have been instantiated. We can't instantiate
845 them until the device instantiation method for the layout has
846 been executed. We do however want to record any specified
848 if (pw) IMAGE_INSTANCE_WIDTH (ii) = pw;
849 if (ph) IMAGE_INSTANCE_HEIGHT (ii) = ph;
853 widget_post_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
857 debug_widget_instances++;
858 stderr_out ("instantiated ");
859 debug_print (instantiator);
860 stderr_out ("%d widgets instantiated\n", debug_widget_instances);
864 /* Get the geometry of a button control. We need to adjust the size
865 depending on the type of button. */
867 button_query_geometry (Lisp_Object image_instance,
868 int* width, int* height,
869 enum image_instance_geometry disp, Lisp_Object domain)
871 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
873 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
874 IMAGE_INSTANCE_WIDGET_FACE (ii),
876 /* Adjust the size for borders. */
877 if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
879 *width = w + 3 * widget_instance_border_width (ii);
881 if (EQ (XGUI_ITEM (IMAGE_INSTANCE_WIDGET_ITEM (ii))->style, Qradio)
883 EQ (XGUI_ITEM (IMAGE_INSTANCE_WIDGET_ITEM (ii))->style, Qtoggle))
884 /* This is an approximation to the size of the actual button bit. */
887 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
888 *height = h + 3 * widget_instance_border_width (ii);
891 /* Get the geometry of an edit field. */
893 edit_field_query_geometry (Lisp_Object image_instance,
894 int* width, int* height,
895 enum image_instance_geometry disp, Lisp_Object domain)
897 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
899 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
900 IMAGE_INSTANCE_WIDGET_FACE (ii),
902 /* Adjust the size for borders. */
903 if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
904 *width = w + 4 * widget_instance_border_width (ii);
905 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
906 *height = h + 4 * widget_instance_border_width (ii);
909 /* tree-view geometry - get the height right */
911 tree_view_query_geometry (Lisp_Object image_instance,
912 int* width, int* height,
913 enum image_instance_geometry disp, Lisp_Object domain)
915 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
916 Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
921 /* #### what should this be. reconsider when X has tree views. */
922 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
923 IMAGE_INSTANCE_WIDGET_FACE (ii),
924 width, 0, 0, domain);
929 /* #### widget face would be better here. */
930 default_face_font_info (domain, 0, 0, &h, 0, 0);
931 GET_LIST_LENGTH (items, len);
936 /* Get the geometry of a tab control. This is based on the number of
937 items and text therin in the tab control. */
939 tab_control_query_geometry (Lisp_Object image_instance,
940 int* width, int* height,
941 enum image_instance_geometry disp, Lisp_Object domain)
943 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
944 Lisp_Object items = XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii));
948 LIST_LOOP (rest, items)
952 query_string_geometry (XGUI_ITEM (XCAR (rest))->name,
953 IMAGE_INSTANCE_WIDGET_FACE (ii),
955 tw += 5 * widget_instance_border_width (ii); /* some bias */
957 th = max (th, h + 2 * widget_instance_border_width (ii));
960 /* Fixup returned values depending on orientation. */
961 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii))
963 if (height) *height = tw;
964 if (width) *width = th;
968 if (height) *height = th;
969 if (width) *width = tw;
973 /* Determine whether only the order has changed for a tab. */
974 int tab_control_order_only_changed (Lisp_Object image_instance)
976 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
977 int found = 0, len, pending_len;
980 /* Degenerate case. */
981 if (NILP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)))
984 /* See whether we just need a change in order. */
985 GET_LIST_LENGTH (IMAGE_INSTANCE_WIDGET_ITEMS (ii), len);
986 GET_LIST_LENGTH (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii),
988 if (len == pending_len)
990 LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
992 Lisp_Object pending_rest;
994 LIST_LOOP (pending_rest,
995 XCDR (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)))
997 if (gui_item_equal_sans_selected (XCAR (rest),
998 XCAR (pending_rest), 0))
1012 /*****************************************************************************
1014 *****************************************************************************/
1015 /* We need to cascade normalization.*/
1017 layout_normalize (Lisp_Object inst, Lisp_Object console_type,
1018 Lisp_Object dest_mask)
1020 /* This function can call lisp */
1021 struct gcpro gcpro1, gcpro2;
1022 Lisp_Object alist = Qnil, new_items = Qnil, border;
1023 /* This function can call lisp */
1026 GCPRO2 (alist, new_items);
1027 alist = tagged_vector_to_alist (inst);
1028 items = assq_no_quit (Q_items, alist);
1030 /* We need to normalize sub-objects. */
1034 LIST_LOOP (rest, XCDR (items))
1036 /* Substitute the new instantiator */
1037 new_items = Fcons (normalize_image_instantiator (XCAR (rest),
1038 console_type, dest_mask),
1041 new_items = Fnreverse (new_items);
1042 Fsetcdr (items, new_items);
1044 /* Normalize the border spec. */
1045 border = assq_no_quit (Q_border, alist);
1046 if (!NILP (border) && VECTORP (XCDR (border)))
1048 Fsetcdr (border, normalize_image_instantiator (XCDR (border),
1049 console_type, dest_mask));
1053 Lisp_Object result = alist_to_tagged_vector (XVECTOR_DATA (inst)[0],
1056 RETURN_UNGCPRO (result);
1060 /* Update the instances in the layout. */
1062 layout_update (Lisp_Object image_instance, Lisp_Object instantiator)
1064 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1065 Lisp_Object items = find_keyword_in_vector (instantiator, Q_items);
1066 Lisp_Object border_inst = find_keyword_in_vector (instantiator, Q_border);
1067 Lisp_Object justify = find_keyword_in_vector (instantiator, Q_justify);
1068 Lisp_Object hjustify = find_keyword_in_vector (instantiator, Q_horizontally_justify);
1069 Lisp_Object vjustify = find_keyword_in_vector (instantiator, Q_vertically_justify);
1070 Lisp_Object border = Qnil;
1071 Lisp_Object children = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii);
1072 int structure_changed = 0;
1073 struct gcpro gcpro1;
1075 /* Pick up horizontal justification, left is the default.*/
1076 if (!NILP (hjustify))
1078 if (EQ (hjustify, Qright) || EQ (hjustify, Qbottom))
1079 IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_RIGHT;
1080 else if (EQ (hjustify, Qcenter))
1081 IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_CENTER;
1083 /* If not set use general justification. */
1084 else if (!NILP (justify))
1086 if (EQ (justify, Qright) || EQ (justify, Qbottom))
1087 IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_RIGHT;
1088 else if (EQ (justify, Qcenter))
1089 IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_CENTER;
1092 /* Pick up vertical justification, top is the default. */
1093 if (!NILP (vjustify))
1095 if (EQ (vjustify, Qright) || EQ (vjustify, Qbottom))
1096 IMAGE_INSTANCE_SUBWINDOW_V_JUSTIFY (ii) = LAYOUT_JUSTIFY_BOTTOM;
1097 else if (EQ (vjustify, Qcenter))
1098 IMAGE_INSTANCE_SUBWINDOW_V_JUSTIFY (ii) = LAYOUT_JUSTIFY_CENTER;
1100 /* If not set use general justification. */
1101 else if (!NILP (justify))
1103 if (EQ (justify, Qright) || EQ (justify, Qbottom))
1104 IMAGE_INSTANCE_SUBWINDOW_V_JUSTIFY (ii) = LAYOUT_JUSTIFY_BOTTOM;
1105 else if (EQ (justify, Qcenter))
1106 IMAGE_INSTANCE_SUBWINDOW_V_JUSTIFY (ii) = LAYOUT_JUSTIFY_CENTER;
1109 /* We want to avoid consing if we can. This is quite awkward because
1110 we have to deal with the border as well as the items. */
1113 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)))
1115 border = XCAR (children);
1116 children = XCDR (children);
1119 #ifdef DEBUG_WIDGET_OUTPUT
1120 stderr_out ("layout updated\n");
1122 /* Update the border. */
1123 if (!NILP (border_inst))
1125 if (VECTORP (border_inst))
1127 /* We are going to be sneaky here and add the border text as
1128 just another child, the layout and output routines don't know
1129 this and will just display at the offsets we prescribe. */
1131 call3 (Qset_glyph_image, border, border_inst,
1132 IMAGE_INSTANCE_DOMAIN (ii));
1135 border = Fcons (call1 (Qmake_glyph, border_inst), Qnil);
1136 structure_changed = 1;
1138 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (0);
1145 structure_changed = 1;
1147 if (EQ (border_inst, Qt))
1148 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = Qetched_in;
1150 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = border_inst;
1154 /* Pick up the sub-widgets. */
1158 GET_LIST_LENGTH (items, len1);
1159 GET_LIST_LENGTH (children, len2);
1160 /* The structure hasn't changed so just update the images. */
1161 if (!structure_changed && len1 == len2)
1163 /* Pick up the sub-widgets. */
1164 for (; !NILP (children); children = XCDR (children), items = XCDR (items))
1166 call3 (Qset_glyph_image, XCAR (children), XCAR (items),
1167 IMAGE_INSTANCE_DOMAIN (ii));
1170 /* The structure has changed so start over. */
1173 /* Instantiate any new glyphs. */
1174 for (; !NILP (items); items = XCDR (items))
1176 /* #### We really want to use call_with_suspended_errors
1177 here, but it won't allow us to call lisp. */
1178 border = Fcons (call1 (Qmake_glyph, XCAR (items)), border);
1180 IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = Fnreverse (border);
1187 layout_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1188 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1189 int dest_mask, Lisp_Object domain)
1191 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1192 Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
1194 #ifdef DEBUG_WIDGET_OUTPUT
1195 stderr_out ("layout instantiated\n");
1197 /* Do widget type instantiation first. */
1198 widget_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
1203 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_VERTICAL;
1206 /* Get child glyphs and finish instantiation. We can't do image
1207 instance children yet as we might not have a containing
1209 layout_update (image_instance, instantiator);
1213 layout_post_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1218 /* Layout widget. Sizing commentary: we have a number of problems that
1219 we would like to address. Some consider some of these more
1220 important than others. It used to be that size information was
1221 determined at instantiation time and was then fixed forever
1222 after. Generally this is not what we want. Users want size to be
1223 "big enough" to accommodate whatever they are trying to show and
1224 this is dependent on text length, lines, font metrics etc. Of
1225 course these attributes can change dynamically and so the size
1226 should changed dynamically also. Only in a few limited cases should
1227 the size be fixed and remain fixed. Of course this actually means
1228 that we don't really want to specify the size *at all* for most
1229 widgets - we want it to be discovered dynamically. Thus we can
1230 envisage the following scenarios:
1232 1. A button is sized to accommodate its text, the text changes and the
1233 button should change size also.
1235 2. A button is given an explicit size. Its size should never change.
1237 3. Layout is put inside an area. The size of the area changes, the
1238 layout should change with it.
1240 4. A button grows to accommodate additional text. The whitespace
1241 around it should be modified to cope with the new layout
1244 5. A button grows. The area surrounding it should grow also if
1247 What metrics are important?
1248 1. Actual width and height.
1250 2. Whether the width and height are what the widget actually wants, or
1251 whether it can grow or shrink.
1253 Text glyphs are particularly troublesome since their metrics depend
1254 on the context in which they are being viewed. For instance they
1255 can appear differently depending on the window face, frame face or
1256 glyph face. In order to simplify this text glyphs can now only have
1257 a glyph-face or image-instance face. All other glyphs are
1258 essentially fixed in appearance. Perhaps the problem is that text
1259 glyphs are cached on a device basis like most other glyphs. Instead
1260 they should be cached per-window and then the instance would be
1261 fixed and we wouldn't have to mess around with font metrics and the
1264 Another sizing problem is alignment. We provide layout widgets that
1265 allow users to stack widgets vertically or horizontally. These
1266 layouts also allow the widgets to be centered (space evenly
1267 distributed), left or right justified (fixed spacing widgets
1268 stacked against the left, righ, top or bottom edge). Unfortunately
1269 this doesn't allow widgets in different layouts to be aligned. For
1270 instance how should the search dialog be organized for alignment?
1271 The obvious choice of two vertical columns does not work since the
1272 size of individual widgets will affect where they get placed. The
1273 same is true for several rows of widgets. To solve this problem we
1274 introduce the notion of `logical_unit_height'. This is a size
1275 quantity that is designed to be big enough to accomodate the
1276 largest `single height unit'. The function
1277 widget_logical_unit_height() determines the value of this in
1278 pixels. It is dependent on the widget face and some combination of
1279 spacing and border-width. Thus if users specify left or right
1280 justification in a vertical layout they get something in logical
1281 units. To simplify this the functions
1282 `widget-logical-to-character-height' and
1283 `widget-logical-to-character-width' allow conversion between
1284 characters and logical units so that frames can be sized
1287 /* Query the geometry of a layout widget. */
1289 layout_query_geometry (Lisp_Object image_instance, int* width,
1290 int* height, enum image_instance_geometry disp,
1293 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1294 Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii), rest;
1295 int maxph = 0, maxpw = 0, nitems = 0, ph_adjust = 0;
1296 int gheight, gwidth, luh;
1298 /* If we are not initialized then we won't have any children. */
1299 if (!IMAGE_INSTANCE_INITIALIZED (ii))
1302 /* First just set up what we already have. */
1303 if (width) *width = IMAGE_INSTANCE_WIDTH (ii);
1304 if (height) *height = IMAGE_INSTANCE_HEIGHT (ii);
1306 /* If we are not allowed to dynamically size then return. */
1307 if (!IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)
1309 !IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
1312 luh = widget_logical_unit_height (ii);
1314 /* Pick up the border text if we have one. */
1315 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)))
1317 glyph_query_geometry (XCAR (items), &gwidth, &gheight, disp,
1319 ph_adjust = gheight;
1320 /* Include text width in vertical layouts. */
1321 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_VERTICAL)
1322 maxpw = gwidth + BORDER_FIDDLE_FACTOR;
1323 items = XCDR (items);
1326 /* Flip through the items to work out how much stuff we have to display */
1327 LIST_LOOP (rest, items)
1329 Lisp_Object glyph = XCAR (rest);
1330 glyph_query_geometry (glyph, &gwidth, &gheight, disp, image_instance);
1333 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL)
1335 maxph = max (maxph, gheight);
1340 maxpw = max (maxpw, gwidth);
1345 /* Work out minimum space we need to fit all the items. This could
1346 have been fixed by the user. */
1347 if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii)) {
1348 if (!NILP (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii)))
1350 Lisp_Object dynamic_width =
1351 Feval (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii));
1352 if (INTP (dynamic_width))
1353 *width = XINT (dynamic_width);
1355 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL)
1357 *width = maxpw + ((nitems + 1) * widget_instance_border_width (ii) +
1358 IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2;
1362 *width = maxpw + 2 * (widget_instance_border_width (ii) * 2 +
1363 IMAGE_INSTANCE_MARGIN_WIDTH (ii));
1367 /* Work out vertical spacings. */
1368 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)) {
1369 if (!NILP (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii)))
1371 Lisp_Object dynamic_height =
1372 Feval (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii));
1373 if (INTP (dynamic_height))
1374 *height = XINT (dynamic_height);
1376 else if (IMAGE_INSTANCE_SUBWINDOW_LOGICAL_LAYOUT (ii))
1378 *height = nitems * luh + ph_adjust;
1380 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_VERTICAL)
1382 *height = maxph + ((nitems + 1) * widget_instance_border_width (ii) +
1383 IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2 + ph_adjust;
1387 *height = maxph + (2 * widget_instance_border_width (ii) +
1388 IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2 + ph_adjust;
1391 #ifdef DEBUG_WIDGET_OUTPUT
1392 stderr_out ("layout wants %dx%d\n", *width, *height);
1397 layout_layout (Lisp_Object image_instance,
1398 int width, int height, int xoffset, int yoffset,
1401 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1403 Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii);
1404 int x, y, maxph = 0, maxpw = 0, nitems = 0,
1405 horiz_spacing, vert_spacing, ph_adjust = 0;
1406 int gheight, gwidth;
1407 /* See comments in widget_logical_unit_height(). */
1408 int luh = widget_logical_unit_height (ii);
1410 /* If we are not initialized then we won't have any children. */
1411 if (!IMAGE_INSTANCE_INITIALIZED (ii))
1414 #ifdef DEBUG_WIDGET_OUTPUT
1415 stderr_out ("layout output %dx%d\n", width, height);
1418 /* Pick up the border text if we have one. A border can have the
1419 values Qetched_in, Qetched_out, Qbevel_in, Qbevel_out or an
1420 integer. The first four just affect the display properties of the
1421 border that is drawn. The last is an offset and implies that the
1422 first item in the list of subcontrols is a text control that
1423 should be displayed on the border. */
1424 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)))
1426 Lisp_Object border = XCAR (items);
1427 items = XCDR (items);
1428 glyph_query_geometry (border, &gwidth, &gheight,
1429 IMAGE_DESIRED_GEOMETRY, image_instance);
1430 /* The vertical offset for subsequent items is the full height
1431 of the border glyph. */
1432 ph_adjust = gheight;
1433 /* The offset for the border is half the glyph height. */
1434 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (gheight / 2);
1436 /* #### Really, what should this be? */
1437 glyph_do_layout (border, gwidth, gheight, BORDER_FIDDLE_FACTOR, 0,
1441 /* Flip through the items to work out how much stuff we have to display. */
1442 LIST_LOOP (rest, items)
1444 Lisp_Object glyph = XCAR (rest);
1446 glyph_query_geometry (glyph, &gwidth, &gheight,
1447 IMAGE_DESIRED_GEOMETRY, image_instance);
1449 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1450 == LAYOUT_HORIZONTAL)
1452 maxph = max (maxph, gheight);
1457 maxpw = max (maxpw, gwidth);
1462 /* work out spacing between items and bounds of the layout */
1464 /* The user wants a smaller space than the largest item, so we
1465 just provide default spacing and will let the output routines
1467 horiz_spacing = widget_spacing (IMAGE_INSTANCE_DOMAIN (ii));
1468 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1469 == LAYOUT_HORIZONTAL)
1470 /* We have a larger area to display in so distribute the space
1472 horiz_spacing = (width - (maxpw +
1473 IMAGE_INSTANCE_MARGIN_WIDTH (ii) * 2))
1476 horiz_spacing = (width - maxpw) / 2
1477 - IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1479 /* We are trying here to get widgets to line up when they are left
1480 or right justified vertically. This means that we must position
1481 widgets on logical unit boundaries, even though their height may
1482 be greater or less than a logical unit. In order to avoid
1483 clipping we need to determine how big the widget wants to be and
1484 then allocate as many logical units as necessary in order to
1487 vert_spacing = widget_spacing (IMAGE_INSTANCE_DOMAIN (ii)) * 2;
1488 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1491 if (!IMAGE_INSTANCE_SUBWINDOW_V_CENTERED (ii))
1492 vert_spacing = widget_spacing (IMAGE_INSTANCE_DOMAIN (ii)) * 2;
1494 vert_spacing = (height - (maxph + ph_adjust +
1495 IMAGE_INSTANCE_MARGIN_WIDTH (ii) * 2))
1499 vert_spacing = (height - (maxph + ph_adjust)) / 2
1500 - IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1502 y = yoffset = vert_spacing + ph_adjust + IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1503 x = horiz_spacing + IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1505 /* Now flip through putting items where we want them, paying
1506 attention to justification. Make sure we don't mess with the
1508 LIST_LOOP (rest, items)
1510 Lisp_Object glyph = XCAR (rest);
1512 glyph_query_geometry (glyph, &gwidth, &gheight,
1513 IMAGE_DESIRED_GEOMETRY, image_instance);
1515 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL)
1517 if (IMAGE_INSTANCE_SUBWINDOW_BOTTOM_JUSTIFIED (ii))
1518 y = height - (gheight + vert_spacing);
1519 else if (IMAGE_INSTANCE_SUBWINDOW_V_CENTERED (ii))
1520 y = (height - gheight) / 2;
1524 if (IMAGE_INSTANCE_SUBWINDOW_RIGHT_JUSTIFIED (ii))
1525 x = width - (gwidth + horiz_spacing);
1526 else if (IMAGE_INSTANCE_SUBWINDOW_H_CENTERED (ii))
1527 x = (width - gwidth) / 2;
1530 /* Now layout subwidgets if they require it. */
1531 glyph_do_layout (glyph, gwidth, gheight, x, y, image_instance);
1533 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL)
1535 x += (gwidth + horiz_spacing);
1539 y += (gheight + vert_spacing);
1540 if (!IMAGE_INSTANCE_SUBWINDOW_V_CENTERED (ii))
1542 /* justified, vertical layout, try and align on logical unit
1544 y = ROUND_UP (y - yoffset, luh) + yoffset;
1552 /* Get the glyphs that comprise a layout. These are created internally
1553 and so are otherwise inaccessible to lisp. We need some way of getting
1554 properties from the widgets that comprise a layout and this is the
1555 simplest way of doing it.
1557 #### Eventually we should allow some more intelligent access to
1560 layout_property (Lisp_Object image_instance, Lisp_Object prop)
1562 /* This function can GC. */
1563 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1564 if (EQ (prop, Q_items))
1566 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)) &&
1567 CONSP (IMAGE_INSTANCE_LAYOUT_CHILDREN (ii)))
1568 return Fcopy_sequence (XCDR
1569 (IMAGE_INSTANCE_LAYOUT_CHILDREN (ii)));
1571 return Fcopy_sequence (IMAGE_INSTANCE_LAYOUT_CHILDREN (ii));
1576 /* Layout subwindows if they are real subwindows. */
1578 native_layout_layout (Lisp_Object image_instance,
1579 int width, int height, int xoffset, int yoffset,
1582 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
1585 /* The first time this gets called, the layout will be only
1586 partially instantiated. The children get done in
1587 post_instantiate. */
1588 if (!IMAGE_INSTANCE_INITIALIZED (ii))
1591 /* Defining this overrides the default layout_layout so we first have to call that to get
1592 suitable instances and values set up. */
1593 layout_layout (image_instance, width, height, xoffset, yoffset, domain);
1595 LIST_LOOP (rest, IMAGE_INSTANCE_LAYOUT_CHILDREN (ii))
1597 struct display_glyph_area dga;
1600 dga.width = IMAGE_INSTANCE_WIDTH (ii);
1601 dga.height = IMAGE_INSTANCE_HEIGHT (ii);
1603 map_subwindow (XCAR (rest),
1604 IMAGE_INSTANCE_XOFFSET (ii),
1605 IMAGE_INSTANCE_YOFFSET (ii), &dga);
1610 DEFUN ("widget-logical-to-character-width", Fwidget_logical_to_character_width, 1, 3, 0, /*
1611 Convert the width in logical widget units to characters.
1612 Logical widget units do not take into account adjusments made for
1613 layout borders, so this adjusment is approximated.
1615 (width, face, domain))
1617 int w, neww, charwidth;
1618 int border_width = DEFAULT_WIDGET_BORDER_WIDTH;
1621 domain = Fselected_frame (Qnil);
1626 if (HAS_DEVMETH_P (DOMAIN_XDEVICE (domain), widget_border_width))
1627 border_width = DEVMETH (DOMAIN_XDEVICE (domain), widget_border_width, ());
1629 default_face_font_info (domain, 0, 0, 0, &charwidth, 0);
1630 neww = ROUND_UP (charwidth * w + 4 * border_width + 2 * widget_spacing (domain),
1631 charwidth) / charwidth;
1633 return make_int (neww);
1636 DEFUN ("widget-logical-to-character-height", Fwidget_logical_to_character_height, 1, 3, 0, /*
1637 Convert the height in logical widget units to characters.
1638 Logical widget units do not take into account adjusments made for
1639 layout borders, so this adjustment is approximated.
1641 If the components of a widget layout are justified to the top or the
1642 bottom then they are aligned in terms of `logical units'. This is a
1643 size quantity that is designed to be big enough to accomodate the
1644 largest `single height' widget. It is dependent on the widget face and
1645 some combination of spacing and border-width. Thus if you specify top
1646 or bottom justification in a vertical layout the subcontrols are laid
1647 out one per logical unit. This allows adjoining layouts to have
1648 identical alignment for their subcontrols.
1650 Since frame sizes are measured in characters, this function allows you
1651 to do appropriate conversion between logical units and characters.
1653 (height, face, domain))
1655 int h, newh, charheight;
1659 domain = Fselected_frame (Qnil);
1663 default_face_font_info (domain, 0, 0, &charheight, 0, 0);
1664 newh = ROUND_UP (logical_unit_height (Fsymbol_name (Qwidget),
1665 Vwidget_face, domain) * h, charheight)
1668 return make_int (newh);
1672 /************************************************************************/
1673 /* initialization */
1674 /************************************************************************/
1677 syms_of_glyphs_widget (void)
1679 DEFSYMBOL (Qetched_in);
1680 DEFSYMBOL (Qetched_out);
1681 DEFSYMBOL (Qbevel_in);
1682 DEFSYMBOL (Qbevel_out);
1683 DEFSYMBOL (Qmake_glyph);
1685 DEFSUBR (Fwidget_logical_to_character_height);
1686 DEFSUBR (Fwidget_logical_to_character_width);
1689 #define VALID_GUI_KEYWORDS(type) do { \
1690 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_active, check_valid_anything); \
1691 IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything); \
1692 IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string); \
1693 IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol); \
1694 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_selected, check_valid_anything); \
1695 IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything); \
1696 IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol); \
1697 IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything); \
1698 IIFORMAT_VALID_KEYWORD (type, Q_initial_focus, check_valid_anything); \
1699 IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string); \
1700 IIFORMAT_VALID_KEYWORD (type, Q_accelerator, check_valid_string); \
1701 IIFORMAT_VALID_KEYWORD (type, Q_label, check_valid_anything); \
1702 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback, check_valid_callback); \
1703 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback_ex, check_valid_callback); \
1704 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_descriptor, \
1705 check_valid_string_or_vector); \
1708 #define VALID_WIDGET_KEYWORDS(type) do { \
1709 IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int); \
1710 IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int); \
1711 IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int_or_function); \
1712 IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int_or_function); \
1713 IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face); \
1717 static void image_instantiator_widget (void)
1718 { /* we only do this for properties */
1719 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget");
1720 IIFORMAT_HAS_METHOD (widget, property);
1721 IIFORMAT_HAS_METHOD (widget, update);
1722 IIFORMAT_HAS_METHOD (widget, query_geometry);
1723 IIFORMAT_HAS_METHOD (widget, layout);
1726 static void image_instantiator_buttons (void)
1728 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button");
1729 IIFORMAT_HAS_SHARED_METHOD (button, validate, widget);
1730 IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget);
1731 IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget);
1732 IIFORMAT_HAS_SHARED_METHOD (button, post_instantiate, widget);
1733 IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget);
1734 IIFORMAT_HAS_SHARED_METHOD (button, governing_domain, subwindow);
1735 IIFORMAT_HAS_METHOD (button, query_geometry);
1736 IIFORMAT_VALID_KEYWORD (button,
1737 Q_image, check_valid_instantiator);
1738 VALID_WIDGET_KEYWORDS (button);
1739 VALID_GUI_KEYWORDS (button);
1742 static void image_instantiator_edit_fields (void)
1744 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit_field, "edit-field");
1745 IIFORMAT_HAS_SHARED_METHOD (edit_field, validate, widget);
1746 IIFORMAT_HAS_SHARED_METHOD (edit_field, possible_dest_types, widget);
1747 IIFORMAT_HAS_SHARED_METHOD (edit_field, instantiate, widget);
1748 IIFORMAT_HAS_SHARED_METHOD (edit_field, post_instantiate, widget);
1749 IIFORMAT_HAS_SHARED_METHOD (edit_field, governing_domain, subwindow);
1750 IIFORMAT_HAS_METHOD (edit_field, query_geometry);
1751 VALID_WIDGET_KEYWORDS (edit_field);
1752 VALID_GUI_KEYWORDS (edit_field);
1755 static void image_instantiator_combo_box (void)
1757 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo_box, "combo-box");
1758 IIFORMAT_HAS_METHOD (combo_box, validate);
1759 IIFORMAT_HAS_SHARED_METHOD (combo_box, possible_dest_types, widget);
1760 IIFORMAT_HAS_SHARED_METHOD (combo_box, governing_domain, subwindow);
1762 VALID_GUI_KEYWORDS (combo_box);
1764 IIFORMAT_VALID_KEYWORD (combo_box, Q_width, check_valid_int);
1765 IIFORMAT_VALID_KEYWORD (combo_box, Q_height, check_valid_int);
1766 IIFORMAT_VALID_KEYWORD (combo_box, Q_pixel_width,
1767 check_valid_int_or_function);
1768 IIFORMAT_VALID_KEYWORD (combo_box, Q_face, check_valid_face);
1769 IIFORMAT_VALID_KEYWORD (combo_box, Q_items, check_valid_item_list);
1772 static void image_instantiator_scrollbar (void)
1774 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar");
1775 IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget);
1776 IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget);
1777 IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget);
1778 IIFORMAT_HAS_SHARED_METHOD (scrollbar, post_instantiate, widget);
1779 IIFORMAT_HAS_SHARED_METHOD (scrollbar, governing_domain, subwindow);
1780 VALID_GUI_KEYWORDS (scrollbar);
1782 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width,
1783 check_valid_int_or_function);
1784 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height,
1785 check_valid_int_or_function);
1786 IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face);
1789 static void image_instantiator_progress_guage (void)
1791 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge, "progress-gauge");
1792 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, validate, widget);
1793 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, possible_dest_types, widget);
1794 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, instantiate, widget);
1795 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, post_instantiate, widget);
1796 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, governing_domain, subwindow);
1797 VALID_WIDGET_KEYWORDS (progress_gauge);
1798 VALID_GUI_KEYWORDS (progress_gauge);
1800 IIFORMAT_VALID_KEYWORD (progress_gauge, Q_value, check_valid_int);
1803 static void image_instantiator_tree_view (void)
1805 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tree_view, "tree-view");
1806 IIFORMAT_HAS_SHARED_METHOD (tree_view, validate, combo_box);
1807 IIFORMAT_HAS_SHARED_METHOD (tree_view, possible_dest_types, widget);
1808 IIFORMAT_HAS_SHARED_METHOD (tree_view, instantiate, widget);
1809 IIFORMAT_HAS_SHARED_METHOD (tree_view, post_instantiate, widget);
1810 IIFORMAT_HAS_SHARED_METHOD (tree_view, governing_domain, subwindow);
1811 IIFORMAT_HAS_METHOD (tree_view, query_geometry);
1812 VALID_WIDGET_KEYWORDS (tree_view);
1813 VALID_GUI_KEYWORDS (tree_view);
1814 IIFORMAT_VALID_KEYWORD (tree_view, Q_items, check_valid_item_list);
1817 static void image_instantiator_tab_control (void)
1819 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tab_control, "tab-control");
1820 IIFORMAT_HAS_SHARED_METHOD (tab_control, validate, combo_box);
1821 IIFORMAT_HAS_SHARED_METHOD (tab_control, possible_dest_types, widget);
1822 IIFORMAT_HAS_SHARED_METHOD (tab_control, instantiate, widget);
1823 IIFORMAT_HAS_SHARED_METHOD (tab_control, post_instantiate, widget);
1824 IIFORMAT_HAS_SHARED_METHOD (tab_control, governing_domain, subwindow);
1825 IIFORMAT_HAS_METHOD (tab_control, query_geometry);
1826 VALID_WIDGET_KEYWORDS (tab_control);
1827 VALID_GUI_KEYWORDS (tab_control);
1828 IIFORMAT_VALID_KEYWORD (tab_control, Q_orientation,
1829 check_valid_tab_orientation);
1830 IIFORMAT_VALID_KEYWORD (tab_control, Q_items, check_valid_item_list);
1833 static void image_instantiator_labels (void)
1835 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label");
1836 IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget);
1837 IIFORMAT_HAS_SHARED_METHOD (label, instantiate, widget);
1838 IIFORMAT_HAS_SHARED_METHOD (label, post_instantiate, widget);
1839 IIFORMAT_HAS_SHARED_METHOD (label, governing_domain, subwindow);
1840 VALID_WIDGET_KEYWORDS (label);
1841 IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string);
1844 #define VALID_LAYOUT_KEYWORDS(layout) \
1845 VALID_WIDGET_KEYWORDS (layout); \
1846 IIFORMAT_VALID_KEYWORD (layout, Q_orientation, check_valid_orientation); \
1847 IIFORMAT_VALID_KEYWORD (layout, Q_justify, check_valid_justification); \
1848 IIFORMAT_VALID_KEYWORD (layout, Q_vertically_justify, check_valid_justification); \
1849 IIFORMAT_VALID_KEYWORD (layout, Q_horizontally_justify, check_valid_justification); \
1850 IIFORMAT_VALID_KEYWORD (layout, Q_border, check_valid_border); \
1851 IIFORMAT_VALID_KEYWORD (layout, Q_margin_width, check_valid_int); \
1852 IIFORMAT_VALID_KEYWORD (layout, Q_items, \
1853 check_valid_instantiator_list)
1855 static void image_instantiator_layout (void)
1857 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (layout, "layout");
1858 IIFORMAT_HAS_SHARED_METHOD (layout, possible_dest_types, widget);
1859 IIFORMAT_HAS_METHOD (layout, instantiate);
1860 IIFORMAT_HAS_METHOD (layout, post_instantiate);
1861 IIFORMAT_HAS_SHARED_METHOD (layout, governing_domain, subwindow);
1862 IIFORMAT_HAS_METHOD (layout, normalize);
1863 IIFORMAT_HAS_METHOD (layout, query_geometry);
1864 IIFORMAT_HAS_METHOD (layout, layout);
1865 IIFORMAT_HAS_METHOD (layout, update);
1866 IIFORMAT_HAS_METHOD (layout, property);
1868 VALID_GUI_KEYWORDS (layout);
1869 VALID_LAYOUT_KEYWORDS (layout);
1872 static void image_instantiator_native_layout (void)
1874 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (native_layout, "native-layout");
1875 IIFORMAT_HAS_SHARED_METHOD (native_layout, possible_dest_types, widget);
1876 IIFORMAT_HAS_SHARED_METHOD (native_layout, instantiate, layout);
1877 IIFORMAT_HAS_SHARED_METHOD (native_layout, post_instantiate, layout);
1878 IIFORMAT_HAS_METHOD (native_layout, layout);
1879 IIFORMAT_HAS_SHARED_METHOD (native_layout, governing_domain, subwindow);
1880 IIFORMAT_HAS_SHARED_METHOD (native_layout, normalize, layout);
1881 IIFORMAT_HAS_SHARED_METHOD (native_layout, query_geometry, layout);
1882 IIFORMAT_HAS_SHARED_METHOD (native_layout, layout, layout);
1883 IIFORMAT_HAS_SHARED_METHOD (native_layout, property, layout);
1885 VALID_GUI_KEYWORDS (native_layout);
1886 VALID_LAYOUT_KEYWORDS (native_layout);
1890 image_instantiator_format_create_glyphs_widget (void)
1892 image_instantiator_widget();
1893 image_instantiator_buttons();
1894 image_instantiator_edit_fields();
1895 image_instantiator_combo_box();
1896 image_instantiator_scrollbar();
1897 image_instantiator_progress_guage();
1898 image_instantiator_tree_view();
1899 image_instantiator_tab_control();
1900 image_instantiator_labels();
1901 image_instantiator_layout();
1902 image_instantiator_native_layout();
1906 reinit_vars_of_glyphs_widget (void)
1908 #ifdef DEBUG_WIDGETS
1909 debug_widget_instances = 0;
1914 vars_of_glyphs_widget (void)
1916 reinit_vars_of_glyphs_widget ();
1921 specifier_vars_of_glyphs_widget (void)
1923 DEFVAR_SPECIFIER ("widget-border-width",
1924 &Vwidget_border_width /*
1925 *Border width of widgets.
1926 This is a specifier; use `set-specifier' to change it.
1928 Vwidget_border_width = Fmake_specifier (Qnatnum);