comparison src/macmenu.c @ 80453:07666d9ede23

[!TARGET_API_MAC_CARBON]: Move includes to mactoolbox.c. (enum mac_menu_kind): Move enum to mactoolbox.c. (min_menu_id): Move variable to mactoolbox.c. (quit_dialog_event_loop) [TARGET_API_MAC_CARBON]: Likewise. (DIALOG_WINDOW_RESOURCE): Move define to mactoolbox.c. (DIALOG_BUTTON_COMMAND_ID_OFFSET, DIALOG_BUTTON_COMMAND_ID_P) (DIALOG_BUTTON_COMMAND_ID_VALUE, DIALOG_BUTTON_MAKE_COMMAND_ID) [TARGET_API_MAC_CARBON]: Likewise. (XtPointer): Move typedef to macgui.h. (enum button_type): Move enum to macgui.h. (widget_value): Move typedef to macgui.h. (DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN, DIALOG_RIGHT_MARGIN) (DIALOG_BOTTOM_MARGIN, DIALOG_MIN_INNER_WIDTH, DIALOG_MAX_INNER_WIDTH) (DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE) (DIALOG_BUTTON_BUTTON_VERTICAL_SPACE, DIALOG_BUTTON_MIN_WIDTH) (DIALOG_TEXT_MIN_HEIGHT, DIALOG_TEXT_BUTTONS_VERTICAL_SPACE) (DIALOG_ICON_WIDTH, DIALOG_ICON_HEIGHT, DIALOG_ICON_LEFT_MARGIN) (DIALOG_ICON_TOP_MARGIN): Move defines to macgui.h. (popup_activated_flag): Make variable non-static. (x_activate_menubar, install_menu_quit_handler, pop_down_menu) (add_menu_item, fill_menu, dispose_menus): Move functions to mactoolbox.c. (restore_show_help_function, menu_target_item_handler) (install_menu_target_item_handler, mac_handle_dialog_event) (install_dialog_event_handler, pop_down_dialog, create_and_show_dialog) [TARGET_API_MAC_CARBON]: Likewise. (menu_quit_handler) [MAC_OS_X_VERSION_MAX_ALLOWED >= 1030]: Likewise. (mac_dialog) [!TARGET_API_MAC_CARBON]: Likewise. (find_and_call_menu_selection, name_is_separator): Make function non-static. (Vshow_help_function, timer_check) [TARGET_API_MAC_CARBON]: Move extern to mactoolbox.c. (set_frame_menubar): Don't call install_menu_quit_handler. (menu_item_selection): New variable. (mac_menu_show): Use create_and_show_popup_menu. (create_and_show_dialog) [TARGET_API_MAC_CARBON]: Don't return selection but set variable menu_item_selection. All uses changed. (mac_fill_menubar): Rename from fill_menubar. All uses changed. Call install_menu_quit_handler. Move to mactoolbox.c.
author YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
date Sun, 06 Apr 2008 01:58:19 +0000
parents 59863894d837
children a044f4615c60 3af508d0bd74
comparison
equal deleted inserted replaced
80452:6d01fa145e93 80453:07666d9ede23
34 #include "blockinput.h" 34 #include "blockinput.h"
35 #include "buffer.h" 35 #include "buffer.h"
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"
56 42
57 /* Load sys/types.h if not already loaded. 43 /* Load sys/types.h if not already loaded.
60 #include <sys/types.h> 46 #include <sys/types.h>
61 #endif 47 #endif
62 48
63 #include "dispextern.h" 49 #include "dispextern.h"
64 50
65 enum 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
76 static 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
83 54
84 #undef HAVE_MULTILINGUAL_MENU 55 #undef HAVE_MULTILINGUAL_MENU
85 56
86 /******************************************************************/ 57 /******************************************************************/
87 /* Definitions copied from lwlib.h */
88
89 typedef void * XtPointer;
90
91 enum 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. */
100 typedef 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)),\
153 0, (sizeof (widget_value))) 61 0, (sizeof (widget_value)))
154 #define free_widget_value(wv) xfree (wv) 62 #define free_widget_value(wv) xfree (wv)
196 static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object, 104 static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
197 int, int)); 105 int, int));
198 static void list_of_panes P_ ((Lisp_Object)); 106 static void list_of_panes P_ ((Lisp_Object));
199 static void list_of_items P_ ((Lisp_Object)); 107 static void list_of_items P_ ((Lisp_Object));
200 108
201 static void find_and_call_menu_selection P_ ((FRAME_PTR, int, Lisp_Object,
202 void *));
203 static int fill_menu P_ ((MenuRef, widget_value *, enum mac_menu_kind, int));
204 static void fill_menubar P_ ((widget_value *, int));
205 static 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.
210 112
211 It describes the panes and items within the panes. 113 It describes the panes and items within the panes.
258 160
259 /* Current depth within submenus. */ 161 /* Current depth within submenus. */
260 static int menu_items_submenu_depth; 162 static int menu_items_submenu_depth;
261 163
262 /* Nonzero means a menu is currently active. */ 164 /* Nonzero means a menu is currently active. */
263 static int popup_activated_flag; 165 int 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.
267 While it is nonzero, all calls to set_frame_menubar go deep. 169 While it is nonzero, all calls to set_frame_menubar go deep.
268 170
878 return selection; 780 return selection;
879 } 781 }
880 782
881 #ifdef HAVE_MENUS 783 #ifdef HAVE_MENUS
882 784
883 /* Regard ESC and C-g as Cancel even without the Cancel button. */
884
885 #if 0 /* defined (MAC_OSX) */
886 static Boolean
887 mac_dialog_modal_filter (dialog, event, item_hit)
888 DialogRef dialog;
889 EventRecord *event;
890 DialogItemIndex *item_hit;
891 {
892 Boolean result;
893
894 result = StdFilterProc (dialog, event, item_hit);
895 if (result == false
896 && (event->what == keyDown || event->what == autoKey)
897 && ((event->message & charCodeMask) == kEscapeCharCode
898 || mac_quit_char_key_p (event->modifiers,
899 (event->message & keyCodeMask) >> 8)))
900 {
901 *item_hit = kStdCancelItemIndex;
902 return true;
903 }
904
905 return result;
906 }
907 #endif
908
909 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0, 785 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
910 doc: /* Pop up a dialog box and return user's selection. 786 doc: /* Pop up a dialog box and return user's selection.
911 POSITION specifies which frame to use. 787 POSITION specifies which frame to use.
912 This is normally a mouse button event or a window or frame. 788 This is normally a mouse button event or a window or frame.
913 If POSITION is t, it means to use the frame the mouse is on. 789 If POSITION is t, it means to use the frame the mouse is on.
989 else 865 else
990 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME, 866 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME,
991 but I don't want to make one now. */ 867 but I don't want to make one now. */
992 CHECK_WINDOW (window); 868 CHECK_WINDOW (window);
993 869
994 #if 0 /* defined (MAC_OSX) */
995 /* Special treatment for Fmessage_box, Fyes_or_no_p, and Fy_or_n_p. */
996 if (EQ (position, Qt)
997 && STRINGP (Fcar (contents))
998 && ((!NILP (Fequal (XCDR (contents),
999 Fcons (Fcons (build_string ("OK"), Qt), Qnil)))
1000 && EQ (header, Qt))
1001 || (!NILP (Fequal (XCDR (contents),
1002 Fcons (Fcons (build_string ("Yes"), Qt),
1003 Fcons (Fcons (build_string ("No"), Qnil),
1004 Qnil))))
1005 && NILP (header))))
1006 {
1007 OSStatus err = noErr;
1008 AlertStdCFStringAlertParamRec param;
1009 CFStringRef error_string, explanation_string;
1010 DialogRef alert;
1011 DialogItemIndex item_hit;
1012 Lisp_Object tem;
1013
1014 /* Force a redisplay before showing the dialog. If a frame is
1015 created just before showing the dialog, its contents may not
1016 have been fully drawn. */
1017 Fredisplay (Qt);
1018
1019 tem = Fstring_match (concat3 (build_string ("\\("),
1020 call0 (intern ("sentence-end")),
1021 build_string ("\\)\n")),
1022 XCAR (contents), Qnil);
1023 BLOCK_INPUT;
1024 if (NILP (tem))
1025 {
1026 error_string = cfstring_create_with_string (XCAR (contents));
1027 if (error_string == NULL)
1028 err = memFullErr;
1029 explanation_string = NULL;
1030 }
1031 else
1032 {
1033 tem = Fmatch_end (make_number (1));
1034 error_string =
1035 cfstring_create_with_string (Fsubstring (XCAR (contents),
1036 make_number (0), tem));
1037 if (error_string == NULL)
1038 err = memFullErr;
1039 else
1040 {
1041 XSETINT (tem, XINT (tem) + 1);
1042 explanation_string =
1043 cfstring_create_with_string (Fsubstring (XCAR (contents),
1044 tem, Qnil));
1045 if (explanation_string == NULL)
1046 {
1047 CFRelease (error_string);
1048 err = memFullErr;
1049 }
1050 }
1051 }
1052 if (err == noErr)
1053 err = GetStandardAlertDefaultParams (&param,
1054 kStdCFStringAlertVersionOne);
1055 if (err == noErr)
1056 {
1057 param.movable = true;
1058 param.position = kWindowAlertPositionParentWindow;
1059 if (NILP (header))
1060 {
1061 param.defaultText = CFSTR ("Yes");
1062 param.otherText = CFSTR ("No");
1063 #if 0
1064 param.cancelText = CFSTR ("Cancel");
1065 param.cancelButton = kAlertStdAlertCancelButton;
1066 #endif
1067 }
1068 err = CreateStandardAlert (kAlertNoteAlert, error_string,
1069 explanation_string, &param, &alert);
1070 CFRelease (error_string);
1071 if (explanation_string)
1072 CFRelease (explanation_string);
1073 }
1074 if (err == noErr)
1075 err = RunStandardAlert (alert, mac_dialog_modal_filter, &item_hit);
1076 UNBLOCK_INPUT;
1077
1078 if (err == noErr)
1079 {
1080 if (item_hit == kStdCancelItemIndex)
1081 Fsignal (Qquit, Qnil);
1082 else if (item_hit == kStdOkItemIndex)
1083 return Qt;
1084 else
1085 return Qnil;
1086 }
1087 }
1088 #endif
1089 #ifndef HAVE_DIALOGS 870 #ifndef HAVE_DIALOGS
1090 /* Display a menu with these alternatives 871 /* Display a menu with these alternatives
1091 in the middle of frame F. */ 872 in the middle of frame F. */
1092 { 873 {
1093 Lisp_Object x, y, frame, newpos; 874 Lisp_Object x, y, frame, newpos;
1123 return selection; 904 return selection;
1124 } 905 }
1125 #endif /* HAVE_DIALOGS */ 906 #endif /* HAVE_DIALOGS */
1126 } 907 }
1127 908
1128 /* Activate the menu bar of frame F.
1129 This is called from keyboard.c when it gets the
1130 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
1131
1132 To activate the menu bar, we use the button-press event location
1133 that was saved in saved_menu_event_location.
1134
1135 But first we recompute the menu bar contents (the whole tree).
1136
1137 The reason for saving the button event until here, instead of
1138 passing it to the toolkit right away, is that we can safely
1139 execute Lisp code. */
1140
1141 void
1142 x_activate_menubar (f)
1143 FRAME_PTR f;
1144 {
1145 SInt32 menu_choice;
1146 SInt16 menu_id, menu_item;
1147 extern Point saved_menu_event_location;
1148
1149 set_frame_menubar (f, 0, 1);
1150 BLOCK_INPUT;
1151
1152 popup_activated_flag = 1;
1153 menu_choice = MenuSelect (saved_menu_event_location);
1154 popup_activated_flag = 0;
1155 menu_id = HiWord (menu_choice);
1156 menu_item = LoWord (menu_choice);
1157
1158 #if !TARGET_API_MAC_CARBON
1159 if (menu_id == min_menu_id[MAC_MENU_M_APPLE])
1160 do_apple_menu (menu_item);
1161 else
1162 #endif
1163 if (menu_id)
1164 {
1165 MenuRef menu = GetMenuRef (menu_id);
1166
1167 if (menu)
1168 {
1169 UInt32 refcon;
1170
1171 GetMenuItemRefCon (menu, menu_item, &refcon);
1172 find_and_call_menu_selection (f, f->menu_bar_items_used,
1173 f->menu_bar_vector, (void *) refcon);
1174 }
1175 }
1176
1177 HiliteMenu (0);
1178
1179 UNBLOCK_INPUT;
1180 }
1181
1182 /* Find the menu selection and store it in the keyboard buffer. 909 /* Find the menu selection and store it in the keyboard buffer.
1183 F is the frame the menu is on. 910 F is the frame the menu is on.
1184 MENU_BAR_ITEMS_USED is the length of VECTOR. 911 MENU_BAR_ITEMS_USED is the length of VECTOR.
1185 VECTOR is an array of menu events for the whole menu. */ 912 VECTOR is an array of menu events for the whole menu. */
1186 913
1187 static void 914 void
1188 find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data) 915 find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data)
1189 FRAME_PTR f; 916 FRAME_PTR f;
1190 int menu_bar_items_used; 917 int menu_bar_items_used;
1191 Lisp_Object vector; 918 Lisp_Object vector;
1192 void *client_data; 919 void *client_data;
1575 update_submenu_strings (wv->contents); 1302 update_submenu_strings (wv->contents);
1576 } 1303 }
1577 } 1304 }
1578 1305
1579 1306
1580 #if TARGET_API_MAC_CARBON
1581 extern Lisp_Object Vshow_help_function;
1582
1583 static Lisp_Object
1584 restore_show_help_function (old_show_help_function)
1585 Lisp_Object old_show_help_function;
1586 {
1587 Vshow_help_function = old_show_help_function;
1588
1589 return Qnil;
1590 }
1591
1592 static pascal OSStatus
1593 menu_target_item_handler (next_handler, event, data)
1594 EventHandlerCallRef next_handler;
1595 EventRef event;
1596 void *data;
1597 {
1598 OSStatus err;
1599 MenuRef menu;
1600 MenuItemIndex menu_item;
1601 Lisp_Object help;
1602 GrafPtr port;
1603 int specpdl_count = SPECPDL_INDEX ();
1604
1605 /* Don't be bothered with the overflowed toolbar items menu. */
1606 if (!popup_activated ())
1607 return eventNotHandledErr;
1608
1609 err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef,
1610 NULL, sizeof (MenuRef), NULL, &menu);
1611 if (err == noErr)
1612 err = GetEventParameter (event, kEventParamMenuItemIndex,
1613 typeMenuItemIndex, NULL,
1614 sizeof (MenuItemIndex), NULL, &menu_item);
1615 if (err == noErr)
1616 err = GetMenuItemProperty (menu, menu_item,
1617 MAC_EMACS_CREATOR_CODE, 'help',
1618 sizeof (Lisp_Object), NULL, &help);
1619 if (err != noErr)
1620 help = Qnil;
1621
1622 /* Temporarily bind Vshow_help_function to Qnil because we don't
1623 want tooltips during menu tracking. */
1624 record_unwind_protect (restore_show_help_function, Vshow_help_function);
1625 Vshow_help_function = Qnil;
1626 GetPort (&port);
1627 show_help_echo (help, Qnil, Qnil, Qnil, 1);
1628 SetPort (port);
1629 unbind_to (specpdl_count, Qnil);
1630
1631 return err == noErr ? noErr : eventNotHandledErr;
1632 }
1633
1634 OSStatus
1635 install_menu_target_item_handler ()
1636 {
1637 static const EventTypeSpec specs[] =
1638 {{kEventClassMenu, kEventMenuTargetItem}};
1639
1640 return InstallApplicationEventHandler (NewEventHandlerUPP
1641 (menu_target_item_handler),
1642 GetEventTypeCount (specs),
1643 specs, NULL, NULL);
1644 }
1645 #endif /* TARGET_API_MAC_CARBON */
1646
1647 /* Event handler function that pops down a menu on C-g. We can only pop
1648 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
1649
1650 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1651 static pascal OSStatus
1652 menu_quit_handler (nextHandler, theEvent, userData)
1653 EventHandlerCallRef nextHandler;
1654 EventRef theEvent;
1655 void* userData;
1656 {
1657 OSStatus err;
1658 UInt32 keyCode;
1659 UInt32 keyModifiers;
1660
1661 err = GetEventParameter (theEvent, kEventParamKeyCode,
1662 typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
1663
1664 if (err == noErr)
1665 err = GetEventParameter (theEvent, kEventParamKeyModifiers,
1666 typeUInt32, NULL, sizeof(UInt32),
1667 NULL, &keyModifiers);
1668
1669 if (err == noErr && mac_quit_char_key_p (keyModifiers, keyCode))
1670 {
1671 MenuRef menu = userData != 0
1672 ? (MenuRef)userData : AcquireRootMenu ();
1673
1674 CancelMenuTracking (menu, true, 0);
1675 if (!userData) ReleaseMenu (menu);
1676 return noErr;
1677 }
1678
1679 return CallNextEventHandler (nextHandler, theEvent);
1680 }
1681 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1682
1683 /* Add event handler to all menus that belong to KIND so we can detect
1684 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
1685 when C-g is detected. NULL means the menu bar. If
1686 CancelMenuTracking isn't available, do nothing. */
1687
1688 static void
1689 install_menu_quit_handler (kind, root_menu)
1690 enum mac_menu_kind kind;
1691 MenuRef root_menu;
1692 {
1693 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1694 static const EventTypeSpec typesList[] =
1695 {{kEventClassKeyboard, kEventRawKeyDown}};
1696 int id;
1697
1698 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1699 if (CancelMenuTracking == NULL)
1700 return;
1701 #endif
1702 for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++)
1703 {
1704 MenuRef menu = GetMenuRef (id);
1705
1706 if (menu == NULL)
1707 break;
1708 InstallMenuEventHandler (menu, menu_quit_handler,
1709 GetEventTypeCount (typesList),
1710 typesList, root_menu, NULL);
1711 }
1712 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1713 }
1714
1715 /* Set the contents of the menubar widgets of frame F. 1307 /* Set the contents of the menubar widgets of frame F.
1716 The argument FIRST_TIME is currently ignored; 1308 The argument FIRST_TIME is currently ignored;
1717 it is set the first time this is called, from initialize_frame_menubar. */ 1309 it is set the first time this is called, from initialize_frame_menubar. */
1718 1310
1719 void 1311 void
1945 BLOCK_INPUT; 1537 BLOCK_INPUT;
1946 1538
1947 /* Non-null value to indicate menubar has already been "created". */ 1539 /* Non-null value to indicate menubar has already been "created". */
1948 f->output_data.mac->menubar_widget = 1; 1540 f->output_data.mac->menubar_widget = 1;
1949 1541
1950 fill_menubar (first_wv->contents, deep_p); 1542 mac_fill_menubar (first_wv->contents, deep_p);
1951 1543
1952 /* Add event handler so we can detect C-g. */
1953 install_menu_quit_handler (MAC_MENU_MENU_BAR, NULL);
1954 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB, NULL);
1955 free_menubar_widget_value_tree (first_wv); 1544 free_menubar_widget_value_tree (first_wv);
1956 1545
1957 UNBLOCK_INPUT; 1546 UNBLOCK_INPUT;
1958 } 1547 }
1959 1548
1966 { 1555 {
1967 f->output_data.mac->menubar_widget = 0; 1556 f->output_data.mac->menubar_widget = 0;
1968 } 1557 }
1969 1558
1970 1559
1971 static Lisp_Object 1560 /* The item selected in the popup menu. */
1972 pop_down_menu (arg) 1561 int menu_item_selection;
1973 Lisp_Object arg;
1974 {
1975 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1976 FRAME_PTR f = p->pointer;
1977 MenuRef menu = GetMenuRef (min_menu_id[MAC_MENU_POPUP]);
1978
1979 BLOCK_INPUT;
1980
1981 /* Must reset this manually because the button release event is not
1982 passed to Emacs event loop. */
1983 FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0;
1984
1985 /* delete all menus */
1986 dispose_menus (MAC_MENU_POPUP_SUB, 0);
1987 DeleteMenu (min_menu_id[MAC_MENU_POPUP]);
1988 DisposeMenu (menu);
1989
1990 UNBLOCK_INPUT;
1991
1992 return Qnil;
1993 }
1994 1562
1995 /* Mac_menu_show actually displays a menu using the panes and items in 1563 /* Mac_menu_show actually displays a menu using the panes and items in
1996 menu_items and returns the value selected from it; we assume input 1564 menu_items and returns the value selected from it; we assume input
1997 is blocked by the caller. */ 1565 is blocked by the caller. */
1998 1566
2016 int keymaps; 1584 int keymaps;
2017 Lisp_Object title; 1585 Lisp_Object title;
2018 char **error; 1586 char **error;
2019 { 1587 {
2020 int i; 1588 int i;
2021 int menu_item_choice;
2022 UInt32 menu_item_selection;
2023 MenuRef menu;
2024 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; 1589 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
2025 widget_value **submenu_stack 1590 widget_value **submenu_stack
2026 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); 1591 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
2027 Lisp_Object *subprefix_stack 1592 Lisp_Object *subprefix_stack
2028 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); 1593 = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object));
2029 int submenu_depth = 0; 1594 int submenu_depth = 0;
2030 1595
2031 int first_pane; 1596 int first_pane;
2032 int specpdl_count = SPECPDL_INDEX ();
2033 1597
2034 *error = NULL; 1598 *error = NULL;
2035 1599
2036 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH) 1600 if (menu_items_used <= MENU_ITEMS_PANE_LENGTH)
2037 { 1601 {
2213 wv_title->help = Qnil; 1777 wv_title->help = Qnil;
2214 wv_title->next = wv_sep; 1778 wv_title->next = wv_sep;
2215 first_wv->contents = wv_title; 1779 first_wv->contents = wv_title;
2216 } 1780 }
2217 1781
2218 /* Actually create the menu. */
2219 menu = NewMenu (min_menu_id[MAC_MENU_POPUP], "\p");
2220 InsertMenu (menu, -1);
2221 fill_menu (menu, first_wv->contents, MAC_MENU_POPUP_SUB,
2222 min_menu_id[MAC_MENU_POPUP_SUB]);
2223
2224 /* Free the widget_value objects we used to specify the
2225 contents. */
2226 free_menubar_widget_value_tree (first_wv);
2227
2228 /* Adjust coordinates to be root-window-relative. */
2229 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
2230 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
2231
2232 /* No selection has been chosen yet. */ 1782 /* No selection has been chosen yet. */
2233 menu_item_selection = 0; 1783 menu_item_selection = 0;
2234 1784
2235 record_unwind_protect (pop_down_menu, make_save_value (f, 0)); 1785 /* Actually create and show the menu until popped down. */
2236 1786 create_and_show_popup_menu (f, first_wv, x, y, for_click);
2237 /* Add event handler so we can detect C-g. */ 1787
2238 install_menu_quit_handler (MAC_MENU_POPUP, menu); 1788 /* Free the widget_value objects we used to specify the contents. */
2239 install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu); 1789 free_menubar_widget_value_tree (first_wv);
2240
2241 /* Display the menu. */
2242 popup_activated_flag = 1;
2243 menu_item_choice = PopUpMenuSelect (menu, y, x, 0);
2244 popup_activated_flag = 0;
2245
2246 /* Get the refcon to find the correct item */
2247 if (menu_item_choice)
2248 {
2249 MenuRef sel_menu = GetMenuRef (HiWord (menu_item_choice));
2250
2251 if (sel_menu)
2252 GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice),
2253 &menu_item_selection);
2254 }
2255
2256 unbind_to (specpdl_count, Qnil);
2257 1790
2258 /* Find the selected item, and its pane, to return 1791 /* Find the selected item, and its pane, to return
2259 the proper value. */ 1792 the proper value. */
2260 if (menu_item_selection != 0) 1793 if (menu_item_selection != 0)
2261 { 1794 {
2318 1851
2319 1852
2320 #ifdef HAVE_DIALOGS 1853 #ifdef HAVE_DIALOGS
2321 /* Construct native Mac OS dialog based on widget_value tree. */ 1854 /* Construct native Mac OS dialog based on widget_value tree. */
2322 1855
2323 #if TARGET_API_MAC_CARBON
2324
2325 #define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
2326 #define DIALOG_BUTTON_COMMAND_ID_P(id) \
2327 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
2328 #define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
2329 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
2330 #define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
2331 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
2332
2333 extern EMACS_TIME timer_check P_ ((int));
2334 static int quit_dialog_event_loop;
2335
2336 static pascal OSStatus
2337 mac_handle_dialog_event (next_handler, event, data)
2338 EventHandlerCallRef next_handler;
2339 EventRef event;
2340 void *data;
2341 {
2342 OSStatus err, result = eventNotHandledErr;
2343 WindowRef window = (WindowRef) data;
2344
2345 switch (GetEventClass (event))
2346 {
2347 case kEventClassCommand:
2348 {
2349 HICommand command;
2350
2351 err = GetEventParameter (event, kEventParamDirectObject,
2352 typeHICommand, NULL, sizeof (HICommand),
2353 NULL, &command);
2354 if (err == noErr)
2355 if (DIALOG_BUTTON_COMMAND_ID_P (command.commandID))
2356 {
2357 SetWRefCon (window, command.commandID);
2358 quit_dialog_event_loop = 1;
2359 break;
2360 }
2361
2362 result = CallNextEventHandler (next_handler, event);
2363 }
2364 break;
2365
2366 case kEventClassKeyboard:
2367 {
2368 OSStatus result;
2369 char char_code;
2370
2371 result = CallNextEventHandler (next_handler, event);
2372 if (result != eventNotHandledErr)
2373 break;
2374
2375 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
2376 typeChar, NULL, sizeof (char),
2377 NULL, &char_code);
2378 if (err == noErr)
2379 switch (char_code)
2380 {
2381 case kEscapeCharCode:
2382 quit_dialog_event_loop = 1;
2383 break;
2384
2385 default:
2386 {
2387 UInt32 modifiers, key_code;
2388
2389 err = GetEventParameter (event, kEventParamKeyModifiers,
2390 typeUInt32, NULL, sizeof (UInt32),
2391 NULL, &modifiers);
2392 if (err == noErr)
2393 err = GetEventParameter (event, kEventParamKeyCode,
2394 typeUInt32, NULL, sizeof (UInt32),
2395 NULL, &key_code);
2396 if (err == noErr)
2397 if (mac_quit_char_key_p (modifiers, key_code))
2398 quit_dialog_event_loop = 1;
2399 }
2400 break;
2401 }
2402 }
2403 break;
2404
2405 default:
2406 abort ();
2407 }
2408
2409 if (quit_dialog_event_loop)
2410 {
2411 err = QuitEventLoop (GetCurrentEventLoop ());
2412 if (err == noErr)
2413 result = noErr;
2414 }
2415
2416 return result;
2417 }
2418
2419 static OSStatus
2420 install_dialog_event_handler (window)
2421 WindowRef window;
2422 {
2423 static const EventTypeSpec specs[] =
2424 {{kEventClassCommand, kEventCommandProcess},
2425 {kEventClassKeyboard, kEventRawKeyDown}};
2426 static EventHandlerUPP handle_dialog_eventUPP = NULL;
2427
2428 if (handle_dialog_eventUPP == NULL)
2429 handle_dialog_eventUPP = NewEventHandlerUPP (mac_handle_dialog_event);
2430 return InstallWindowEventHandler (window, handle_dialog_eventUPP,
2431 GetEventTypeCount (specs), specs,
2432 window, NULL);
2433 }
2434
2435 #define DIALOG_LEFT_MARGIN (112)
2436 #define DIALOG_TOP_MARGIN (24)
2437 #define DIALOG_RIGHT_MARGIN (24)
2438 #define DIALOG_BOTTOM_MARGIN (20)
2439 #define DIALOG_MIN_INNER_WIDTH (338)
2440 #define DIALOG_MAX_INNER_WIDTH (564)
2441 #define DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE (12)
2442 #define DIALOG_BUTTON_BUTTON_VERTICAL_SPACE (12)
2443 #define DIALOG_BUTTON_MIN_WIDTH (68)
2444 #define DIALOG_TEXT_MIN_HEIGHT (50)
2445 #define DIALOG_TEXT_BUTTONS_VERTICAL_SPACE (10)
2446 #define DIALOG_ICON_WIDTH (64)
2447 #define DIALOG_ICON_HEIGHT (64)
2448 #define DIALOG_ICON_LEFT_MARGIN (24)
2449 #define DIALOG_ICON_TOP_MARGIN (15)
2450
2451 static Lisp_Object
2452 pop_down_dialog (arg)
2453 Lisp_Object arg;
2454 {
2455 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
2456 WindowRef window = p->pointer;
2457
2458 BLOCK_INPUT;
2459
2460 if (popup_activated_flag)
2461 EndAppModalStateForWindow (window);
2462 DisposeWindow (window);
2463 popup_activated_flag = 0;
2464
2465 UNBLOCK_INPUT;
2466
2467 return Qnil;
2468 }
2469
2470 static int
2471 create_and_show_dialog (f, first_wv)
2472 FRAME_PTR f;
2473 widget_value *first_wv;
2474 {
2475 OSStatus err;
2476 char *dialog_name, *message;
2477 int nb_buttons, first_group_count, i, result = 0;
2478 widget_value *wv;
2479 short buttons_height, text_height, inner_width, inner_height;
2480 Rect empty_rect, *rects;
2481 WindowRef window = NULL;
2482 ControlRef *buttons, default_button = NULL, text;
2483 int specpdl_count = SPECPDL_INDEX ();
2484
2485 dialog_name = first_wv->name;
2486 nb_buttons = dialog_name[1] - '0';
2487 first_group_count = nb_buttons - (dialog_name[4] - '0');
2488
2489 wv = first_wv->contents;
2490 message = wv->value;
2491
2492 wv = wv->next;
2493 SetRect (&empty_rect, 0, 0, 0, 0);
2494
2495 /* Create dialog window. */
2496 err = CreateNewWindow (kMovableModalWindowClass,
2497 kWindowStandardHandlerAttribute,
2498 &empty_rect, &window);
2499 if (err == noErr)
2500 {
2501 record_unwind_protect (pop_down_dialog, make_save_value (window, 0));
2502 err = SetThemeWindowBackground (window, kThemeBrushMovableModalBackground,
2503 true);
2504 }
2505 if (err == noErr)
2506 err = SetWindowTitleWithCFString (window, (dialog_name[0] == 'Q'
2507 ? CFSTR ("Question")
2508 : CFSTR ("Information")));
2509
2510 /* Create button controls and measure their optimal bounds. */
2511 if (err == noErr)
2512 {
2513 buttons = alloca (sizeof (ControlRef) * nb_buttons);
2514 rects = alloca (sizeof (Rect) * nb_buttons);
2515 for (i = 0; i < nb_buttons; i++)
2516 {
2517 CFStringRef label = cfstring_create_with_utf8_cstring (wv->value);
2518
2519 if (label == NULL)
2520 err = memFullErr;
2521 else
2522 {
2523 err = CreatePushButtonControl (window, &empty_rect,
2524 label, &buttons[i]);
2525 CFRelease (label);
2526 }
2527 if (err == noErr)
2528 {
2529 if (!wv->enabled)
2530 {
2531 #ifdef MAC_OSX
2532 err = DisableControl (buttons[i]);
2533 #else
2534 err = DeactivateControl (buttons[i]);
2535 #endif
2536 }
2537 else if (default_button == NULL)
2538 default_button = buttons[i];
2539 }
2540 if (err == noErr)
2541 {
2542 SInt16 unused;
2543
2544 rects[i] = empty_rect;
2545 err = GetBestControlRect (buttons[i], &rects[i], &unused);
2546 }
2547 if (err == noErr)
2548 {
2549 UInt32 command_id;
2550
2551 OffsetRect (&rects[i], -rects[i].left, -rects[i].top);
2552 if (rects[i].right < DIALOG_BUTTON_MIN_WIDTH)
2553 rects[i].right = DIALOG_BUTTON_MIN_WIDTH;
2554 else if (rects[i].right > DIALOG_MAX_INNER_WIDTH)
2555 rects[i].right = DIALOG_MAX_INNER_WIDTH;
2556
2557 command_id = DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv->call_data);
2558 err = SetControlCommandID (buttons[i], command_id);
2559 }
2560 if (err != noErr)
2561 break;
2562 wv = wv->next;
2563 }
2564 }
2565
2566 /* Layout buttons. rects[i] is set relative to the bottom-right
2567 corner of the inner box. */
2568 if (err == noErr)
2569 {
2570 short bottom, right, max_height, left_align_shift;
2571
2572 inner_width = DIALOG_MIN_INNER_WIDTH;
2573 bottom = right = max_height = 0;
2574 for (i = 0; i < nb_buttons; i++)
2575 {
2576 if (right - rects[i].right < - inner_width)
2577 {
2578 if (i != first_group_count
2579 && right - rects[i].right >= - DIALOG_MAX_INNER_WIDTH)
2580 inner_width = - (right - rects[i].right);
2581 else
2582 {
2583 bottom -= max_height + DIALOG_BUTTON_BUTTON_VERTICAL_SPACE;
2584 right = max_height = 0;
2585 }
2586 }
2587 if (max_height < rects[i].bottom)
2588 max_height = rects[i].bottom;
2589 OffsetRect (&rects[i], right - rects[i].right,
2590 bottom - rects[i].bottom);
2591 right = rects[i].left - DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
2592 if (i == first_group_count - 1)
2593 right -= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
2594 }
2595 buttons_height = - (bottom - max_height);
2596
2597 left_align_shift = - (inner_width + rects[nb_buttons - 1].left);
2598 for (i = nb_buttons - 1; i >= first_group_count; i--)
2599 {
2600 if (bottom != rects[i].bottom)
2601 {
2602 left_align_shift = - (inner_width + rects[i].left);
2603 bottom = rects[i].bottom;
2604 }
2605 OffsetRect (&rects[i], left_align_shift, 0);
2606 }
2607 }
2608
2609 /* Create a static text control and measure its bounds. */
2610 if (err == noErr)
2611 {
2612 CFStringRef message_string;
2613 Rect bounds;
2614
2615 message_string = cfstring_create_with_utf8_cstring (message);
2616 if (message_string == NULL)
2617 err = memFullErr;
2618 else
2619 {
2620 ControlFontStyleRec text_style;
2621
2622 text_style.flags = 0;
2623 SetRect (&bounds, 0, 0, inner_width, 0);
2624 err = CreateStaticTextControl (window, &bounds, message_string,
2625 &text_style, &text);
2626 CFRelease (message_string);
2627 }
2628 if (err == noErr)
2629 {
2630 SInt16 unused;
2631
2632 bounds = empty_rect;
2633 err = GetBestControlRect (text, &bounds, &unused);
2634 }
2635 if (err == noErr)
2636 {
2637 text_height = bounds.bottom - bounds.top;
2638 if (text_height < DIALOG_TEXT_MIN_HEIGHT)
2639 text_height = DIALOG_TEXT_MIN_HEIGHT;
2640 }
2641 }
2642
2643 /* Place buttons. */
2644 if (err == noErr)
2645 {
2646 inner_height = (text_height + DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
2647 + buttons_height);
2648
2649 for (i = 0; i < nb_buttons; i++)
2650 {
2651 OffsetRect (&rects[i], DIALOG_LEFT_MARGIN + inner_width,
2652 DIALOG_TOP_MARGIN + inner_height);
2653 SetControlBounds (buttons[i], &rects[i]);
2654 }
2655 }
2656
2657 /* Place text. */
2658 if (err == noErr)
2659 {
2660 Rect bounds;
2661
2662 SetRect (&bounds, DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN,
2663 DIALOG_LEFT_MARGIN + inner_width,
2664 DIALOG_TOP_MARGIN + text_height);
2665 SetControlBounds (text, &bounds);
2666 }
2667
2668 /* Create the application icon at the upper-left corner. */
2669 if (err == noErr)
2670 {
2671 ControlButtonContentInfo content;
2672 ControlRef icon;
2673 static const ProcessSerialNumber psn = {0, kCurrentProcess};
2674 #ifdef MAC_OSX
2675 FSRef app_location;
2676 #else
2677 ProcessInfoRec pinfo;
2678 FSSpec app_spec;
2679 #endif
2680 SInt16 unused;
2681
2682 content.contentType = kControlContentIconRef;
2683 #ifdef MAC_OSX
2684 err = GetProcessBundleLocation (&psn, &app_location);
2685 if (err == noErr)
2686 err = GetIconRefFromFileInfo (&app_location, 0, NULL, 0, NULL,
2687 kIconServicesNormalUsageFlag,
2688 &content.u.iconRef, &unused);
2689 #else
2690 bzero (&pinfo, sizeof (ProcessInfoRec));
2691 pinfo.processInfoLength = sizeof (ProcessInfoRec);
2692 pinfo.processAppSpec = &app_spec;
2693 err = GetProcessInformation (&psn, &pinfo);
2694 if (err == noErr)
2695 err = GetIconRefFromFile (&app_spec, &content.u.iconRef, &unused);
2696 #endif
2697 if (err == noErr)
2698 {
2699 Rect bounds;
2700
2701 SetRect (&bounds, DIALOG_ICON_LEFT_MARGIN, DIALOG_ICON_TOP_MARGIN,
2702 DIALOG_ICON_LEFT_MARGIN + DIALOG_ICON_WIDTH,
2703 DIALOG_ICON_TOP_MARGIN + DIALOG_ICON_HEIGHT);
2704 err = CreateIconControl (window, &bounds, &content, true, &icon);
2705 ReleaseIconRef (content.u.iconRef);
2706 }
2707 }
2708
2709 /* Show the dialog window and run event loop. */
2710 if (err == noErr)
2711 if (default_button)
2712 err = SetWindowDefaultButton (window, default_button);
2713 if (err == noErr)
2714 err = install_dialog_event_handler (window);
2715 if (err == noErr)
2716 {
2717 SizeWindow (window,
2718 DIALOG_LEFT_MARGIN + inner_width + DIALOG_RIGHT_MARGIN,
2719 DIALOG_TOP_MARGIN + inner_height + DIALOG_BOTTOM_MARGIN,
2720 true);
2721 err = RepositionWindow (window, FRAME_MAC_WINDOW (f),
2722 kWindowAlertPositionOnParentWindow);
2723 }
2724 if (err == noErr)
2725 {
2726 SetWRefCon (window, 0);
2727 ShowWindow (window);
2728 BringToFront (window);
2729 popup_activated_flag = 1;
2730 err = BeginAppModalStateForWindow (window);
2731 }
2732 if (err == noErr)
2733 {
2734 EventTargetRef toolbox_dispatcher = GetEventDispatcherTarget ();
2735
2736 quit_dialog_event_loop = 0;
2737 while (1)
2738 {
2739 EMACS_TIME next_time = timer_check (1);
2740 long secs = EMACS_SECS (next_time);
2741 long usecs = EMACS_USECS (next_time);
2742 EventTimeout timeout;
2743 EventRef event;
2744
2745 if (secs < 0 || (secs == 0 && usecs == 0))
2746 {
2747 /* Sometimes timer_check returns -1 (no timers) even if
2748 there are timers. So do a timeout anyway. */
2749 secs = 1;
2750 usecs = 0;
2751 }
2752
2753 timeout = (secs * kEventDurationSecond
2754 + usecs * kEventDurationMicrosecond);
2755 err = ReceiveNextEvent (0, NULL, timeout, kEventRemoveFromQueue,
2756 &event);
2757 if (err == noErr)
2758 {
2759 SendEventToEventTarget (event, toolbox_dispatcher);
2760 ReleaseEvent (event);
2761 }
2762 #if 0 /* defined (MAC_OSX) */
2763 else if (err != eventLoopTimedOutErr)
2764 {
2765 if (err == eventLoopQuitErr)
2766 err = noErr;
2767 break;
2768 }
2769 #else
2770 /* The return value of ReceiveNextEvent seems to be
2771 unreliable. Use our own global variable instead. */
2772 if (quit_dialog_event_loop)
2773 {
2774 err = noErr;
2775 break;
2776 }
2777 #endif
2778 }
2779 }
2780 if (err == noErr)
2781 {
2782 UInt32 command_id = GetWRefCon (window);
2783
2784 if (DIALOG_BUTTON_COMMAND_ID_P (command_id))
2785 result = DIALOG_BUTTON_COMMAND_ID_VALUE (command_id);
2786 }
2787
2788 unbind_to (specpdl_count, Qnil);
2789
2790 return result;
2791 }
2792 #else /* not TARGET_API_MAC_CARBON */
2793 static int
2794 mac_dialog (widget_value *wv)
2795 {
2796 char *dialog_name;
2797 char *prompt;
2798 char **button_labels;
2799 UInt32 *ref_cons;
2800 int nb_buttons;
2801 int left_count;
2802 int i;
2803 int dialog_width;
2804 Rect rect;
2805 WindowRef window_ptr;
2806 ControlRef ch;
2807 int left;
2808 EventRecord event_record;
2809 SInt16 part_code;
2810 int control_part_code;
2811 Point mouse;
2812
2813 dialog_name = wv->name;
2814 nb_buttons = dialog_name[1] - '0';
2815 left_count = nb_buttons - (dialog_name[4] - '0');
2816 button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
2817 ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons);
2818
2819 wv = wv->contents;
2820 prompt = (char *) alloca (strlen (wv->value) + 1);
2821 strcpy (prompt, wv->value);
2822 c2pstr (prompt);
2823
2824 wv = wv->next;
2825 for (i = 0; i < nb_buttons; i++)
2826 {
2827 button_labels[i] = wv->value;
2828 button_labels[i] = (char *) alloca (strlen (wv->value) + 1);
2829 strcpy (button_labels[i], wv->value);
2830 c2pstr (button_labels[i]);
2831 ref_cons[i] = (UInt32) wv->call_data;
2832 wv = wv->next;
2833 }
2834
2835 window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowRef) -1);
2836
2837 SetPortWindowPort (window_ptr);
2838
2839 TextFont (0);
2840 /* Left and right margins in the dialog are 13 pixels each.*/
2841 dialog_width = 14;
2842 /* Calculate width of dialog box: 8 pixels on each side of the text
2843 label in each button, 12 pixels between buttons. */
2844 for (i = 0; i < nb_buttons; i++)
2845 dialog_width += StringWidth (button_labels[i]) + 16 + 12;
2846
2847 if (left_count != 0 && nb_buttons - left_count != 0)
2848 dialog_width += 12;
2849
2850 dialog_width = max (dialog_width, StringWidth (prompt) + 26);
2851
2852 SizeWindow (window_ptr, dialog_width, 78, 0);
2853 ShowWindow (window_ptr);
2854
2855 SetPortWindowPort (window_ptr);
2856
2857 TextFont (0);
2858
2859 MoveTo (13, 29);
2860 DrawString (prompt);
2861
2862 left = 13;
2863 for (i = 0; i < nb_buttons; i++)
2864 {
2865 int button_width = StringWidth (button_labels[i]) + 16;
2866 SetRect (&rect, left, 45, left + button_width, 65);
2867 ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0,
2868 kControlPushButtonProc, ref_cons[i]);
2869 left += button_width + 12;
2870 if (i == left_count - 1)
2871 left += 12;
2872 }
2873
2874 i = 0;
2875 while (!i)
2876 {
2877 if (WaitNextEvent (mDownMask, &event_record, 10, NULL))
2878 if (event_record.what == mouseDown)
2879 {
2880 part_code = FindWindow (event_record.where, &window_ptr);
2881 if (part_code == inContent)
2882 {
2883 mouse = event_record.where;
2884 GlobalToLocal (&mouse);
2885 control_part_code = FindControl (mouse, window_ptr, &ch);
2886 if (control_part_code == kControlButtonPart)
2887 if (TrackControl (ch, mouse, NULL))
2888 i = GetControlReference (ch);
2889 }
2890 }
2891 }
2892
2893 DisposeWindow (window_ptr);
2894
2895 return i;
2896 }
2897 #endif /* not TARGET_API_MAC_CARBON */
2898
2899 static char * button_names [] = { 1856 static char * button_names [] = {
2900 "button1", "button2", "button3", "button4", "button5", 1857 "button1", "button2", "button3", "button4", "button5",
2901 "button6", "button7", "button8", "button9", "button10" }; 1858 "button6", "button7", "button8", "button9", "button10" };
2902 1859
2903 static Lisp_Object 1860 static Lisp_Object
2907 Lisp_Object title, header; 1864 Lisp_Object title, header;
2908 char **error_name; 1865 char **error_name;
2909 { 1866 {
2910 int i, nb_buttons=0; 1867 int i, nb_buttons=0;
2911 char dialog_name[6]; 1868 char dialog_name[6];
2912 int menu_item_selection;
2913 1869
2914 widget_value *wv, *first_wv = 0, *prev_wv = 0; 1870 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2915 1871
2916 /* Number of elements seen so far, before boundary. */ 1872 /* Number of elements seen so far, before boundary. */
2917 int left_count = 0; 1873 int left_count = 0;
3024 dialog_name[5] = 0; 1980 dialog_name[5] = 0;
3025 wv->contents = first_wv; 1981 wv->contents = first_wv;
3026 first_wv = wv; 1982 first_wv = wv;
3027 } 1983 }
3028 1984
1985 /* No selection has been chosen yet. */
1986 menu_item_selection = 0;
1987
3029 /* Force a redisplay before showing the dialog. If a frame is created 1988 /* Force a redisplay before showing the dialog. If a frame is created
3030 just before showing the dialog, its contents may not have been fully 1989 just before showing the dialog, its contents may not have been fully
3031 drawn. */ 1990 drawn. */
3032 Fredisplay (Qt); 1991 Fredisplay (Qt);
3033 1992
3034 /* Actually create the dialog. */ 1993 /* Actually create the dialog. */
3035 #if TARGET_API_MAC_CARBON 1994 #if TARGET_API_MAC_CARBON
3036 menu_item_selection = create_and_show_dialog (f, first_wv); 1995 create_and_show_dialog (f, first_wv);
3037 #else 1996 #else
3038 menu_item_selection = mac_dialog (first_wv); 1997 menu_item_selection = mac_dialog (first_wv);
3039 #endif 1998 #endif
3040 1999
3041 /* Free the widget_value objects we used to specify the contents. */ 2000 /* Free the widget_value objects we used to specify the contents. */
3091 } 2050 }
3092 #endif /* HAVE_DIALOGS */ 2051 #endif /* HAVE_DIALOGS */
3093 2052
3094 2053
3095 /* Is this item a separator? */ 2054 /* Is this item a separator? */
3096 static int 2055 int
3097 name_is_separator (name) 2056 name_is_separator (name)
3098 const char *name; 2057 const char *name;
3099 { 2058 {
3100 const char *start = name; 2059 const char *start = name;
3101 2060
3104 /* Separators can also be of the form "--:TripleSuperMegaEtched" 2063 /* Separators can also be of the form "--:TripleSuperMegaEtched"
3105 or "--deep-shadow". We don't implement them yet, se we just treat 2064 or "--deep-shadow". We don't implement them yet, se we just treat
3106 them like normal separators. */ 2065 them like normal separators. */
3107 return (*name == '\0' || start + 2 == name); 2066 return (*name == '\0' || start + 2 == name);
3108 } 2067 }
3109
3110 static void
3111 add_menu_item (menu, pos, wv)
3112 MenuRef menu;
3113 int pos;
3114 widget_value *wv;
3115 {
3116 #if TARGET_API_MAC_CARBON
3117 CFStringRef item_name;
3118 #else
3119 Str255 item_name;
3120 #endif
3121
3122 if (name_is_separator (wv->name))
3123 AppendMenu (menu, "\p-");
3124 else
3125 {
3126 AppendMenu (menu, "\pX");
3127
3128 #if TARGET_API_MAC_CARBON
3129 item_name = cfstring_create_with_utf8_cstring (wv->name);
3130
3131 if (wv->key != NULL)
3132 {
3133 CFStringRef name, key;
3134
3135 name = item_name;
3136 key = cfstring_create_with_utf8_cstring (wv->key);
3137 item_name = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@ %@"),
3138 name, key);
3139 CFRelease (name);
3140 CFRelease (key);
3141 }
3142
3143 SetMenuItemTextWithCFString (menu, pos, item_name);
3144 CFRelease (item_name);
3145
3146 if (wv->enabled)
3147 EnableMenuItem (menu, pos);
3148 else
3149 DisableMenuItem (menu, pos);
3150
3151 if (STRINGP (wv->help))
3152 SetMenuItemProperty (menu, pos, MAC_EMACS_CREATOR_CODE, 'help',
3153 sizeof (Lisp_Object), &wv->help);
3154 #else /* ! TARGET_API_MAC_CARBON */
3155 item_name[sizeof (item_name) - 1] = '\0';
3156 strncpy (item_name, wv->name, sizeof (item_name) - 1);
3157 if (wv->key != NULL)
3158 {
3159 int len = strlen (item_name);
3160
3161 strncpy (item_name + len, " ", sizeof (item_name) - 1 - len);
3162 len = strlen (item_name);
3163 strncpy (item_name + len, wv->key, sizeof (item_name) - 1 - len);
3164 }
3165 c2pstr (item_name);
3166 SetMenuItemText (menu, pos, item_name);
3167
3168 if (wv->enabled)
3169 EnableItem (menu, pos);
3170 else
3171 DisableItem (menu, pos);
3172 #endif /* ! TARGET_API_MAC_CARBON */
3173
3174 /* Draw radio buttons and tickboxes. */
3175 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
3176 wv->button_type == BUTTON_TYPE_RADIO))
3177 SetItemMark (menu, pos, checkMark);
3178 else
3179 SetItemMark (menu, pos, noMark);
3180
3181 SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
3182 }
3183 }
3184
3185 /* Construct native Mac OS menu based on widget_value tree. */
3186
3187 static int
3188 fill_menu (menu, wv, kind, submenu_id)
3189 MenuRef menu;
3190 widget_value *wv;
3191 enum mac_menu_kind kind;
3192 int submenu_id;
3193 {
3194 int pos;
3195
3196 for (pos = 1; wv != NULL; wv = wv->next, pos++)
3197 {
3198 add_menu_item (menu, pos, wv);
3199 if (wv->contents && submenu_id < min_menu_id[kind + 1])
3200 {
3201 MenuRef submenu = NewMenu (submenu_id, "\pX");
3202
3203 InsertMenu (submenu, -1);
3204 #if TARGET_API_MAC_CARBON
3205 SetMenuItemHierarchicalMenu (menu, pos, submenu);
3206 #else
3207 SetMenuItemHierarchicalID (menu, pos, submenu_id);
3208 #endif
3209 submenu_id = fill_menu (submenu, wv->contents, kind, submenu_id + 1);
3210 }
3211 }
3212
3213 return submenu_id;
3214 }
3215
3216 /* Construct native Mac OS menubar based on widget_value tree. */
3217
3218 static void
3219 fill_menubar (wv, deep_p)
3220 widget_value *wv;
3221 int deep_p;
3222 {
3223 int id, submenu_id;
3224 #if !TARGET_API_MAC_CARBON
3225 int title_changed_p = 0;
3226 #endif
3227
3228 /* Clean up the menu bar when filled by the entire menu trees. */
3229 if (deep_p)
3230 {
3231 dispose_menus (MAC_MENU_MENU_BAR, 0);
3232 dispose_menus (MAC_MENU_MENU_BAR_SUB, 0);
3233 #if !TARGET_API_MAC_CARBON
3234 title_changed_p = 1;
3235 #endif
3236 }
3237
3238 /* Fill menu bar titles and submenus. Reuse the existing menu bar
3239 titles as much as possible to minimize redraw (if !deep_p). */
3240 submenu_id = min_menu_id[MAC_MENU_MENU_BAR_SUB];
3241 for (id = min_menu_id[MAC_MENU_MENU_BAR];
3242 wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1];
3243 wv = wv->next, id++)
3244 {
3245 OSStatus err = noErr;
3246 MenuRef menu;
3247 #if TARGET_API_MAC_CARBON
3248 CFStringRef title;
3249
3250 title = CFStringCreateWithCString (NULL, wv->name,
3251 kCFStringEncodingMacRoman);
3252 #else
3253 Str255 title;
3254
3255 strncpy (title, wv->name, 255);
3256 title[255] = '\0';
3257 c2pstr (title);
3258 #endif
3259
3260 menu = GetMenuRef (id);
3261 if (menu)
3262 {
3263 #if TARGET_API_MAC_CARBON
3264 CFStringRef old_title;
3265
3266 err = CopyMenuTitleAsCFString (menu, &old_title);
3267 if (err == noErr)
3268 {
3269 if (CFStringCompare (title, old_title, 0) != kCFCompareEqualTo)
3270 {
3271 #ifdef MAC_OSX
3272 if (id + 1 == min_menu_id[MAC_MENU_MENU_BAR + 1]
3273 || GetMenuRef (id + 1) == NULL)
3274 {
3275 /* This is a workaround for Mac OS X 10.5 where
3276 just calling SetMenuTitleWithCFString fails
3277 to change the title of the last (Help) menu
3278 in the menu bar. */
3279 DeleteMenu (id);
3280 DisposeMenu (menu);
3281 menu = NULL;
3282 }
3283 else
3284 #endif /* MAC_OSX */
3285 err = SetMenuTitleWithCFString (menu, title);
3286 }
3287 CFRelease (old_title);
3288 }
3289 else
3290 err = SetMenuTitleWithCFString (menu, title);
3291 #else /* !TARGET_API_MAC_CARBON */
3292 if (!EqualString (title, (*menu)->menuData, false, false))
3293 {
3294 DeleteMenu (id);
3295 DisposeMenu (menu);
3296 menu = NewMenu (id, title);
3297 InsertMenu (menu, GetMenuRef (id + 1) ? id + 1 : 0);
3298 title_changed_p = 1;
3299 }
3300 #endif /* !TARGET_API_MAC_CARBON */
3301 }
3302
3303 if (!menu)
3304 {
3305 #if TARGET_API_MAC_CARBON
3306 err = CreateNewMenu (id, 0, &menu);
3307 if (err == noErr)
3308 err = SetMenuTitleWithCFString (menu, title);
3309 #else
3310 menu = NewMenu (id, title);
3311 #endif
3312 if (err == noErr)
3313 {
3314 InsertMenu (menu, 0);
3315 #if !TARGET_API_MAC_CARBON
3316 title_changed_p = 1;
3317 #endif
3318 }
3319 }
3320 #if TARGET_API_MAC_CARBON
3321 CFRelease (title);
3322 #endif
3323
3324 if (err == noErr)
3325 if (wv->contents)
3326 submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
3327 submenu_id);
3328 }
3329
3330 if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuRef (id))
3331 {
3332 dispose_menus (MAC_MENU_MENU_BAR, id);
3333 #if !TARGET_API_MAC_CARBON
3334 title_changed_p = 1;
3335 #endif
3336 }
3337
3338 #if !TARGET_API_MAC_CARBON
3339 if (title_changed_p)
3340 InvalMenuBar ();
3341 #endif
3342 }
3343
3344 /* Dispose of menus that belong to KIND, and remove them from the menu
3345 list. ID is the lower bound of menu IDs that will be processed. */
3346
3347 static void
3348 dispose_menus (kind, id)
3349 enum mac_menu_kind kind;
3350 int id;
3351 {
3352 for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++)
3353 {
3354 MenuRef menu = GetMenuRef (id);
3355
3356 if (menu == NULL)
3357 break;
3358 DeleteMenu (id);
3359 DisposeMenu (menu);
3360 }
3361 }
3362
3363 #endif /* HAVE_MENUS */ 2068 #endif /* HAVE_MENUS */
3364 2069
3365 /* Detect if a menu is currently active. */ 2070 /* Detect if a menu is currently active. */
3366 2071
3367 int 2072 int