/* Menu support for GNU Emacs on the Microsoft Windows API.
- Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2015 Free
+ Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2016 Free
Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "lisp.h"
#include "keyboard.h"
-#include "keymap.h"
#include "frame.h"
-#include "termhooks.h"
-#include "window.h"
#include "blockinput.h"
-#include "character.h"
#include "buffer.h"
-#include "charset.h"
-#include "coding.h"
+#include "coding.h" /* for ENCODE_SYSTEM */
#include "menu.h"
/* This may include sys/types.h, and that somehow loses
#include <sys/types.h>
#endif
-#include "dispextern.h"
-
#include "w32common.h" /* for osinfo_cache */
#undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
MessageBoxW_Proc unicode_message_box = NULL;
#endif /* NTGUI_UNICODE */
-Lisp_Object Qdebug_on_next_call, Qunsupported__w32_dialog;
-
void set_frame_menubar (struct frame *, bool, bool);
#ifdef HAVE_DIALOGS
-static Lisp_Object w32_dialog_show (struct frame *, 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 bool is_simple_dialog (Lisp_Object);
static Lisp_Object simple_dialog_show (struct frame *, Lisp_Object, Lisp_Object);
#endif
/* Display them in a dialog box. */
block_input ();
- selection = w32_dialog_show (f, 0, title, header, &error_name);
+ selection = w32_dialog_show (f, title, header, &error_name);
unblock_input ();
discard_menu_items ();
void
x_activate_menubar (struct frame *f)
{
- set_frame_menubar (f, 0, 1);
+ set_frame_menubar (f, false, true);
/* Lock out further menubar changes while active. */
f->output_data.w32->menubar_active = 1;
else
{
entry = AREF (vector, i + MENU_ITEMS_ITEM_VALUE);
- /* The EMACS_INT cast avoids a warning. There's no problem
+ /* The UINT_PTR cast avoids a warning. There's no problem
as long as pointers have enough bits to hold small integers. */
- if ((int) (EMACS_INT) client_data == i)
+ if ((int) (UINT_PTR) client_data == i)
{
int j;
struct input_event buf;
XSETFRAME (Vmenu_updating_frame, f);
if (! menubar_widget)
- deep_p = 1;
+ deep_p = true;
if (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)
else
first_wv->contents = wv;
/* Don't set wv->name here; GC during the loop might relocate it. */
- wv->enabled = 1;
+ wv->enabled = true;
wv->button_type = BUTTON_TYPE_NONE;
prev_wv = wv;
}
/* 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);
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.
/* 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_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1);
+ {
+ windows_or_buffers_changed = 23;
+ adjust_frame_size (f, -1, -1, 2, false, Qmenu_bar_lines);
+ }
}
unblock_input ();
/* This function is called before the first chance to redisplay
the frame. It has to be, so the frame will have the right size. */
fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
- set_frame_menubar (f, 1, 1);
+ set_frame_menubar (f, true, true);
}
/* Get rid of the menu bar of frame F, and free its storage.
/* 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.
(We return nil on failure, but the value doesn't actually matter.) */
Lisp_Object
-w32_menu_show (struct frame *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;
Lisp_Object *subprefix_stack
= (Lisp_Object *) alloca (menu_items_used * word_size);
int submenu_depth = 0;
- int first_pane;
+ bool first_pane;
*error = NULL;
/* 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;
+ first_pane = true;
/* Loop over all panes and items, filling in the tree. */
i = 0;
submenu_stack[submenu_depth++] = save_wv;
save_wv = prev_wv;
prev_wv = 0;
- first_pane = 1;
+ first_pane = false;
i++;
}
else if (EQ (AREF (menu_items, i), Qlambda))
{
prev_wv = save_wv;
save_wv = submenu_stack[--submenu_depth];
- first_pane = 0;
+ first_pane = false;
i++;
}
else if (EQ (AREF (menu_items, i), Qt)
/* 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;
}
save_wv = wv;
prev_wv = 0;
}
- first_pane = 0;
+ first_pane = false;
i += MENU_ITEMS_PANE_LENGTH;
}
else
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);
+ wv->call_data = !NILP (def) ? (void *) (UINT_PTR) i : 0;
if (NILP (type))
wv->button_type = BUTTON_TYPE_NONE;
wv->selected = !NILP (selected);
- if (!STRINGP (help))
- help = Qnil;
-
- wv->help = help;
-
prev_wv = wv;
i += MENU_ITEMS_ITEM_LENGTH;
/* 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;
}
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;
}
}
}
- else if (!for_click)
+ else if (!(menuflags & MENU_FOR_CLICK))
{
unblock_input ();
/* Make "Cancel" equivalent to C-g. */
"button6", "button7", "button8", "button9", "button10" };
static Lisp_Object
-w32_dialog_show (struct frame *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];
/* Number of elements seen so far, before boundary. */
int left_count = 0;
- /* 1 means we've seen the boundary between left-hand elts and right-hand. */
- int boundary_seen = 0;
+ /* true means we've seen the boundary between left-hand elts and
+ right-hand. */
+ bool boundary_seen = false;
*error = NULL;
/* 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. */
{
/* This is the boundary between left-side elts
and right-side elts. Stop incrementing right_count. */
- boundary_seen = 1;
+ boundary_seen = true;
i++;
continue;
}
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)
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
/* Actually create the dialog. */
dialog_id = widget_id_tick++;
menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
- f->output_data.w32->widget, 1, 0,
+ f->output_data.w32->widget, true, 0,
dialog_selection_callback, 0);
lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
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;
}
}
anywhere in Emacs that uses the other specific dialog choices that
MessageBox provides. */
-static int
+static bool
is_simple_dialog (Lisp_Object contents)
{
Lisp_Object options;
Lisp_Object name, yes, no, other;
if (!CONSP (contents))
- return 0;
+ return false;
options = XCDR (contents);
yes = build_string ("Yes");
no = build_string ("No");
if (!CONSP (options))
- return 0;
+ return false;
name = XCAR (options);
if (!CONSP (name))
- return 0;
+ return false;
name = XCAR (name);
if (!NILP (Fstring_equal (name, yes)))
else if (!NILP (Fstring_equal (name, no)))
other = yes;
else
- return 0;
+ return false;
options = XCDR (options);
if (!CONSP (options))
- return 0;
+ return false;
name = XCAR (options);
if (!CONSP (name))
- return 0;
+ return false;
name = XCAR (name);
if (NILP (Fstring_equal (name, other)))
- return 0;
+ return false;
/* Check there are no more options. */
options = XCDR (options);
if (STRINGP (temp))
{
- char *utf8_text = SDATA (ENCODE_UTF_8 (temp));
+ char *utf8_text = SSDATA (ENCODE_UTF_8 (temp));
/* Be pessimistic about the number of characters needed.
Remember characters outside the BMP will take more than
one utf16 word, so we cannot simply use the character
length of temp. */
int utf8_len = strlen (utf8_text);
text = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
- utf8to16 (utf8_text, utf8_len, text);
+ utf8to16 ((unsigned char *)utf8_text, utf8_len, text);
}
else
{
encoding so questions representable by the system codepage
are encoded properly. */
if (STRINGP (temp))
- text = SDATA (ENCODE_SYSTEM (temp));
+ text = SSDATA (ENCODE_SYSTEM (temp));
else
text = "";
if (wv->key != NULL)
{
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);
+ p = stpcpy (out_string, wv->name);
+ p = stpcpy (p, "\t");
+ strcpy (p, wv->key);
}
else
out_string = (char *)wv->name;
else
utf16_string = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
- utf8to16 (out_string, utf8_len, utf16_string);
+ utf8to16 ((unsigned char *)out_string, utf8_len, utf16_string);
return_value = unicode_append_menu (menu, fuFlags,
item != NULL ? (UINT_PTR) item
: (UINT_PTR) wv->call_data,
info.cbSize = sizeof (info);
info.fMask = MIIM_DATA;
- /* Set help string for menu item. Leave it as a Lisp_Object
- until it is ready to be displayed, since GC can happen while
- menus are active. */
+ /* Set help string for menu item. Leave it as a pointer to
+ a Lisp_String until it is ready to be displayed, since GC
+ can happen while menus are active. */
if (!NILP (wv->help))
{
+ /* We use XUNTAG below because in a 32-bit build
+ --with-wide-int we cannot pass a Lisp_Object
+ via a DWORD member of MENUITEMINFO. */
/* 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);
+ eassert (STRINGP (wv->help));
+ info.dwItemData = (ULONG_PTR) XUNTAG (wv->help, Lisp_String);
}
if (wv->button_type == BUTTON_TYPE_RADIO)
{
struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
Lisp_Object frame, help;
- /* No help echo on owner-draw menu items, or when the keyboard is used
- to navigate the menus, since tooltips are distracting if they pop
- up elsewhere. */
- if (flags & MF_OWNERDRAW || flags & MF_POPUP
- || !(flags & MF_MOUSESELECT))
+ /* No help echo on owner-draw menu items, or when the keyboard
+ is used to navigate the menus, since tooltips are distracting
+ if they pop up elsewhere. */
+ if ((flags & MF_OWNERDRAW) || (flags & MF_POPUP)
+ || !(flags & MF_MOUSESELECT)
+ /* Ignore any dwItemData for menu items whose flags don't
+ have the MF_HILITE bit set. These are dwItemData that
+ Windows sends our way, but they aren't pointers to our
+ Lisp_String objects, so trying to create Lisp_Strings out
+ of them below and pass that to the keyboard queue will
+ crash Emacs when we try to display those "strings". It
+ is unclear why we get these dwItemData, or what they are:
+ sometimes they point to a wchar_t string that is the menu
+ title, sometimes to someting that doesn't look like text
+ at all. (The problematic data also comes with the 0x0800
+ bit set, but this bit is not documented, so we don't want
+ to depend on it.) */
+ || !(flags & MF_HILITE))
help = Qnil;
else
{
info.fMask = MIIM_DATA;
get_menu_item_info (menu, item, FALSE, &info);
- help = info.dwItemData ? XIL (info.dwItemData) : Qnil;
+ help =
+ info.dwItemData
+ ? make_lisp_ptr ((void *) info.dwItemData, Lisp_String)
+ : Qnil;
}
/* Store the help echo in the keyboard buffer as the X toolkit