91946b0ea7e30a5981e7bb137b9c719d70f40209
[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
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 (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);
565             }
566         }
567       /* Finish off with dynamic sizing. */
568       if (!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 (!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       items = XCDR (items);
1321     }
1322
1323   /* Flip through the items to work out how much stuff we have to display */
1324   LIST_LOOP (rest, items)
1325     {
1326       Lisp_Object glyph = XCAR (rest);
1327       glyph_query_geometry (glyph, &gwidth, &gheight, disp, image_instance);
1328
1329       nitems ++;
1330       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL)
1331         {
1332           maxph = max (maxph, gheight);
1333           maxpw += gwidth;
1334         }
1335       else
1336         {
1337           maxpw = max (maxpw, gwidth);
1338           maxph += gheight;
1339         }
1340     }
1341
1342   /* Work out minimum space we need to fit all the items. This could
1343      have been fixed by the user. */
1344   if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii)) {
1345     if (!NILP (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii)))
1346       {
1347         Lisp_Object dynamic_width =
1348           Feval (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii));
1349         if (INTP (dynamic_width))
1350           *width = XINT (dynamic_width);
1351       }
1352     else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL) 
1353       {
1354         *width = maxpw + ((nitems + 1) * widget_instance_border_width (ii) +
1355                           IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2;
1356       }
1357     else
1358       {
1359         *width = maxpw + 2 * (widget_instance_border_width (ii) * 2 +
1360                               IMAGE_INSTANCE_MARGIN_WIDTH (ii));
1361       }
1362   }
1363
1364   /* Work out vertical spacings. */
1365   if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)) {
1366     if (!NILP (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii)))
1367       {
1368         Lisp_Object dynamic_height =
1369           Feval (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii));
1370         if (INTP (dynamic_height))
1371           *height = XINT (dynamic_height);
1372       }
1373     else if (IMAGE_INSTANCE_SUBWINDOW_LOGICAL_LAYOUT (ii))
1374       {
1375         *height = nitems * luh + ph_adjust;
1376       }
1377     else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_VERTICAL)
1378       {
1379         *height = maxph + ((nitems + 1) * widget_instance_border_width (ii) +
1380                            IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2 + ph_adjust;
1381       }
1382     else
1383       {
1384         *height = maxph + (2 * widget_instance_border_width (ii) +
1385                            IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2 + ph_adjust;
1386       }
1387   }
1388 #ifdef DEBUG_WIDGET_OUTPUT
1389   stderr_out ("layout wants %dx%d\n", *width, *height);
1390 #endif
1391 }
1392
1393 int
1394 layout_layout (Lisp_Object image_instance,
1395                int width, int height, int xoffset, int yoffset,
1396                Lisp_Object domain)
1397 {
1398   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1399   Lisp_Object rest;
1400   Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii);
1401   int x, y, maxph = 0, maxpw = 0, nitems = 0,
1402     horiz_spacing, vert_spacing, ph_adjust = 0;
1403   int gheight, gwidth;
1404   /* See comments in widget_logical_unit_height(). */
1405   int luh = widget_logical_unit_height (ii);
1406
1407   /* If we are not initialized then we won't have any children. */
1408   if (!IMAGE_INSTANCE_INITIALIZED (ii))
1409       return 0;
1410
1411 #ifdef DEBUG_WIDGET_OUTPUT
1412   stderr_out ("layout output %dx%d\n", width, height);
1413 #endif
1414
1415   /* Pick up the border text if we have one. A border can have the
1416      values Qetched_in, Qetched_out, Qbevel_in, Qbevel_out or an
1417      integer. The first four just affect the display properties of the
1418      border that is drawn. The last is an offset and implies that the
1419      first item in the list of subcontrols is a text control that
1420      should be displayed on the border. */
1421   if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)))
1422     {
1423       Lisp_Object border = XCAR (items);
1424       items = XCDR (items);
1425       glyph_query_geometry (border, &gwidth, &gheight,
1426                             IMAGE_DESIRED_GEOMETRY, image_instance);
1427       /* The vertical offset for subsequent items is the full height
1428          of the border glyph. */
1429       ph_adjust = gheight;
1430       /* The offset for the border is half the glyph height. */
1431       IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (gheight / 2);
1432
1433       /* #### Really, what should this be? */
1434       glyph_do_layout (border, gwidth, gheight, 10, 0,
1435                        image_instance);
1436     }
1437
1438   /* Flip through the items to work out how much stuff we have to display. */
1439   LIST_LOOP (rest, items)
1440     {
1441       Lisp_Object glyph = XCAR (rest);
1442
1443       glyph_query_geometry (glyph, &gwidth, &gheight,
1444                             IMAGE_DESIRED_GEOMETRY, image_instance);
1445       nitems ++;
1446       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1447           == LAYOUT_HORIZONTAL)
1448         {
1449           maxph = max (maxph, gheight);
1450           maxpw += gwidth;
1451         }
1452       else
1453         {
1454           maxpw = max (maxpw, gwidth);
1455           maxph += gheight;
1456         }
1457     }
1458
1459   /* work out spacing between items and bounds of the layout */
1460   if (width < maxpw)
1461     /* The user wants a smaller space than the largest item, so we
1462        just provide default spacing and will let the output routines
1463        clip. */
1464     horiz_spacing = widget_spacing (IMAGE_INSTANCE_DOMAIN (ii));
1465   else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1466            == LAYOUT_HORIZONTAL) 
1467     /* We have a larger area to display in so distribute the space
1468        evenly. */
1469     horiz_spacing = (width - (maxpw +
1470                               IMAGE_INSTANCE_MARGIN_WIDTH (ii) * 2))
1471       / (nitems + 1);
1472   else
1473     horiz_spacing = (width - maxpw) / 2
1474       - IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1475
1476   /* We are trying here to get widgets to line up when they are left
1477      or right justified vertically. This means that we must position
1478      widgets on logical unit boundaries, even though their height may
1479      be greater or less than a logical unit. In order to avoid
1480      clipping we need to determine how big the widget wants to be and
1481      then allocate as many logical units as necessary in order to
1482      accommodate it. */
1483   if (height < maxph)
1484     vert_spacing = widget_spacing (IMAGE_INSTANCE_DOMAIN (ii)) * 2;
1485   else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1486            == LAYOUT_VERTICAL)
1487     {
1488       if (!IMAGE_INSTANCE_SUBWINDOW_V_CENTERED (ii))
1489         vert_spacing = widget_spacing (IMAGE_INSTANCE_DOMAIN (ii)) * 2;
1490       else
1491         vert_spacing = (height - (maxph + ph_adjust +
1492                                   IMAGE_INSTANCE_MARGIN_WIDTH (ii) * 2))
1493           / (nitems + 1);
1494     }
1495   else
1496     vert_spacing = (height - (maxph + ph_adjust)) / 2
1497       - IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1498
1499   y = yoffset = vert_spacing + ph_adjust + IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1500   x = horiz_spacing + IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1501
1502   /* Now flip through putting items where we want them, paying
1503      attention to justification. Make sure we don't mess with the
1504      border glyph. */
1505   LIST_LOOP (rest, items)
1506     {
1507       Lisp_Object glyph = XCAR (rest);
1508
1509       glyph_query_geometry (glyph, &gwidth, &gheight,
1510                             IMAGE_DESIRED_GEOMETRY, image_instance);
1511
1512       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL)
1513         {
1514           if (IMAGE_INSTANCE_SUBWINDOW_BOTTOM_JUSTIFIED (ii))
1515             y = height - (gheight + vert_spacing);
1516           else if (IMAGE_INSTANCE_SUBWINDOW_V_CENTERED (ii))
1517             y = (height - gheight) / 2;
1518         }
1519       else
1520         {
1521           if (IMAGE_INSTANCE_SUBWINDOW_RIGHT_JUSTIFIED (ii))
1522             x = width - (gwidth + horiz_spacing);
1523           else if (IMAGE_INSTANCE_SUBWINDOW_H_CENTERED (ii))
1524             x = (width - gwidth) / 2;
1525         }
1526
1527       /* Now layout subwidgets if they require it. */
1528       glyph_do_layout (glyph, gwidth, gheight, x, y, image_instance);
1529
1530       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL)
1531         {
1532           x += (gwidth + horiz_spacing);
1533         }
1534       else
1535         {
1536           y += (gheight + vert_spacing);
1537           if (!IMAGE_INSTANCE_SUBWINDOW_V_CENTERED (ii))
1538             {
1539               /* justified, vertical layout, try and align on logical unit
1540                  boundaries. */
1541               y = ROUND_UP (y - yoffset, luh) + yoffset;
1542             }
1543         }
1544
1545     }
1546   return 1;
1547 }
1548
1549 /* Get the glyphs that comprise a layout. These are created internally
1550    and so are otherwise inaccessible to lisp. We need some way of getting
1551    properties from the widgets that comprise a layout and this is the
1552    simplest way of doing it.
1553
1554    #### Eventually we should allow some more intelligent access to
1555    sub-widgets. */
1556 static Lisp_Object
1557 layout_property (Lisp_Object image_instance, Lisp_Object prop)
1558 {
1559   /* This function can GC. */
1560   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1561   if (EQ (prop, Q_items))
1562     {
1563       if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)) &&
1564           CONSP (IMAGE_INSTANCE_LAYOUT_CHILDREN (ii)))
1565         return Fcopy_sequence (XCDR
1566                                (IMAGE_INSTANCE_LAYOUT_CHILDREN (ii)));
1567       else
1568         return Fcopy_sequence (IMAGE_INSTANCE_LAYOUT_CHILDREN (ii));
1569     }
1570   return Qunbound;
1571 }
1572
1573 /* Layout subwindows if they are real subwindows. */
1574 static int
1575 native_layout_layout (Lisp_Object image_instance,
1576                       int width, int height, int xoffset, int yoffset,
1577                       Lisp_Object domain)
1578 {
1579   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
1580   Lisp_Object rest;
1581
1582   /* The first time this gets called, the layout will be only
1583      partially instantiated. The children get done in
1584      post_instantiate. */
1585   if (!IMAGE_INSTANCE_INITIALIZED (ii))
1586     return 0;
1587
1588   /* Defining this overrides the default layout_layout so we first have to call that to get
1589      suitable instances and values set up. */
1590   layout_layout (image_instance, width, height, xoffset, yoffset, domain);
1591
1592   LIST_LOOP (rest, IMAGE_INSTANCE_LAYOUT_CHILDREN (ii))
1593     {
1594       struct display_glyph_area dga;
1595       dga.xoffset = 0;
1596       dga.yoffset = 0;
1597       dga.width = IMAGE_INSTANCE_WIDTH (ii);
1598       dga.height = IMAGE_INSTANCE_HEIGHT (ii);
1599
1600       map_subwindow (XCAR (rest),
1601                      IMAGE_INSTANCE_XOFFSET (ii),
1602                      IMAGE_INSTANCE_YOFFSET (ii), &dga);
1603     }
1604   return 1;
1605 }
1606
1607 DEFUN ("widget-logical-to-character-width", Fwidget_logical_to_character_width, 1, 3, 0, /*
1608 Convert the width in logical widget units to characters.
1609 Logical widget units do not take into account adjusments made for
1610 layout borders, so this adjusment is approximated.
1611 */
1612        (width, face, domain))
1613 {
1614   int w, neww, charwidth;
1615   int border_width = DEFAULT_WIDGET_BORDER_WIDTH;
1616
1617   if (NILP (domain))
1618     domain = Fselected_frame (Qnil);
1619
1620   CHECK_INT (width);
1621   w = XINT (width);
1622   
1623   if (HAS_DEVMETH_P (DOMAIN_XDEVICE (domain), widget_border_width))
1624     border_width = DEVMETH (DOMAIN_XDEVICE (domain), widget_border_width, ());
1625
1626   default_face_font_info (domain, 0, 0, 0, &charwidth, 0);
1627   neww = ROUND_UP (charwidth * w + 4 * border_width + 2 * widget_spacing (domain), 
1628                 charwidth) / charwidth;
1629   
1630   return make_int (neww);
1631 }
1632
1633 DEFUN ("widget-logical-to-character-height", Fwidget_logical_to_character_height, 1, 3, 0, /*
1634 Convert the height in logical widget units to characters.
1635 Logical widget units do not take into account adjusments made for
1636 layout borders, so this adjustment is approximated.
1637
1638 If the components of a widget layout are justified to the top or the
1639 bottom then they are aligned in terms of `logical units'. This is a
1640 size quantity that is designed to be big enough to accomodate the
1641 largest `single height' widget. It is dependent on the widget face and
1642 some combination of spacing and border-width. Thus if you specify top
1643 or bottom justification in a vertical layout the subcontrols are laid
1644 out one per logical unit. This allows adjoining layouts to have
1645 identical alignment for their subcontrols.
1646
1647 Since frame sizes are measured in characters, this function allows you
1648 to do appropriate conversion between logical units and characters.
1649 */
1650        (height, face, domain))
1651 {
1652   int h, newh, charheight;
1653   
1654   CHECK_INT (height);
1655   if (NILP (domain))
1656     domain = Fselected_frame (Qnil);
1657
1658   h = XINT (height);
1659
1660   default_face_font_info (domain, 0, 0, &charheight, 0, 0);
1661   newh = ROUND_UP (logical_unit_height (Fsymbol_name (Qwidget), 
1662                                         Vwidget_face, domain) * h, charheight)
1663     / charheight;
1664
1665   return make_int (newh);
1666 }
1667
1668 \f
1669 /************************************************************************/
1670 /*                            initialization                            */
1671 /************************************************************************/
1672
1673 void
1674 syms_of_glyphs_widget (void)
1675 {
1676   DEFSYMBOL (Qetched_in);
1677   DEFSYMBOL (Qetched_out);
1678   DEFSYMBOL (Qbevel_in);
1679   DEFSYMBOL (Qbevel_out);
1680   DEFSYMBOL (Qmake_glyph);
1681
1682   DEFSUBR (Fwidget_logical_to_character_height);
1683   DEFSUBR (Fwidget_logical_to_character_width);
1684 }
1685
1686 #define VALID_GUI_KEYWORDS(type) do {                                         \
1687   IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_active, check_valid_anything);      \
1688   IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything);              \
1689   IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string);                  \
1690   IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol);                 \
1691   IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_selected, check_valid_anything);    \
1692   IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything);              \
1693   IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol);                \
1694   IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything);            \
1695   IIFORMAT_VALID_KEYWORD (type, Q_initial_focus, check_valid_anything);       \
1696   IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string);          \
1697   IIFORMAT_VALID_KEYWORD (type, Q_accelerator, check_valid_string);           \
1698   IIFORMAT_VALID_KEYWORD (type, Q_label, check_valid_anything);               \
1699   IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback, check_valid_callback);    \
1700   IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback_ex, check_valid_callback); \
1701   IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_descriptor,                         \
1702                                   check_valid_string_or_vector);              \
1703 } while (0)
1704
1705 #define VALID_WIDGET_KEYWORDS(type) do {                                      \
1706   IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int);                    \
1707   IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int);                   \
1708   IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int_or_function);  \
1709   IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int_or_function); \
1710   IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face);                    \
1711 } while (0)
1712
1713
1714 static void image_instantiator_widget (void)
1715 { /* we only do this for properties */
1716   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget");
1717   IIFORMAT_HAS_METHOD (widget, property);
1718   IIFORMAT_HAS_METHOD (widget, update);
1719   IIFORMAT_HAS_METHOD (widget, query_geometry);
1720   IIFORMAT_HAS_METHOD (widget, layout);
1721 }
1722
1723 static void image_instantiator_buttons (void)
1724 {
1725   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button");
1726   IIFORMAT_HAS_SHARED_METHOD (button, validate, widget);
1727   IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget);
1728   IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget);
1729   IIFORMAT_HAS_SHARED_METHOD (button, post_instantiate, widget);
1730   IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget);
1731   IIFORMAT_HAS_SHARED_METHOD (button, governing_domain, subwindow);
1732   IIFORMAT_HAS_METHOD (button, query_geometry);
1733   IIFORMAT_VALID_KEYWORD (button,
1734                           Q_image, check_valid_instantiator);
1735   VALID_WIDGET_KEYWORDS (button);
1736   VALID_GUI_KEYWORDS (button);
1737 }
1738
1739 static void image_instantiator_edit_fields (void)
1740 {
1741   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit_field, "edit-field");
1742   IIFORMAT_HAS_SHARED_METHOD (edit_field, validate, widget);
1743   IIFORMAT_HAS_SHARED_METHOD (edit_field, possible_dest_types, widget);
1744   IIFORMAT_HAS_SHARED_METHOD (edit_field, instantiate, widget);
1745   IIFORMAT_HAS_SHARED_METHOD (edit_field, post_instantiate, widget);
1746   IIFORMAT_HAS_SHARED_METHOD (edit_field, governing_domain, subwindow);
1747   IIFORMAT_HAS_METHOD (edit_field, query_geometry);
1748   VALID_WIDGET_KEYWORDS (edit_field);
1749   VALID_GUI_KEYWORDS (edit_field);
1750 }
1751
1752 static void image_instantiator_combo_box (void)
1753 {
1754   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo_box, "combo-box");
1755   IIFORMAT_HAS_METHOD (combo_box, validate);
1756   IIFORMAT_HAS_SHARED_METHOD (combo_box, possible_dest_types, widget);
1757   IIFORMAT_HAS_SHARED_METHOD (combo_box, governing_domain, subwindow);
1758
1759   VALID_GUI_KEYWORDS (combo_box);
1760
1761   IIFORMAT_VALID_KEYWORD (combo_box, Q_width, check_valid_int);
1762   IIFORMAT_VALID_KEYWORD (combo_box, Q_height, check_valid_int);
1763   IIFORMAT_VALID_KEYWORD (combo_box, Q_pixel_width,
1764                           check_valid_int_or_function);
1765   IIFORMAT_VALID_KEYWORD (combo_box, Q_face, check_valid_face);
1766   IIFORMAT_VALID_KEYWORD (combo_box, Q_items, check_valid_item_list);
1767 }
1768
1769 static void image_instantiator_scrollbar (void)
1770 {
1771   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar");
1772   IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget);
1773   IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget);
1774   IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget);
1775   IIFORMAT_HAS_SHARED_METHOD (scrollbar, post_instantiate, widget);
1776   IIFORMAT_HAS_SHARED_METHOD (scrollbar, governing_domain, subwindow);
1777   VALID_GUI_KEYWORDS (scrollbar);
1778
1779   IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width,
1780                           check_valid_int_or_function);
1781   IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height,
1782                           check_valid_int_or_function);
1783   IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face);
1784 }
1785
1786 static void image_instantiator_progress_guage (void)
1787 {
1788   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge, "progress-gauge");
1789   IIFORMAT_HAS_SHARED_METHOD (progress_gauge, validate, widget);
1790   IIFORMAT_HAS_SHARED_METHOD (progress_gauge, possible_dest_types, widget);
1791   IIFORMAT_HAS_SHARED_METHOD (progress_gauge, instantiate, widget);
1792   IIFORMAT_HAS_SHARED_METHOD (progress_gauge, post_instantiate, widget);
1793   IIFORMAT_HAS_SHARED_METHOD (progress_gauge, governing_domain, subwindow);
1794   VALID_WIDGET_KEYWORDS (progress_gauge);
1795   VALID_GUI_KEYWORDS (progress_gauge);
1796
1797   IIFORMAT_VALID_KEYWORD (progress_gauge, Q_value, check_valid_int);
1798 }
1799
1800 static void image_instantiator_tree_view (void)
1801 {
1802   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tree_view, "tree-view");
1803   IIFORMAT_HAS_SHARED_METHOD (tree_view, validate, combo_box);
1804   IIFORMAT_HAS_SHARED_METHOD (tree_view, possible_dest_types, widget);
1805   IIFORMAT_HAS_SHARED_METHOD (tree_view, instantiate, widget);
1806   IIFORMAT_HAS_SHARED_METHOD (tree_view, post_instantiate, widget);
1807   IIFORMAT_HAS_SHARED_METHOD (tree_view, governing_domain, subwindow);
1808   IIFORMAT_HAS_METHOD (tree_view, query_geometry);
1809   VALID_WIDGET_KEYWORDS (tree_view);
1810   VALID_GUI_KEYWORDS (tree_view);
1811   IIFORMAT_VALID_KEYWORD (tree_view, Q_items, check_valid_item_list);
1812 }
1813
1814 static void image_instantiator_tab_control (void)
1815 {
1816   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tab_control, "tab-control");
1817   IIFORMAT_HAS_SHARED_METHOD (tab_control, validate, combo_box);
1818   IIFORMAT_HAS_SHARED_METHOD (tab_control, possible_dest_types, widget);
1819   IIFORMAT_HAS_SHARED_METHOD (tab_control, instantiate, widget);
1820   IIFORMAT_HAS_SHARED_METHOD (tab_control, post_instantiate, widget);
1821   IIFORMAT_HAS_SHARED_METHOD (tab_control, governing_domain, subwindow);
1822   IIFORMAT_HAS_METHOD (tab_control, query_geometry);
1823   VALID_WIDGET_KEYWORDS (tab_control);
1824   VALID_GUI_KEYWORDS (tab_control);
1825   IIFORMAT_VALID_KEYWORD (tab_control, Q_orientation,
1826                           check_valid_tab_orientation);
1827   IIFORMAT_VALID_KEYWORD (tab_control, Q_items, check_valid_item_list);
1828 }
1829
1830 static void image_instantiator_labels (void)
1831 {
1832   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label");
1833   IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget);
1834   IIFORMAT_HAS_SHARED_METHOD (label, instantiate, widget);
1835   IIFORMAT_HAS_SHARED_METHOD (label, post_instantiate, widget);
1836   IIFORMAT_HAS_SHARED_METHOD (label, governing_domain, subwindow);
1837   VALID_WIDGET_KEYWORDS (label);
1838   IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string);
1839 }
1840
1841 #define VALID_LAYOUT_KEYWORDS(layout)                                      \
1842   VALID_WIDGET_KEYWORDS (layout);                                          \
1843   IIFORMAT_VALID_KEYWORD (layout, Q_orientation, check_valid_orientation); \
1844   IIFORMAT_VALID_KEYWORD (layout, Q_justify, check_valid_justification);   \
1845   IIFORMAT_VALID_KEYWORD (layout, Q_vertically_justify, check_valid_justification);   \
1846   IIFORMAT_VALID_KEYWORD (layout, Q_horizontally_justify, check_valid_justification);   \
1847   IIFORMAT_VALID_KEYWORD (layout, Q_border, check_valid_border);           \
1848   IIFORMAT_VALID_KEYWORD (layout, Q_margin_width, check_valid_int);        \
1849   IIFORMAT_VALID_KEYWORD (layout, Q_items,                                 \
1850                           check_valid_instantiator_list)
1851
1852 static void image_instantiator_layout (void)
1853 {
1854   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (layout, "layout");
1855   IIFORMAT_HAS_SHARED_METHOD (layout, possible_dest_types, widget);
1856   IIFORMAT_HAS_METHOD (layout, instantiate);
1857   IIFORMAT_HAS_METHOD (layout, post_instantiate);
1858   IIFORMAT_HAS_SHARED_METHOD (layout, governing_domain, subwindow);
1859   IIFORMAT_HAS_METHOD (layout, normalize);
1860   IIFORMAT_HAS_METHOD (layout, query_geometry);
1861   IIFORMAT_HAS_METHOD (layout, layout);
1862   IIFORMAT_HAS_METHOD (layout, update);
1863   IIFORMAT_HAS_METHOD (layout, property);
1864
1865   VALID_GUI_KEYWORDS (layout);
1866   VALID_LAYOUT_KEYWORDS (layout);
1867 }
1868
1869 static void image_instantiator_native_layout (void)
1870 {
1871   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (native_layout, "native-layout");
1872   IIFORMAT_HAS_SHARED_METHOD (native_layout, possible_dest_types, widget);
1873   IIFORMAT_HAS_SHARED_METHOD (native_layout, instantiate, layout);
1874   IIFORMAT_HAS_SHARED_METHOD (native_layout, post_instantiate, layout);
1875   IIFORMAT_HAS_METHOD (native_layout, layout);
1876   IIFORMAT_HAS_SHARED_METHOD (native_layout, governing_domain, subwindow);
1877   IIFORMAT_HAS_SHARED_METHOD (native_layout, normalize, layout);
1878   IIFORMAT_HAS_SHARED_METHOD (native_layout, query_geometry, layout);
1879   IIFORMAT_HAS_SHARED_METHOD (native_layout, layout, layout);
1880   IIFORMAT_HAS_SHARED_METHOD (native_layout, property, layout);
1881
1882   VALID_GUI_KEYWORDS (native_layout);
1883   VALID_LAYOUT_KEYWORDS (native_layout);
1884 }
1885
1886 void
1887 image_instantiator_format_create_glyphs_widget (void)
1888 {
1889   image_instantiator_widget();
1890   image_instantiator_buttons();
1891   image_instantiator_edit_fields();
1892   image_instantiator_combo_box();
1893   image_instantiator_scrollbar();
1894   image_instantiator_progress_guage();
1895   image_instantiator_tree_view();
1896   image_instantiator_tab_control();
1897   image_instantiator_labels();
1898   image_instantiator_layout();
1899   image_instantiator_native_layout();
1900 }
1901
1902 void
1903 reinit_vars_of_glyphs_widget (void)
1904 {
1905 #ifdef DEBUG_WIDGETS
1906   debug_widget_instances = 0;
1907 #endif
1908 }
1909
1910 void
1911 vars_of_glyphs_widget (void)
1912 {
1913   reinit_vars_of_glyphs_widget ();
1914 }
1915
1916
1917 void
1918 specifier_vars_of_glyphs_widget (void)
1919 {
1920   DEFVAR_SPECIFIER ("widget-border-width",
1921                     &Vwidget_border_width /*
1922 *Border width of widgets.
1923 This is a specifier; use `set-specifier' to change it.
1924 */ );
1925   Vwidget_border_width = Fmake_specifier (Qnatnum);
1926 }