+ if (!pw)
+ pw = glyph_width (glyph, image_instance) + 2 * widget_instance_border_width (ii);
+ if (!ph)
+ ph = glyph_height (glyph, image_instance) + 2 * widget_instance_border_width (ii);
+ IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
+ IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
+ }
+
+ /* Pick up the margin width. */
+ if (!NILP (mwidth))
+ IMAGE_INSTANCE_MARGIN_WIDTH (ii) = XINT (mwidth);
+
+ IMAGE_INSTANCE_WANTS_INITIAL_FOCUS (ii) = !NILP (ifocus);
+
+ /* Layout for the layout widget is premature at this point since the
+ children will not have been instantiated. We can't instantiate
+ them until the device instantiation method for the layout has
+ been executed. We do however want to record any specified
+ dimensions. */
+ if (pw) IMAGE_INSTANCE_WIDTH (ii) = pw;
+ if (ph) IMAGE_INSTANCE_HEIGHT (ii) = ph;
+}
+
+static void
+widget_post_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+ Lisp_Object domain)
+{
+#ifdef DEBUG_WIDGETS
+ debug_widget_instances++;
+ stderr_out ("instantiated ");
+ debug_print (instantiator);
+ stderr_out ("%d widgets instantiated\n", debug_widget_instances);
+#endif
+}
+
+/* Get the geometry of a button control. We need to adjust the size
+ depending on the type of button. */
+static void
+button_query_geometry (Lisp_Object image_instance,
+ int* width, int* height,
+ enum image_instance_geometry disp, Lisp_Object domain)
+{
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ int w, h;
+ query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
+ IMAGE_INSTANCE_WIDGET_FACE (ii),
+ &w, &h, 0, domain);
+ /* Adjust the size for borders. */
+ if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
+ {
+ *width = w + 3 * widget_instance_border_width (ii);
+
+ if (EQ (XGUI_ITEM (IMAGE_INSTANCE_WIDGET_ITEM (ii))->style, Qradio)
+ ||
+ EQ (XGUI_ITEM (IMAGE_INSTANCE_WIDGET_ITEM (ii))->style, Qtoggle))
+ /* This is an approximation to the size of the actual button bit. */
+ *width += 12;
+ }
+ if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
+ *height = h + 3 * widget_instance_border_width (ii);
+}
+
+/* Get the geometry of an edit field. */
+static void
+edit_field_query_geometry (Lisp_Object image_instance,
+ int* width, int* height,
+ enum image_instance_geometry disp, Lisp_Object domain)
+{
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ int w, h;
+ query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
+ IMAGE_INSTANCE_WIDGET_FACE (ii),
+ &w, &h, 0, domain);
+ /* Adjust the size for borders. */
+ if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
+ *width = w + 4 * widget_instance_border_width (ii);
+ if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
+ *height = h + 4 * widget_instance_border_width (ii);
+}
+
+/* tree-view geometry - get the height right */
+static void
+tree_view_query_geometry (Lisp_Object image_instance,
+ int* width, int* height,
+ enum image_instance_geometry disp, Lisp_Object domain)
+{
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
+
+
+ if (*width)
+ {
+ /* #### what should this be. reconsider when X has tree views. */
+ query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
+ IMAGE_INSTANCE_WIDGET_FACE (ii),
+ width, 0, 0, domain);
+ }
+ if (*height)
+ {
+ int len, h;
+ /* #### widget face would be better here. */
+ default_face_font_info (domain, 0, 0, &h, 0, 0);
+ GET_LIST_LENGTH (items, len);
+ *height = len * h;
+ }
+}
+
+/* Get the geometry of a tab control. This is based on the number of
+ items and text therin in the tab control. */
+static void
+tab_control_query_geometry (Lisp_Object image_instance,
+ int* width, int* height,
+ enum image_instance_geometry disp, Lisp_Object domain)
+{
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ Lisp_Object items = XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii));
+ Lisp_Object rest;
+ int tw = 0, th = 0;
+
+ LIST_LOOP (rest, items)
+ {
+ int h, w;
+
+ query_string_geometry (XGUI_ITEM (XCAR (rest))->name,
+ IMAGE_INSTANCE_WIDGET_FACE (ii),
+ &w, &h, 0, domain);
+ tw += 5 * widget_instance_border_width (ii); /* some bias */
+ tw += w;
+ th = max (th, h + 2 * widget_instance_border_width (ii));
+ }
+
+ /* Fixup returned values depending on orientation. */
+ if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii))
+ {
+ if (height) *height = tw;
+ if (width) *width = th;
+ }
+ else
+ {
+ if (height) *height = th;
+ if (width) *width = tw;
+ }
+}
+
+/* Determine whether only the order has changed for a tab. */
+int tab_control_order_only_changed (Lisp_Object image_instance)
+{
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ int found = 0, len, pending_len;
+ Lisp_Object rest;
+
+ /* Degenerate case. */
+ if (NILP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)))
+ return 1;
+
+ /* See whether we just need a change in order. */
+ GET_LIST_LENGTH (IMAGE_INSTANCE_WIDGET_ITEMS (ii), len);
+ GET_LIST_LENGTH (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii),
+ pending_len);
+ if (len == pending_len)
+ {
+ LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
+ {
+ Lisp_Object pending_rest;
+ found = 0;
+ LIST_LOOP (pending_rest,
+ XCDR (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)))
+ {
+ if (gui_item_equal_sans_selected (XCAR (rest),
+ XCAR (pending_rest), 0))
+ {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ break;
+ }
+ }
+ return found;
+}
+
+\f
+/*****************************************************************************
+ * widget layout *
+ *****************************************************************************/
+/* We need to cascade normalization.*/
+static Lisp_Object
+layout_normalize (Lisp_Object inst, Lisp_Object console_type,
+ Lisp_Object dest_mask)
+{
+ /* This function can call lisp */
+ struct gcpro gcpro1, gcpro2;
+ Lisp_Object alist = Qnil, new_items = Qnil, border;
+ /* This function can call lisp */
+ Lisp_Object items;
+
+ GCPRO2 (alist, new_items);
+ alist = tagged_vector_to_alist (inst);
+ items = assq_no_quit (Q_items, alist);
+
+ /* We need to normalize sub-objects. */
+ if (!NILP (items))
+ {
+ Lisp_Object rest;
+ LIST_LOOP (rest, XCDR (items))
+ {
+ /* Substitute the new instantiator */
+ new_items = Fcons (normalize_image_instantiator (XCAR (rest),
+ console_type, dest_mask),
+ new_items);
+ }
+ new_items = Fnreverse (new_items);
+ Fsetcdr (items, new_items);
+ }
+ /* Normalize the border spec. */
+ border = assq_no_quit (Q_border, alist);
+ if (!NILP (border) && VECTORP (XCDR (border)))
+ {
+ Fsetcdr (border, normalize_image_instantiator (XCDR (border),
+ console_type, dest_mask));
+ }
+
+ {
+ Lisp_Object result = alist_to_tagged_vector (XVECTOR_DATA (inst)[0],
+ alist);
+ free_alist (alist);
+ RETURN_UNGCPRO (result);
+ }
+}
+
+/* Update the instances in the layout. */
+static void
+layout_update (Lisp_Object image_instance, Lisp_Object instantiator)
+{
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ Lisp_Object items = find_keyword_in_vector (instantiator, Q_items);
+ Lisp_Object border_inst = find_keyword_in_vector (instantiator, Q_border);
+ Lisp_Object justify = find_keyword_in_vector (instantiator, Q_justify);
+ Lisp_Object hjustify = find_keyword_in_vector (instantiator, Q_horizontally_justify);
+ Lisp_Object vjustify = find_keyword_in_vector (instantiator, Q_vertically_justify);
+ Lisp_Object border = Qnil;
+ Lisp_Object children = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii);
+ int structure_changed = 0;
+ struct gcpro gcpro1;
+
+ /* Pick up horizontal justification, left is the default.*/
+ if (!NILP (hjustify))
+ {
+ if (EQ (hjustify, Qright) || EQ (hjustify, Qbottom))
+ IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_RIGHT;
+ else if (EQ (hjustify, Qcenter))
+ IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_CENTER;
+ }
+ /* If not set use general justification. */
+ else if (!NILP (justify))
+ {
+ if (EQ (justify, Qright) || EQ (justify, Qbottom))
+ IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_RIGHT;
+ else if (EQ (justify, Qcenter))
+ IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_CENTER;