#include "dispextern.h"
-#define POPUP_SUBMENU_ID 235
-#define MIN_POPUP_SUBMENU_ID 512
-#define MIN_MENU_ID 256
-#define MIN_SUBMENU_ID 1
+enum mac_menu_kind { /* Menu ID range */
+ MAC_MENU_APPLE, /* 0 (Reserved by Apple) */
+ MAC_MENU_MENU_BAR, /* 1 .. 234 */
+ MAC_MENU_POPUP, /* 235 */
+ MAC_MENU_DRIVER, /* 236 .. 255 (Reserved) */
+ MAC_MENU_MENU_BAR_SUB, /* 256 .. 16383 */
+ MAC_MENU_POPUP_SUB, /* 16384 .. 32767 */
+ MAC_MENU_END /* 32768 */
+};
+
+static const int min_menu_id[] = {0, 1, 235, 236, 256, 16384, 32768};
#define DIALOG_WINDOW_RESOURCE 130
static void list_of_panes P_ ((Lisp_Object));
static void list_of_items P_ ((Lisp_Object));
-static int fill_menu P_ ((MenuHandle, widget_value *, int));
+static int fill_menu P_ ((MenuHandle, widget_value *, enum mac_menu_kind, int));
static void fill_menubar P_ ((widget_value *, int));
-static void dispose_menus P_ ((int));
+static void dispose_menus P_ ((enum mac_menu_kind, int));
\f
/* This holds a Lisp vector that holds the results of decoding
}
}
+/* This undoes save_menu_items, and it is called by the specpdl unwind
+ mechanism. */
+
+static Lisp_Object
+restore_menu_items (saved)
+ Lisp_Object saved;
+{
+ menu_items = XCAR (saved);
+ menu_items_allocated = (VECTORP (menu_items) ? ASIZE (menu_items) : 0);
+ saved = XCDR (saved);
+ menu_items_used = XINT (XCAR (saved));
+ saved = XCDR (saved);
+ menu_items_n_panes = XINT (XCAR (saved));
+ saved = XCDR (saved);
+ menu_items_submenu_depth = XINT (XCAR (saved));
+ return Qnil;
+}
+
+/* Push the whole state of menu_items processing onto the specpdl.
+ It will be restored when the specpdl is unwound. */
+
+static void
+save_menu_items ()
+{
+ Lisp_Object saved = list4 (menu_items,
+ make_number (menu_items_used),
+ make_number (menu_items_n_panes),
+ make_number (menu_items_submenu_depth));
+ record_unwind_protect (restore_menu_items, saved);
+ menu_items = Qnil;
+}
+\f
/* Make the menu_items vector twice as large. */
static void
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));
Lisp_Object arg;
{
discard_menu_items ();
+ return Qnil;
}
DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
int i;
int submenu_depth = 0;
widget_value **submenu_stack;
+ int panes_seen = 0;
submenu_stack
= (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
Lisp_Object pane_name, prefix;
char *pane_string;
+ panes_seen++;
+
pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME];
prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
Lisp_Object item_name, enable, descrip, def, type, selected;
Lisp_Object help;
+ /* All items should be contained in panes. */
+ if (panes_seen == 0)
+ abort ();
+
item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME);
enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE);
descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY);
EventRef theEvent;
void* userData;
{
+ OSStatus err;
UInt32 keyCode;
UInt32 keyModifiers;
extern int mac_quit_char_modifiers;
extern int mac_quit_char_keycode;
- GetEventParameter (theEvent, kEventParamKeyCode,
- typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
+ err = GetEventParameter (theEvent, kEventParamKeyCode,
+ typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
- GetEventParameter (theEvent, kEventParamKeyModifiers,
- typeUInt32, NULL, sizeof(UInt32),
- NULL, &keyModifiers);
+ if (err == noErr)
+ err = GetEventParameter (theEvent, kEventParamKeyModifiers,
+ typeUInt32, NULL, sizeof(UInt32),
+ NULL, &keyModifiers);
- if (keyCode == mac_quit_char_keycode
+ if (err == noErr && keyCode == mac_quit_char_keycode
&& keyModifiers == mac_quit_char_modifiers)
{
MenuRef menu = userData != 0
}
#endif /* HAVE_CANCELMENUTRACKING */
-/* Add event handler for MENU_HANDLE so we can detect C-g.
- If MENU_HANDLE is NULL, install handler for all menus in the menu bar.
+/* Add event handler to all menus that belong to KIND so we can detect C-g.
+ MENU_HANDLE is the root menu of the tracking session to dismiss
+ when C-g is detected. NULL means the menu bar.
If CancelMenuTracking isn't available, do nothing. */
static void
-install_menu_quit_handler (MenuHandle menu_handle)
+install_menu_quit_handler (kind, menu_handle)
+ enum mac_menu_kind kind;
+ MenuHandle menu_handle;
{
#ifdef HAVE_CANCELMENUTRACKING
EventTypeSpec typesList[] = { { kEventClassKeyboard, kEventRawKeyDown } };
- int i = MIN_MENU_ID;
- MenuHandle menu = menu_handle ? menu_handle : GetMenuHandle (i);
+ int id;
- while (menu != NULL)
+ for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++)
{
- InstallMenuEventHandler (menu, menu_quit_handler,
- GetEventTypeCount (typesList),
- typesList, menu_handle, NULL);
- if (menu_handle) break;
- menu = GetMenuHandle (++i);
- }
+ MenuHandle menu = GetMenuHandle (id);
- i = menu_handle ? MIN_POPUP_SUBMENU_ID : MIN_SUBMENU_ID;
- menu = GetMenuHandle (i);
- while (menu != NULL)
- {
+ if (menu == NULL)
+ break;
InstallMenuEventHandler (menu, menu_quit_handler,
GetEventTypeCount (typesList),
typesList, menu_handle, NULL);
- menu = GetMenuHandle (++i);
}
#endif /* HAVE_CANCELMENUTRACKING */
}
/* Fill in menu_items with the current menu bar contents.
This can evaluate Lisp code. */
+ save_menu_items ();
+
menu_items = f->menu_bar_vector;
menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0;
submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
}
set_buffer_internal_1 (prev);
- unbind_to (specpdl_count, Qnil);
/* If there has been no change in the Lisp-level contents
of the menu bar, skip redisplaying it. Just exit. */
+ /* Compare the new menu items with the ones computed last time. */
for (i = 0; i < previous_menu_items_used; i++)
if (menu_items_used == i
|| (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i])))
break;
if (i == menu_items_used && i == previous_menu_items_used && i != 0)
{
+ /* The menu items have not changed. Don't bother updating
+ the menus in any form, since it would be a no-op. */
free_menubar_widget_value_tree (first_wv);
discard_menu_items ();
-
+ unbind_to (specpdl_count, Qnil);
return;
}
+ /* The menu items are different, so store them in the frame. */
+ f->menu_bar_vector = menu_items;
+ f->menu_bar_items_used = menu_items_used;
+
+ /* This calls restore_menu_items to restore menu_items, etc.,
+ as they were outside. */
+ unbind_to (specpdl_count, Qnil);
+
/* Now GC cannot happen during the lifetime of the widget_value,
so it's safe to store data from a Lisp_String. */
wv = first_wv->contents;
wv = wv->next;
}
- f->menu_bar_vector = menu_items;
- f->menu_bar_items_used = menu_items_used;
- discard_menu_items ();
}
else
{
fill_menubar (first_wv->contents, deep_p);
/* Add event handler so we can detect C-g. */
- install_menu_quit_handler (NULL);
+ install_menu_quit_handler (MAC_MENU_MENU_BAR, NULL);
+ install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB, NULL);
free_menubar_widget_value_tree (first_wv);
UNBLOCK_INPUT;
{
struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
FRAME_PTR f = p->pointer;
- MenuHandle menu = GetMenuHandle (POPUP_SUBMENU_ID);
+ MenuHandle menu = GetMenuHandle (min_menu_id[MAC_MENU_POPUP]);
BLOCK_INPUT;
FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0;
/* delete all menus */
- dispose_menus (MIN_POPUP_SUBMENU_ID);
- DeleteMenu (POPUP_SUBMENU_ID);
+ dispose_menus (MAC_MENU_POPUP_SUB, 0);
+ DeleteMenu (min_menu_id[MAC_MENU_POPUP]);
DisposeMenu (menu);
UNBLOCK_INPUT;
}
/* Actually create the menu. */
- menu = NewMenu (POPUP_SUBMENU_ID, "\p");
+ menu = NewMenu (min_menu_id[MAC_MENU_POPUP], "\p");
InsertMenu (menu, -1);
- fill_menu (menu, first_wv->contents, MIN_POPUP_SUBMENU_ID);
+ fill_menu (menu, first_wv->contents, MAC_MENU_POPUP_SUB,
+ min_menu_id[MAC_MENU_POPUP_SUB]);
/* Free the widget_value objects we used to specify the
contents. */
record_unwind_protect (pop_down_menu, make_save_value (f, 0));
/* Add event handler so we can detect C-g. */
- install_menu_quit_handler (menu);
+ install_menu_quit_handler (MAC_MENU_POPUP, menu);
+ install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu);
/* Display the menu. */
menu_item_choice = PopUpMenuSelect (menu, pos.v, pos.h, 0);
/* Construct native Mac OS menu based on widget_value tree. */
static int
-fill_menu (menu, wv, submenu_id)
+fill_menu (menu, wv, kind, submenu_id)
MenuHandle menu;
widget_value *wv;
+ enum mac_menu_kind kind;
int submenu_id;
{
int pos;
for (pos = 1; wv != NULL; wv = wv->next, pos++)
{
add_menu_item (menu, pos, wv);
- if (wv->contents)
+ if (wv->contents && submenu_id < min_menu_id[kind + 1])
{
MenuHandle submenu = NewMenu (submenu_id, "\pX");
InsertMenu (submenu, -1);
SetMenuItemHierarchicalID (menu, pos, submenu_id);
- submenu_id = fill_menu (submenu, wv->contents, submenu_id + 1);
+ submenu_id = fill_menu (submenu, wv->contents, kind, submenu_id + 1);
}
}
/* Clean up the menu bar when filled by the entire menu trees. */
if (deep_p)
{
- dispose_menus (MIN_MENU_ID);
- dispose_menus (MIN_SUBMENU_ID);
+ dispose_menus (MAC_MENU_MENU_BAR, 0);
+ dispose_menus (MAC_MENU_MENU_BAR_SUB, 0);
#if !TARGET_API_MAC_CARBON
title_changed_p = 1;
#endif
/* Fill menu bar titles and submenus. Reuse the existing menu bar
titles as much as possible to minimize redraw (if !deep_p). */
- submenu_id = MIN_SUBMENU_ID;
- for (id = MIN_MENU_ID; wv != NULL; wv = wv->next, id++)
+ submenu_id = min_menu_id[MAC_MENU_MENU_BAR_SUB];
+ for (id = min_menu_id[MAC_MENU_MENU_BAR];
+ wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1];
+ wv = wv->next, id++)
{
strncpy (title, wv->name, 255);
title[255] = '\0';
}
if (wv->contents)
- submenu_id = fill_menu (menu, wv->contents, submenu_id);
+ submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
+ submenu_id);
}
- if (GetMenuHandle (id))
+ if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuHandle (id))
{
- dispose_menus (id);
+ dispose_menus (MAC_MENU_MENU_BAR, id);
#if !TARGET_API_MAC_CARBON
title_changed_p = 1;
#endif
#endif
}
+/* Dispose of menus that belong to KIND, and remove them from the menu
+ list. ID is the lower bound of menu IDs that will be processed. */
+
static void
-dispose_menus (id)
+dispose_menus (kind, id)
+ enum mac_menu_kind kind;
int id;
{
- MenuHandle menu;
-
- while ((menu = GetMenuHandle (id)) != NULL)
+ for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++)
{
+ MenuHandle menu = GetMenuHandle (id);
+
+ if (menu == NULL)
+ break;
DeleteMenu (id);
DisposeMenu (menu);
- id++;
}
}