comparison src/w32menu.c @ 41733:917737801660

(current_popup_menu, get_menu_item_info): (set_menu_item_info): New vars. (set_frame_menubar): Doc fix clarifying GC interaction with menus. (w32_menu_show): Set current_popup_menu. (add_menu_item): Allocate new strings for owner-drawn menu items and help strings. Use owner-draw for disabled menu items again. (w32_menu_display_help): Ignore owner-drawn items and popup menus. (w32_free_submenu_strings, w32_free_menu_strings): New functions.
author Jason Rumney <jasonr@gnu.org>
date Sat, 01 Dec 2001 11:14:23 +0000
parents 258fa72efab7
children 4d8905b9ee49
comparison
equal deleted inserted replaced
41732:0d9b74cd27cd 41733:917737801660
117 #ifndef TRUE 117 #ifndef TRUE
118 #define TRUE 1 118 #define TRUE 1
119 #define FALSE 0 119 #define FALSE 0
120 #endif /* no TRUE */ 120 #endif /* no TRUE */
121 121
122 static HMENU current_popup_menu;
123
124 FARPROC get_menu_item_info;
125 FARPROC set_menu_item_info;
126
122 Lisp_Object Vmenu_updating_frame; 127 Lisp_Object Vmenu_updating_frame;
123 128
124 Lisp_Object Qdebug_on_next_call; 129 Lisp_Object Qdebug_on_next_call;
125 130
126 extern Lisp_Object Qmenu_bar; 131 extern Lisp_Object Qmenu_bar;
1414 1419
1415 return; 1420 return;
1416 } 1421 }
1417 1422
1418 /* Now GC cannot happen during the lifetime of the widget_value, 1423 /* Now GC cannot happen during the lifetime of the widget_value,
1419 so it's safe to store data from a Lisp_String. */ 1424 so it's safe to store data from a Lisp_String, as long as
1425 local copies are made when the actual menu is created.
1426 Windows takes care of this for normal string items, but
1427 not for owner-drawn items or additional item-info. */
1420 wv = first_wv->contents; 1428 wv = first_wv->contents;
1421 for (i = 0; i < XVECTOR (items)->size; i += 4) 1429 for (i = 0; i < XVECTOR (items)->size; i += 4)
1422 { 1430 {
1423 Lisp_Object string; 1431 Lisp_Object string;
1424 string = XVECTOR (items)->contents[i + 1]; 1432 string = XVECTOR (items)->contents[i + 1];
1750 wv_title->next = wv_sep; 1758 wv_title->next = wv_sep;
1751 first_wv->contents = wv_title; 1759 first_wv->contents = wv_title;
1752 } 1760 }
1753 1761
1754 /* Actually create the menu. */ 1762 /* Actually create the menu. */
1755 menu = CreatePopupMenu (); 1763 current_popup_menu = menu = CreatePopupMenu ();
1756 fill_in_menu (menu, first_wv->contents); 1764 fill_in_menu (menu, first_wv->contents);
1757 1765
1758 /* Adjust coordinates to be root-window-relative. */ 1766 /* Adjust coordinates to be root-window-relative. */
1759 pos.x = x; 1767 pos.x = x;
1760 pos.y = y; 1768 pos.y = y;
1834 1842
1835 return Qnil; 1843 return Qnil;
1836 } 1844 }
1837 1845
1838 1846
1847 #ifdef HAVE_DIALOGS
1839 static char * button_names [] = { 1848 static char * button_names [] = {
1840 "button1", "button2", "button3", "button4", "button5", 1849 "button1", "button2", "button3", "button4", "button5",
1841 "button6", "button7", "button8", "button9", "button10" }; 1850 "button6", "button7", "button8", "button9", "button10" };
1842 1851
1843 static Lisp_Object 1852 static Lisp_Object
1957 wv->contents = first_wv; 1966 wv->contents = first_wv;
1958 first_wv = wv; 1967 first_wv = wv;
1959 } 1968 }
1960 1969
1961 /* Actually create the dialog. */ 1970 /* Actually create the dialog. */
1962 #ifdef HAVE_DIALOGS
1963 dialog_id = widget_id_tick++; 1971 dialog_id = widget_id_tick++;
1964 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv, 1972 menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
1965 f->output_data.w32->widget, 1, 0, 1973 f->output_data.w32->widget, 1, 0,
1966 dialog_selection_callback, 0); 1974 dialog_selection_callback, 0);
1967 lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE); 1975 lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
1968 #endif
1969 1976
1970 /* Free the widget_value objects we used to specify the contents. */ 1977 /* Free the widget_value objects we used to specify the contents. */
1971 free_menubar_widget_value_tree (first_wv); 1978 free_menubar_widget_value_tree (first_wv);
1972 1979
1973 /* No selection has been chosen yet. */ 1980 /* No selection has been chosen yet. */
1974 menu_item_selection = 0; 1981 menu_item_selection = 0;
1975 1982
1976 /* Display the menu. */ 1983 /* Display the menu. */
1977 #ifdef HAVE_DIALOGS
1978 lw_pop_up_all_widgets (dialog_id); 1984 lw_pop_up_all_widgets (dialog_id);
1979 popup_activated_flag = 1; 1985 popup_activated_flag = 1;
1980 1986
1981 /* Process events that apply to the menu. */ 1987 /* Process events that apply to the menu. */
1982 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id); 1988 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
1983 1989
1984 lw_destroy_all_widgets (dialog_id); 1990 lw_destroy_all_widgets (dialog_id);
1985 #endif
1986 1991
1987 /* Find the selected item, and its pane, to return 1992 /* Find the selected item, and its pane, to return
1988 the proper value. */ 1993 the proper value. */
1989 if (menu_item_selection != 0) 1994 if (menu_item_selection != 0)
1990 { 1995 {
2021 } 2026 }
2022 } 2027 }
2023 2028
2024 return Qnil; 2029 return Qnil;
2025 } 2030 }
2031 #endif /* HAVE_DIALOGS */
2026 2032
2027 2033
2028 /* Is this item a separator? */ 2034 /* Is this item a separator? */
2029 static int 2035 static int
2030 name_is_separator (name) 2036 name_is_separator (name)
2075 strcat (out_string, wv->key); 2081 strcat (out_string, wv->key);
2076 } 2082 }
2077 else 2083 else
2078 out_string = wv->name; 2084 out_string = wv->name;
2079 2085
2080 if (wv->title) 2086 if (wv->title || wv->call_data == 0)
2081 { 2087 {
2082 #if 0 /* no GC while popup menu is active */ 2088 /* Only use MF_OWNERDRAW if GetMenuItemInfo is usable, since
2083 out_string = LocalAlloc (0, strlen (wv->name) + 1); 2089 we can't deallocate the memory otherwise. */
2084 strcpy (out_string, wv->name); 2090 if (get_menu_item_info)
2085 #endif 2091 {
2086 fuFlags = MF_OWNERDRAW | MF_DISABLED; 2092 out_string = LocalAlloc (LPTR, strlen (wv->name) + 1);
2087 } 2093 strcpy (out_string, wv->name);
2088 else if (wv->call_data == 0) 2094 fuFlags = MF_OWNERDRAW | MF_DISABLED;
2089 fuFlags |= MF_DISABLED; 2095 }
2096 else
2097 fuFlags = MF_DISABLED;
2098 }
2090 2099
2091 /* Draw radio buttons and tickboxes. */ 2100 /* Draw radio buttons and tickboxes. */
2092 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE || 2101 else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
2093 wv->button_type == BUTTON_TYPE_RADIO)) 2102 wv->button_type == BUTTON_TYPE_RADIO))
2094 fuFlags |= MF_CHECKED; 2103 fuFlags |= MF_CHECKED;
2106 out_string ); 2115 out_string );
2107 2116
2108 /* This must be done after the menu item is created. */ 2117 /* This must be done after the menu item is created. */
2109 if (!wv->title && wv->call_data != 0) 2118 if (!wv->title && wv->call_data != 0)
2110 { 2119 {
2111 HMODULE user32 = GetModuleHandle ("user32.dll");
2112 FARPROC set_menu_item_info = GetProcAddress (user32, "SetMenuItemInfoA");
2113
2114 if (set_menu_item_info) 2120 if (set_menu_item_info)
2115 { 2121 {
2116 MENUITEMINFO info; 2122 MENUITEMINFO info;
2117 bzero (&info, sizeof (info)); 2123 bzero (&info, sizeof (info));
2118 info.cbSize = sizeof (info); 2124 info.cbSize = sizeof (info);
2119 info.fMask = MIIM_DATA; 2125 info.fMask = MIIM_DATA;
2120 2126
2121 /* Set help string for menu item. */ 2127 /* Set help string for menu item. Allocate new memory
2122 info.dwItemData = (DWORD)wv->help; 2128 from the heap for it, since garbage collection can
2129 occur while menus are active. */
2130 if (wv->help)
2131 {
2132 info.dwItemData
2133 = (DWORD) LocalAlloc (LPTR, strlen(wv->help) + 1);
2134 strcpy (info.dwItemData, wv->help);
2135 }
2123 2136
2124 if (wv->button_type == BUTTON_TYPE_RADIO) 2137 if (wv->button_type == BUTTON_TYPE_RADIO)
2125 { 2138 {
2126 /* CheckMenuRadioItem allows us to differentiate TOGGLE and 2139 /* CheckMenuRadioItem allows us to differentiate TOGGLE and
2127 RADIO items, but is not available on NT 3.51 and earlier. */ 2140 RADIO items, but is not available on NT 3.51 and earlier. */
2181 supported on NT 3.51 and earlier, as GetMenuItemInfo is not 2194 supported on NT 3.51 and earlier, as GetMenuItemInfo is not
2182 available. */ 2195 available. */
2183 void 2196 void
2184 w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags) 2197 w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags)
2185 { 2198 {
2186 HMODULE user32 = GetModuleHandle ("user32.dll");
2187 FARPROC get_menu_item_info = GetProcAddress (user32, "GetMenuItemInfoA");
2188
2189 if (get_menu_item_info) 2199 if (get_menu_item_info)
2190 { 2200 {
2191 MENUITEMINFO info;
2192 struct frame *f = x_window_to_frame (&one_w32_display_info, owner); 2201 struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
2193 Lisp_Object frame, help; 2202 Lisp_Object frame, help;
2194 2203
2195 bzero (&info, sizeof (info)); 2204 // No help echo on owner-draw menu items.
2196 info.cbSize = sizeof (info); 2205 if (flags & MF_OWNERDRAW || flags & MF_POPUP)
2197 info.fMask = MIIM_DATA; 2206 help = Qnil;
2198 get_menu_item_info (menu, item, FALSE, &info); 2207 else
2199 2208 {
2200 help = info.dwItemData ? build_string ((char *)info.dwItemData) : Qnil; 2209 MENUITEMINFO info;
2210
2211 bzero (&info, sizeof (info));
2212 info.cbSize = sizeof (info);
2213 info.fMask = MIIM_DATA;
2214 get_menu_item_info (menu, item, FALSE, &info);
2215
2216 help = info.dwItemData ? build_string ((char *)info.dwItemData) : Qnil;
2217 }
2201 2218
2202 /* Store the help echo in the keyboard buffer as the X toolkit 2219 /* Store the help echo in the keyboard buffer as the X toolkit
2203 version does, rather than directly showing it. This seems to 2220 version does, rather than directly showing it. This seems to
2204 solve the GC problems that were present when we based the 2221 solve the GC problems that were present when we based the
2205 Windows code on the non-toolkit version. */ 2222 Windows code on the non-toolkit version. */
2213 appear to do anything, unless it has some side effect. */ 2230 appear to do anything, unless it has some side effect. */
2214 show_help_echo (help, Qnil, Qnil, Qnil, 1); 2231 show_help_echo (help, Qnil, Qnil, Qnil, 1);
2215 } 2232 }
2216 } 2233 }
2217 2234
2218 2235 /* Free memory used by owner-drawn and help_echo strings. */
2236 static void
2237 w32_free_submenu_strings (menu)
2238 HMENU menu;
2239 {
2240 int i, num = GetMenuItemCount (menu);
2241 for (i = 0; i < num; i++)
2242 {
2243 MENUITEMINFO info;
2244
2245 info.cbSize = sizeof (info);
2246 info.fMask = MIIM_DATA | MIIM_SUBMENU;
2247
2248 get_menu_item_info (menu, i, TRUE, &info);
2249
2250 /* Both owner-drawn names and help strings are held in dwItemData. */
2251 if (info.dwItemData)
2252 LocalFree (info.dwItemData);
2253
2254 /* Recurse down submenus. */
2255 if (info.hSubMenu)
2256 w32_free_submenu_strings (info.hSubMenu);
2257 }
2258 }
2259
2260 void
2261 w32_free_menu_strings (hwnd)
2262 HWND hwnd;
2263 {
2264 HMENU menu = current_popup_menu;
2265
2266 if (get_menu_item_info)
2267 {
2268 /* If there is no popup menu active, free the strings from the frame's
2269 menubar. */
2270 if (!menu)
2271 menu = GetMenu (hwnd);
2272
2273 if (menu)
2274 w32_free_submenu_strings (menu);
2275 }
2276
2277 current_popup_menu = NULL;
2278 }
2219 2279
2220 #endif /* HAVE_MENUS */ 2280 #endif /* HAVE_MENUS */
2281
2221 2282
2222 syms_of_w32menu () 2283 syms_of_w32menu ()
2223 { 2284 {
2285 /* See if Get/SetMenuItemInfo functions are available. */
2286 HMODULE user32 = GetModuleHandle ("user32.dll");
2287 get_menu_item_info = GetProcAddress (user32, "GetMenuItemInfoA");
2288 set_menu_item_info = GetProcAddress (user32, "SetMenuItemInfoA");
2289
2224 staticpro (&menu_items); 2290 staticpro (&menu_items);
2225 menu_items = Qnil; 2291 menu_items = Qnil;
2292
2293 current_popup_menu = NULL;
2226 2294
2227 Qdebug_on_next_call = intern ("debug-on-next-call"); 2295 Qdebug_on_next_call = intern ("debug-on-next-call");
2228 staticpro (&Qdebug_on_next_call); 2296 staticpro (&Qdebug_on_next_call);
2229 2297
2230 DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame, 2298 DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,