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 "dispextern.h"
-#undef HAVE_MULTILINGUAL_MENU
#undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
/******************************************************************/
typedef struct _widget_value
{
/* name of widget */
+ Lisp_Object lname;
char* name;
/* value (meaning depend on widget type) */
char* value;
/* keyboard equivalent. no implications for XtTranslations */
+ Lisp_Object lkey;
char* key;
/* Help string or nil if none.
GC finds this string through the frame's menu_bar_vector
IN HMENU,
IN UINT,
IN BOOL,
- IN OUT LPMENUITEMINFOA
- );
+ IN OUT LPMENUITEMINFOA);
typedef BOOL (WINAPI * SetMenuItemInfoA_Proc) (
IN HMENU,
IN UINT,
IN BOOL,
- IN LPCMENUITEMINFOA
- );
+ IN LPCMENUITEMINFOA);
-GetMenuItemInfoA_Proc get_menu_item_info=NULL;
-SetMenuItemInfoA_Proc set_menu_item_info=NULL;
+GetMenuItemInfoA_Proc get_menu_item_info = NULL;
+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 Qmenu_bar;
-extern Lisp_Object Qmouse_click, Qevent_kind;
extern Lisp_Object QCtoggle, QCradio;
#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 ();
pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
-#ifndef HAVE_MULTILINGUAL_MENU
- if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
+ if (STRINGP (pane_name))
{
- pane_name = ENCODE_SYSTEM (pane_name);
+ if (unicode_append_menu)
+ /* Encode as UTF-8 for now. */
+ pane_name = ENCODE_UTF_8 (pane_name);
+ else if (STRING_MULTIBYTE (pane_name))
+ pane_name = ENCODE_SYSTEM (pane_name);
+
ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
}
-#endif
+
pane_string = (NILP (pane_name)
? "" : (char *) SDATA (pane_name));
/* If there is just one top-level pane, put all its items directly
save_wv->next = wv;
else
first_wv->contents = wv;
- wv->name = pane_string;
- /* Ignore the @ that means "separate pane".
- This is a kludge, but this isn't worth more time. */
- if (!NILP (prefix) && wv->name[0] == '@')
- wv->name++;
- wv->value = 0;
+ wv->lname = pane_name;
+ /* Set value to 1 so update_submenu_strings can handle '@' */
+ wv->value = (char *) 1;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
wv->help = Qnil;
selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
-#ifndef HAVE_MULTILINGUAL_MENU
- if (STRING_MULTIBYTE (item_name))
+ if (STRINGP (item_name))
{
- item_name = ENCODE_SYSTEM (item_name);
+ if (unicode_append_menu)
+ item_name = ENCODE_UTF_8 (item_name);
+ else if (STRING_MULTIBYTE (item_name))
+ item_name = ENCODE_SYSTEM (item_name);
+
ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
}
descrip = ENCODE_SYSTEM (descrip);
ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
}
-#endif /* not HAVE_MULTILINGUAL_MENU */
wv = xmalloc_widget_value ();
if (prev_wv)
else
save_wv->contents = wv;
- wv->name = (char *) SDATA (item_name);
+ wv->lname = item_name;
if (!NILP (descrip))
- wv->key = (char *) SDATA (descrip);
+ wv->lkey = descrip;
wv->value = 0;
/* The EMACS_INT cast avoids a warning. There's no problem
as long as pointers have enough bits to hold small integers. */
return first_wv;
}
+
+
+/* Walk through the widget_value tree starting at FIRST_WV and update
+ the char * pointers from the corresponding lisp values.
+ We do this after building the whole tree, since GC may happen while the
+ tree is constructed, and small strings are relocated. So we must wait
+ until no GC can happen before storing pointers into lisp values. */
+static void
+update_submenu_strings (first_wv)
+ widget_value *first_wv;
+{
+ widget_value *wv;
+
+ for (wv = first_wv; wv; wv = wv->next)
+ {
+ if (wv->lname && ! NILP (wv->lname))
+ {
+ wv->name = SDATA (wv->lname);
+
+ /* Ignore the @ that means "separate pane".
+ This is a kludge, but this isn't worth more time. */
+ if (wv->value == (char *)1)
+ {
+ if (wv->name[0] == '@')
+ wv->name++;
+ wv->value = 0;
+ }
+ }
+
+ if (wv->lkey && ! NILP (wv->lkey))
+ wv->key = SDATA (wv->lkey);
+
+ if (wv->contents)
+ update_submenu_strings (wv->contents);
+ }
+}
+
\f
/* Set the contents of the menubar widgets of frame F.
The argument FIRST_TIME is currently ignored;
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);
if (NILP (string))
break;
wv->name = (char *) SDATA (string);
+ update_submenu_strings (wv->contents);
wv = wv->next;
}
char *pane_string;
pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME);
prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
-#ifndef HAVE_MULTILINGUAL_MENU
- if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
+
+ if (STRINGP (pane_name))
{
- pane_name = ENCODE_SYSTEM (pane_name);
+ if (unicode_append_menu)
+ pane_name = ENCODE_UTF_8 (pane_name);
+ else if (STRING_MULTIBYTE (pane_name))
+ pane_name = ENCODE_SYSTEM (pane_name);
+
ASET (menu_items, i + MENU_ITEMS_PANE_NAME, pane_name);
}
-#endif
+
pane_string = (NILP (pane_name)
? "" : (char *) SDATA (pane_name));
/* If there is just one top-level pane, put all its items directly
selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED);
help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP);
-#ifndef HAVE_MULTILINGUAL_MENU
- if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
+ if (STRINGP (item_name))
{
- item_name = ENCODE_SYSTEM (item_name);
+ if (unicode_append_menu)
+ item_name = ENCODE_UTF_8 (item_name);
+ else if (STRING_MULTIBYTE (item_name))
+ item_name = ENCODE_SYSTEM (item_name);
+
ASET (menu_items, i + MENU_ITEMS_ITEM_NAME, item_name);
}
- if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+
+ if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
{
descrip = ENCODE_SYSTEM (descrip);
ASET (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY, descrip);
}
-#endif /* not HAVE_MULTILINGUAL_MENU */
wv = xmalloc_widget_value ();
if (prev_wv)
wv_sep->next = first_wv->contents;
wv_sep->help = Qnil;
-#ifndef HAVE_MULTILINGUAL_MENU
- if (STRING_MULTIBYTE (title))
+ if (unicode_append_menu)
+ title = ENCODE_UTF_8 (title);
+ else if (STRING_MULTIBYTE (title))
title = ENCODE_SYSTEM (title);
-#endif
+
wv_title->name = (char *) SDATA (title);
wv_title->enabled = TRUE;
wv_title->title = TRUE;
"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';
return AppendMenu (menu, MF_MENUBARBREAK, 0, NULL);
}
+/* UTF8: 0xxxxxxx, 110xxxxx 10xxxxxx, 1110xxxx, 10xxxxxx, 10xxxxxx */
+static void
+utf8to16 (unsigned char * src, int len, WCHAR * dest)
+{
+ while (len > 0)
+ {
+ int utf16;
+ if (*src < 0x80)
+ {
+ *dest = (WCHAR) *src;
+ dest++; src++; len--;
+ }
+ /* Since we might get >3 byte sequences which we don't handle, ignore the extra parts. */
+ else if (*src < 0xC0)
+ {
+ src++; len--;
+ }
+ /* 2 char UTF-8 sequence. */
+ else if (*src < 0xE0)
+ {
+ *dest = (WCHAR) (((*src & 0x1f) << 6)
+ | (*(src + 1) & 0x3f));
+ src += 2; len -= 2; dest++;
+ }
+ else if (*src < 0xF0)
+ {
+ *dest = (WCHAR) (((*src & 0x0f) << 12)
+ | ((*(src + 1) & 0x3f) << 6)
+ | (*(src + 2) & 0x3f));
+ src += 3; len -= 3; dest++;
+ }
+ else /* Not encodable. Insert Unicode Substitution char. */
+ {
+ *dest = (WCHAR) 0xfffd;
+ src++; len--; dest++;
+ }
+ }
+ *dest = 0;
+}
+
static int
add_menu_item (HMENU menu, widget_value *wv, HMENU item)
{
fuFlags |= MF_UNCHECKED;
}
- return_value =
- AppendMenu (menu,
- fuFlags,
- item != NULL ? (UINT) item : (UINT) wv->call_data,
- out_string );
+ if (unicode_append_menu && out_string)
+ {
+ /* Convert out_string from UTF-8 to UTF-16-LE. */
+ int utf8_len = strlen (out_string);
+ WCHAR * utf16_string;
+ if (fuFlags & MF_OWNERDRAW)
+ utf16_string = local_alloc ((utf8_len + 1) * sizeof (WCHAR));
+ else
+ utf16_string = 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,
+ utf16_string);
+ if (fuFlags & MF_OWNERDRAW)
+ local_free (out_string);
+ }
+ else
+ {
+ return_value =
+ AppendMenu (menu,
+ fuFlags,
+ item != NULL ? (UINT) item : (UINT) wv->call_data,
+ out_string );
+ }
/* This must be done after the menu item is created. */
if (!wv->title && wv->call_data != 0)
/* 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. */
- if (wv->help)
- info.dwItemData = (DWORD) wv->help;
-
+ if (!NILP (wv->help))
+#ifdef USE_LISP_UNION_TYPE
+ info.dwItemData = (DWORD) (wv->help).i;
+#else
+ info.dwItemData = (DWORD) (wv->help);
+#endif
if (wv->button_type == BUTTON_TYPE_RADIO)
{
/* CheckMenuRadioItem allows us to differentiate TOGGLE and
struct frame *f = x_window_to_frame (&one_w32_display_info, owner);
Lisp_Object frame, help;
- // No help echo on owner-draw menu items.
+ /* No help echo on owner-draw menu items. */
if (flags & MF_OWNERDRAW || flags & MF_POPUP)
help = Qnil;
else
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
}
/* Store the help echo in the keyboard buffer as the X toolkit
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");
}
/* arch-tag: 0eaed431-bb4e-4aac-a527-95a1b4f1fed0