#include <config.h>
#include <stdio.h>
#include "lisp.h"
#include "termhooks.h"
#include "keyboard.h"
#include "keymap.h"
#include "frame.h"
#include "window.h"
#include "blockinput.h"
#include "buffer.h"
#include "charset.h"
#include "coding.h"
#if !TARGET_API_MAC_CARBON
#include <MacTypes.h>
#include <Menus.h>
#include <QuickDraw.h>
#include <ToolUtils.h>
#include <Fonts.h>
#include <Controls.h>
#include <Windows.h>
#include <Events.h>
#if defined (__MRC__) || (__MSL__ >= 0x6000)
#include <ControlDefinitions.h>
#endif
#endif
#include "macterm.h"
#ifndef makedev
#include <sys/types.h>
#endif
#include "dispextern.h"
enum mac_menu_kind {
MAC_MENU_APPLE,
MAC_MENU_MENU_BAR,
MAC_MENU_M_APPLE,
MAC_MENU_POPUP,
MAC_MENU_DRIVER,
MAC_MENU_MENU_BAR_SUB,
MAC_MENU_POPUP_SUB,
MAC_MENU_END
};
static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
#define DIALOG_WINDOW_RESOURCE 130
#if TARGET_API_MAC_CARBON
#define HAVE_DIALOGS 1
#endif
#undef HAVE_MULTILINGUAL_MENU
typedef void * XtPointer;
enum button_type
{
BUTTON_TYPE_NONE,
BUTTON_TYPE_TOGGLE,
BUTTON_TYPE_RADIO
};
typedef struct _widget_value
{
Lisp_Object lname;
char* name;
char* value;
Lisp_Object lkey;
char* key;
Lisp_Object help;
Boolean enabled;
Boolean selected;
enum button_type button_type;
Boolean title;
#if 0
Boolean edited;
change_type change;
change_type this_one_change;
#endif
struct _widget_value* contents;
XtPointer call_data;
struct _widget_value* next;
#if 0
void* toolkit_data;
Boolean free_toolkit_data;
struct _widget_value *free_list;
#endif
} widget_value;
#define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
0, (sizeof (widget_value)))
#define free_widget_value(wv) xfree (wv)
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
Lisp_Object Qdebug_on_next_call;
extern Lisp_Object Vmenu_updating_frame;
extern Lisp_Object Qmenu_bar, Qmac_apple_event;
extern Lisp_Object QCtoggle, QCradio;
extern Lisp_Object Voverriding_local_map;
extern Lisp_Object Voverriding_local_map_menu_flag;
extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
extern Lisp_Object Qmenu_bar_update_hook;
void set_frame_menubar P_ ((FRAME_PTR, int, int));
#if TARGET_API_MAC_CARBON
#define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str)
#else
#define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str)
#endif
static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
Lisp_Object, Lisp_Object, Lisp_Object,
Lisp_Object, Lisp_Object));
#ifdef HAVE_DIALOGS
static Lisp_Object mac_dialog_show P_ ((FRAME_PTR, int, Lisp_Object,
Lisp_Object, char **));
#endif
static Lisp_Object mac_menu_show P_ ((struct frame *, int, int, int, int,
Lisp_Object, char **));
static void keymap_panes P_ ((Lisp_Object *, int, int));
static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
int, int));
static void list_of_panes P_ ((Lisp_Object));
static void list_of_items P_ ((Lisp_Object));
static void find_and_call_menu_selection P_ ((FRAME_PTR, int, Lisp_Object,
void *));
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_ ((enum mac_menu_kind, int));
#define MENU_ITEMS_PANE_NAME 1
#define MENU_ITEMS_PANE_PREFIX 2
#define MENU_ITEMS_PANE_LENGTH 3
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;
static int menu_items_allocated;
static int menu_items_used;
static int menu_items_n_panes;
static int menu_items_submenu_depth;
static int popup_activated_flag;
int pending_menu_activation;
static void
init_menu_items ()
{
if (NILP (menu_items))
{
menu_items_allocated = 60;
menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil);
}
menu_items_used = 0;
menu_items_n_panes = 0;
menu_items_submenu_depth = 0;
}
static void
finish_menu_items ()
{
}
static void
discard_menu_items ()
{
if (menu_items_allocated > 200)
{
menu_items = Qnil;
menu_items_allocated = 0;
}
}
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;
}
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;
}
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));
}
static void
push_submenu_start ()
{
if (menu_items_used + 1 > menu_items_allocated)
grow_menu_items ();
XVECTOR (menu_items)->contents[menu_items_used++] = Qnil;
menu_items_submenu_depth++;
}
static void
push_submenu_end ()
{
if (menu_items_used + 1 > menu_items_allocated)
grow_menu_items ();
XVECTOR (menu_items)->contents[menu_items_used++] = Qlambda;
menu_items_submenu_depth--;
}
static void
push_left_right_boundary ()
{
if (menu_items_used + 1 > menu_items_allocated)
grow_menu_items ();
XVECTOR (menu_items)->contents[menu_items_used++] = Qquote;
}
static void
push_menu_pane (name, prefix_vec)
Lisp_Object name, prefix_vec;
{
if (menu_items_used + MENU_ITEMS_PANE_LENGTH > menu_items_allocated)
grow_menu_items ();
if (menu_items_submenu_depth == 0)
menu_items_n_panes++;
XVECTOR (menu_items)->contents[menu_items_used++] = Qt;
XVECTOR (menu_items)->contents[menu_items_used++] = name;
XVECTOR (menu_items)->contents[menu_items_used++] = prefix_vec;
}
static void
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++] = name;
XVECTOR (menu_items)->contents[menu_items_used++] = enable;
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;
}
static void
keymap_panes (keymaps, nmaps, notreal)
Lisp_Object *keymaps;
int nmaps;
int notreal;
{
int mapno;
init_menu_items ();
for (mapno = 0; mapno < nmaps; mapno++)
single_keymap_panes (keymaps[mapno],
Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10);
finish_menu_items ();
}
struct skp
{
Lisp_Object pending_maps;
int maxdepth, notreal;
};
static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
void *));
static void
single_keymap_panes (keymap, pane_name, prefix, notreal, maxdepth)
Lisp_Object keymap;
Lisp_Object pane_name;
Lisp_Object prefix;
int notreal;
int maxdepth;
{
struct skp skp;
struct gcpro gcpro1;
skp.pending_maps = Qnil;
skp.maxdepth = maxdepth;
skp.notreal = notreal;
if (maxdepth <= 0)
return;
push_menu_pane (pane_name, prefix);
GCPRO1 (skp.pending_maps);
map_keymap (keymap, single_menu_item, Qnil, &skp, 1);
UNGCPRO;
while (CONSP (skp.pending_maps))
{
Lisp_Object elt, eltcdr, string;
elt = XCAR (skp.pending_maps);
eltcdr = XCDR (elt);
string = XCAR (eltcdr);
single_keymap_panes (Fcar (elt), string,
XCDR (eltcdr), notreal, maxdepth - 1);
skp.pending_maps = XCDR (skp.pending_maps);
}
}
static void
single_menu_item (key, item, dummy, skp_v)
Lisp_Object key, item, dummy;
void *skp_v;
{
Lisp_Object map, item_string, enabled;
struct gcpro gcpro1, gcpro2;
int res;
struct skp *skp = skp_v;
GCPRO2 (key, item);
res = parse_menu_item (item, skp->notreal, 0);
UNGCPRO;
if (!res)
return;
map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP];
if (skp->notreal)
{
if (!NILP (map))
single_keymap_panes (map, Qnil, key, 1, skp->maxdepth - 1);
return;
}
enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
if (!NILP (map) && SREF (item_string, 0) == '@')
{
if (!NILP (enabled))
skp->pending_maps = Fcons (Fcons (map, Fcons (item_string, key)),
skp->pending_maps);
return;
}
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_TYPE],
XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED],
XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]);
if (! (NILP (map) || NILP (enabled)))
{
push_submenu_start ();
single_keymap_panes (map, Qnil, key, 0, skp->maxdepth - 1);
push_submenu_end ();
}
}
static void
list_of_panes (menu)
Lisp_Object menu;
{
Lisp_Object tail;
init_menu_items ();
for (tail = menu; CONSP (tail); tail = XCDR (tail))
{
Lisp_Object elt, pane_name, pane_data;
elt = XCAR (tail);
pane_name = Fcar (elt);
CHECK_STRING (pane_name);
push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil);
pane_data = Fcdr (elt);
CHECK_CONS (pane_data);
list_of_items (pane_data);
}
finish_menu_items ();
}
static void
list_of_items (pane)
Lisp_Object pane;
{
Lisp_Object tail, item, item1;
for (tail = pane; CONSP (tail); tail = XCDR (tail))
{
item = XCAR (tail);
if (STRINGP (item))
push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt,
Qnil, Qnil, Qnil, Qnil);
else if (CONSP (item))
{
item1 = XCAR (item);
CHECK_STRING (item1);
push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item),
Qt, Qnil, Qnil, Qnil, Qnil);
}
else
push_left_right_boundary ();
}
}
static Lisp_Object
cleanup_popup_menu (arg)
Lisp_Object arg;
{
discard_menu_items ();
return Qnil;
}
DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
doc: )
(position, menu)
Lisp_Object position, menu;
{
Lisp_Object keymap, tem;
int xpos = 0, ypos = 0;
Lisp_Object title;
char *error_name = NULL;
Lisp_Object selection;
FRAME_PTR f = NULL;
Lisp_Object x, y, window;
int keymaps = 0;
int for_click = 0;
int specpdl_count = SPECPDL_INDEX ();
struct gcpro gcpro1;
#ifdef HAVE_MENUS
if (! NILP (position))
{
check_mac ();
if (EQ (position, Qt)
|| (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
|| EQ (XCAR (position), Qtool_bar)
|| EQ (XCAR (position), Qmac_apple_event))))
{
FRAME_PTR new_f = SELECTED_FRAME ();
Lisp_Object bar_window;
enum scroll_bar_part part;
unsigned long time;
if (mouse_position_hook)
(*mouse_position_hook) (&new_f, 1, &bar_window,
&part, &x, &y, &time);
if (new_f != 0)
XSETFRAME (window, new_f);
else
{
window = selected_window;
XSETFASTINT (x, 0);
XSETFASTINT (y, 0);
}
}
else
{
tem = Fcar (position);
if (CONSP (tem))
{
window = Fcar (Fcdr (position));
x = XCAR (tem);
y = Fcar (XCDR (tem));
}
else
{
for_click = 1;
tem = Fcar (Fcdr (position));
window = Fcar (tem);
tem = Fcar (Fcdr (Fcdr (tem)));
x = Fcar (tem);
y = Fcdr (tem);
}
}
CHECK_NUMBER (x);
CHECK_NUMBER (y);
if (FRAMEP (window))
{
f = XFRAME (window);
xpos = 0;
ypos = 0;
}
else if (WINDOWP (window))
{
CHECK_LIVE_WINDOW (window);
f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
xpos = WINDOW_LEFT_EDGE_X (XWINDOW (window));
ypos = WINDOW_TOP_EDGE_Y (XWINDOW (window));
}
else
CHECK_WINDOW (window);
xpos += XINT (x);
ypos += XINT (y);
XSETFRAME (Vmenu_updating_frame, f);
}
else
Vmenu_updating_frame = Qnil;
#endif
title = Qnil;
GCPRO1 (title);
keymap = get_keymap (menu, 0, 0);
if (CONSP (keymap))
{
Lisp_Object prompt;
keymap_panes (&menu, 1, NILP (position));
prompt = Fkeymap_prompt (keymap);
if (NILP (title) && !NILP (prompt))
title = prompt;
if (!NILP (prompt) && menu_items_n_panes >= 0)
XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = prompt;
keymaps = 1;
}
else if (CONSP (menu) && KEYMAPP (XCAR (menu)))
{
int nmaps = XFASTINT (Flength (menu));
Lisp_Object *maps
= (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
int i;
title = Qnil;
for (tem = menu, i = 0; CONSP (tem); tem = XCDR (tem))
{
Lisp_Object prompt;
maps[i++] = keymap = get_keymap (XCAR (tem), 1, 0);
prompt = Fkeymap_prompt (keymap);
if (NILP (title) && !NILP (prompt))
title = prompt;
}
keymap_panes (maps, nmaps, NILP (position));
if (!NILP (title) && menu_items_n_panes >= 0)
XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
keymaps = 1;
}
else
{
title = Fcar (menu);
CHECK_STRING (title);
list_of_panes (Fcdr (menu));
keymaps = 0;
}
if (NILP (position))
{
discard_menu_items ();
UNGCPRO;
return Qnil;
}
#ifdef HAVE_MENUS
record_unwind_protect (cleanup_popup_menu, Qnil);
BLOCK_INPUT;
selection = mac_menu_show (f, xpos, ypos, for_click,
keymaps, title, &error_name);
UNBLOCK_INPUT;
unbind_to (specpdl_count, Qnil);
UNGCPRO;
#endif
if (error_name) error (error_name);
return selection;
}
#ifdef HAVE_MENUS
#ifdef MAC_OSX
static Boolean
mac_dialog_modal_filter (dialog, event, item_hit)
DialogRef dialog;
EventRecord *event;
DialogItemIndex *item_hit;
{
Boolean result;
result = StdFilterProc (dialog, event, item_hit);
if (result == false
&& (event->what == keyDown || event->what == autoKey)
&& ((event->message & charCodeMask) == kEscapeCharCode
|| mac_quit_char_key_p (event->modifiers,
(event->message & keyCodeMask) >> 8)))
{
*item_hit = kStdCancelItemIndex;
return true;
}
return result;
}
#endif
DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
doc: )
(position, contents, header)
Lisp_Object position, contents, header;
{
FRAME_PTR f = NULL;
Lisp_Object window;
check_mac ();
if (EQ (position, Qt)
|| (CONSP (position) && (EQ (XCAR (position), Qmenu_bar)
|| EQ (XCAR (position), Qtool_bar)
|| EQ (XCAR (position), Qmac_apple_event))))
{
#if 0
FRAME_PTR new_f = SELECTED_FRAME ();
Lisp_Object bar_window;
enum scroll_bar_part part;
unsigned long 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;
tem = Fcar (position);
if (CONSP (tem))
window = Fcar (Fcdr (position));
else
{
tem = Fcar (Fcdr (position));
window = Fcar (tem);
}
}
else if (WINDOWP (position) || FRAMEP (position))
window = position;
else
window = Qnil;
if (FRAMEP (window))
f = XFRAME (window);
else if (WINDOWP (window))
{
CHECK_LIVE_WINDOW (window);
f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
}
else
CHECK_WINDOW (window);
#ifdef MAC_OSX
if (EQ (position, Qt)
&& STRINGP (Fcar (contents))
&& ((!NILP (Fequal (XCDR (contents),
Fcons (Fcons (build_string ("OK"), Qt), Qnil)))
&& EQ (header, Qt))
|| (!NILP (Fequal (XCDR (contents),
Fcons (Fcons (build_string ("Yes"), Qt),
Fcons (Fcons (build_string ("No"), Qnil),
Qnil))))
&& NILP (header))))
{
OSStatus err = noErr;
AlertStdCFStringAlertParamRec param;
CFStringRef error_string, explanation_string;
DialogRef alert;
DialogItemIndex item_hit;
Lisp_Object tem;
Fredisplay (Qt);
tem = Fstring_match (concat3 (build_string ("\\("),
call0 (intern ("sentence-end")),
build_string ("\\)\n")),
XCAR (contents), Qnil);
BLOCK_INPUT;
if (NILP (tem))
{
error_string = cfstring_create_with_string (XCAR (contents));
if (error_string == NULL)
err = memFullErr;
explanation_string = NULL;
}
else
{
tem = Fmatch_end (make_number (1));
error_string =
cfstring_create_with_string (Fsubstring (XCAR (contents),
make_number (0), tem));
if (error_string == NULL)
err = memFullErr;
else
{
XSETINT (tem, XINT (tem) + 1);
explanation_string =
cfstring_create_with_string (Fsubstring (XCAR (contents),
tem, Qnil));
if (explanation_string == NULL)
{
CFRelease (error_string);
err = memFullErr;
}
}
}
if (err == noErr)
err = GetStandardAlertDefaultParams (¶m,
kStdCFStringAlertVersionOne);
if (err == noErr)
{
param.movable = true;
param.position = kWindowAlertPositionParentWindow;
if (NILP (header))
{
param.defaultText = CFSTR ("Yes");
param.otherText = CFSTR ("No");
#if 0
param.cancelText = CFSTR ("Cancel");
param.cancelButton = kAlertStdAlertCancelButton;
#endif
}
err = CreateStandardAlert (kAlertNoteAlert, error_string,
explanation_string, ¶m, &alert);
CFRelease (error_string);
if (explanation_string)
CFRelease (explanation_string);
}
if (err == noErr)
err = RunStandardAlert (alert, mac_dialog_modal_filter, &item_hit);
UNBLOCK_INPUT;
if (err == noErr)
{
if (item_hit == kStdCancelItemIndex)
Fsignal (Qquit, Qnil);
else if (item_hit == kStdOkItemIndex)
return Qt;
else
return Qnil;
}
}
#endif
#ifndef HAVE_DIALOGS
{
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
{
Lisp_Object title;
char *error_name;
Lisp_Object selection;
int specpdl_count = SPECPDL_INDEX ();
title = Fcar (contents);
CHECK_STRING (title);
list_of_panes (Fcons (contents, Qnil));
record_unwind_protect (cleanup_popup_menu, Qnil);
BLOCK_INPUT;
selection = mac_dialog_show (f, 0, title, header, &error_name);
UNBLOCK_INPUT;
unbind_to (specpdl_count, Qnil);
if (error_name) error (error_name);
return selection;
}
#endif
}
void
x_activate_menubar (f)
FRAME_PTR f;
{
SInt32 menu_choice;
SInt16 menu_id, menu_item;
extern Point saved_menu_event_location;
set_frame_menubar (f, 0, 1);
BLOCK_INPUT;
popup_activated_flag = 1;
menu_choice = MenuSelect (saved_menu_event_location);
popup_activated_flag = 0;
menu_id = HiWord (menu_choice);
menu_item = LoWord (menu_choice);
#if !TARGET_API_MAC_CARBON
if (menu_id == min_menu_id[MAC_MENU_M_APPLE])
do_apple_menu (menu_item);
else
#endif
if (menu_id)
{
MenuHandle menu = GetMenuHandle (menu_id);
if (menu)
{
UInt32 refcon;
GetMenuItemRefCon (menu, menu_item, &refcon);
find_and_call_menu_selection (f, f->menu_bar_items_used,
f->menu_bar_vector, (void *) refcon);
}
}
HiliteMenu (0);
UNBLOCK_INPUT;
}
static void
find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data)
FRAME_PTR f;
int menu_bar_items_used;
Lisp_Object vector;
void *client_data;
{
Lisp_Object prefix, entry;
Lisp_Object *subprefix_stack;
int submenu_depth = 0;
int i;
entry = Qnil;
subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object));
prefix = Qnil;
i = 0;
while (i < menu_bar_items_used)
{
if (EQ (XVECTOR (vector)->contents[i], Qnil))
{
subprefix_stack[submenu_depth++] = prefix;
prefix = entry;
i++;
}
else if (EQ (XVECTOR (vector)->contents[i], Qlambda))
{
prefix = subprefix_stack[--submenu_depth];
i++;
}
else if (EQ (XVECTOR (vector)->contents[i], Qt))
{
prefix = XVECTOR (vector)->contents[i + MENU_ITEMS_PANE_PREFIX];
i += MENU_ITEMS_PANE_LENGTH;
}
else
{
entry = XVECTOR (vector)->contents[i + MENU_ITEMS_ITEM_VALUE];
if ((int) (EMACS_INT) client_data == i)
{
int j;
struct input_event buf;
Lisp_Object frame;
EVENT_INIT (buf);
XSETFRAME (frame, f);
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 = frame;
buf.arg = subprefix_stack[j];
kbd_buffer_store_event (&buf);
}
if (!NILP (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 = frame;
buf.arg = entry;
kbd_buffer_store_event (&buf);
return;
}
i += MENU_ITEMS_ITEM_LENGTH;
}
}
}
widget_value *
xmalloc_widget_value ()
{
widget_value *value;
BLOCK_INPUT;
value = malloc_widget_value ();
UNBLOCK_INPUT;
return value;
}
void
free_menubar_widget_value_tree (wv)
widget_value *wv;
{
if (! wv) return;
wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
if (wv->contents && (wv->contents != (widget_value*)1))
{
free_menubar_widget_value_tree (wv->contents);
wv->contents = (widget_value *) 0xDEADBEEF;
}
if (wv->next)
{
free_menubar_widget_value_tree (wv->next);
wv->next = (widget_value *) 0xDEADBEEF;
}
BLOCK_INPUT;
free_widget_value (wv);
UNBLOCK_INPUT;
}
static int
parse_single_submenu (item_key, item_name, maps)
Lisp_Object item_key, item_name, maps;
{
Lisp_Object length;
int len;
Lisp_Object *mapvec;
int i;
int top_level_items = 0;
length = Flength (maps);
len = XINT (length);
mapvec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
for (i = 0; i < len; i++)
{
mapvec[i] = Fcar (maps);
maps = Fcdr (maps);
}
for (i = 0; i < len; i++)
{
if (!KEYMAPP (mapvec[i]))
{
top_level_items = 1;
push_menu_pane (Qnil, Qnil);
push_menu_item (item_name, Qt, item_key, mapvec[i],
Qnil, Qnil, Qnil, Qnil);
}
else
{
Lisp_Object prompt;
prompt = Fkeymap_prompt (mapvec[i]);
single_keymap_panes (mapvec[i],
!NILP (prompt) ? prompt : item_name,
item_key, 0, 10);
}
}
return top_level_items;
}
static widget_value *
digest_single_submenu (start, end, top_level_items)
int start, end, top_level_items;
{
widget_value *wv, *prev_wv, *save_wv, *first_wv;
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 *));
wv = xmalloc_widget_value ();
wv->name = "menu";
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
wv->help = Qnil;
first_wv = wv;
save_wv = 0;
prev_wv = 0;
i = start;
while (i < end)
{
if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
{
submenu_stack[submenu_depth++] = save_wv;
save_wv = prev_wv;
prev_wv = 0;
i++;
}
else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
{
prev_wv = save_wv;
save_wv = submenu_stack[--submenu_depth];
i++;
}
else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
&& submenu_depth != 0)
i += MENU_ITEMS_PANE_LENGTH;
else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
i += 1;
else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
{
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];
#ifndef HAVE_MULTILINGUAL_MENU
if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name))
{
pane_name = ENCODE_MENU_STRING (pane_name);
AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
}
#endif
pane_string = (NILP (pane_name)
? "" : (char *) SDATA (pane_name));
if (menu_items_n_panes == 1)
pane_string = "";
if (strcmp (pane_string, ""))
{
wv = xmalloc_widget_value ();
if (save_wv)
save_wv->next = wv;
else
first_wv->contents = wv;
wv->lname = pane_name;
wv->value = (char *)1;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
wv->help = Qnil;
save_wv = wv;
}
else
save_wv = first_wv;
prev_wv = 0;
i += MENU_ITEMS_PANE_LENGTH;
}
else
{
Lisp_Object item_name, enable, descrip, def, type, selected;
Lisp_Object help;
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);
def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
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))
{
item_name = ENCODE_MENU_STRING (item_name);
AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
}
if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
{
descrip = ENCODE_MENU_STRING (descrip);
AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
}
#endif
wv = xmalloc_widget_value ();
if (prev_wv)
prev_wv->next = wv;
else
save_wv->contents = wv;
wv->lname = item_name;
if (!NILP (descrip))
wv->lkey = descrip;
wv->value = 0;
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))
help = Qnil;
wv->help = help;
prev_wv = wv;
i += MENU_ITEMS_ITEM_LENGTH;
}
}
if (top_level_items && first_wv->contents && first_wv->contents->next == 0)
{
wv = first_wv->contents;
free_widget_value (first_wv);
return wv;
}
return first_wv;
}
static void
update_submenu_strings (first_wv)
widget_value *first_wv;
{
widget_value *wv;
for (wv = first_wv; wv; wv = wv->next)
{
if (STRINGP (wv->lname))
{
wv->name = SDATA (wv->lname);
if (wv->value == (char *)1)
{
if (wv->name[0] == '@')
wv->name++;
wv->value = 0;
}
}
if (STRINGP (wv->lkey))
wv->key = SDATA (wv->lkey);
if (wv->contents)
update_submenu_strings (wv->contents);
}
}
#if TARGET_API_MAC_CARBON
extern Lisp_Object Vshow_help_function;
static Lisp_Object
restore_show_help_function (old_show_help_function)
Lisp_Object old_show_help_function;
{
Vshow_help_function = old_show_help_function;
return Qnil;
}
static pascal OSStatus
menu_target_item_handler (next_handler, event, data)
EventHandlerCallRef next_handler;
EventRef event;
void *data;
{
OSStatus err, result;
MenuRef menu;
MenuItemIndex menu_item;
Lisp_Object help;
GrafPtr port;
int specpdl_count = SPECPDL_INDEX ();
result = CallNextEventHandler (next_handler, event);
err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef,
NULL, sizeof (MenuRef), NULL, &menu);
if (err == noErr)
err = GetEventParameter (event, kEventParamMenuItemIndex,
typeMenuItemIndex, NULL,
sizeof (MenuItemIndex), NULL, &menu_item);
if (err == noErr)
err = GetMenuItemProperty (menu, menu_item,
MAC_EMACS_CREATOR_CODE, 'help',
sizeof (Lisp_Object), NULL, &help);
if (err != noErr)
help = Qnil;
record_unwind_protect (restore_show_help_function, Vshow_help_function);
Vshow_help_function = Qnil;
GetPort (&port);
show_help_echo (help, Qnil, Qnil, Qnil, 1);
SetPort (port);
unbind_to (specpdl_count, Qnil);
return err == noErr ? noErr : result;
}
#endif
OSStatus
install_menu_target_item_handler (window)
WindowPtr window;
{
OSStatus err = noErr;
#if TARGET_API_MAC_CARBON
static const EventTypeSpec specs[] =
{{kEventClassMenu, kEventMenuTargetItem}};
static EventHandlerUPP menu_target_item_handlerUPP = NULL;
if (menu_target_item_handlerUPP == NULL)
menu_target_item_handlerUPP =
NewEventHandlerUPP (menu_target_item_handler);
err = InstallWindowEventHandler (window, menu_target_item_handlerUPP,
GetEventTypeCount (specs), specs,
NULL, NULL);
#endif
return err;
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
static pascal OSStatus
menu_quit_handler (nextHandler, theEvent, userData)
EventHandlerCallRef nextHandler;
EventRef theEvent;
void* userData;
{
OSStatus err;
UInt32 keyCode;
UInt32 keyModifiers;
err = GetEventParameter (theEvent, kEventParamKeyCode,
typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
if (err == noErr)
err = GetEventParameter (theEvent, kEventParamKeyModifiers,
typeUInt32, NULL, sizeof(UInt32),
NULL, &keyModifiers);
if (err == noErr && mac_quit_char_key_p (keyModifiers, keyCode))
{
MenuRef menu = userData != 0
? (MenuRef)userData : AcquireRootMenu ();
CancelMenuTracking (menu, true, 0);
if (!userData) ReleaseMenu (menu);
return noErr;
}
return CallNextEventHandler (nextHandler, theEvent);
}
#endif
static void
install_menu_quit_handler (kind, menu_handle)
enum mac_menu_kind kind;
MenuHandle menu_handle;
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
static const EventTypeSpec typesList[] =
{{kEventClassKeyboard, kEventRawKeyDown}};
int id;
#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
if (CancelMenuTracking == NULL)
return;
#endif
for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++)
{
MenuHandle menu = GetMenuHandle (id);
if (menu == NULL)
break;
InstallMenuEventHandler (menu, menu_quit_handler,
GetEventTypeCount (typesList),
typesList, menu_handle, NULL);
}
#endif
}
void
set_frame_menubar (f, first_time, deep_p)
FRAME_PTR f;
int first_time;
int deep_p;
{
int menubar_widget = f->output_data.mac->menubar_widget;
Lisp_Object items;
widget_value *wv, *first_wv, *prev_wv = 0;
int i, last_i = 0;
int *submenu_start, *submenu_end;
int *submenu_top_level_items, *submenu_n_panes;
XSETFRAME (Vmenu_updating_frame, f);
if (! menubar_widget)
deep_p = 1;
else if (pending_menu_activation && !deep_p)
deep_p = 1;
if (deep_p)
{
struct buffer *prev = current_buffer;
Lisp_Object buffer;
int specpdl_count = SPECPDL_INDEX ();
int previous_menu_items_used = f->menu_bar_items_used;
Lisp_Object *previous_items
= (Lisp_Object *) alloca (previous_menu_items_used
* sizeof (Lisp_Object));
if (! menubar_widget)
previous_menu_items_used = 0;
buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer;
specbind (Qinhibit_quit, Qt);
specbind (Qdebug_on_next_call, Qnil);
record_unwind_save_match_data ();
if (NILP (Voverriding_local_map_menu_flag))
{
specbind (Qoverriding_terminal_local_map, Qnil);
specbind (Qoverriding_local_map, Qnil);
}
set_buffer_internal_1 (XBUFFER (buffer));
safe_run_hooks (Qactivate_menubar_hook);
if (! NILP (Vlucid_menu_bar_dirty_flag))
call0 (Qrecompute_lucid_menubar);
safe_run_hooks (Qmenu_bar_update_hook);
FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
items = FRAME_MENU_BAR_ITEMS (f);
if (previous_menu_items_used)
bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items,
previous_menu_items_used * sizeof (Lisp_Object));
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 *));
submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *));
submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int));
submenu_top_level_items
= (int *) alloca (XVECTOR (items)->size * sizeof (int *));
init_menu_items ();
for (i = 0; i < XVECTOR (items)->size; i += 4)
{
Lisp_Object key, string, maps;
last_i = i;
key = XVECTOR (items)->contents[i];
string = XVECTOR (items)->contents[i + 1];
maps = XVECTOR (items)->contents[i + 2];
if (NILP (string))
break;
submenu_start[i] = menu_items_used;
menu_items_n_panes = 0;
submenu_top_level_items[i]
= parse_single_submenu (key, string, maps);
submenu_n_panes[i] = menu_items_n_panes;
submenu_end[i] = menu_items_used;
}
finish_menu_items ();
wv = xmalloc_widget_value ();
wv->name = "menubar";
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
wv->help = Qnil;
first_wv = wv;
for (i = 0; i < last_i; i += 4)
{
menu_items_n_panes = submenu_n_panes[i];
wv = digest_single_submenu (submenu_start[i], submenu_end[i],
submenu_top_level_items[i]);
if (prev_wv)
prev_wv->next = wv;
else
first_wv->contents = wv;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
prev_wv = wv;
}
set_buffer_internal_1 (prev);
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)
{
free_menubar_widget_value_tree (first_wv);
discard_menu_items ();
unbind_to (specpdl_count, Qnil);
return;
}
f->menu_bar_vector = menu_items;
f->menu_bar_items_used = menu_items_used;
unbind_to (specpdl_count, Qnil);
wv = first_wv->contents;
for (i = 0; i < XVECTOR (items)->size; i += 4)
{
Lisp_Object string;
string = XVECTOR (items)->contents[i + 1];
if (NILP (string))
break;
wv->name = (char *) SDATA (string);
update_submenu_strings (wv->contents);
wv = wv->next;
}
}
else
{
wv = xmalloc_widget_value ();
wv->name = "menubar";
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
wv->help = Qnil;
first_wv = wv;
items = FRAME_MENU_BAR_ITEMS (f);
for (i = 0; i < XVECTOR (items)->size; i += 4)
{
Lisp_Object string;
string = XVECTOR (items)->contents[i + 1];
if (NILP (string))
break;
wv = xmalloc_widget_value ();
wv->name = (char *) SDATA (string);
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
wv->help = Qnil;
wv->call_data = (void *) (EMACS_INT) (-1);
if (prev_wv)
prev_wv->next = wv;
else
first_wv->contents = wv;
prev_wv = wv;
}
f->menu_bar_items_used = 0;
}
BLOCK_INPUT;
f->output_data.mac->menubar_widget = 1;
fill_menubar (first_wv->contents, deep_p);
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;
}
void
free_frame_menubar (f)
FRAME_PTR f;
{
f->output_data.mac->menubar_widget = 0;
}
static Lisp_Object
pop_down_menu (arg)
Lisp_Object arg;
{
struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
FRAME_PTR f = p->pointer;
MenuHandle menu = GetMenuHandle (min_menu_id[MAC_MENU_POPUP]);
BLOCK_INPUT;
FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0;
dispose_menus (MAC_MENU_POPUP_SUB, 0);
DeleteMenu (min_menu_id[MAC_MENU_POPUP]);
DisposeMenu (menu);
UNBLOCK_INPUT;
return Qnil;
}
static Lisp_Object
mac_menu_show (f, x, y, for_click, keymaps, title, error)
FRAME_PTR f;
int x;
int y;
int for_click;
int keymaps;
Lisp_Object title;
char **error;
{
int i;
int menu_item_choice;
UInt32 menu_item_selection;
MenuHandle menu;
Point pos;
widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
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));
int submenu_depth = 0;
int first_pane;
int specpdl_count = SPECPDL_INDEX ();
*error = NULL;
if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
{
*error = "Empty menu";
return Qnil;
}
wv = xmalloc_widget_value ();
wv->name = "menu";
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
wv->help = Qnil;
first_wv = wv;
first_pane = 1;
i = 0;
while (i < menu_items_used)
{
if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
{
submenu_stack[submenu_depth++] = save_wv;
save_wv = prev_wv;
prev_wv = 0;
first_pane = 1;
i++;
}
else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
{
prev_wv = save_wv;
save_wv = submenu_stack[--submenu_depth];
first_pane = 0;
i++;
}
else if (EQ (XVECTOR (menu_items)->contents[i], Qt)
&& submenu_depth != 0)
i += MENU_ITEMS_PANE_LENGTH;
else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
i += 1;
else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
{
Lisp_Object pane_name, prefix;
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))
{
pane_name = ENCODE_MENU_STRING (pane_name);
AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name;
}
#endif
pane_string = (NILP (pane_name)
? "" : (char *) SDATA (pane_name));
if (menu_items_n_panes == 1)
pane_string = "";
if (!keymaps && strcmp (pane_string, ""))
{
wv = xmalloc_widget_value ();
if (save_wv)
save_wv->next = wv;
else
first_wv->contents = wv;
wv->name = pane_string;
if (keymaps && !NILP (prefix))
wv->name++;
wv->value = 0;
wv->enabled = 1;
wv->button_type = BUTTON_TYPE_NONE;
wv->help = Qnil;
save_wv = wv;
prev_wv = 0;
}
else if (first_pane)
{
save_wv = wv;
prev_wv = 0;
}
first_pane = 0;
i += MENU_ITEMS_PANE_LENGTH;
}
else
{
Lisp_Object item_name, enable, descrip, def, type, selected, help;
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);
def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION);
type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE);
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))
{
item_name = ENCODE_MENU_STRING (item_name);
AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name;
}
if (STRINGP (descrip) && STRING_MULTIBYTE (descrip))
{
descrip = ENCODE_MENU_STRING (descrip);
AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip;
}
#endif
wv = xmalloc_widget_value ();
if (prev_wv)
prev_wv->next = wv;
else
save_wv->contents = wv;
wv->name = (char *) SDATA (item_name);
if (!NILP (descrip))
wv->key = (char *) SDATA (descrip);
wv->value = 0;
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))
help = Qnil;
wv->help = help;
prev_wv = wv;
i += MENU_ITEMS_ITEM_LENGTH;
}
}
if (!NILP (title))
{
widget_value *wv_title = xmalloc_widget_value ();
widget_value *wv_sep = xmalloc_widget_value ();
wv_sep->name = "--";
wv_sep->next = first_wv->contents;
wv_sep->help = Qnil;
#ifndef HAVE_MULTILINGUAL_MENU
if (STRING_MULTIBYTE (title))
title = ENCODE_MENU_STRING (title);
#endif
wv_title->name = (char *) SDATA (title);
wv_title->enabled = FALSE;
wv_title->title = TRUE;
wv_title->button_type = BUTTON_TYPE_NONE;
wv_title->help = Qnil;
wv_title->next = wv_sep;
first_wv->contents = wv_title;
}
menu = NewMenu (min_menu_id[MAC_MENU_POPUP], "\p");
InsertMenu (menu, -1);
fill_menu (menu, first_wv->contents, MAC_MENU_POPUP_SUB,
min_menu_id[MAC_MENU_POPUP_SUB]);
free_menubar_widget_value_tree (first_wv);
pos.h = x;
pos.v = y;
SetPortWindowPort (FRAME_MAC_WINDOW (f));
LocalToGlobal (&pos);
menu_item_selection = 0;
record_unwind_protect (pop_down_menu, make_save_value (f, 0));
install_menu_quit_handler (MAC_MENU_POPUP, menu);
install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu);
popup_activated_flag = 1;
menu_item_choice = PopUpMenuSelect (menu, pos.v, pos.h, 0);
popup_activated_flag = 0;
if (menu_item_choice)
{
MenuHandle sel_menu = GetMenuHandle (HiWord (menu_item_choice));
if (sel_menu)
GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice),
&menu_item_selection);
}
unbind_to (specpdl_count, Qnil);
if (menu_item_selection != 0)
{
Lisp_Object prefix, entry;
prefix = entry = Qnil;
i = 0;
while (i < menu_items_used)
{
if (EQ (XVECTOR (menu_items)->contents[i], Qnil))
{
subprefix_stack[submenu_depth++] = prefix;
prefix = entry;
i++;
}
else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda))
{
prefix = subprefix_stack[--submenu_depth];
i++;
}
else if (EQ (XVECTOR (menu_items)->contents[i], Qt))
{
prefix
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
i += MENU_ITEMS_PANE_LENGTH;
}
else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
i += 1;
else
{
entry
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
if (menu_item_selection == i)
{
if (keymaps != 0)
{
int j;
entry = Fcons (entry, Qnil);
if (!NILP (prefix))
entry = Fcons (prefix, entry);
for (j = submenu_depth - 1; j >= 0; j--)
if (!NILP (subprefix_stack[j]))
entry = Fcons (subprefix_stack[j], entry);
}
return entry;
}
i += MENU_ITEMS_ITEM_LENGTH;
}
}
}
else if (!for_click)
Fsignal (Qquit, Qnil);
return Qnil;
}
#ifdef HAVE_DIALOGS
#if TARGET_API_MAC_CARBON
static pascal OSStatus
mac_handle_dialog_event (next_handler, event, data)
EventHandlerCallRef next_handler;
EventRef event;
void *data;
{
OSStatus err;
WindowRef window = (WindowRef) data;
switch (GetEventClass (event))
{
case kEventClassCommand:
{
HICommand command;
err = GetEventParameter (event, kEventParamDirectObject,
typeHICommand, NULL, sizeof (HICommand),
NULL, &command);
if (err == noErr)
if ((command.commandID & ~0xffff) == 'Bt\0\0')
{
SetWRefCon (window, command.commandID);
err = QuitAppModalLoopForWindow (window);
return err == noErr ? noErr : eventNotHandledErr;
}
return CallNextEventHandler (next_handler, event);
}
break;
case kEventClassKeyboard:
{
OSStatus result;
char char_code;
result = CallNextEventHandler (next_handler, event);
if (result == noErr)
return noErr;
err = GetEventParameter (event, kEventParamKeyMacCharCodes,
typeChar, NULL, sizeof (char),
NULL, &char_code);
if (err == noErr)
switch (char_code)
{
case kEscapeCharCode:
err = QuitAppModalLoopForWindow (window);
break;
default:
{
UInt32 modifiers, key_code;
err = GetEventParameter (event, kEventParamKeyModifiers,
typeUInt32, NULL, sizeof (UInt32),
NULL, &modifiers);
if (err == noErr)
err = GetEventParameter (event, kEventParamKeyCode,
typeUInt32, NULL, sizeof (UInt32),
NULL, &key_code);
if (err == noErr)
{
if (mac_quit_char_key_p (modifiers, key_code))
err = QuitAppModalLoopForWindow (window);
else
err = eventNotHandledErr;
}
}
break;
}
return err == noErr ? noErr : result;
}
break;
default:
abort ();
}
}
static OSStatus
install_dialog_event_handler (window)
WindowRef window;
{
static const EventTypeSpec specs[] =
{{kEventClassCommand, kEventCommandProcess},
{kEventClassKeyboard, kEventRawKeyDown}};
static EventHandlerUPP handle_dialog_eventUPP = NULL;
if (handle_dialog_eventUPP == NULL)
handle_dialog_eventUPP = NewEventHandlerUPP (mac_handle_dialog_event);
return InstallWindowEventHandler (window, handle_dialog_eventUPP,
GetEventTypeCount (specs), specs,
window, NULL);
}
#define DIALOG_LEFT_MARGIN (112)
#define DIALOG_TOP_MARGIN (24)
#define DIALOG_RIGHT_MARGIN (24)
#define DIALOG_BOTTOM_MARGIN (20)
#define DIALOG_MIN_INNER_WIDTH (338)
#define DIALOG_MAX_INNER_WIDTH (564)
#define DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE (12)
#define DIALOG_BUTTON_BUTTON_VERTICAL_SPACE (12)
#define DIALOG_BUTTON_MIN_WIDTH (68)
#define DIALOG_TEXT_MIN_HEIGHT (50)
#define DIALOG_TEXT_BUTTONS_VERTICAL_SPACE (10)
#define DIALOG_ICON_WIDTH (64)
#define DIALOG_ICON_HEIGHT (64)
#define DIALOG_ICON_LEFT_MARGIN (24)
#define DIALOG_ICON_TOP_MARGIN (15)
static int
create_and_show_dialog (f, first_wv)
FRAME_PTR f;
widget_value *first_wv;
{
OSStatus err;
char *dialog_name, *message;
int nb_buttons, first_group_count, i, result = 0;
widget_value *wv;
short buttons_height, text_height, inner_width, inner_height;
Rect empty_rect, *rects;
WindowRef window = NULL;
ControlRef *buttons, default_button = NULL, text;
dialog_name = first_wv->name;
nb_buttons = dialog_name[1] - '0';
first_group_count = nb_buttons - (dialog_name[4] - '0');
wv = first_wv->contents;
message = wv->value;
wv = wv->next;
SetRect (&empty_rect, 0, 0, 0, 0);
err = CreateNewWindow (kMovableModalWindowClass,
kWindowStandardHandlerAttribute,
&empty_rect, &window);
if (err == noErr)
err = SetThemeWindowBackground (window, kThemeBrushMovableModalBackground,
true);
if (err == noErr)
err = SetWindowTitleWithCFString (window, (dialog_name[0] == 'Q'
? CFSTR ("Question")
: CFSTR ("Information")));
if (err == noErr)
{
buttons = alloca (sizeof (ControlRef) * nb_buttons);
rects = alloca (sizeof (Rect) * nb_buttons);
for (i = 0; i < nb_buttons; i++)
{
CFStringRef label = cfstring_create_with_utf8_cstring (wv->value);
if (label == NULL)
err = memFullErr;
else
{
err = CreatePushButtonControl (window, &empty_rect,
label, &buttons[i]);
CFRelease (label);
}
if (err == noErr)
{
if (!wv->enabled)
{
#ifdef MAC_OSX
err = DisableControl (buttons[i]);
#else
err = DeactivateControl (buttons[i]);
#endif
}
else if (default_button == NULL)
default_button = buttons[i];
}
if (err == noErr)
{
SInt16 unused;
rects[i] = empty_rect;
err = GetBestControlRect (buttons[i], &rects[i], &unused);
}
if (err == noErr)
{
OffsetRect (&rects[i], -rects[i].left, -rects[i].top);
if (rects[i].right < DIALOG_BUTTON_MIN_WIDTH)
rects[i].right = DIALOG_BUTTON_MIN_WIDTH;
else if (rects[i].right > DIALOG_MAX_INNER_WIDTH)
rects[i].right = DIALOG_MAX_INNER_WIDTH;
err = SetControlCommandID (buttons[i],
'Bt\0\0' + (int) wv->call_data);
}
if (err != noErr)
break;
wv = wv->next;
}
}
if (err == noErr)
{
short bottom, right, max_height, left_align_shift;
inner_width = DIALOG_MIN_INNER_WIDTH;
bottom = right = max_height = 0;
for (i = 0; i < nb_buttons; i++)
{
if (right - rects[i].right < - inner_width)
{
if (i != first_group_count
&& right - rects[i].right >= - DIALOG_MAX_INNER_WIDTH)
inner_width = - (right - rects[i].right);
else
{
bottom -= max_height + DIALOG_BUTTON_BUTTON_VERTICAL_SPACE;
right = max_height = 0;
}
}
if (max_height < rects[i].bottom)
max_height = rects[i].bottom;
OffsetRect (&rects[i], right - rects[i].right,
bottom - rects[i].bottom);
right = rects[i].left - DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
if (i == first_group_count - 1)
right -= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
}
buttons_height = - (bottom - max_height);
left_align_shift = - (inner_width + rects[nb_buttons - 1].left);
for (i = nb_buttons - 1; i >= first_group_count; i--)
{
if (bottom != rects[i].bottom)
{
left_align_shift = - (inner_width + rects[i].left);
bottom = rects[i].bottom;
}
OffsetRect (&rects[i], left_align_shift, 0);
}
}
if (err == noErr)
{
CFStringRef message_string;
Rect bounds;
message_string = cfstring_create_with_utf8_cstring (message);
if (message_string == NULL)
err = memFullErr;
else
{
ControlFontStyleRec text_style;
text_style.flags = 0;
SetRect (&bounds, 0, 0, inner_width, 0);
err = CreateStaticTextControl (window, &bounds, message_string,
&text_style, &text);
CFRelease (message_string);
}
if (err == noErr)
{
SInt16 unused;
bounds = empty_rect;
err = GetBestControlRect (text, &bounds, &unused);
}
if (err == noErr)
{
text_height = bounds.bottom - bounds.top;
if (text_height < DIALOG_TEXT_MIN_HEIGHT)
text_height = DIALOG_TEXT_MIN_HEIGHT;
}
}
if (err == noErr)
{
inner_height = (text_height + DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
+ buttons_height);
for (i = 0; i < nb_buttons; i++)
{
OffsetRect (&rects[i], DIALOG_LEFT_MARGIN + inner_width,
DIALOG_TOP_MARGIN + inner_height);
SetControlBounds (buttons[i], &rects[i]);
}
}
if (err == noErr)
{
Rect bounds;
SetRect (&bounds, DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN,
DIALOG_LEFT_MARGIN + inner_width,
DIALOG_TOP_MARGIN + text_height);
SetControlBounds (text, &bounds);
}
if (err == noErr)
{
ControlButtonContentInfo content;
ControlRef icon;
static const ProcessSerialNumber psn = {0, kCurrentProcess};
#ifdef MAC_OSX
FSRef app_location;
#else
ProcessInfoRec pinfo;
FSSpec app_spec;
#endif
SInt16 unused;
content.contentType = kControlContentIconRef;
#ifdef MAC_OSX
err = GetProcessBundleLocation (&psn, &app_location);
if (err == noErr)
err = GetIconRefFromFileInfo (&app_location, 0, NULL, 0, NULL,
kIconServicesNormalUsageFlag,
&content.u.iconRef, &unused);
#else
bzero (&pinfo, sizeof (ProcessInfoRec));
pinfo.processInfoLength = sizeof (ProcessInfoRec);
pinfo.processAppSpec = &app_spec;
err = GetProcessInformation (&psn, &pinfo);
if (err == noErr)
err = GetIconRefFromFile (&app_spec, &content.u.iconRef, &unused);
#endif
if (err == noErr)
{
Rect bounds;
SetRect (&bounds, DIALOG_ICON_LEFT_MARGIN, DIALOG_ICON_TOP_MARGIN,
DIALOG_ICON_LEFT_MARGIN + DIALOG_ICON_WIDTH,
DIALOG_ICON_TOP_MARGIN + DIALOG_ICON_HEIGHT);
err = CreateIconControl (window, &bounds, &content, true, &icon);
ReleaseIconRef (content.u.iconRef);
}
}
if (err == noErr)
if (default_button)
err = SetWindowDefaultButton (window, default_button);
if (err == noErr)
err = install_dialog_event_handler (window);
if (err == noErr)
{
SizeWindow (window,
DIALOG_LEFT_MARGIN + inner_width + DIALOG_RIGHT_MARGIN,
DIALOG_TOP_MARGIN + inner_height + DIALOG_BOTTOM_MARGIN,
true);
err = RepositionWindow (window, FRAME_MAC_WINDOW (f),
kWindowAlertPositionOnParentWindow);
}
if (err == noErr)
{
SetWRefCon (window, 0);
ShowWindow (window);
BringToFront (window);
err = RunAppModalLoopForWindow (window);
}
if (err == noErr)
{
UInt32 command_id = GetWRefCon (window);
if ((command_id & ~0xffff) == 'Bt\0\0')
result = command_id - 'Bt\0\0';
}
if (window)
DisposeWindow (window);
return result;
}
#else
static int
mac_dialog (widget_value *wv)
{
char *dialog_name;
char *prompt;
char **button_labels;
UInt32 *ref_cons;
int nb_buttons;
int left_count;
int i;
int dialog_width;
Rect rect;
WindowPtr window_ptr;
ControlHandle ch;
int left;
EventRecord event_record;
SInt16 part_code;
int control_part_code;
Point mouse;
dialog_name = wv->name;
nb_buttons = dialog_name[1] - '0';
left_count = nb_buttons - (dialog_name[4] - '0');
button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons);
wv = wv->contents;
prompt = (char *) alloca (strlen (wv->value) + 1);
strcpy (prompt, wv->value);
c2pstr (prompt);
wv = wv->next;
for (i = 0; i < nb_buttons; i++)
{
button_labels[i] = wv->value;
button_labels[i] = (char *) alloca (strlen (wv->value) + 1);
strcpy (button_labels[i], wv->value);
c2pstr (button_labels[i]);
ref_cons[i] = (UInt32) wv->call_data;
wv = wv->next;
}
window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowPtr) -1);
SetPortWindowPort (window_ptr);
TextFont (0);
dialog_width = 14;
for (i = 0; i < nb_buttons; i++)
dialog_width += StringWidth (button_labels[i]) + 16 + 12;
if (left_count != 0 && nb_buttons - left_count != 0)
dialog_width += 12;
dialog_width = max (dialog_width, StringWidth (prompt) + 26);
SizeWindow (window_ptr, dialog_width, 78, 0);
ShowWindow (window_ptr);
SetPortWindowPort (window_ptr);
TextFont (0);
MoveTo (13, 29);
DrawString (prompt);
left = 13;
for (i = 0; i < nb_buttons; i++)
{
int button_width = StringWidth (button_labels[i]) + 16;
SetRect (&rect, left, 45, left + button_width, 65);
ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0,
kControlPushButtonProc, ref_cons[i]);
left += button_width + 12;
if (i == left_count - 1)
left += 12;
}
i = 0;
while (!i)
{
if (WaitNextEvent (mDownMask, &event_record, 10, NULL))
if (event_record.what == mouseDown)
{
part_code = FindWindow (event_record.where, &window_ptr);
if (part_code == inContent)
{
mouse = event_record.where;
GlobalToLocal (&mouse);
control_part_code = FindControl (mouse, window_ptr, &ch);
if (control_part_code == kControlButtonPart)
if (TrackControl (ch, mouse, NULL))
i = GetControlReference (ch);
}
}
}
DisposeWindow (window_ptr);
return i;
}
#endif
static char * button_names [] = {
"button1", "button2", "button3", "button4", "button5",
"button6", "button7", "button8", "button9", "button10" };
static Lisp_Object
mac_dialog_show (f, keymaps, title, header, error_name)
FRAME_PTR f;
int keymaps;
Lisp_Object title, header;
char **error_name;
{
int i, nb_buttons=0;
char dialog_name[6];
int menu_item_selection;
widget_value *wv, *first_wv = 0, *prev_wv = 0;
int left_count = 0;
int boundary_seen = 0;
*error_name = NULL;
if (menu_items_n_panes > 1)
{
*error_name = "Multiple panes in dialog box";
return Qnil;
}
{
Lisp_Object pane_name, prefix;
char *pane_string;
pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME];
prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX];
pane_string = (NILP (pane_name)
? "" : (char *) SDATA (pane_name));
prev_wv = xmalloc_widget_value ();
prev_wv->value = pane_string;
if (keymaps && !NILP (prefix))
prev_wv->name++;
prev_wv->enabled = 1;
prev_wv->name = "message";
prev_wv->help = Qnil;
first_wv = prev_wv;
i = MENU_ITEMS_PANE_LENGTH;
while (i < menu_items_used)
{
Lisp_Object item_name, enable, descrip;
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];
if (NILP (item_name))
{
free_menubar_widget_value_tree (first_wv);
*error_name = "Submenu in dialog items";
return Qnil;
}
if (EQ (item_name, Qquote))
{
boundary_seen = 1;
i++;
continue;
}
if (nb_buttons >= 9)
{
free_menubar_widget_value_tree (first_wv);
*error_name = "Too many dialog items";
return Qnil;
}
wv = xmalloc_widget_value ();
prev_wv->next = wv;
wv->name = (char *) button_names[nb_buttons];
if (!NILP (descrip))
wv->key = (char *) SDATA (descrip);
wv->value = (char *) SDATA (item_name);
wv->call_data = (void *) i;
wv->enabled = !NILP (enable);
wv->help = Qnil;
prev_wv = wv;
if (! boundary_seen)
left_count++;
nb_buttons++;
i += MENU_ITEMS_ITEM_LENGTH;
}
if (! boundary_seen)
left_count = nb_buttons - nb_buttons / 2;
wv = xmalloc_widget_value ();
wv->name = dialog_name;
wv->help = Qnil;
if (NILP(header))
dialog_name[0] = 'Q';
else
dialog_name[0] = 'I';
dialog_name[1] = '0' + nb_buttons;
dialog_name[2] = 'B';
dialog_name[3] = 'R';
dialog_name[4] = '0' + nb_buttons - left_count;
dialog_name[5] = 0;
wv->contents = first_wv;
first_wv = wv;
}
Fredisplay (Qt);
#if TARGET_API_MAC_CARBON
menu_item_selection = create_and_show_dialog (f, first_wv);
#else
menu_item_selection = mac_dialog (first_wv);
#endif
free_menubar_widget_value_tree (first_wv);
if (menu_item_selection != 0)
{
Lisp_Object prefix;
prefix = Qnil;
i = 0;
while (i < menu_items_used)
{
Lisp_Object entry;
if (EQ (XVECTOR (menu_items)->contents[i], Qt))
{
prefix
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX];
i += MENU_ITEMS_PANE_LENGTH;
}
else if (EQ (XVECTOR (menu_items)->contents[i], Qquote))
{
++i;
}
else
{
entry
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
if (menu_item_selection == i)
{
if (keymaps != 0)
{
entry = Fcons (entry, Qnil);
if (!NILP (prefix))
entry = Fcons (prefix, entry);
}
return entry;
}
i += MENU_ITEMS_ITEM_LENGTH;
}
}
}
else
Fsignal (Qquit, Qnil);
return Qnil;
}
#endif
static int
name_is_separator (name)
const char *name;
{
const char *start = name;
while (*name == '-') name++;
return (*name == '\0' || start + 2 == name);
}
static void
add_menu_item (menu, pos, wv)
MenuHandle menu;
int pos;
widget_value *wv;
{
#if TARGET_API_MAC_CARBON
CFStringRef item_name;
#else
Str255 item_name;
#endif
if (name_is_separator (wv->name))
AppendMenu (menu, "\p-");
else
{
AppendMenu (menu, "\pX");
#if TARGET_API_MAC_CARBON
item_name = cfstring_create_with_utf8_cstring (wv->name);
if (wv->key != NULL)
{
CFStringRef name, key;
name = item_name;
key = cfstring_create_with_utf8_cstring (wv->key);
item_name = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@ %@"),
name, key);
CFRelease (name);
CFRelease (key);
}
SetMenuItemTextWithCFString (menu, pos, item_name);
CFRelease (item_name);
if (wv->enabled)
EnableMenuItem (menu, pos);
else
DisableMenuItem (menu, pos);
if (STRINGP (wv->help))
SetMenuItemProperty (menu, pos, MAC_EMACS_CREATOR_CODE, 'help',
sizeof (Lisp_Object), &wv->help);
#else
item_name[sizeof (item_name) - 1] = '\0';
strncpy (item_name, wv->name, sizeof (item_name) - 1);
if (wv->key != NULL)
{
int len = strlen (item_name);
strncpy (item_name + len, " ", sizeof (item_name) - 1 - len);
len = strlen (item_name);
strncpy (item_name + len, wv->key, sizeof (item_name) - 1 - len);
}
c2pstr (item_name);
SetMenuItemText (menu, pos, item_name);
if (wv->enabled)
EnableItem (menu, pos);
else
DisableItem (menu, pos);
#endif
if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
wv->button_type == BUTTON_TYPE_RADIO))
SetItemMark (menu, pos, checkMark);
else
SetItemMark (menu, pos, noMark);
SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
}
}
static int
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 && 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, kind, submenu_id + 1);
}
}
return submenu_id;
}
static void
fill_menubar (wv, deep_p)
widget_value *wv;
int deep_p;
{
int id, submenu_id;
MenuHandle menu;
Str255 title;
#if !TARGET_API_MAC_CARBON
int title_changed_p = 0;
#endif
if (deep_p)
{
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
}
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';
c2pstr (title);
menu = GetMenuHandle (id);
if (menu)
{
#if TARGET_API_MAC_CARBON
Str255 old_title;
GetMenuTitle (menu, old_title);
if (!EqualString (title, old_title, false, false))
SetMenuTitle (menu, title);
#else
if (!EqualString (title, (*menu)->menuData, false, false))
{
DeleteMenu (id);
DisposeMenu (menu);
menu = NewMenu (id, title);
InsertMenu (menu, GetMenuHandle (id + 1) ? id + 1 : 0);
title_changed_p = 1;
}
#endif
}
else
{
menu = NewMenu (id, title);
InsertMenu (menu, 0);
#if !TARGET_API_MAC_CARBON
title_changed_p = 1;
#endif
}
if (wv->contents)
submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
submenu_id);
}
if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuHandle (id))
{
dispose_menus (MAC_MENU_MENU_BAR, id);
#if !TARGET_API_MAC_CARBON
title_changed_p = 1;
#endif
}
#if !TARGET_API_MAC_CARBON
if (title_changed_p)
InvalMenuBar ();
#endif
}
static void
dispose_menus (kind, id)
enum mac_menu_kind kind;
int id;
{
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);
}
}
#endif
int
popup_activated ()
{
return popup_activated_flag;
}
DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
doc: )
()
{
return Qnil;
}
void
syms_of_macmenu ()
{
staticpro (&menu_items);
menu_items = Qnil;
Qdebug_on_next_call = intern ("debug-on-next-call");
staticpro (&Qdebug_on_next_call);
defsubr (&Sx_popup_menu);
defsubr (&Smenu_or_popup_active_p);
#ifdef HAVE_MENUS
defsubr (&Sx_popup_dialog);
#endif
}