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