+ IMAGE_INSTANCE_PIXMAP_MAXSLICE (ii) = slices;
+ IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICES (ii) =
+ xnew_array_and_zero (HBITMAP, slices);
+}
+
+\f
+#ifdef HAVE_WIDGETS
+
+/************************************************************************/
+/* widgets */
+/************************************************************************/
+static void
+mswindows_widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+ Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+ int dest_mask, Lisp_Object domain,
+ const char* class, int flags, int exflags)
+{
+ /* this function can call lisp */
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii), style;
+ Lisp_Object frame = FW_FRAME (domain);
+ Extbyte* nm=0;
+ HWND wnd;
+ int id = 0xffff;
+ Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
+ Lisp_Gui_Item* pgui = XGUI_ITEM (gui);
+
+ CHECK_MSWINDOWS_DEVICE (device);
+
+ if (!gui_item_active_p (gui))
+ flags |= WS_DISABLED;
+
+ style = pgui->style;
+
+ if (!NILP (pgui->callback) || !NILP (pgui->callback_ex))
+ {
+ id = mswindows_register_widget_instance (image_instance, domain);
+ }
+
+ if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
+ TO_EXTERNAL_FORMAT (LISP_STRING, IMAGE_INSTANCE_WIDGET_TEXT (ii),
+ C_STRING_ALLOCA, nm,
+ Qnative);
+
+ /* allocate space for the clip window and then allocate the clip window */
+ ii->data = xnew_and_zero (struct mswindows_subwindow_data);
+
+ if ((IMAGE_INSTANCE_MSWINDOWS_CLIPWINDOW (ii)
+ = CreateWindowEx(
+ WS_EX_CONTROLPARENT, /* EX flags */
+ XEMACS_CONTROL_CLASS,
+ 0, /* text */
+ WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD,
+ 0, /* starting x position */
+ 0, /* starting y position */
+ IMAGE_INSTANCE_WIDGET_WIDTH (ii),
+ IMAGE_INSTANCE_WIDGET_HEIGHT (ii),
+ /* parent window */
+ FRAME_MSWINDOWS_HANDLE (XFRAME (frame)),
+ (HMENU)id, /* No menu */
+ NULL, /* must be null for this class */
+ NULL)) == NULL)
+ signal_simple_error ("window creation failed with code",
+ make_int (GetLastError()));
+
+ if ((wnd = CreateWindowEx(
+ exflags /* | WS_EX_NOPARENTNOTIFY*/,
+ class,
+ nm,
+ flags | WS_CHILD | WS_VISIBLE,
+ 0, /* starting x position */
+ 0, /* starting y position */
+ IMAGE_INSTANCE_WIDGET_WIDTH (ii),
+ IMAGE_INSTANCE_WIDGET_HEIGHT (ii),
+ /* parent window */
+ IMAGE_INSTANCE_MSWINDOWS_CLIPWINDOW (ii),
+ (HMENU)id, /* No menu */
+ (HINSTANCE)
+ GetWindowLong
+ (FRAME_MSWINDOWS_HANDLE (XFRAME (frame)),
+ GWL_HINSTANCE),
+ NULL)) == NULL)
+ signal_simple_error ("window creation failed with code",
+ make_int (GetLastError()));
+
+ IMAGE_INSTANCE_SUBWINDOW_ID (ii) = wnd;
+ SetWindowLong (wnd, GWL_USERDATA, (LONG)LISP_TO_VOID(image_instance));
+ /* set the widget font from the widget face */
+ SendMessage (wnd, WM_SETFONT,
+ (WPARAM) mswindows_widget_hfont (ii, domain),
+ MAKELPARAM (TRUE, 0));
+}
+
+/* Instantiate a button widget. Unfortunately instantiated widgets are
+ particular to a frame since they need to have a parent. It's not
+ like images where you just select the image into the context you
+ want to display it in and BitBlt it. So image instances can have a
+ many-to-one relationship with things you see, whereas widgets can
+ only be one-to-one (i.e. per frame) */
+static void
+mswindows_button_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+ Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+ int dest_mask, Lisp_Object domain)
+{
+ /* This function can call lisp */
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ HWND wnd;
+ int flags = WS_TABSTOP;/* BS_NOTIFY #### is needed to get exotic feedback
+ only. Since we seem to want nothing beyond BN_CLICK,
+ the style is perhaps not necessary -- kkm */
+ Lisp_Object style;
+ Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
+ Lisp_Gui_Item* pgui = XGUI_ITEM (gui);
+ Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image);
+
+ if (!NILP (glyph))
+ {
+ if (!IMAGE_INSTANCEP (glyph))
+ glyph = glyph_image_instance (glyph, domain, ERROR_ME, 1);
+
+ if (IMAGE_INSTANCEP (glyph))
+ flags |= XIMAGE_INSTANCE_MSWINDOWS_BITMAP (glyph) ?
+ BS_BITMAP : BS_ICON;
+ }
+
+ style = pgui->style;
+
+ /* #### consider using the default face for radio and toggle
+ buttons. */
+ if (EQ (style, Qradio))
+ {
+ flags |= BS_RADIOBUTTON;
+ }
+ else if (EQ (style, Qtoggle))
+ {
+ flags |= BS_AUTOCHECKBOX;
+ }
+ else
+ {
+ flags |= BS_DEFPUSHBUTTON;
+ }
+
+ mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+ pointer_bg, dest_mask, domain, "BUTTON",
+ flags, 0);
+
+ wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+ /* set the checked state */
+ if (gui_item_selected_p (gui))
+ SendMessage (wnd, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
+ else
+ SendMessage (wnd, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
+ /* add the image if one was given */
+ if (!NILP (glyph) && IMAGE_INSTANCEP (glyph)
+ &&
+ IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (glyph)))
+ {
+ SendMessage (wnd, BM_SETIMAGE,
+ (WPARAM) (XIMAGE_INSTANCE_MSWINDOWS_BITMAP (glyph) ?
+ IMAGE_BITMAP : IMAGE_ICON),
+ (XIMAGE_INSTANCE_MSWINDOWS_BITMAP (glyph) ?
+ (LPARAM) XIMAGE_INSTANCE_MSWINDOWS_BITMAP (glyph) :
+ (LPARAM) XIMAGE_INSTANCE_MSWINDOWS_ICON (glyph)));
+ }
+}
+
+/* Update the state of a button. */
+static void
+mswindows_button_update (Lisp_Object image_instance)
+{
+ /* This function can GC if IN_REDISPLAY is false. */
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+
+ /* buttons checked or otherwise */
+ if (gui_item_selected_p (IMAGE_INSTANCE_WIDGET_ITEM (ii)))
+ SendMessage (WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii),
+ BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
+ else
+ SendMessage (WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii),
+ BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
+}
+
+/* instantiate an edit control */
+static void
+mswindows_edit_field_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+ Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+ int dest_mask, Lisp_Object domain)
+{
+ mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+ pointer_bg, dest_mask, domain, "EDIT",
+ ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP
+ | WS_BORDER, WS_EX_CLIENTEDGE);
+}
+
+/* instantiate a progress gauge */
+static void
+mswindows_progress_gauge_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+ Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+ int dest_mask, Lisp_Object domain)
+{
+ HWND wnd;
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+ pointer_bg, dest_mask, domain, PROGRESS_CLASS,
+ WS_BORDER | PBS_SMOOTH, WS_EX_CLIENTEDGE);
+ wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+ /* set the colors */
+#ifdef PBS_SETBKCOLOR
+ SendMessage (wnd, PBS_SETBKCOLOR, 0,
+ (LPARAM) (COLOR_INSTANCE_MSWINDOWS_COLOR
+ (XCOLOR_INSTANCE
+ (FACE_BACKGROUND
+ (XIMAGE_INSTANCE_WIDGET_FACE (ii),
+ XIMAGE_INSTANCE_SUBWINDOW_FRAME (ii))))));
+#endif
+#ifdef PBS_SETBARCOLOR
+ SendMessage (wnd, PBS_SETBARCOLOR, 0,
+ (L:PARAM) (COLOR_INSTANCE_MSWINDOWS_COLOR
+ (XCOLOR_INSTANCE
+ (FACE_FOREGROUND
+ (XIMAGE_INSTANCE_WIDGET_FACE (ii),
+ XIMAGE_INSTANCE_SUBWINDOW_FRAME (ii))))));
+#endif
+}
+
+/* instantiate a tree view widget */
+static HTREEITEM add_tree_item (Lisp_Object image_instance,
+ HWND wnd, HTREEITEM parent, Lisp_Object item,
+ int children, Lisp_Object domain)
+{
+ TV_INSERTSTRUCT tvitem;
+ HTREEITEM ret;
+
+ tvitem.hParent = parent;
+ tvitem.hInsertAfter = TVI_LAST;
+ tvitem.item.mask = TVIF_TEXT | TVIF_CHILDREN;
+ tvitem.item.cChildren = children;
+
+ if (GUI_ITEMP (item))
+ {
+ tvitem.item.lParam = mswindows_register_gui_item (image_instance,
+ item, domain);
+ tvitem.item.mask |= TVIF_PARAM;
+ TO_EXTERNAL_FORMAT (LISP_STRING, XGUI_ITEM (item)->name,
+ C_STRING_ALLOCA, tvitem.item.pszText,
+ Qnative);
+ }
+ else
+ TO_EXTERNAL_FORMAT (LISP_STRING, item,
+ C_STRING_ALLOCA, tvitem.item.pszText,
+ Qnative);
+
+ tvitem.item.cchTextMax = strlen (tvitem.item.pszText);
+
+ if ((ret = (HTREEITEM)SendMessage (wnd, TVM_INSERTITEM,
+ 0, (LPARAM)&tvitem)) == 0)
+ signal_simple_error ("error adding tree view entry", item);
+
+ return ret;
+}
+
+static void add_tree_item_list (Lisp_Object image_instance,
+ HWND wnd, HTREEITEM parent, Lisp_Object list,
+ Lisp_Object domain)
+{
+ Lisp_Object rest;
+
+ /* get the first item */
+ parent = add_tree_item (image_instance, wnd, parent, XCAR (list), TRUE, domain);
+ /* recursively add items to the tree view */
+ LIST_LOOP (rest, XCDR (list))
+ {
+ if (LISTP (XCAR (rest)))
+ add_tree_item_list (image_instance, wnd, parent, XCAR (rest), domain);
+ else
+ add_tree_item (image_instance, wnd, parent, XCAR (rest), FALSE, domain);
+ }
+}
+
+static void
+mswindows_tree_view_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+ Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+ int dest_mask, Lisp_Object domain)
+{
+ Lisp_Object rest;
+ HWND wnd;
+ HTREEITEM parent;
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+ pointer_bg, dest_mask, domain, WC_TREEVIEW,
+ WS_TABSTOP | WS_BORDER | PBS_SMOOTH
+ | TVS_HASLINES | TVS_HASBUTTONS,
+ WS_EX_CLIENTEDGE);
+
+ wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+
+ /* define a root */
+ parent = add_tree_item (image_instance, wnd, NULL,
+ XCAR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)),
+ TRUE, domain);
+
+ /* recursively add items to the tree view */
+ /* add items to the tab */
+ LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
+ {
+ if (LISTP (XCAR (rest)))
+ add_tree_item_list (image_instance, wnd, parent, XCAR (rest), domain);
+ else
+ add_tree_item (image_instance, wnd, parent, XCAR (rest), FALSE, domain);
+ }
+}
+
+/* instantiate a tab control */
+static TC_ITEM* add_tab_item (Lisp_Object image_instance,
+ HWND wnd, Lisp_Object item,
+ Lisp_Object domain, int i)
+{
+ TC_ITEM tvitem, *ret;
+
+ tvitem.mask = TCIF_TEXT;
+
+ if (GUI_ITEMP (item))
+ {
+ tvitem.lParam = mswindows_register_gui_item (image_instance,
+ item, domain);
+ tvitem.mask |= TCIF_PARAM;
+ TO_EXTERNAL_FORMAT (LISP_STRING, XGUI_ITEM (item)->name,
+ C_STRING_ALLOCA, tvitem.pszText,
+ Qnative);
+ }
+ else
+ {
+ CHECK_STRING (item);
+ TO_EXTERNAL_FORMAT (LISP_STRING, item,
+ C_STRING_ALLOCA, tvitem.pszText,
+ Qnative);
+ }
+
+ tvitem.cchTextMax = strlen (tvitem.pszText);
+
+ if ((ret = (TC_ITEM*)SendMessage (wnd, TCM_INSERTITEM,
+ i, (LPARAM)&tvitem)) < 0)
+ signal_simple_error ("error adding tab entry", item);
+
+ return ret;
+}
+
+static void
+mswindows_tab_control_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+ Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+ int dest_mask, Lisp_Object domain)
+{
+ /* This function can call lisp */
+ Lisp_Object rest;
+ HWND wnd;
+ int i = 0, selected = 0;
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
+ unsigned int flags = WS_TABSTOP;
+
+ if (EQ (orient, Qleft) || EQ (orient, Qright))
+ {
+ flags |= TCS_VERTICAL | TCS_MULTILINE;
+ }
+ if (EQ (orient, Qright) || EQ (orient, Qbottom))
+ {
+ flags |= TCS_BOTTOM;
+ }
+
+ mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+ pointer_bg, dest_mask, domain, WC_TABCONTROL,
+ /* borders don't suit tabs so well */
+ flags, 0);
+ wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+ /* add items to the tab */
+ LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
+ {
+ add_tab_item (image_instance, wnd, XCAR (rest), domain, i);
+ if (gui_item_selected_p (XCAR (rest)))
+ selected = i;
+ i++;
+ }
+ SendMessage (wnd, TCM_SETCURSEL, selected, 0);
+}
+
+/* set the properties of a tab control */
+static void
+mswindows_tab_control_update (Lisp_Object image_instance)
+{
+ /* This function can GC if IN_REDISPLAY is false. */
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+
+ if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii))
+ {
+ HWND wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+ int i = 0, selected = 0;
+ Lisp_Object rest;
+
+ /* delete the pre-existing items */
+ SendMessage (wnd, TCM_DELETEALLITEMS, 0, 0);
+
+ /* add items to the tab */
+ LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)))
+ {
+ add_tab_item (image_instance, wnd, XCAR (rest),
+ IMAGE_INSTANCE_SUBWINDOW_FRAME (ii), i);
+ if (gui_item_selected_p (XCAR (rest)))
+ selected = i;
+ i++;
+ }
+ SendMessage (wnd, TCM_SETCURSEL, selected, 0);
+ }
+}
+
+/* instantiate a static control possible for putting other things in */
+static void
+mswindows_label_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+ Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+ int dest_mask, Lisp_Object domain)
+{
+ mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+ pointer_bg, dest_mask, domain, "STATIC",
+ 0, WS_EX_STATICEDGE);
+}
+
+/* instantiate a scrollbar control */
+static void
+mswindows_scrollbar_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+ Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+ int dest_mask, Lisp_Object domain)
+{
+ mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+ pointer_bg, dest_mask, domain, "SCROLLBAR",
+ WS_TABSTOP, WS_EX_CLIENTEDGE);
+}
+
+/* instantiate a combo control */
+static void
+mswindows_combo_box_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+ Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+ int dest_mask, Lisp_Object domain)
+{
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ HWND wnd;
+ Lisp_Object rest;
+ Lisp_Object data = Fplist_get (find_keyword_in_vector (instantiator, Q_properties),
+ Q_items, Qnil);
+ int len, height;
+
+ /* Maybe ought to generalise this more but it may be very windows
+ specific. In windows the window height of a combo box is the
+ height when the combo box is open. Thus we need to set the height
+ before creating the window and then reset it to a single line
+ after the window is created so that redisplay does the right
+ thing. */
+ widget_instantiate (image_instance, instantiator, pointer_fg,
+ pointer_bg, dest_mask, domain);
+
+ /* We now have everything right apart from the height. */
+ default_face_font_info (domain, 0, 0, &height, 0, 0);
+ GET_LIST_LENGTH (data, len);
+
+ height = (height + WIDGET_BORDER_HEIGHT * 2 ) * len;
+ IMAGE_INSTANCE_HEIGHT (ii) = height;
+
+ /* Now create the widget. */
+ mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+ pointer_bg, dest_mask, domain, "COMBOBOX",
+ WS_BORDER | WS_TABSTOP | CBS_DROPDOWN
+ | CBS_AUTOHSCROLL
+ | CBS_HASSTRINGS | WS_VSCROLL,
+ WS_EX_CLIENTEDGE);
+ /* Reset the height. layout will probably do this safely, but better make sure. */
+ image_instance_layout (image_instance,
+ IMAGE_UNSPECIFIED_GEOMETRY,
+ IMAGE_UNSPECIFIED_GEOMETRY,
+ domain);
+
+ wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+ /* add items to the combo box */
+ SendMessage (wnd, CB_RESETCONTENT, 0, 0);
+ LIST_LOOP (rest, Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), Q_items, Qnil))
+ {
+ Extbyte* lparam;
+ TO_EXTERNAL_FORMAT (LISP_STRING, XCAR (rest),
+ C_STRING_ALLOCA, lparam,
+ Qnative);
+ if (SendMessage (wnd, CB_ADDSTRING, 0, (LPARAM)lparam) == CB_ERR)
+ signal_simple_error ("error adding combo entries", instantiator);
+ }
+}
+
+/* get properties of a control */
+static Lisp_Object
+mswindows_widget_property (Lisp_Object image_instance, Lisp_Object prop)
+{
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ HWND wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+ /* get the text from a control */
+ if (EQ (prop, Q_text))
+ {
+ Extcount len = SendMessage (wnd, WM_GETTEXTLENGTH, 0, 0);
+ Extbyte *buf = (Extbyte*) alloca (len+1);
+
+ SendMessage (wnd, WM_GETTEXT, (WPARAM)len+1, (LPARAM) buf);
+ return build_ext_string (buf, Qnative);
+ }
+ return Qunbound;
+}
+
+/* get properties of a button */
+static Lisp_Object
+mswindows_button_property (Lisp_Object image_instance, Lisp_Object prop)
+{
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ HWND wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+ /* check the state of a button */
+ if (EQ (prop, Q_selected))
+ {
+ if (SendMessage (wnd, BM_GETSTATE, 0, 0) & BST_CHECKED)
+ return Qt;
+ else
+ return Qnil;
+ }
+ return Qunbound;
+}
+
+/* get properties of a combo box */
+static Lisp_Object
+mswindows_combo_box_property (Lisp_Object image_instance, Lisp_Object prop)
+{
+ Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+ HWND wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+ /* get the text from a control */
+ if (EQ (prop, Q_text))
+ {
+ long item = SendMessage (wnd, CB_GETCURSEL, 0, 0);
+ Extcount len = SendMessage (wnd, CB_GETLBTEXTLEN, (WPARAM)item, 0);
+ Extbyte* buf = (Extbyte*) alloca (len+1);
+ SendMessage (wnd, CB_GETLBTEXT, (WPARAM)item, (LPARAM)buf);
+ return build_ext_string (buf, Qnative);
+ }
+ return Qunbound;