/* Menu support for GNU Emacs on the Microsoft W32 API.
- Copyright (C) 1986, 1988, 1993, 1994, 1996, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1986, 88, 93, 94, 96, 98, 1999 Free Software Foundation, Inc.
This file is part of GNU Emacs.
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <signal.h>
#include <config.h>
+#include <signal.h>
#include <stdio.h>
#include "lisp.h"
#include "termhooks.h"
+#include "keyboard.h"
#include "frame.h"
#include "window.h"
-#include "keyboard.h"
#include "blockinput.h"
#include "buffer.h"
+#include "charset.h"
+#include "coding.h"
/* This may include sys/types.h, and that somehow loses
if this is not done before the other system files. */
#include "dispextern.h"
+#undef HAVE_MULTILINGUAL_MENU
+#undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
+
/******************************************************************/
/* Definitions copied from lwlib.h */
typedef void * XtPointer;
typedef char Boolean;
-#define True 1
-#define False 0
-
-typedef enum _change_type
+enum button_type
{
- NO_CHANGE = 0,
- INVISIBLE_CHANGE = 1,
- VISIBLE_CHANGE = 2,
- STRUCTURAL_CHANGE = 3
-} change_type;
+ BUTTON_TYPE_NONE,
+ BUTTON_TYPE_TOGGLE,
+ BUTTON_TYPE_RADIO
+};
typedef struct _widget_value
{
char* value;
/* keyboard equivalent. no implications for XtTranslations */
char* key;
+ /* Help string or null if none. */
+ char *help;
/* true if enabled */
Boolean enabled;
/* true if selected */
Boolean selected;
+ /* The type of a button. */
+ enum button_type button_type;
/* true if menu title */
Boolean title;
#if 0
void set_frame_menubar ();
-static Lisp_Object w32_menu_show ();
+static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
+ Lisp_Object, Lisp_Object, Lisp_Object,
+ Lisp_Object, Lisp_Object));
static Lisp_Object w32_dialog_show ();
+static Lisp_Object w32_menu_show ();
static void keymap_panes ();
static void single_keymap_panes ();
#define MENU_ITEMS_PANE_PREFIX 2
#define MENU_ITEMS_PANE_LENGTH 3
-#define MENU_ITEMS_ITEM_NAME 0
-#define MENU_ITEMS_ITEM_ENABLE 1
-#define MENU_ITEMS_ITEM_VALUE 2
-#define MENU_ITEMS_ITEM_EQUIV_KEY 3
-#define MENU_ITEMS_ITEM_DEFINITION 4
-#define MENU_ITEMS_ITEM_LENGTH 5
+enum menu_item_idx
+{
+ MENU_ITEMS_ITEM_NAME = 0,
+ MENU_ITEMS_ITEM_ENABLE,
+ MENU_ITEMS_ITEM_VALUE,
+ MENU_ITEMS_ITEM_EQUIV_KEY,
+ MENU_ITEMS_ITEM_DEFINITION,
+ MENU_ITEMS_ITEM_TYPE,
+ MENU_ITEMS_ITEM_SELECTED,
+ MENU_ITEMS_ITEM_HELP,
+ MENU_ITEMS_ITEM_LENGTH
+};
static Lisp_Object menu_items;
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
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.
\f
/* Return the frame whose ->output_data.w32->menubar_widget equals
- MENU, or 0 if none. */
+ ID, or 0 if none. */
static struct frame *
-menubar_id_to_frame (HMENU menu)
+menubar_id_to_frame (id)
+ HMENU id;
{
Lisp_Object tail, frame;
FRAME_PTR f;
- for (tail = Vframe_list; GC_CONSP (tail); tail = XCONS (tail)->cdr)
+ for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
{
- frame = XCONS (tail)->car;
+ frame = XCAR (tail);
if (!GC_FRAMEP (frame))
continue;
f = XFRAME (frame);
- if (f->output_data.nothing == 1)
+ if (!FRAME_WINDOW_P (f))
continue;
- if (f->output_data.w32->menubar_widget == menu)
+ if (f->output_data.w32->menubar_widget == id)
return f;
}
return 0;
XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
}
-/* Push one menu item into the current pane.
- NAME is the string to display. ENABLE if non-nil means
- this item can be selected. KEY is the key generated by
- choosing this item, or nil if this item doesn't really have a definition.
- DEF is the definition of this item.
- EQUIV is the textual description of the keyboard equivalent for
- this item (or nil if none). */
+/* Push one menu item into the current pane. NAME is the string to
+ display. ENABLE if non-nil means this item can be selected. KEY
+ is the key generated by choosing this item, or nil if this item
+ doesn't really have a definition. DEF is the definition of this
+ item. EQUIV is the textual description of the keyboard equivalent
+ for this item (or nil if none). TYPE is the type of this menu
+ item, one of nil, `toggle' or `radio'. */
static void
-push_menu_item (name, enable, key, def, equiv)
- Lisp_Object name, enable, key, def, equiv;
+push_menu_item (name, enable, key, def, equiv, type, selected, help)
+ Lisp_Object name, enable, key, def, equiv, type, selected, help;
{
if (menu_items_used + MENU_ITEMS_ITEM_LENGTH > menu_items_allocated)
grow_menu_items ();
XVECTOR (menu_items)->contents[menu_items_used++] = key;
XVECTOR (menu_items)->contents[menu_items_used++] = equiv;
XVECTOR (menu_items)->contents[menu_items_used++] = def;
+ XVECTOR (menu_items)->contents[menu_items_used++] = type;
+ XVECTOR (menu_items)->contents[menu_items_used++] = selected;
+ XVECTOR (menu_items)->contents[menu_items_used++] = help;
}
\f
/* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
But don't make a pane that is empty--ignore that map instead.
P is the number of panes we have made so far. */
for (mapno = 0; mapno < nmaps; mapno++)
- single_keymap_panes (keymaps[mapno], Qnil, Qnil, notreal, 10);
+ single_keymap_panes (keymaps[mapno],
+ map_prompt (keymaps[mapno]), Qnil, notreal, 10);
finish_menu_items ();
}
Lisp_Object pending_maps = Qnil;
Lisp_Object tail, item;
struct gcpro gcpro1, gcpro2;
- int notbuttons = 0;
if (maxdepth <= 0)
return;
push_menu_pane (pane_name, prefix);
-#ifndef HAVE_BOXES
- /* Remember index for first item in this pane so we can go back and
- add a prefix when (if) we see the first button. After that, notbuttons
- is set to 0, to mark that we have seen a button and all non button
- items need a prefix. */
- notbuttons = menu_items_used;
-#endif
-
- for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
+ for (tail = keymap; CONSP (tail); tail = XCDR (tail))
{
GCPRO2 (keymap, pending_maps);
/* Look at each key binding, and if it is a menu item add it
to this menu. */
- item = XCONS (tail)->car;
+ item = XCAR (tail);
if (CONSP (item))
- single_menu_item (XCONS (item)->car, XCONS (item)->cdr,
- &pending_maps, notreal, maxdepth, ¬buttons);
+ single_menu_item (XCAR (item), XCDR (item),
+ &pending_maps, notreal, maxdepth);
else if (VECTORP (item))
{
/* Loop over the char values represented in the vector. */
Lisp_Object character;
XSETFASTINT (character, c);
single_menu_item (character, XVECTOR (item)->contents[c],
- &pending_maps, notreal, maxdepth, ¬buttons);
+ &pending_maps, notreal, maxdepth);
}
}
UNGCPRO;
{
Lisp_Object elt, eltcdr, string;
elt = Fcar (pending_maps);
- eltcdr = XCONS (elt)->cdr;
- string = XCONS (eltcdr)->car;
+ eltcdr = XCDR (elt);
+ string = XCAR (eltcdr);
/* We no longer discard the @ from the beginning of the string here.
Instead, we do this in w32_menu_show. */
single_keymap_panes (Fcar (elt), string,
- XCONS (eltcdr)->cdr, notreal, maxdepth - 1);
+ XCDR (eltcdr), notreal, maxdepth - 1);
pending_maps = Fcdr (pending_maps);
}
}
separate panes.
If NOTREAL is nonzero, only check for equivalent key bindings, don't
evaluate expressions in menu items and don't make any menu.
- If we encounter submenus deeper than MAXDEPTH levels, ignore them.
- NOTBUTTONS_PTR is only used when simulating toggle boxes and radio
- buttons. It points to variable notbuttons in single_keymap_panes,
- which keeps track of if we have seen a button in this menu or not. */
+ If we encounter submenus deeper than MAXDEPTH levels, ignore them. */
static void
-single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth,
- notbuttons_ptr)
+single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth)
Lisp_Object key, item;
Lisp_Object *pending_maps_ptr;
int maxdepth, notreal;
- int *notbuttons_ptr;
{
- Lisp_Object def, map, item_string, enabled;
+ Lisp_Object map, item_string, enabled;
struct gcpro gcpro1, gcpro2;
int res;
return;
}
-#ifndef HAVE_BOXES
- /* Simulate radio buttons and toggle boxes by putting a prefix in
- front of them. */
- {
- Lisp_Object prefix = Qnil;
- Lisp_Object type = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
- if (!NILP (type))
- {
- Lisp_Object selected
- = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
-
- if (*notbuttons_ptr)
- /* The first button. Line up previous items in this menu. */
- {
- int index = *notbuttons_ptr; /* Index for first item this menu. */
- int submenu = 0;
- Lisp_Object tem;
- while (index < menu_items_used)
- {
- tem
- = XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME];
- if (NILP (tem))
- {
- index++;
- submenu++; /* Skip sub menu. */
- }
- else if (EQ (tem, Qlambda))
- {
- index++;
- submenu--; /* End sub menu. */
- }
- else if (EQ (tem, Qt))
- index += 3; /* Skip new pane marker. */
- else if (EQ (tem, Qquote))
- index++; /* Skip a left, right divider. */
- else
- {
- if (!submenu && XSTRING (tem)->data[0] != '\0'
- && XSTRING (tem)->data[0] != '-')
- XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME]
- = concat2 (build_string (" "), tem);
- index += MENU_ITEMS_ITEM_LENGTH;
- }
- }
- *notbuttons_ptr = 0;
- }
-
- /* Calculate prefix, if any, for this item. */
- if (EQ (type, QCtoggle))
- prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
- else if (EQ (type, QCradio))
- prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
- }
- /* Not a button. If we have earlier buttons, then we need a prefix. */
- else if (!*notbuttons_ptr && XSTRING (item_string)->data[0] != '\0'
- && XSTRING (item_string)->data[0] != '-')
- prefix = build_string (" ");
-
- if (!NILP (prefix))
- item_string = concat2 (prefix, item_string);
- }
-#endif /* not HAVE_BOXES */
-
-#if 0
- if (!NILP(map))
- /* Indicate visually that this is a submenu. */
- item_string = concat2 (item_string, build_string (" >"));
-#endif
-
push_menu_item (item_string, enabled, key,
XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF],
- XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]);
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ],
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE],
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
-#if 1
/* Display a submenu using the toolkit. */
if (! (NILP (map) || NILP (enabled)))
{
single_keymap_panes (map, Qnil, key, 0, maxdepth - 1);
push_submenu_end ();
}
-#endif
}
\f
/* Push all the panes and items of a menu described by the
{
item = Fcar (tail);
if (STRINGP (item))
- push_menu_item (item, Qnil, Qnil, Qt, Qnil);
+ push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil);
else if (NILP (item))
push_left_right_boundary ();
else
CHECK_CONS (item, 0);
item1 = Fcar (item);
CHECK_STRING (item1, 1);
- push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil);
+ push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil);
}
}
}
(position, menu)
Lisp_Object position, menu;
{
- int number_of_panes, panes;
Lisp_Object keymap, tem;
int xpos, ypos;
Lisp_Object title;
char *error_name;
Lisp_Object selection;
- int i, j;
FRAME_PTR f;
Lisp_Object x, y, window;
int keymaps = 0;
/* Decode the first argument: find the window and the coordinates. */
if (EQ (position, Qt)
- || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar)))
+ || (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
+ || EQ (XCAR (position), Qtool_bar))))
{
/* Use the mouse's current position. */
- FRAME_PTR new_f = selected_frame;
+ FRAME_PTR new_f = SELECTED_FRAME ();
Lisp_Object bar_window;
- int part;
+ enum scroll_bar_part part;
unsigned long time;
if (mouse_position_hook)
CHECK_LIVE_WINDOW (window, 0);
f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
- xpos = (FONT_WIDTH (f->output_data.w32->font)
+ xpos = (FONT_WIDTH (FRAME_FONT (f))
* XFASTINT (XWINDOW (window)->left));
- ypos = (f->output_data.w32->line_height
+ ypos = (FRAME_LINE_HEIGHT (f)
* XFASTINT (XWINDOW (window)->top));
}
else
/* Decode the menu items from what was specified. */
- keymap = Fkeymapp (menu);
- tem = Qnil;
- if (CONSP (menu))
- tem = Fkeymapp (Fcar (menu));
- if (!NILP (keymap))
+ keymap = get_keymap (menu, 0, 0);
+ if (CONSP (keymap))
{
/* We were given a keymap. Extract menu info from the keymap. */
Lisp_Object prompt;
- keymap = get_keymap (menu);
/* Extract the detailed info to make one pane. */
keymap_panes (&menu, 1, NILP (position));
keymaps = 1;
}
- else if (!NILP (tem))
+ else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
{
/* We were given a list of keymaps. */
int nmaps = XFASTINT (Flength (menu));
{
Lisp_Object prompt;
- maps[i++] = keymap = get_keymap (Fcar (tem));
+ maps[i++] = keymap = get_keymap (Fcar (tem), 1, 0);
prompt = map_prompt (keymap);
if (NILP (title) && !NILP (prompt))
/* Decode the first argument: find the window or frame to use. */
if (EQ (position, Qt)
- || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar)))
+ || (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;
+ FRAME_PTR new_f = SELECTED_FRAME ();
Lisp_Object bar_window;
- int part;
+ enum scroll_bar_part part;
unsigned long time;
Lisp_Object x, y;
but I don't want to make one now. */
CHECK_WINDOW (window, 0);
-#if 1
+#ifndef HAVE_DIALOGS
/* Display a menu with these alternatives
in the middle of frame F. */
{
return Fx_popup_menu (newpos,
Fcons (Fcar (contents), Fcons (contents, Qnil)));
}
-#else
+#else /* HAVE_DIALOGS */
{
Lisp_Object title;
char *error_name;
if (error_name) error (error_name);
return selection;
}
-#endif
+#endif /* HAVE_DIALOGS */
}
/* Activate the menu bar of frame F.
This way we can safely execute Lisp code. */
+void
x_activate_menubar (f)
FRAME_PTR f;
{
Lisp_Object frame;
XSETFRAME (frame, f);
- buf.kind = menu_bar_event;
- buf.frame_or_window = Fcons (frame, Fcons (Qmenu_bar, Qnil));
+ buf.kind = MENU_BAR_EVENT;
+ buf.frame_or_window = frame;
+ buf.arg = frame;
kbd_buffer_store_event (&buf);
for (j = 0; j < submenu_depth; j++)
if (!NILP (subprefix_stack[j]))
{
- buf.kind = menu_bar_event;
- buf.frame_or_window = Fcons (frame, subprefix_stack[j]);
+ buf.kind = MENU_BAR_EVENT;
+ buf.frame_or_window = frame;
+ buf.arg = subprefix_stack[j];
kbd_buffer_store_event (&buf);
}
if (!NILP (prefix))
{
- buf.kind = menu_bar_event;
- buf.frame_or_window = Fcons (frame, prefix);
+ buf.kind = MENU_BAR_EVENT;
+ buf.frame_or_window = frame;
+ buf.arg = prefix;
kbd_buffer_store_event (&buf);
}
- buf.kind = menu_bar_event;
- buf.frame_or_window = Fcons (frame, entry);
+ buf.kind = MENU_BAR_EVENT;
+ buf.frame_or_window = frame;
+ buf.arg = entry;
kbd_buffer_store_event (&buf);
return;
int len;
Lisp_Object *mapvec;
widget_value **submenu_stack;
- int mapno;
int previous_items = menu_items_used;
int top_level_items = 0;
for (i = 0; i < len; i++)
{
if (SYMBOLP (mapvec[i])
- || (CONSP (mapvec[i])
- && NILP (Fkeymapp (mapvec[i]))))
+ || (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i])))
{
/* Here we have a command at top level in the menu bar
as opposed to a submenu. */
top_level_items = 1;
push_menu_pane (Qnil, Qnil);
- push_menu_item (item_name, Qt, item_key, mapvec[i], Qnil);
+ push_menu_item (item_name, Qt, item_key, mapvec[i],
+ Qnil, Qnil, Qnil, Qnil);
}
else
single_keymap_panes (mapvec[i], item_name, item_key, 0, 10);
wv->name = "menu";
wv->value = 0;
wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
first_wv = wv;
save_wv = 0;
prev_wv = 0;
char *pane_string;
pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+#ifndef HAVE_MULTILINGUAL_MENU
+ if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
+ pane_name = ENCODE_SYSTEM (pane_name);
+#endif
pane_string = (NILP (pane_name)
? "" : (char *) XSTRING (pane_name)->data);
/* If there is just one top-level pane, put all its items directly
wv->name++;
wv->value = 0;
wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
}
save_wv = wv;
prev_wv = 0;
else
{
/* Create a new item within current pane. */
- Lisp_Object item_name, enable, descrip, def;
+ Lisp_Object item_name, enable, descrip, def, type, selected;
+ Lisp_Object help;
+
item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
descrip
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
+ type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE];
+ selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED];
+ help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
+
+#ifndef HAVE_MULTILINGUAL_MENU
+ if (STRING_MULTIBYTE (item_name))
+ item_name = ENCODE_SYSTEM (item_name);
+ if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+ descrip = ENCODE_SYSTEM (descrip);
+#endif
wv = xmalloc_widget_value ();
if (prev_wv)
as long as pointers have enough bits to hold small integers. */
wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0);
wv->enabled = !NILP (enable);
+
+ if (NILP (type))
+ wv->button_type = BUTTON_TYPE_NONE;
+ else if (EQ (type, QCradio))
+ wv->button_type = BUTTON_TYPE_RADIO;
+ else if (EQ (type, QCtoggle))
+ wv->button_type = BUTTON_TYPE_TOGGLE;
+ else
+ abort ();
+
+ wv->selected = !NILP (selected);
+ if (STRINGP (help))
+ wv->help = (char *) XSTRING (help)->data;
+ else
+ wv->help = NULL;
+
prev_wv = wv;
i += MENU_ITEMS_ITEM_LENGTH;
int deep_p;
{
HMENU menubar_widget = f->output_data.w32->menubar_widget;
- Lisp_Object tail, items, frame;
+ Lisp_Object items;
widget_value *wv, *first_wv, *prev_wv = 0;
int i;
wv->name = "menubar";
wv->value = 0;
wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
first_wv = wv;
if (deep_p)
set_buffer_internal_1 (XBUFFER (buffer));
/* Run the Lucid hook. */
- call1 (Vrun_hooks, Qactivate_menubar_hook);
+ safe_run_hooks (Qactivate_menubar_hook);
/* If it has changed current-menubar from previous value,
really recompute the menubar from the value. */
if (! NILP (Vlucid_menu_bar_dirty_flag))
first_wv->contents = wv;
/* Don't set wv->name here; GC during the loop might relocate it. */
wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
prev_wv = wv;
}
else
{
/* Make a widget-value tree containing
- just the top level menu bar strings.
-
- It turns out to be worth comparing the new contents with the
- previous contents to avoid unnecessary rebuilding even of just
- the top-level menu bar, which turns out to be fairly slow. We
- co-opt f->menu_bar_vector for this purpose, since its contents
- are effectively discarded at this point anyway.
-
- Note that the lisp-level hooks have already been run by
- update_menu_bar - it's kinda a shame the code is duplicated
- above as well for deep_p, but there we are. */
+ just the top level menu bar strings. */
items = FRAME_MENU_BAR_ITEMS (f);
-
- /* If there has been no change in the Lisp-level contents of just
- the menu bar itself, skip redisplaying it. Just exit. */
- for (i = 0; i < f->menu_bar_items_used; i += 4)
- if (i == XVECTOR (items)->size
- || (XVECTOR (f->menu_bar_vector)->contents[i]
- != XVECTOR (items)->contents[i]))
- break;
- if (i == XVECTOR (items)->size && i == f->menu_bar_items_used && i != 0)
- return;
-
for (i = 0; i < XVECTOR (items)->size; i += 4)
{
Lisp_Object string;
wv->name = (char *) XSTRING (string)->data;
wv->value = 0;
wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
/* This prevents lwlib from assuming this
menu item is really supposed to be empty. */
/* The EMACS_INT cast avoids a warning.
prev_wv = wv;
}
- /* Remember the contents of FRAME_MENU_BAR_ITEMS (f) in
- f->menu_bar_vector, so we can check whether the top-level
- menubar contents have changed next time. */
- if (XVECTOR (f->menu_bar_vector)->size < XVECTOR (items)->size)
- f->menu_bar_vector
- = Fmake_vector (make_number (XVECTOR (items)->size), Qnil);
- bcopy (XVECTOR (items)->contents,
- XVECTOR (f->menu_bar_vector)->contents,
- XVECTOR (items)->size * sizeof (Lisp_Object));
- f->menu_bar_items_used = XVECTOR (items)->size;
+ /* Forget what we thought we knew about what is in the
+ detailed contents of the menu bar menus.
+ Changing the top level always destroys the contents. */
+ f->menu_bar_items_used = 0;
}
/* Create or update the menu bar widget. */
Lisp_Object *subprefix_stack
= (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
int submenu_depth = 0;
-
int first_pane;
- int next_release_must_exit = 0;
*error = NULL;
wv->name = "menu";
wv->value = 0;
wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
first_wv = wv;
first_pane = 1;
char *pane_string;
pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
+#ifndef HAVE_MULTILINGUAL_MENU
+ if (!NILP (pane_name) && STRING_MULTIBYTE (pane_name))
+ pane_name = ENCODE_SYSTEM (pane_name);
+#endif
pane_string = (NILP (pane_name)
? "" : (char *) XSTRING (pane_name)->data);
/* If there is just one top-level pane, put all its items directly
wv->name++;
wv->value = 0;
wv->enabled = 1;
+ wv->button_type = BUTTON_TYPE_NONE;
save_wv = wv;
prev_wv = 0;
}
else
{
/* Create a new item within current pane. */
- Lisp_Object item_name, enable, descrip, def;
+ Lisp_Object item_name, enable, descrip, def, type, selected, help;
+
item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
descrip
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
def = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_DEFINITION];
+ type = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_TYPE];
+ selected = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_SELECTED];
+ help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
+
+#ifndef HAVE_MULTILINGUAL_MENU
+ if (STRINGP (item_name) && STRING_MULTIBYTE (item_name))
+ item_name = ENCODE_SYSTEM (item_name);
+ if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
+ descrip = ENCODE_SYSTEM (descrip);
+#endif
wv = xmalloc_widget_value ();
if (prev_wv)
wv->value = 0;
/* Use the contents index as call_data, since we are
restricted to 16-bits.. */
- wv->call_data = (void *) (EMACS_INT) i;
+ wv->call_data = !NILP (def) ? (void *) (EMACS_INT) i : 0;
wv->enabled = !NILP (enable);
+
+ if (NILP (type))
+ wv->button_type = BUTTON_TYPE_NONE;
+ else if (EQ (type, QCtoggle))
+ wv->button_type = BUTTON_TYPE_TOGGLE;
+ else if (EQ (type, QCradio))
+ wv->button_type = BUTTON_TYPE_RADIO;
+ else
+ abort ();
+
+ wv->selected = !NILP (selected);
+
+ if (STRINGP (help))
+ wv->help = (char *) XSTRING (help)->data;
+ else
+ wv->help = NULL;
+
prev_wv = wv;
i += MENU_ITEMS_ITEM_LENGTH;
wv_sep->name = "--";
wv_sep->next = first_wv->contents;
+#ifndef HAVE_MULTILINGUAL_MENU
+ if (STRING_MULTIBYTE (title))
+ title = ENCODE_SYSTEM (title);
+#endif
wv_title->name = (char *) XSTRING (title)->data;
- /* Handle title specially, so it looks better. */
- wv_title->title = True;
+ wv_title->enabled = TRUE;
+ wv_title->title = TRUE;
+ wv_title->button_type = BUTTON_TYPE_NONE;
wv_title->next = wv_sep;
first_wv->contents = wv_title;
}
/* Actually create the menu. */
menu = CreatePopupMenu ();
fill_in_menu (menu, first_wv->contents);
-
+
/* Adjust coordinates to be root-window-relative. */
pos.x = x;
pos.y = y;
ClientToScreen (FRAME_W32_WINDOW (f), &pos);
- /* Free the widget_value objects we used to specify the contents. */
- free_menubar_widget_value_tree (first_wv);
-
/* No selection has been chosen yet. */
menu_item_selection = 0;
during the call. */
discard_mouse_events ();
+ /* Free the widget_value objects we used to specify the contents. */
+ free_menubar_widget_value_tree (first_wv);
+
DestroyMenu (menu);
/* Find the selected item, and its pane, to return
{
/* Create a new item within current pane. */
- Lisp_Object item_name, enable, descrip;
+ Lisp_Object item_name, enable, descrip, help;
+
item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME];
enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
descrip
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
+ help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP];
if (NILP (item_name))
{
}
/* Actually create the dialog. */
-#if 0
+#ifdef HAVE_DIALOGS
dialog_id = widget_id_tick++;
menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv,
f->output_data.w32->widget, 1, 0,
dialog_selection_callback, 0);
- lw_modify_all_widgets (dialog_id, first_wv->contents, True);
+ lw_modify_all_widgets (dialog_id, first_wv->contents, TRUE);
#endif
/* Free the widget_value objects we used to specify the contents. */
menu_item_selection = 0;
/* Display the menu. */
-#if 0
+#ifdef HAVE_DIALOGS
lw_pop_up_all_widgets (dialog_id);
popup_activated_flag = 1;
{
UINT fuFlags;
char *out_string;
+ int return_value;
if (name_is_separator (wv->name))
- fuFlags = MF_SEPARATOR;
+ {
+ fuFlags = MF_SEPARATOR;
+ out_string = NULL;
+ }
else
{
if (wv->enabled)
else
out_string = wv->name;
- if (wv->title)
+ if (wv->title || wv->call_data == 0)
{
#if 0 /* no GC while popup menu is active */
out_string = LocalAlloc (0, strlen (wv->name) + 1);
#endif
fuFlags = MF_OWNERDRAW | MF_DISABLED;
}
+ /* Draw radio buttons and tickboxes. */
+ else if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
+ wv->button_type == BUTTON_TYPE_RADIO))
+ fuFlags |= MF_CHECKED;
+ else
+ fuFlags |= MF_UNCHECKED;
}
if (item != NULL)
fuFlags = MF_POPUP;
- return AppendMenu (menu,
- fuFlags,
- item != NULL ? (UINT) item : (UINT) wv->call_data,
- (fuFlags == MF_SEPARATOR) ? NULL: out_string );
+ 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 ((fuFlags & MF_STRING) != 0)
+ {
+ HMODULE user32 = GetModuleHandle ("user32.dll");
+ FARPROC set_menu_item_info = GetProcAddress (user32, "SetMenuItemInfoA");
+
+ if (set_menu_item_info)
+ {
+ MENUITEMINFO info;
+ bzero (&info, sizeof (info));
+ info.cbSize = sizeof (info);
+ info.fMask = MIIM_DATA;
+
+ /* Set help string for menu item. */
+ info.dwItemData = (DWORD)wv->help;
+
+ if (wv->button_type == BUTTON_TYPE_RADIO)
+ {
+ /* CheckMenuRadioItem allows us to differentiate TOGGLE and
+ RADIO items, but is not available on NT 3.51 and earlier. */
+ info.fMask |= MIIM_TYPE | MIIM_STATE;
+ info.fType = MFT_RADIOCHECK | MFT_STRING;
+ info.dwTypeData = out_string;
+ info.fState = wv->selected ? MFS_CHECKED : MFS_UNCHECKED;
+ }
+
+ set_menu_item_info (menu,
+ item != NULL ? (UINT) item : (UINT) wv->call_data,
+ FALSE, &info);
+ }
+ }
+ return return_value;
}
/* Construct native Windows menu(bar) based on widget_value tree. */
-static int
+int
fill_in_menu (HMENU menu, widget_value *wv)
{
int items_added = 0;
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. */
+void
+w32_menu_display_help (HMENU menu, UINT item, UINT flags)
+{
+ int pane = 0; /* TODO: Set this to pane number. */
+
+ HMODULE user32 = GetModuleHandle ("user32.dll");
+ FARPROC get_menu_item_info = GetProcAddress (user32, "GetMenuItemInfoA");
+
+ if (get_menu_item_info)
+ {
+ extern Lisp_Object Qmenu_item;
+ Lisp_Object *first_item;
+ Lisp_Object pane_name;
+ Lisp_Object menu_object;
+ MENUITEMINFO info;
+
+ bzero (&info, sizeof (info));
+ info.cbSize = sizeof (info);
+ info.fMask = MIIM_DATA;
+ get_menu_item_info (menu, item, FALSE, &info);
+
+ first_item = XVECTOR (menu_items)->contents;
+ if (EQ (first_item[0], Qt))
+ pane_name = first_item[MENU_ITEMS_PANE_NAME];
+ else if (EQ (first_item[0], Qquote))
+ /* This shouldn't happen, see w32_menu_show. */
+ pane_name = build_string ("");
+ else
+ pane_name = first_item[MENU_ITEMS_ITEM_NAME];
+
+ /* (menu-item MENU-NAME PANE-NUMBER) */
+ menu_object = Fcons (Qmenu_item,
+ Fcons (pane_name,
+ Fcons (make_number (pane), Qnil)));
+
+ show_help_echo (info.dwItemData ?
+ build_string ((char *) info.dwItemData) : Qnil,
+ Qnil, menu_object, make_number (item), 1);
+ }
+}
+
+
+
#endif /* HAVE_MENUS */
\f
syms_of_w32menu ()