From 014510b01f9351d93187b339a156133614cd49a0 Mon Sep 17 00:00:00 2001 From: Geoff Voelker Date: Wed, 3 Sep 1997 00:53:34 +0000 Subject: [PATCH] (init_menu_items): Disable code. (x_activate_menubar): New function. (initialize_frame_menubar): Pass in new param to set_frame_menubar. (get_frame_menubar_event): Check for the possibility of a menu-bar button. A menu-bar button is a caption on the menu bar with no submenu. (set_frame_menubar): Correctly handle menu-bar buttons. (add_menu_item): Equiv parameter send and paid attention to. (keymap_panes, list_of_panes): Use CreatePopupMenu. (single_keymap_panes): Use CreatePopupMenu. Send key descriptions to add_menu_item. (list_of_items): Use CreatePopupMenu. Send nil description to add_menu_item. (get_menu_event): Send keymap instead of menu to get_keymap_event. (Fx_popup_menu): Extra parameter to mouse_position_hook. Don't send address of menu to win32menu_show. (win32menu_show): Send message to call popup menu rather than trying directly. get_menu_event should take an address. Call eat_mouse_events in order to get rid of any extraneous mouse events. (list_of_panes): Only bring up one pane if the length of the list of panes is one. (single_keymap_panes): Fixed problem with 'descrip' lisp object not being protected properly (GCPRO). (get_single_keymap_event): Fixed problem with 'descrip' lisp object not being protected properly (GCPRO). (name_is_separator): New function. (list_of_panes): If a pane's name is empty ("") items are now placed in the main popup instead of a blank-named submenu. This seems to be an undocumented feature of x-popup-menu. (list_of_items): New argument HMENU. Use 1 and 0 instead of Qt and Qnil for enable in add_menu_item --- src/w32menu.c | 379 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 278 insertions(+), 101 deletions(-) diff --git a/src/w32menu.c b/src/w32menu.c index f77ce136fe2..0495818d7ff 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -66,6 +66,8 @@ extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map; extern Lisp_Object Qmenu_bar_update_hook; +void set_frame_menubar (); + static Lisp_Object w32_dialog_show (); static Lisp_Object w32menu_show (); @@ -79,6 +81,7 @@ static HMENU create_menu_items (); /* Initialize the menu_items structure if we haven't already done so. Also mark it as currently empty. */ +#if 0 static void init_menu_items (lpmm) menu_map * lpmm; @@ -93,17 +96,6 @@ init_menu_items (lpmm) lpmm->menu_items_used = 0; } -/* Call when finished using the data for the current menu - in menu_items. */ - -static void -discard_menu_items (lpmm) - menu_map * lpmm; -{ - lpmm->menu_items = Qnil; - lpmm->menu_items_allocated = lpmm->menu_items_used = 0; -} - /* Make the menu_items vector twice as large. */ static void @@ -120,6 +112,39 @@ grow_menu_items (lpmm) lpmm->menu_items = new; } +#endif + +/* Call when finished using the data for the current menu + in menu_items. */ + +static void +discard_menu_items (lpmm) + menu_map * lpmm; +{ +#if 0 + lpmm->menu_items = Qnil; +#endif + lpmm->menu_items_allocated = lpmm->menu_items_used = 0; +} + +/* Is this item a separator? */ +static int +name_is_separator (name) + Lisp_Object name; +{ + int isseparator = (((char *)XSTRING (name)->data)[0] == 0); + + if (!isseparator) + { + /* Check if name string consists of only dashes ('-') */ + char *string = (char *)XSTRING (name)->data; + while (*string == '-') string++; + isseparator = (*string == 0); + } + + return isseparator; +} + /* Indicate boundary between left and right. */ @@ -137,28 +162,40 @@ add_left_right_boundary (hmenu) of the keyboard equivalent for this item (or nil if none). */ static void -add_menu_item (lpmm, hmenu, name, enable, key) +add_menu_item (lpmm, hmenu, name, enable, key, equiv) menu_map * lpmm; HMENU hmenu; Lisp_Object name; UINT enable; Lisp_Object key; + Lisp_Object equiv; { UINT fuFlags; + Lisp_Object out_string; - if (NILP (name) - || ((char *) XSTRING (name)->data)[0] == 0 - || strcmp ((char *) XSTRING (name)->data, "--") == 0) + if (NILP (name) || name_is_separator (name)) fuFlags = MF_SEPARATOR; - else if (enable) - fuFlags = MF_STRING; - else - fuFlags = MF_STRING | MF_GRAYED; - + else + { + if (enable) + fuFlags = MF_STRING; + else + fuFlags = MF_STRING | MF_GRAYED; + + if (!NILP (equiv)) + { + out_string = concat2 (name, make_string ("\t", 1)); + out_string = concat2 (out_string, equiv); + } + else + out_string = name; + } + AppendMenu (hmenu, fuFlags, lpmm->menu_items_used + 1, - (fuFlags == MF_SEPARATOR)?NULL: (char *) XSTRING (name)->data); + (fuFlags == MF_SEPARATOR)?NULL: + (char *) XSTRING (out_string)->data); lpmm->menu_items_used++; #if 0 @@ -316,16 +353,18 @@ keymap_panes (lpmm, keymaps, nmaps, notreal) int notreal; { int mapno; - - // init_menu_items (lpmm); - + +#if 0 + init_menu_items (lpmm); +#endif + if (nmaps > 1) { HMENU hmenu; if (!notreal) { - hmenu = CreateMenu (); + hmenu = CreatePopupMenu (); if (!hmenu) return (NULL); } @@ -376,11 +415,11 @@ single_keymap_panes (lpmm, keymap, pane_name, prefix, notreal) Lisp_Object pending_maps; Lisp_Object tail, item, item1, item_string, table; HMENU hmenu; - struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; if (!notreal) { - hmenu = CreateMenu (); + hmenu = CreatePopupMenu (); if (hmenu == NULL) return NULL; } else @@ -427,7 +466,12 @@ single_keymap_panes (lpmm, keymap, pane_name, prefix, notreal) GCPRO4 (keymap, pending_maps, def, prefix); def = menu_item_equiv_key (item_string, item1, &descrip); - enabled = menu_item_enabled_p (def, notreal); + { + struct gcpro gcpro1; + GCPRO1 (descrip); + enabled = menu_item_enabled_p (def, notreal); + UNGCPRO; + } UNGCPRO; @@ -445,7 +489,7 @@ single_keymap_panes (lpmm, keymap, pane_name, prefix, notreal) { Lisp_Object submap; - GCPRO4 (keymap, pending_maps, item, item_string); + GCPRO5 (keymap, pending_maps, item, item_string, descrip); submap = get_keymap_1 (def, 0, 1); @@ -459,7 +503,8 @@ single_keymap_panes (lpmm, keymap, pane_name, prefix, notreal) hmenu, item_string, !NILP (enabled), - Fcons (XCONS (item)->car, prefix)); + Fcons (XCONS (item)->car, prefix), + descrip); } } else @@ -510,11 +555,16 @@ single_keymap_panes (lpmm, keymap, pane_name, prefix, notreal) aside from that, must protect whatever might be a string. Since there's no GCPRO5, we refetch item_string instead of protecting it. */ - GCPRO4 (keymap, pending_maps, def, descrip); + GCPRO3 (keymap, pending_maps, def); descrip = def = Qnil; def = menu_item_equiv_key (item_string, item1, &descrip); - enabled = menu_item_enabled_p (def, notreal); + { + struct gcpro gcpro1; + GCPRO1 (descrip); + enabled = menu_item_enabled_p (def, notreal); + UNGCPRO; + } UNGCPRO; @@ -528,7 +578,7 @@ single_keymap_panes (lpmm, keymap, pane_name, prefix, notreal) { Lisp_Object submap; - GCPRO4 (keymap, pending_maps, descrip, item_string); + GCPRO5 (keymap, pending_maps, descrip, item_string, descrip); submap = get_keymap_1 (def, 0, 1); @@ -542,7 +592,8 @@ single_keymap_panes (lpmm, keymap, pane_name, prefix, notreal) hmenu, item_string, !NILP (enabled), - character); + character, + descrip); } } else @@ -609,29 +660,49 @@ list_of_panes (lpmm, menu) Lisp_Object tail; HMENU hmenu; - hmenu = CreateMenu (); - if (hmenu == NULL) return NULL; + if (XFASTINT (Flength (menu)) > 1) + { + hmenu = CreatePopupMenu (); + if (hmenu == NULL) return NULL; - // init_menu_items (lpmm); +/* init_menu_items (lpmm); */ - for (tail = menu; !NILP (tail); tail = Fcdr (tail)) + for (tail = menu; !NILP (tail); tail = Fcdr (tail)) + { + Lisp_Object elt, pane_name, pane_data; + HMENU new_hmenu; + + elt = Fcar (tail); + pane_name = Fcar (elt); + CHECK_STRING (pane_name, 0); + pane_data = Fcdr (elt); + CHECK_CONS (pane_data, 0); + + if (XSTRING (pane_name)->data[0] == 0) + { + list_of_items (hmenu, lpmm, pane_data); + } + else + { + new_hmenu = list_of_items (NULL, lpmm, pane_data); + if (new_hmenu == NULL) goto error; + + AppendMenu (hmenu, MF_POPUP, (UINT)new_hmenu, + (char *) XSTRING (pane_name)->data); + } + } + } + else { Lisp_Object elt, pane_name, pane_data; - HMENU new_hmenu; - - elt = Fcar (tail); + + elt = Fcar (menu); pane_name = Fcar (elt); CHECK_STRING (pane_name, 0); pane_data = Fcdr (elt); CHECK_CONS (pane_data, 0); - - new_hmenu = list_of_items (lpmm, pane_data); - if (new_hmenu == NULL) goto error; - - AppendMenu (hmenu, MF_POPUP, (UINT)new_hmenu, - (char *) XSTRING (pane_name)->data); + hmenu = list_of_items (NULL, lpmm, pane_data); } - return (hmenu); error: @@ -643,21 +714,24 @@ list_of_panes (lpmm, menu) /* Push the items in a single pane defined by the alist PANE. */ static HMENU -list_of_items (lpmm, pane) +list_of_items (hmenu, lpmm, pane) + HMENU hmenu; menu_map * lpmm; Lisp_Object pane; { Lisp_Object tail, item, item1; - HMENU hmenu; - hmenu = CreateMenu (); - if (hmenu == NULL) return NULL; + if (hmenu == NULL) + { + hmenu = CreatePopupMenu (); + if (hmenu == NULL) return NULL; + } for (tail = pane; !NILP (tail); tail = Fcdr (tail)) { item = Fcar (tail); if (STRINGP (item)) - add_menu_item (lpmm, hmenu, item, Qnil, Qnil); + add_menu_item (lpmm, hmenu, item, 0, Qnil, Qnil); else if (NILP (item)) add_left_right_boundary (); else @@ -665,7 +739,7 @@ list_of_items (lpmm, pane) CHECK_CONS (item, 0); item1 = Fcar (item); CHECK_STRING (item1, 1); - add_menu_item (lpmm, hmenu, item1, Qt, Fcdr (item)); + add_menu_item (lpmm, hmenu, item1, 1, Fcdr (item), Qnil); } } @@ -770,7 +844,7 @@ get_single_keymap_event (keymap, lpnum) { Lisp_Object pending_maps; Lisp_Object tail, item, item1, item_string, table; - struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; pending_maps = Qnil; @@ -828,7 +902,7 @@ get_single_keymap_event (keymap, lpnum) { Lisp_Object submap; - GCPRO4 (keymap, pending_maps, item, item_string); + GCPRO5 (keymap, pending_maps, item, item_string, descrip); submap = get_keymap_1 (def, 0, 1); @@ -887,7 +961,7 @@ get_single_keymap_event (keymap, lpnum) aside from that, must protect whatever might be a string. Since there's no GCPRO5, we refetch item_string instead of protecting it. */ - GCPRO4 (keymap, pending_maps, def, descrip); + GCPRO3 (keymap, pending_maps, def); descrip = def = Qnil; def = menu_item_equiv_key (item_string, item1, &descrip); @@ -904,7 +978,7 @@ get_single_keymap_event (keymap, lpnum) { Lisp_Object submap; - GCPRO4 (keymap, pending_maps, descrip, item_string); + GCPRO5 (keymap, pending_maps, descrip, item_string, descrip); submap = get_keymap_1 (def, 0, 1); @@ -1072,7 +1146,7 @@ get_menu_event (menu, lpnum) { keymap = get_keymap (menu); - event = get_keymap_event (menu, 1, lpnum); + event = get_keymap_event (&keymap, 1, lpnum); } else if (!NILP (tem)) { @@ -1162,8 +1236,8 @@ cached information about equivalent key sequences.") unsigned long time; if (mouse_position_hook) - (*mouse_position_hook) (&new_f, 1, &bar_window, - &part, &x, &y, &time); + (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, + &time); if (new_f != 0) XSETFRAME (window, new_f); else @@ -1368,15 +1442,41 @@ get_frame_menubar_event (f, num) for (i = 0; i < XVECTOR (items)->size; i += 4) { - Lisp_Object event; - - event = get_menu_event (XVECTOR (items)->contents[i + 2], &num); - - if (num <= 0) + Lisp_Object event, binding; + binding = XVECTOR (items)->contents[i + 2]; + + /* Check to see if this might be a menubar button. It might be + if it is not a keymap, it is a cons cell, its car is not a + keymap, and its cdr is nil. */ + if (NILP (Fkeymapp (binding)) + && CONSP (binding) + && NILP (Fkeymapp (XCONS (binding)->car)) + && NILP (XCONS (binding)->cdr)) { - UNGCPRO; - UNBLOCK_INPUT; - return (Fcons (XVECTOR (items)->contents[i], event)); + /* The fact that we have to check that this is a string here + is the reason we don't do all this rigamarole in + get_menu_event. */ + if (XTYPE (XVECTOR (items)->contents[i + 1]) == Lisp_String) + { + /* This was a menubar button. */ + if (--num <= 0) + { + UNGCPRO; + UNBLOCK_INPUT; + return (Fcons (XVECTOR (items)->contents[i], Qnil)); + } + } + } + else + { + event = get_menu_event (binding, &num); + + if (num <= 0) + { + UNGCPRO; + UNBLOCK_INPUT; + return (Fcons (XVECTOR (items)->contents[i], event)); + } } } @@ -1386,21 +1486,56 @@ get_frame_menubar_event (f, num) return (Qnil); } +/* Activate the menu bar of frame F. + This is called from keyboard.c when it gets the + menu_bar_activate_event out of the Emacs event queue. + + To activate the menu bar, we signal to the input thread that it can + return from the WM_INITMENU message, allowing the normal Windows + processing of the menus. + + But first we recompute the menu bar contents (the whole tree). + + This way we can safely execute Lisp code. */ + +x_activate_menubar (f) + FRAME_PTR f; +{ + set_frame_menubar (f, 0, 1); + + /* Lock out further menubar changes while active. */ + f->output_data.w32->menubar_active = 1; + + /* Signal input thread to return from WM_INITMENU. */ + complete_deferred_msg (FRAME_W32_WINDOW (f), WM_INITMENU, 0); +} + void -set_frame_menubar (f, first_time) +set_frame_menubar (f, first_time, deep_p) FRAME_PTR f; int first_time; + int deep_p; { Lisp_Object tail, items; HMENU hmenu; int i; - struct gcpro gcpro1; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; menu_map mm; int count = specpdl_ptr - specpdl; struct buffer *prev = current_buffer; Lisp_Object buffer; + /* We must not change the menubar when actually in use. */ + if (f->output_data.w32->menubar_active) + return; + +#if 0 /* I don't see why this should be needed */ + /* Ensure menubar is up to date when about to be used. */ + if (f->output_data.w32->pending_menu_activation && !deep_p) + deep_p = 1; +#endif + buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer; specbind (Qinhibit_quit, Qt); /* Don't let the debugger step into this code @@ -1432,16 +1567,25 @@ set_frame_menubar (f, first_time) if (NILP (items)) items = FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); + hmenu = f->output_data.w32->menubar_widget; + if (!hmenu) + { hmenu = CreateMenu (); - if (!hmenu) goto error; + } + else + { + /* Delete current contents. */ + while (DeleteMenu (hmenu, 0, MF_BYPOSITION)) + ; + } discard_menu_items (&mm); UNBLOCK_INPUT; for (i = 0; i < XVECTOR (items)->size; i += 4) { - Lisp_Object string; + Lisp_Object string, binding; int keymaps; CHAR *error; HMENU new_hmenu; @@ -1449,27 +1593,58 @@ set_frame_menubar (f, first_time) string = XVECTOR (items)->contents[i + 1]; if (NILP (string)) break; + + binding = XVECTOR (items)->contents[i + 2]; + + if (NILP (Fkeymapp (binding)) + && CONSP (binding) + && NILP (Fkeymapp (XCONS (binding)->car)) + && NILP (XCONS (binding)->cdr)) + { + /* This is a menubar button. */ + Lisp_Object descrip, def; + Lisp_Object enabled, item; + item = Fcons (string, Fcar (binding)); + descrip = def = Qnil; + UNGCPRO; + GCPRO4 (items, item, def, string); + + def = menu_item_equiv_key (string, item, &descrip); + enabled = menu_item_enabled_p (def, 0); + + UNGCPRO; + GCPRO1 (items); + + add_menu_item (&mm, hmenu, string, enabled, def, Qnil); + } + else + { + /* Input must not be blocked here because we call general + Lisp code and internal_condition_case_1. */ + new_hmenu = create_menu_items (&mm, binding, 0); - /* Input must not be blocked here - because we call general Lisp code and internal_condition_case_1. */ - new_hmenu = create_menu_items (&mm, - XVECTOR (items)->contents[i + 2], - 0); - - if (!new_hmenu) - continue; + if (!new_hmenu) + continue; - BLOCK_INPUT; - AppendMenu (hmenu, MF_POPUP, (UINT)new_hmenu, - (char *) XSTRING (string)->data); - UNBLOCK_INPUT; + BLOCK_INPUT; + AppendMenu (hmenu, MF_POPUP, (UINT)new_hmenu, + (char *) XSTRING (string)->data); + UNBLOCK_INPUT; + } } BLOCK_INPUT; { - HMENU old = GetMenu (FRAME_W32_WINDOW (f)); + HMENU old = f->output_data.w32->menubar_widget; SetMenu (FRAME_W32_WINDOW (f), hmenu); - DestroyMenu (old); + f->output_data.w32->menubar_widget = hmenu; + /* Causes flicker when menu bar is updated + DrawMenuBar (FRAME_W32_WINDOW (f)); */ + + /* Force the window size to be recomputed so that the frame's text + area remains the same, if menubar has just been created. */ + if (old == NULL) + x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f)); } error: @@ -1488,6 +1663,7 @@ free_frame_menubar (f) { HMENU old = GetMenu (FRAME_W32_WINDOW (f)); SetMenu (FRAME_W32_WINDOW (f), NULL); + f->output_data.w32->menubar_widget = NULL; DestroyMenu (old); } @@ -1501,7 +1677,7 @@ void initialize_frame_menubar (f) FRAME_PTR f; { - set_frame_menubar (f, 1); + set_frame_menubar (f, 1, 1); } #if 0 @@ -1590,7 +1766,7 @@ else if (EQ (XVECTOR (menu_items)->contents[i], Qt)) if (!hmenu || strcmp (pane_string, "")) { - HMENU new_hmenu = CreateMenu (); + HMENU new_hmenu = CreatePopupMenu (); if (!new_hmenu) { @@ -1620,10 +1796,9 @@ else enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; // descrip = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; - if (((char *) XSTRING (item_name)->data)[0] == 0 - || strcmp ((char *) XSTRING (item_name)->data, "--") == 0) + if (name_is_separator (item_name)) fuFlags = MF_SEPARATOR; - else if (NILP (enable) || !XUINT(enable)) + else if (NILP (enable) || !XUINT (enable)) fuFlags = MF_STRING | MF_GRAYED; else fuFlags = MF_STRING; @@ -1701,14 +1876,16 @@ w32menu_show (f, x, y, menu, hmenu, error) return Qnil; } #endif - + /* Display the menu. */ - menu_selection = TrackPopupMenu (hmenu, - 0x10, - pos.x, pos.y, - 0, - FRAME_W32_WINDOW (f), - NULL); + menu_selection = SendMessage (FRAME_W32_WINDOW (f), + WM_EMACS_TRACKPOPUPMENU, + (WPARAM)hmenu, (LPARAM)&pos); + + /* Clean up extraneous mouse events which might have been generated + during the call. */ + discard_mouse_events (); + if (menu_selection == -1) { *error = "Invalid menu specification"; @@ -1721,7 +1898,7 @@ w32menu_show (f, x, y, menu, hmenu, error) #if 1 if (menu_selection > 0) { - return get_menu_event (menu, menu_selection); + return get_menu_event (menu, &menu_selection); } #else if (menu_selection > 0 && menu_selection <= lpmm->menu_items_used) @@ -1729,7 +1906,7 @@ w32menu_show (f, x, y, menu, hmenu, error) return (XVECTOR (lpmm->menu_items)->contents[menu_selection - 1]); } #endif - + return Qnil; } -- 2.39.2