BUTTON_TYPE_RADIO
};
+/* This structure is based on the one in ../lwlib/lwlib.h, modified
+ for Windows. */
typedef struct _widget_value
{
/* name of widget */
char* value;
/* keyboard equivalent. no implications for XtTranslations */
char* key;
- /* Help string or null if none. */
- char *help;
+ /* Help string or nil if none.
+ GC finds this string through the frame's menu_bar_vector
+ or through menu_items. */
+ Lisp_Object help;
/* true if enabled */
Boolean enabled;
/* true if selected */
#define FALSE 0
#endif /* no TRUE */
+static HMENU current_popup_menu;
+
+FARPROC get_menu_item_info;
+FARPROC set_menu_item_info;
+
Lisp_Object Vmenu_updating_frame;
Lisp_Object Qdebug_on_next_call;
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
first_wv = wv;
save_wv = 0;
prev_wv = 0;
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
}
save_wv = wv;
prev_wv = 0;
abort ();
wv->selected = !NILP (selected);
- if (STRINGP (help))
- wv->help = (char *) XSTRING (help)->data;
- else
- wv->help = NULL;
+ if (!STRINGP (help))
+ help = Qnil;
+
+ wv->help = help;
prev_wv = wv;
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
first_wv = wv;
if (deep_p)
}
/* Now GC cannot happen during the lifetime of the widget_value,
- so it's safe to store data from a Lisp_String. */
+ so it's safe to store data from a Lisp_String, as long as
+ local copies are made when the actual menu is created.
+ Windows takes care of this for normal string items, but
+ not for owner-drawn items or additional item-info. */
wv = first_wv->contents;
for (i = 0; i < XVECTOR (items)->size; i += 4)
{
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
/* This prevents lwlib from assuming this
menu item is really supposed to be empty. */
/* The EMACS_INT cast avoids a warning.
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
first_wv = wv;
first_pane = 1;
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
+ wv->help = Qnil;
save_wv = wv;
prev_wv = 0;
}
abort ();
wv->selected = !NILP (selected);
- if (STRINGP (help))
- wv->help = XSTRING (help)->data;
+ if (!STRINGP (help))
+ help = Qnil;
+
+ wv->help = help;
prev_wv = wv;
so that it looks better. Having two separators looks odd. */
wv_sep->name = "--";
wv_sep->next = first_wv->contents;
+ wv_sep->help = Qnil;
#ifndef HAVE_MULTILINGUAL_MENU
if (STRING_MULTIBYTE (title))
wv_title->enabled = TRUE;
wv_title->title = TRUE;
wv_title->button_type = BUTTON_TYPE_NONE;
+ wv_title->help = Qnil;
wv_title->next = wv_sep;
first_wv->contents = wv_title;
}
/* Actually create the menu. */
- menu = CreatePopupMenu ();
+ current_popup_menu = menu = CreatePopupMenu ();
fill_in_menu (menu, first_wv->contents);
/* Adjust coordinates to be root-window-relative. */
}
\f
+#ifdef HAVE_DIALOGS
static char * button_names [] = {
"button1", "button2", "button3", "button4", "button5",
"button6", "button7", "button8", "button9", "button10" };
prev_wv->name++;
prev_wv->enabled = 1;
prev_wv->name = "message";
+ prev_wv->help = Qnil;
first_wv = prev_wv;
/* Loop over all panes and items, filling in the tree. */
wv->value = (char *) XSTRING (item_name)->data;
wv->call_data = (void *) &XVECTOR (menu_items)->contents[i];
wv->enabled = !NILP (enable);
+ wv->help = Qnil;
prev_wv = wv;
if (! boundary_seen)
wv = xmalloc_widget_value ();
wv->name = dialog_name;
+ wv->help = Qnil;
/* Dialog boxes use a really stupid name encoding
which specifies how many buttons to use
}
/* Actually create the dialog. */
-#ifdef HAVE_DIALOGS
dialog_id = widget_id_tick++;
menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
f->output_data.w32->widget, 1, 0,
dialog_selection_callback, 0);
lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
-#endif
/* Free the widget_value objects we used to specify the contents. */
free_menubar_widget_value_tree (first_wv);
menu_item_selection = 0;
/* Display the menu. */
-#ifdef HAVE_DIALOGS
lw_pop_up_all_widgets (dialog_id);
popup_activated_flag = 1;
popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
lw_destroy_all_widgets (dialog_id);
-#endif
/* Find the selected item, and its pane, to return
the proper value. */
return Qnil;
}
+#endif /* HAVE_DIALOGS */
\f
/* Is this item a separator? */
else
out_string = wv->name;
- if (wv->title)
+ if (item != NULL)
+ fuFlags = MF_POPUP;
+ else if (wv->title || wv->call_data == 0)
{
-#if 0 /* no GC while popup menu is active */
- out_string = LocalAlloc (0, strlen (wv->name) + 1);
- strcpy (out_string, wv->name);
+ /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
+ we can't deallocate the memory otherwise. */
+ if (get_menu_item_info)
+ {
+ out_string = (char *) LocalAlloc (LPTR, strlen (wv->name) + 1);
+#ifdef MENU_DEBUG
+ DebPrint ("Menu: allocing %ld for owner-draw", info.dwItemData);
#endif
- fuFlags = MF_OWNERDRAW | MF_DISABLED;
+ strcpy (out_string, wv->name);
+ fuFlags = MF_OWNERDRAW | MF_DISABLED;
+ }
+ else
+ fuFlags = MF_DISABLED;
}
- else if (wv->call_data == 0)
- fuFlags |= MF_DISABLED;
/* Draw radio buttons and tickboxes. */
else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
fuFlags |= MF_UNCHECKED;
}
- if (item != NULL)
- fuFlags = MF_POPUP;
-
return_value =
AppendMenu (menu,
fuFlags,
/* This must be done after the menu item is created. */
if (!wv->title && wv->call_data != 0)
{
- HMODULE user32 = GetModuleHandle ("user32.dll");
- FARPROC set_menu_item_info = GetProcAddress (user32, "SetMenuItemInfoA");
-
if (set_menu_item_info)
{
MENUITEMINFO info;
info.cbSize = sizeof (info);
info.fMask = MIIM_DATA;
- /* Set help string for menu item. */
- info.dwItemData = (DWORD)wv->help;
+ /* Set help string for menu item. Leave it as a Lisp_Object
+ until it is ready to be displayed, since GC can happen while
+ menus are active. */
+ if (wv->help)
+ info.dwItemData = (DWORD) wv->help;
if (wv->button_type == BUTTON_TYPE_RADIO)
{
void
w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
{
- HMODULE user32 = GetModuleHandle ("user32.dll");
- FARPROC get_menu_item_info = GetProcAddress (user32, "GetMenuItemInfoA");
-
if (get_menu_item_info)
{
- MENUITEMINFO info;
struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
Lisp_Object frame, help;
- bzero (&info, sizeof (info));
- info.cbSize = sizeof (info);
- info.fMask = MIIM_DATA;
- get_menu_item_info (menu, item, FALSE, &info);
+ // No help echo on owner-draw menu items.
+ if (flags & MF_OWNERDRAW || flags & MF_POPUP)
+ help = Qnil;
+ else
+ {
+ MENUITEMINFO info;
- help = info.dwItemData ? build_string ((char *)info.dwItemData) : Qnil;
+ bzero (&info, sizeof (info));
+ info.cbSize = sizeof (info);
+ info.fMask = MIIM_DATA;
+ get_menu_item_info (menu, item, FALSE, &info);
+
+ help = info.dwItemData ? (Lisp_Object) info.dwItemData : Qnil;
+ }
/* Store the help echo in the keyboard buffer as the X toolkit
version does, rather than directly showing it. This seems to
}
}
+/* Free memory used by owner-drawn strings. */
+static void
+w32_free_submenu_strings (menu)
+ HMENU menu;
+{
+ int i, num = GetMenuItemCount (menu);
+ for (i = 0; i < num; i++)
+ {
+ MENUITEMINFO info;
+ bzero (&info, sizeof (info));
+ info.cbSize = sizeof (info);
+ info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;
+
+ get_menu_item_info (menu, i, TRUE, &info);
+ /* Owner-drawn names are held in dwItemData. */
+ if ((info.fType & MF_OWNERDRAW) && info.dwItemData)
+ {
+#ifdef MENU_DEBUG
+ DebPrint ("Menu: freeing %ld for owner-draw", info.dwItemData);
+#endif
+ LocalFree (info.dwItemData);
+ }
+
+ /* Recurse down submenus. */
+ if (info.hSubMenu)
+ w32_free_submenu_strings (info.hSubMenu);
+ }
+}
+
+void
+w32_free_menu_strings (hwnd)
+ HWND hwnd;
+{
+ HMENU menu = current_popup_menu;
+
+ if (get_menu_item_info)
+ {
+ /* If there is no popup menu active, free the strings from the frame's
+ menubar. */
+ if (!menu)
+ menu = GetMenu (hwnd);
+
+ if (menu)
+ w32_free_submenu_strings (menu);
+ }
+
+ current_popup_menu = NULL;
+}
#endif /* HAVE_MENUS */
+
\f
syms_of_w32menu ()
{
+ /* See if Get/SetMenuItemInfo functions are available. */
+ HMODULE user32 = GetModuleHandle ("user32.dll");
+ get_menu_item_info = GetProcAddress (user32, "GetMenuItemInfoA");
+ set_menu_item_info = GetProcAddress (user32, "SetMenuItemInfoA");
+
staticpro (&menu_items);
menu_items = Qnil;
+ current_popup_menu = NULL;
+
Qdebug_on_next_call = intern ("debug-on-next-call");
staticpro (&Qdebug_on_next_call);