aboutsummaryrefslogtreecommitdiffstats
path: root/src/macmenu.c
diff options
context:
space:
mode:
authorMiles Bader2008-04-18 02:56:45 +0000
committerMiles Bader2008-04-18 02:56:45 +0000
commitd02fe47dd3be7310d1bfd6e802d1fac2ea5f5e9d (patch)
tree9ba3090ea2e4c57322ad5104dc910eedffb40ae4 /src/macmenu.c
parentdc6ee347e3e4fe96397ef913d2ffe4901cc0c1a8 (diff)
parentbcb96719b37029024876fca1f65eab69d32aa6d8 (diff)
downloademacs-d02fe47dd3be7310d1bfd6e802d1fac2ea5f5e9d.tar.gz
emacs-d02fe47dd3be7310d1bfd6e802d1fac2ea5f5e9d.zip
Merge from emacs--rel--22
Revision: emacs@sv.gnu.org/emacs--devo--0--patch-1112
Diffstat (limited to 'src/macmenu.c')
-rw-r--r--src/macmenu.c1323
1 files changed, 14 insertions, 1309 deletions
diff --git a/src/macmenu.c b/src/macmenu.c
index ddc6e3c2b84..bb45013fc73 100644
--- a/src/macmenu.c
+++ b/src/macmenu.c
@@ -36,20 +36,6 @@ Boston, MA 02110-1301, USA. */
36#include "charset.h" 36#include "charset.h"
37#include "coding.h" 37#include "coding.h"
38 38
39#if !TARGET_API_MAC_CARBON
40#include <MacTypes.h>
41#include <Menus.h>
42#include <Quickdraw.h>
43#include <ToolUtils.h>
44#include <Fonts.h>
45#include <Controls.h>
46#include <Windows.h>
47#include <Events.h>
48#if defined (__MRC__) || (__MSL__ >= 0x6000)
49#include <ControlDefinitions.h>
50#endif
51#endif /* not TARGET_API_MAC_CARBON */
52
53/* This may include sys/types.h, and that somehow loses 39/* This may include sys/types.h, and that somehow loses
54 if this is not done before the other system files. */ 40 if this is not done before the other system files. */
55#include "macterm.h" 41#include "macterm.h"
@@ -62,21 +48,6 @@ Boston, MA 02110-1301, USA. */
62 48
63#include "dispextern.h" 49#include "dispextern.h"
64 50
65enum mac_menu_kind { /* Menu ID range */
66 MAC_MENU_APPLE, /* 0 (Reserved by Apple) */
67 MAC_MENU_MENU_BAR, /* 1 .. 233 */
68 MAC_MENU_M_APPLE, /* 234 (== M_APPLE) */
69 MAC_MENU_POPUP, /* 235 */
70 MAC_MENU_DRIVER, /* 236 .. 255 (Reserved) */
71 MAC_MENU_MENU_BAR_SUB, /* 256 .. 16383 */
72 MAC_MENU_POPUP_SUB, /* 16384 .. 32767 */
73 MAC_MENU_END /* 32768 */
74};
75
76static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
77
78#define DIALOG_WINDOW_RESOURCE 130
79
80#if TARGET_API_MAC_CARBON 51#if TARGET_API_MAC_CARBON
81#define HAVE_DIALOGS 1 52#define HAVE_DIALOGS 1
82#endif 53#endif
@@ -84,69 +55,6 @@ static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
84#undef HAVE_MULTILINGUAL_MENU 55#undef HAVE_MULTILINGUAL_MENU
85 56
86/******************************************************************/ 57/******************************************************************/
87/* Definitions copied from lwlib.h */
88
89typedef void * XtPointer;
90
91enum button_type
92{
93 BUTTON_TYPE_NONE,
94 BUTTON_TYPE_TOGGLE,
95 BUTTON_TYPE_RADIO
96};
97
98/* This structure is based on the one in ../lwlib/lwlib.h, modified
99 for Mac OS. */
100typedef struct _widget_value
101{
102 /* name of widget */
103 Lisp_Object lname;
104 char* name;
105 /* value (meaning depend on widget type) */
106 char* value;
107 /* keyboard equivalent. no implications for XtTranslations */
108 Lisp_Object lkey;
109 char* key;
110 /* Help string or nil if none.
111 GC finds this string through the frame's menu_bar_vector
112 or through menu_items. */
113 Lisp_Object help;
114 /* true if enabled */
115 Boolean enabled;
116 /* true if selected */
117 Boolean selected;
118 /* The type of a button. */
119 enum button_type button_type;
120 /* true if menu title */
121 Boolean title;
122#if 0
123 /* true if was edited (maintained by get_value) */
124 Boolean edited;
125 /* true if has changed (maintained by lw library) */
126 change_type change;
127 /* true if this widget itself has changed,
128 but not counting the other widgets found in the `next' field. */
129 change_type this_one_change;
130#endif
131 /* Contents of the sub-widgets, also selected slot for checkbox */
132 struct _widget_value* contents;
133 /* data passed to callback */
134 XtPointer call_data;
135 /* next one in the list */
136 struct _widget_value* next;
137#if 0
138 /* slot for the toolkit dependent part. Always initialize to NULL. */
139 void* toolkit_data;
140 /* tell us if we should free the toolkit data slot when freeing the
141 widget_value itself. */
142 Boolean free_toolkit_data;
143
144 /* we resource the widget_value structures; this points to the next
145 one on the free list if this one has been deallocated.
146 */
147 struct _widget_value *free_list;
148#endif
149} widget_value;
150 58
151/* Assumed by other routines to zero area returned. */ 59/* Assumed by other routines to zero area returned. */
152#define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\ 60#define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
@@ -198,12 +106,6 @@ static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
198static void list_of_panes P_ ((Lisp_Object)); 106static void list_of_panes P_ ((Lisp_Object));
199static void list_of_items P_ ((Lisp_Object)); 107static void list_of_items P_ ((Lisp_Object));
200 108
201static void find_and_call_menu_selection P_ ((FRAME_PTR, int, Lisp_Object,
202 void *));
203static int fill_menu P_ ((MenuRef, widget_value *, enum mac_menu_kind, int));
204static void fill_menubar P_ ((widget_value *, int));
205static void dispose_menus P_ ((enum mac_menu_kind, int));
206
207 109
208/* This holds a Lisp vector that holds the results of decoding 110/* This holds a Lisp vector that holds the results of decoding
209 the keymaps or alist-of-alists that specify a menu. 111 the keymaps or alist-of-alists that specify a menu.
@@ -260,7 +162,7 @@ static int menu_items_n_panes;
260static int menu_items_submenu_depth; 162static int menu_items_submenu_depth;
261 163
262/* Nonzero means a menu is currently active. */ 164/* Nonzero means a menu is currently active. */
263static int popup_activated_flag; 165int popup_activated_flag;
264 166
265/* This is set nonzero after the user activates the menu bar, and set 167/* This is set nonzero after the user activates the menu bar, and set
266 to zero again after the menu bars are redisplayed by prepare_menu_bar. 168 to zero again after the menu bars are redisplayed by prepare_menu_bar.
@@ -873,32 +775,6 @@ no quit occurs and `x-popup-menu' returns nil. */)
873 775
874#ifdef HAVE_MENUS 776#ifdef HAVE_MENUS
875 777
876/* Regard ESC and C-g as Cancel even without the Cancel button. */
877
878#if 0 /* defined (MAC_OSX) */
879static Boolean
880mac_dialog_modal_filter (dialog, event, item_hit)
881 DialogRef dialog;
882 EventRecord *event;
883 DialogItemIndex *item_hit;
884{
885 Boolean result;
886
887 result = StdFilterProc (dialog, event, item_hit);
888 if (result == false
889 && (event->what == keyDown || event->what == autoKey)
890 && ((event->message & charCodeMask) == kEscapeCharCode
891 || mac_quit_char_key_p (event->modifiers,
892 (event->message & keyCodeMask) >> 8)))
893 {
894 *item_hit = kStdCancelItemIndex;
895 return true;
896 }
897
898 return result;
899}
900#endif
901
902DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0, 778DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
903 doc: /* Pop up a dialog box and return user's selection. 779 doc: /* Pop up a dialog box and return user's selection.
904POSITION specifies which frame to use. 780POSITION specifies which frame to use.
@@ -984,101 +860,6 @@ for instance using the window manager, then this produces a quit and
984 but I don't want to make one now. */ 860 but I don't want to make one now. */
985 CHECK_WINDOW (window); 861 CHECK_WINDOW (window);
986 862
987#if 0 /* defined (MAC_OSX) */
988 /* Special treatment for Fmessage_box, Fyes_or_no_p, and Fy_or_n_p. */
989 if (EQ (position, Qt)
990 && STRINGP (Fcar (contents))
991 && ((!NILP (Fequal (XCDR (contents),
992 Fcons (Fcons (build_string ("OK"), Qt), Qnil)))
993 && EQ (header, Qt))
994 || (!NILP (Fequal (XCDR (contents),
995 Fcons (Fcons (build_string ("Yes"), Qt),
996 Fcons (Fcons (build_string ("No"), Qnil),
997 Qnil))))
998 && NILP (header))))
999 {
1000 OSStatus err = noErr;
1001 AlertStdCFStringAlertParamRec param;
1002 CFStringRef error_string, explanation_string;
1003 DialogRef alert;
1004 DialogItemIndex item_hit;
1005 Lisp_Object tem;
1006
1007 /* Force a redisplay before showing the dialog. If a frame is
1008 created just before showing the dialog, its contents may not
1009 have been fully drawn. */
1010 Fredisplay (Qt);
1011
1012 tem = Fstring_match (concat3 (build_string ("\\("),
1013 call0 (intern ("sentence-end")),
1014 build_string ("\\)\n")),
1015 XCAR (contents), Qnil);
1016 BLOCK_INPUT;
1017 if (NILP (tem))
1018 {
1019 error_string = cfstring_create_with_string (XCAR (contents));
1020 if (error_string == NULL)
1021 err = memFullErr;
1022 explanation_string = NULL;
1023 }
1024 else
1025 {
1026 tem = Fmatch_end (make_number (1));
1027 error_string =
1028 cfstring_create_with_string (Fsubstring (XCAR (contents),
1029 make_number (0), tem));
1030 if (error_string == NULL)
1031 err = memFullErr;
1032 else
1033 {
1034 XSETINT (tem, XINT (tem) + 1);
1035 explanation_string =
1036 cfstring_create_with_string (Fsubstring (XCAR (contents),
1037 tem, Qnil));
1038 if (explanation_string == NULL)
1039 {
1040 CFRelease (error_string);
1041 err = memFullErr;
1042 }
1043 }
1044 }
1045 if (err == noErr)
1046 err = GetStandardAlertDefaultParams (&param,
1047 kStdCFStringAlertVersionOne);
1048 if (err == noErr)
1049 {
1050 param.movable = true;
1051 param.position = kWindowAlertPositionParentWindow;
1052 if (NILP (header))
1053 {
1054 param.defaultText = CFSTR ("Yes");
1055 param.otherText = CFSTR ("No");
1056#if 0
1057 param.cancelText = CFSTR ("Cancel");
1058 param.cancelButton = kAlertStdAlertCancelButton;
1059#endif
1060 }
1061 err = CreateStandardAlert (kAlertNoteAlert, error_string,
1062 explanation_string, &param, &alert);
1063 CFRelease (error_string);
1064 if (explanation_string)
1065 CFRelease (explanation_string);
1066 }
1067 if (err == noErr)
1068 err = RunStandardAlert (alert, mac_dialog_modal_filter, &item_hit);
1069 UNBLOCK_INPUT;
1070
1071 if (err == noErr)
1072 {
1073 if (item_hit == kStdCancelItemIndex)
1074 Fsignal (Qquit, Qnil);
1075 else if (item_hit == kStdOkItemIndex)
1076 return Qt;
1077 else
1078 return Qnil;
1079 }
1080 }
1081#endif
1082#ifndef HAVE_DIALOGS 863#ifndef HAVE_DIALOGS
1083 /* Display a menu with these alternatives 864 /* Display a menu with these alternatives
1084 in the middle of frame F. */ 865 in the middle of frame F. */
@@ -1118,66 +899,12 @@ for instance using the window manager, then this produces a quit and
1118#endif /* HAVE_DIALOGS */ 899#endif /* HAVE_DIALOGS */
1119} 900}
1120 901
1121/* Activate the menu bar of frame F.
1122 This is called from keyboard.c when it gets the
1123 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
1124
1125 To activate the menu bar, we use the button-press event location
1126 that was saved in saved_menu_event_location.
1127
1128 But first we recompute the menu bar contents (the whole tree).
1129
1130 The reason for saving the button event until here, instead of
1131 passing it to the toolkit right away, is that we can safely
1132 execute Lisp code. */
1133
1134void
1135x_activate_menubar (f)
1136 FRAME_PTR f;
1137{
1138 SInt32 menu_choice;
1139 SInt16 menu_id, menu_item;
1140 extern Point saved_menu_event_location;
1141
1142 set_frame_menubar (f, 0, 1);
1143 BLOCK_INPUT;
1144
1145 popup_activated_flag = 1;
1146 menu_choice = MenuSelect (saved_menu_event_location);
1147 popup_activated_flag = 0;
1148 menu_id = HiWord (menu_choice);
1149 menu_item = LoWord (menu_choice);
1150
1151#if !TARGET_API_MAC_CARBON
1152 if (menu_id == min_menu_id[MAC_MENU_M_APPLE])
1153 do_apple_menu (menu_item);
1154 else
1155#endif
1156 if (menu_id)
1157 {
1158 MenuRef menu = GetMenuRef (menu_id);
1159
1160 if (menu)
1161 {
1162 UInt32 refcon;
1163
1164 GetMenuItemRefCon (menu, menu_item, &refcon);
1165 find_and_call_menu_selection (f, f->menu_bar_items_used,
1166 f->menu_bar_vector, (void *) refcon);
1167 }
1168 }
1169
1170 HiliteMenu (0);
1171
1172 UNBLOCK_INPUT;
1173}
1174
1175/* Find the menu selection and store it in the keyboard buffer. 902/* Find the menu selection and store it in the keyboard buffer.
1176 F is the frame the menu is on. 903 F is the frame the menu is on.
1177 MENU_BAR_ITEMS_USED is the length of VECTOR. 904 MENU_BAR_ITEMS_USED is the length of VECTOR.
1178 VECTOR is an array of menu events for the whole menu. */ 905 VECTOR is an array of menu events for the whole menu. */
1179 906
1180static void 907void
1181find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data) 908find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data)
1182 FRAME_PTR f; 909 FRAME_PTR f;
1183 int menu_bar_items_used; 910 int menu_bar_items_used;
@@ -1570,141 +1297,6 @@ update_submenu_strings (first_wv)
1570} 1297}
1571 1298
1572 1299
1573#if TARGET_API_MAC_CARBON
1574extern Lisp_Object Vshow_help_function;
1575
1576static Lisp_Object
1577restore_show_help_function (old_show_help_function)
1578 Lisp_Object old_show_help_function;
1579{
1580 Vshow_help_function = old_show_help_function;
1581
1582 return Qnil;
1583}
1584
1585static pascal OSStatus
1586menu_target_item_handler (next_handler, event, data)
1587 EventHandlerCallRef next_handler;
1588 EventRef event;
1589 void *data;
1590{
1591 OSStatus err;
1592 MenuRef menu;
1593 MenuItemIndex menu_item;
1594 Lisp_Object help;
1595 GrafPtr port;
1596 int specpdl_count = SPECPDL_INDEX ();
1597
1598 /* Don't be bothered with the overflowed toolbar items menu. */
1599 if (!popup_activated ())
1600 return eventNotHandledErr;
1601
1602 err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef,
1603 NULL, sizeof (MenuRef), NULL, &menu);
1604 if (err == noErr)
1605 err = GetEventParameter (event, kEventParamMenuItemIndex,
1606 typeMenuItemIndex, NULL,
1607 sizeof (MenuItemIndex), NULL, &menu_item);
1608 if (err == noErr)
1609 err = GetMenuItemProperty (menu, menu_item,
1610 MAC_EMACS_CREATOR_CODE, 'help',
1611 sizeof (Lisp_Object), NULL, &help);
1612 if (err != noErr)
1613 help = Qnil;
1614
1615 /* Temporarily bind Vshow_help_function to Qnil because we don't
1616 want tooltips during menu tracking. */
1617 record_unwind_protect (restore_show_help_function, Vshow_help_function);
1618 Vshow_help_function = Qnil;
1619 GetPort (&port);
1620 show_help_echo (help, Qnil, Qnil, Qnil, 1);
1621 SetPort (port);
1622 unbind_to (specpdl_count, Qnil);
1623
1624 return err == noErr ? noErr : eventNotHandledErr;
1625}
1626
1627OSStatus
1628install_menu_target_item_handler ()
1629{
1630 static const EventTypeSpec specs[] =
1631 {{kEventClassMenu, kEventMenuTargetItem}};
1632
1633 return InstallApplicationEventHandler (NewEventHandlerUPP
1634 (menu_target_item_handler),
1635 GetEventTypeCount (specs),
1636 specs, NULL, NULL);
1637}
1638#endif /* TARGET_API_MAC_CARBON */
1639
1640/* Event handler function that pops down a menu on C-g. We can only pop
1641 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
1642
1643#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1644static pascal OSStatus
1645menu_quit_handler (nextHandler, theEvent, userData)
1646 EventHandlerCallRef nextHandler;
1647 EventRef theEvent;
1648 void* userData;
1649{
1650 OSStatus err;
1651 UInt32 keyCode;
1652 UInt32 keyModifiers;
1653
1654 err = GetEventParameter (theEvent, kEventParamKeyCode,
1655 typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
1656
1657 if (err == noErr)
1658 err = GetEventParameter (theEvent, kEventParamKeyModifiers,
1659 typeUInt32, NULL, sizeof(UInt32),
1660 NULL, &keyModifiers);
1661
1662 if (err == noErr && mac_quit_char_key_p (keyModifiers, keyCode))
1663 {
1664 MenuRef menu = userData != 0
1665 ? (MenuRef)userData : AcquireRootMenu ();
1666
1667 CancelMenuTracking (menu, true, 0);
1668 if (!userData) ReleaseMenu (menu);
1669 return noErr;
1670 }
1671
1672 return CallNextEventHandler (nextHandler, theEvent);
1673}
1674#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1675
1676/* Add event handler to all menus that belong to KIND so we can detect
1677 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
1678 when C-g is detected. NULL means the menu bar. If
1679 CancelMenuTracking isn't available, do nothing. */
1680
1681static void
1682install_menu_quit_handler (kind, root_menu)
1683 enum mac_menu_kind kind;
1684 MenuRef root_menu;
1685{
1686#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1687 static const EventTypeSpec typesList[] =
1688 {{kEventClassKeyboard, kEventRawKeyDown}};
1689 int id;
1690
1691#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1692 if (CancelMenuTracking == NULL)
1693 return;
1694#endif
1695 for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++)
1696 {
1697 MenuRef menu = GetMenuRef (id);
1698
1699 if (menu == NULL)
1700 break;
1701 InstallMenuEventHandler (menu, menu_quit_handler,
1702 GetEventTypeCount (typesList),
1703 typesList, root_menu, NULL);
1704 }
1705#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1706}
1707
1708/* Set the contents of the menubar widgets of frame F. 1300/* Set the contents of the menubar widgets of frame F.
1709 The argument FIRST_TIME is currently ignored; 1301 The argument FIRST_TIME is currently ignored;
1710 it is set the first time this is called, from initialize_frame_menubar. */ 1302 it is set the first time this is called, from initialize_frame_menubar. */
@@ -1940,11 +1532,8 @@ set_frame_menubar (f, first_time, deep_p)
1940 /* Non-null value to indicate menubar has already been "created". */ 1532 /* Non-null value to indicate menubar has already been "created". */
1941 f->output_data.mac->menubar_widget = 1; 1533 f->output_data.mac->menubar_widget = 1;
1942 1534
1943 fill_menubar (first_wv->contents, deep_p); 1535 mac_fill_menubar (first_wv->contents, deep_p);
1944 1536
1945 /* Add event handler so we can detect C-g. */
1946 install_menu_quit_handler (MAC_MENU_MENU_BAR, NULL);
1947 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB, NULL);
1948 free_menubar_widget_value_tree (first_wv); 1537 free_menubar_widget_value_tree (first_wv);
1949 1538
1950 UNBLOCK_INPUT; 1539 UNBLOCK_INPUT;
@@ -1961,29 +1550,8 @@ free_frame_menubar (f)
1961} 1550}
1962 1551
1963 1552
1964static Lisp_Object 1553/* The item selected in the popup menu. */
1965pop_down_menu (arg) 1554int menu_item_selection;
1966 Lisp_Object arg;
1967{
1968 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1969 FRAME_PTR f = p->pointer;
1970 MenuRef menu = GetMenuRef (min_menu_id[MAC_MENU_POPUP]);
1971
1972 BLOCK_INPUT;
1973
1974 /* Must reset this manually because the button release event is not
1975 passed to Emacs event loop. */
1976 FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0;
1977
1978 /* delete all menus */
1979 dispose_menus (MAC_MENU_POPUP_SUB, 0);
1980 DeleteMenu (min_menu_id[MAC_MENU_POPUP]);
1981 DisposeMenu (menu);
1982
1983 UNBLOCK_INPUT;
1984
1985 return Qnil;
1986}
1987 1555
1988/* Mac_menu_show actually displays a menu using the panes and items in 1556/* Mac_menu_show actually displays a menu using the panes and items in
1989 menu_items and returns the value selected from it; we assume input 1557 menu_items and returns the value selected from it; we assume input
@@ -2011,9 +1579,6 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
2011 char **error; 1579 char **error;
2012{ 1580{
2013 int i; 1581 int i;
2014 int menu_item_choice;
2015 UInt32 menu_item_selection;
2016 MenuRef menu;
2017 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; 1582 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
2018 widget_value **submenu_stack 1583 widget_value **submenu_stack
2019 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); 1584 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
@@ -2022,7 +1587,6 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
2022 int submenu_depth = 0; 1587 int submenu_depth = 0;
2023 1588
2024 int first_pane; 1589 int first_pane;
2025 int specpdl_count = SPECPDL_INDEX ();
2026 1590
2027 *error = NULL; 1591 *error = NULL;
2028 1592
@@ -2208,45 +1772,14 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
2208 first_wv->contents = wv_title; 1772 first_wv->contents = wv_title;
2209 } 1773 }
2210 1774
2211 /* Actually create the menu. */
2212 menu = NewMenu (min_menu_id[MAC_MENU_POPUP], "\p");
2213 InsertMenu (menu, -1);
2214 fill_menu (menu, first_wv->contents, MAC_MENU_POPUP_SUB,
2215 min_menu_id[MAC_MENU_POPUP_SUB]);
2216
2217 /* Free the widget_value objects we used to specify the
2218 contents. */
2219 free_menubar_widget_value_tree (first_wv);
2220
2221 /* Adjust coordinates to be root-window-relative. */
2222 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
2223 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
2224
2225 /* No selection has been chosen yet. */ 1775 /* No selection has been chosen yet. */
2226 menu_item_selection = 0; 1776 menu_item_selection = 0;
2227 1777
2228 record_unwind_protect (pop_down_menu, make_save_value (f, 0)); 1778 /* Actually create and show the menu until popped down. */
1779 create_and_show_popup_menu (f, first_wv, x, y, for_click);
2229 1780
2230 /* Add event handler so we can detect C-g. */ 1781 /* Free the widget_value objects we used to specify the contents. */
2231 install_menu_quit_handler (MAC_MENU_POPUP, menu); 1782 free_menubar_widget_value_tree (first_wv);
2232 install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu);
2233
2234 /* Display the menu. */
2235 popup_activated_flag = 1;
2236 menu_item_choice = PopUpMenuSelect (menu, y, x, 0);
2237 popup_activated_flag = 0;
2238
2239 /* Get the refcon to find the correct item */
2240 if (menu_item_choice)
2241 {
2242 MenuRef sel_menu = GetMenuRef (HiWord (menu_item_choice));
2243
2244 if (sel_menu)
2245 GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice),
2246 &menu_item_selection);
2247 }
2248
2249 unbind_to (specpdl_count, Qnil);
2250 1783
2251 /* Find the selected item, and its pane, to return 1784 /* Find the selected item, and its pane, to return
2252 the proper value. */ 1785 the proper value. */
@@ -2313,582 +1846,6 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
2313#ifdef HAVE_DIALOGS 1846#ifdef HAVE_DIALOGS
2314/* Construct native Mac OS dialog based on widget_value tree. */ 1847/* Construct native Mac OS dialog based on widget_value tree. */
2315 1848
2316#if TARGET_API_MAC_CARBON
2317
2318#define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
2319#define DIALOG_BUTTON_COMMAND_ID_P(id) \
2320 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
2321#define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
2322 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
2323#define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
2324 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
2325
2326extern EMACS_TIME timer_check P_ ((int));
2327static int quit_dialog_event_loop;
2328
2329static pascal OSStatus
2330mac_handle_dialog_event (next_handler, event, data)
2331 EventHandlerCallRef next_handler;
2332 EventRef event;
2333 void *data;
2334{
2335 OSStatus err, result = eventNotHandledErr;
2336 WindowRef window = (WindowRef) data;
2337
2338 switch (GetEventClass (event))
2339 {
2340 case kEventClassCommand:
2341 {
2342 HICommand command;
2343
2344 err = GetEventParameter (event, kEventParamDirectObject,
2345 typeHICommand, NULL, sizeof (HICommand),
2346 NULL, &command);
2347 if (err == noErr)
2348 if (DIALOG_BUTTON_COMMAND_ID_P (command.commandID))
2349 {
2350 SetWRefCon (window, command.commandID);
2351 quit_dialog_event_loop = 1;
2352 break;
2353 }
2354
2355 result = CallNextEventHandler (next_handler, event);
2356 }
2357 break;
2358
2359 case kEventClassKeyboard:
2360 {
2361 OSStatus result;
2362 char char_code;
2363
2364 result = CallNextEventHandler (next_handler, event);
2365 if (result != eventNotHandledErr)
2366 break;
2367
2368 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
2369 typeChar, NULL, sizeof (char),
2370 NULL, &char_code);
2371 if (err == noErr)
2372 switch (char_code)
2373 {
2374 case kEscapeCharCode:
2375 quit_dialog_event_loop = 1;
2376 break;
2377
2378 default:
2379 {
2380 UInt32 modifiers, key_code;
2381
2382 err = GetEventParameter (event, kEventParamKeyModifiers,
2383 typeUInt32, NULL, sizeof (UInt32),
2384 NULL, &modifiers);
2385 if (err == noErr)
2386 err = GetEventParameter (event, kEventParamKeyCode,
2387 typeUInt32, NULL, sizeof (UInt32),
2388 NULL, &key_code);
2389 if (err == noErr)
2390 if (mac_quit_char_key_p (modifiers, key_code))
2391 quit_dialog_event_loop = 1;
2392 }
2393 break;
2394 }
2395 }
2396 break;
2397
2398 default:
2399 abort ();
2400 }
2401
2402 if (quit_dialog_event_loop)
2403 {
2404 err = QuitEventLoop (GetCurrentEventLoop ());
2405 if (err == noErr)
2406 result = noErr;
2407 }
2408
2409 return result;
2410}
2411
2412static OSStatus
2413install_dialog_event_handler (window)
2414 WindowRef window;
2415{
2416 static const EventTypeSpec specs[] =
2417 {{kEventClassCommand, kEventCommandProcess},
2418 {kEventClassKeyboard, kEventRawKeyDown}};
2419 static EventHandlerUPP handle_dialog_eventUPP = NULL;
2420
2421 if (handle_dialog_eventUPP == NULL)
2422 handle_dialog_eventUPP = NewEventHandlerUPP (mac_handle_dialog_event);
2423 return InstallWindowEventHandler (window, handle_dialog_eventUPP,
2424 GetEventTypeCount (specs), specs,
2425 window, NULL);
2426}
2427
2428#define DIALOG_LEFT_MARGIN (112)
2429#define DIALOG_TOP_MARGIN (24)
2430#define DIALOG_RIGHT_MARGIN (24)
2431#define DIALOG_BOTTOM_MARGIN (20)
2432#define DIALOG_MIN_INNER_WIDTH (338)
2433#define DIALOG_MAX_INNER_WIDTH (564)
2434#define DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE (12)
2435#define DIALOG_BUTTON_BUTTON_VERTICAL_SPACE (12)
2436#define DIALOG_BUTTON_MIN_WIDTH (68)
2437#define DIALOG_TEXT_MIN_HEIGHT (50)
2438#define DIALOG_TEXT_BUTTONS_VERTICAL_SPACE (10)
2439#define DIALOG_ICON_WIDTH (64)
2440#define DIALOG_ICON_HEIGHT (64)
2441#define DIALOG_ICON_LEFT_MARGIN (24)
2442#define DIALOG_ICON_TOP_MARGIN (15)
2443
2444static Lisp_Object
2445pop_down_dialog (arg)
2446 Lisp_Object arg;
2447{
2448 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
2449 WindowRef window = p->pointer;
2450
2451 BLOCK_INPUT;
2452
2453 if (popup_activated_flag)
2454 EndAppModalStateForWindow (window);
2455 DisposeWindow (window);
2456 popup_activated_flag = 0;
2457
2458 UNBLOCK_INPUT;
2459
2460 return Qnil;
2461}
2462
2463static int
2464create_and_show_dialog (f, first_wv)
2465 FRAME_PTR f;
2466 widget_value *first_wv;
2467{
2468 OSStatus err;
2469 char *dialog_name, *message;
2470 int nb_buttons, first_group_count, i, result = 0;
2471 widget_value *wv;
2472 short buttons_height, text_height, inner_width, inner_height;
2473 Rect empty_rect, *rects;
2474 WindowRef window = NULL;
2475 ControlRef *buttons, default_button = NULL, text;
2476 int specpdl_count = SPECPDL_INDEX ();
2477
2478 dialog_name = first_wv->name;
2479 nb_buttons = dialog_name[1] - '0';
2480 first_group_count = nb_buttons - (dialog_name[4] - '0');
2481
2482 wv = first_wv->contents;
2483 message = wv->value;
2484
2485 wv = wv->next;
2486 SetRect (&empty_rect, 0, 0, 0, 0);
2487
2488 /* Create dialog window. */
2489 err = CreateNewWindow (kMovableModalWindowClass,
2490 kWindowStandardHandlerAttribute,
2491 &empty_rect, &window);
2492 if (err == noErr)
2493 {
2494 record_unwind_protect (pop_down_dialog, make_save_value (window, 0));
2495 err = SetThemeWindowBackground (window, kThemeBrushMovableModalBackground,
2496 true);
2497 }
2498 if (err == noErr)
2499 err = SetWindowTitleWithCFString (window, (dialog_name[0] == 'Q'
2500 ? CFSTR ("Question")
2501 : CFSTR ("Information")));
2502
2503 /* Create button controls and measure their optimal bounds. */
2504 if (err == noErr)
2505 {
2506 buttons = alloca (sizeof (ControlRef) * nb_buttons);
2507 rects = alloca (sizeof (Rect) * nb_buttons);
2508 for (i = 0; i < nb_buttons; i++)
2509 {
2510 CFStringRef label = cfstring_create_with_utf8_cstring (wv->value);
2511
2512 if (label == NULL)
2513 err = memFullErr;
2514 else
2515 {
2516 err = CreatePushButtonControl (window, &empty_rect,
2517 label, &buttons[i]);
2518 CFRelease (label);
2519 }
2520 if (err == noErr)
2521 {
2522 if (!wv->enabled)
2523 {
2524#ifdef MAC_OSX
2525 err = DisableControl (buttons[i]);
2526#else
2527 err = DeactivateControl (buttons[i]);
2528#endif
2529 }
2530 else if (default_button == NULL)
2531 default_button = buttons[i];
2532 }
2533 if (err == noErr)
2534 {
2535 SInt16 unused;
2536
2537 rects[i] = empty_rect;
2538 err = GetBestControlRect (buttons[i], &rects[i], &unused);
2539 }
2540 if (err == noErr)
2541 {
2542 UInt32 command_id;
2543
2544 OffsetRect (&rects[i], -rects[i].left, -rects[i].top);
2545 if (rects[i].right < DIALOG_BUTTON_MIN_WIDTH)
2546 rects[i].right = DIALOG_BUTTON_MIN_WIDTH;
2547 else if (rects[i].right > DIALOG_MAX_INNER_WIDTH)
2548 rects[i].right = DIALOG_MAX_INNER_WIDTH;
2549
2550 command_id = DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv->call_data);
2551 err = SetControlCommandID (buttons[i], command_id);
2552 }
2553 if (err != noErr)
2554 break;
2555 wv = wv->next;
2556 }
2557 }
2558
2559 /* Layout buttons. rects[i] is set relative to the bottom-right
2560 corner of the inner box. */
2561 if (err == noErr)
2562 {
2563 short bottom, right, max_height, left_align_shift;
2564
2565 inner_width = DIALOG_MIN_INNER_WIDTH;
2566 bottom = right = max_height = 0;
2567 for (i = 0; i < nb_buttons; i++)
2568 {
2569 if (right - rects[i].right < - inner_width)
2570 {
2571 if (i != first_group_count
2572 && right - rects[i].right >= - DIALOG_MAX_INNER_WIDTH)
2573 inner_width = - (right - rects[i].right);
2574 else
2575 {
2576 bottom -= max_height + DIALOG_BUTTON_BUTTON_VERTICAL_SPACE;
2577 right = max_height = 0;
2578 }
2579 }
2580 if (max_height < rects[i].bottom)
2581 max_height = rects[i].bottom;
2582 OffsetRect (&rects[i], right - rects[i].right,
2583 bottom - rects[i].bottom);
2584 right = rects[i].left - DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
2585 if (i == first_group_count - 1)
2586 right -= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
2587 }
2588 buttons_height = - (bottom - max_height);
2589
2590 left_align_shift = - (inner_width + rects[nb_buttons - 1].left);
2591 for (i = nb_buttons - 1; i >= first_group_count; i--)
2592 {
2593 if (bottom != rects[i].bottom)
2594 {
2595 left_align_shift = - (inner_width + rects[i].left);
2596 bottom = rects[i].bottom;
2597 }
2598 OffsetRect (&rects[i], left_align_shift, 0);
2599 }
2600 }
2601
2602 /* Create a static text control and measure its bounds. */
2603 if (err == noErr)
2604 {
2605 CFStringRef message_string;
2606 Rect bounds;
2607
2608 message_string = cfstring_create_with_utf8_cstring (message);
2609 if (message_string == NULL)
2610 err = memFullErr;
2611 else
2612 {
2613 ControlFontStyleRec text_style;
2614
2615 text_style.flags = 0;
2616 SetRect (&bounds, 0, 0, inner_width, 0);
2617 err = CreateStaticTextControl (window, &bounds, message_string,
2618 &text_style, &text);
2619 CFRelease (message_string);
2620 }
2621 if (err == noErr)
2622 {
2623 SInt16 unused;
2624
2625 bounds = empty_rect;
2626 err = GetBestControlRect (text, &bounds, &unused);
2627 }
2628 if (err == noErr)
2629 {
2630 text_height = bounds.bottom - bounds.top;
2631 if (text_height < DIALOG_TEXT_MIN_HEIGHT)
2632 text_height = DIALOG_TEXT_MIN_HEIGHT;
2633 }
2634 }
2635
2636 /* Place buttons. */
2637 if (err == noErr)
2638 {
2639 inner_height = (text_height + DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
2640 + buttons_height);
2641
2642 for (i = 0; i < nb_buttons; i++)
2643 {
2644 OffsetRect (&rects[i], DIALOG_LEFT_MARGIN + inner_width,
2645 DIALOG_TOP_MARGIN + inner_height);
2646 SetControlBounds (buttons[i], &rects[i]);
2647 }
2648 }
2649
2650 /* Place text. */
2651 if (err == noErr)
2652 {
2653 Rect bounds;
2654
2655 SetRect (&bounds, DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN,
2656 DIALOG_LEFT_MARGIN + inner_width,
2657 DIALOG_TOP_MARGIN + text_height);
2658 SetControlBounds (text, &bounds);
2659 }
2660
2661 /* Create the application icon at the upper-left corner. */
2662 if (err == noErr)
2663 {
2664 ControlButtonContentInfo content;
2665 ControlRef icon;
2666 static const ProcessSerialNumber psn = {0, kCurrentProcess};
2667#ifdef MAC_OSX
2668 FSRef app_location;
2669#else
2670 ProcessInfoRec pinfo;
2671 FSSpec app_spec;
2672#endif
2673 SInt16 unused;
2674
2675 content.contentType = kControlContentIconRef;
2676#ifdef MAC_OSX
2677 err = GetProcessBundleLocation (&psn, &app_location);
2678 if (err == noErr)
2679 err = GetIconRefFromFileInfo (&app_location, 0, NULL, 0, NULL,
2680 kIconServicesNormalUsageFlag,
2681 &content.u.iconRef, &unused);
2682#else
2683 bzero (&pinfo, sizeof (ProcessInfoRec));
2684 pinfo.processInfoLength = sizeof (ProcessInfoRec);
2685 pinfo.processAppSpec = &app_spec;
2686 err = GetProcessInformation (&psn, &pinfo);
2687 if (err == noErr)
2688 err = GetIconRefFromFile (&app_spec, &content.u.iconRef, &unused);
2689#endif
2690 if (err == noErr)
2691 {
2692 Rect bounds;
2693
2694 SetRect (&bounds, DIALOG_ICON_LEFT_MARGIN, DIALOG_ICON_TOP_MARGIN,
2695 DIALOG_ICON_LEFT_MARGIN + DIALOG_ICON_WIDTH,
2696 DIALOG_ICON_TOP_MARGIN + DIALOG_ICON_HEIGHT);
2697 err = CreateIconControl (window, &bounds, &content, true, &icon);
2698 ReleaseIconRef (content.u.iconRef);
2699 }
2700 }
2701
2702 /* Show the dialog window and run event loop. */
2703 if (err == noErr)
2704 if (default_button)
2705 err = SetWindowDefaultButton (window, default_button);
2706 if (err == noErr)
2707 err = install_dialog_event_handler (window);
2708 if (err == noErr)
2709 {
2710 SizeWindow (window,
2711 DIALOG_LEFT_MARGIN + inner_width + DIALOG_RIGHT_MARGIN,
2712 DIALOG_TOP_MARGIN + inner_height + DIALOG_BOTTOM_MARGIN,
2713 true);
2714 err = RepositionWindow (window, FRAME_MAC_WINDOW (f),
2715 kWindowAlertPositionOnParentWindow);
2716 }
2717 if (err == noErr)
2718 {
2719 SetWRefCon (window, 0);
2720 ShowWindow (window);
2721 BringToFront (window);
2722 popup_activated_flag = 1;
2723 err = BeginAppModalStateForWindow (window);
2724 }
2725 if (err == noErr)
2726 {
2727 EventTargetRef toolbox_dispatcher = GetEventDispatcherTarget ();
2728
2729 quit_dialog_event_loop = 0;
2730 while (1)
2731 {
2732 EMACS_TIME next_time = timer_check (1);
2733 long secs = EMACS_SECS (next_time);
2734 long usecs = EMACS_USECS (next_time);
2735 EventTimeout timeout;
2736 EventRef event;
2737
2738 if (secs < 0 || (secs == 0 && usecs == 0))
2739 {
2740 /* Sometimes timer_check returns -1 (no timers) even if
2741 there are timers. So do a timeout anyway. */
2742 secs = 1;
2743 usecs = 0;
2744 }
2745
2746 timeout = (secs * kEventDurationSecond
2747 + usecs * kEventDurationMicrosecond);
2748 err = ReceiveNextEvent (0, NULL, timeout, kEventRemoveFromQueue,
2749 &event);
2750 if (err == noErr)
2751 {
2752 SendEventToEventTarget (event, toolbox_dispatcher);
2753 ReleaseEvent (event);
2754 }
2755#if 0 /* defined (MAC_OSX) */
2756 else if (err != eventLoopTimedOutErr)
2757 {
2758 if (err == eventLoopQuitErr)
2759 err = noErr;
2760 break;
2761 }
2762#else
2763 /* The return value of ReceiveNextEvent seems to be
2764 unreliable. Use our own global variable instead. */
2765 if (quit_dialog_event_loop)
2766 {
2767 err = noErr;
2768 break;
2769 }
2770#endif
2771 }
2772 }
2773 if (err == noErr)
2774 {
2775 UInt32 command_id = GetWRefCon (window);
2776
2777 if (DIALOG_BUTTON_COMMAND_ID_P (command_id))
2778 result = DIALOG_BUTTON_COMMAND_ID_VALUE (command_id);
2779 }
2780
2781 unbind_to (specpdl_count, Qnil);
2782
2783 return result;
2784}
2785#else /* not TARGET_API_MAC_CARBON */
2786static int
2787mac_dialog (widget_value *wv)
2788{
2789 char *dialog_name;
2790 char *prompt;
2791 char **button_labels;
2792 UInt32 *ref_cons;
2793 int nb_buttons;
2794 int left_count;
2795 int i;
2796 int dialog_width;
2797 Rect rect;
2798 WindowRef window_ptr;
2799 ControlRef ch;
2800 int left;
2801 EventRecord event_record;
2802 SInt16 part_code;
2803 int control_part_code;
2804 Point mouse;
2805
2806 dialog_name = wv->name;
2807 nb_buttons = dialog_name[1] - '0';
2808 left_count = nb_buttons - (dialog_name[4] - '0');
2809 button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
2810 ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons);
2811
2812 wv = wv->contents;
2813 prompt = (char *) alloca (strlen (wv->value) + 1);
2814 strcpy (prompt, wv->value);
2815 c2pstr (prompt);
2816
2817 wv = wv->next;
2818 for (i = 0; i < nb_buttons; i++)
2819 {
2820 button_labels[i] = wv->value;
2821 button_labels[i] = (char *) alloca (strlen (wv->value) + 1);
2822 strcpy (button_labels[i], wv->value);
2823 c2pstr (button_labels[i]);
2824 ref_cons[i] = (UInt32) wv->call_data;
2825 wv = wv->next;
2826 }
2827
2828 window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowRef) -1);
2829
2830 SetPortWindowPort (window_ptr);
2831
2832 TextFont (0);
2833 /* Left and right margins in the dialog are 13 pixels each.*/
2834 dialog_width = 14;
2835 /* Calculate width of dialog box: 8 pixels on each side of the text
2836 label in each button, 12 pixels between buttons. */
2837 for (i = 0; i < nb_buttons; i++)
2838 dialog_width += StringWidth (button_labels[i]) + 16 + 12;
2839
2840 if (left_count != 0 && nb_buttons - left_count != 0)
2841 dialog_width += 12;
2842
2843 dialog_width = max (dialog_width, StringWidth (prompt) + 26);
2844
2845 SizeWindow (window_ptr, dialog_width, 78, 0);
2846 ShowWindow (window_ptr);
2847
2848 SetPortWindowPort (window_ptr);
2849
2850 TextFont (0);
2851
2852 MoveTo (13, 29);
2853 DrawString (prompt);
2854
2855 left = 13;
2856 for (i = 0; i < nb_buttons; i++)
2857 {
2858 int button_width = StringWidth (button_labels[i]) + 16;
2859 SetRect (&rect, left, 45, left + button_width, 65);
2860 ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0,
2861 kControlPushButtonProc, ref_cons[i]);
2862 left += button_width + 12;
2863 if (i == left_count - 1)
2864 left += 12;
2865 }
2866
2867 i = 0;
2868 while (!i)
2869 {
2870 if (WaitNextEvent (mDownMask, &event_record, 10, NULL))
2871 if (event_record.what == mouseDown)
2872 {
2873 part_code = FindWindow (event_record.where, &window_ptr);
2874 if (part_code == inContent)
2875 {
2876 mouse = event_record.where;
2877 GlobalToLocal (&mouse);
2878 control_part_code = FindControl (mouse, window_ptr, &ch);
2879 if (control_part_code == kControlButtonPart)
2880 if (TrackControl (ch, mouse, NULL))
2881 i = GetControlReference (ch);
2882 }
2883 }
2884 }
2885
2886 DisposeWindow (window_ptr);
2887
2888 return i;
2889}
2890#endif /* not TARGET_API_MAC_CARBON */
2891
2892static char * button_names [] = { 1849static char * button_names [] = {
2893 "button1", "button2", "button3", "button4", "button5", 1850 "button1", "button2", "button3", "button4", "button5",
2894 "button6", "button7", "button8", "button9", "button10" }; 1851 "button6", "button7", "button8", "button9", "button10" };
@@ -2902,7 +1859,6 @@ mac_dialog_show (f, keymaps, title, header, error_name)
2902{ 1859{
2903 int i, nb_buttons=0; 1860 int i, nb_buttons=0;
2904 char dialog_name[6]; 1861 char dialog_name[6];
2905 int menu_item_selection;
2906 1862
2907 widget_value *wv, *first_wv = 0, *prev_wv = 0; 1863 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2908 1864
@@ -3019,6 +1975,9 @@ mac_dialog_show (f, keymaps, title, header, error_name)
3019 first_wv = wv; 1975 first_wv = wv;
3020 } 1976 }
3021 1977
1978 /* No selection has been chosen yet. */
1979 menu_item_selection = 0;
1980
3022 /* Force a redisplay before showing the dialog. If a frame is created 1981 /* Force a redisplay before showing the dialog. If a frame is created
3023 just before showing the dialog, its contents may not have been fully 1982 just before showing the dialog, its contents may not have been fully
3024 drawn. */ 1983 drawn. */
@@ -3026,7 +1985,7 @@ mac_dialog_show (f, keymaps, title, header, error_name)
3026 1985
3027 /* Actually create the dialog. */ 1986 /* Actually create the dialog. */
3028#if TARGET_API_MAC_CARBON 1987#if TARGET_API_MAC_CARBON
3029 menu_item_selection = create_and_show_dialog (f, first_wv); 1988 create_and_show_dialog (f, first_wv);
3030#else 1989#else
3031 menu_item_selection = mac_dialog (first_wv); 1990 menu_item_selection = mac_dialog (first_wv);
3032#endif 1991#endif
@@ -3086,7 +2045,7 @@ mac_dialog_show (f, keymaps, title, header, error_name)
3086 2045
3087 2046
3088/* Is this item a separator? */ 2047/* Is this item a separator? */
3089static int 2048int
3090name_is_separator (name) 2049name_is_separator (name)
3091 const char *name; 2050 const char *name;
3092{ 2051{
@@ -3099,260 +2058,6 @@ name_is_separator (name)
3099 them like normal separators. */ 2058 them like normal separators. */
3100 return (*name == '\0' || start + 2 == name); 2059 return (*name == '\0' || start + 2 == name);
3101} 2060}
3102
3103static void
3104add_menu_item (menu, pos, wv)
3105 MenuRef menu;
3106 int pos;
3107 widget_value *wv;
3108{
3109#if TARGET_API_MAC_CARBON
3110 CFStringRef item_name;
3111#else
3112 Str255 item_name;
3113#endif
3114
3115 if (name_is_separator (wv->name))
3116 AppendMenu (menu, "\p-");
3117 else
3118 {
3119 AppendMenu (menu, "\pX");
3120
3121#if TARGET_API_MAC_CARBON
3122 item_name = cfstring_create_with_utf8_cstring (wv->name);
3123
3124 if (wv->key != NULL)
3125 {
3126 CFStringRef name, key;
3127
3128 name = item_name;
3129 key = cfstring_create_with_utf8_cstring (wv->key);
3130 item_name = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@ %@"),
3131 name, key);
3132 CFRelease (name);
3133 CFRelease (key);
3134 }
3135
3136 SetMenuItemTextWithCFString (menu, pos, item_name);
3137 CFRelease (item_name);
3138
3139 if (wv->enabled)
3140 EnableMenuItem (menu, pos);
3141 else
3142 DisableMenuItem (menu, pos);
3143
3144 if (STRINGP (wv->help))
3145 SetMenuItemProperty (menu, pos, MAC_EMACS_CREATOR_CODE, 'help',
3146 sizeof (Lisp_Object), &wv->help);
3147#else /* ! TARGET_API_MAC_CARBON */
3148 item_name[sizeof (item_name) - 1] = '\0';
3149 strncpy (item_name, wv->name, sizeof (item_name) - 1);
3150 if (wv->key != NULL)
3151 {
3152 int len = strlen (item_name);
3153
3154 strncpy (item_name + len, " ", sizeof (item_name) - 1 - len);
3155 len = strlen (item_name);
3156 strncpy (item_name + len, wv->key, sizeof (item_name) - 1 - len);
3157 }
3158 c2pstr (item_name);
3159 SetMenuItemText (menu, pos, item_name);
3160
3161 if (wv->enabled)
3162 EnableItem (menu, pos);
3163 else
3164 DisableItem (menu, pos);
3165#endif /* ! TARGET_API_MAC_CARBON */
3166
3167 /* Draw radio buttons and tickboxes. */
3168 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
3169 wv->button_type == BUTTON_TYPE_RADIO))
3170 SetItemMark (menu, pos, checkMark);
3171 else
3172 SetItemMark (menu, pos, noMark);
3173
3174 SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
3175 }
3176}
3177
3178/* Construct native Mac OS menu based on widget_value tree. */
3179
3180static int
3181fill_menu (menu, wv, kind, submenu_id)
3182 MenuRef menu;
3183 widget_value *wv;
3184 enum mac_menu_kind kind;
3185 int submenu_id;
3186{
3187 int pos;
3188
3189 for (pos = 1; wv != NULL; wv = wv->next, pos++)
3190 {
3191 add_menu_item (menu, pos, wv);
3192 if (wv->contents && submenu_id < min_menu_id[kind + 1])
3193 {
3194 MenuRef submenu = NewMenu (submenu_id, "\pX");
3195
3196 InsertMenu (submenu, -1);
3197#if TARGET_API_MAC_CARBON
3198 SetMenuItemHierarchicalMenu (menu, pos, submenu);
3199#else
3200 SetMenuItemHierarchicalID (menu, pos, submenu_id);
3201#endif
3202 submenu_id = fill_menu (submenu, wv->contents, kind, submenu_id + 1);
3203 }
3204 }
3205
3206 return submenu_id;
3207}
3208
3209/* Construct native Mac OS menubar based on widget_value tree. */
3210
3211static void
3212fill_menubar (wv, deep_p)
3213 widget_value *wv;
3214 int deep_p;
3215{
3216 int id, submenu_id;
3217#if !TARGET_API_MAC_CARBON
3218 int title_changed_p = 0;
3219#endif
3220
3221 /* Clean up the menu bar when filled by the entire menu trees. */
3222 if (deep_p)
3223 {
3224 dispose_menus (MAC_MENU_MENU_BAR, 0);
3225 dispose_menus (MAC_MENU_MENU_BAR_SUB, 0);
3226#if !TARGET_API_MAC_CARBON
3227 title_changed_p = 1;
3228#endif
3229 }
3230
3231 /* Fill menu bar titles and submenus. Reuse the existing menu bar
3232 titles as much as possible to minimize redraw (if !deep_p). */
3233 submenu_id = min_menu_id[MAC_MENU_MENU_BAR_SUB];
3234 for (id = min_menu_id[MAC_MENU_MENU_BAR];
3235 wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1];
3236 wv = wv->next, id++)
3237 {
3238 OSStatus err = noErr;
3239 MenuRef menu;
3240#if TARGET_API_MAC_CARBON
3241 CFStringRef title;
3242
3243 title = CFStringCreateWithCString (NULL, wv->name,
3244 kCFStringEncodingMacRoman);
3245#else
3246 Str255 title;
3247
3248 strncpy (title, wv->name, 255);
3249 title[255] = '\0';
3250 c2pstr (title);
3251#endif
3252
3253 menu = GetMenuRef (id);
3254 if (menu)
3255 {
3256#if TARGET_API_MAC_CARBON
3257 CFStringRef old_title;
3258
3259 err = CopyMenuTitleAsCFString (menu, &old_title);
3260 if (err == noErr)
3261 {
3262 if (CFStringCompare (title, old_title, 0) != kCFCompareEqualTo)
3263 {
3264#ifdef MAC_OSX
3265 if (id + 1 == min_menu_id[MAC_MENU_MENU_BAR + 1]
3266 || GetMenuRef (id + 1) == NULL)
3267 {
3268 /* This is a workaround for Mac OS X 10.5 where
3269 just calling SetMenuTitleWithCFString fails
3270 to change the title of the last (Help) menu
3271 in the menu bar. */
3272 DeleteMenu (id);
3273 DisposeMenu (menu);
3274 menu = NULL;
3275 }
3276 else
3277#endif /* MAC_OSX */
3278 err = SetMenuTitleWithCFString (menu, title);
3279 }
3280 CFRelease (old_title);
3281 }
3282 else
3283 err = SetMenuTitleWithCFString (menu, title);
3284#else /* !TARGET_API_MAC_CARBON */
3285 if (!EqualString (title, (*menu)->menuData, false, false))
3286 {
3287 DeleteMenu (id);
3288 DisposeMenu (menu);
3289 menu = NewMenu (id, title);
3290 InsertMenu (menu, GetMenuRef (id + 1) ? id + 1 : 0);
3291 title_changed_p = 1;
3292 }
3293#endif /* !TARGET_API_MAC_CARBON */
3294 }
3295
3296 if (!menu)
3297 {
3298#if TARGET_API_MAC_CARBON
3299 err = CreateNewMenu (id, 0, &menu);
3300 if (err == noErr)
3301 err = SetMenuTitleWithCFString (menu, title);
3302#else
3303 menu = NewMenu (id, title);
3304#endif
3305 if (err == noErr)
3306 {
3307 InsertMenu (menu, 0);
3308#if !TARGET_API_MAC_CARBON
3309 title_changed_p = 1;
3310#endif
3311 }
3312 }
3313#if TARGET_API_MAC_CARBON
3314 CFRelease (title);
3315#endif
3316
3317 if (err == noErr)
3318 if (wv->contents)
3319 submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
3320 submenu_id);
3321 }
3322
3323 if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuRef (id))
3324 {
3325 dispose_menus (MAC_MENU_MENU_BAR, id);
3326#if !TARGET_API_MAC_CARBON
3327 title_changed_p = 1;
3328#endif
3329 }
3330
3331#if !TARGET_API_MAC_CARBON
3332 if (title_changed_p)
3333 InvalMenuBar ();
3334#endif
3335}
3336
3337/* Dispose of menus that belong to KIND, and remove them from the menu
3338 list. ID is the lower bound of menu IDs that will be processed. */
3339
3340static void
3341dispose_menus (kind, id)
3342 enum mac_menu_kind kind;
3343 int id;
3344{
3345 for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++)
3346 {
3347 MenuRef menu = GetMenuRef (id);
3348
3349 if (menu == NULL)
3350 break;
3351 DeleteMenu (id);
3352 DisposeMenu (menu);
3353 }
3354}
3355
3356#endif /* HAVE_MENUS */ 2061#endif /* HAVE_MENUS */
3357 2062
3358/* Detect if a menu is currently active. */ 2063/* Detect if a menu is currently active. */