/* Menu support for GNU Emacs on Mac OS.
Copyright (C) 2000, 2001, 2002, 2003, 2004,
- 2005, 2006 Free Software Foundation, Inc.
+ 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
#include <stdio.h>
#include "lisp.h"
+#include "frame.h"
#include "termhooks.h"
#include "keyboard.h"
#include "keymap.h"
-#include "frame.h"
#include "window.h"
#include "blockinput.h"
#include "buffer.h"
#define DIALOG_WINDOW_RESOURCE 130
+#if TARGET_API_MAC_CARBON
#define HAVE_DIALOGS 1
+#endif
#undef HAVE_MULTILINGUAL_MENU
-#undef HAVE_DIALOGS /* TODO: Implement native dialogs. */
/******************************************************************/
/* Definitions copied from lwlib.h */
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 int fill_menu P_ ((MenuRef, 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));
/* Current depth within submenus. */
static int menu_items_submenu_depth;
+/* Nonzero means a menu is currently active. */
+static int popup_activated_flag;
+
/* 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.
enum scroll_bar_part part;
unsigned long time;
- if (mouse_position_hook)
- (*mouse_position_hook) (&new_f, 1, &bar_window,
+ if (FRAME_TERMINAL (new_f)->mouse_position_hook)
+ (*FRAME_TERMINAL (new_f)->mouse_position_hook) (&new_f, 1, &bar_window,
&part, &x, &y, &time);
if (new_f != 0)
XSETFRAME (window, new_f);
#ifdef HAVE_MENUS
+/* Regard ESC and C-g as Cancel even without the Cancel button. */
+
+#if 0 /* defined (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: /* Pop up a dialog box and return user's selection.
POSITION specifies which frame to use.
but I don't want to make one now. */
CHECK_WINDOW (window);
+#if 0 /* defined (MAC_OSX) */
+ /* Special treatment for Fmessage_box, Fyes_or_no_p, and Fy_or_n_p. */
+ 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;
+
+ /* Force a redisplay before showing the dialog. If a frame is
+ created just before showing the dialog, its contents may not
+ have been fully drawn. */
+ 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
/* Display a menu with these alternatives
in the middle of frame F. */
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);
#endif
if (menu_id)
{
- MenuHandle menu = GetMenuHandle (menu_id);
+ MenuRef menu = GetMenuRef (menu_id);
if (menu)
{
EventRef event;
void *data;
{
- OSStatus err, result;
+ OSStatus err;
MenuRef menu;
MenuItemIndex menu_item;
Lisp_Object help;
GrafPtr port;
int specpdl_count = SPECPDL_INDEX ();
- result = CallNextEventHandler (next_handler, event);
+ /* Don't be bothered with the overflowed toolbar items menu. */
+ if (!popup_activated ())
+ return eventNotHandledErr;
err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef,
NULL, sizeof (MenuRef), NULL, &menu);
SetPort (port);
unbind_to (specpdl_count, Qnil);
- return err == noErr ? noErr : result;
+ return err == noErr ? noErr : eventNotHandledErr;
}
-#endif
OSStatus
-install_menu_target_item_handler (window)
- WindowPtr window;
+install_menu_target_item_handler ()
{
- 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;
+ return InstallApplicationEventHandler (NewEventHandlerUPP
+ (menu_target_item_handler),
+ GetEventTypeCount (specs),
+ specs, NULL, NULL);
}
+#endif /* TARGET_API_MAC_CARBON */
/* 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). */
OSStatus err;
UInt32 keyCode;
UInt32 keyModifiers;
- extern int mac_quit_char_modifiers;
- extern int mac_quit_char_keycode;
err = GetEventParameter (theEvent, kEventParamKeyCode,
typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
typeUInt32, NULL, sizeof(UInt32),
NULL, &keyModifiers);
- if (err == noErr && keyCode == mac_quit_char_keycode
- && keyModifiers == mac_quit_char_modifiers)
+ if (err == noErr && mac_quit_char_key_p (keyModifiers, keyCode))
{
MenuRef menu = userData != 0
? (MenuRef)userData : AcquireRootMenu ();
}
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
-/* 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. */
+/* Add event handler to all menus that belong to KIND so we can detect
+ C-g. ROOT_MENU 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 (kind, menu_handle)
+install_menu_quit_handler (kind, root_menu)
enum mac_menu_kind kind;
- MenuHandle menu_handle;
+ MenuRef root_menu;
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
static const EventTypeSpec typesList[] =
#endif
for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++)
{
- MenuHandle menu = GetMenuHandle (id);
+ MenuRef menu = GetMenuRef (id);
if (menu == NULL)
break;
InstallMenuEventHandler (menu, menu_quit_handler,
GetEventTypeCount (typesList),
- typesList, menu_handle, NULL);
+ typesList, root_menu, NULL);
}
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
}
XSETFRAME (Vmenu_updating_frame, f);
+ /* This seems to be unnecessary for Carbon. */
+#if 0
if (! menubar_widget)
deep_p = 1;
else if (pending_menu_activation && !deep_p)
deep_p = 1;
+#endif
if (deep_p)
{
{
struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
FRAME_PTR f = p->pointer;
- MenuHandle menu = GetMenuHandle (min_menu_id[MAC_MENU_POPUP]);
+ MenuRef menu = GetMenuRef (min_menu_id[MAC_MENU_POPUP]);
BLOCK_INPUT;
char **error;
{
int i;
- UInt32 refcon;
int menu_item_choice;
- int menu_item_selection;
- MenuHandle menu;
- Point pos;
+ UInt32 menu_item_selection;
+ MenuRef menu;
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 *));
free_menubar_widget_value_tree (first_wv);
/* Adjust coordinates to be root-window-relative. */
- pos.h = x;
- pos.v = y;
-
- SetPortWindowPort (FRAME_MAC_WINDOW (f));
- LocalToGlobal (&pos);
+ x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
+ y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
/* No selection has been chosen yet. */
- menu_item_choice = 0;
menu_item_selection = 0;
record_unwind_protect (pop_down_menu, make_save_value (f, 0));
install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu);
/* Display the menu. */
- menu_item_choice = PopUpMenuSelect (menu, pos.v, pos.h, 0);
- menu_item_selection = LoWord (menu_item_choice);
+ popup_activated_flag = 1;
+ menu_item_choice = PopUpMenuSelect (menu, y, x, 0);
+ popup_activated_flag = 0;
/* Get the refcon to find the correct item */
- if (menu_item_selection)
+ if (menu_item_choice)
{
- MenuHandle sel_menu = GetMenuHandle (HiWord (menu_item_choice));
- if (sel_menu) {
- GetMenuItemRefCon (sel_menu, menu_item_selection, &refcon);
- }
+ MenuRef sel_menu = GetMenuRef (HiWord (menu_item_choice));
+
+ if (sel_menu)
+ GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice),
+ &menu_item_selection);
}
- else if (! for_click)
- /* Make "Cancel" equivalent to C-g unless this menu was popped up by
- a mouse press. */
- Fsignal (Qquit, Qnil);
+
+ unbind_to (specpdl_count, Qnil);
/* Find the selected item, and its pane, to return
the proper value. */
{
entry
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE];
- if ((int) (EMACS_INT) refcon == i)
+ if (menu_item_selection == i)
{
if (keymaps != 0)
{
/* Make "Cancel" equivalent to C-g. */
Fsignal (Qquit, Qnil);
- unbind_to (specpdl_count, Qnil);
-
return Qnil;
}
\f
#ifdef HAVE_DIALOGS
-/* Construct native Mac OS menubar based on widget_value tree. */
+/* Construct native Mac OS dialog based on widget_value tree. */
+
+#if TARGET_API_MAC_CARBON
+
+#define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
+#define DIALOG_BUTTON_COMMAND_ID_P(id) \
+ (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
+#define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
+ ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
+#define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
+ ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
+
+extern EMACS_TIME timer_check P_ ((int));
+static int quit_dialog_event_loop;
+
+static pascal OSStatus
+mac_handle_dialog_event (next_handler, event, data)
+ EventHandlerCallRef next_handler;
+ EventRef event;
+ void *data;
+{
+ OSStatus err, result = eventNotHandledErr;
+ 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 (DIALOG_BUTTON_COMMAND_ID_P (command.commandID))
+ {
+ SetWRefCon (window, command.commandID);
+ quit_dialog_event_loop = 1;
+ break;
+ }
+
+ result = CallNextEventHandler (next_handler, event);
+ }
+ break;
+
+ case kEventClassKeyboard:
+ {
+ OSStatus result;
+ char char_code;
+
+ result = CallNextEventHandler (next_handler, event);
+ if (result != eventNotHandledErr)
+ break;
+
+ err = GetEventParameter (event, kEventParamKeyMacCharCodes,
+ typeChar, NULL, sizeof (char),
+ NULL, &char_code);
+ if (err == noErr)
+ switch (char_code)
+ {
+ case kEscapeCharCode:
+ quit_dialog_event_loop = 1;
+ 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))
+ quit_dialog_event_loop = 1;
+ }
+ break;
+ }
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (quit_dialog_event_loop)
+ {
+ err = QuitEventLoop (GetCurrentEventLoop ());
+ if (err == noErr)
+ result = noErr;
+ }
+
+ return result;
+}
+
+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 Lisp_Object
+pop_down_dialog (arg)
+ Lisp_Object arg;
+{
+ struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
+ WindowRef window = p->pointer;
+
+ BLOCK_INPUT;
+
+ if (popup_activated_flag)
+ EndAppModalStateForWindow (window);
+ DisposeWindow (window);
+ popup_activated_flag = 0;
+
+ UNBLOCK_INPUT;
+
+ return Qnil;
+}
+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;
+ int specpdl_count = SPECPDL_INDEX ();
+
+ 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);
+
+ /* Create dialog window. */
+ err = CreateNewWindow (kMovableModalWindowClass,
+ kWindowStandardHandlerAttribute,
+ &empty_rect, &window);
+ if (err == noErr)
+ {
+ record_unwind_protect (pop_down_dialog, make_save_value (window, 0));
+ err = SetThemeWindowBackground (window, kThemeBrushMovableModalBackground,
+ true);
+ }
+ if (err == noErr)
+ err = SetWindowTitleWithCFString (window, (dialog_name[0] == 'Q'
+ ? CFSTR ("Question")
+ : CFSTR ("Information")));
+
+ /* Create button controls and measure their optimal bounds. */
+ 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)
+ {
+ UInt32 command_id;
+
+ 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;
+
+ command_id = DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv->call_data);
+ err = SetControlCommandID (buttons[i], command_id);
+ }
+ if (err != noErr)
+ break;
+ wv = wv->next;
+ }
+ }
+
+ /* Layout buttons. rects[i] is set relative to the bottom-right
+ corner of the inner box. */
+ 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);
+ }
+ }
+
+ /* Create a static text control and measure its bounds. */
+ 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;
+ }
+ }
+
+ /* Place buttons. */
+ 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]);
+ }
+ }
+
+ /* Place text. */
+ 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);
+ }
+
+ /* Create the application icon at the upper-left corner. */
+ 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);
+ }
+ }
+
+ /* Show the dialog window and run event loop. */
+ 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);
+ popup_activated_flag = 1;
+ err = BeginAppModalStateForWindow (window);
+ }
+ if (err == noErr)
+ {
+ EventTargetRef toolbox_dispatcher = GetEventDispatcherTarget ();
+
+ quit_dialog_event_loop = 0;
+ while (1)
+ {
+ EMACS_TIME next_time = timer_check (1);
+ long secs = EMACS_SECS (next_time);
+ long usecs = EMACS_USECS (next_time);
+ EventTimeout timeout;
+ EventRef event;
+
+ if (secs < 0 || (secs == 0 && usecs == 0))
+ {
+ /* Sometimes timer_check returns -1 (no timers) even if
+ there are timers. So do a timeout anyway. */
+ secs = 1;
+ usecs = 0;
+ }
+
+ timeout = (secs * kEventDurationSecond
+ + usecs * kEventDurationMicrosecond);
+ err = ReceiveNextEvent (0, NULL, timeout, kEventRemoveFromQueue,
+ &event);
+ if (err == noErr)
+ {
+ SendEventToEventTarget (event, toolbox_dispatcher);
+ ReleaseEvent (event);
+ }
+#ifdef MAC_OSX
+ else if (err != eventLoopTimedOutErr)
+ {
+ if (err == eventLoopQuitErr)
+ err = noErr;
+ break;
+ }
+#else
+ /* The return value of ReceiveNextEvent seems to be
+ unreliable. Use our own global variable instead. */
+ if (quit_dialog_event_loop)
+ {
+ err = noErr;
+ break;
+ }
+#endif
+ }
+ }
+ if (err == noErr)
+ {
+ UInt32 command_id = GetWRefCon (window);
+
+ if (DIALOG_BUTTON_COMMAND_ID_P (command_id))
+ result = DIALOG_BUTTON_COMMAND_ID_VALUE (command_id);
+ }
+
+ unbind_to (specpdl_count, Qnil);
+
+ return result;
+}
+#else /* not TARGET_API_MAC_CARBON */
static int
mac_dialog (widget_value *wv)
{
int i;
int dialog_width;
Rect rect;
- WindowPtr window_ptr;
- ControlHandle ch;
+ WindowRef window_ptr;
+ ControlRef ch;
int left;
EventRecord event_record;
SInt16 part_code;
wv = wv->next;
}
- window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowPtr) -1);
+ window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowRef) -1);
SetPortWindowPort (window_ptr);
return i;
}
+#endif /* not TARGET_API_MAC_CARBON */
static char * button_names [] = {
"button1", "button2", "button3", "button4", "button5",
first_wv = wv;
}
+ /* Force a redisplay before showing the dialog. If a frame is created
+ just before showing the dialog, its contents may not have been fully
+ drawn. */
+ Fredisplay (Qt);
+
/* Actually create the dialog. */
-#ifdef HAVE_DIALOGS
- menu_item_selection = mac_dialog (first_wv);
+#if TARGET_API_MAC_CARBON
+ menu_item_selection = create_and_show_dialog (f, first_wv);
#else
- menu_item_selection = 0;
+ menu_item_selection = mac_dialog (first_wv);
#endif
/* Free the widget_value objects we used to specify the contents. */
static void
add_menu_item (menu, pos, wv)
- MenuHandle menu;
+ MenuRef menu;
int pos;
widget_value *wv;
{
static int
fill_menu (menu, wv, kind, submenu_id)
- MenuHandle menu;
+ MenuRef menu;
widget_value *wv;
enum mac_menu_kind kind;
int submenu_id;
add_menu_item (menu, pos, wv);
if (wv->contents && submenu_id < min_menu_id[kind + 1])
{
- MenuHandle submenu = NewMenu (submenu_id, "\pX");
+ MenuRef submenu = NewMenu (submenu_id, "\pX");
InsertMenu (submenu, -1);
SetMenuItemHierarchicalID (menu, pos, submenu_id);
int deep_p;
{
int id, submenu_id;
- MenuHandle menu;
- Str255 title;
#if !TARGET_API_MAC_CARBON
int title_changed_p = 0;
#endif
wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1];
wv = wv->next, id++)
{
+ OSStatus err = noErr;
+ MenuRef menu;
+#if TARGET_API_MAC_CARBON
+ CFStringRef title;
+
+ title = CFStringCreateWithCString (NULL, wv->name,
+ kCFStringEncodingMacRoman);
+#else
+ Str255 title;
+
strncpy (title, wv->name, 255);
title[255] = '\0';
c2pstr (title);
+#endif
- menu = GetMenuHandle (id);
+ menu = GetMenuRef (id);
if (menu)
{
#if TARGET_API_MAC_CARBON
- Str255 old_title;
+ CFStringRef old_title;
- GetMenuTitle (menu, old_title);
- if (!EqualString (title, old_title, false, false))
- SetMenuTitle (menu, title);
+ err = CopyMenuTitleAsCFString (menu, &old_title);
+ if (err == noErr)
+ {
+ if (CFStringCompare (title, old_title, 0) != kCFCompareEqualTo)
+ err = SetMenuTitleWithCFString (menu, title);
+ CFRelease (old_title);
+ }
+ else
+ err = SetMenuTitleWithCFString (menu, title);
#else /* !TARGET_API_MAC_CARBON */
if (!EqualString (title, (*menu)->menuData, false, false))
{
DeleteMenu (id);
DisposeMenu (menu);
menu = NewMenu (id, title);
- InsertMenu (menu, GetMenuHandle (id + 1) ? id + 1 : 0);
+ InsertMenu (menu, GetMenuRef (id + 1) ? id + 1 : 0);
title_changed_p = 1;
}
#endif /* !TARGET_API_MAC_CARBON */
}
else
{
+#if TARGET_API_MAC_CARBON
+ err = CreateNewMenu (id, 0, &menu);
+ if (err == noErr)
+ err = SetMenuTitleWithCFString (menu, title);
+#else
menu = NewMenu (id, title);
- InsertMenu (menu, 0);
+#endif
+ if (err == noErr)
+ {
+ InsertMenu (menu, 0);
#if !TARGET_API_MAC_CARBON
- title_changed_p = 1;
+ title_changed_p = 1;
#endif
+ }
}
+#if TARGET_API_MAC_CARBON
+ CFRelease (title);
+#endif
- if (wv->contents)
- submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
- submenu_id);
+ if (err == noErr)
+ 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))
+ if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuRef (id))
{
dispose_menus (MAC_MENU_MENU_BAR, id);
#if !TARGET_API_MAC_CARBON
{
for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++)
{
- MenuHandle menu = GetMenuHandle (id);
+ MenuRef menu = GetMenuRef (id);
if (menu == NULL)
break;
#endif /* HAVE_MENUS */
+/* Detect if a menu is currently active. */
+
+int
+popup_activated ()
+{
+ return popup_activated_flag;
+}
+
/* The following is used by delayed window autoselection. */
DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0,
doc: /* Return t if a menu or popup dialog is active. */)
()
{
+#if TARGET_API_MAC_CARBON
+ return (popup_activated ()) ? Qt : Qnil;
+#else
/* Always return Qnil since menu selection functions do not return
until a selection has been made or cancelled. */
return Qnil;
+#endif
}
\f
void