/* Menu support for GNU Emacs on the Microsoft W32 API.
- Copyright (C) 1986,88,93,94,96,98,1999,2003 Free Software Foundation, Inc.
+ Copyright (C) 1986, 1988, 1993, 1994, 1996, 1998, 1999, 2001, 2002,
+ 2003, 2004, 2005, 2006, 2007 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 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include <config.h>
#include <signal.h>
#include <stdio.h>
+#include <mbstring.h>
#include "lisp.h"
#include "termhooks.h"
#include "keyboard.h"
#define FALSE 0
#endif /* no TRUE */
-static HMENU current_popup_menu;
+HMENU current_popup_menu;
void syms_of_w32menu ();
void globals_of_w32menu ();
SetMenuItemInfoA_Proc set_menu_item_info = NULL;
AppendMenuW_Proc unicode_append_menu = NULL;
-Lisp_Object Vmenu_updating_frame;
-
Lisp_Object Qdebug_on_next_call;
+extern Lisp_Object Vmenu_updating_frame;
+
extern Lisp_Object Qmenu_bar;
extern Lisp_Object QCtoggle, QCradio;
/* Current depth within submenus. */
static int menu_items_submenu_depth;
-/* Flag which when set indicates a dialog or menu has been posted by
- Xt on behalf of one of the widget sets. */
-static int popup_activated_flag;
-
static int next_menubar_widget_id;
/* This is set nonzero after the user activates the menu bar, and set
XSETFRAME (Vmenu_updating_frame, f);
}
- Vmenu_updating_frame = Qnil;
+ else
+ Vmenu_updating_frame = Qnil;
#endif /* HAVE_MENUS */
title = Qnil;
}
#ifdef HAVE_MENUS
- /* If resources from a previous popup menu exist yet, does nothing
- until the `menu_free_timer' has freed them (see w32fns.c).
+ /* If resources from a previous popup menu still exist, does nothing
+ until the `menu_free_timer' has freed them (see w32fns.c). This
+ can occur if you press ESC or click outside a menu without selecting
+ a menu item.
*/
if (current_popup_menu)
{
UNBLOCK_INPUT;
discard_menu_items ();
+
#endif /* HAVE_MENUS */
UNGCPRO;
#ifdef HAVE_MENUS
-DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
+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.
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.) */)
- (position, contents)
- Lisp_Object position, contents;
+\(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". */)
+ (position, contents, header)
+ Lisp_Object position, contents, header;
{
FRAME_PTR f = NULL;
Lisp_Object window;
/* Display them in a dialog box. */
BLOCK_INPUT;
- selection = w32_dialog_show (f, 0, title, &error_name);
+ selection = w32_dialog_show (f, 0, title, header, &error_name);
UNBLOCK_INPUT;
discard_menu_items ();
buf.kind = MENU_BAR_EVENT;
buf.frame_or_window = frame;
buf.arg = entry;
- kbd_buffer_store_event (&buf);
-
/* Free memory used by owner-drawn and help-echo strings. */
w32_free_menu_strings (FRAME_W32_WINDOW (f));
- f->output_data.w32->menu_command_in_progress = 0;
+ kbd_buffer_store_event (&buf);
+
f->output_data.w32->menubar_active = 0;
return;
}
}
/* Free memory used by owner-drawn and help-echo strings. */
w32_free_menu_strings (FRAME_W32_WINDOW (f));
- f->output_data.w32->menu_command_in_progress = 0;
f->output_data.w32->menubar_active = 0;
}
because it is not reentrant. */
specbind (Qdebug_on_next_call, Qnil);
- record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ record_unwind_save_match_data ();
+
if (NILP (Voverriding_local_map_menu_flag))
{
specbind (Qoverriding_terminal_local_map, Qnil);
DestroyMenu (menu);
+ /* Free the owner-drawn and help-echo menu strings. */
+ w32_free_menu_strings (FRAME_W32_WINDOW (f));
+ f->output_data.w32->menubar_active = 0;
+
/* Find the selected item, and its pane, to return
the proper value. */
if (menu_item_selection != 0)
}
}
}
+ else if (!for_click)
+ /* Make "Cancel" equivalent to C-g. */
+ Fsignal (Qquit, Qnil);
return Qnil;
}
"button6", "button7", "button8", "button9", "button10" };
static Lisp_Object
-w32_dialog_show (f, keymaps, title, error)
+w32_dialog_show (f, keymaps, title, header, error)
FRAME_PTR f;
int keymaps;
- Lisp_Object title;
+ Lisp_Object title, header;
char **error;
{
int i, nb_buttons=0;
wv->name = dialog_name;
wv->help = Qnil;
+ /* Frame title: 'Q' = Question, 'I' = Information.
+ Can also have 'E' = Error if, one day, we want
+ a popup for errors. */
+ if (NILP(header))
+ dialog_name[0] = 'Q';
+ else
+ dialog_name[0] = 'I';
+
/* Dialog boxes use a really stupid name encoding
which specifies how many buttons to use
- and how many buttons are on the right.
- The Q means something also. */
- dialog_name[0] = 'Q';
+ and how many buttons are on the right. */
dialog_name[1] = '0' + nb_buttons;
dialog_name[2] = 'B';
dialog_name[3] = 'R';
/* Display the menu. */
lw_pop_up_all_widgets (dialog_id);
- popup_activated_flag = 1;
/* Process events that apply to the menu. */
popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id);
}
}
}
+ else
+ /* Make "Cancel" equivalent to C-g. */
+ Fsignal (Qquit, Qnil);
return Qnil;
}
add_menu_item (HMENU menu, widget_value *wv, HMENU item)
{
UINT fuFlags;
- char *out_string;
+ char *out_string, *p, *q;
int return_value;
+ size_t nlen, orig_len;
if (name_is_separator (wv->name))
{
else
out_string = wv->name;
+ /* Quote any special characters within the menu item's text and
+ key binding. */
+ nlen = orig_len = strlen (out_string);
+ if (unicode_append_menu)
+ {
+ /* With UTF-8, & cannot be part of a multibyte character. */
+ for (p = out_string; *p; p++)
+ {
+ if (*p == '&')
+ nlen++;
+ }
+ }
+ else
+ {
+ /* If encoded with the system codepage, use multibyte string
+ functions in case of multibyte characters that contain '&'. */
+ for (p = out_string; *p; p = _mbsinc (p))
+ {
+ if (_mbsnextc (p) == '&')
+ nlen++;
+ }
+ }
+
+ if (nlen > orig_len)
+ {
+ p = out_string;
+ out_string = alloca (nlen + 1);
+ q = out_string;
+ while (*p)
+ {
+ if (unicode_append_menu)
+ {
+ if (*p == '&')
+ *q++ = *p;
+ *q++ = *p++;
+ }
+ else
+ {
+ if (_mbsnextc (p) == '&')
+ {
+ _mbsncpy (q, p, 1);
+ q = _mbsinc (q);
+ }
+ _mbsncpy (q, p, 1);
+ p = _mbsinc (p);
+ q = _mbsinc (q);
+ }
+ }
+ *q = '\0';
+ }
+
if (item != NULL)
fuFlags = MF_POPUP;
else if (wv->title || wv->call_data == 0)
item != NULL ? (UINT) item
: (UINT) wv->call_data,
utf16_string);
- if (fuFlags & MF_OWNERDRAW)
+ if (!return_value)
+ {
+ /* 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
+ happen the first time a menu is used, the encoding is
+ of minor importance compared with menus not working at all. */
+ return_value =
+ AppendMenu (menu, fuFlags,
+ item != NULL ? (UINT) item: (UINT) wv->call_data,
+ out_string);
+ /* Don't use unicode menus in future. */
+ unicode_append_menu = NULL;
+ }
+
+ if (unicode_append_menu && (fuFlags & MF_OWNERDRAW))
local_free (out_string);
}
else
return 1;
}
-int
-popup_activated ()
-{
- /* popup_activated_flag not actually used on W32 */
- return 0;
-}
-
/* Display help string for currently pointed to menu item. Not
supported on NT 3.51 and earlier, as GetMenuItemInfo is not
available. */
struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
Lisp_Object frame, help;
- /* No help echo on owner-draw menu items. */
- if (flags & MF_OWNERDRAW || flags & MF_POPUP)
+ /* 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))
help = Qnil;
else
{
#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. */)
+ ()
+{
+#ifdef HAVE_MENUS
+ FRAME_PTR f;
+ f = SELECTED_FRAME ();
+ return (f->output_data.w32->menubar_active > 0) ? Qt : Qnil;
+#else
+ return Qnil;
+#endif /* HAVE_MENUS */
+}
+
void syms_of_w32menu ()
{
globals_of_w32menu ();
Qdebug_on_next_call = intern ("debug-on-next-call");
staticpro (&Qdebug_on_next_call);
- DEFVAR_LISP ("menu-updating-frame", &Vmenu_updating_frame,
- doc: /* Frame for which we are updating a menu.
-The enable predicate for a menu command should check this variable. */);
- Vmenu_updating_frame = Qnil;
-
defsubr (&Sx_popup_menu);
+ defsubr (&Smenu_or_popup_active_p);
#ifdef HAVE_MENUS
defsubr (&Sx_popup_dialog);
#endif