X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/f46305c86cd247b2396e73ce8bb064f69373834d..2bfa3d3e1fb347ba76bddf77f3e288049635821d:/src/w32menu.c diff --git a/src/w32menu.c b/src/w32menu.c index 346402b7c6..19eac1329a 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -1,5 +1,5 @@ /* Menu support for GNU Emacs on the Microsoft Windows API. - Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2013 Free + Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2014 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -82,8 +82,8 @@ typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) ( IN LPCMENUITEMINFOA); typedef int (WINAPI * MessageBoxW_Proc) ( IN HWND window, - IN WCHAR *text, - IN WCHAR *caption, + IN const WCHAR *text, + IN const WCHAR *caption, IN UINT type); #ifdef NTGUI_UNICODE @@ -98,15 +98,15 @@ AppendMenuW_Proc unicode_append_menu = NULL; MessageBoxW_Proc unicode_message_box = NULL; #endif /* NTGUI_UNICODE */ -Lisp_Object Qdebug_on_next_call; +Lisp_Object Qdebug_on_next_call, Qunsupported__w32_dialog; -void set_frame_menubar (FRAME_PTR, bool, bool); +void set_frame_menubar (struct frame *, bool, bool); #ifdef HAVE_DIALOGS -static Lisp_Object w32_dialog_show (FRAME_PTR, int, Lisp_Object, char**); +static Lisp_Object w32_dialog_show (struct frame *, Lisp_Object, Lisp_Object, char **); #else static int is_simple_dialog (Lisp_Object); -static Lisp_Object simple_dialog_show (FRAME_PTR, Lisp_Object, Lisp_Object); +static Lisp_Object simple_dialog_show (struct frame *, Lisp_Object, Lisp_Object); #endif static void utf8to16 (unsigned char *, int, WCHAR *); @@ -114,128 +114,42 @@ static int fill_in_menu (HMENU, widget_value *); void w32_free_menu_strings (HWND); -#ifdef HAVE_MENUS - -DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0, - doc: /* Pop up a dialog box and return user's selection. -POSITION specifies which frame to use. -This is normally a mouse button event or a window or frame. -If POSITION is t, it means to use the frame the mouse is on. -The dialog box appears in the middle of the specified frame. - -CONTENTS specifies the alternatives to display in the dialog box. -It is a list of the form (TITLE ITEM1 ITEM2...). -Each ITEM is a cons cell (STRING . VALUE). -The return value is VALUE from the chosen item. - -An ITEM may also be just a string--that makes a nonselectable item. -An ITEM may also be nil--that means to put all preceding items -on the left of the dialog box and all following items on the right. -\(By default, approximately half appear on each side.) - -If HEADER is non-nil, the frame title for the box is "Information", -otherwise it is "Question". */) - (Lisp_Object position, Lisp_Object contents, Lisp_Object header) +Lisp_Object +w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) { - FRAME_PTR f = NULL; - Lisp_Object window; - - /* Decode the first argument: find the window or frame to use. */ - if (EQ (position, Qt) - || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) - || EQ (XCAR (position), Qtool_bar)))) - { -#if 0 /* Using the frame the mouse is on may not be right. */ - /* Use the mouse's current position. */ - FRAME_PTR new_f = SELECTED_FRAME (); - Lisp_Object bar_window; - enum scroll_bar_part part; - Time time; - Lisp_Object x, y; - - (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time); - - if (new_f != 0) - XSETFRAME (window, new_f); - else - window = selected_window; -#endif - window = selected_window; - } - else if (CONSP (position)) - { - Lisp_Object tem = XCAR (position); - if (CONSP (tem)) - window = Fcar (XCDR (position)); - else - { - tem = Fcar (XCDR (position)); /* EVENT_START (position) */ - window = Fcar (tem); /* POSN_WINDOW (tem) */ - } - } - else if (WINDOWP (position) || FRAMEP (position)) - window = position; - else - window = Qnil; - - /* Decode where to put the menu. */ - - if (FRAMEP (window)) - f = XFRAME (window); - else if (WINDOWP (window)) - { - CHECK_LIVE_WINDOW (window); - f = XFRAME (WINDOW_FRAME (XWINDOW (window))); - } - else - /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME, - but I don't want to make one now. */ - CHECK_WINDOW (window); check_window_system (f); #ifndef HAVE_DIALOGS - { - /* Handle simple Yes/No choices as MessageBox popups. */ - if (is_simple_dialog (contents)) - return simple_dialog_show (f, contents, header); - else - { - /* Display a menu with these alternatives - in the middle of frame F. */ - Lisp_Object x, y, frame, newpos; - XSETFRAME (frame, f); - XSETINT (x, x_pixel_width (f) / 2); - XSETINT (y, x_pixel_height (f) / 2); - newpos = Fcons (Fcons (x, Fcons (y, Qnil)), Fcons (frame, Qnil)); - return Fx_popup_menu (newpos, - Fcons (Fcar (contents), Fcons (contents, Qnil))); - } - } -#else /* HAVE_DIALOGS */ - { - Lisp_Object title; - char *error_name; - Lisp_Object selection; + /* Handle simple Yes/No choices as MessageBox popups. */ + if (is_simple_dialog (contents)) + return simple_dialog_show (f, contents, header); + else + return Qunsupported__w32_dialog; +#else /* HAVE_DIALOGS */ + { + Lisp_Object title; + char *error_name; + Lisp_Object selection; - /* Decode the dialog items from what was specified. */ - title = Fcar (contents); - CHECK_STRING (title); + /* Decode the dialog items from what was specified. */ + title = Fcar (contents); + CHECK_STRING (title); - list_of_panes (Fcons (contents, Qnil)); + list_of_panes (Fcons (contents, Qnil)); - /* Display them in a dialog box. */ - block_input (); - selection = w32_dialog_show (f, 0, title, header, &error_name); - unblock_input (); + /* Display them in a dialog box. */ + block_input (); + selection = w32_dialog_show (f, title, header, &error_name); + unblock_input (); - discard_menu_items (); - FRAME_X_DISPLAY_INFO (f)->grabbed = 0; + discard_menu_items (); + FRAME_DISPLAY_INFO (f)->grabbed = 0; - if (error_name) error (error_name); - return selection; - } + if (error_name) error (error_name); + return selection; + } #endif /* HAVE_DIALOGS */ } @@ -252,7 +166,7 @@ otherwise it is "Question". */) This way we can safely execute Lisp code. */ void -x_activate_menubar (FRAME_PTR f) +x_activate_menubar (struct frame *f) { set_frame_menubar (f, 0, 1); @@ -269,7 +183,7 @@ x_activate_menubar (FRAME_PTR f) and put the appropriate events into the keyboard buffer. */ void -menubar_selection_callback (FRAME_PTR f, void * client_data) +menubar_selection_callback (struct frame *f, void * client_data) { Lisp_Object prefix, entry; Lisp_Object vector; @@ -361,7 +275,7 @@ menubar_selection_callback (FRAME_PTR f, void * client_data) it is set the first time this is called, from initialize_frame_menubar. */ void -set_frame_menubar (FRAME_PTR f, bool first_time, bool deep_p) +set_frame_menubar (struct frame *f, bool first_time, bool deep_p) { HMENU menubar_widget = f->output_data.w32->menubar_widget; Lisp_Object items; @@ -385,7 +299,7 @@ set_frame_menubar (FRAME_PTR f, bool first_time, bool deep_p) struct buffer *prev = current_buffer; Lisp_Object buffer; - ptrdiff_t specpdl_count = SPECPDL_INDEX (); + dynwind_begin (); int previous_menu_items_used = f->menu_bar_items_used; Lisp_Object *previous_items = (Lisp_Object *) alloca (previous_menu_items_used @@ -462,12 +376,8 @@ set_frame_menubar (FRAME_PTR f, bool first_time, bool deep_p) /* Convert menu_items into widget_value trees to display the menu. This cannot evaluate Lisp code. */ - wv = xmalloc_widget_value (); - wv->name = "menubar"; - wv->value = 0; - wv->enabled = 1; + wv = make_widget_value ("menubar", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; - wv->help = Qnil; first_wv = wv; for (i = 0; i < last_i; i += 4) @@ -498,7 +408,7 @@ set_frame_menubar (FRAME_PTR f, bool first_time, bool deep_p) { free_menubar_widget_value_tree (first_wv); discard_menu_items (); - unbind_to (specpdl_count, Qnil); + dynwind_end (); return; } @@ -506,7 +416,7 @@ set_frame_menubar (FRAME_PTR f, bool first_time, bool deep_p) f->menu_bar_items_used = menu_items_used; /* This undoes save_menu_items. */ - unbind_to (specpdl_count, Qnil); + dynwind_end (); /* Now GC cannot happen during the lifetime of the widget_value, so it's safe to store data from a Lisp_String, as long as @@ -530,12 +440,8 @@ set_frame_menubar (FRAME_PTR f, bool first_time, bool deep_p) /* Make a widget-value tree containing just the top level menu bar strings. */ - wv = xmalloc_widget_value (); - wv->name = "menubar"; - wv->value = 0; - wv->enabled = 1; + wv = make_widget_value ("menubar", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; - wv->help = Qnil; first_wv = wv; items = FRAME_MENU_BAR_ITEMS (f); @@ -547,12 +453,8 @@ set_frame_menubar (FRAME_PTR f, bool first_time, bool deep_p) if (NILP (string)) break; - wv = xmalloc_widget_value (); - wv->name = SSDATA (string); - wv->value = 0; - wv->enabled = 1; + wv = make_widget_value (SSDATA (string), NULL, true, Qnil); 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. @@ -601,7 +503,7 @@ set_frame_menubar (FRAME_PTR f, bool first_time, bool deep_p) /* 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_widget == NULL) - x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f)); + x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1); } unblock_input (); @@ -613,7 +515,7 @@ set_frame_menubar (FRAME_PTR f, bool first_time, bool deep_p) is visible. */ void -initialize_frame_menubar (FRAME_PTR f) +initialize_frame_menubar (struct frame *f) { /* This function is called before the first chance to redisplay the frame. It has to be, so the frame will have the right size. */ @@ -625,7 +527,7 @@ initialize_frame_menubar (FRAME_PTR f) This is used when deleting a frame, and when turning off the menu bar. */ void -free_frame_menubar (FRAME_PTR f) +free_frame_menubar (struct frame *f) { block_input (); @@ -647,8 +549,9 @@ free_frame_menubar (FRAME_PTR f) /* F is the frame the menu is for. X and Y are the frame-relative specified position, relative to the inside upper left corner of the frame F. - FOR_CLICK is nonzero if this menu was invoked for a mouse click. - KEYMAPS is 1 if this menu was specified with keymaps; + Bitfield MENUFLAGS bits are: + MENU_FOR_CLICK is set if this menu was invoked for a mouse click. + MENU_KEYMAPS is set if this menu was specified with keymaps; in that case, we return a list containing the chosen item's value and perhaps also the pane's prefix. TITLE is the specified menu title. @@ -656,7 +559,7 @@ free_frame_menubar (FRAME_PTR f) (We return nil on failure, but the value doesn't actually matter.) */ Lisp_Object -w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, +w32_menu_show (struct frame *f, int x, int y, int menuflags, Lisp_Object title, const char **error) { int i; @@ -682,14 +585,12 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, return Qnil; } + block_input (); + /* Create a tree of widget_value objects representing the panes and their items. */ - wv = xmalloc_widget_value (); - wv->name = "menu"; - wv->value = 0; - wv->enabled = 1; + wv = make_widget_value ("menu", NULL, true, Qnil); wv->button_type = BUTTON_TYPE_NONE; - wv->help = Qnil; first_wv = wv; first_pane = 1; @@ -723,7 +624,7 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, { /* Create a new pane. */ Lisp_Object pane_name, prefix; - char *pane_string; + const char *pane_string; pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); @@ -747,20 +648,16 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, /* If the pane has a meaningful name, make the pane a top-level menu item with its items as a submenu beneath it. */ - if (!keymaps && strcmp (pane_string, "")) + if (!(menuflags & MENU_KEYMAPS) && strcmp (pane_string, "")) { - wv = xmalloc_widget_value (); + wv = make_widget_value (pane_string, NULL, true, Qnil); if (save_wv) save_wv->next = wv; else first_wv->contents = wv; - wv->name = pane_string; - if (keymaps && !NILP (prefix)) + if ((menuflags & MENU_KEYMAPS) && !NILP (prefix)) wv->name++; - wv->value = 0; - wv->enabled = 1; wv->button_type = BUTTON_TYPE_NONE; - wv->help = Qnil; save_wv = wv; prev_wv = 0; } @@ -801,19 +698,17 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip); } - wv = xmalloc_widget_value (); + wv = make_widget_value (SSDATA (item_name), NULL, !NILP (enable), + STRINGP (help) ? help : Qnil); if (prev_wv) prev_wv->next = wv; else save_wv->contents = wv; - wv->name = SSDATA (item_name); if (!NILP (descrip)) wv->key = SSDATA (descrip); - wv->value = 0; /* Use the contents index as call_data, since we are restricted to 16-bits. */ wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0; - wv->enabled = !NILP (enable); if (NILP (type)) wv->button_type = BUTTON_TYPE_NONE; @@ -826,11 +721,6 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, wv->selected = !NILP (selected); - if (!STRINGP (help)) - help = Qnil; - - wv->help = help; - prev_wv = wv; i += MENU_ITEMS_ITEM_LENGTH; @@ -840,25 +730,21 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, /* Deal with the title, if it is non-nil. */ if (!NILP (title)) { - widget_value *wv_title = xmalloc_widget_value (); - widget_value *wv_sep = xmalloc_widget_value (); + widget_value *wv_title; + widget_value *wv_sep = make_widget_value ("--", NULL, false, Qnil); /* Maybe replace this separator with a bitmap or owner-draw item so that it looks better. Having two separators looks odd. */ - wv_sep->name = "--"; wv_sep->next = first_wv->contents; - wv_sep->help = Qnil; if (unicode_append_menu) title = ENCODE_UTF_8 (title); else if (STRING_MULTIBYTE (title)) title = ENCODE_SYSTEM (title); - wv_title->name = SSDATA (title); - wv_title->enabled = TRUE; + wv_title = make_widget_value (SSDATA (title), NULL, true, Qnil); 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; } @@ -883,7 +769,7 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, /* Clean up extraneous mouse events which might have been generated during the call. */ discard_mouse_events (); - FRAME_X_DISPLAY_INFO (f)->grabbed = 0; + FRAME_DISPLAY_INFO (f)->grabbed = 0; /* Free the widget_value objects we used to specify the contents. */ free_menubar_widget_value_tree (first_wv); @@ -926,10 +812,10 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, i += 1; else { - entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); + entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); if (menu_item_selection == i) { - if (keymaps != 0) + if (menuflags & MENU_KEYMAPS) { int j; @@ -940,16 +826,21 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, if (!NILP (subprefix_stack[j])) entry = Fcons (subprefix_stack[j], entry); } + unblock_input (); return entry; } i += MENU_ITEMS_ITEM_LENGTH; } } } - else if (!for_click) - /* Make "Cancel" equivalent to C-g. */ - Fsignal (Qquit, Qnil); + else if (!(menuflags & MENU_FOR_CLICK)) + { + unblock_input (); + /* Make "Cancel" equivalent to C-g. */ + Fsignal (Qquit, Qnil); + } + unblock_input (); return Qnil; } @@ -983,9 +874,8 @@ static char * button_names [] = { "button6", "button7", "button8", "button9", "button10" }; static Lisp_Object -w32_dialog_show (FRAME_PTR f, int keymaps, - Lisp_Object title, Lisp_Object header, - char **error) +w32_dialog_show (struct frame *f, Lisp_Object title, + Lisp_Object header, char **error) { int i, nb_buttons = 0; char dialog_name[6]; @@ -1009,19 +899,12 @@ w32_dialog_show (FRAME_PTR f, int keymaps, /* Create a tree of widget_value objects representing the text label and buttons. */ { - Lisp_Object pane_name, prefix; + Lisp_Object pane_name; char *pane_string; pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME); - prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX); pane_string = (NILP (pane_name) ? "" : SSDATA (pane_name)); - prev_wv = xmalloc_widget_value (); - prev_wv->value = pane_string; - if (keymaps && !NILP (prefix)) - prev_wv->name++; - prev_wv->enabled = 1; - prev_wv->name = "message"; - prev_wv->help = Qnil; + prev_wv = make_widget_value ("message", pane_string, true, Qnil); first_wv = prev_wv; /* Loop over all panes and items, filling in the tree. */ @@ -1058,15 +941,13 @@ w32_dialog_show (FRAME_PTR f, int keymaps, return Qnil; } - wv = xmalloc_widget_value (); + wv = make_widget_value (button_names[nb_buttons], + SSDATA (item_name), + !NILP (enable), Qnil); prev_wv->next = wv; - wv->name = (char *) button_names[nb_buttons]; if (!NILP (descrip)) wv->key = SSDATA (descrip); - wv->value = SSDATA (item_name); wv->call_data = aref_addr (menu_items, i); - wv->enabled = !NILP (enable); - wv->help = Qnil; prev_wv = wv; if (! boundary_seen) @@ -1081,9 +962,7 @@ w32_dialog_show (FRAME_PTR f, int keymaps, if (! boundary_seen) left_count = nb_buttons - nb_buttons / 2; - wv = xmalloc_widget_value (); - wv->name = dialog_name; - wv->help = Qnil; + wv = make_widget_value (dialog_name, NULL, false, Qnil); /* Frame title: 'Q' = Question, 'I' = Information. Can also have 'E' = Error if, one day, we want @@ -1123,7 +1002,7 @@ w32_dialog_show (FRAME_PTR f, int keymaps, lw_pop_up_all_widgets (dialog_id); /* Process events that apply to the menu. */ - popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id); + popup_get_selection ((XEvent *) 0, FRAME_DISPLAY_INFO (f), dialog_id); lw_destroy_all_widgets (dialog_id); @@ -1131,32 +1010,18 @@ w32_dialog_show (FRAME_PTR f, int keymaps, the proper value. */ if (menu_item_selection != 0) { - Lisp_Object prefix; - - prefix = Qnil; i = 0; while (i < menu_items_used) { Lisp_Object entry; if (EQ (AREF (menu_items, i), Qt)) - { - prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); - i += MENU_ITEMS_PANE_LENGTH; - } + i += MENU_ITEMS_PANE_LENGTH; else { - entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); + entry = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); if (menu_item_selection == i) - { - if (keymaps != 0) - { - entry = Fcons (entry, Qnil); - if (!NILP (prefix)) - entry = Fcons (prefix, entry); - } - return entry; - } + return entry; i += MENU_ITEMS_ITEM_LENGTH; } } @@ -1219,7 +1084,7 @@ is_simple_dialog (Lisp_Object contents) } static Lisp_Object -simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header) +simple_dialog_show (struct frame *f, Lisp_Object contents, Lisp_Object header) { int answer; UINT type; @@ -1234,7 +1099,8 @@ simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header) /* Use Unicode if possible, so any language can be displayed. */ if (unicode_message_box) { - WCHAR *text, *title; + WCHAR *text; + const WCHAR *title; USE_SAFE_ALLOCA; if (STRINGP (temp)) @@ -1269,7 +1135,7 @@ simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header) } else { - char *text, *title; + const char *text, *title; /* Fall back on ANSI message box, but at least use system encoding so questions representable by the system codepage @@ -1690,36 +1556,28 @@ w32_free_menu_strings (HWND hwnd) current_popup_menu = NULL; } -#endif /* HAVE_MENUS */ - /* The following is used by delayed window autoselection. */ DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0, doc: /* Return t if a menu or popup dialog is active on selected frame. */) (void) { -#ifdef HAVE_MENUS - FRAME_PTR f; + struct frame *f; f = SELECTED_FRAME (); return (f->output_data.w32->menubar_active > 0) ? Qt : Qnil; -#else - return Qnil; -#endif /* HAVE_MENUS */ } void syms_of_w32menu (void) { +#include "w32menu.x" + globals_of_w32menu (); current_popup_menu = NULL; DEFSYM (Qdebug_on_next_call, "debug-on-next-call"); - - defsubr (&Smenu_or_popup_active_p); -#ifdef HAVE_MENUS - defsubr (&Sx_popup_dialog); -#endif + DEFSYM (Qunsupported__w32_dialog, "unsupported--w32-dialog"); } /*