Mercurial > emacs
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 (¶m, | |
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, ¶m, &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 |