Mercurial > emacs
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, |