d7c8c587a4b7f4190ada214499a18d76dd71c1b4
[chise/xemacs-chise.git.1] / src / glyphs-widget.c
1 /* Widget-specific glyph objects.
2    Copyright (C) 1998, 1999, 2000 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 Q_descriptor, Q_height, Q_width, Q_properties, Q_items;
62 Lisp_Object Q_image, Q_text, Q_orientation, Q_justify, Q_border;
63 Lisp_Object Q_margin_width;
64 Lisp_Object Qetched_in, Qetched_out, Qbevel_in, Qbevel_out;
65
66 #ifdef DEBUG_WIDGETS
67 int debug_widget_instances;
68 #endif
69
70 /* TODO:
71    - tooltips for controls, especially buttons.
72    - keyboard traversal.
73    - lisp configurable layout.
74  */
75
76 /* In MS-Windows normal windows work in pixels, dialog boxes work in
77    dialog box units. Why? sigh. We could reuse the metrics for dialogs
78    if this were not the case. As it is we have to position things
79    pixel wise. I'm not even sure that X has this problem at least for
80    buttons in groups. */
81 static int
82 widget_possible_dest_types (void)
83 {
84   return IMAGE_WIDGET_MASK;
85 }
86
87 static void
88 check_valid_glyph_or_instantiator (Lisp_Object data)
89 {
90   Lisp_Object glyph = data;
91   if (SYMBOLP (data))
92     glyph = XSYMBOL (data)->value;
93
94   if (IMAGE_INSTANCEP (glyph))
95     CHECK_IMAGE_INSTANCE (glyph);
96   else if (!CONSP (glyph) && !VECTORP (glyph))
97     CHECK_BUFFER_GLYPH (glyph);
98 }
99
100 static void
101 check_valid_orientation (Lisp_Object data)
102 {
103   if (!EQ (data, Qhorizontal)
104       &&
105       !EQ (data, Qvertical))
106     signal_simple_error ("unknown orientation for layout", data);
107 }
108
109 static void
110 check_valid_tab_orientation (Lisp_Object data)
111 {
112   if (!EQ (data, Qtop)
113       &&
114       !EQ (data, Qbottom)
115       &&
116       !EQ (data, Qleft)
117       &&
118       !EQ (data, Qright))
119     signal_simple_error ("unknown orientation for tab control", data);
120 }
121
122 static void
123 check_valid_justification (Lisp_Object data)
124 {
125   if (!EQ (data, Qleft) && !EQ (data, Qright) && !EQ (data, Qcenter))
126     signal_simple_error ("unknown justification for layout", data);
127 }
128
129 static void
130 check_valid_border (Lisp_Object data)
131 {
132   if (!EQ (data, Qt) && !EQ (data, Qetched_in) && !EQ (data, Qetched_out)
133       && !EQ (data, Qbevel_in) && !EQ (data, Qbevel_out)
134       && !GLYPHP (data) && !VECTORP (data))
135     signal_simple_error ("unknown border style for layout", data);
136 }
137
138 static void
139 check_valid_anything (Lisp_Object data)
140 {
141 }
142
143 static void
144 check_valid_callback (Lisp_Object data)
145 {
146     if (!SYMBOLP (data)
147         && !COMPILED_FUNCTIONP (data)
148         && !CONSP (data))
149     {
150         signal_simple_error (":callback must be a function or expression", data);
151     }
152 }
153
154 static void
155 check_valid_int_or_function (Lisp_Object data)
156 {
157   if (!INTP (data) && !CONSP (data))
158     signal_simple_error ("must be an integer or expresssion", data);
159 }
160
161 static void
162 check_valid_symbol (Lisp_Object data)
163 {
164     CHECK_SYMBOL (data);
165 }
166
167 static void
168 check_valid_string_or_vector (Lisp_Object data)
169 {
170     if (!STRINGP (data) && !VECTORP (data))
171         signal_simple_error (":descriptor must be a string or a vector", data);
172 }
173
174 void
175 check_valid_item_list_1 (Lisp_Object items)
176 {
177   Lisp_Object rest;
178
179   CHECK_LIST (items);
180   EXTERNAL_LIST_LOOP (rest, items)
181     {
182       if (STRINGP (XCAR (rest)))
183         CHECK_STRING (XCAR (rest));
184       else if (VECTORP (XCAR (rest)))
185         gui_parse_item_keywords (XCAR (rest));
186       else if (LISTP (XCAR (rest)))
187         check_valid_item_list_1 (XCAR (rest));
188       else
189         signal_simple_error ("Items must be vectors, lists or strings", items);
190     }
191 }
192
193 static void
194 check_valid_item_list (Lisp_Object data)
195 {
196   Lisp_Object items;
197
198   Fcheck_valid_plist (data);
199   items = Fplist_get (data, Q_items, Qnil);
200
201   check_valid_item_list_1 (items);
202 }
203
204 static void
205 check_valid_glyph_or_instantiator_list (Lisp_Object data)
206 {
207   Lisp_Object rest;
208
209   CHECK_LIST (data);
210   EXTERNAL_LIST_LOOP (rest, data)
211     {
212       check_valid_glyph_or_instantiator (XCAR (rest));
213     }
214 }
215
216 static Lisp_Object
217 glyph_instantiator_to_glyph (Lisp_Object sym)
218 {
219   /* This function calls lisp. */
220   Lisp_Object glyph = sym;
221   struct gcpro gcpro1;
222           
223   GCPRO1 (glyph);
224   /* if we have a symbol get at the actual data */
225   if (SYMBOLP (glyph))
226     glyph = XSYMBOL (glyph)->value;
227           
228   if (CONSP (glyph))
229     glyph = Feval (glyph);
230
231   /* Be really helpful to the user. */
232   if (VECTORP (glyph))
233     {
234       glyph = call1 (intern ("make-glyph"), glyph);
235     }
236
237   /* substitute the new glyph */
238   RETURN_UNGCPRO (glyph);
239 }
240
241 static void 
242 substitute_keyword_value (Lisp_Object inst, Lisp_Object key, Lisp_Object val)
243 {
244   int i;
245   /* substitute the new glyph */
246   for (i = 0; i < XVECTOR_LENGTH (inst); i++)
247     {
248       if (EQ (key, XVECTOR_DATA (inst)[i]))
249         {
250           XVECTOR_DATA (inst)[i+1] = val;
251           break;
252         }
253     }
254 }
255
256 /* Wire widget property invocations to specific widgets. The problem
257    we are solving here is that when instantiators get converted to
258    instances they lose some type information (they just become
259    subwindows or widgets for example). For widgets we need to preserve
260    this type information so that we can do widget specific operations
261    on the instances. This is encoded in the widget type
262    field. widget_property gets invoked by decoding the primary type
263    (Qwidget), <widget>_property then invokes based on the secondary
264    type (Qedit_field for example). It is debatable whether we should
265    wire things in this generalised way rather than treating widgets
266    specially in image_instance_property. */
267 static Lisp_Object 
268 widget_property (Lisp_Object image_instance, Lisp_Object prop)
269 {
270   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
271   struct image_instantiator_methods* meths;
272
273   /* first see if its a general property ... */
274   if (!NILP (Fplist_member (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop)))
275     return Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, Qnil);
276
277   /* .. then try device specific methods ... */
278   meths = decode_device_ii_format (image_instance_device (image_instance),
279                                    IMAGE_INSTANCE_WIDGET_TYPE (ii), 
280                                    ERROR_ME_NOT);
281   if (meths && HAS_IIFORMAT_METH_P (meths, property))
282     return IIFORMAT_METH (meths, property, (image_instance, prop));
283   /* ... then format specific methods ... */
284   meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), 
285                                    ERROR_ME_NOT);
286   if (meths && HAS_IIFORMAT_METH_P (meths, property))
287     return IIFORMAT_METH (meths, property, (image_instance, prop));
288   /* ... then fail */
289   return Qunbound;
290 }
291
292 static Lisp_Object 
293 widget_set_property (Lisp_Object image_instance, Lisp_Object prop, Lisp_Object val)
294 {
295   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
296   struct image_instantiator_methods* meths;
297   Lisp_Object ret;
298
299   /* PIck up any generic properties that we might need to keep hold
300      of. */
301   if (EQ (prop, Q_text))
302     {
303       IMAGE_INSTANCE_WIDGET_TEXT (ii) = val;
304       IMAGE_INSTANCE_TEXT_CHANGED (ii) = 1;
305     }
306
307   /* Now try device specific methods first ... */
308   meths = decode_device_ii_format (image_instance_device (image_instance), 
309                                    IMAGE_INSTANCE_WIDGET_TYPE (ii), 
310                                    ERROR_ME_NOT);
311   if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
312       &&
313       !UNBOUNDP (ret = 
314                  IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
315     {
316       return ret;
317     }
318   /* ... then format specific methods ... */
319   meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), 
320                                    ERROR_ME_NOT);
321   if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
322       &&
323       !UNBOUNDP (ret = 
324                  IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
325     {
326       return ret;
327     }
328   /* we didn't do any device specific properties, so shove the property in our plist */
329   IMAGE_INSTANCE_WIDGET_PROPS (ii)
330     = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
331   return val;
332 }
333
334 /* Like the rest of redisplay, we want widget updates to occur
335    asynchronously. Thus toolkit specific methods for setting
336    properties must be called by redisplay instead of by
337    *_set_property. Thus *_set_property records the change and this
338    function actually implements it. We want to be slightly clever
339    about this however by supplying format specific functions for the
340    updates instead of lumping them all into this function. Note that
341    there is no need for format generic functions. */
342 void
343 update_widget (Lisp_Object widget)
344 {
345   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (widget);
346   struct image_instantiator_methods* meths;
347
348   if (!WIDGET_IMAGE_INSTANCEP (widget)
349       || EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout)
350       || EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qnative_layout))
351     return;
352
353   /* Device generic methods. We must update the widget's size as it
354      may have been changed by the the layout routines. We also do this
355      here so that explicit resizing from lisp does not result in
356      synchronous updates. */
357   MAYBE_DEVMETH (DOMAIN_XDEVICE (ii->domain), update_widget, (ii));
358
359   /* Device-format specific methods */
360   meths = decode_device_ii_format (image_instance_device (widget), 
361                                    IMAGE_INSTANCE_WIDGET_TYPE (ii), 
362                                    ERROR_ME_NOT);
363   MAYBE_IIFORMAT_METH (meths, update, (widget));
364
365   /* Pick up the items we recorded earlier. */
366   if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii))
367     {
368       IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
369         IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii);
370       IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil;
371     }
372 }
373
374 /* Query for a widgets desired geometry. If no type specific method is
375    provided then use the widget text to calculate sizes. */
376 static void 
377 widget_query_geometry (Lisp_Object image_instance, 
378                        unsigned int* width, unsigned int* height,
379                        enum image_instance_geometry disp, Lisp_Object domain)
380 {
381   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
382   struct image_instantiator_methods* meths;
383   Lisp_Object dynamic_width = Qnil;
384   Lisp_Object dynamic_height = Qnil;
385
386   /* First just set up what we already have. */
387   if (width)    *width = IMAGE_INSTANCE_WIDTH (ii);
388   if (height)   *height = IMAGE_INSTANCE_HEIGHT (ii);
389   
390   if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)
391       ||
392       IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
393     {
394       /* .. then try device specific methods ... */
395       meths = decode_device_ii_format (image_instance_device (image_instance),
396                                        IMAGE_INSTANCE_WIDGET_TYPE (ii), 
397                                        ERROR_ME_NOT);
398       if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
399         IIFORMAT_METH (meths, query_geometry, (image_instance, 
400                                                width, height, disp,
401                                                domain));
402       else
403         {
404           /* ... then format specific methods ... */
405           meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), 
406                                            ERROR_ME_NOT);
407           if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
408             IIFORMAT_METH (meths, query_geometry, (image_instance, 
409                                                    width, height, disp,
410                                                    domain));
411           else 
412             {
413               unsigned int w, h;
414               
415               /* Then if we are allowed to resize the widget, make the
416                  size the same as the text dimensions. */
417               query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
418                                      IMAGE_INSTANCE_WIDGET_FACE (ii),
419                                      &w, &h, 0, domain);
420               /* Adjust the size for borders. */
421               if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
422                 *width = w + 2 * WIDGET_BORDER_WIDTH;
423               if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
424                 *height = h +  2 * WIDGET_BORDER_HEIGHT;
425             }
426         }
427       /* Finish off with dynamic sizing. */
428       if (!NILP (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii)))
429         {
430           dynamic_width = Feval (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii));
431           if (INTP (dynamic_width))
432             *width = XINT (dynamic_width);
433         }
434       if (!NILP (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii)))
435         {
436           dynamic_height = Feval (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii));
437           if (INTP (dynamic_height))
438             *height = XINT (dynamic_height);
439         }
440     }
441 }
442
443 static int 
444 widget_layout (Lisp_Object image_instance, 
445                unsigned int width, unsigned int height, Lisp_Object domain)
446 {
447   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
448   struct image_instantiator_methods* meths;
449
450   /* .. then try device specific methods ... */
451   meths = decode_device_ii_format (image_instance_device (image_instance),
452                                    IMAGE_INSTANCE_WIDGET_TYPE (ii), 
453                                    ERROR_ME_NOT);
454   if (meths && HAS_IIFORMAT_METH_P (meths, layout))
455     return IIFORMAT_METH (meths, layout, (image_instance, 
456                                           width, height, domain));
457   else
458     {
459       /* ... then format specific methods ... */
460       meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), 
461                                        ERROR_ME_NOT);
462       if (meths && HAS_IIFORMAT_METH_P (meths, layout))
463         return IIFORMAT_METH (meths, layout, (image_instance, 
464                                               width, height, domain));
465     }
466   return 1;
467 }
468
469 static void
470 widget_validate (Lisp_Object instantiator)
471 {
472   Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
473
474   if (NILP (desc))
475     signal_simple_error ("Must supply :descriptor", instantiator);
476
477   if (VECTORP (desc))
478     gui_parse_item_keywords (desc);
479
480   if (!NILP (find_keyword_in_vector (instantiator, Q_width))
481       && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width)))
482     signal_simple_error ("Must supply only one of :width and :pixel-width", instantiator);
483
484   if (!NILP (find_keyword_in_vector (instantiator, Q_height))
485              && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height)))
486     signal_simple_error ("Must supply only one of :height and :pixel-height", instantiator);
487 }
488
489 static void
490 combo_box_validate (Lisp_Object instantiator)
491 {
492   widget_validate (instantiator);
493   if (NILP (find_keyword_in_vector (instantiator, Q_properties)))
494     signal_simple_error ("Must supply item list", instantiator);
495 }
496
497 /* we need to convert things like glyphs to images, eval expressions
498    etc.*/
499 static Lisp_Object
500 widget_normalize (Lisp_Object inst, Lisp_Object console_type)
501 {
502   /* This function can call lisp */
503   Lisp_Object glyph = find_keyword_in_vector (inst, Q_image);
504
505   /* we need to eval glyph if its an expression, we do this for the
506      same reasons we normalize file to data. */
507   if (!NILP (glyph))
508     {
509       substitute_keyword_value (inst, Q_image, glyph_instantiator_to_glyph (glyph));
510     }
511
512   return inst;
513 }
514
515 static void
516 initialize_widget_image_instance (Lisp_Image_Instance *ii, Lisp_Object type)
517 {
518   /*  initialize_subwindow_image_instance (ii);*/
519   IMAGE_INSTANCE_WIDGET_TYPE (ii) = type;
520   IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil;
521   SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Qnil);
522   IMAGE_INSTANCE_WIDGET_ITEMS (ii) = allocate_gui_item ();
523   IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = Qnil;
524   IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil;
525   IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii) = Qnil;
526   IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii) = Qnil;
527   IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 1;
528   IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 1;
529   IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_HORIZONTAL;
530   IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii) = 0;
531 }
532
533 /* Instantiate a button widget. Unfortunately instantiated widgets are
534    particular to a frame since they need to have a parent. It's not
535    like images where you just select the image into the context you
536    want to display it in and BitBlt it. So image instances can have a
537    many-to-one relationship with things you see, whereas widgets can
538    only be one-to-one (i.e. per frame) */
539 void
540 widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
541                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
542                     int dest_mask, Lisp_Object domain)
543 {
544   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
545   Lisp_Object face = find_keyword_in_vector (instantiator, Q_face);
546   Lisp_Object height = find_keyword_in_vector (instantiator, Q_height);
547   Lisp_Object width = find_keyword_in_vector (instantiator, Q_width);
548   Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width);
549   Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height);
550   Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
551   Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image);
552   Lisp_Object props = find_keyword_in_vector (instantiator, Q_properties);
553   Lisp_Object items = find_keyword_in_vector (instantiator, Q_items);
554   Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
555   Lisp_Object mwidth = find_keyword_in_vector (instantiator, Q_margin_width);
556   int pw=0, ph=0, tw=0, th=0;
557   
558   /* this just does pixel type sizing */
559   subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
560                          dest_mask, domain);
561   
562   if (!(dest_mask & IMAGE_WIDGET_MASK))
563     incompatible_image_types (instantiator, dest_mask, IMAGE_WIDGET_MASK);
564
565   initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]);
566
567   IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
568   IMAGE_INSTANCE_WIDGET_PROPS (ii) = props;
569
570   /* retrieve the fg and bg colors */
571   if (!NILP (face))
572     SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Fget_face (face));
573   
574   /* retrieve the gui item information. This is easy if we have been
575      provided with a vector, more difficult if we have just been given
576      keywords */
577   if (STRINGP (desc) || NILP (desc))
578     {
579       /* big cheat - we rely on the fact that a gui item looks like an instantiator */
580       IMAGE_INSTANCE_WIDGET_ITEMS (ii) = 
581         gui_parse_item_keywords_no_errors (instantiator);
582       IMAGE_INSTANCE_WIDGET_TEXT (ii) = desc;
583     }
584   else
585     IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
586       gui_parse_item_keywords_no_errors (desc);
587       
588   /* Pick up the orientation before we do our first layout. */
589   if (EQ (orient, Qleft) || EQ (orient, Qright) || EQ (orient, Qvertical))
590     IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_VERTICAL;
591
592   /* parse more gui items out of the properties */
593   if (!NILP (props)
594       && 
595       !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout)
596       && !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qnative_layout))
597     {
598       if (NILP (items))
599         {
600           items = Fplist_get (props, Q_items, Qnil);
601         }
602       if (!NILP (items))
603         {
604           IMAGE_INSTANCE_WIDGET_ITEMS (ii) = 
605             Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii), 
606                    parse_gui_item_tree_children (items));
607         }
608     }
609
610   /* Normalize size information. We now only assign sizes if the user
611      gives us some explicitly, or there are some constraints that we
612      can't change later on. Otherwise we postpone sizing until query
613      geometry gets called. */
614   if (!NILP (pixwidth))         /* pixwidth takes precendent */
615     {
616       if (!INTP (pixwidth))
617         IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii) = pixwidth;
618       else
619         {
620           pw = XINT (pixwidth);
621           IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
622         }
623     }
624   else if (!NILP (width))
625     {
626       tw = XINT (width);
627       IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
628     }
629
630   if (!NILP (pixheight))
631     {
632       if (!INTP (pixheight))
633         IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii) = pixheight;
634       else
635         {
636           ph = XINT (pixheight);
637           IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
638         }
639     }
640   else if (!NILP (height) && XINT (height) > 1)
641     {
642       th = XINT (height);
643       IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
644     }
645
646   /* Taking the default face information when the user has specified
647      size in characters is probably as good as any since the widget
648      face is more likely to be proportional and thus give inadequate
649      results. Using character sizes can only ever be approximate
650      anyway. */
651   if (tw || th)
652     {
653       int charwidth, charheight;
654       default_face_font_info (domain, 0, 0, &charheight, &charwidth, 0);
655       if (tw)
656         pw = charwidth * tw;
657       if (th)
658         ph = charheight * th;
659     }
660
661   /* for a widget with an image pick up the dimensions from that */
662   if (!NILP (glyph))
663     {
664       if (!pw)
665         pw = glyph_width (glyph, domain) + 2 * WIDGET_BORDER_WIDTH;
666       if (!ph)
667         ph = glyph_height (glyph, domain) + 2 * WIDGET_BORDER_HEIGHT;
668       IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
669       IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
670     }
671
672   /* Pick up the margin width. */
673   if (!NILP (mwidth))
674     IMAGE_INSTANCE_MARGIN_WIDTH (ii) = XINT (mwidth);
675
676   /* Layout for the layout widget is premature at this point since the
677      children will not have been instantiated. We can't instantiate
678      them until the device instantiation method for the layout has
679      been executed. We do however want to record any specified
680      dimensions. */
681   if (pw)       IMAGE_INSTANCE_WIDTH (ii) = pw;
682   if (ph)       IMAGE_INSTANCE_HEIGHT (ii) = ph;
683 }
684
685 static void
686 widget_post_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
687                          Lisp_Object domain)
688 {
689 #ifdef DEBUG_WIDGETS
690   debug_widget_instances++;
691   stderr_out ("instantiated ");
692   debug_print (instantiator);
693   stderr_out ("%d widgets instantiated\n", debug_widget_instances);
694 #endif
695 }
696
697 /* Get the geometry of a button control. We need to adjust the size
698    depending on the type of button. */
699 static void
700 button_query_geometry (Lisp_Object image_instance, 
701                        unsigned int* width, unsigned int* height,
702                        enum image_instance_geometry disp, Lisp_Object domain)
703 {
704   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
705   unsigned int w, h;
706   query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
707                          IMAGE_INSTANCE_WIDGET_FACE (ii),
708                          &w, &h, 0, domain);
709   /* Adjust the size for borders. */
710   if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
711     {
712       *width = w + 2 * WIDGET_BORDER_WIDTH;
713
714       if (EQ (XGUI_ITEM (IMAGE_INSTANCE_WIDGET_ITEM (ii))->style, Qradio)
715           ||
716           EQ (XGUI_ITEM (IMAGE_INSTANCE_WIDGET_ITEM (ii))->style, Qtoggle))
717         /* This is an approximation to the size of the actual button bit. */
718         *width += 12;
719     }
720   if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
721     *height = h +  2 * WIDGET_BORDER_HEIGHT;
722 }
723
724 /* tree-view geometry - get the height right */
725 static void
726 tree_view_query_geometry (Lisp_Object image_instance, 
727                           unsigned int* width, unsigned int* height,
728                           enum image_instance_geometry disp, Lisp_Object domain)
729 {
730   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
731   Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
732
733   
734   if (*width)
735     {
736       /* #### what should this be. reconsider when X has tree views. */
737       query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
738                              IMAGE_INSTANCE_WIDGET_FACE (ii),
739                              width, 0, 0, domain);
740     }
741   if (*height)
742     {
743       int len, h;
744       default_face_font_info (domain, 0, 0, &h, 0, 0);
745       GET_LIST_LENGTH (items, len);
746       *height = len * h;
747     }
748 }
749
750 /* Get the geometry of a tab control. This is based on the number of
751    items and text therin in the tab control. */
752 static void
753 tab_control_query_geometry (Lisp_Object image_instance, 
754                             unsigned int* width, unsigned int* height,
755                             enum image_instance_geometry disp, Lisp_Object domain)
756 {
757   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
758   Lisp_Object items = XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii));
759   Lisp_Object rest;
760   unsigned int tw = 0, th = 0;
761
762   LIST_LOOP (rest, items)
763     {
764       unsigned int h, w;
765
766       query_string_geometry (XGUI_ITEM (XCAR (rest))->name,
767                              IMAGE_INSTANCE_WIDGET_FACE (ii),
768                              &w, &h, 0, domain);
769       tw += 5 * WIDGET_BORDER_WIDTH; /* some bias */
770       tw += w;
771       th = max (th, h + 2 * WIDGET_BORDER_HEIGHT);
772     }
773
774   /* Fixup returned values depending on orientation. */
775   if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii))
776     {
777       if (height)       *height = tw;
778       if (width)        *width = th;
779     }
780   else
781     {
782       if (height)       *height = th;
783       if (width)        *width = tw;
784     }
785 }
786
787 /* Get the geometry of a tab control. This is based on the number of
788    items and text therin in the tab control. */
789 static Lisp_Object
790 tab_control_set_property (Lisp_Object image_instance, 
791                           Lisp_Object prop,
792                           Lisp_Object val)
793 {
794   /* Record new items for update. *_tab_control_update will do the
795      rest. */
796   if (EQ (prop, Q_items))
797     {
798       Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
799
800       check_valid_item_list_1 (val);
801       
802       /* Don't set the actual items since we might decide not to use
803          the new ones (because nothing has really changed). If we did
804          set them and didn't use them then we would get into whole
805          heaps of trouble when the old items get GC'd. */
806       IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) =
807         Fcons (XCAR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)), 
808                parse_gui_item_tree_children (val));
809       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 1;
810
811       return Qt;
812     }
813   return Qunbound;
814 }
815
816 /* set the properties of a progres guage */
817 static Lisp_Object
818 progress_gauge_set_property (Lisp_Object image_instance,
819                              Lisp_Object prop,
820                              Lisp_Object val)
821 {
822   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
823
824   if (EQ (prop, Q_value))
825     {
826       CHECK_INT (val);
827 #ifdef DEBUG_WIDGET_OUTPUT
828       printf ("progress gauge value set to %ld\n", XINT (val));
829 #endif
830       IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) =
831         copy_gui_item_tree (IMAGE_INSTANCE_WIDGET_ITEMS (ii));
832 #ifdef ERROR_CHECK_GLYPHS
833       assert (GUI_ITEMP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)));
834 #endif
835       if (GUI_ITEMP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)))
836         XGUI_ITEM (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii))->value = val;
837
838       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 1;
839
840       return Qt;
841     }
842   return Qunbound;
843 }
844
845 \f
846 /*****************************************************************************
847  *                              widget layout                               *
848  *****************************************************************************/
849 /* we need to convert things like glyphs to images, eval expressions
850    etc.*/
851 static Lisp_Object
852 layout_normalize (Lisp_Object inst, Lisp_Object console_type)
853 {
854   /* This function can call lisp */
855   Lisp_Object items = find_keyword_in_vector (inst, Q_items);
856   Lisp_Object border = find_keyword_in_vector (inst, Q_border);
857   /* we need to eval glyph if its an expression, we do this for the
858      same reasons we normalize file to data. */
859   if (!NILP (items))
860     {
861       Lisp_Object rest;
862       LIST_LOOP (rest, items)
863         {
864           /* substitute the new glyph */
865           Fsetcar (rest, glyph_instantiator_to_glyph (XCAR (rest)));
866         }
867     }
868   /* normalize the border spec. */
869   if (VECTORP (border) || CONSP (border))
870     {
871       substitute_keyword_value (inst, Q_border, glyph_instantiator_to_glyph (border));
872     }
873   return inst;
874 }
875
876 static void
877 layout_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
878                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
879                     int dest_mask, Lisp_Object domain)
880 {
881   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
882   Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
883   Lisp_Object border = find_keyword_in_vector (instantiator, Q_border);
884
885   /* Do widget type instantiation first. */
886   widget_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
887                       dest_mask, domain);
888
889   if (NILP (orient))
890     {
891       IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_VERTICAL;
892     }
893       
894   if (EQ (border, Qt))
895     {
896       IMAGE_INSTANCE_LAYOUT_BORDER (ii) = Qetched_in;
897     }
898   else
899     {
900       IMAGE_INSTANCE_LAYOUT_BORDER (ii) = border;
901     }
902   /* We don't do the children yet as we might not have a containing
903      window. */
904 }
905
906 static void
907 layout_post_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
908                          Lisp_Object domain)
909 {
910   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
911   Lisp_Object items = find_keyword_in_vector (instantiator, Q_items);
912   Lisp_Object rest, children = Qnil;
913
914   if (GLYPHP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)))
915     {
916       /* We are going to be sneaky here and add the border text as
917          just another child, the layout and output routines don't know
918          this and will just display at the offsets we prescribe. */
919       Lisp_Object gii = glyph_image_instance 
920         (IMAGE_INSTANCE_LAYOUT_BORDER (ii),
921          image_instance, ERROR_ME, 1);
922
923       if (!IMAGE_INSTANCEP (gii))
924         return;
925       /* make sure we are designated as the parent. */
926       XIMAGE_INSTANCE_PARENT (gii) = image_instance;
927       children = Fcons (gii, children);
928       IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (0);
929     }
930
931   /* Pick up the sub-widgets. */
932   LIST_LOOP (rest, items)
933     {
934       /* make sure the image is instantiated */
935       Lisp_Object gii = glyph_image_instance (XCAR (rest), 
936                                               image_instance, ERROR_ME, 1);
937       if (!IMAGE_INSTANCEP (gii))
938         return;
939       /* make sure we are designated as the parent. */
940       XIMAGE_INSTANCE_PARENT (gii) = image_instance;
941       children = Fcons (gii, children);
942     }
943   /* Make sure elements in the layout are in the order the
944      user expected. */
945   children = Fnreverse (children);
946   IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = children;
947 }
948
949 /* Layout widget. Sizing commentary: we have a number of problems that
950    we would like to address. Some consider some of these more
951    important than others. It used to be that size information was
952    determined at instantiation time and was then fixed forever
953    after. Generally this is not what we want. Users want size to be
954    "big enough" to accommodate whatever they are trying to show and
955    this is dependent on text length, lines, font metrics etc. Of
956    course these attributes can change dynamically and so the size
957    should changed dynamically also. Only in a few limited cases should
958    the size be fixed and remain fixed. Of course this actually means
959    that we don't really want to specifiy the size *at all* for most
960    widgets - we want it to be discovered dynamically. Thus we can
961    envisage the following scenarios:
962    
963    1. A button is sized to accommodate its text, the text changes and the
964    button should change size also.  
965
966    2. A button is given an explicit size. Its size should never change.
967
968    3. Layout is put inside an area. The size of the area changes, the
969    layout should change with it. 
970
971    4. A button grows to accommodate additional text. The whitespace
972    around it should be modified to cope with the new layout
973    requirements. 
974
975    5. A button grows. The area surrounding it should grow also if
976    possible. 
977
978    What metrics are important?
979    1. Actual width and height.
980    
981    2. Whether the width and height are what the widget actually wants, or
982    whether it can grow or shrink. 
983
984    Text glyphs are particularly troublesome since their metrics depend
985    on the context in which they are being viewed. For instance they
986    can appear differently depending on the window face, frame face or
987    glyph face. In order to simplify this text glyphs can now only have
988    a glyph-face or image-instance face. All other glyphs are
989    essentially fixed in appearance. Perhaps the problem is that text
990    glyphs are cached on a device basis like most other glyphs. Instead
991    they should be cached per-window and then the instance would be
992    fixed and we wouldn't have to mess around with font metrics and the
993    rest. */
994
995 /* Query the geometry of a layout widget. We assume that we can only
996    get here if the size is not already fixed. */
997 static void
998 layout_query_geometry (Lisp_Object image_instance, unsigned int* width,
999                        unsigned int* height, enum image_instance_geometry disp,
1000                        Lisp_Object domain)
1001 {
1002   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1003   Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii), rest;
1004   int maxph = 0, maxpw = 0, nitems = 0, ph_adjust = 0;
1005   unsigned int gheight, gwidth;
1006
1007   /* If we are not initialized then we won't have any children. */
1008   if (!IMAGE_INSTANCE_INITIALIZED (ii))
1009       return;
1010
1011   /* First just set up what we already have. */
1012   if (width)    *width = IMAGE_INSTANCE_WIDTH (ii);
1013   if (height)   *height = IMAGE_INSTANCE_HEIGHT (ii);
1014   
1015   /* If we are not allowed to dynamically size then return. */
1016   if (!IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)
1017       &&
1018       !IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
1019     return;
1020
1021   /* Pick up the border text if we have one. */
1022   if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)))
1023     {
1024       image_instance_query_geometry (XCAR (items), &gwidth, &gheight, disp, domain);
1025       ph_adjust = gheight / 2;
1026       items = XCDR (items);
1027     }
1028   
1029   /* Flip through the items to work out how much stuff we have to display */
1030   LIST_LOOP (rest, items)
1031     {
1032       Lisp_Object glyph = XCAR (rest);
1033       image_instance_query_geometry (glyph, &gwidth, &gheight, disp, domain);
1034
1035       nitems ++;
1036       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) 
1037           == LAYOUT_HORIZONTAL)
1038         {
1039           maxph = max (maxph, gheight);
1040           maxpw += gwidth;
1041         }
1042       else
1043         {
1044           maxpw = max (maxpw, gwidth);
1045           maxph += gheight;
1046         }
1047     }
1048
1049   /* Work out minimum space we need to fit all the items. This could
1050      have been fixed by the user. */
1051   if (!NILP (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii)))
1052     {
1053       Lisp_Object dynamic_width = 
1054         Feval (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii));
1055       if (INTP (dynamic_width))
1056         *width = XINT (dynamic_width);
1057     }
1058   else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1059            == LAYOUT_HORIZONTAL)
1060     *width = maxpw + ((nitems + 1) * WIDGET_BORDER_WIDTH +
1061                       IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2;
1062   else 
1063     *width = maxpw + 2 * (WIDGET_BORDER_WIDTH * 2 + 
1064                           IMAGE_INSTANCE_MARGIN_WIDTH (ii));
1065
1066   /* Work out vertical spacings. */
1067   if (!NILP (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii)))
1068     {
1069       Lisp_Object dynamic_height = 
1070         Feval (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii));
1071       if (INTP (dynamic_height))
1072         *height = XINT (dynamic_height);
1073     }
1074   else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1075            == LAYOUT_VERTICAL)
1076     *height = maxph + ((nitems + 1) * WIDGET_BORDER_HEIGHT +
1077                        IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2 + ph_adjust;
1078   else
1079     *height = maxph + (2 * WIDGET_BORDER_HEIGHT +
1080                        IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2 + ph_adjust;
1081 }
1082
1083 int
1084 layout_layout (Lisp_Object image_instance, 
1085                unsigned int width, unsigned int height, Lisp_Object domain)
1086 {
1087   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1088   Lisp_Object rest;
1089   Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii);
1090   int x, y, maxph = 0, maxpw = 0, nitems = 0,
1091     horiz_spacing, vert_spacing, ph_adjust = 0;
1092   unsigned int gheight, gwidth;
1093
1094   /* If we are not initialized then we won't have any children. */
1095   if (!IMAGE_INSTANCE_INITIALIZED (ii))
1096       return 0;
1097
1098   /* Pick up the border text if we have one. */
1099   if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)))
1100     {
1101       Lisp_Object border = XCAR (items);
1102       items = XCDR (items);
1103       image_instance_query_geometry (border, &gwidth, &gheight,
1104                                      IMAGE_DESIRED_GEOMETRY, domain);
1105       /* #### Really, what should this be? */
1106       XIMAGE_INSTANCE_XOFFSET (border) = 10;
1107       XIMAGE_INSTANCE_YOFFSET (border) = 0;
1108       ph_adjust = gheight / 2;
1109       IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (ph_adjust);
1110
1111       image_instance_layout (border, gwidth, gheight, domain);
1112     }
1113
1114   /* Flip through the items to work out how much stuff we have to display. */
1115   LIST_LOOP (rest, items)
1116     {
1117       Lisp_Object glyph = XCAR (rest);
1118       
1119       image_instance_query_geometry (glyph, &gwidth, &gheight, 
1120                                      IMAGE_DESIRED_GEOMETRY, domain);
1121       nitems ++;
1122       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) 
1123           == LAYOUT_HORIZONTAL)
1124         {
1125           maxph = max (maxph, gheight);
1126           maxpw += gwidth;
1127         }
1128       else
1129         {
1130           maxpw = max (maxpw, gwidth);
1131           maxph += gheight;
1132         }
1133     }
1134
1135   /* work out spacing between items and bounds of the layout */
1136   if (width < maxpw)
1137     /* The user wants a smaller space than the largest item, so we
1138        just provide default spacing and will let the output routines
1139        clip.. */
1140     horiz_spacing = WIDGET_BORDER_WIDTH * 2;
1141   else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) 
1142            == LAYOUT_HORIZONTAL)
1143     /* We have a larger area to display in so distribute the space
1144        evenly. */
1145     horiz_spacing = (width - (maxpw + 
1146                               IMAGE_INSTANCE_MARGIN_WIDTH (ii) * 2)) 
1147       / (nitems + 1);
1148   else
1149     horiz_spacing = (width - maxpw) / 2
1150       - IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1151
1152   if (height < maxph)
1153     vert_spacing = WIDGET_BORDER_HEIGHT * 2;
1154   else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) 
1155            == LAYOUT_VERTICAL)
1156     vert_spacing = (height - (maxph + ph_adjust + 
1157                               IMAGE_INSTANCE_MARGIN_WIDTH (ii) * 2)) 
1158       / (nitems + 1);
1159   else
1160     vert_spacing = (height - (maxph + ph_adjust)) / 2 
1161       - IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1162
1163   y = vert_spacing + ph_adjust + IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1164   x = horiz_spacing + IMAGE_INSTANCE_MARGIN_WIDTH (ii);
1165
1166   /* Now flip through putting items where we want them, paying
1167      attention to justification. Make sure we don't mess with the
1168      border glyph. */
1169   LIST_LOOP (rest, items)
1170     {
1171       Lisp_Object glyph = XCAR (rest);
1172
1173       image_instance_query_geometry (glyph, &gwidth, &gheight, 
1174                                      IMAGE_DESIRED_GEOMETRY, domain);
1175
1176       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) 
1177           == LAYOUT_HORIZONTAL)
1178         {
1179           if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii) 
1180               == LAYOUT_JUSTIFY_RIGHT)
1181             y = height - (gheight + vert_spacing);
1182           if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii) 
1183               == LAYOUT_JUSTIFY_CENTER)
1184             y = (height - gheight) / 2;
1185         }
1186       else 
1187         {
1188           if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii) 
1189               == LAYOUT_JUSTIFY_RIGHT)
1190             x = width - (gwidth + horiz_spacing);
1191           if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii) 
1192               == LAYOUT_JUSTIFY_CENTER)
1193             x = (width - gwidth) / 2;
1194         }
1195         
1196       XIMAGE_INSTANCE_XOFFSET (glyph) = x;
1197       XIMAGE_INSTANCE_YOFFSET (glyph) = y;
1198         
1199       if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) 
1200           == LAYOUT_HORIZONTAL)
1201         {
1202           x += (gwidth + horiz_spacing);
1203         }
1204       else
1205         {
1206           y += (gheight + vert_spacing);
1207         }
1208       
1209       /* Now layout subwidgets if they require it. */
1210       image_instance_layout (glyph, gwidth, gheight, domain);
1211     }
1212   return 1;
1213 }
1214
1215 /* Layout subwindows if they are real subwindows. */
1216 static int
1217 native_layout_layout (Lisp_Object image_instance,
1218                       unsigned int width, unsigned int height,
1219                       Lisp_Object domain)
1220 {
1221   Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
1222   Lisp_Object rest;
1223   
1224   /* The first time this gets called, the layout will be only
1225      partially instantiated. The children get done in
1226      post_instantiate. */
1227   if (!IMAGE_INSTANCE_INITIALIZED (ii))
1228     return 0;
1229
1230   /* Defining this overrides the default layout_layout so we first have to call that to get 
1231      suitable instances and values set up. */
1232   layout_layout (image_instance, width, height, domain);
1233
1234   LIST_LOOP (rest, IMAGE_INSTANCE_LAYOUT_CHILDREN (ii))
1235     {
1236       struct display_glyph_area dga;
1237       dga.xoffset = 0;
1238       dga.yoffset = 0;
1239       dga.width = IMAGE_INSTANCE_WIDTH (ii);
1240       dga.height = IMAGE_INSTANCE_HEIGHT (ii);
1241
1242       map_subwindow (XCAR (rest), 
1243                      IMAGE_INSTANCE_XOFFSET (ii),
1244                      IMAGE_INSTANCE_YOFFSET (ii), &dga);
1245     }
1246   return 1;
1247 }
1248
1249 \f
1250 /************************************************************************/
1251 /*                            initialization                            */
1252 /************************************************************************/
1253
1254 void
1255 syms_of_glyphs_widget (void)
1256 {
1257   defkeyword (&Q_descriptor, ":descriptor");
1258   defkeyword (&Q_height, ":height");
1259   defkeyword (&Q_width, ":width");
1260   defkeyword (&Q_properties, ":properties");
1261   defkeyword (&Q_items, ":items");
1262   defkeyword (&Q_image, ":image");
1263   defkeyword (&Q_text, ":text");
1264   defkeyword (&Q_orientation, ":orientation");
1265   defkeyword (&Q_justify, ":justify");
1266   defkeyword (&Q_border, ":border");
1267   defkeyword (&Q_margin_width, ":margin-width");
1268
1269   defsymbol (&Qetched_in, "etched-in");
1270   defsymbol (&Qetched_out, "etched-out");
1271   defsymbol (&Qbevel_in, "bevel-in");
1272   defsymbol (&Qbevel_out, "bevel-out");
1273 }
1274
1275 #define VALID_GUI_KEYWORDS(type) do {                                                   \
1276   IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_active, check_valid_anything);                \
1277   IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything);                        \
1278   IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string);                            \
1279   IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol);                           \
1280   IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_selected, check_valid_anything);              \
1281   IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything);                        \
1282   IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol);                          \
1283   IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything);                      \
1284   IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string);                    \
1285   IIFORMAT_VALID_KEYWORD (type, Q_accelerator, check_valid_string);                     \
1286   IIFORMAT_VALID_KEYWORD (type, Q_label, check_valid_anything);                         \
1287   IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback, check_valid_callback);              \
1288   IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback_ex, check_valid_callback);           \
1289   IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_descriptor, check_valid_string_or_vector);    \
1290 } while (0)
1291
1292 #define VALID_WIDGET_KEYWORDS(type) do {                                \
1293   IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int);              \
1294   IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int);             \
1295   IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int_or_function);\
1296   IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int_or_function);\
1297   IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face);              \
1298 } while (0)
1299
1300
1301 static void image_instantiator_widget (void)
1302 { /* we only do this for properties */
1303   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget");
1304   IIFORMAT_HAS_METHOD (widget, property);
1305   IIFORMAT_HAS_METHOD (widget, set_property);
1306   IIFORMAT_HAS_METHOD (widget, query_geometry);
1307   IIFORMAT_HAS_METHOD (widget, layout);
1308 }
1309
1310 static void image_instantiator_buttons (void)
1311 {
1312   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button");
1313   IIFORMAT_HAS_SHARED_METHOD (button, validate, widget);
1314   IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget);
1315   IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget);
1316   IIFORMAT_HAS_SHARED_METHOD (button, post_instantiate, widget);
1317   IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget);
1318   IIFORMAT_HAS_SHARED_METHOD (button, governing_domain, subwindow);
1319   IIFORMAT_HAS_METHOD (button, query_geometry);
1320   IIFORMAT_VALID_KEYWORD (button,
1321                           Q_image, check_valid_glyph_or_instantiator);
1322   VALID_WIDGET_KEYWORDS (button);
1323   VALID_GUI_KEYWORDS (button);
1324 }
1325
1326 static void image_instantiator_edit_fields (void)
1327 {
1328   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit_field, "edit-field");
1329   IIFORMAT_HAS_SHARED_METHOD (edit_field, validate, widget);
1330   IIFORMAT_HAS_SHARED_METHOD (edit_field, possible_dest_types, widget);
1331   IIFORMAT_HAS_SHARED_METHOD (edit_field, instantiate, widget);
1332   IIFORMAT_HAS_SHARED_METHOD (edit_field, post_instantiate, widget);
1333   IIFORMAT_HAS_SHARED_METHOD (edit_field, governing_domain, subwindow);
1334   VALID_WIDGET_KEYWORDS (edit_field);
1335   VALID_GUI_KEYWORDS (edit_field);
1336 }
1337
1338 static void image_instantiator_combo_box (void)
1339 {
1340   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo_box, "combo-box");
1341   IIFORMAT_HAS_METHOD (combo_box, validate);
1342   IIFORMAT_HAS_SHARED_METHOD (combo_box, possible_dest_types, widget);
1343   IIFORMAT_HAS_SHARED_METHOD (combo_box, governing_domain, subwindow);
1344
1345   VALID_GUI_KEYWORDS (combo_box);
1346
1347   IIFORMAT_VALID_KEYWORD (combo_box, Q_width, check_valid_int);
1348   IIFORMAT_VALID_KEYWORD (combo_box, Q_height, check_valid_int);
1349   IIFORMAT_VALID_KEYWORD (combo_box, Q_pixel_width, check_valid_int_or_function);
1350   IIFORMAT_VALID_KEYWORD (combo_box, Q_face, check_valid_face);
1351   IIFORMAT_VALID_KEYWORD (combo_box, Q_properties, check_valid_item_list);
1352 }
1353
1354 static void image_instantiator_scrollbar (void)
1355 {
1356   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar");
1357   IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget);
1358   IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget);
1359   IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget);
1360   IIFORMAT_HAS_SHARED_METHOD (scrollbar, post_instantiate, widget);
1361   IIFORMAT_HAS_SHARED_METHOD (scrollbar, governing_domain, subwindow);
1362   VALID_GUI_KEYWORDS (scrollbar);
1363
1364   IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width, check_valid_int_or_function);
1365   IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height, check_valid_int_or_function);
1366   IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face);
1367 }
1368
1369 static void image_instantiator_progress_guage (void)
1370 {
1371   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge, "progress-gauge");
1372   IIFORMAT_HAS_SHARED_METHOD (progress_gauge, validate, widget);
1373   IIFORMAT_HAS_SHARED_METHOD (progress_gauge, possible_dest_types, widget);
1374   IIFORMAT_HAS_SHARED_METHOD (progress_gauge, instantiate, widget);
1375   IIFORMAT_HAS_SHARED_METHOD (progress_gauge, post_instantiate, widget);
1376   IIFORMAT_HAS_SHARED_METHOD (progress_gauge, governing_domain, subwindow);
1377   IIFORMAT_HAS_METHOD (progress_gauge, set_property);
1378   VALID_WIDGET_KEYWORDS (progress_gauge);
1379   VALID_GUI_KEYWORDS (progress_gauge);
1380 }
1381
1382 static void image_instantiator_tree_view (void)
1383 {
1384   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tree_view, "tree-view");
1385   IIFORMAT_HAS_SHARED_METHOD (tree_view, validate, combo_box);
1386   IIFORMAT_HAS_SHARED_METHOD (tree_view, possible_dest_types, widget);
1387   IIFORMAT_HAS_SHARED_METHOD (tree_view, instantiate, widget);
1388   IIFORMAT_HAS_SHARED_METHOD (tree_view, post_instantiate, widget);
1389   IIFORMAT_HAS_SHARED_METHOD (tree_view, governing_domain, subwindow);
1390   IIFORMAT_HAS_METHOD (tree_view, query_geometry);
1391   VALID_WIDGET_KEYWORDS (tree_view);
1392   VALID_GUI_KEYWORDS (tree_view);
1393   IIFORMAT_VALID_KEYWORD (tree_view, Q_properties, check_valid_item_list);
1394 }
1395
1396 static void image_instantiator_tab_control (void)
1397 {
1398   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tab_control, "tab-control");
1399   IIFORMAT_HAS_SHARED_METHOD (tab_control, validate, combo_box);
1400   IIFORMAT_HAS_SHARED_METHOD (tab_control, possible_dest_types, widget);
1401   IIFORMAT_HAS_SHARED_METHOD (tab_control, instantiate, widget);
1402   IIFORMAT_HAS_SHARED_METHOD (tab_control, post_instantiate, widget);
1403   IIFORMAT_HAS_SHARED_METHOD (tab_control, governing_domain, subwindow);
1404   IIFORMAT_HAS_METHOD (tab_control, query_geometry);
1405   IIFORMAT_HAS_METHOD (tab_control, set_property);
1406   VALID_WIDGET_KEYWORDS (tab_control);
1407   VALID_GUI_KEYWORDS (tab_control);
1408   IIFORMAT_VALID_KEYWORD (tab_control, Q_orientation, check_valid_tab_orientation);
1409   IIFORMAT_VALID_KEYWORD (tab_control, Q_properties, check_valid_item_list);
1410 }
1411
1412 static void image_instantiator_labels (void)
1413 {
1414   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label");
1415   IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget);
1416   IIFORMAT_HAS_SHARED_METHOD (label, instantiate, widget);
1417   IIFORMAT_HAS_SHARED_METHOD (label, post_instantiate, widget);
1418   IIFORMAT_HAS_SHARED_METHOD (label, governing_domain, subwindow);
1419   VALID_WIDGET_KEYWORDS (label);
1420   IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string);
1421 }
1422
1423 #define VALID_LAYOUT_KEYWORDS(layout) \
1424   VALID_WIDGET_KEYWORDS (layout);                                               \
1425   IIFORMAT_VALID_KEYWORD (layout, Q_orientation, check_valid_orientation);      \
1426   IIFORMAT_VALID_KEYWORD (layout, Q_justify, check_valid_justification);        \
1427   IIFORMAT_VALID_KEYWORD (layout, Q_border, check_valid_border);                \
1428   IIFORMAT_VALID_KEYWORD (layout, Q_margin_width, check_valid_int);     \
1429   IIFORMAT_VALID_KEYWORD (layout, Q_items,                              \
1430                           check_valid_glyph_or_instantiator_list)
1431
1432 static void image_instantiator_layout (void)
1433 {
1434   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (layout, "layout");
1435   IIFORMAT_HAS_SHARED_METHOD (layout, possible_dest_types, widget);
1436   IIFORMAT_HAS_METHOD (layout, instantiate);
1437   IIFORMAT_HAS_METHOD (layout, post_instantiate);
1438   IIFORMAT_HAS_SHARED_METHOD (layout, governing_domain, subwindow);
1439   IIFORMAT_HAS_METHOD (layout, normalize);
1440   IIFORMAT_HAS_METHOD (layout, query_geometry);
1441   IIFORMAT_HAS_METHOD (layout, layout);
1442
1443   VALID_GUI_KEYWORDS (layout);
1444   VALID_LAYOUT_KEYWORDS (layout);
1445 }
1446
1447 static void image_instantiator_native_layout (void)
1448 {
1449   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (native_layout, "native-layout");
1450   IIFORMAT_HAS_SHARED_METHOD (native_layout, possible_dest_types, widget);
1451   IIFORMAT_HAS_SHARED_METHOD (native_layout, instantiate, layout);
1452   IIFORMAT_HAS_SHARED_METHOD (native_layout, post_instantiate, layout);
1453   IIFORMAT_HAS_METHOD (native_layout, layout);
1454   IIFORMAT_HAS_SHARED_METHOD (native_layout, governing_domain, subwindow);
1455   IIFORMAT_HAS_SHARED_METHOD (native_layout, normalize, layout);
1456   IIFORMAT_HAS_SHARED_METHOD (native_layout, query_geometry, layout);
1457   IIFORMAT_HAS_SHARED_METHOD (native_layout, layout, layout);
1458
1459   VALID_GUI_KEYWORDS (native_layout);
1460   VALID_LAYOUT_KEYWORDS (native_layout);
1461 }
1462
1463 void
1464 image_instantiator_format_create_glyphs_widget (void)
1465 {
1466   image_instantiator_widget();
1467   image_instantiator_buttons();
1468   image_instantiator_edit_fields();
1469   image_instantiator_combo_box();
1470   image_instantiator_scrollbar();
1471   image_instantiator_progress_guage();
1472   image_instantiator_tree_view();
1473   image_instantiator_tab_control();
1474   image_instantiator_labels();
1475   image_instantiator_layout();
1476   image_instantiator_native_layout();
1477 }
1478
1479 void
1480 reinit_vars_of_glyphs_widget (void)
1481 {
1482 #ifdef DEBUG_WIDGETS
1483   debug_widget_instances = 0;
1484 #endif
1485 }
1486
1487 void
1488 vars_of_glyphs_widget (void)
1489 {
1490   reinit_vars_of_glyphs_widget ();
1491 }