/* Contributed by Andrew Choi (akochoi@mac.com). */
#include <config.h>
-#include <signal.h>
#include <stdio.h>
#include "lisp.h"
#include "charset.h"
#include "coding.h"
-#ifndef MAC_OSX
+#if !TARGET_API_MAC_CARBON
#include <MacTypes.h>
#include <Menus.h>
#include <QuickDraw.h>
#if defined (__MRC__) || (__MSL__ >= 0x6000)
#include <ControlDefinitions.h>
#endif
-#endif /* not MAC_OSX */
+#endif /* not TARGET_API_MAC_CARBON */
/* This may include sys/types.h, and that somehow loses
if this is not done before the other system files. */
}
}
\f
+static Lisp_Object
+cleanup_popup_menu (arg)
+ Lisp_Object arg;
+{
+ discard_menu_items ();
+}
+
DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
doc: /* Pop up a deck-of-cards menu and return user's selection.
POSITION is a position specification. This is either a mouse button
int keymaps = 0;
int for_click = 0;
struct gcpro gcpro1;
+ int specpdl_count = SPECPDL_INDEX ();
+
#ifdef HAVE_MENUS
if (! NILP (position))
#ifdef HAVE_MENUS
/* Display them in a menu. */
+ record_unwind_protect (cleanup_popup_menu, Qnil);
BLOCK_INPUT;
selection = mac_menu_show (f, xpos, ypos, for_click,
keymaps, title, &error_name);
UNBLOCK_INPUT;
-
- discard_menu_items ();
+ unbind_to (specpdl_count, Qnil);
UNGCPRO;
#endif /* HAVE_MENUS */
#ifdef HAVE_MENUS
-DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0,
+DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
doc: /* Pop up a dialog box and return user's selection.
POSITION specifies which frame to use.
This is normally a mouse button event or a window or frame.
An ITEM may also be just a string--that makes a nonselectable item.
An ITEM may also be nil--that means to put all preceding items
on the left of the dialog box and all following items on the right.
-\(By default, approximately half appear on each side.) */)
- (position, contents)
- Lisp_Object position, contents;
+\(By default, approximately half appear on each side.)
+
+If HEADER is non-nil, the frame title for the box is "Information",
+otherwise it is "Question". */)
+ (position, contents, header)
+ Lisp_Object position, contents, header;
{
FRAME_PTR f = NULL;
Lisp_Object window;
/* Display them in a dialog box. */
BLOCK_INPUT;
- selection = mac_dialog_show (f, 0, title, &error_name);
+ selection = mac_dialog_show (f, 0, title, header, &error_name);
UNBLOCK_INPUT;
discard_menu_items ();
for (wv = first_wv; wv; wv = wv->next)
{
- if (wv->lname && ! NILP (wv->lname))
+ if (STRINGP (wv->lname))
{
wv->name = SDATA (wv->lname);
}
}
- if (wv->lkey && ! NILP (wv->lkey))
+ if (STRINGP (wv->lkey))
wv->key = SDATA (wv->lkey);
if (wv->contents)
}
\f
+/* Event handler function that pops down a menu on C-g. We can only pop
+ down menus if CancelMenuTracking is present (OSX 10.3 or later). */
+
+#ifdef HAVE_CANCELMENUTRACKING
+static pascal OSStatus
+menu_quit_handler (nextHandler, theEvent, userData)
+ EventHandlerCallRef nextHandler;
+ EventRef theEvent;
+ void* userData;
+{
+ 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);
+
+ GetEventParameter (theEvent, kEventParamKeyModifiers,
+ typeUInt32, NULL, sizeof(UInt32),
+ NULL, &keyModifiers);
+
+ if (keyCode == mac_quit_char_keycode
+ && keyModifiers == mac_quit_char_modifiers)
+ {
+ MenuRef menu = userData != 0
+ ? (MenuRef)userData : AcquireRootMenu ();
+
+ CancelMenuTracking (menu, true, 0);
+ if (!userData) ReleaseMenu (menu);
+ return noErr;
+ }
+
+ return CallNextEventHandler (nextHandler, theEvent);
+}
+#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.
+ If CancelMenuTracking isn't available, do nothing. */
+
+static void
+install_menu_quit_handler (MenuHandle menu_handle)
+{
+#ifdef HAVE_CANCELMENUTRACKING
+ EventHandlerUPP handler = NewEventHandlerUPP(menu_quit_handler);
+ UInt32 numTypes = 1;
+ EventTypeSpec typesList[] = { { kEventClassKeyboard, kEventRawKeyDown } };
+ int i = MIN_MENU_ID;
+ MenuHandle menu = menu_handle ? menu_handle : GetMenuHandle (i);
+
+ while (menu != NULL)
+ {
+ InstallMenuEventHandler (menu, handler, GetEventTypeCount (typesList),
+ typesList, menu_handle, NULL);
+ if (menu_handle) break;
+ menu = GetMenuHandle (++i);
+ }
+ DisposeEventHandlerUPP (handler);
+#endif /* HAVE_CANCELMENUTRACKING */
+}
+
/* Set the contents of the menubar widgets of frame F.
The argument FIRST_TIME is currently ignored;
it is set the first time this is called, from initialize_frame_menubar. */
because it is not reentrant. */
specbind (Qdebug_on_next_call, Qnil);
- record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ record_unwind_save_match_data ();
if (NILP (Voverriding_local_map_menu_flag))
{
specbind (Qoverriding_terminal_local_map, Qnil);
DrawMenuBar ();
+ /* Add event handler so we can detect C-g. */
+ install_menu_quit_handler (NULL);
free_menubar_widget_value_tree (first_wv);
UNBLOCK_INPUT;
}
\f
-/* mac_menu_show actually displays a menu using the panes and items in
+static Lisp_Object
+pop_down_menu (arg)
+ Lisp_Object arg;
+{
+ struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg));
+ struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg));
+
+ FRAME_PTR f = p1->pointer;
+ MenuHandle *menu = p2->pointer;
+
+ BLOCK_INPUT;
+
+ /* Must reset this manually because the button release event is not
+ passed to Emacs event loop. */
+ FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0;
+
+ /* delete all menus */
+ {
+ int i = MIN_POPUP_SUBMENU_ID;
+ MenuHandle submenu = GetMenuHandle (i);
+ while (submenu != NULL)
+ {
+ DeleteMenu (i);
+ DisposeMenu (submenu);
+ submenu = GetMenuHandle (++i);
+ }
+ }
+
+ DeleteMenu (POPUP_SUBMENU_ID);
+ DisposeMenu (*menu);
+
+ UNBLOCK_INPUT;
+
+ return Qnil;
+}
+
+/* Mac_menu_show actually displays a menu using the panes and items in
menu_items and returns the value selected from it; we assume input
is blocked by the caller. */
= (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
int submenu_depth = 0;
int first_pane;
+ int specpdl_count = SPECPDL_INDEX ();
*error = NULL;
title = ENCODE_MENU_STRING (title);
#endif
wv_title->name = (char *) SDATA (title);
- wv_title->enabled = TRUE;
+ wv_title->enabled = FALSE;
wv_title->title = TRUE;
wv_title->button_type = BUTTON_TYPE_NONE;
wv_title->help = Qnil;
submenu_id = MIN_POPUP_SUBMENU_ID;
fill_submenu (menu, first_wv->contents);
+ /* Free the widget_value objects we used to specify the
+ contents. */
+ free_menubar_widget_value_tree (first_wv);
+
/* Adjust coordinates to be root-window-relative. */
pos.h = x;
pos.v = y;
InsertMenu (menu, -1);
+ record_unwind_protect (pop_down_menu,
+ Fcons (make_save_value (f, 0),
+ make_save_value (&menu, 0)));
+
+ /* Add event handler so we can detect C-g. */
+ install_menu_quit_handler (menu);
+
/* Display the menu. */
menu_item_choice = PopUpMenuSelect (menu, pos.v, pos.h, 0);
menu_item_selection = LoWord (menu_item_choice);
- /* Get the refcon to find the correct item*/
+ /* Get the refcon to find the correct item */
if (menu_item_selection)
{
MenuHandle sel_menu = GetMenuHandle (HiWord (menu_item_choice));
GetMenuItemRefCon (sel_menu, menu_item_selection, &refcon);
}
}
-
-#if 0
- /* Clean up extraneous mouse events which might have been generated
- during the call. */
- discard_mouse_events ();
-#endif
-
- /* Must reset this manually because the button release event is not
- passed to Emacs event loop. */
- FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0;
-
- /* Free the widget_value objects we used to specify the
- contents. */
- free_menubar_widget_value_tree (first_wv);
-
- /* delete all menus */
- {
- int i = MIN_POPUP_SUBMENU_ID;
- MenuHandle submenu = GetMenuHandle (i);
- while (submenu != NULL)
- {
- DeleteMenu (i);
- DisposeMenu (submenu);
- submenu = GetMenuHandle (++i);
- }
- }
-
- DeleteMenu (POPUP_SUBMENU_ID);
- DisposeMenu (menu);
+ else if (! for_click)
+ /* Make "Cancel" equivalent to C-g unless this menu was popped up by
+ a mouse press. */
+ Fsignal (Qquit, Qnil);
/* Find the selected item, and its pane, to return
the proper value. */
}
}
}
+ else if (!for_click)
+ /* Make "Cancel" equivalent to C-g. */
+ Fsignal (Qquit, Qnil);
+
+ unbind_to (specpdl_count, Qnil);
return Qnil;
}
"button6", "button7", "button8", "button9", "button10" };
static Lisp_Object
-mac_dialog_show (f, keymaps, title, error)
+mac_dialog_show (f, keymaps, title, header, error)
FRAME_PTR f;
int keymaps;
- Lisp_Object title;
+ Lisp_Object title, header;
char **error;
{
int i, nb_buttons=0;
wv->name = dialog_name;
wv->help = Qnil;
+ /* Frame title: 'Q' = Question, 'I' = Information.
+ Can also have 'E' = Error if, one day, we want
+ a popup for errors. */
+ if (NILP(header))
+ dialog_name[0] = 'Q';
+ else
+ dialog_name[0] = 'I';
+
/* Dialog boxes use a really stupid name encoding
which specifies how many buttons to use
- and how many buttons are on the right.
- The Q means something also. */
- dialog_name[0] = 'Q';
+ and how many buttons are on the right. */
dialog_name[1] = '0' + nb_buttons;
dialog_name[2] = 'B';
dialog_name[3] = 'R';
int force_disable)
{
Str255 item_name;
- int pos, i;
+ int pos;
if (name_is_separator (wv->name))
AppendMenu (menu, "\p-");
item_name[255] = 0;
#if TARGET_API_MAC_CARBON
{
- CFStringRef string =
- CFStringCreateWithCString (NULL, item_name, kCFStringEncodingUTF8);
+ CFStringRef string = cfstring_create_with_utf8_cstring (item_name);
SetMenuItemTextWithCFString (menu, pos, string);
CFRelease (string);
else
SetItemMark (menu, pos, noMark);
}
- }
- SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
+ SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
+ }
if (submenu != NULL)
SetMenuItemHierarchicalID (menu, pos, submenu);