X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/b5f869a7d838121b17493ad66958309c0d6031e5..b97f22cdad55a0964758cef3a19ce3fa1098657d:/src/w32menu.c diff --git a/src/w32menu.c b/src/w32menu.c index c8c6a319b4..36bf9574fd 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -1,5 +1,5 @@ -/* Menu support for GNU Emacs on the Microsoft W32 API. - Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2011 +/* Menu support for GNU Emacs on the Microsoft Windows API. + Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2012 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -21,7 +21,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include #include "lisp.h" @@ -31,9 +30,9 @@ along with GNU Emacs. If not, see . */ #include "termhooks.h" #include "window.h" #include "blockinput.h" +#include "character.h" #include "buffer.h" #include "charset.h" -#include "character.h" #include "coding.h" #include "menu.h" @@ -41,6 +40,14 @@ along with GNU Emacs. If not, see . */ if this is not done before the other system files. */ #include "w32term.h" +/* Cygwin does not support the multibyte string functions declared in + * mbstring.h below --- but that's okay: because Cygwin is + * UNICODE-only, we don't need to use these functions anyway. */ + +#ifndef NTGUI_UNICODE +#include +#endif /* !NTGUI_UNICODE */ + /* Load sys/types.h if not already loaded. In some systems loading it twice is suicidal. */ #ifndef makedev @@ -49,6 +56,8 @@ along with GNU Emacs. If not, see . */ #include "dispextern.h" +#include "w32common.h" /* for osinfo_cache */ + #undef HAVE_DIALOGS /* TODO: Implement native dialogs. */ #ifndef TRUE @@ -77,14 +86,21 @@ typedef int (WINAPI * MessageBoxW_Proc) ( IN WCHAR *caption, IN UINT type); +#ifdef NTGUI_UNICODE +#define get_menu_item_info GetMenuItemInfoA +#define set_menu_item_info SetMenuItemInfoA +#define unicode_append_menu AppendMenuW +#define unicode_message_box MessageBoxW +#else /* !NTGUI_UNICODE */ GetMenuItemInfoA_Proc get_menu_item_info = NULL; SetMenuItemInfoA_Proc set_menu_item_info = NULL; AppendMenuW_Proc unicode_append_menu = NULL; MessageBoxW_Proc unicode_message_box = NULL; +#endif /* NTGUI_UNICODE */ Lisp_Object Qdebug_on_next_call; -void set_frame_menubar (FRAME_PTR, int, int); +void set_frame_menubar (FRAME_PTR, bool, bool); #ifdef HAVE_DIALOGS static Lisp_Object w32_dialog_show (FRAME_PTR, int, Lisp_Object, char**); @@ -97,6 +113,7 @@ static void utf8to16 (unsigned char *, int, WCHAR *); static int fill_in_menu (HMENU, widget_value *); void w32_free_menu_strings (HWND); + /* This is set nonzero after the user activates the menu bar, and set @@ -146,7 +163,7 @@ otherwise it is "Question". */) FRAME_PTR new_f = SELECTED_FRAME (); Lisp_Object bar_window; enum scroll_bar_part part; - unsigned long time; + Time time; Lisp_Object x, y; (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time); @@ -160,13 +177,12 @@ otherwise it is "Question". */) } else if (CONSP (position)) { - Lisp_Object tem; - tem = Fcar (position); + Lisp_Object tem = XCAR (position); if (CONSP (tem)) - window = Fcar (Fcdr (position)); + window = Fcar (XCDR (position)); else { - tem = Fcar (Fcdr (position)); /* EVENT_START (position) */ + tem = Fcar (XCDR (position)); /* EVENT_START (position) */ window = Fcar (tem); /* POSN_WINDOW (tem) */ } } @@ -221,9 +237,9 @@ otherwise it is "Question". */) list_of_panes (Fcons (contents, Qnil)); /* Display them in a dialog box. */ - BLOCK_INPUT; + block_input (); selection = w32_dialog_show (f, 0, title, header, &error_name); - UNBLOCK_INPUT; + unblock_input (); discard_menu_items (); FRAME_X_DISPLAY_INFO (f)->grabbed = 0; @@ -275,7 +291,7 @@ menubar_selection_callback (FRAME_PTR f, void * client_data) if (!f) return; entry = Qnil; - subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object)); + subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * word_size); vector = f->menu_bar_vector; prefix = Qnil; i = 0; @@ -356,7 +372,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, int first_time, int deep_p) +set_frame_menubar (FRAME_PTR f, bool first_time, bool deep_p) { HMENU menubar_widget = f->output_data.w32->menubar_widget; Lisp_Object items; @@ -382,11 +398,11 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) struct buffer *prev = current_buffer; Lisp_Object buffer; - int specpdl_count = SPECPDL_INDEX (); + ptrdiff_t specpdl_count = SPECPDL_INDEX (); int previous_menu_items_used = f->menu_bar_items_used; Lisp_Object *previous_items = (Lisp_Object *) alloca (previous_menu_items_used - * sizeof (Lisp_Object)); + * word_size); /* If we are making a new widget, its contents are empty, do always reinitialize them. */ @@ -412,14 +428,14 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) /* Run the hooks. */ safe_run_hooks (Qactivate_menubar_hook); safe_run_hooks (Qmenu_bar_update_hook); - FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); + fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f))); items = FRAME_MENU_BAR_ITEMS (f); /* Save the frame's previous menu bar contents data. */ if (previous_menu_items_used) memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents, - previous_menu_items_used * sizeof (Lisp_Object)); + previous_menu_items_used * word_size); /* Fill in menu_items with the current menu bar contents. This can evaluate Lisp code. */ @@ -427,11 +443,10 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) menu_items = f->menu_bar_vector; menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0; - submenu_start = (int *) alloca (ASIZE (items) * sizeof (int *)); - submenu_end = (int *) alloca (ASIZE (items) * sizeof (int *)); + submenu_start = (int *) alloca (ASIZE (items) * sizeof (int)); + submenu_end = (int *) alloca (ASIZE (items) * sizeof (int)); submenu_n_panes = (int *) alloca (ASIZE (items) * sizeof (int)); - submenu_top_level_items - = (int *) alloca (ASIZE (items) * sizeof (int *)); + submenu_top_level_items = (int *) alloca (ASIZE (items) * sizeof (int)); init_menu_items (); for (i = 0; i < ASIZE (items); i += 4) { @@ -500,7 +515,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) return; } - f->menu_bar_vector = menu_items; + fset_menu_bar_vector (f, menu_items); f->menu_bar_items_used = menu_items_used; /* This undoes save_menu_items. */ @@ -572,7 +587,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) /* Create or update the menu bar widget. */ - BLOCK_INPUT; + block_input (); if (menubar_widget) { @@ -602,7 +617,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f)); } - UNBLOCK_INPUT; + unblock_input (); } /* Called from Fx_create_frame to create the initial menubar of a frame @@ -615,7 +630,7 @@ initialize_frame_menubar (FRAME_PTR 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. */ - FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f)); + fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f))); set_frame_menubar (f, 1, 1); } @@ -625,7 +640,7 @@ initialize_frame_menubar (FRAME_PTR f) void free_frame_menubar (FRAME_PTR f) { - BLOCK_INPUT; + block_input (); { HMENU old = GetMenu (FRAME_W32_WINDOW (f)); @@ -634,7 +649,7 @@ free_frame_menubar (FRAME_PTR f) DestroyMenu (old); } - UNBLOCK_INPUT; + unblock_input (); } @@ -665,7 +680,7 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, widget_value **submenu_stack = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); Lisp_Object *subprefix_stack - = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); + = (Lisp_Object *) alloca (menu_items_used * word_size); int submenu_depth = 0; int first_pane; @@ -820,7 +835,7 @@ w32_menu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, else if (EQ (type, QCradio)) wv->button_type = BUTTON_TYPE_RADIO; else - abort (); + emacs_abort (); wv->selected = !NILP (selected); @@ -1062,7 +1077,7 @@ w32_dialog_show (FRAME_PTR f, int keymaps, if (!NILP (descrip)) wv->key = SSDATA (descrip); wv->value = SSDATA (item_name); - wv->call_data = (void *) &AREF (menu_items, i); + wv->call_data = aref_addr (menu_items, i); wv->enabled = !NILP (enable); wv->help = Qnil; prev_wv = wv; @@ -1175,18 +1190,23 @@ w32_dialog_show (FRAME_PTR f, int keymaps, static int is_simple_dialog (Lisp_Object contents) { - Lisp_Object options = XCDR (contents); + Lisp_Object options; Lisp_Object name, yes, no, other; + if (!CONSP (contents)) + return 0; + options = XCDR (contents); + yes = build_string ("Yes"); no = build_string ("No"); if (!CONSP (options)) return 0; - name = XCAR (XCAR (options)); - if (!CONSP (options)) + name = XCAR (options); + if (!CONSP (name)) return 0; + name = XCAR (name); if (!NILP (Fstring_equal (name, yes))) other = no; @@ -1199,7 +1219,10 @@ is_simple_dialog (Lisp_Object contents) if (!CONSP (options)) return 0; - name = XCAR (XCAR (options)); + name = XCAR (options); + if (!CONSP (name)) + return 0; + name = XCAR (name); if (NILP (Fstring_equal (name, other))) return 0; @@ -1221,10 +1244,11 @@ simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header) is_simple_dialog, we don't need to worry about checking contents to see what type of dialog to use. */ - /* Use unicode if possible, so any language can be displayed. */ + /* Use Unicode if possible, so any language can be displayed. */ if (unicode_message_box) { WCHAR *text, *title; + USE_SAFE_ALLOCA; if (STRINGP (temp)) { @@ -1234,7 +1258,7 @@ simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header) one utf16 word, so we cannot simply use the character length of temp. */ int utf8_len = strlen (utf8_text); - text = alloca ((utf8_len + 1) * sizeof (WCHAR)); + text = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR)); utf8to16 (utf8_text, utf8_len, text); } else @@ -1254,6 +1278,7 @@ simple_dialog_show (FRAME_PTR f, Lisp_Object contents, Lisp_Object header) } answer = unicode_message_box (FRAME_W32_WINDOW (f), text, title, type); + SAFE_FREE (); } else { @@ -1360,6 +1385,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) char *out_string, *p, *q; int return_value; size_t nlen, orig_len; + USE_SAFE_ALLOCA; if (menu_separator_name_p (wv->name)) { @@ -1375,7 +1401,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) if (wv->key != NULL) { - out_string = alloca (strlen (wv->name) + strlen (wv->key) + 2); + out_string = SAFE_ALLOCA (strlen (wv->name) + strlen (wv->key) + 2); strcpy (out_string, wv->name); strcat (out_string, "\t"); strcat (out_string, wv->key); @@ -1395,6 +1421,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) nlen++; } } +#ifndef NTGUI_UNICODE else { /* If encoded with the system codepage, use multibyte string @@ -1405,11 +1432,12 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) nlen++; } } +#endif /* !NTGUI_UNICODE */ if (nlen > orig_len) { p = out_string; - out_string = alloca (nlen + 1); + out_string = SAFE_ALLOCA (nlen + 1); q = out_string; while (*p) { @@ -1419,6 +1447,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) *q++ = *p; *q++ = *p++; } +#ifndef NTGUI_UNICODE else { if (_mbsnextc (p) == '&') @@ -1430,6 +1459,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) p = _mbsinc (p); q = _mbsinc (q); } +#endif /* !NTGUI_UNICODE */ } *q = '\0'; } @@ -1445,7 +1475,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) out_string = (char *) local_alloc (strlen (wv->name) + 1); strcpy (out_string, wv->name); #ifdef MENU_DEBUG - DebPrint ("Menu: allocing %ld for owner-draw", out_string); + DebPrint ("Menu: allocating %ld for owner-draw", out_string); #endif fuFlags = MF_OWNERDRAW | MF_DISABLED; } @@ -1469,16 +1499,18 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) if (fuFlags & MF_OWNERDRAW) utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR)); else - utf16_string = alloca ((utf8_len + 1) * sizeof (WCHAR)); + utf16_string = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR)); utf8to16 (out_string, utf8_len, utf16_string); return_value = unicode_append_menu (menu, fuFlags, - item != NULL ? (UINT) item - : (UINT) wv->call_data, + item != NULL ? (UINT_PTR) item + : (UINT_PTR) wv->call_data, utf16_string); + +#ifndef NTGUI_UNICODE /* Fallback does not apply when always UNICODE */ if (!return_value) { - /* On W9x/ME, unicode menus are not supported, though AppendMenuW + /* On W9x/ME, Unicode menus are not supported, though AppendMenuW apparently does exist at least in some cases and appears to be stubbed out to do nothing. out_string is UTF-8, but since our standard menus are in English and this is only going to @@ -1486,11 +1518,15 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) of minor importance compared with menus not working at all. */ return_value = AppendMenu (menu, fuFlags, - item != NULL ? (UINT) item: (UINT) wv->call_data, + item != NULL ? (UINT_PTR) item: (UINT_PTR) wv->call_data, out_string); - /* Don't use unicode menus in future. */ - unicode_append_menu = NULL; + /* Don't use Unicode menus in future, unless this is Windows + NT or later, where a failure of AppendMenuW does NOT mean + Unicode menus are unsupported. */ + if (osinfo_cache.dwPlatformId != VER_PLATFORM_WIN32_NT) + unicode_append_menu = NULL; } +#endif /* NTGUI_UNICODE */ if (unicode_append_menu && (fuFlags & MF_OWNERDRAW)) local_free (out_string); @@ -1500,7 +1536,7 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) return_value = AppendMenu (menu, fuFlags, - item != NULL ? (UINT) item : (UINT) wv->call_data, + item != NULL ? (UINT_PTR) item : (UINT_PTR) wv->call_data, out_string ); } @@ -1518,11 +1554,14 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) until it is ready to be displayed, since GC can happen while menus are active. */ if (!NILP (wv->help)) -#ifdef USE_LISP_UNION_TYPE - info.dwItemData = (DWORD) (wv->help).i; -#else - info.dwItemData = (DWORD) (wv->help); -#endif + { + /* As of Jul-2012, w32api headers say that dwItemData + has DWORD type, but that's a bug: it should actually + be ULONG_PTR, which is correct for 32-bit and 64-bit + Windows alike. MSVC headers get it right; hopefully, + MinGW headers will, too. */ + info.dwItemData = (ULONG_PTR) XLI (wv->help); + } if (wv->button_type == BUTTON_TYPE_RADIO) { /* CheckMenuRadioItem allows us to differentiate TOGGLE and @@ -1534,10 +1573,11 @@ add_menu_item (HMENU menu, widget_value *wv, HMENU item) } set_menu_item_info (menu, - item != NULL ? (UINT) item : (UINT) wv->call_data, + item != NULL ? (UINT_PTR) item : (UINT_PTR) wv->call_data, FALSE, &info); } } + SAFE_FREE (); return return_value; } @@ -1596,12 +1636,7 @@ w32_menu_display_help (HWND owner, HMENU menu, UINT item, UINT flags) info.fMask = MIIM_DATA; get_menu_item_info (menu, item, FALSE, &info); -#ifdef USE_LISP_UNION_TYPE - help = info.dwItemData ? (Lisp_Object) ((EMACS_INT) info.dwItemData) - : Qnil; -#else - help = info.dwItemData ? (Lisp_Object) info.dwItemData : Qnil; -#endif + help = info.dwItemData ? XIL (info.dwItemData) : Qnil; } /* Store the help echo in the keyboard buffer as the X toolkit @@ -1711,10 +1746,12 @@ syms_of_w32menu (void) void globals_of_w32menu (void) { +#ifndef NTGUI_UNICODE /* See if Get/SetMenuItemInfo functions are available. */ HMODULE user32 = GetModuleHandle ("user32.dll"); get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA"); set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA"); unicode_append_menu = (AppendMenuW_Proc) GetProcAddress (user32, "AppendMenuW"); unicode_message_box = (MessageBoxW_Proc) GetProcAddress (user32, "MessageBoxW"); +#endif /* !NTGUI_UNICODE */ }