/* 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, 2008
+ 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 <signal.h>
#include <stdio.h>
+#include <mbstring.h>
+
#include "lisp.h"
-#include "termhooks.h"
#include "keyboard.h"
#include "keymap.h"
#include "frame.h"
+#include "termhooks.h"
#include "window.h"
#include "blockinput.h"
#include "buffer.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
static void
grow_menu_items ()
{
- Lisp_Object old;
- int old_size = menu_items_allocated;
- old = menu_items;
-
menu_items_allocated *= 2;
- menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
- bcopy (XVECTOR (old)->contents, XVECTOR (menu_items)->contents,
- old_size * sizeof (Lisp_Object));
+ menu_items = larger_vector (menu_items, menu_items_allocated, Qnil);
}
/* Begin a submenu. */
init_menu_items ();
- for (tail = menu; !NILP (tail); tail = Fcdr (tail))
+ for (tail = menu; CONSP (tail); tail = XCDR (tail))
{
Lisp_Object elt, pane_name, pane_data;
- elt = Fcar (tail);
+ elt = XCAR (tail);
pane_name = Fcar (elt);
CHECK_STRING (pane_name);
push_menu_pane (pane_name, Qnil);
{
Lisp_Object tail, item, item1;
- for (tail = pane; !NILP (tail); tail = Fcdr (tail))
+ for (tail = pane; CONSP (tail); tail = XCDR (tail))
{
- item = Fcar (tail);
+ item = XCAR (tail);
if (STRINGP (item))
push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
else if (NILP (item))
enum scroll_bar_part part;
unsigned long time;
- if (mouse_position_hook)
- (*mouse_position_hook) (&new_f, 1, &bar_window,
+ if (FRAME_TERMINAL (new_f)->mouse_position_hook)
+ (*FRAME_TERMINAL (new_f)->mouse_position_hook) (&new_f, 1, &bar_window,
&part, &x, &y, &time);
if (new_f != 0)
XSETFRAME (window, new_f);
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;
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;
}
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;
}
/* 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