(U+6215): Apply new conventions for glyph granularity.
[chise/xemacs-chise.git.1] / src / glyphs-widget.c
1 /* Widget-specific glyph objects.
2    Copyright (C) 1998, 1999, 2000, 2002 Andy Piper.
3
4 This file is part of XEmacs.
5
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
9 later version.
10
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
14 for more details.
15
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.  */
20
21 /* Synched up with: Not in FSF. */
22
23 /* written by Andy Piper <andy@xemacs.org> */
24
25 #include <config.h>
26 #include "lisp.h"
27 #include "lstream.h"
28 #include "console.h"
29 #include "device.h"
30 #include "faces.h"
31 #include "glyphs.h"
32 #include "objects.h"
33 #include "bytecode.h"
34 #include "window.h"
35 #include "buffer.h"
36 #include "frame.h"
37 #include "insdel.h"
38 #include "opaque.h"
39
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);
49 Lisp_Object Qlabel;
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);
57 Lisp_Object Qlayout;
58 DEFINE_IMAGE_INSTANTIATOR_FORMAT (native_layout);
59 Lisp_Object Qnative_layout;
60
61 Lisp_Object Qetched_in, Qetched_out, Qbevel_in, Qbevel_out;
62 Lisp_Object Qmake_glyph;
63 Lisp_Object Vwidget_border_width;
64
65 static int
66 widget_border_width (Lisp_Object domain);
67 static int
68 widget_spacing (Lisp_Object domain);
69 #define BORDER_FIDDLE_FACTOR 10
70 #ifdef DEBUG_WIDGETS
71 int debug_widget_instances;
72 #endif
73
74 /* TODO:
75    - tooltips for controls, especially buttons.
76    - keyboard traversal.
77    - lisp configurable layout.
78  */
79
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
84    buttons in groups. */
85 static int
86 widget_possible_dest_types (void)
87 {
88   return IMAGE_WIDGET_MASK;
89 }
90
91 static void
92 check_valid_instantiator (Lisp_Object data)
93 {
94   Lisp_Object glyph = data;
95   if (SYMBOLP (data))
96     glyph = XSYMBOL (data)->value;
97
98   if (!CONSP (glyph) && !VECTORP (glyph))
99     invalid_argument ("instantiator item must be a vector", data);
100 }
101
102 static void
103 check_valid_orientation (Lisp_Object data)
104 {
105   if (!EQ (data, Qhorizontal)
106       &&
107       !EQ (data, Qvertical))
108     invalid_argument ("unknown orientation for layout", data);
109 }
110
111 static void
112 check_valid_tab_orientation (Lisp_Object data)
113 {
114   if (!EQ (data, Qtop)
115       &&
116       !EQ (data, Qbottom)
117       &&
118       !EQ (data, Qleft)
119       &&
120       !EQ (data, Qright))
121     invalid_argument ("unknown orientation for tab control", data);
122 }
123
124 static void
125 check_valid_justification (Lisp_Object data)
126 {
127   if (!EQ (data, Qleft) 
128       && 
129       !EQ (data, Qright) 
130       && 
131       !EQ (data, Qtop) 
132       && 
133       !EQ (data, Qbottom) 
134       && 
135       !EQ (data, Qcenter))
136     invalid_argument ("unknown justification for layout", data);
137 }
138
139 static void
140 check_valid_border (Lisp_Object data)
141 {
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);
146 }
147
148 static void
149 check_valid_anything (Lisp_Object data)
150 {
151 }
152
153 static void
154 check_valid_callback (Lisp_Object data)
155 {
156     if (!SYMBOLP (data)
157         && !COMPILED_FUNCTIONP (data)
158         && !CONSP (data))
159     {
160         invalid_argument (":callback must be a function or expression", data);
161     }
162 }
163
164 static void
165 check_valid_int_or_function (Lisp_Object data)
166 {
167   if (!INTP (data) && !CONSP (data) && !SYMBOLP (data))
168     invalid_argument ("must be an integer or expresssion", data);
169 }
170
171 static void
172 check_valid_symbol (Lisp_Object data)
173 {
174     CHECK_SYMBOL (data);
175 }
176
177 static void
178 check_valid_string_or_vector (Lisp_Object data)
179 {
180     if (!STRINGP (data) && !VECTORP (data))
181         invalid_argument (":descriptor must be a string or a vector", data);
182 }
183
184 void
185 check_valid_item_list (Lisp_Object items)
186 {
187   Lisp_Object rest;
188
189   CHECK_LIST (items);
190   EXTERNAL_LIST_LOOP (rest, items)
191     {
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));
198       else
199         invalid_argument ("Items must be vectors, lists or strings", items);
200     }
201 }
202
203 static void
204 check_valid_instantiator_list (Lisp_Object data)
205 {
206   Lisp_Object rest;
207
208   CHECK_LIST (data);
209   EXTERNAL_LIST_LOOP (rest, data)
210     {
211       check_valid_instantiator (XCAR (rest));
212     }
213 }
214
215 static Lisp_Object
216 glyph_instantiator_to_glyph (Lisp_Object sym)
217 {
218   /* This function calls lisp. */
219   Lisp_Object glyph = sym;
220   struct gcpro gcpro1;
221
222   GCPRO1 (glyph);
223   /* if we have a symbol get at the actual data */
224   if (SYMBOLP (glyph))
225     glyph = XSYMBOL (glyph)->value;
226
227   if (CONSP (glyph))
228     glyph = Feval (glyph);
229
230   /* Be really helpful to the user. */
231   if (VECTORP (glyph))
232     {
233       glyph = call1 (Qmake_glyph, glyph);
234     }
235
236   /* substitute the new glyph */
237   RETURN_UNGCPRO (glyph);
238 }
239
240 static void
241 substitute_keyword_value (Lisp_Object inst, Lisp_Object key, Lisp_Object val)
242 {
243   int i;
244   /* substitute the new glyph */
245   for (i = 0; i < XVECTOR_LENGTH (inst); i++)
246     {
247       if (EQ (key, XVECTOR_DATA (inst)[i]))
248         {
249           XVECTOR_DATA (inst)[i+1] = val;
250           break;
251         }
252     }
253 }
254
255 /* Determine the border with of the widget. */
256 static int
257 widget_border_width (Lisp_Object domain)
258 {
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, ());
264   else 
265     return DEFAULT_WIDGET_BORDER_WIDTH;
266 }
267
268 static int
269 widget_instance_border_width (Lisp_Image_Instance* ii)
270 {
271   return widget_border_width (IMAGE_INSTANCE_DOMAIN (ii));
272 }
273
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. */
280 static int
281 logical_unit_height (Lisp_Object text, Lisp_Object face, Lisp_Object domain)
282 {
283   int charheight = 0;
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
288      the edit-field. */
289   return charheight + 2 * widget_spacing (domain)
290     + 4 * widget_border_width (domain);
291 }
292
293 static int
294 widget_logical_unit_height (Lisp_Image_Instance* ii)
295 {
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));
303 }
304
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. */
316 static Lisp_Object
317 widget_property (Lisp_Object image_instance, Lisp_Object prop)
318 {
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);
325 #endif
326   /* .. then try device specific methods ... */
327   meths = decode_device_ii_format (image_instance_device (image_instance),
328                                    IMAGE_INSTANCE_WIDGET_TYPE (ii),
329                                    ERROR_ME_NOT);
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),
334                                    ERROR_ME_NOT);
335   if (meths && HAS_IIFORMAT_METH_P (meths, property))
336     return IIFORMAT_METH (meths, property, (image_instance, prop));
337   /* ... then fail */
338   return Qunbound;
339 }
340
341 /* Update the displayed properties of a widget.
342
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.
348
349    #### property is still a valid function since we have to be able to
350    extract information from the actual widget.
351
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. */
356 static void
357 widget_update (Lisp_Object image_instance, Lisp_Object instantiator)
358 {
359   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
360   struct image_instantiator_methods* meths;
361   struct gcpro gcpro1;
362
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;
367
368   GCPRO1 (descriptor_item);
369
370   /* Pick up any generic properties that we might need to keep hold
371      of. 
372      #### This is potentially bogus because it is changing the items
373      in place rather than in the pending items. */
374   if (!NILP (text))
375     {
376       IMAGE_INSTANCE_WIDGET_TEXT (ii) = text;
377       IMAGE_INSTANCE_TEXT_CHANGED (ii) = 1;
378     }
379
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
382      keywords.
383
384      #### This is inconsistent with instantiation in that you have to
385      have the :descriptor keyword for updates in order to recognise 
386      changes. */
387   if (VECTORP (desc))
388     {
389       descriptor_item = gui_parse_item_keywords_no_errors (desc);
390     }
391   else
392     {
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
396          changed. */
397       descriptor_item = copy_gui_item (IMAGE_INSTANCE_WIDGET_ITEM (ii));
398       if (!update_gui_item_keywords (descriptor_item, instantiator))
399         descriptor_item = Qnil;
400     }
401
402   /* Record new items for update. *_redisplay will do the
403      rest. */
404   if (!EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout)
405       && 
406       !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qnative_layout))
407     {
408       if (!NILP (items))
409         {
410           if (NILP (descriptor_item))
411             descriptor_item = IMAGE_INSTANCE_WIDGET_ITEM (ii);
412           
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));
417 #endif
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));
423         }
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) 
427                && 
428                CONSP (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
429         {
430           descriptor_item = Fcons 
431             (descriptor_item,
432              copy_gui_item_tree (XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii))));
433         }
434     }
435
436   if (!NILP (descriptor_item))
437     {
438       IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = descriptor_item;
439       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 1;
440     }
441
442   UNGCPRO;
443       
444   /* Now try device specific methods first ... */
445   meths = decode_device_ii_format (image_instance_device (image_instance),
446                                    IMAGE_INSTANCE_WIDGET_TYPE (ii),
447                                    ERROR_ME_NOT);
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),
451                                    ERROR_ME_NOT);
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);
457 #endif
458 }
459
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! */
468 void
469 redisplay_widget (Lisp_Object widget)
470 {
471   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (widget);
472   struct image_instantiator_methods* meths;
473
474   if (!WIDGET_IMAGE_INSTANCEP (widget)
475       || EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout)
476       || EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qnative_layout))
477     return;
478
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), 
482                                    ERROR_ME_NOT);
483   MAYBE_IIFORMAT_METH (meths, redisplay, (widget));
484
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));
493
494   /* Pick up the items we recorded earlier. */
495   if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii))
496     {
497       IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
498         IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii);
499       IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil;
500     }
501 }
502
503 /* Determine the spacing of the widget. */
504 static int
505 widget_spacing (Lisp_Object domain)
506 {
507   if (HAS_DEVMETH_P (DOMAIN_XDEVICE (domain), widget_spacing))
508     return DEVMETH (DOMAIN_XDEVICE (domain),
509                     widget_spacing, (0));
510   else 
511     return DEFAULT_WIDGET_SPACING;
512 }
513
514 /* Query for a widgets desired geometry. If no type specific method is
515    provided then use the widget text to calculate sizes. */
516 static void
517 widget_query_geometry (Lisp_Object image_instance,
518                        int* width, int* height,
519                        enum image_instance_geometry disp, Lisp_Object domain)
520 {
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;
525
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);
529
530   if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)
531       ||
532       IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
533     {
534       /* .. then try device specific methods ... */
535       meths = decode_device_ii_format (image_instance_device (image_instance),
536                                        IMAGE_INSTANCE_WIDGET_TYPE (ii),
537                                        ERROR_ME_NOT);
538       if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
539         IIFORMAT_METH (meths, query_geometry, (image_instance,
540                                                width, height, disp,
541                                                domain));
542       else
543         {
544           /* ... then format specific methods ... */
545           meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
546                                            ERROR_ME_NOT);
547           if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
548             IIFORMAT_METH (meths, query_geometry, (image_instance,
549                                                    width, height, disp,
550                                                    domain));
551           else
552             {
553               int w, h;
554
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),
559                                      &w, &h, 0, domain);
560               /* Adjust the size for borders. */
561               if (width && IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
562                 *width = w + 2 * widget_instance_border_width (ii);
563               if (height && IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
564                 *height = h +  2 * widget_instance_border_width (ii);
565             }
566         }
567       /* Finish off with dynamic sizing. */
568       if (width && !NILP (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii)))
569         {
570           dynamic_width = Feval (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii));
571           if (INTP (dynamic_width))
572             *width = XINT (dynamic_width);
573         }
574       if (height && !NILP (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii)))
575         {
576           dynamic_height = Feval (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii));
577           if (INTP (dynamic_height))
578             *height = XINT (dynamic_height);
579         }
580     }
581 }
582
583 static int
584 widget_layout (Lisp_Object image_instance,
585                int width, int height, int xoffset, int yoffset,
586                Lisp_Object domain)
587 {
588   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
589   struct image_instantiator_methods* meths;
590
591   /* .. then try device specific methods ... */
592   meths = decode_device_ii_format (image_instance_device (image_instance),
593                                    IMAGE_INSTANCE_WIDGET_TYPE (ii),
594                                    ERROR_ME_NOT);
595   if (meths && HAS_IIFORMAT_METH_P (meths, layout))
596     return IIFORMAT_METH (meths, layout, (image_instance,
597                                           width, height, xoffset, yoffset,
598                                           domain));
599   else
600     {
601       /* ... then format specific methods ... */
602       meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
603                                        ERROR_ME_NOT);
604       if (meths && HAS_IIFORMAT_METH_P (meths, layout))
605         return IIFORMAT_METH (meths, layout, (image_instance,
606                                               width, height, xoffset, yoffset,
607                                               domain));
608     }
609   return 1;
610 }
611
612 static void
613 widget_validate (Lisp_Object instantiator)
614 {
615   Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
616
617   if (NILP (desc))
618     syntax_error ("Must supply :descriptor", instantiator);
619
620   if (VECTORP (desc))
621     gui_parse_item_keywords (desc);
622
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);
626
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);
630 }
631
632 static void
633 combo_box_validate (Lisp_Object instantiator)
634 {
635   widget_validate (instantiator);
636   if (NILP (find_keyword_in_vector (instantiator, Q_items)))
637     syntax_error ("Must supply item list", instantiator);
638 }
639
640 /* we need to convert things like glyphs to images, eval expressions
641    etc.*/
642 static Lisp_Object
643 widget_normalize (Lisp_Object inst, Lisp_Object console_type,
644                   Lisp_Object dest_mask)
645 {
646   /* This function can call lisp */
647   Lisp_Object glyph = find_keyword_in_vector (inst, Q_image);
648
649   /* we need to eval glyph if its an expression, we do this for the
650      same reasons we normalize file to data.
651
652      #### should just normalize the data. */
653   if (!NILP (glyph))
654     {
655       substitute_keyword_value (inst, Q_image, glyph_instantiator_to_glyph (glyph));
656     }
657
658   return inst;
659 }
660
661 static void
662 initialize_widget_image_instance (Lisp_Image_Instance *ii, Lisp_Object type)
663 {
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;
678 }
679
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) */
686 void
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)
690 {
691   /* #### practically all of this should be moved to widget_update()
692      so that users can dynamically change all possible widget
693      properties. */
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;
707
708   /* this just does pixel type sizing */
709   subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
710                          dest_mask, domain);
711
712   if (!(dest_mask & IMAGE_WIDGET_MASK))
713     incompatible_image_types (instantiator, dest_mask, IMAGE_WIDGET_MASK);
714
715   initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]);
716
717   IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
718
719   /* retrieve the fg and bg colors */
720   if (!NILP (face))
721     SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Fget_face (face));
722
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.
727
728      #### This is bogus in that descriptor and items share the same slot, 
729      we should rationalize. */
730   if (VECTORP (desc))
731     {
732       IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
733         gui_parse_item_keywords_no_errors (desc);
734     }
735   else
736     {
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);
740     }
741
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;
745
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))
749     {
750       IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
751         Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii),
752                parse_gui_item_tree_children (items));
753     }
754
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 */
760     {
761       if (!INTP (pixwidth))
762         IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii) = pixwidth;
763       else
764         {
765           pw = XINT (pixwidth);
766           IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
767         }
768     }
769   else if (!NILP (width))
770     {
771       tw = XINT (width);
772       IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
773     }
774
775   if (!NILP (pixheight))
776     {
777       if (!INTP (pixheight))
778         IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii) = pixheight;
779       else
780         {
781           ph = XINT (pixheight);
782           IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
783         }
784     }
785   else if (!NILP (height) && XINT (height) > 1)
786     {
787       th = XINT (height);
788       IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
789     }
790
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. */
797   if (tw)
798     {
799       int charwidth;
800       default_face_font_info (domain, 0, 0, 0, &charwidth, 0);
801       pw = ROUND_UP (charwidth * tw + 4 * widget_instance_border_width (ii), charwidth);
802     }
803
804   /* For heights the widget face is more appropriate. */
805   if (th == 1) 
806     {
807       int charheight;
808       if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii))) 
809         {
810           query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
811                                  IMAGE_INSTANCE_WIDGET_FACE (ii),
812                                  0, &charheight, 0, domain);
813         }
814       else 
815         {
816           default_face_font_info (domain, 0, 0, &charheight, 0, 0);
817         }
818       ph = (charheight + 2 * widget_instance_border_width (ii)) * th;
819     }
820   /* For heights > 1 use logical units. */
821   else if (th > 1) 
822     {
823       ph = widget_logical_unit_height (ii) * th;
824     }
825
826   /* for a widget with an image pick up the dimensions from that */
827   if (!NILP (glyph))
828     {
829       if (!pw)
830         pw = glyph_width (glyph, image_instance) + 2 * widget_instance_border_width (ii);
831       if (!ph)
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;
835     }
836
837   /* Pick up the margin width. */
838   if (!NILP (mwidth))
839     IMAGE_INSTANCE_MARGIN_WIDTH (ii) = XINT (mwidth);
840
841   IMAGE_INSTANCE_WANTS_INITIAL_FOCUS (ii) = !NILP (ifocus);
842
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
847      dimensions. */
848   if (pw)       IMAGE_INSTANCE_WIDTH (ii) = pw;
849   if (ph)       IMAGE_INSTANCE_HEIGHT (ii) = ph;
850 }
851
852 static void
853 widget_post_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
854                          Lisp_Object domain)
855 {
856 #ifdef DEBUG_WIDGETS
857   debug_widget_instances++;
858   stderr_out ("instantiated ");
859   debug_print (instantiator);
860   stderr_out ("%d widgets instantiated\n", debug_widget_instances);
861 #endif
862 }
863
864 /* Get the geometry of a button control. We need to adjust the size
865    depending on the type of button. */
866 static void
867 button_query_geometry (Lisp_Object image_instance,
868                        int* width, int* height,
869                        enum image_instance_geometry disp, Lisp_Object domain)
870 {
871   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
872   int w, h;
873   query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
874                          IMAGE_INSTANCE_WIDGET_FACE (ii),
875                          &w, &h, 0, domain);
876   /* Adjust the size for borders. */
877   if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
878     {
879       *width = w + 3 * widget_instance_border_width (ii);
880
881       if (EQ (XGUI_ITEM (IMAGE_INSTANCE_WIDGET_ITEM (ii))->style, Qradio)
882           ||
883           EQ (XGUI_ITEM (IMAGE_INSTANCE_WIDGET_ITEM (ii))->style, Qtoggle))
884         /* This is an approximation to the size of the actual button bit. */
885         *width += 12;
886     }
887   if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
888     *height = h +  3 * widget_instance_border_width (ii);
889 }
890
891 /* Get the geometry of an edit field. */
892 static void
893 edit_field_query_geometry (Lisp_Object image_instance,
894                        int* width, int* height,
895                        enum image_instance_geometry disp, Lisp_Object domain)
896 {
897   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
898   int w, h;
899   query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
900                          IMAGE_INSTANCE_WIDGET_FACE (ii),
901                          &w, &h, 0, domain);
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);
907 }
908
909 /* tree-view geometry - get the height right */
910 static void
911 tree_view_query_geometry (Lisp_Object image_instance,
912                           int* width, int* height,
913                           enum image_instance_geometry disp, Lisp_Object domain)
914 {
915   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
916   Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
917
918
919   if (*width)
920     {
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);
925     }
926   if (*height)
927     {
928       int len, h;
929       /* #### widget face would be better here. */
930       default_face_font_info (domain, 0, 0, &h, 0, 0);
931       GET_LIST_LENGTH (items, len);
932       *height = len * h;
933     }
934 }
935
936 /* Get the geometry of a tab control. This is based on the number of
937    items and text therin in the tab control. */
938 static void
939 tab_control_query_geometry (Lisp_Object image_instance,
940                             int* width, int* height,
941                             enum image_instance_geometry disp, Lisp_Object domain)
942 {
943   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
944   Lisp_Object items = XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii));
945   Lisp_Object rest;
946   int tw = 0, th = 0;
947
948   LIST_LOOP (rest, items)
949     {
950       int h, w;
951
952       query_string_geometry (XGUI_ITEM (XCAR (rest))->name,
953                              IMAGE_INSTANCE_WIDGET_FACE (ii),
954                              &w, &h, 0, domain);
955       tw += 5 * widget_instance_border_width (ii); /* some bias */
956       tw += w;
957       th = max (th, h + 2 * widget_instance_border_width (ii));
958     }
959
960   /* Fixup returned values depending on orientation. */
961   if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii))
962     {
963       if (height)       *height = tw;
964       if (width)        *width = th;
965     }
966   else
967     {
968       if (height)       *height = th;
969       if (width)        *width = tw;
970     }
971 }
972
973 /* Determine whether only the order has changed for a tab. */
974 int tab_control_order_only_changed (Lisp_Object image_instance)
975 {
976   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
977   int found = 0, len, pending_len;
978   Lisp_Object rest;
979
980   /* Degenerate case. */
981   if (NILP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)))
982     return 1;
983
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),
987                    pending_len);
988   if (len == pending_len)
989     {
990       LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
991         {
992           Lisp_Object pending_rest;
993           found = 0;
994           LIST_LOOP (pending_rest,
995                      XCDR (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)))
996             {
997               if (gui_item_equal_sans_selected (XCAR (rest),
998                                                 XCAR (pending_rest), 0))
999                 {
1000                   found = 1;
1001                   break;
1002                 }
1003             }
1004           if (!found)
1005             break;
1006         }
1007     }
1008   return found;
1009 }
1010
1011 \f
1012 /*****************************************************************************
1013  *                              widget layout                               *
1014  *****************************************************************************/
1015 /* We need to cascade normalization.*/
1016 static Lisp_Object
1017 layout_normalize (Lisp_Object inst, Lisp_Object console_type,
1018                   Lisp_Object dest_mask)
1019 {
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 */
1024   Lisp_Object items;
1025
1026   GCPRO2 (alist, new_items);
1027   alist = tagged_vector_to_alist (inst);
1028   items = assq_no_quit (Q_items, alist);
1029
1030   /* We need to normalize sub-objects. */
1031   if (!NILP (items))
1032     {
1033       Lisp_Object rest;
1034       LIST_LOOP (rest, XCDR (items))
1035         {
1036           /* Substitute the new instantiator */
1037           new_items = Fcons (normalize_image_instantiator (XCAR (rest),
1038                                                            console_type, dest_mask),
1039                              new_items);
1040         }
1041       new_items = Fnreverse (new_items);
1042       Fsetcdr (items, new_items);
1043     }
1044   /* Normalize the border spec. */
1045   border = assq_no_quit (Q_border, alist);
1046   if (!NILP (border) && VECTORP (XCDR (border)))
1047     {
1048       Fsetcdr (border, normalize_image_instantiator (XCDR (border),
1049                                                      console_type, dest_mask));
1050     }
1051
1052   {
1053     Lisp_Object result = alist_to_tagged_vector (XVECTOR_DATA (inst)[0],
1054                                                  alist);
1055     free_alist (alist);
1056     RETURN_UNGCPRO (result);
1057   }
1058 }
1059
1060 /* Update the instances in the layout. */
1061 static void
1062 layout_update (Lisp_Object image_instance, Lisp_Object instantiator)
1063 {
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;
1074
1075   /* Pick up horizontal justification, left is the default.*/
1076   if (!NILP (hjustify)) 
1077     {
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;
1082     }
1083   /* If not set use general justification. */
1084   else if (!NILP (justify))
1085     {
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;
1090     }
1091
1092   /* Pick up vertical justification, top is the default. */
1093   if (!NILP (vjustify)) 
1094     {
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;
1099     }
1100   /* If not set use general justification. */
1101   else if (!NILP (justify)) 
1102     {
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;
1107     }
1108
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. */
1111   GCPRO1 (border);
1112
1113   if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)))
1114     {
1115       border = XCAR (children);
1116       children = XCDR (children);
1117     }
1118
1119 #ifdef DEBUG_WIDGET_OUTPUT
1120   stderr_out ("layout updated\n");
1121 #endif
1122   /* Update the border. */
1123   if (!NILP (border_inst))
1124     {
1125       if (VECTORP (border_inst))
1126         {
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. */
1130           if (!NILP (border))
1131             call3 (Qset_glyph_image, border, border_inst,
1132                    IMAGE_INSTANCE_DOMAIN (ii));
1133           else
1134             {
1135               border = Fcons (call1 (Qmake_glyph, border_inst), Qnil);
1136               structure_changed = 1;
1137             }
1138           IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (0);
1139         }
1140       else
1141         {
1142           if (!NILP (border))
1143             {
1144               border = Qnil;
1145               structure_changed = 1;
1146             }
1147           if (EQ (border_inst, Qt))
1148               IMAGE_INSTANCE_LAYOUT_BORDER (ii) = Qetched_in;
1149           else
1150             IMAGE_INSTANCE_LAYOUT_BORDER (ii) = border_inst;
1151         }
1152     }
1153
1154   /* Pick up the sub-widgets. */
1155   if (!NILP (items))
1156     {
1157       int len1, len2;
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)
1162         {
1163           /* Pick up the sub-widgets. */
1164           for (; !NILP (children); children = XCDR (children), items = XCDR (items))
1165             {
1166               call3 (Qset_glyph_image, XCAR (children), XCAR (items),
1167                      IMAGE_INSTANCE_DOMAIN (ii));
1168             }
1169         }
1170       /* The structure has changed so start over. */
1171       else
1172         {
1173           /* Instantiate any new glyphs. */
1174           for (; !NILP (items); items = XCDR (items))
1175             {
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);
1179             }
1180           IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = Fnreverse (border);
1181         }
1182     }
1183   UNGCPRO;
1184 }
1185
1186 static void
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)
1190 {
1191   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1192   Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
1193
1194 #ifdef DEBUG_WIDGET_OUTPUT
1195   stderr_out ("layout instantiated\n");
1196 #endif
1197   /* Do widget type instantiation first. */
1198   widget_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
1199                       dest_mask, domain);
1200
1201   if (NILP (orient))
1202     {
1203       IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_VERTICAL;
1204     }
1205
1206   /* Get child glyphs and finish instantiation. We can't do image
1207      instance children yet as we might not have a containing
1208      window. */
1209   layout_update (image_instance, instantiator);
1210 }
1211
1212 static void
1213 layout_post_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1214                          Lisp_Object domain)
1215 {
1216 }
1217
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:
1231
1232    1. A button is sized to accommodate its text, the text changes and the
1233    button should change size also.
1234
1235    2. A button is given an explicit size. Its size should never change.
1236
1237    3. Layout is put inside an area. The size of the area changes, the
1238    layout should change with it.
1239
1240    4. A button grows to accommodate additional text. The whitespace
1241    around it should be modified to cope with the new layout
1242    requirements.
1243
1244    5. A button grows. The area surrounding it should grow also if
1245    possible.
1246
1247    What metrics are important?
1248    1. Actual width and height.
1249
1250    2. Whether the width and height are what the widget actually wants, or
1251    whether it can grow or shrink.
1252
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
1262    rest. 
1263
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
1285    appropriately. */
1286
1287 /* Query the geometry of a layout widget. */
1288 static void
1289 layout_query_geometry (Lisp_Object image_instance, int* width,
1290                        int* height, enum image_instance_geometry disp,
1291                        Lisp_Object domain)
1292 {
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;
1297
1298   /* If we are not initialized then we won't have any children. */
1299   if (!IMAGE_INSTANCE_INITIALIZED (ii))
1300       return;
1301
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);
1305
1306   /* If we are not allowed to dynamically size then return. */
1307   if (!IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)
1308       &&
1309       !IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
1310     return;
1311
1312   luh = widget_logical_unit_height (ii);
1313
1314   /* Pick up the border text if we have one. */
1315   if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)))
1316     {
1317       glyph_query_geometry (XCAR (items), &gwidth, &gheight, disp,
1318                             image_instance);
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);
1324     }
1325
1326   /* Flip through the items to work out how much stuff we have to display */
1327   LIST_LOOP (rest, items)
1328     {
1329       Lisp_Object glyph = XCAR (rest);
1330       glyph_query_geometry (glyph, &gwidth, &gheight, disp, image_instance);
1331
1332       nitems ++;
1333       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL)
1334         {
1335           maxph = max (maxph, gheight);
1336           maxpw += gwidth;
1337         }
1338       else
1339         {
1340           maxpw = max (maxpw, gwidth);
1341           maxph += gheight;
1342         }
1343     }
1344
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)))
1349       {
1350         Lisp_Object dynamic_width =
1351           Feval (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii));
1352         if (INTP (dynamic_width))
1353           *width = XINT (dynamic_width);
1354       }
1355     else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL) 
1356       {
1357         *width = maxpw + ((nitems + 1) * widget_instance_border_width (ii) +
1358                           IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2;
1359       }
1360     else
1361       {
1362         *width = maxpw + 2 * (widget_instance_border_width (ii) * 2 +
1363                               IMAGE_INSTANCE_MARGIN_WIDTH (ii));
1364       }
1365   }
1366
1367   /* Work out vertical spacings. */
1368   if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)) {
1369     if (!NILP (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii)))
1370       {
1371         Lisp_Object dynamic_height =
1372           Feval (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii));
1373         if (INTP (dynamic_height))
1374           *height = XINT (dynamic_height);
1375       }
1376     else if (IMAGE_INSTANCE_SUBWINDOW_LOGICAL_LAYOUT (ii))
1377       {
1378         *height = nitems * luh + ph_adjust;
1379       }
1380     else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_VERTICAL)
1381       {
1382         *height = maxph + ((nitems + 1) * widget_instance_border_width (ii) +
1383                            IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2 + ph_adjust;
1384       }
1385     else
1386       {
1387         *height = maxph + (2 * widget_instance_border_width (ii) +
1388                            IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2 + ph_adjust;
1389       }
1390   }
1391 #ifdef DEBUG_WIDGET_OUTPUT
1392   stderr_out ("layout wants %dx%d\n", *width, *height);
1393 #endif
1394 }
1395
1396 int
1397 layout_layout (Lisp_Object image_instance,
1398                int width, int height, int xoffset, int yoffset,
1399                Lisp_Object domain)
1400 {
1401   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1402   Lisp_Object rest;
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);
1409
1410   /* If we are not initialized then we won't have any children. */
1411   if (!IMAGE_INSTANCE_INITIALIZED (ii))
1412       return 0;
1413
1414 #ifdef DEBUG_WIDGET_OUTPUT
1415   stderr_out ("layout output %dx%d\n", width, height);
1416 #endif
1417
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)))
1425     {
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);
1435
1436       /* #### Really, what should this be? */
1437       glyph_do_layout (border, gwidth, gheight, BORDER_FIDDLE_FACTOR, 0,
1438                        image_instance);
1439     }
1440
1441   /* Flip through the items to work out how much stuff we have to display. */
1442   LIST_LOOP (rest, items)
1443     {
1444       Lisp_Object glyph = XCAR (rest);
1445
1446       glyph_query_geometry (glyph, &gwidth, &gheight,
1447                             IMAGE_DESIRED_GEOMETRY, image_instance);
1448       nitems ++;
1449       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1450           == LAYOUT_HORIZONTAL)
1451         {
1452           maxph = max (maxph, gheight);
1453           maxpw += gwidth;
1454         }
1455       else
1456         {
1457           maxpw = max (maxpw, gwidth);
1458           maxph += gheight;
1459         }
1460     }
1461
1462   /* work out spacing between items and bounds of the layout */
1463   if (width < maxpw)
1464     /* The user wants a smaller space than the largest item, so we
1465        just provide default spacing and will let the output routines
1466        clip. */
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
1471        evenly. */
1472     horiz_spacing = (width - (maxpw +
1473                               IMAGE_INSTANCE_MARGIN_WIDTH (ii) * 2))
1474       / (nitems + 1);
1475   else
1476     horiz_spacing = (width - maxpw) / 2
1477       - IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1478
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
1485      accommodate it. */
1486   if (height < maxph)
1487     vert_spacing = widget_spacing (IMAGE_INSTANCE_DOMAIN (ii)) * 2;
1488   else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1489            == LAYOUT_VERTICAL)
1490     {
1491       if (!IMAGE_INSTANCE_SUBWINDOW_V_CENTERED (ii))
1492         vert_spacing = widget_spacing (IMAGE_INSTANCE_DOMAIN (ii)) * 2;
1493       else
1494         vert_spacing = (height - (maxph + ph_adjust +
1495                                   IMAGE_INSTANCE_MARGIN_WIDTH (ii) * 2))
1496           / (nitems + 1);
1497     }
1498   else
1499     vert_spacing = (height - (maxph + ph_adjust)) / 2
1500       - IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1501
1502   y = yoffset = vert_spacing + ph_adjust + IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1503   x = horiz_spacing + IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1504
1505   /* Now flip through putting items where we want them, paying
1506      attention to justification. Make sure we don't mess with the
1507      border glyph. */
1508   LIST_LOOP (rest, items)
1509     {
1510       Lisp_Object glyph = XCAR (rest);
1511
1512       glyph_query_geometry (glyph, &gwidth, &gheight,
1513                             IMAGE_DESIRED_GEOMETRY, image_instance);
1514
1515       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL)
1516         {
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;
1521         }
1522       else
1523         {
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;
1528         }
1529
1530       /* Now layout subwidgets if they require it. */
1531       glyph_do_layout (glyph, gwidth, gheight, x, y, image_instance);
1532
1533       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL)
1534         {
1535           x += (gwidth + horiz_spacing);
1536         }
1537       else
1538         {
1539           y += (gheight + vert_spacing);
1540           if (!IMAGE_INSTANCE_SUBWINDOW_V_CENTERED (ii))
1541             {
1542               /* justified, vertical layout, try and align on logical unit
1543                  boundaries. */
1544               y = ROUND_UP (y - yoffset, luh) + yoffset;
1545             }
1546         }
1547
1548     }
1549   return 1;
1550 }
1551
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.
1556
1557    #### Eventually we should allow some more intelligent access to
1558    sub-widgets. */
1559 static Lisp_Object
1560 layout_property (Lisp_Object image_instance, Lisp_Object prop)
1561 {
1562   /* This function can GC. */
1563   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1564   if (EQ (prop, Q_items))
1565     {
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)));
1570       else
1571         return Fcopy_sequence (IMAGE_INSTANCE_LAYOUT_CHILDREN (ii));
1572     }
1573   return Qunbound;
1574 }
1575
1576 /* Layout subwindows if they are real subwindows. */
1577 static int
1578 native_layout_layout (Lisp_Object image_instance,
1579                       int width, int height, int xoffset, int yoffset,
1580                       Lisp_Object domain)
1581 {
1582   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
1583   Lisp_Object rest;
1584
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))
1589     return 0;
1590
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);
1594
1595   LIST_LOOP (rest, IMAGE_INSTANCE_LAYOUT_CHILDREN (ii))
1596     {
1597       struct display_glyph_area dga;
1598       dga.xoffset = 0;
1599       dga.yoffset = 0;
1600       dga.width = IMAGE_INSTANCE_WIDTH (ii);
1601       dga.height = IMAGE_INSTANCE_HEIGHT (ii);
1602
1603       map_subwindow (XCAR (rest),
1604                      IMAGE_INSTANCE_XOFFSET (ii),
1605                      IMAGE_INSTANCE_YOFFSET (ii), &dga);
1606     }
1607   return 1;
1608 }
1609
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.
1614 */
1615        (width, face, domain))
1616 {
1617   int w, neww, charwidth;
1618   int border_width = DEFAULT_WIDGET_BORDER_WIDTH;
1619
1620   if (NILP (domain))
1621     domain = Fselected_frame (Qnil);
1622
1623   CHECK_INT (width);
1624   w = XINT (width);
1625   
1626   if (HAS_DEVMETH_P (DOMAIN_XDEVICE (domain), widget_border_width))
1627     border_width = DEVMETH (DOMAIN_XDEVICE (domain), widget_border_width, ());
1628
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;
1632   
1633   return make_int (neww);
1634 }
1635
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.
1640
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.
1649
1650 Since frame sizes are measured in characters, this function allows you
1651 to do appropriate conversion between logical units and characters.
1652 */
1653        (height, face, domain))
1654 {
1655   int h, newh, charheight;
1656   
1657   CHECK_INT (height);
1658   if (NILP (domain))
1659     domain = Fselected_frame (Qnil);
1660
1661   h = XINT (height);
1662
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)
1666     / charheight;
1667
1668   return make_int (newh);
1669 }
1670
1671 \f
1672 /************************************************************************/
1673 /*                            initialization                            */
1674 /************************************************************************/
1675
1676 void
1677 syms_of_glyphs_widget (void)
1678 {
1679   DEFSYMBOL (Qetched_in);
1680   DEFSYMBOL (Qetched_out);
1681   DEFSYMBOL (Qbevel_in);
1682   DEFSYMBOL (Qbevel_out);
1683   DEFSYMBOL (Qmake_glyph);
1684
1685   DEFSUBR (Fwidget_logical_to_character_height);
1686   DEFSUBR (Fwidget_logical_to_character_width);
1687 }
1688
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);              \
1706 } while (0)
1707
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);                    \
1714 } while (0)
1715
1716
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);
1724 }
1725
1726 static void image_instantiator_buttons (void)
1727 {
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);
1740 }
1741
1742 static void image_instantiator_edit_fields (void)
1743 {
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);
1753 }
1754
1755 static void image_instantiator_combo_box (void)
1756 {
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);
1761
1762   VALID_GUI_KEYWORDS (combo_box);
1763
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);
1770 }
1771
1772 static void image_instantiator_scrollbar (void)
1773 {
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);
1781
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);
1787 }
1788
1789 static void image_instantiator_progress_guage (void)
1790 {
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);
1799
1800   IIFORMAT_VALID_KEYWORD (progress_gauge, Q_value, check_valid_int);
1801 }
1802
1803 static void image_instantiator_tree_view (void)
1804 {
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);
1815 }
1816
1817 static void image_instantiator_tab_control (void)
1818 {
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);
1831 }
1832
1833 static void image_instantiator_labels (void)
1834 {
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);
1842 }
1843
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)
1854
1855 static void image_instantiator_layout (void)
1856 {
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);
1867
1868   VALID_GUI_KEYWORDS (layout);
1869   VALID_LAYOUT_KEYWORDS (layout);
1870 }
1871
1872 static void image_instantiator_native_layout (void)
1873 {
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);
1884
1885   VALID_GUI_KEYWORDS (native_layout);
1886   VALID_LAYOUT_KEYWORDS (native_layout);
1887 }
1888
1889 void
1890 image_instantiator_format_create_glyphs_widget (void)
1891 {
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();
1903 }
1904
1905 void
1906 reinit_vars_of_glyphs_widget (void)
1907 {
1908 #ifdef DEBUG_WIDGETS
1909   debug_widget_instances = 0;
1910 #endif
1911 }
1912
1913 void
1914 vars_of_glyphs_widget (void)
1915 {
1916   reinit_vars_of_glyphs_widget ();
1917 }
1918
1919
1920 void
1921 specifier_vars_of_glyphs_widget (void)
1922 {
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.
1927 */ );
1928   Vwidget_border_width = Fmake_specifier (Qnatnum);
1929 }