/* 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.
+ Copyright (C) 1986, 1988, 1993-1994, 1996, 1998-1999, 2001-2014 Free
+ Software Foundation, Inc.
This file is part of GNU Emacs.
#include <signal.h>
#include <stdio.h>
-#include <mbstring.h>
#include <setjmp.h>
#include "lisp.h"
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 <mbstring.h>
+#endif /* !NTGUI_UNICODE */
+
/* Load sys/types.h if not already loaded.
In some systems loading it twice is suicidal. */
#ifndef makedev
#include "dispextern.h"
-#include "w32heap.h" /* for osinfo_cache */
+#include "w32common.h" /* for osinfo_cache */
#undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
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
+#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 (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 *, int, 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 *);
static int fill_in_menu (HMENU, widget_value *);
void w32_free_menu_strings (HWND);
-\f
-
-/* This is set nonzero after the user activates the menu bar, and set
- to zero again after the menu bars are redisplayed by prepare_menu_bar.
- While it is nonzero, all calls to set_frame_menubar go deep.
- I don't understand why this is needed, but it does seem to be
- needed on Motif, according to Marcus Daniels <marcus@sysc.pdx.edu>. */
-
-int pending_menu_activation;
-\f
-#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)
+#ifdef HAVE_DIALOGS
+Lisp_Object
+w32_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
{
- FRAME_PTR f = NULL;
- Lisp_Object window;
-
- check_w32 ();
-
- /* 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);
+ Lisp_Object title;
+ char *error_name;
+ Lisp_Object selection;
-#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;
+ check_window_system (f);
- /* 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, 0, 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;
- }
-#endif /* HAVE_DIALOGS */
+ if (error_name) error (error_name);
+ return selection;
}
+#endif /* HAVE_DIALOGS */
/* Activate the menu bar of frame F.
This is called from keyboard.c when it gets the
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);
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;
if (!f)
return;
entry = Qnil;
- subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object));
- vector = FVAR (f, menu_bar_vector);
+ subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * word_size);
+ vector = f->menu_bar_vector;
prefix = Qnil;
i = 0;
while (i < f->menu_bar_items_used)
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 (struct frame *f, bool first_time, bool deep_p)
{
HMENU menubar_widget = f->output_data.w32->menubar_widget;
Lisp_Object items;
if (! menubar_widget)
deep_p = 1;
- else if (pending_menu_activation && !deep_p)
- deep_p = 1;
if (deep_p)
{
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. */
if (! menubar_widget)
previous_menu_items_used = 0;
- buffer = WVAR (XWINDOW (FRAME_SELECTED_WINDOW (f)), buffer);
+ buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents;
specbind (Qinhibit_quit, Qt);
/* Don't let the debugger step into this code
because it is not reentrant. */
/* 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 (FVAR (f, menu_bar_vector))->contents,
- previous_menu_items_used * sizeof (Lisp_Object));
+ memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents,
+ previous_menu_items_used * word_size);
/* Fill in menu_items with the current menu bar contents.
This can evaluate Lisp code. */
save_menu_items ();
- menu_items = FVAR (f, menu_bar_vector);
+ 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));
return;
}
- FVAR (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. */
/* Create or update the menu bar widget. */
- BLOCK_INPUT;
+ block_input ();
if (menubar_widget)
{
/* 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;
+ unblock_input ();
}
/* Called from Fx_create_frame to create the initial menubar of a frame
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. */
- 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);
}
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;
+ block_input ();
{
HMENU old = GetMenu (FRAME_W32_WINDOW (f));
DestroyMenu (old);
}
- UNBLOCK_INPUT;
+ unblock_input ();
}
\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 for_click, int keymaps,
Lisp_Object title, const char **error)
{
int i;
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;
return Qnil;
}
+ block_input ();
+
/* Create a tree of widget_value objects
representing the panes and their items. */
wv = xmalloc_widget_value ();
{
/* 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);
else if (EQ (type, QCradio))
wv->button_type = BUTTON_TYPE_RADIO;
else
- abort ();
+ emacs_abort ();
wv->selected = !NILP (selected);
/* 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);
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);
+ {
+ unblock_input ();
+ /* Make "Cancel" equivalent to C-g. */
+ Fsignal (Qquit, Qnil);
+ }
+ unblock_input ();
return Qnil;
}
\f
"button6", "button7", "button8", "button9", "button10" };
static Lisp_Object
-w32_dialog_show (FRAME_PTR f, int keymaps,
+w32_dialog_show (struct frame *f, int keymaps,
Lisp_Object title, Lisp_Object header,
char **error)
{
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;
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);
}
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;
/* 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))
one utf16 word, so we cannot simply use the character
length of temp. */
int utf8_len = strlen (utf8_text);
- SAFE_ALLOCA (text, WCHAR *, (utf8_len + 1) * sizeof (WCHAR));
+ text = SAFE_ALLOCA ((utf8_len + 1) * sizeof (WCHAR));
utf8to16 (utf8_text, utf8_len, text);
}
else
}
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
if (wv->key != NULL)
{
- SAFE_ALLOCA (out_string, char *,
- 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);
nlen++;
}
}
+#ifndef NTGUI_UNICODE
else
{
/* If encoded with the system codepage, use multibyte string
nlen++;
}
}
+#endif /* !NTGUI_UNICODE */
if (nlen > orig_len)
{
p = out_string;
- SAFE_ALLOCA (out_string, char *, nlen + 1);
+ out_string = SAFE_ALLOCA (nlen + 1);
q = out_string;
while (*p)
{
*q++ = *p;
*q++ = *p++;
}
+#ifndef NTGUI_UNICODE
else
{
if (_mbsnextc (p) == '&')
p = _mbsinc (p);
q = _mbsinc (q);
}
+#endif /* !NTGUI_UNICODE */
}
*q = '\0';
}
if (fuFlags & MF_OWNERDRAW)
utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
else
- SAFE_ALLOCA (utf16_string, WCHAR *, (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
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, unless this is Windows
NT or later, where a failure of AppendMenuW does NOT mean
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);
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 );
}
}
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);
}
}
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
DEFSYM (Qdebug_on_next_call, "debug-on-next-call");
defsubr (&Smenu_or_popup_active_p);
-#ifdef HAVE_MENUS
- defsubr (&Sx_popup_dialog);
-#endif
}
/*
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 */
}