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