aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/dired.el2
-rw-r--r--lisp/progmodes/cc-langs.el9
-rw-r--r--src/ChangeLog159
-rw-r--r--src/Makefile.in5
-rw-r--r--src/dired.c8
-rw-r--r--src/fileio.c4
-rw-r--r--src/mac.c26
-rw-r--r--src/macfns.c427
-rw-r--r--src/macgui.h115
-rw-r--r--src/macmenu.c1323
-rw-r--r--src/macselect.c770
-rw-r--r--src/macterm.h116
-rw-r--r--src/mactoolbox.c6211
13 files changed, 6658 insertions, 2517 deletions
diff --git a/lisp/dired.el b/lisp/dired.el
index faa048373e7..375894ca8c1 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -3250,7 +3250,7 @@ Anything else means ask for each directory."
3250 3250
3251(defun dired-dnd-popup-notice () 3251(defun dired-dnd-popup-notice ()
3252 (message-box 3252 (message-box
3253 "Recursive copies not enabled.\nSee variable dired-recursive-copies.")) 3253 "Dired recursive copies are currently disabled.\nSee the variable `dired-recursive-copies'."))
3254 3254
3255 3255
3256(defun dired-dnd-do-ask-action (uri) 3256(defun dired-dnd-do-ask-action (uri)
diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el
index ed3efc66ec2..f22b75218da 100644
--- a/lisp/progmodes/cc-langs.el
+++ b/lisp/progmodes/cc-langs.el
@@ -728,13 +728,14 @@ definition, or nil if the language doesn't have any."
728 "define")) 728 "define"))
729 729
730(c-lang-defconst c-opt-cpp-macro-define-start 730(c-lang-defconst c-opt-cpp-macro-define-start
731 ;; Regexp matching everything up to the macro body of a cpp define, 731 ;; Regexp matching everything up to the macro body of a cpp define, or the
732 ;; or the end of the logical line if there is none. Set if 732 ;; end of the logical line if there is none. Submatch 1 is the name of the
733 ;; c-opt-cpp-macro-define is. 733 ;; macro. Set if c-opt-cpp-macro-define is.
734 t (if (c-lang-const c-opt-cpp-macro-define) 734 t (if (c-lang-const c-opt-cpp-macro-define)
735 (concat (c-lang-const c-opt-cpp-prefix) 735 (concat (c-lang-const c-opt-cpp-prefix)
736 (c-lang-const c-opt-cpp-macro-define) 736 (c-lang-const c-opt-cpp-macro-define)
737 "[ \t]+\\(\\sw\\|_\\)+\\(\([^\)]*\)\\)?" 737 "[ \t]+\\(\\(\\sw\\|_\\)+\\)\\(\([^\)]*\)\\)?"
738 ;; ^ ^ #defined name
738 "\\([ \t]\\|\\\\\n\\)*"))) 739 "\\([ \t]\\|\\\\\n\\)*")))
739(c-lang-defvar c-opt-cpp-macro-define-start 740(c-lang-defvar c-opt-cpp-macro-define-start
740 (c-lang-const c-opt-cpp-macro-define-start)) 741 (c-lang-const c-opt-cpp-macro-define-start))
diff --git a/src/ChangeLog b/src/ChangeLog
index 0b849d99c43..cf9bbe2d8bc 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,162 @@
12008-04-06 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
2
3 * Makefile.in (MAC_OBJ): Add mactoolbox.o.
4 (mactoolbox.o): New target.
5
6 * mac.c [MAC_OSX] (select_and_poll_event, sys_select):
7 Use mac_run_loop_run_once instead of CFRunLoopRunInMode.
8
9 * macfns.c (x_set_background_color, mac_window, x_create_tip_frame):
10 Use mac_set_frame_window_background instead of XSetWindowBackground.
11 (x_set_tool_bar_lines) [USE_MAC_TOOLBAR]:
12 Use mac_is_window_toolbar_visible instead of IsWindowToolbarVisible.
13 (x_set_name_internal) [TARGET_API_MAC_CARBON]: Use mac_set_window_title
14 instead of SetWindowTitleWithCFString.
15 (mac_update_proxy_icon) [TARGET_API_MAC_CARBON]: Remove BLOCK_INPUT.
16 Move function to mactoolbox.c.
17 (mac_update_title_bar) [TARGET_API_MAC_CARBON]:
18 Use mac_set_window_modified instead of SetWindowModified.
19 Add BLOCK_INPUT around mac_set_window_modified/mac_update_proxy_icon.
20 (mac_window, x_create_tip_frame): Use mac_create_frame_window.
21 (Fx_focus_frame): Use mac_front_non_floating_window instead of
22 FrontNonFloatingWindow. Use mac_activate_window instead of
23 ActivateWindow. Use mac_active_non_floating_window instead of
24 ActiveNonFloatingWindow.
25 (show_hourglass, hide_hourglass) [TARGET_API_MAC_CARBON]:
26 Use mac_show_hourglass and mac_hide_hourglass.
27 (compute_tip_xy) [TARGET_API_MAC_CARBON]: Use mac_get_global_mouse
28 instead of GetGlobalMouse.
29 (Fx_show_tip): Use mac_move_window/mac_size_window/mac_show_window
30 instead of MoveWindow/SizeWindow/ShowWindow, respectively.
31 Use mac_bring_window_to_front instead of BringToFront.
32 (Qfile_name_history) [TARGET_API_MAC_CARBON]: Move extern to
33 mactoolbox.c.
34 (Fx_file_dialog) [TARGET_API_MAC_CARBON]: Move function body to
35 mac_file_dialog in mactoolbox.c. Use mac_file_dialog.
36 (mac_nav_event_callback) [TARGET_API_MAC_CARBON]: Move function to
37 mactoolbox.c.
38
39 * macgui.h [!HAVE_CARBON]: Include Quickdraw.h instead of QuickDraw.h.
40 (XtPointer): Move typedef from macmenu.c.
41 (enum button_type): Move enum from macmenu.c.
42 (widget_value): Move typedef from macmenu.c.
43 (M_APPLE, I_ABOUT, EXTRA_STACK_ALLOC, ARGV_STRING_LIST_ID)
44 (DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN, DIALOG_RIGHT_MARGIN)
45 (DIALOG_BOTTOM_MARGIN, DIALOG_MIN_INNER_WIDTH, DIALOG_MAX_INNER_WIDTH)
46 (DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE)
47 (DIALOG_BUTTON_BUTTON_VERTICAL_SPACE, DIALOG_BUTTON_MIN_WIDTH)
48 (DIALOG_TEXT_MIN_HEIGHT, DIALOG_TEXT_BUTTONS_VERTICAL_SPACE)
49 (DIALOG_ICON_WIDTH, DIALOG_ICON_HEIGHT, DIALOG_ICON_LEFT_MARGIN)
50 (DIALOG_ICON_TOP_MARGIN): Move defines from macmenu.c.
51 (Selection): Move typedef from macselect.c.
52 (RAM_TOO_LARGE_ALERT_ID, ABOUT_ALERT_ID) [MAC_OS8]: Move defines from
53 macterm.c.
54 (mac_set_window_title, mac_set_window_modified, mac_is_window_visible)
55 (mac_is_window_collapsed, mac_bring_window_to_front)
56 (mac_send_window_behind, mac_hide_window, mac_show_window)
57 (mac_collapse_window, mac_front_non_floating_window)
58 (mac_active_non_floating_window, mac_activate_window)
59 (mac_move_window_structure, mac_move_window, mac_size_window)
60 (mac_get_global_mouse, mac_is_window_toolbar_visible): New defines.
61
62 * macmenu.c [!TARGET_API_MAC_CARBON]: Move includes to mactoolbox.c.
63 (enum mac_menu_kind): Move enum to mactoolbox.c.
64 (min_menu_id): Move variable to mactoolbox.c.
65 (quit_dialog_event_loop) [TARGET_API_MAC_CARBON]: Likewise.
66 (DIALOG_WINDOW_RESOURCE): Move define to mactoolbox.c.
67 (DIALOG_BUTTON_COMMAND_ID_OFFSET, DIALOG_BUTTON_COMMAND_ID_P)
68 (DIALOG_BUTTON_COMMAND_ID_VALUE, DIALOG_BUTTON_MAKE_COMMAND_ID)
69 [TARGET_API_MAC_CARBON]: Likewise.
70 (XtPointer): Move typedef to macgui.h.
71 (enum button_type): Move enum to macgui.h.
72 (widget_value): Move typedef to macgui.h.
73 (DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN, DIALOG_RIGHT_MARGIN)
74 (DIALOG_BOTTOM_MARGIN, DIALOG_MIN_INNER_WIDTH, DIALOG_MAX_INNER_WIDTH)
75 (DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE)
76 (DIALOG_BUTTON_BUTTON_VERTICAL_SPACE, DIALOG_BUTTON_MIN_WIDTH)
77 (DIALOG_TEXT_MIN_HEIGHT, DIALOG_TEXT_BUTTONS_VERTICAL_SPACE)
78 (DIALOG_ICON_WIDTH, DIALOG_ICON_HEIGHT, DIALOG_ICON_LEFT_MARGIN)
79 (DIALOG_ICON_TOP_MARGIN): Move defines to macgui.h.
80 (popup_activated_flag): Make variable non-static.
81 (x_activate_menubar, install_menu_quit_handler, pop_down_menu)
82 (add_menu_item, fill_menu, dispose_menus):
83 Move functions to mactoolbox.c.
84 (restore_show_help_function, menu_target_item_handler)
85 (install_menu_target_item_handler, mac_handle_dialog_event)
86 (install_dialog_event_handler, pop_down_dialog, create_and_show_dialog)
87 [TARGET_API_MAC_CARBON]: Likewise.
88 (menu_quit_handler) [MAC_OS_X_VERSION_MAX_ALLOWED >= 1030]: Likewise.
89 (mac_dialog) [!TARGET_API_MAC_CARBON]: Likewise.
90 (find_and_call_menu_selection, name_is_separator): Make function
91 non-static.
92 (Vshow_help_function, timer_check) [TARGET_API_MAC_CARBON]: Move extern
93 to mactoolbox.c.
94 (set_frame_menubar): Don't call install_menu_quit_handler.
95 (menu_item_selection): New variable.
96 (mac_menu_show): Use create_and_show_popup_menu.
97 (create_and_show_dialog) [TARGET_API_MAC_CARBON]: Don't return
98 selection but set variable menu_item_selection. All uses changed.
99 (mac_fill_menubar): Rename from fill_menubar. All uses changed.
100 Call install_menu_quit_handler. Move to mactoolbox.c.
101
102 * macselect.c [!TARGET_API_MAC_CARBON]: Don't include Scrap.h.
103 (Selection): Move typedef to macgui.h.
104 (Vselection_converter_alist, Qmac_scrap_name, Qmac_ostype)
105 (Vmac_apple_event_map, Qmac_apple_event_class, Qmac_apple_event_id):
106 Make variables non-static.
107 (Vmac_dnd_known_types) [TARGET_API_MAC_CARBON]: Likewise.
108 (mac_handle_apple_event, cleanup_all_suspended_apple_events):
109 Make functions non-static.
110 (Vmac_service_selection) [MAC_OSX]: Likewise.
111 (mac_get_selection_from_symbol, get_flavor_type_from_symbol)
112 (mac_valid_selection_target_p, mac_clear_selection)
113 (mac_get_selection_ownership_info, mac_valid_selection_value_p)
114 (mac_put_selection_value, mac_selection_has_target_p)
115 (mac_get_selection_value, mac_get_selection_target_list)
116 (init_apple_event_handler, install_drag_handler, remove_drag_handler):
117 Move functions to mactoolbox.c.
118 (mac_do_track_drag, mac_do_receive_drag) [TARGET_API_MAC_CARBON]:
119 Likewise.
120 (copy_scrap_flavor_data, mac_handle_service_event)
121 (install_service_handler) [MAC_OSX]: Likewise.
122 (syms_of_macselect) <Vmac_dnd_known_types>:
123 Use mac_dnd_default_known_types.
124
125 * macterm.h (FRAME_OUTER_TO_INNER_DIFF_X, FRAME_OUTER_TO_INNER_DIFF_Y):
126 Move to mactoolbox.c.
127 (HOURGLASS_WIDTH, HOURGLASS_HEIGHT): Change to 15.
128 (Fx_selection_owner_p): Add EXFUN.
129 (install_window_handler, remove_window_handler, XSetWindowBackground):
130 Remove externs.
131 (do_apple_menu) [!TARGET_API_MAC_CARBON]: Likewise.
132 (mac_prepare_for_quickdraw) [USE_CG_DRAWING]: Likewise.
133 (x_raise_frame, x_lower_frame, mac_alert_sound_play)
134 (install_application_handler, mac_get_frame_bounds, mac_get_frame_mouse)
135 (mac_convert_frame_point_to_global, mac_set_frame_window_background)
136 (mac_update_begin mac_update_end, mac_frame_up_to_date, x_flush)
137 (mac_create_frame_window, mac_dispose_frame_window, mac_begin_clip)
138 (mac_end_clip, mac_create_scroll_bar, mac_dispose_scroll_bar)
139 (mac_set_scroll_bar_bounds, mac_redraw_scroll_bar, mac_fill_menubar)
140 (create_and_show_popup_menu, mac_get_selection_from_symbol)
141 (mac_valid_selection_target_p, mac_clear_selection)
142 (mac_get_selection_ownership_info, mac_valid_selection_value_p)
143 (mac_put_selection_value, mac_selection_has_target_p)
144 (mac_get_selection_value, mac_get_selection_target_list): Add externs.
145 (mac_update_proxy_icon, mac_show_hourglass, mac_hide_hourglass)
146 (mac_reposition_hourglass, mac_file_dialog, create_and_show_dialog)
147 (mac_dnd_default_known_types) [TARGET_API_MAC_CARBON]: Likewise.
148 (mac_run_loop_run_once) [MAC_OSX]: Likewise.
149 (mac_dialog) [!TARGET_API_MAC_CARBON]: Likewise.
150 (mac_begin_cg_clip, mac_end_cg_clip) [USE_CG_DRAWING]: Likewise.
151 (x_set_toolkit_scroll_bar_thumb) [!USE_TOOLKIT_SCROLL_BARS]: Likewise.
152 (x_scroll_bar_set_handle) [!USE_TOOLKIT_SCROLL_BARS]: Likewise.
153
154 * mactoolbox.c: New file.
155
1562008-03-31 Jason Rumney <jasonr@gnu.org>
157
158 * dired.c (Ffile_attributes) [WINDOWSNT]: Cast uid and gid to unsigned.
159
12008-04-18 Stefan Monnier <monnier@iro.umontreal.ca> 1602008-04-18 Stefan Monnier <monnier@iro.umontreal.ca>
2 161
3 * fileio.c (Fexpand_file_name): Refine last fix so `nm' is only 162 * fileio.c (Fexpand_file_name): Refine last fix so `nm' is only
diff --git a/src/Makefile.in b/src/Makefile.in
index 8566848a434..011a630f056 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -549,7 +549,7 @@ CYGWIN_OBJ = sheap.o
549 549
550#ifdef HAVE_CARBON 550#ifdef HAVE_CARBON
551mac = $(dot)$(dot)/mac/ 551mac = $(dot)$(dot)/mac/
552MAC_OBJ = mac.o macterm.o macfns.o macmenu.o macselect.o fontset.o fringe.o image.o 552MAC_OBJ = mac.o macterm.o macfns.o macmenu.o macselect.o fontset.o fringe.o image.o mactoolbox.o
553emacsapp = $(PWD)/$(mac)Emacs.app/ 553emacsapp = $(PWD)/$(mac)Emacs.app/
554emacsappsrc = ${srcdir}/../mac/Emacs.app/ 554emacsappsrc = ${srcdir}/../mac/Emacs.app/
555#endif 555#endif
@@ -1268,6 +1268,9 @@ macterm.o: blockinput.h atimer.h systime.h syssignal.h macterm.h macgui.h \
1268 process.h coding.h $(config_h) 1268 process.h coding.h $(config_h)
1269macselect.o: blockinput.h atimer.h systime.h macterm.h macgui.h frame.h \ 1269macselect.o: blockinput.h atimer.h systime.h macterm.h macgui.h frame.h \
1270 keymap.h $(config_h) 1270 keymap.h $(config_h)
1271mactoolbox.o: blockinput.h atimer.h systime.h macterm.h macgui.h frame.h \
1272 charset.h coding.h ccl.h dispextern.h fontset.h termhooks.h buffer.h \
1273 window.h keyboard.h $(config_h)
1271 1274
1272${emacsapp}Contents/Resources/English.lproj: 1275${emacsapp}Contents/Resources/English.lproj:
1273 mkdir -p $@ 1276 mkdir -p $@
diff --git a/src/dired.c b/src/dired.c
index 2e11259eef1..3efc87ac844 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -979,8 +979,16 @@ Elements of the attribute list are:
979 shorter than an int (e.g., `short'), GCC whines about comparison 979 shorter than an int (e.g., `short'), GCC whines about comparison
980 being always false due to limited range of data type. Fix by 980 being always false due to limited range of data type. Fix by
981 copying s.st_uid and s.st_gid into int variables. */ 981 copying s.st_uid and s.st_gid into int variables. */
982#ifdef WINDOWSNT
983 /* Windows uses signed short for the uid and gid in the stat structure,
984 but we use an int for getuid (limited to the range 0-60000).
985 So users with uid > 32767 need their uid patched back here. */
986 uid = (unsigned short) s.st_uid;
987 gid = (unsigned short) s.st_gid;
988#else
982 uid = s.st_uid; 989 uid = s.st_uid;
983 gid = s.st_gid; 990 gid = s.st_gid;
991#endif
984 if (NILP (id_format) || EQ (id_format, Qinteger)) 992 if (NILP (id_format) || EQ (id_format, Qinteger))
985 { 993 {
986 values[2] = make_fixnum_or_float (uid); 994 values[2] = make_fixnum_or_float (uid);
diff --git a/src/fileio.c b/src/fileio.c
index 6c8db062be8..a63ac6dd748 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6055,8 +6055,8 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */)
6055 restore_message (); 6055 restore_message ();
6056 } 6056 }
6057 else if (!auto_save_error_occurred) 6057 else if (!auto_save_error_occurred)
6058 /* Don't overwrite the error message if an error occurred. */ 6058 /* Don't overwrite the error message if an error occurred.
6059 /* If we displayed a message and then restored a state 6059 If we displayed a message and then restored a state
6060 with no message, leave a "done" message on the screen. */ 6060 with no message, leave a "done" message on the screen. */
6061 message1 ("Auto-saving...done"); 6061 message1 ("Auto-saving...done");
6062 } 6062 }
diff --git a/src/mac.c b/src/mac.c
index 74cfeb24865..0ae233f048e 100644
--- a/src/mac.c
+++ b/src/mac.c
@@ -4989,8 +4989,8 @@ extern int noninteractive;
4989 SELECT_TIMEOUT_THRESHOLD_RUNLOOP seconds). 4989 SELECT_TIMEOUT_THRESHOLD_RUNLOOP seconds).
4990 -> Create CFSocket for each socket and add it into the current 4990 -> Create CFSocket for each socket and add it into the current
4991 event RunLoop so that the current event loop gets quit when 4991 event RunLoop so that the current event loop gets quit when
4992 the socket becomes ready. Then CFRunLoopRunInMode can wait 4992 the socket becomes ready. Then mac_run_loop_run_once can
4993 for both kinds of inputs. 4993 wait for both kinds of inputs.
4994 4. Otherwise. 4994 4. Otherwise.
4995 -> Periodically poll the window input channel while repeatedly 4995 -> Periodically poll the window input channel while repeatedly
4996 executing `select' with a short timeout 4996 executing `select' with a short timeout
@@ -5045,7 +5045,7 @@ select_and_poll_event (nfds, rfds, wfds, efds, timeout)
5045 if (efds) oefds = *efds; 5045 if (efds) oefds = *efds;
5046 } 5046 }
5047 5047
5048 /* Try detect_input_pending before CFRunLoopRunInMode in the same 5048 /* Try detect_input_pending before mac_run_loop_run_once in the same
5049 BLOCK_INPUT block, in case that some input has already been read 5049 BLOCK_INPUT block, in case that some input has already been read
5050 asynchronously. */ 5050 asynchronously. */
5051 BLOCK_INPUT; 5051 BLOCK_INPUT;
@@ -5062,15 +5062,7 @@ select_and_poll_event (nfds, rfds, wfds, efds, timeout)
5062 if (timeoutval == 0.0) 5062 if (timeoutval == 0.0)
5063 timedout_p = 1; 5063 timedout_p = 1;
5064 else 5064 else
5065 { 5065 timedout_p = mac_run_loop_run_once (timeoutval);
5066#if USE_CG_DRAWING
5067 mac_prepare_for_quickdraw (NULL);
5068#endif
5069 if (CFRunLoopRunInMode (kCFRunLoopDefaultMode,
5070 timeoutval >= 0 ? timeoutval : 100000, true)
5071 == kCFRunLoopRunTimedOut)
5072 timedout_p = 1;
5073 }
5074 5066
5075 if (timeout == NULL && timedout_p) 5067 if (timeout == NULL && timedout_p)
5076 { 5068 {
@@ -5193,7 +5185,7 @@ sys_select (nfds, rfds, wfds, efds, timeout)
5193 if (timeoutval > 0 && timeoutval <= SELECT_TIMEOUT_THRESHOLD_RUNLOOP) 5185 if (timeoutval > 0 && timeoutval <= SELECT_TIMEOUT_THRESHOLD_RUNLOOP)
5194 goto poll_periodically; 5186 goto poll_periodically;
5195 5187
5196 /* Try detect_input_pending before CFRunLoopRunInMode in the 5188 /* Try detect_input_pending before mac_run_loop_run_once in the
5197 same BLOCK_INPUT block, in case that some input has already 5189 same BLOCK_INPUT block, in case that some input has already
5198 been read asynchronously. */ 5190 been read asynchronously. */
5199 BLOCK_INPUT; 5191 BLOCK_INPUT;
@@ -5246,13 +5238,7 @@ sys_select (nfds, rfds, wfds, efds, timeout)
5246 CFRunLoopAddSource (runloop, source, kCFRunLoopDefaultMode); 5238 CFRunLoopAddSource (runloop, source, kCFRunLoopDefaultMode);
5247 } 5239 }
5248 5240
5249#if USE_CG_DRAWING 5241 timedout_p = mac_run_loop_run_once (timeoutval);
5250 mac_prepare_for_quickdraw (NULL);
5251#endif
5252 if (CFRunLoopRunInMode (kCFRunLoopDefaultMode,
5253 timeoutval >= 0 ? timeoutval : 100000, true)
5254 == kCFRunLoopRunTimedOut)
5255 timedout_p = 1;
5256 5242
5257 for (fd = minfd; fd < nfds; fd++) 5243 for (fd = minfd; fd < nfds; fd++)
5258 if (FD_ISSET (fd, rfds) || (wfds && FD_ISSET (fd, wfds))) 5244 if (FD_ISSET (fd, rfds) || (wfds && FD_ISSET (fd, wfds)))
diff --git a/src/macfns.c b/src/macfns.c
index 9e471c6c588..21866876155 100644
--- a/src/macfns.c
+++ b/src/macfns.c
@@ -1346,7 +1346,7 @@ x_set_background_color (f, arg, oldval)
1346 BLOCK_INPUT; 1346 BLOCK_INPUT;
1347 XSetBackground (dpy, mac->normal_gc, bg); 1347 XSetBackground (dpy, mac->normal_gc, bg);
1348 XSetForeground (dpy, mac->reverse_gc, bg); 1348 XSetForeground (dpy, mac->reverse_gc, bg);
1349 XSetWindowBackground (dpy, FRAME_MAC_WINDOW (f), bg); 1349 mac_set_frame_window_background (f, bg);
1350 XSetForeground (dpy, mac->cursor_gc, bg); 1350 XSetForeground (dpy, mac->cursor_gc, bg);
1351 1351
1352 UNBLOCK_INPUT; 1352 UNBLOCK_INPUT;
@@ -1686,7 +1686,8 @@ x_set_tool_bar_lines (f, value, oldval)
1686 if (nlines) 1686 if (nlines)
1687 { 1687 {
1688 FRAME_EXTERNAL_TOOL_BAR (f) = 1; 1688 FRAME_EXTERNAL_TOOL_BAR (f) = 1;
1689 if (FRAME_MAC_P (f) && !IsWindowToolbarVisible (FRAME_MAC_WINDOW (f))) 1689 if (FRAME_MAC_P (f)
1690 && !mac_is_window_toolbar_visible (FRAME_MAC_WINDOW (f)))
1690 /* Make sure next redisplay shows the tool bar. */ 1691 /* Make sure next redisplay shows the tool bar. */
1691 XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = Qt; 1692 XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = Qt;
1692 } 1693 }
@@ -1770,7 +1771,7 @@ x_set_name_internal (f, name)
1770 CFStringRef windowTitle = 1771 CFStringRef windowTitle =
1771 cfstring_create_with_utf8_cstring (SDATA (name)); 1772 cfstring_create_with_utf8_cstring (SDATA (name));
1772 1773
1773 SetWindowTitleWithCFString (FRAME_MAC_WINDOW (f), windowTitle); 1774 mac_set_window_title (FRAME_MAC_WINDOW (f), windowTitle);
1774 CFRelease (windowTitle); 1775 CFRelease (windowTitle);
1775#else 1776#else
1776 Str255 windowTitle; 1777 Str255 windowTitle;
@@ -1935,98 +1936,6 @@ mac_set_font (f, arg, oldval)
1935#endif 1936#endif
1936} 1937}
1937 1938
1938#if TARGET_API_MAC_CARBON
1939static void
1940mac_update_proxy_icon (f)
1941 struct frame *f;
1942{
1943 OSStatus err;
1944 Lisp_Object file_name =
1945 XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer)->filename;
1946 Window w = FRAME_MAC_WINDOW (f);
1947 AliasHandle alias = NULL;
1948
1949 BLOCK_INPUT;
1950
1951 err = GetWindowProxyAlias (w, &alias);
1952 if (err == errWindowDoesNotHaveProxy && !STRINGP (file_name))
1953 goto out;
1954
1955 if (STRINGP (file_name))
1956 {
1957 AEDesc desc;
1958#ifdef MAC_OSX
1959 FSRef fref, fref_proxy;
1960#else
1961 FSSpec fss, fss_proxy;
1962#endif
1963 Boolean changed;
1964 Lisp_Object encoded_file_name = ENCODE_FILE (file_name);
1965
1966#ifdef MAC_OSX
1967 err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name),
1968 SBYTES (encoded_file_name), typeFSRef, &desc);
1969#else
1970 SetPortWindowPort (w);
1971 err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name),
1972 SBYTES (encoded_file_name), typeFSS, &desc);
1973#endif
1974 if (err == noErr)
1975 {
1976#ifdef MAC_OSX
1977 err = AEGetDescData (&desc, &fref, sizeof (FSRef));
1978#else
1979 err = AEGetDescData (&desc, &fss, sizeof (FSSpec));
1980#endif
1981 AEDisposeDesc (&desc);
1982 }
1983 if (err == noErr)
1984 {
1985 if (alias)
1986 {
1987 /* (FS)ResolveAlias never sets `changed' to true if
1988 `alias' is minimal. */
1989#ifdef MAC_OSX
1990 err = FSResolveAlias (NULL, alias, &fref_proxy, &changed);
1991 if (err == noErr)
1992 err = FSCompareFSRefs (&fref, &fref_proxy);
1993#else
1994 err = ResolveAlias (NULL, alias, &fss_proxy, &changed);
1995 if (err == noErr)
1996 err = !(fss.vRefNum == fss_proxy.vRefNum
1997 && fss.parID == fss_proxy.parID
1998 && EqualString (fss.name, fss_proxy.name,
1999 false, true));
2000#endif
2001 }
2002 if (err != noErr || alias == NULL)
2003 {
2004 if (alias)
2005 DisposeHandle ((Handle) alias);
2006#ifdef MAC_OSX
2007 err = FSNewAliasMinimal (&fref, &alias);
2008#else
2009 err = NewAliasMinimal (&fss, &alias);
2010#endif
2011 changed = true;
2012 }
2013 }
2014 if (err == noErr)
2015 if (changed)
2016 err = SetWindowProxyAlias (w, alias);
2017 }
2018
2019 if (alias)
2020 DisposeHandle ((Handle) alias);
2021
2022 if (err != noErr || !STRINGP (file_name))
2023 RemoveWindowProxy (w);
2024
2025 out:
2026 UNBLOCK_INPUT;
2027}
2028#endif
2029
2030void 1939void
2031mac_update_title_bar (f, save_match_data) 1940mac_update_title_bar (f, save_match_data)
2032 struct frame *f; 1941 struct frame *f;
@@ -2048,9 +1957,11 @@ mac_update_title_bar (f, save_match_data)
2048 || (!MINI_WINDOW_P (w) 1957 || (!MINI_WINDOW_P (w)
2049 && (modified_p != !NILP (w->last_had_star)))) 1958 && (modified_p != !NILP (w->last_had_star))))
2050 { 1959 {
2051 SetWindowModified (FRAME_MAC_WINDOW (f), 1960 BLOCK_INPUT;
2052 !MINI_WINDOW_P (w) && modified_p); 1961 mac_set_window_modified (FRAME_MAC_WINDOW (f),
1962 !MINI_WINDOW_P (w) && modified_p);
2053 mac_update_proxy_icon (f); 1963 mac_update_proxy_icon (f);
1964 UNBLOCK_INPUT;
2054 } 1965 }
2055#endif 1966#endif
2056} 1967}
@@ -2247,52 +2158,12 @@ mac_window (f, window_prompting, minibuffer_only)
2247 long window_prompting; 2158 long window_prompting;
2248 int minibuffer_only; 2159 int minibuffer_only;
2249{ 2160{
2250 Rect r;
2251
2252 BLOCK_INPUT; 2161 BLOCK_INPUT;
2253 2162
2254 SetRect (&r, f->left_pos, f->top_pos, 2163 mac_create_frame_window (f, 0);
2255 f->left_pos + FRAME_PIXEL_WIDTH (f),
2256 f->top_pos + FRAME_PIXEL_HEIGHT (f));
2257#if TARGET_API_MAC_CARBON
2258 CreateNewWindow (kDocumentWindowClass,
2259 kWindowStandardDocumentAttributes
2260#ifdef MAC_OSX
2261 | kWindowToolbarButtonAttribute
2262#endif
2263 , &r, &FRAME_MAC_WINDOW (f));
2264 if (FRAME_MAC_WINDOW (f))
2265 {
2266 SetWRefCon (FRAME_MAC_WINDOW (f), (long) f->output_data.mac);
2267 if (install_window_handler (FRAME_MAC_WINDOW (f)) != noErr)
2268 {
2269 DisposeWindow (FRAME_MAC_WINDOW (f));
2270 FRAME_MAC_WINDOW (f) = NULL;
2271 }
2272 }
2273#else /* !TARGET_API_MAC_CARBON */
2274 FRAME_MAC_WINDOW (f)
2275 = NewCWindow (NULL, &r, "\p", false, zoomDocProc,
2276 (WindowRef) -1, 1, (long) f->output_data.mac);
2277#endif /* !TARGET_API_MAC_CARBON */
2278 /* so that update events can find this mac_output struct */
2279 f->output_data.mac->mFP = f; /* point back to emacs frame */
2280
2281#ifndef MAC_OSX
2282 if (FRAME_MAC_WINDOW (f))
2283 {
2284 ControlRef root_control;
2285 2164
2286 if (CreateRootControl (FRAME_MAC_WINDOW (f), &root_control) != noErr)
2287 {
2288 DisposeWindow (FRAME_MAC_WINDOW (f));
2289 FRAME_MAC_WINDOW (f) = NULL;
2290 }
2291 }
2292#endif
2293 if (FRAME_MAC_WINDOW (f)) 2165 if (FRAME_MAC_WINDOW (f))
2294 XSetWindowBackground (FRAME_MAC_DISPLAY(f), FRAME_MAC_WINDOW (f), 2166 mac_set_frame_window_background (f, FRAME_BACKGROUND_PIXEL (f));
2295 FRAME_BACKGROUND_PIXEL (f));
2296 2167
2297#if USE_MAC_TOOLBAR 2168#if USE_MAC_TOOLBAR
2298 /* At the moment, the size of the tool bar is not yet known. We 2169 /* At the moment, the size of the tool bar is not yet known. We
@@ -2875,7 +2746,7 @@ FRAME nil means use the selected frame. */)
2875 if (!front_p) 2746 if (!front_p)
2876 { 2747 {
2877#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 2748#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
2878 if (FrontNonFloatingWindow () == FRAME_MAC_WINDOW (f)) 2749 if (mac_front_non_floating_window () == FRAME_MAC_WINDOW (f))
2879 SetFrontProcessWithOptions (&current_psn, 2750 SetFrontProcessWithOptions (&current_psn,
2880 kSetFrontProcessFrontWindowOnly); 2751 kSetFrontProcessFrontWindowOnly);
2881 else 2752 else
@@ -2884,8 +2755,8 @@ FRAME nil means use the selected frame. */)
2884 } 2755 }
2885 2756
2886#ifdef MAC_OSX 2757#ifdef MAC_OSX
2887 ActivateWindow (ActiveNonFloatingWindow (), false); 2758 mac_activate_window (mac_active_non_floating_window (), false);
2888 ActivateWindow (FRAME_MAC_WINDOW (f), true); 2759 mac_activate_window (FRAME_MAC_WINDOW (f), true);
2889#else 2760#else
2890#if !TARGET_API_MAC_CARBON 2761#if !TARGET_API_MAC_CARBON
2891 /* SelectWindow (Non-Carbon) does not issue deactivate events if the 2762 /* SelectWindow (Non-Carbon) does not issue deactivate events if the
@@ -3663,26 +3534,7 @@ show_hourglass (timer)
3663 3534
3664 if (FRAME_LIVE_P (f) && FRAME_MAC_P (f) 3535 if (FRAME_LIVE_P (f) && FRAME_MAC_P (f)
3665 && FRAME_MAC_WINDOW (f) != tip_window) 3536 && FRAME_MAC_WINDOW (f) != tip_window)
3666 { 3537 mac_show_hourglass (f);
3667#if USE_CG_DRAWING
3668 mac_prepare_for_quickdraw (f);
3669#endif
3670 if (!f->output_data.mac->hourglass_control)
3671 {
3672 Window w = FRAME_MAC_WINDOW (f);
3673 Rect r;
3674 ControlRef c;
3675
3676 GetWindowPortBounds (w, &r);
3677 r.left = r.right - HOURGLASS_WIDTH;
3678 r.bottom = r.top + HOURGLASS_HEIGHT;
3679 if (CreateChasingArrowsControl (w, &r, &c) == noErr)
3680 f->output_data.mac->hourglass_control = c;
3681 }
3682
3683 if (f->output_data.mac->hourglass_control)
3684 ShowControl (f->output_data.mac->hourglass_control);
3685 }
3686 } 3538 }
3687 3539
3688 hourglass_shown_p = 1; 3540 hourglass_shown_p = 1;
@@ -3708,15 +3560,8 @@ hide_hourglass ()
3708 { 3560 {
3709 struct frame *f = XFRAME (frame); 3561 struct frame *f = XFRAME (frame);
3710 3562
3711 if (FRAME_MAC_P (f) 3563 if (FRAME_MAC_P (f))
3712 /* Watch out for newly created frames. */ 3564 mac_hide_hourglass (f);
3713 && f->output_data.mac->hourglass_control)
3714 {
3715#if USE_CG_DRAWING
3716 mac_prepare_for_quickdraw (f);
3717#endif
3718 HideControl (f->output_data.mac->hourglass_control);
3719 }
3720 } 3565 }
3721 3566
3722 hourglass_shown_p = 0; 3567 hourglass_shown_p = 0;
@@ -3953,33 +3798,17 @@ x_create_tip_frame (dpyinfo, parms, text)
3953 3798
3954 window_prompting = x_figure_window_size (f, parms, 0); 3799 window_prompting = x_figure_window_size (f, parms, 0);
3955 3800
3956 { 3801 BLOCK_INPUT;
3957 Rect r;
3958 3802
3959 BLOCK_INPUT; 3803 mac_create_frame_window (f, 1);
3960 SetRect (&r, 0, 0, 1, 1); 3804
3961#if TARGET_API_MAC_CARBON 3805 if (FRAME_MAC_WINDOW (f))
3962 if (CreateNewWindow (kHelpWindowClass, 3806 {
3963#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020 3807 mac_set_frame_window_background (f, FRAME_BACKGROUND_PIXEL (f));
3964 kWindowIgnoreClicksAttribute | 3808 tip_window = FRAME_MAC_WINDOW (f);
3965#endif 3809 }
3966 kWindowNoUpdatesAttribute | 3810
3967 kWindowNoActivatesAttribute, 3811 UNBLOCK_INPUT;
3968 &r, &tip_window) == noErr)
3969#else
3970 if (tip_window = NewCWindow (NULL, &r, "\p", false, plainDBox,
3971 NULL, false, 0L))
3972#endif
3973 {
3974 FRAME_MAC_WINDOW (f) = tip_window;
3975 XSetWindowBackground (FRAME_MAC_DISPLAY(f), tip_window,
3976 FRAME_BACKGROUND_PIXEL (f));
3977 SetWRefCon (tip_window, (long) f->output_data.mac);
3978 /* so that update events can find this mac_output struct */
3979 f->output_data.mac->mFP = f;
3980 }
3981 UNBLOCK_INPUT;
3982 }
3983 3812
3984 x_make_gc (f); 3813 x_make_gc (f);
3985 3814
@@ -4076,7 +3905,7 @@ compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
4076 3905
4077 BLOCK_INPUT; 3906 BLOCK_INPUT;
4078#if TARGET_API_MAC_CARBON 3907#if TARGET_API_MAC_CARBON
4079 GetGlobalMouse (&mouse_pos); 3908 mac_get_global_mouse (&mouse_pos);
4080#else 3909#else
4081 GetMouse (&mouse_pos); 3910 GetMouse (&mouse_pos);
4082 LocalToGlobal (&mouse_pos); 3911 LocalToGlobal (&mouse_pos);
@@ -4200,7 +4029,7 @@ Text larger than the specified size is clipped. */)
4200 BLOCK_INPUT; 4029 BLOCK_INPUT;
4201 compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f), 4030 compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f),
4202 FRAME_PIXEL_HEIGHT (f), &root_x, &root_y); 4031 FRAME_PIXEL_HEIGHT (f), &root_x, &root_y);
4203 MoveWindow (FRAME_MAC_WINDOW (f), root_x, root_y, false); 4032 mac_move_window (FRAME_MAC_WINDOW (f), root_x, root_y, false);
4204 UNBLOCK_INPUT; 4033 UNBLOCK_INPUT;
4205 goto start_timer; 4034 goto start_timer;
4206 } 4035 }
@@ -4302,10 +4131,10 @@ Text larger than the specified size is clipped. */)
4302 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y); 4131 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
4303 4132
4304 BLOCK_INPUT; 4133 BLOCK_INPUT;
4305 MoveWindow (FRAME_MAC_WINDOW (f), root_x, root_y, false); 4134 mac_move_window (FRAME_MAC_WINDOW (f), root_x, root_y, false);
4306 SizeWindow (FRAME_MAC_WINDOW (f), width, height, true); 4135 mac_size_window (FRAME_MAC_WINDOW (f), width, height, true);
4307 ShowWindow (FRAME_MAC_WINDOW (f)); 4136 mac_show_window (FRAME_MAC_WINDOW (f));
4308 BringToFront (FRAME_MAC_WINDOW (f)); 4137 mac_bring_window_to_front (FRAME_MAC_WINDOW (f));
4309 UNBLOCK_INPUT; 4138 UNBLOCK_INPUT;
4310 4139
4311 FRAME_PIXEL_WIDTH (f) = width; 4140 FRAME_PIXEL_WIDTH (f) = width;
@@ -4366,25 +4195,11 @@ Value is t if tooltip was open, nil otherwise. */)
4366 4195
4367 4196
4368 4197
4369#if TARGET_API_MAC_CARBON
4370/*********************************************************************** 4198/***********************************************************************
4371 File selection dialog 4199 File selection dialog
4372 ***********************************************************************/ 4200 ***********************************************************************/
4373 4201
4374static pascal void mac_nav_event_callback P_ ((NavEventCallbackMessage, 4202#if TARGET_API_MAC_CARBON
4375 NavCBRecPtr, void *));
4376
4377/**
4378 There is a relatively standard way to do this using applescript to run
4379 a (choose file) method. However, this doesn't do "the right thing"
4380 by working only if the find-file occurred during a menu or toolbar
4381 click. So we must do the file dialog by hand, using the navigation
4382 manager. This also has more flexibility in determining the default
4383 directory and whether or not we are going to choose a file.
4384 **/
4385
4386extern Lisp_Object Qfile_name_history;
4387
4388DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0, 4203DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
4389 doc: /* Read file name, prompting with PROMPT in directory DIR. 4204 doc: /* Read file name, prompting with PROMPT in directory DIR.
4390Use a file selection dialog. 4205Use a file selection dialog.
@@ -4394,182 +4209,10 @@ If ONLY-DIR-P is non-nil, the user can only select directories. */)
4394 (prompt, dir, default_filename, mustmatch, only_dir_p) 4209 (prompt, dir, default_filename, mustmatch, only_dir_p)
4395 Lisp_Object prompt, dir, default_filename, mustmatch, only_dir_p; 4210 Lisp_Object prompt, dir, default_filename, mustmatch, only_dir_p;
4396{ 4211{
4397 Lisp_Object file = Qnil; 4212 return mac_file_dialog (prompt, dir, default_filename, mustmatch, only_dir_p);
4398 int count = SPECPDL_INDEX ();
4399 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
4400 char filename[MAXPATHLEN];
4401 static NavEventUPP mac_nav_event_callbackUPP = NULL;
4402
4403 check_mac ();
4404
4405 GCPRO6 (prompt, dir, default_filename, mustmatch, file, only_dir_p);
4406 CHECK_STRING (prompt);
4407 CHECK_STRING (dir);
4408
4409 /* Create the dialog with PROMPT as title, using DIR as initial
4410 directory and using "*" as pattern. */
4411 dir = Fexpand_file_name (dir, Qnil);
4412
4413 {
4414 OSStatus status;
4415 NavDialogCreationOptions options;
4416 NavDialogRef dialogRef;
4417 NavTypeListHandle fileTypes = NULL;
4418 NavUserAction userAction;
4419 CFStringRef message=NULL, saveName = NULL;
4420
4421 BLOCK_INPUT;
4422 /* No need for a callback function because we are modal */
4423 NavGetDefaultDialogCreationOptions(&options);
4424 options.modality = kWindowModalityAppModal;
4425 options.location.h = options.location.v = -1;
4426 options.optionFlags = kNavDefaultNavDlogOptions;
4427 options.optionFlags |= kNavAllFilesInPopup; /* All files allowed */
4428 options.optionFlags |= kNavSelectAllReadableItem;
4429 options.optionFlags &= ~kNavAllowMultipleFiles;
4430 if (!NILP(prompt))
4431 {
4432 message = cfstring_create_with_string (prompt);
4433 options.message = message;
4434 }
4435 /* Don't set the application, let it use default.
4436 options.clientName = CFSTR ("Emacs");
4437 */
4438
4439 if (mac_nav_event_callbackUPP == NULL)
4440 mac_nav_event_callbackUPP = NewNavEventUPP (mac_nav_event_callback);
4441
4442 if (!NILP (only_dir_p))
4443 status = NavCreateChooseFolderDialog(&options, mac_nav_event_callbackUPP,
4444 NULL, NULL, &dialogRef);
4445 else if (NILP (mustmatch))
4446 {
4447 /* This is a save dialog */
4448 options.optionFlags |= kNavDontConfirmReplacement;
4449 options.actionButtonLabel = CFSTR ("Ok");
4450 options.windowTitle = CFSTR ("Enter name");
4451
4452 if (STRINGP (default_filename))
4453 {
4454 Lisp_Object utf8 = ENCODE_UTF_8 (default_filename);
4455 char *begPtr = SDATA(utf8);
4456 char *filePtr = begPtr + SBYTES(utf8);
4457 while (filePtr != begPtr && !IS_DIRECTORY_SEP(filePtr[-1]))
4458 filePtr--;
4459 saveName = cfstring_create_with_utf8_cstring (filePtr);
4460 options.saveFileName = saveName;
4461 options.optionFlags |= kNavSelectDefaultLocation;
4462 }
4463 status = NavCreatePutFileDialog(&options,
4464 'TEXT', kNavGenericSignature,
4465 mac_nav_event_callbackUPP, NULL,
4466 &dialogRef);
4467 }
4468 else
4469 {
4470 /* This is an open dialog*/
4471 status = NavCreateChooseFileDialog(&options, fileTypes,
4472 mac_nav_event_callbackUPP, NULL,
4473 NULL, NULL, &dialogRef);
4474 }
4475
4476 /* Set the default location and continue*/
4477 if (status == noErr)
4478 {
4479 Lisp_Object encoded_dir = ENCODE_FILE (dir);
4480 AEDesc defLocAed;
4481
4482 status = AECreateDesc (TYPE_FILE_NAME, SDATA (encoded_dir),
4483 SBYTES (encoded_dir), &defLocAed);
4484 if (status == noErr)
4485 {
4486 NavCustomControl(dialogRef, kNavCtlSetLocation, (void*) &defLocAed);
4487 AEDisposeDesc(&defLocAed);
4488 }
4489 status = NavDialogRun(dialogRef);
4490 }
4491
4492 if (saveName) CFRelease(saveName);
4493 if (message) CFRelease(message);
4494
4495 if (status == noErr) {
4496 userAction = NavDialogGetUserAction(dialogRef);
4497 switch (userAction)
4498 {
4499 case kNavUserActionNone:
4500 case kNavUserActionCancel:
4501 break; /* Treat cancel like C-g */
4502 case kNavUserActionOpen:
4503 case kNavUserActionChoose:
4504 case kNavUserActionSaveAs:
4505 {
4506 NavReplyRecord reply;
4507 Size len;
4508
4509 status = NavDialogGetReply(dialogRef, &reply);
4510 if (status != noErr)
4511 break;
4512 status = AEGetNthPtr (&reply.selection, 1, TYPE_FILE_NAME,
4513 NULL, NULL, filename,
4514 sizeof (filename) - 1, &len);
4515 if (status == noErr)
4516 {
4517 len = min (len, sizeof (filename) - 1);
4518 filename[len] = '\0';
4519 if (reply.saveFileName)
4520 {
4521 /* If it was a saved file, we need to add the file name */
4522 if (len && len < sizeof (filename) - 1
4523 && filename[len-1] != '/')
4524 filename[len++] = '/';
4525 CFStringGetCString(reply.saveFileName, filename+len,
4526 sizeof (filename) - len,
4527#ifdef MAC_OSX
4528 kCFStringEncodingUTF8
4529#else
4530 CFStringGetSystemEncoding ()
4531#endif
4532 );
4533 }
4534 file = DECODE_FILE (make_unibyte_string (filename,
4535 strlen (filename)));
4536 }
4537 NavDisposeReply(&reply);
4538 }
4539 break;
4540 }
4541 NavDialogDispose(dialogRef);
4542 UNBLOCK_INPUT;
4543 }
4544 else {
4545 UNBLOCK_INPUT;
4546 /* Fall back on minibuffer if there was a problem */
4547 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
4548 dir, mustmatch, dir, Qfile_name_history,
4549 default_filename, Qnil);
4550 }
4551 }
4552
4553 UNGCPRO;
4554
4555 /* Make "Cancel" equivalent to C-g. */
4556 if (NILP (file))
4557 Fsignal (Qquit, Qnil);
4558
4559 return unbind_to (count, file);
4560}
4561
4562
4563/* Need to register some event callback function for enabling drag and
4564 drop in Navigation Service dialogs. */
4565static pascal void
4566mac_nav_event_callback (selector, parms, data)
4567 NavEventCallbackMessage selector;
4568 NavCBRecPtr parms;
4569 void *data ;
4570{
4571} 4213}
4572#endif 4214#endif
4215
4573 4216
4574/*********************************************************************** 4217/***********************************************************************
4575 Fonts 4218 Fonts
diff --git a/src/macgui.h b/src/macgui.h
index 755bffbd461..c549a885f48 100644
--- a/src/macgui.h
+++ b/src/macgui.h
@@ -71,7 +71,7 @@ typedef unsigned long Time;
71#undef Z 71#undef Z
72#define Z (current_buffer->text->z) 72#define Z (current_buffer->text->z)
73#else /* not HAVE_CARBON */ 73#else /* not HAVE_CARBON */
74#include <QuickDraw.h> /* for WindowRef */ 74#include <Quickdraw.h> /* for WindowRef */
75#include <QDOffscreen.h> /* for GWorldPtr */ 75#include <QDOffscreen.h> /* for GWorldPtr */
76#include <Appearance.h> /* for ThemeCursor */ 76#include <Appearance.h> /* for ThemeCursor */
77#include <Windows.h> 77#include <Windows.h>
@@ -127,6 +127,28 @@ typedef unsigned long Time;
127#endif 127#endif
128 128
129typedef WindowRef Window; 129typedef WindowRef Window;
130#if TARGET_API_MAC_CARBON
131typedef ScrapRef Selection;
132#else
133typedef int Selection;
134#endif
135#define mac_set_window_title SetWindowTitleWithCFString
136#define mac_set_window_modified SetWindowModified
137#define mac_is_window_visible IsWindowVisible
138#define mac_is_window_collapsed IsWindowCollapsed
139#define mac_bring_window_to_front BringToFront
140#define mac_send_window_behind SendBehind
141#define mac_hide_window HideWindow
142#define mac_show_window ShowWindow
143#define mac_collapse_window CollapseWindow
144#define mac_front_non_floating_window FrontNonFloatingWindow
145#define mac_active_non_floating_window ActiveNonFloatingWindow
146#define mac_activate_window ActivateWindow
147#define mac_move_window_structure MoveWindowStructure
148#define mac_move_window MoveWindow
149#define mac_size_window SizeWindow
150#define mac_get_global_mouse GetGlobalMouse
151#define mac_is_window_toolbar_visible IsWindowToolbarVisible
130typedef GWorldPtr Pixmap; 152typedef GWorldPtr Pixmap;
131 153
132#define Cursor ThemeCursor 154#define Cursor ThemeCursor
@@ -363,6 +385,97 @@ typedef struct {
363 (nr).right = ((nr).left + (width)), \ 385 (nr).right = ((nr).left + (width)), \
364 (nr).bottom = ((nr).top + (height))) 386 (nr).bottom = ((nr).top + (height)))
365 387
388/* Definitions copied from lwlib.h */
389
390typedef void * XtPointer;
391
392enum button_type
393{
394 BUTTON_TYPE_NONE,
395 BUTTON_TYPE_TOGGLE,
396 BUTTON_TYPE_RADIO
397};
398
399/* This structure is based on the one in ../lwlib/lwlib.h, modified
400 for Mac OS. */
401typedef struct _widget_value
402{
403 /* name of widget */
404 Lisp_Object lname;
405 char* name;
406 /* value (meaning depend on widget type) */
407 char* value;
408 /* keyboard equivalent. no implications for XtTranslations */
409 Lisp_Object lkey;
410 char* key;
411 /* Help string or nil if none.
412 GC finds this string through the frame's menu_bar_vector
413 or through menu_items. */
414 Lisp_Object help;
415 /* true if enabled */
416 Boolean enabled;
417 /* true if selected */
418 Boolean selected;
419 /* The type of a button. */
420 enum button_type button_type;
421 /* true if menu title */
422 Boolean title;
423#if 0
424 /* true if was edited (maintained by get_value) */
425 Boolean edited;
426 /* true if has changed (maintained by lw library) */
427 change_type change;
428 /* true if this widget itself has changed,
429 but not counting the other widgets found in the `next' field. */
430 change_type this_one_change;
431#endif
432 /* Contents of the sub-widgets, also selected slot for checkbox */
433 struct _widget_value* contents;
434 /* data passed to callback */
435 XtPointer call_data;
436 /* next one in the list */
437 struct _widget_value* next;
438#if 0
439 /* slot for the toolkit dependent part. Always initialize to NULL. */
440 void* toolkit_data;
441 /* tell us if we should free the toolkit data slot when freeing the
442 widget_value itself. */
443 Boolean free_toolkit_data;
444
445 /* we resource the widget_value structures; this points to the next
446 one on the free list if this one has been deallocated.
447 */
448 struct _widget_value *free_list;
449#endif
450} widget_value;
451
452#if MAC_OS8
453#define M_APPLE 234
454#define I_ABOUT 1
455
456#define EXTRA_STACK_ALLOC (256 * 1024)
457
458#define ARGV_STRING_LIST_ID 129
459#define RAM_TOO_LARGE_ALERT_ID 129
460#define ABOUT_ALERT_ID 128
461#endif
462
463#define DIALOG_LEFT_MARGIN (112)
464#define DIALOG_TOP_MARGIN (24)
465#define DIALOG_RIGHT_MARGIN (24)
466#define DIALOG_BOTTOM_MARGIN (20)
467#define DIALOG_MIN_INNER_WIDTH (338)
468#define DIALOG_MAX_INNER_WIDTH (564)
469#define DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE (12)
470#define DIALOG_BUTTON_BUTTON_VERTICAL_SPACE (12)
471#define DIALOG_BUTTON_MIN_WIDTH (68)
472#define DIALOG_TEXT_MIN_HEIGHT (50)
473#define DIALOG_TEXT_BUTTONS_VERTICAL_SPACE (10)
474#define DIALOG_ICON_WIDTH (64)
475#define DIALOG_ICON_HEIGHT (64)
476#define DIALOG_ICON_LEFT_MARGIN (24)
477#define DIALOG_ICON_TOP_MARGIN (15)
478
366#endif /* EMACS_MACGUI_H */ 479#endif /* EMACS_MACGUI_H */
367 480
368/* arch-tag: 5a0da49a-35e2-418b-a58c-8a55778ae849 481/* arch-tag: 5a0da49a-35e2-418b-a58c-8a55778ae849
diff --git a/src/macmenu.c b/src/macmenu.c
index ddc6e3c2b84..bb45013fc73 100644
--- a/src/macmenu.c
+++ b/src/macmenu.c
@@ -36,20 +36,6 @@ Boston, MA 02110-1301, USA. */
36#include "charset.h" 36#include "charset.h"
37#include "coding.h" 37#include "coding.h"
38 38
39#if !TARGET_API_MAC_CARBON
40#include <MacTypes.h>
41#include <Menus.h>
42#include <Quickdraw.h>
43#include <ToolUtils.h>
44#include <Fonts.h>
45#include <Controls.h>
46#include <Windows.h>
47#include <Events.h>
48#if defined (__MRC__) || (__MSL__ >= 0x6000)
49#include <ControlDefinitions.h>
50#endif
51#endif /* not TARGET_API_MAC_CARBON */
52
53/* This may include sys/types.h, and that somehow loses 39/* This may include sys/types.h, and that somehow loses
54 if this is not done before the other system files. */ 40 if this is not done before the other system files. */
55#include "macterm.h" 41#include "macterm.h"
@@ -62,21 +48,6 @@ Boston, MA 02110-1301, USA. */
62 48
63#include "dispextern.h" 49#include "dispextern.h"
64 50
65enum mac_menu_kind { /* Menu ID range */
66 MAC_MENU_APPLE, /* 0 (Reserved by Apple) */
67 MAC_MENU_MENU_BAR, /* 1 .. 233 */
68 MAC_MENU_M_APPLE, /* 234 (== M_APPLE) */
69 MAC_MENU_POPUP, /* 235 */
70 MAC_MENU_DRIVER, /* 236 .. 255 (Reserved) */
71 MAC_MENU_MENU_BAR_SUB, /* 256 .. 16383 */
72 MAC_MENU_POPUP_SUB, /* 16384 .. 32767 */
73 MAC_MENU_END /* 32768 */
74};
75
76static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
77
78#define DIALOG_WINDOW_RESOURCE 130
79
80#if TARGET_API_MAC_CARBON 51#if TARGET_API_MAC_CARBON
81#define HAVE_DIALOGS 1 52#define HAVE_DIALOGS 1
82#endif 53#endif
@@ -84,69 +55,6 @@ static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
84#undef HAVE_MULTILINGUAL_MENU 55#undef HAVE_MULTILINGUAL_MENU
85 56
86/******************************************************************/ 57/******************************************************************/
87/* Definitions copied from lwlib.h */
88
89typedef void * XtPointer;
90
91enum button_type
92{
93 BUTTON_TYPE_NONE,
94 BUTTON_TYPE_TOGGLE,
95 BUTTON_TYPE_RADIO
96};
97
98/* This structure is based on the one in ../lwlib/lwlib.h, modified
99 for Mac OS. */
100typedef struct _widget_value
101{
102 /* name of widget */
103 Lisp_Object lname;
104 char* name;
105 /* value (meaning depend on widget type) */
106 char* value;
107 /* keyboard equivalent. no implications for XtTranslations */
108 Lisp_Object lkey;
109 char* key;
110 /* Help string or nil if none.
111 GC finds this string through the frame's menu_bar_vector
112 or through menu_items. */
113 Lisp_Object help;
114 /* true if enabled */
115 Boolean enabled;
116 /* true if selected */
117 Boolean selected;
118 /* The type of a button. */
119 enum button_type button_type;
120 /* true if menu title */
121 Boolean title;
122#if 0
123 /* true if was edited (maintained by get_value) */
124 Boolean edited;
125 /* true if has changed (maintained by lw library) */
126 change_type change;
127 /* true if this widget itself has changed,
128 but not counting the other widgets found in the `next' field. */
129 change_type this_one_change;
130#endif
131 /* Contents of the sub-widgets, also selected slot for checkbox */
132 struct _widget_value* contents;
133 /* data passed to callback */
134 XtPointer call_data;
135 /* next one in the list */
136 struct _widget_value* next;
137#if 0
138 /* slot for the toolkit dependent part. Always initialize to NULL. */
139 void* toolkit_data;
140 /* tell us if we should free the toolkit data slot when freeing the
141 widget_value itself. */
142 Boolean free_toolkit_data;
143
144 /* we resource the widget_value structures; this points to the next
145 one on the free list if this one has been deallocated.
146 */
147 struct _widget_value *free_list;
148#endif
149} widget_value;
150 58
151/* Assumed by other routines to zero area returned. */ 59/* Assumed by other routines to zero area returned. */
152#define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\ 60#define malloc_widget_value() (void *)memset (xmalloc (sizeof (widget_value)),\
@@ -198,12 +106,6 @@ static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
198static void list_of_panes P_ ((Lisp_Object)); 106static void list_of_panes P_ ((Lisp_Object));
199static void list_of_items P_ ((Lisp_Object)); 107static void list_of_items P_ ((Lisp_Object));
200 108
201static void find_and_call_menu_selection P_ ((FRAME_PTR, int, Lisp_Object,
202 void *));
203static int fill_menu P_ ((MenuRef, widget_value *, enum mac_menu_kind, int));
204static void fill_menubar P_ ((widget_value *, int));
205static void dispose_menus P_ ((enum mac_menu_kind, int));
206
207 109
208/* This holds a Lisp vector that holds the results of decoding 110/* This holds a Lisp vector that holds the results of decoding
209 the keymaps or alist-of-alists that specify a menu. 111 the keymaps or alist-of-alists that specify a menu.
@@ -260,7 +162,7 @@ static int menu_items_n_panes;
260static int menu_items_submenu_depth; 162static int menu_items_submenu_depth;
261 163
262/* Nonzero means a menu is currently active. */ 164/* Nonzero means a menu is currently active. */
263static int popup_activated_flag; 165int popup_activated_flag;
264 166
265/* This is set nonzero after the user activates the menu bar, and set 167/* This is set nonzero after the user activates the menu bar, and set
266 to zero again after the menu bars are redisplayed by prepare_menu_bar. 168 to zero again after the menu bars are redisplayed by prepare_menu_bar.
@@ -873,32 +775,6 @@ no quit occurs and `x-popup-menu' returns nil. */)
873 775
874#ifdef HAVE_MENUS 776#ifdef HAVE_MENUS
875 777
876/* Regard ESC and C-g as Cancel even without the Cancel button. */
877
878#if 0 /* defined (MAC_OSX) */
879static Boolean
880mac_dialog_modal_filter (dialog, event, item_hit)
881 DialogRef dialog;
882 EventRecord *event;
883 DialogItemIndex *item_hit;
884{
885 Boolean result;
886
887 result = StdFilterProc (dialog, event, item_hit);
888 if (result == false
889 && (event->what == keyDown || event->what == autoKey)
890 && ((event->message & charCodeMask) == kEscapeCharCode
891 || mac_quit_char_key_p (event->modifiers,
892 (event->message & keyCodeMask) >> 8)))
893 {
894 *item_hit = kStdCancelItemIndex;
895 return true;
896 }
897
898 return result;
899}
900#endif
901
902DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0, 778DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0,
903 doc: /* Pop up a dialog box and return user's selection. 779 doc: /* Pop up a dialog box and return user's selection.
904POSITION specifies which frame to use. 780POSITION specifies which frame to use.
@@ -984,101 +860,6 @@ for instance using the window manager, then this produces a quit and
984 but I don't want to make one now. */ 860 but I don't want to make one now. */
985 CHECK_WINDOW (window); 861 CHECK_WINDOW (window);
986 862
987#if 0 /* defined (MAC_OSX) */
988 /* Special treatment for Fmessage_box, Fyes_or_no_p, and Fy_or_n_p. */
989 if (EQ (position, Qt)
990 && STRINGP (Fcar (contents))
991 && ((!NILP (Fequal (XCDR (contents),
992 Fcons (Fcons (build_string ("OK"), Qt), Qnil)))
993 && EQ (header, Qt))
994 || (!NILP (Fequal (XCDR (contents),
995 Fcons (Fcons (build_string ("Yes"), Qt),
996 Fcons (Fcons (build_string ("No"), Qnil),
997 Qnil))))
998 && NILP (header))))
999 {
1000 OSStatus err = noErr;
1001 AlertStdCFStringAlertParamRec param;
1002 CFStringRef error_string, explanation_string;
1003 DialogRef alert;
1004 DialogItemIndex item_hit;
1005 Lisp_Object tem;
1006
1007 /* Force a redisplay before showing the dialog. If a frame is
1008 created just before showing the dialog, its contents may not
1009 have been fully drawn. */
1010 Fredisplay (Qt);
1011
1012 tem = Fstring_match (concat3 (build_string ("\\("),
1013 call0 (intern ("sentence-end")),
1014 build_string ("\\)\n")),
1015 XCAR (contents), Qnil);
1016 BLOCK_INPUT;
1017 if (NILP (tem))
1018 {
1019 error_string = cfstring_create_with_string (XCAR (contents));
1020 if (error_string == NULL)
1021 err = memFullErr;
1022 explanation_string = NULL;
1023 }
1024 else
1025 {
1026 tem = Fmatch_end (make_number (1));
1027 error_string =
1028 cfstring_create_with_string (Fsubstring (XCAR (contents),
1029 make_number (0), tem));
1030 if (error_string == NULL)
1031 err = memFullErr;
1032 else
1033 {
1034 XSETINT (tem, XINT (tem) + 1);
1035 explanation_string =
1036 cfstring_create_with_string (Fsubstring (XCAR (contents),
1037 tem, Qnil));
1038 if (explanation_string == NULL)
1039 {
1040 CFRelease (error_string);
1041 err = memFullErr;
1042 }
1043 }
1044 }
1045 if (err == noErr)
1046 err = GetStandardAlertDefaultParams (&param,
1047 kStdCFStringAlertVersionOne);
1048 if (err == noErr)
1049 {
1050 param.movable = true;
1051 param.position = kWindowAlertPositionParentWindow;
1052 if (NILP (header))
1053 {
1054 param.defaultText = CFSTR ("Yes");
1055 param.otherText = CFSTR ("No");
1056#if 0
1057 param.cancelText = CFSTR ("Cancel");
1058 param.cancelButton = kAlertStdAlertCancelButton;
1059#endif
1060 }
1061 err = CreateStandardAlert (kAlertNoteAlert, error_string,
1062 explanation_string, &param, &alert);
1063 CFRelease (error_string);
1064 if (explanation_string)
1065 CFRelease (explanation_string);
1066 }
1067 if (err == noErr)
1068 err = RunStandardAlert (alert, mac_dialog_modal_filter, &item_hit);
1069 UNBLOCK_INPUT;
1070
1071 if (err == noErr)
1072 {
1073 if (item_hit == kStdCancelItemIndex)
1074 Fsignal (Qquit, Qnil);
1075 else if (item_hit == kStdOkItemIndex)
1076 return Qt;
1077 else
1078 return Qnil;
1079 }
1080 }
1081#endif
1082#ifndef HAVE_DIALOGS 863#ifndef HAVE_DIALOGS
1083 /* Display a menu with these alternatives 864 /* Display a menu with these alternatives
1084 in the middle of frame F. */ 865 in the middle of frame F. */
@@ -1118,66 +899,12 @@ for instance using the window manager, then this produces a quit and
1118#endif /* HAVE_DIALOGS */ 899#endif /* HAVE_DIALOGS */
1119} 900}
1120 901
1121/* Activate the menu bar of frame F.
1122 This is called from keyboard.c when it gets the
1123 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
1124
1125 To activate the menu bar, we use the button-press event location
1126 that was saved in saved_menu_event_location.
1127
1128 But first we recompute the menu bar contents (the whole tree).
1129
1130 The reason for saving the button event until here, instead of
1131 passing it to the toolkit right away, is that we can safely
1132 execute Lisp code. */
1133
1134void
1135x_activate_menubar (f)
1136 FRAME_PTR f;
1137{
1138 SInt32 menu_choice;
1139 SInt16 menu_id, menu_item;
1140 extern Point saved_menu_event_location;
1141
1142 set_frame_menubar (f, 0, 1);
1143 BLOCK_INPUT;
1144
1145 popup_activated_flag = 1;
1146 menu_choice = MenuSelect (saved_menu_event_location);
1147 popup_activated_flag = 0;
1148 menu_id = HiWord (menu_choice);
1149 menu_item = LoWord (menu_choice);
1150
1151#if !TARGET_API_MAC_CARBON
1152 if (menu_id == min_menu_id[MAC_MENU_M_APPLE])
1153 do_apple_menu (menu_item);
1154 else
1155#endif
1156 if (menu_id)
1157 {
1158 MenuRef menu = GetMenuRef (menu_id);
1159
1160 if (menu)
1161 {
1162 UInt32 refcon;
1163
1164 GetMenuItemRefCon (menu, menu_item, &refcon);
1165 find_and_call_menu_selection (f, f->menu_bar_items_used,
1166 f->menu_bar_vector, (void *) refcon);
1167 }
1168 }
1169
1170 HiliteMenu (0);
1171
1172 UNBLOCK_INPUT;
1173}
1174
1175/* Find the menu selection and store it in the keyboard buffer. 902/* Find the menu selection and store it in the keyboard buffer.
1176 F is the frame the menu is on. 903 F is the frame the menu is on.
1177 MENU_BAR_ITEMS_USED is the length of VECTOR. 904 MENU_BAR_ITEMS_USED is the length of VECTOR.
1178 VECTOR is an array of menu events for the whole menu. */ 905 VECTOR is an array of menu events for the whole menu. */
1179 906
1180static void 907void
1181find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data) 908find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data)
1182 FRAME_PTR f; 909 FRAME_PTR f;
1183 int menu_bar_items_used; 910 int menu_bar_items_used;
@@ -1570,141 +1297,6 @@ update_submenu_strings (first_wv)
1570} 1297}
1571 1298
1572 1299
1573#if TARGET_API_MAC_CARBON
1574extern Lisp_Object Vshow_help_function;
1575
1576static Lisp_Object
1577restore_show_help_function (old_show_help_function)
1578 Lisp_Object old_show_help_function;
1579{
1580 Vshow_help_function = old_show_help_function;
1581
1582 return Qnil;
1583}
1584
1585static pascal OSStatus
1586menu_target_item_handler (next_handler, event, data)
1587 EventHandlerCallRef next_handler;
1588 EventRef event;
1589 void *data;
1590{
1591 OSStatus err;
1592 MenuRef menu;
1593 MenuItemIndex menu_item;
1594 Lisp_Object help;
1595 GrafPtr port;
1596 int specpdl_count = SPECPDL_INDEX ();
1597
1598 /* Don't be bothered with the overflowed toolbar items menu. */
1599 if (!popup_activated ())
1600 return eventNotHandledErr;
1601
1602 err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef,
1603 NULL, sizeof (MenuRef), NULL, &menu);
1604 if (err == noErr)
1605 err = GetEventParameter (event, kEventParamMenuItemIndex,
1606 typeMenuItemIndex, NULL,
1607 sizeof (MenuItemIndex), NULL, &menu_item);
1608 if (err == noErr)
1609 err = GetMenuItemProperty (menu, menu_item,
1610 MAC_EMACS_CREATOR_CODE, 'help',
1611 sizeof (Lisp_Object), NULL, &help);
1612 if (err != noErr)
1613 help = Qnil;
1614
1615 /* Temporarily bind Vshow_help_function to Qnil because we don't
1616 want tooltips during menu tracking. */
1617 record_unwind_protect (restore_show_help_function, Vshow_help_function);
1618 Vshow_help_function = Qnil;
1619 GetPort (&port);
1620 show_help_echo (help, Qnil, Qnil, Qnil, 1);
1621 SetPort (port);
1622 unbind_to (specpdl_count, Qnil);
1623
1624 return err == noErr ? noErr : eventNotHandledErr;
1625}
1626
1627OSStatus
1628install_menu_target_item_handler ()
1629{
1630 static const EventTypeSpec specs[] =
1631 {{kEventClassMenu, kEventMenuTargetItem}};
1632
1633 return InstallApplicationEventHandler (NewEventHandlerUPP
1634 (menu_target_item_handler),
1635 GetEventTypeCount (specs),
1636 specs, NULL, NULL);
1637}
1638#endif /* TARGET_API_MAC_CARBON */
1639
1640/* Event handler function that pops down a menu on C-g. We can only pop
1641 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
1642
1643#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1644static pascal OSStatus
1645menu_quit_handler (nextHandler, theEvent, userData)
1646 EventHandlerCallRef nextHandler;
1647 EventRef theEvent;
1648 void* userData;
1649{
1650 OSStatus err;
1651 UInt32 keyCode;
1652 UInt32 keyModifiers;
1653
1654 err = GetEventParameter (theEvent, kEventParamKeyCode,
1655 typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
1656
1657 if (err == noErr)
1658 err = GetEventParameter (theEvent, kEventParamKeyModifiers,
1659 typeUInt32, NULL, sizeof(UInt32),
1660 NULL, &keyModifiers);
1661
1662 if (err == noErr && mac_quit_char_key_p (keyModifiers, keyCode))
1663 {
1664 MenuRef menu = userData != 0
1665 ? (MenuRef)userData : AcquireRootMenu ();
1666
1667 CancelMenuTracking (menu, true, 0);
1668 if (!userData) ReleaseMenu (menu);
1669 return noErr;
1670 }
1671
1672 return CallNextEventHandler (nextHandler, theEvent);
1673}
1674#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1675
1676/* Add event handler to all menus that belong to KIND so we can detect
1677 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
1678 when C-g is detected. NULL means the menu bar. If
1679 CancelMenuTracking isn't available, do nothing. */
1680
1681static void
1682install_menu_quit_handler (kind, root_menu)
1683 enum mac_menu_kind kind;
1684 MenuRef root_menu;
1685{
1686#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
1687 static const EventTypeSpec typesList[] =
1688 {{kEventClassKeyboard, kEventRawKeyDown}};
1689 int id;
1690
1691#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
1692 if (CancelMenuTracking == NULL)
1693 return;
1694#endif
1695 for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++)
1696 {
1697 MenuRef menu = GetMenuRef (id);
1698
1699 if (menu == NULL)
1700 break;
1701 InstallMenuEventHandler (menu, menu_quit_handler,
1702 GetEventTypeCount (typesList),
1703 typesList, root_menu, NULL);
1704 }
1705#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
1706}
1707
1708/* Set the contents of the menubar widgets of frame F. 1300/* Set the contents of the menubar widgets of frame F.
1709 The argument FIRST_TIME is currently ignored; 1301 The argument FIRST_TIME is currently ignored;
1710 it is set the first time this is called, from initialize_frame_menubar. */ 1302 it is set the first time this is called, from initialize_frame_menubar. */
@@ -1940,11 +1532,8 @@ set_frame_menubar (f, first_time, deep_p)
1940 /* Non-null value to indicate menubar has already been "created". */ 1532 /* Non-null value to indicate menubar has already been "created". */
1941 f->output_data.mac->menubar_widget = 1; 1533 f->output_data.mac->menubar_widget = 1;
1942 1534
1943 fill_menubar (first_wv->contents, deep_p); 1535 mac_fill_menubar (first_wv->contents, deep_p);
1944 1536
1945 /* Add event handler so we can detect C-g. */
1946 install_menu_quit_handler (MAC_MENU_MENU_BAR, NULL);
1947 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB, NULL);
1948 free_menubar_widget_value_tree (first_wv); 1537 free_menubar_widget_value_tree (first_wv);
1949 1538
1950 UNBLOCK_INPUT; 1539 UNBLOCK_INPUT;
@@ -1961,29 +1550,8 @@ free_frame_menubar (f)
1961} 1550}
1962 1551
1963 1552
1964static Lisp_Object 1553/* The item selected in the popup menu. */
1965pop_down_menu (arg) 1554int menu_item_selection;
1966 Lisp_Object arg;
1967{
1968 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
1969 FRAME_PTR f = p->pointer;
1970 MenuRef menu = GetMenuRef (min_menu_id[MAC_MENU_POPUP]);
1971
1972 BLOCK_INPUT;
1973
1974 /* Must reset this manually because the button release event is not
1975 passed to Emacs event loop. */
1976 FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0;
1977
1978 /* delete all menus */
1979 dispose_menus (MAC_MENU_POPUP_SUB, 0);
1980 DeleteMenu (min_menu_id[MAC_MENU_POPUP]);
1981 DisposeMenu (menu);
1982
1983 UNBLOCK_INPUT;
1984
1985 return Qnil;
1986}
1987 1555
1988/* Mac_menu_show actually displays a menu using the panes and items in 1556/* Mac_menu_show actually displays a menu using the panes and items in
1989 menu_items and returns the value selected from it; we assume input 1557 menu_items and returns the value selected from it; we assume input
@@ -2011,9 +1579,6 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
2011 char **error; 1579 char **error;
2012{ 1580{
2013 int i; 1581 int i;
2014 int menu_item_choice;
2015 UInt32 menu_item_selection;
2016 MenuRef menu;
2017 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; 1582 widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0;
2018 widget_value **submenu_stack 1583 widget_value **submenu_stack
2019 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); 1584 = (widget_value **) alloca (menu_items_used * sizeof (widget_value *));
@@ -2022,7 +1587,6 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
2022 int submenu_depth = 0; 1587 int submenu_depth = 0;
2023 1588
2024 int first_pane; 1589 int first_pane;
2025 int specpdl_count = SPECPDL_INDEX ();
2026 1590
2027 *error = NULL; 1591 *error = NULL;
2028 1592
@@ -2208,45 +1772,14 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
2208 first_wv->contents = wv_title; 1772 first_wv->contents = wv_title;
2209 } 1773 }
2210 1774
2211 /* Actually create the menu. */
2212 menu = NewMenu (min_menu_id[MAC_MENU_POPUP], "\p");
2213 InsertMenu (menu, -1);
2214 fill_menu (menu, first_wv->contents, MAC_MENU_POPUP_SUB,
2215 min_menu_id[MAC_MENU_POPUP_SUB]);
2216
2217 /* Free the widget_value objects we used to specify the
2218 contents. */
2219 free_menubar_widget_value_tree (first_wv);
2220
2221 /* Adjust coordinates to be root-window-relative. */
2222 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
2223 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
2224
2225 /* No selection has been chosen yet. */ 1775 /* No selection has been chosen yet. */
2226 menu_item_selection = 0; 1776 menu_item_selection = 0;
2227 1777
2228 record_unwind_protect (pop_down_menu, make_save_value (f, 0)); 1778 /* Actually create and show the menu until popped down. */
1779 create_and_show_popup_menu (f, first_wv, x, y, for_click);
2229 1780
2230 /* Add event handler so we can detect C-g. */ 1781 /* Free the widget_value objects we used to specify the contents. */
2231 install_menu_quit_handler (MAC_MENU_POPUP, menu); 1782 free_menubar_widget_value_tree (first_wv);
2232 install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu);
2233
2234 /* Display the menu. */
2235 popup_activated_flag = 1;
2236 menu_item_choice = PopUpMenuSelect (menu, y, x, 0);
2237 popup_activated_flag = 0;
2238
2239 /* Get the refcon to find the correct item */
2240 if (menu_item_choice)
2241 {
2242 MenuRef sel_menu = GetMenuRef (HiWord (menu_item_choice));
2243
2244 if (sel_menu)
2245 GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice),
2246 &menu_item_selection);
2247 }
2248
2249 unbind_to (specpdl_count, Qnil);
2250 1783
2251 /* Find the selected item, and its pane, to return 1784 /* Find the selected item, and its pane, to return
2252 the proper value. */ 1785 the proper value. */
@@ -2313,582 +1846,6 @@ mac_menu_show (f, x, y, for_click, keymaps, title, error)
2313#ifdef HAVE_DIALOGS 1846#ifdef HAVE_DIALOGS
2314/* Construct native Mac OS dialog based on widget_value tree. */ 1847/* Construct native Mac OS dialog based on widget_value tree. */
2315 1848
2316#if TARGET_API_MAC_CARBON
2317
2318#define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
2319#define DIALOG_BUTTON_COMMAND_ID_P(id) \
2320 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
2321#define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
2322 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
2323#define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
2324 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
2325
2326extern EMACS_TIME timer_check P_ ((int));
2327static int quit_dialog_event_loop;
2328
2329static pascal OSStatus
2330mac_handle_dialog_event (next_handler, event, data)
2331 EventHandlerCallRef next_handler;
2332 EventRef event;
2333 void *data;
2334{
2335 OSStatus err, result = eventNotHandledErr;
2336 WindowRef window = (WindowRef) data;
2337
2338 switch (GetEventClass (event))
2339 {
2340 case kEventClassCommand:
2341 {
2342 HICommand command;
2343
2344 err = GetEventParameter (event, kEventParamDirectObject,
2345 typeHICommand, NULL, sizeof (HICommand),
2346 NULL, &command);
2347 if (err == noErr)
2348 if (DIALOG_BUTTON_COMMAND_ID_P (command.commandID))
2349 {
2350 SetWRefCon (window, command.commandID);
2351 quit_dialog_event_loop = 1;
2352 break;
2353 }
2354
2355 result = CallNextEventHandler (next_handler, event);
2356 }
2357 break;
2358
2359 case kEventClassKeyboard:
2360 {
2361 OSStatus result;
2362 char char_code;
2363
2364 result = CallNextEventHandler (next_handler, event);
2365 if (result != eventNotHandledErr)
2366 break;
2367
2368 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
2369 typeChar, NULL, sizeof (char),
2370 NULL, &char_code);
2371 if (err == noErr)
2372 switch (char_code)
2373 {
2374 case kEscapeCharCode:
2375 quit_dialog_event_loop = 1;
2376 break;
2377
2378 default:
2379 {
2380 UInt32 modifiers, key_code;
2381
2382 err = GetEventParameter (event, kEventParamKeyModifiers,
2383 typeUInt32, NULL, sizeof (UInt32),
2384 NULL, &modifiers);
2385 if (err == noErr)
2386 err = GetEventParameter (event, kEventParamKeyCode,
2387 typeUInt32, NULL, sizeof (UInt32),
2388 NULL, &key_code);
2389 if (err == noErr)
2390 if (mac_quit_char_key_p (modifiers, key_code))
2391 quit_dialog_event_loop = 1;
2392 }
2393 break;
2394 }
2395 }
2396 break;
2397
2398 default:
2399 abort ();
2400 }
2401
2402 if (quit_dialog_event_loop)
2403 {
2404 err = QuitEventLoop (GetCurrentEventLoop ());
2405 if (err == noErr)
2406 result = noErr;
2407 }
2408
2409 return result;
2410}
2411
2412static OSStatus
2413install_dialog_event_handler (window)
2414 WindowRef window;
2415{
2416 static const EventTypeSpec specs[] =
2417 {{kEventClassCommand, kEventCommandProcess},
2418 {kEventClassKeyboard, kEventRawKeyDown}};
2419 static EventHandlerUPP handle_dialog_eventUPP = NULL;
2420
2421 if (handle_dialog_eventUPP == NULL)
2422 handle_dialog_eventUPP = NewEventHandlerUPP (mac_handle_dialog_event);
2423 return InstallWindowEventHandler (window, handle_dialog_eventUPP,
2424 GetEventTypeCount (specs), specs,
2425 window, NULL);
2426}
2427
2428#define DIALOG_LEFT_MARGIN (112)
2429#define DIALOG_TOP_MARGIN (24)
2430#define DIALOG_RIGHT_MARGIN (24)
2431#define DIALOG_BOTTOM_MARGIN (20)
2432#define DIALOG_MIN_INNER_WIDTH (338)
2433#define DIALOG_MAX_INNER_WIDTH (564)
2434#define DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE (12)
2435#define DIALOG_BUTTON_BUTTON_VERTICAL_SPACE (12)
2436#define DIALOG_BUTTON_MIN_WIDTH (68)
2437#define DIALOG_TEXT_MIN_HEIGHT (50)
2438#define DIALOG_TEXT_BUTTONS_VERTICAL_SPACE (10)
2439#define DIALOG_ICON_WIDTH (64)
2440#define DIALOG_ICON_HEIGHT (64)
2441#define DIALOG_ICON_LEFT_MARGIN (24)
2442#define DIALOG_ICON_TOP_MARGIN (15)
2443
2444static Lisp_Object
2445pop_down_dialog (arg)
2446 Lisp_Object arg;
2447{
2448 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
2449 WindowRef window = p->pointer;
2450
2451 BLOCK_INPUT;
2452
2453 if (popup_activated_flag)
2454 EndAppModalStateForWindow (window);
2455 DisposeWindow (window);
2456 popup_activated_flag = 0;
2457
2458 UNBLOCK_INPUT;
2459
2460 return Qnil;
2461}
2462
2463static int
2464create_and_show_dialog (f, first_wv)
2465 FRAME_PTR f;
2466 widget_value *first_wv;
2467{
2468 OSStatus err;
2469 char *dialog_name, *message;
2470 int nb_buttons, first_group_count, i, result = 0;
2471 widget_value *wv;
2472 short buttons_height, text_height, inner_width, inner_height;
2473 Rect empty_rect, *rects;
2474 WindowRef window = NULL;
2475 ControlRef *buttons, default_button = NULL, text;
2476 int specpdl_count = SPECPDL_INDEX ();
2477
2478 dialog_name = first_wv->name;
2479 nb_buttons = dialog_name[1] - '0';
2480 first_group_count = nb_buttons - (dialog_name[4] - '0');
2481
2482 wv = first_wv->contents;
2483 message = wv->value;
2484
2485 wv = wv->next;
2486 SetRect (&empty_rect, 0, 0, 0, 0);
2487
2488 /* Create dialog window. */
2489 err = CreateNewWindow (kMovableModalWindowClass,
2490 kWindowStandardHandlerAttribute,
2491 &empty_rect, &window);
2492 if (err == noErr)
2493 {
2494 record_unwind_protect (pop_down_dialog, make_save_value (window, 0));
2495 err = SetThemeWindowBackground (window, kThemeBrushMovableModalBackground,
2496 true);
2497 }
2498 if (err == noErr)
2499 err = SetWindowTitleWithCFString (window, (dialog_name[0] == 'Q'
2500 ? CFSTR ("Question")
2501 : CFSTR ("Information")));
2502
2503 /* Create button controls and measure their optimal bounds. */
2504 if (err == noErr)
2505 {
2506 buttons = alloca (sizeof (ControlRef) * nb_buttons);
2507 rects = alloca (sizeof (Rect) * nb_buttons);
2508 for (i = 0; i < nb_buttons; i++)
2509 {
2510 CFStringRef label = cfstring_create_with_utf8_cstring (wv->value);
2511
2512 if (label == NULL)
2513 err = memFullErr;
2514 else
2515 {
2516 err = CreatePushButtonControl (window, &empty_rect,
2517 label, &buttons[i]);
2518 CFRelease (label);
2519 }
2520 if (err == noErr)
2521 {
2522 if (!wv->enabled)
2523 {
2524#ifdef MAC_OSX
2525 err = DisableControl (buttons[i]);
2526#else
2527 err = DeactivateControl (buttons[i]);
2528#endif
2529 }
2530 else if (default_button == NULL)
2531 default_button = buttons[i];
2532 }
2533 if (err == noErr)
2534 {
2535 SInt16 unused;
2536
2537 rects[i] = empty_rect;
2538 err = GetBestControlRect (buttons[i], &rects[i], &unused);
2539 }
2540 if (err == noErr)
2541 {
2542 UInt32 command_id;
2543
2544 OffsetRect (&rects[i], -rects[i].left, -rects[i].top);
2545 if (rects[i].right < DIALOG_BUTTON_MIN_WIDTH)
2546 rects[i].right = DIALOG_BUTTON_MIN_WIDTH;
2547 else if (rects[i].right > DIALOG_MAX_INNER_WIDTH)
2548 rects[i].right = DIALOG_MAX_INNER_WIDTH;
2549
2550 command_id = DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv->call_data);
2551 err = SetControlCommandID (buttons[i], command_id);
2552 }
2553 if (err != noErr)
2554 break;
2555 wv = wv->next;
2556 }
2557 }
2558
2559 /* Layout buttons. rects[i] is set relative to the bottom-right
2560 corner of the inner box. */
2561 if (err == noErr)
2562 {
2563 short bottom, right, max_height, left_align_shift;
2564
2565 inner_width = DIALOG_MIN_INNER_WIDTH;
2566 bottom = right = max_height = 0;
2567 for (i = 0; i < nb_buttons; i++)
2568 {
2569 if (right - rects[i].right < - inner_width)
2570 {
2571 if (i != first_group_count
2572 && right - rects[i].right >= - DIALOG_MAX_INNER_WIDTH)
2573 inner_width = - (right - rects[i].right);
2574 else
2575 {
2576 bottom -= max_height + DIALOG_BUTTON_BUTTON_VERTICAL_SPACE;
2577 right = max_height = 0;
2578 }
2579 }
2580 if (max_height < rects[i].bottom)
2581 max_height = rects[i].bottom;
2582 OffsetRect (&rects[i], right - rects[i].right,
2583 bottom - rects[i].bottom);
2584 right = rects[i].left - DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
2585 if (i == first_group_count - 1)
2586 right -= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
2587 }
2588 buttons_height = - (bottom - max_height);
2589
2590 left_align_shift = - (inner_width + rects[nb_buttons - 1].left);
2591 for (i = nb_buttons - 1; i >= first_group_count; i--)
2592 {
2593 if (bottom != rects[i].bottom)
2594 {
2595 left_align_shift = - (inner_width + rects[i].left);
2596 bottom = rects[i].bottom;
2597 }
2598 OffsetRect (&rects[i], left_align_shift, 0);
2599 }
2600 }
2601
2602 /* Create a static text control and measure its bounds. */
2603 if (err == noErr)
2604 {
2605 CFStringRef message_string;
2606 Rect bounds;
2607
2608 message_string = cfstring_create_with_utf8_cstring (message);
2609 if (message_string == NULL)
2610 err = memFullErr;
2611 else
2612 {
2613 ControlFontStyleRec text_style;
2614
2615 text_style.flags = 0;
2616 SetRect (&bounds, 0, 0, inner_width, 0);
2617 err = CreateStaticTextControl (window, &bounds, message_string,
2618 &text_style, &text);
2619 CFRelease (message_string);
2620 }
2621 if (err == noErr)
2622 {
2623 SInt16 unused;
2624
2625 bounds = empty_rect;
2626 err = GetBestControlRect (text, &bounds, &unused);
2627 }
2628 if (err == noErr)
2629 {
2630 text_height = bounds.bottom - bounds.top;
2631 if (text_height < DIALOG_TEXT_MIN_HEIGHT)
2632 text_height = DIALOG_TEXT_MIN_HEIGHT;
2633 }
2634 }
2635
2636 /* Place buttons. */
2637 if (err == noErr)
2638 {
2639 inner_height = (text_height + DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
2640 + buttons_height);
2641
2642 for (i = 0; i < nb_buttons; i++)
2643 {
2644 OffsetRect (&rects[i], DIALOG_LEFT_MARGIN + inner_width,
2645 DIALOG_TOP_MARGIN + inner_height);
2646 SetControlBounds (buttons[i], &rects[i]);
2647 }
2648 }
2649
2650 /* Place text. */
2651 if (err == noErr)
2652 {
2653 Rect bounds;
2654
2655 SetRect (&bounds, DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN,
2656 DIALOG_LEFT_MARGIN + inner_width,
2657 DIALOG_TOP_MARGIN + text_height);
2658 SetControlBounds (text, &bounds);
2659 }
2660
2661 /* Create the application icon at the upper-left corner. */
2662 if (err == noErr)
2663 {
2664 ControlButtonContentInfo content;
2665 ControlRef icon;
2666 static const ProcessSerialNumber psn = {0, kCurrentProcess};
2667#ifdef MAC_OSX
2668 FSRef app_location;
2669#else
2670 ProcessInfoRec pinfo;
2671 FSSpec app_spec;
2672#endif
2673 SInt16 unused;
2674
2675 content.contentType = kControlContentIconRef;
2676#ifdef MAC_OSX
2677 err = GetProcessBundleLocation (&psn, &app_location);
2678 if (err == noErr)
2679 err = GetIconRefFromFileInfo (&app_location, 0, NULL, 0, NULL,
2680 kIconServicesNormalUsageFlag,
2681 &content.u.iconRef, &unused);
2682#else
2683 bzero (&pinfo, sizeof (ProcessInfoRec));
2684 pinfo.processInfoLength = sizeof (ProcessInfoRec);
2685 pinfo.processAppSpec = &app_spec;
2686 err = GetProcessInformation (&psn, &pinfo);
2687 if (err == noErr)
2688 err = GetIconRefFromFile (&app_spec, &content.u.iconRef, &unused);
2689#endif
2690 if (err == noErr)
2691 {
2692 Rect bounds;
2693
2694 SetRect (&bounds, DIALOG_ICON_LEFT_MARGIN, DIALOG_ICON_TOP_MARGIN,
2695 DIALOG_ICON_LEFT_MARGIN + DIALOG_ICON_WIDTH,
2696 DIALOG_ICON_TOP_MARGIN + DIALOG_ICON_HEIGHT);
2697 err = CreateIconControl (window, &bounds, &content, true, &icon);
2698 ReleaseIconRef (content.u.iconRef);
2699 }
2700 }
2701
2702 /* Show the dialog window and run event loop. */
2703 if (err == noErr)
2704 if (default_button)
2705 err = SetWindowDefaultButton (window, default_button);
2706 if (err == noErr)
2707 err = install_dialog_event_handler (window);
2708 if (err == noErr)
2709 {
2710 SizeWindow (window,
2711 DIALOG_LEFT_MARGIN + inner_width + DIALOG_RIGHT_MARGIN,
2712 DIALOG_TOP_MARGIN + inner_height + DIALOG_BOTTOM_MARGIN,
2713 true);
2714 err = RepositionWindow (window, FRAME_MAC_WINDOW (f),
2715 kWindowAlertPositionOnParentWindow);
2716 }
2717 if (err == noErr)
2718 {
2719 SetWRefCon (window, 0);
2720 ShowWindow (window);
2721 BringToFront (window);
2722 popup_activated_flag = 1;
2723 err = BeginAppModalStateForWindow (window);
2724 }
2725 if (err == noErr)
2726 {
2727 EventTargetRef toolbox_dispatcher = GetEventDispatcherTarget ();
2728
2729 quit_dialog_event_loop = 0;
2730 while (1)
2731 {
2732 EMACS_TIME next_time = timer_check (1);
2733 long secs = EMACS_SECS (next_time);
2734 long usecs = EMACS_USECS (next_time);
2735 EventTimeout timeout;
2736 EventRef event;
2737
2738 if (secs < 0 || (secs == 0 && usecs == 0))
2739 {
2740 /* Sometimes timer_check returns -1 (no timers) even if
2741 there are timers. So do a timeout anyway. */
2742 secs = 1;
2743 usecs = 0;
2744 }
2745
2746 timeout = (secs * kEventDurationSecond
2747 + usecs * kEventDurationMicrosecond);
2748 err = ReceiveNextEvent (0, NULL, timeout, kEventRemoveFromQueue,
2749 &event);
2750 if (err == noErr)
2751 {
2752 SendEventToEventTarget (event, toolbox_dispatcher);
2753 ReleaseEvent (event);
2754 }
2755#if 0 /* defined (MAC_OSX) */
2756 else if (err != eventLoopTimedOutErr)
2757 {
2758 if (err == eventLoopQuitErr)
2759 err = noErr;
2760 break;
2761 }
2762#else
2763 /* The return value of ReceiveNextEvent seems to be
2764 unreliable. Use our own global variable instead. */
2765 if (quit_dialog_event_loop)
2766 {
2767 err = noErr;
2768 break;
2769 }
2770#endif
2771 }
2772 }
2773 if (err == noErr)
2774 {
2775 UInt32 command_id = GetWRefCon (window);
2776
2777 if (DIALOG_BUTTON_COMMAND_ID_P (command_id))
2778 result = DIALOG_BUTTON_COMMAND_ID_VALUE (command_id);
2779 }
2780
2781 unbind_to (specpdl_count, Qnil);
2782
2783 return result;
2784}
2785#else /* not TARGET_API_MAC_CARBON */
2786static int
2787mac_dialog (widget_value *wv)
2788{
2789 char *dialog_name;
2790 char *prompt;
2791 char **button_labels;
2792 UInt32 *ref_cons;
2793 int nb_buttons;
2794 int left_count;
2795 int i;
2796 int dialog_width;
2797 Rect rect;
2798 WindowRef window_ptr;
2799 ControlRef ch;
2800 int left;
2801 EventRecord event_record;
2802 SInt16 part_code;
2803 int control_part_code;
2804 Point mouse;
2805
2806 dialog_name = wv->name;
2807 nb_buttons = dialog_name[1] - '0';
2808 left_count = nb_buttons - (dialog_name[4] - '0');
2809 button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
2810 ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons);
2811
2812 wv = wv->contents;
2813 prompt = (char *) alloca (strlen (wv->value) + 1);
2814 strcpy (prompt, wv->value);
2815 c2pstr (prompt);
2816
2817 wv = wv->next;
2818 for (i = 0; i < nb_buttons; i++)
2819 {
2820 button_labels[i] = wv->value;
2821 button_labels[i] = (char *) alloca (strlen (wv->value) + 1);
2822 strcpy (button_labels[i], wv->value);
2823 c2pstr (button_labels[i]);
2824 ref_cons[i] = (UInt32) wv->call_data;
2825 wv = wv->next;
2826 }
2827
2828 window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowRef) -1);
2829
2830 SetPortWindowPort (window_ptr);
2831
2832 TextFont (0);
2833 /* Left and right margins in the dialog are 13 pixels each.*/
2834 dialog_width = 14;
2835 /* Calculate width of dialog box: 8 pixels on each side of the text
2836 label in each button, 12 pixels between buttons. */
2837 for (i = 0; i < nb_buttons; i++)
2838 dialog_width += StringWidth (button_labels[i]) + 16 + 12;
2839
2840 if (left_count != 0 && nb_buttons - left_count != 0)
2841 dialog_width += 12;
2842
2843 dialog_width = max (dialog_width, StringWidth (prompt) + 26);
2844
2845 SizeWindow (window_ptr, dialog_width, 78, 0);
2846 ShowWindow (window_ptr);
2847
2848 SetPortWindowPort (window_ptr);
2849
2850 TextFont (0);
2851
2852 MoveTo (13, 29);
2853 DrawString (prompt);
2854
2855 left = 13;
2856 for (i = 0; i < nb_buttons; i++)
2857 {
2858 int button_width = StringWidth (button_labels[i]) + 16;
2859 SetRect (&rect, left, 45, left + button_width, 65);
2860 ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0,
2861 kControlPushButtonProc, ref_cons[i]);
2862 left += button_width + 12;
2863 if (i == left_count - 1)
2864 left += 12;
2865 }
2866
2867 i = 0;
2868 while (!i)
2869 {
2870 if (WaitNextEvent (mDownMask, &event_record, 10, NULL))
2871 if (event_record.what == mouseDown)
2872 {
2873 part_code = FindWindow (event_record.where, &window_ptr);
2874 if (part_code == inContent)
2875 {
2876 mouse = event_record.where;
2877 GlobalToLocal (&mouse);
2878 control_part_code = FindControl (mouse, window_ptr, &ch);
2879 if (control_part_code == kControlButtonPart)
2880 if (TrackControl (ch, mouse, NULL))
2881 i = GetControlReference (ch);
2882 }
2883 }
2884 }
2885
2886 DisposeWindow (window_ptr);
2887
2888 return i;
2889}
2890#endif /* not TARGET_API_MAC_CARBON */
2891
2892static char * button_names [] = { 1849static char * button_names [] = {
2893 "button1", "button2", "button3", "button4", "button5", 1850 "button1", "button2", "button3", "button4", "button5",
2894 "button6", "button7", "button8", "button9", "button10" }; 1851 "button6", "button7", "button8", "button9", "button10" };
@@ -2902,7 +1859,6 @@ mac_dialog_show (f, keymaps, title, header, error_name)
2902{ 1859{
2903 int i, nb_buttons=0; 1860 int i, nb_buttons=0;
2904 char dialog_name[6]; 1861 char dialog_name[6];
2905 int menu_item_selection;
2906 1862
2907 widget_value *wv, *first_wv = 0, *prev_wv = 0; 1863 widget_value *wv, *first_wv = 0, *prev_wv = 0;
2908 1864
@@ -3019,6 +1975,9 @@ mac_dialog_show (f, keymaps, title, header, error_name)
3019 first_wv = wv; 1975 first_wv = wv;
3020 } 1976 }
3021 1977
1978 /* No selection has been chosen yet. */
1979 menu_item_selection = 0;
1980
3022 /* Force a redisplay before showing the dialog. If a frame is created 1981 /* Force a redisplay before showing the dialog. If a frame is created
3023 just before showing the dialog, its contents may not have been fully 1982 just before showing the dialog, its contents may not have been fully
3024 drawn. */ 1983 drawn. */
@@ -3026,7 +1985,7 @@ mac_dialog_show (f, keymaps, title, header, error_name)
3026 1985
3027 /* Actually create the dialog. */ 1986 /* Actually create the dialog. */
3028#if TARGET_API_MAC_CARBON 1987#if TARGET_API_MAC_CARBON
3029 menu_item_selection = create_and_show_dialog (f, first_wv); 1988 create_and_show_dialog (f, first_wv);
3030#else 1989#else
3031 menu_item_selection = mac_dialog (first_wv); 1990 menu_item_selection = mac_dialog (first_wv);
3032#endif 1991#endif
@@ -3086,7 +2045,7 @@ mac_dialog_show (f, keymaps, title, header, error_name)
3086 2045
3087 2046
3088/* Is this item a separator? */ 2047/* Is this item a separator? */
3089static int 2048int
3090name_is_separator (name) 2049name_is_separator (name)
3091 const char *name; 2050 const char *name;
3092{ 2051{
@@ -3099,260 +2058,6 @@ name_is_separator (name)
3099 them like normal separators. */ 2058 them like normal separators. */
3100 return (*name == '\0' || start + 2 == name); 2059 return (*name == '\0' || start + 2 == name);
3101} 2060}
3102
3103static void
3104add_menu_item (menu, pos, wv)
3105 MenuRef menu;
3106 int pos;
3107 widget_value *wv;
3108{
3109#if TARGET_API_MAC_CARBON
3110 CFStringRef item_name;
3111#else
3112 Str255 item_name;
3113#endif
3114
3115 if (name_is_separator (wv->name))
3116 AppendMenu (menu, "\p-");
3117 else
3118 {
3119 AppendMenu (menu, "\pX");
3120
3121#if TARGET_API_MAC_CARBON
3122 item_name = cfstring_create_with_utf8_cstring (wv->name);
3123
3124 if (wv->key != NULL)
3125 {
3126 CFStringRef name, key;
3127
3128 name = item_name;
3129 key = cfstring_create_with_utf8_cstring (wv->key);
3130 item_name = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@ %@"),
3131 name, key);
3132 CFRelease (name);
3133 CFRelease (key);
3134 }
3135
3136 SetMenuItemTextWithCFString (menu, pos, item_name);
3137 CFRelease (item_name);
3138
3139 if (wv->enabled)
3140 EnableMenuItem (menu, pos);
3141 else
3142 DisableMenuItem (menu, pos);
3143
3144 if (STRINGP (wv->help))
3145 SetMenuItemProperty (menu, pos, MAC_EMACS_CREATOR_CODE, 'help',
3146 sizeof (Lisp_Object), &wv->help);
3147#else /* ! TARGET_API_MAC_CARBON */
3148 item_name[sizeof (item_name) - 1] = '\0';
3149 strncpy (item_name, wv->name, sizeof (item_name) - 1);
3150 if (wv->key != NULL)
3151 {
3152 int len = strlen (item_name);
3153
3154 strncpy (item_name + len, " ", sizeof (item_name) - 1 - len);
3155 len = strlen (item_name);
3156 strncpy (item_name + len, wv->key, sizeof (item_name) - 1 - len);
3157 }
3158 c2pstr (item_name);
3159 SetMenuItemText (menu, pos, item_name);
3160
3161 if (wv->enabled)
3162 EnableItem (menu, pos);
3163 else
3164 DisableItem (menu, pos);
3165#endif /* ! TARGET_API_MAC_CARBON */
3166
3167 /* Draw radio buttons and tickboxes. */
3168 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE ||
3169 wv->button_type == BUTTON_TYPE_RADIO))
3170 SetItemMark (menu, pos, checkMark);
3171 else
3172 SetItemMark (menu, pos, noMark);
3173
3174 SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
3175 }
3176}
3177
3178/* Construct native Mac OS menu based on widget_value tree. */
3179
3180static int
3181fill_menu (menu, wv, kind, submenu_id)
3182 MenuRef menu;
3183 widget_value *wv;
3184 enum mac_menu_kind kind;
3185 int submenu_id;
3186{
3187 int pos;
3188
3189 for (pos = 1; wv != NULL; wv = wv->next, pos++)
3190 {
3191 add_menu_item (menu, pos, wv);
3192 if (wv->contents && submenu_id < min_menu_id[kind + 1])
3193 {
3194 MenuRef submenu = NewMenu (submenu_id, "\pX");
3195
3196 InsertMenu (submenu, -1);
3197#if TARGET_API_MAC_CARBON
3198 SetMenuItemHierarchicalMenu (menu, pos, submenu);
3199#else
3200 SetMenuItemHierarchicalID (menu, pos, submenu_id);
3201#endif
3202 submenu_id = fill_menu (submenu, wv->contents, kind, submenu_id + 1);
3203 }
3204 }
3205
3206 return submenu_id;
3207}
3208
3209/* Construct native Mac OS menubar based on widget_value tree. */
3210
3211static void
3212fill_menubar (wv, deep_p)
3213 widget_value *wv;
3214 int deep_p;
3215{
3216 int id, submenu_id;
3217#if !TARGET_API_MAC_CARBON
3218 int title_changed_p = 0;
3219#endif
3220
3221 /* Clean up the menu bar when filled by the entire menu trees. */
3222 if (deep_p)
3223 {
3224 dispose_menus (MAC_MENU_MENU_BAR, 0);
3225 dispose_menus (MAC_MENU_MENU_BAR_SUB, 0);
3226#if !TARGET_API_MAC_CARBON
3227 title_changed_p = 1;
3228#endif
3229 }
3230
3231 /* Fill menu bar titles and submenus. Reuse the existing menu bar
3232 titles as much as possible to minimize redraw (if !deep_p). */
3233 submenu_id = min_menu_id[MAC_MENU_MENU_BAR_SUB];
3234 for (id = min_menu_id[MAC_MENU_MENU_BAR];
3235 wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1];
3236 wv = wv->next, id++)
3237 {
3238 OSStatus err = noErr;
3239 MenuRef menu;
3240#if TARGET_API_MAC_CARBON
3241 CFStringRef title;
3242
3243 title = CFStringCreateWithCString (NULL, wv->name,
3244 kCFStringEncodingMacRoman);
3245#else
3246 Str255 title;
3247
3248 strncpy (title, wv->name, 255);
3249 title[255] = '\0';
3250 c2pstr (title);
3251#endif
3252
3253 menu = GetMenuRef (id);
3254 if (menu)
3255 {
3256#if TARGET_API_MAC_CARBON
3257 CFStringRef old_title;
3258
3259 err = CopyMenuTitleAsCFString (menu, &old_title);
3260 if (err == noErr)
3261 {
3262 if (CFStringCompare (title, old_title, 0) != kCFCompareEqualTo)
3263 {
3264#ifdef MAC_OSX
3265 if (id + 1 == min_menu_id[MAC_MENU_MENU_BAR + 1]
3266 || GetMenuRef (id + 1) == NULL)
3267 {
3268 /* This is a workaround for Mac OS X 10.5 where
3269 just calling SetMenuTitleWithCFString fails
3270 to change the title of the last (Help) menu
3271 in the menu bar. */
3272 DeleteMenu (id);
3273 DisposeMenu (menu);
3274 menu = NULL;
3275 }
3276 else
3277#endif /* MAC_OSX */
3278 err = SetMenuTitleWithCFString (menu, title);
3279 }
3280 CFRelease (old_title);
3281 }
3282 else
3283 err = SetMenuTitleWithCFString (menu, title);
3284#else /* !TARGET_API_MAC_CARBON */
3285 if (!EqualString (title, (*menu)->menuData, false, false))
3286 {
3287 DeleteMenu (id);
3288 DisposeMenu (menu);
3289 menu = NewMenu (id, title);
3290 InsertMenu (menu, GetMenuRef (id + 1) ? id + 1 : 0);
3291 title_changed_p = 1;
3292 }
3293#endif /* !TARGET_API_MAC_CARBON */
3294 }
3295
3296 if (!menu)
3297 {
3298#if TARGET_API_MAC_CARBON
3299 err = CreateNewMenu (id, 0, &menu);
3300 if (err == noErr)
3301 err = SetMenuTitleWithCFString (menu, title);
3302#else
3303 menu = NewMenu (id, title);
3304#endif
3305 if (err == noErr)
3306 {
3307 InsertMenu (menu, 0);
3308#if !TARGET_API_MAC_CARBON
3309 title_changed_p = 1;
3310#endif
3311 }
3312 }
3313#if TARGET_API_MAC_CARBON
3314 CFRelease (title);
3315#endif
3316
3317 if (err == noErr)
3318 if (wv->contents)
3319 submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
3320 submenu_id);
3321 }
3322
3323 if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuRef (id))
3324 {
3325 dispose_menus (MAC_MENU_MENU_BAR, id);
3326#if !TARGET_API_MAC_CARBON
3327 title_changed_p = 1;
3328#endif
3329 }
3330
3331#if !TARGET_API_MAC_CARBON
3332 if (title_changed_p)
3333 InvalMenuBar ();
3334#endif
3335}
3336
3337/* Dispose of menus that belong to KIND, and remove them from the menu
3338 list. ID is the lower bound of menu IDs that will be processed. */
3339
3340static void
3341dispose_menus (kind, id)
3342 enum mac_menu_kind kind;
3343 int id;
3344{
3345 for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++)
3346 {
3347 MenuRef menu = GetMenuRef (id);
3348
3349 if (menu == NULL)
3350 break;
3351 DeleteMenu (id);
3352 DisposeMenu (menu);
3353 }
3354}
3355
3356#endif /* HAVE_MENUS */ 2061#endif /* HAVE_MENUS */
3357 2062
3358/* Detect if a menu is currently active. */ 2063/* Detect if a menu is currently active. */
diff --git a/src/macselect.c b/src/macselect.c
index 51a30e3a6b5..f71dce14dae 100644
--- a/src/macselect.c
+++ b/src/macselect.c
@@ -25,38 +25,15 @@ Boston, MA 02110-1301, USA. */
25#include "blockinput.h" 25#include "blockinput.h"
26#include "keymap.h" 26#include "keymap.h"
27 27
28#if TARGET_API_MAC_CARBON 28#if !TARGET_API_MAC_CARBON
29typedef ScrapRef Selection;
30#else /* !TARGET_API_MAC_CARBON */
31#include <Scrap.h>
32#include <Endian.h> 29#include <Endian.h>
33typedef int Selection; 30#endif
34#endif /* !TARGET_API_MAC_CARBON */ 31
35
36static OSStatus mac_get_selection_from_symbol P_ ((Lisp_Object, int,
37 Selection *));
38static ScrapFlavorType get_flavor_type_from_symbol P_ ((Lisp_Object,
39 Selection));
40static int mac_valid_selection_target_p P_ ((Lisp_Object));
41static OSStatus mac_clear_selection P_ ((Selection *));
42static Lisp_Object mac_get_selection_ownership_info P_ ((Selection));
43static int mac_valid_selection_value_p P_ ((Lisp_Object, Lisp_Object));
44static OSStatus mac_put_selection_value P_ ((Selection, Lisp_Object,
45 Lisp_Object));
46static int mac_selection_has_target_p P_ ((Selection, Lisp_Object));
47static Lisp_Object mac_get_selection_value P_ ((Selection, Lisp_Object));
48static Lisp_Object mac_get_selection_target_list P_ ((Selection));
49static void x_own_selection P_ ((Lisp_Object, Lisp_Object)); 32static void x_own_selection P_ ((Lisp_Object, Lisp_Object));
50static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object, int)); 33static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object, int));
51static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object, 34static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object,
52 Lisp_Object, 35 Lisp_Object,
53 Lisp_Object)); 36 Lisp_Object));
54EXFUN (Fx_selection_owner_p, 1);
55#ifdef MAC_OSX
56static OSStatus mac_handle_service_event P_ ((EventHandlerCallRef,
57 EventRef, void *));
58void init_service_handler P_ ((void));
59#endif
60 37
61Lisp_Object QPRIMARY, QSECONDARY, QTIMESTAMP, QTARGETS; 38Lisp_Object QPRIMARY, QSECONDARY, QTIMESTAMP, QTARGETS;
62 39
@@ -98,302 +75,13 @@ static Lisp_Object Vselection_alist;
98 selection value to a string representing the given selection type. 75 selection value to a string representing the given selection type.
99 This is for Lisp-level extension of the emacs selection 76 This is for Lisp-level extension of the emacs selection
100 handling. */ 77 handling. */
101static Lisp_Object Vselection_converter_alist; 78Lisp_Object Vselection_converter_alist;
102 79
103/* A selection name (represented as a Lisp symbol) can be associated 80/* A selection name (represented as a Lisp symbol) can be associated
104 with a named scrap via `mac-scrap-name' property. Likewise for a 81 with a named scrap via `mac-scrap-name' property. Likewise for a
105 selection type with a scrap flavor type via `mac-ostype'. */ 82 selection type with a scrap flavor type via `mac-ostype'. */
106static Lisp_Object Qmac_scrap_name, Qmac_ostype; 83Lisp_Object Qmac_scrap_name, Qmac_ostype;
107
108#ifdef MAC_OSX
109/* Selection name for communication via Services menu. */
110static Lisp_Object Vmac_service_selection;
111#endif
112
113/* Get a reference to the selection corresponding to the symbol SYM.
114 The reference is set to *SEL, and it becomes NULL if there's no
115 corresponding selection. Clear the selection if CLEAR_P is
116 non-zero. */
117
118static OSStatus
119mac_get_selection_from_symbol (sym, clear_p, sel)
120 Lisp_Object sym;
121 int clear_p;
122 Selection *sel;
123{
124 OSStatus err = noErr;
125 Lisp_Object str = Fget (sym, Qmac_scrap_name);
126
127 if (!STRINGP (str))
128 *sel = NULL;
129 else
130 {
131#if TARGET_API_MAC_CARBON
132#ifdef MAC_OSX
133 CFStringRef scrap_name = cfstring_create_with_string (str);
134 OptionBits options = (clear_p ? kScrapClearNamedScrap
135 : kScrapGetNamedScrap);
136
137 err = GetScrapByName (scrap_name, options, sel);
138 CFRelease (scrap_name);
139#else /* !MAC_OSX */
140 if (clear_p)
141 err = ClearCurrentScrap ();
142 if (err == noErr)
143 err = GetCurrentScrap (sel);
144#endif /* !MAC_OSX */
145#else /* !TARGET_API_MAC_CARBON */
146 if (clear_p)
147 err = ZeroScrap ();
148 if (err == noErr)
149 *sel = 1;
150#endif /* !TARGET_API_MAC_CARBON */
151 }
152
153 return err;
154}
155
156/* Get a scrap flavor type from the symbol SYM. Return 0 if no
157 corresponding flavor type. If SEL is non-zero, the return value is
158 non-zero only when the SEL has the flavor type. */
159
160static ScrapFlavorType
161get_flavor_type_from_symbol (sym, sel)
162 Lisp_Object sym;
163 Selection sel;
164{
165 Lisp_Object str = Fget (sym, Qmac_ostype);
166 ScrapFlavorType flavor_type;
167
168 if (STRINGP (str) && SBYTES (str) == 4)
169 flavor_type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
170 else
171 flavor_type = 0;
172
173 if (flavor_type && sel)
174 {
175#if TARGET_API_MAC_CARBON
176 OSStatus err;
177 ScrapFlavorFlags flags;
178
179 err = GetScrapFlavorFlags (sel, flavor_type, &flags);
180 if (err != noErr)
181 flavor_type = 0;
182#else /* !TARGET_API_MAC_CARBON */
183 SInt32 size, offset;
184
185 size = GetScrap (NULL, flavor_type, &offset);
186 if (size < 0)
187 flavor_type = 0;
188#endif /* !TARGET_API_MAC_CARBON */
189 }
190
191 return flavor_type;
192}
193
194/* Check if the symbol SYM has a corresponding selection target type. */
195
196static int
197mac_valid_selection_target_p (sym)
198 Lisp_Object sym;
199{
200 return get_flavor_type_from_symbol (sym, 0) != 0;
201}
202
203/* Clear the selection whose reference is *SEL. */
204
205static OSStatus
206mac_clear_selection (sel)
207 Selection *sel;
208{
209#if TARGET_API_MAC_CARBON
210#ifdef MAC_OSX
211 return ClearScrap (sel);
212#else
213 OSStatus err;
214
215 err = ClearCurrentScrap ();
216 if (err == noErr)
217 err = GetCurrentScrap (sel);
218 return err;
219#endif
220#else /* !TARGET_API_MAC_CARBON */
221 return ZeroScrap ();
222#endif /* !TARGET_API_MAC_CARBON */
223}
224
225/* Get ownership information for SEL. Emacs can detect a change of
226 the ownership by comparing saved and current values of the
227 ownership information. */
228
229static Lisp_Object
230mac_get_selection_ownership_info (sel)
231 Selection sel;
232{
233#if TARGET_API_MAC_CARBON
234 return long_to_cons ((unsigned long) sel);
235#else /* !TARGET_API_MAC_CARBON */
236 ScrapStuffPtr scrap_info = InfoScrap ();
237
238 return make_number (scrap_info->scrapCount);
239#endif /* !TARGET_API_MAC_CARBON */
240}
241
242/* Return non-zero if VALUE is a valid selection value for TARGET. */
243
244static int
245mac_valid_selection_value_p (value, target)
246 Lisp_Object value, target;
247{
248 return STRINGP (value);
249}
250
251/* Put Lisp Object VALUE to the selection SEL. The target type is
252 specified by TARGET. */
253
254static OSStatus
255mac_put_selection_value (sel, target, value)
256 Selection sel;
257 Lisp_Object target, value;
258{
259 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, 0);
260
261 if (flavor_type == 0 || !STRINGP (value))
262 return noTypeErr;
263
264#if TARGET_API_MAC_CARBON
265 return PutScrapFlavor (sel, flavor_type, kScrapFlavorMaskNone,
266 SBYTES (value), SDATA (value));
267#else /* !TARGET_API_MAC_CARBON */
268 return PutScrap (SBYTES (value), flavor_type, SDATA (value));
269#endif /* !TARGET_API_MAC_CARBON */
270}
271 84
272/* Check if data for the target type TARGET is available in SEL. */
273
274static int
275mac_selection_has_target_p (sel, target)
276 Selection sel;
277 Lisp_Object target;
278{
279 return get_flavor_type_from_symbol (target, sel) != 0;
280}
281
282/* Get data for the target type TARGET from SEL and create a Lisp
283 string. Return nil if failed to get data. */
284
285static Lisp_Object
286mac_get_selection_value (sel, target)
287 Selection sel;
288 Lisp_Object target;
289{
290 OSStatus err;
291 Lisp_Object result = Qnil;
292 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, sel);
293#if TARGET_API_MAC_CARBON
294 Size size;
295
296 if (flavor_type)
297 {
298 err = GetScrapFlavorSize (sel, flavor_type, &size);
299 if (err == noErr)
300 {
301 do
302 {
303 result = make_uninit_string (size);
304 err = GetScrapFlavorData (sel, flavor_type,
305 &size, SDATA (result));
306 if (err != noErr)
307 result = Qnil;
308 else if (size < SBYTES (result))
309 result = make_unibyte_string (SDATA (result), size);
310 }
311 while (STRINGP (result) && size > SBYTES (result));
312 }
313 }
314#else
315 Handle handle;
316 SInt32 size, offset;
317
318 if (flavor_type)
319 size = GetScrap (NULL, flavor_type, &offset);
320 if (size >= 0)
321 {
322 handle = NewHandle (size);
323 HLock (handle);
324 size = GetScrap (handle, flavor_type, &offset);
325 if (size >= 0)
326 result = make_unibyte_string (*handle, size);
327 DisposeHandle (handle);
328 }
329#endif
330
331 return result;
332}
333
334/* Get the list of target types in SEL. The return value is a list of
335 target type symbols possibly followed by scrap flavor type
336 strings. */
337
338static Lisp_Object
339mac_get_selection_target_list (sel)
340 Selection sel;
341{
342 Lisp_Object result = Qnil, rest, target;
343#if TARGET_API_MAC_CARBON
344 OSStatus err;
345 UInt32 count, i, type;
346 ScrapFlavorInfo *flavor_info = NULL;
347 Lisp_Object strings = Qnil;
348
349 err = GetScrapFlavorCount (sel, &count);
350 if (err == noErr)
351 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
352 err = GetScrapFlavorInfoList (sel, &count, flavor_info);
353 if (err != noErr)
354 {
355 xfree (flavor_info);
356 flavor_info = NULL;
357 }
358 if (flavor_info == NULL)
359 count = 0;
360#endif
361 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
362 {
363 ScrapFlavorType flavor_type = 0;
364
365 if (CONSP (XCAR (rest))
366 && (target = XCAR (XCAR (rest)),
367 SYMBOLP (target))
368 && (flavor_type = get_flavor_type_from_symbol (target, sel)))
369 {
370 result = Fcons (target, result);
371#if TARGET_API_MAC_CARBON
372 for (i = 0; i < count; i++)
373 if (flavor_info[i].flavorType == flavor_type)
374 {
375 flavor_info[i].flavorType = 0;
376 break;
377 }
378#endif
379 }
380 }
381#if TARGET_API_MAC_CARBON
382 if (flavor_info)
383 {
384 for (i = 0; i < count; i++)
385 if (flavor_info[i].flavorType)
386 {
387 type = EndianU32_NtoB (flavor_info[i].flavorType);
388 strings = Fcons (make_unibyte_string ((char *) &type, 4), strings);
389 }
390 result = nconc2 (result, strings);
391 xfree (flavor_info);
392 }
393#endif
394
395 return result;
396}
397 85
398/* Do protocol to assert ourself as a selection owner. 86/* Do protocol to assert ourself as a selection owner.
399 Update the Vselection_alist so that we can reply to later requests for 87 Update the Vselection_alist so that we can reply to later requests for
@@ -892,8 +580,8 @@ and t is the same as `SECONDARY'. */)
892 Apple event support 580 Apple event support
893***********************************************************************/ 581***********************************************************************/
894int mac_ready_for_apple_events = 0; 582int mac_ready_for_apple_events = 0;
895static Lisp_Object Vmac_apple_event_map; 583Lisp_Object Vmac_apple_event_map;
896static Lisp_Object Qmac_apple_event_class, Qmac_apple_event_id; 584Lisp_Object Qmac_apple_event_class, Qmac_apple_event_id;
897static Lisp_Object Qemacs_suspension_id; 585static Lisp_Object Qemacs_suspension_id;
898extern Lisp_Object Qundefined; 586extern Lisp_Object Qundefined;
899extern void mac_store_apple_event P_ ((Lisp_Object, Lisp_Object, 587extern void mac_store_apple_event P_ ((Lisp_Object, Lisp_Object,
@@ -1095,7 +783,7 @@ mac_handle_apple_event_1 (class, id, apple_event, reply)
1095 return err; 783 return err;
1096} 784}
1097 785
1098static pascal OSErr 786pascal OSErr
1099mac_handle_apple_event (apple_event, reply, refcon) 787mac_handle_apple_event (apple_event, reply, refcon)
1100 const AppleEvent *apple_event; 788 const AppleEvent *apple_event;
1101 AppleEvent *reply; 789 AppleEvent *reply;
@@ -1173,40 +861,13 @@ cleanup_suspended_apple_events (head, all_p)
1173 return nresumed; 861 return nresumed;
1174} 862}
1175 863
1176static void 864void
1177cleanup_all_suspended_apple_events () 865cleanup_all_suspended_apple_events ()
1178{ 866{
1179 cleanup_suspended_apple_events (&deferred_apple_events, 1); 867 cleanup_suspended_apple_events (&deferred_apple_events, 1);
1180 cleanup_suspended_apple_events (&suspended_apple_events, 1); 868 cleanup_suspended_apple_events (&suspended_apple_events, 1);
1181} 869}
1182 870
1183void
1184init_apple_event_handler ()
1185{
1186 OSErr err;
1187 long result;
1188
1189 /* Make sure we have Apple events before starting. */
1190 err = Gestalt (gestaltAppleEventsAttr, &result);
1191 if (err != noErr)
1192 abort ();
1193
1194 if (!(result & (1 << gestaltAppleEventsPresent)))
1195 abort ();
1196
1197 err = AEInstallEventHandler (typeWildCard, typeWildCard,
1198#if TARGET_API_MAC_CARBON
1199 NewAEEventHandlerUPP (mac_handle_apple_event),
1200#else
1201 NewAEEventHandlerProc (mac_handle_apple_event),
1202#endif
1203 0L, false);
1204 if (err != noErr)
1205 abort ();
1206
1207 atexit (cleanup_all_suspended_apple_events);
1208}
1209
1210static UInt32 871static UInt32
1211get_suspension_id (apple_event) 872get_suspension_id (apple_event)
1212 Lisp_Object apple_event; 873 Lisp_Object apple_event;
@@ -1399,419 +1060,18 @@ nil, which means the event is already resumed or expired. */)
1399 Drag and drop support 1060 Drag and drop support
1400***********************************************************************/ 1061***********************************************************************/
1401#if TARGET_API_MAC_CARBON 1062#if TARGET_API_MAC_CARBON
1402static Lisp_Object Vmac_dnd_known_types; 1063Lisp_Object Vmac_dnd_known_types;
1403static pascal OSErr mac_do_track_drag P_ ((DragTrackingMessage, WindowRef,
1404 void *, DragRef));
1405static pascal OSErr mac_do_receive_drag P_ ((WindowRef, void *, DragRef));
1406static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL;
1407static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL;
1408
1409extern void mac_store_drag_event P_ ((WindowRef, Point, SInt16,
1410 const AEDesc *));
1411
1412static pascal OSErr
1413mac_do_track_drag (message, window, refcon, drag)
1414 DragTrackingMessage message;
1415 WindowRef window;
1416 void *refcon;
1417 DragRef drag;
1418{
1419 OSErr err = noErr;
1420 static int can_accept;
1421 UInt16 num_items, index;
1422
1423 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
1424 return dragNotAcceptedErr;
1425
1426 switch (message)
1427 {
1428 case kDragTrackingEnterHandler:
1429 err = CountDragItems (drag, &num_items);
1430 if (err != noErr)
1431 break;
1432 can_accept = 0;
1433 for (index = 1; index <= num_items; index++)
1434 {
1435 ItemReference item;
1436 FlavorFlags flags;
1437 Lisp_Object rest;
1438
1439 err = GetDragItemReferenceNumber (drag, index, &item);
1440 if (err != noErr)
1441 continue;
1442 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
1443 {
1444 Lisp_Object str;
1445 FlavorType type;
1446
1447 str = XCAR (rest);
1448 if (!(STRINGP (str) && SBYTES (str) == 4))
1449 continue;
1450 type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
1451
1452 err = GetFlavorFlags (drag, item, type, &flags);
1453 if (err == noErr)
1454 {
1455 can_accept = 1;
1456 break;
1457 }
1458 }
1459 }
1460 break;
1461
1462 case kDragTrackingEnterWindow:
1463 if (can_accept)
1464 {
1465 RgnHandle hilite_rgn = NewRgn ();
1466
1467 if (hilite_rgn)
1468 {
1469 Rect r;
1470
1471 GetWindowPortBounds (window, &r);
1472 OffsetRect (&r, -r.left, -r.top);
1473 RectRgn (hilite_rgn, &r);
1474 ShowDragHilite (drag, hilite_rgn, true);
1475 DisposeRgn (hilite_rgn);
1476 }
1477 SetThemeCursor (kThemeCopyArrowCursor);
1478 }
1479 break;
1480
1481 case kDragTrackingInWindow:
1482 break;
1483
1484 case kDragTrackingLeaveWindow:
1485 if (can_accept)
1486 {
1487 HideDragHilite (drag);
1488 SetThemeCursor (kThemeArrowCursor);
1489 }
1490 break;
1491
1492 case kDragTrackingLeaveHandler:
1493 break;
1494 }
1495
1496 if (err != noErr)
1497 return dragNotAcceptedErr;
1498 return noErr;
1499}
1500
1501static pascal OSErr
1502mac_do_receive_drag (window, refcon, drag)
1503 WindowRef window;
1504 void *refcon;
1505 DragRef drag;
1506{
1507 OSErr err;
1508 int num_types, i;
1509 Lisp_Object rest, str;
1510 FlavorType *types;
1511 AppleEvent apple_event;
1512 Point mouse_pos;
1513 SInt16 modifiers;
1514
1515 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
1516 return dragNotAcceptedErr;
1517
1518 num_types = 0;
1519 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
1520 {
1521 str = XCAR (rest);
1522 if (STRINGP (str) && SBYTES (str) == 4)
1523 num_types++;
1524 }
1525
1526 types = xmalloc (sizeof (FlavorType) * num_types);
1527 i = 0;
1528 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
1529 {
1530 str = XCAR (rest);
1531 if (STRINGP (str) && SBYTES (str) == 4)
1532 types[i++] = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
1533 }
1534
1535 err = create_apple_event_from_drag_ref (drag, num_types, types,
1536 &apple_event);
1537 xfree (types);
1538
1539 if (err == noErr)
1540 err = GetDragMouse (drag, &mouse_pos, NULL);
1541 if (err == noErr)
1542 {
1543 GlobalToLocal (&mouse_pos);
1544 err = GetDragModifiers (drag, NULL, NULL, &modifiers);
1545 }
1546 if (err == noErr)
1547 {
1548 UInt32 key_modifiers = modifiers;
1549
1550 err = AEPutParamPtr (&apple_event, kEventParamKeyModifiers,
1551 typeUInt32, &key_modifiers, sizeof (UInt32));
1552 }
1553
1554 if (err == noErr)
1555 {
1556 mac_store_drag_event (window, mouse_pos, 0, &apple_event);
1557 AEDisposeDesc (&apple_event);
1558 mac_wakeup_from_rne ();
1559 return noErr;
1560 }
1561 else
1562 return dragNotAcceptedErr;
1563}
1564#endif /* TARGET_API_MAC_CARBON */ 1064#endif /* TARGET_API_MAC_CARBON */
1565 1065
1566OSErr
1567install_drag_handler (window)
1568 WindowRef window;
1569{
1570 OSErr err = noErr;
1571
1572#if TARGET_API_MAC_CARBON
1573 if (mac_do_track_dragUPP == NULL)
1574 mac_do_track_dragUPP = NewDragTrackingHandlerUPP (mac_do_track_drag);
1575 if (mac_do_receive_dragUPP == NULL)
1576 mac_do_receive_dragUPP = NewDragReceiveHandlerUPP (mac_do_receive_drag);
1577
1578 err = InstallTrackingHandler (mac_do_track_dragUPP, window, NULL);
1579 if (err == noErr)
1580 err = InstallReceiveHandler (mac_do_receive_dragUPP, window, NULL);
1581#endif
1582
1583 return err;
1584}
1585
1586void
1587remove_drag_handler (window)
1588 WindowRef window;
1589{
1590#if TARGET_API_MAC_CARBON
1591 if (mac_do_track_dragUPP)
1592 RemoveTrackingHandler (mac_do_track_dragUPP, window);
1593 if (mac_do_receive_dragUPP)
1594 RemoveReceiveHandler (mac_do_receive_dragUPP, window);
1595#endif
1596}
1597
1598 1066
1599/*********************************************************************** 1067/***********************************************************************
1600 Services menu support 1068 Services menu support
1601***********************************************************************/ 1069***********************************************************************/
1602#ifdef MAC_OSX 1070#ifdef MAC_OSX
1603OSStatus 1071/* Selection name for communication via Services menu. */
1604install_service_handler () 1072Lisp_Object Vmac_service_selection;
1605{
1606 static const EventTypeSpec specs[] =
1607 {{kEventClassService, kEventServiceGetTypes},
1608 {kEventClassService, kEventServiceCopy},
1609 {kEventClassService, kEventServicePaste},
1610 {kEventClassService, kEventServicePerform}};
1611
1612 return InstallApplicationEventHandler (NewEventHandlerUPP
1613 (mac_handle_service_event),
1614 GetEventTypeCount (specs),
1615 specs, NULL, NULL);
1616}
1617
1618extern OSStatus mac_store_service_event P_ ((EventRef));
1619
1620static OSStatus
1621copy_scrap_flavor_data (from_scrap, to_scrap, flavor_type)
1622 ScrapRef from_scrap, to_scrap;
1623 ScrapFlavorType flavor_type;
1624{
1625 OSStatus err;
1626 Size size, size_allocated;
1627 char *buf = NULL;
1628
1629 err = GetScrapFlavorSize (from_scrap, flavor_type, &size);
1630 if (err == noErr)
1631 buf = xmalloc (size);
1632 while (buf)
1633 {
1634 size_allocated = size;
1635 err = GetScrapFlavorData (from_scrap, flavor_type, &size, buf);
1636 if (err != noErr)
1637 {
1638 xfree (buf);
1639 buf = NULL;
1640 }
1641 else if (size_allocated < size)
1642 buf = xrealloc (buf, size);
1643 else
1644 break;
1645 }
1646 if (err == noErr)
1647 {
1648 if (buf == NULL)
1649 err = memFullErr;
1650 else
1651 {
1652 err = PutScrapFlavor (to_scrap, flavor_type, kScrapFlavorMaskNone,
1653 size, buf);
1654 xfree (buf);
1655 }
1656 }
1657
1658 return err;
1659}
1660
1661static OSStatus
1662mac_handle_service_event (call_ref, event, data)
1663 EventHandlerCallRef call_ref;
1664 EventRef event;
1665 void *data;
1666{
1667 OSStatus err = noErr;
1668 ScrapRef cur_scrap, specific_scrap;
1669 UInt32 event_kind = GetEventKind (event);
1670 CFMutableArrayRef copy_types, paste_types;
1671 CFStringRef type;
1672 Lisp_Object rest;
1673 ScrapFlavorType flavor_type;
1674
1675 /* Check if Vmac_service_selection is a valid selection that has a
1676 corresponding scrap. */
1677 if (!SYMBOLP (Vmac_service_selection))
1678 err = eventNotHandledErr;
1679 else
1680 err = mac_get_selection_from_symbol (Vmac_service_selection, 0, &cur_scrap);
1681 if (!(err == noErr && cur_scrap))
1682 return eventNotHandledErr;
1683
1684 switch (event_kind)
1685 {
1686 case kEventServiceGetTypes:
1687 /* Set paste types. */
1688 err = GetEventParameter (event, kEventParamServicePasteTypes,
1689 typeCFMutableArrayRef, NULL,
1690 sizeof (CFMutableArrayRef), NULL,
1691 &paste_types);
1692 if (err != noErr)
1693 break;
1694
1695 for (rest = Vselection_converter_alist; CONSP (rest);
1696 rest = XCDR (rest))
1697 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
1698 && (flavor_type =
1699 get_flavor_type_from_symbol (XCAR (XCAR (rest)), 0)))
1700 {
1701 type = CreateTypeStringWithOSType (flavor_type);
1702 if (type)
1703 {
1704 CFArrayAppendValue (paste_types, type);
1705 CFRelease (type);
1706 }
1707 }
1708
1709 /* Set copy types. */
1710 err = GetEventParameter (event, kEventParamServiceCopyTypes,
1711 typeCFMutableArrayRef, NULL,
1712 sizeof (CFMutableArrayRef), NULL,
1713 &copy_types);
1714 if (err != noErr)
1715 break;
1716
1717 if (NILP (Fx_selection_owner_p (Vmac_service_selection)))
1718 break;
1719 else
1720 goto copy_all_flavors;
1721
1722 case kEventServiceCopy:
1723 err = GetEventParameter (event, kEventParamScrapRef,
1724 typeScrapRef, NULL,
1725 sizeof (ScrapRef), NULL, &specific_scrap);
1726 if (err != noErr
1727 || NILP (Fx_selection_owner_p (Vmac_service_selection)))
1728 {
1729 err = eventNotHandledErr;
1730 break;
1731 }
1732
1733 copy_all_flavors:
1734 {
1735 UInt32 count, i;
1736 ScrapFlavorInfo *flavor_info = NULL;
1737 ScrapFlavorFlags flags;
1738
1739 err = GetScrapFlavorCount (cur_scrap, &count);
1740 if (err == noErr)
1741 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
1742 err = GetScrapFlavorInfoList (cur_scrap, &count, flavor_info);
1743 if (err != noErr)
1744 {
1745 xfree (flavor_info);
1746 flavor_info = NULL;
1747 }
1748 if (flavor_info == NULL)
1749 break;
1750
1751 for (i = 0; i < count; i++)
1752 {
1753 flavor_type = flavor_info[i].flavorType;
1754 err = GetScrapFlavorFlags (cur_scrap, flavor_type, &flags);
1755 if (err == noErr && !(flags & kScrapFlavorMaskSenderOnly))
1756 {
1757 if (event_kind == kEventServiceCopy)
1758 err = copy_scrap_flavor_data (cur_scrap, specific_scrap,
1759 flavor_type);
1760 else /* event_kind == kEventServiceGetTypes */
1761 {
1762 type = CreateTypeStringWithOSType (flavor_type);
1763 if (type)
1764 {
1765 CFArrayAppendValue (copy_types, type);
1766 CFRelease (type);
1767 }
1768 }
1769 }
1770 }
1771 xfree (flavor_info);
1772 }
1773 break;
1774
1775 case kEventServicePaste:
1776 case kEventServicePerform:
1777 {
1778 int data_exists_p = 0;
1779
1780 err = GetEventParameter (event, kEventParamScrapRef, typeScrapRef,
1781 NULL, sizeof (ScrapRef), NULL,
1782 &specific_scrap);
1783 if (err == noErr)
1784 err = mac_clear_selection (&cur_scrap);
1785 if (err == noErr)
1786 for (rest = Vselection_converter_alist; CONSP (rest);
1787 rest = XCDR (rest))
1788 {
1789 if (! (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))))
1790 continue;
1791 flavor_type = get_flavor_type_from_symbol (XCAR (XCAR (rest)),
1792 specific_scrap);
1793 if (flavor_type == 0)
1794 continue;
1795 err = copy_scrap_flavor_data (specific_scrap, cur_scrap,
1796 flavor_type);
1797 if (err == noErr)
1798 data_exists_p = 1;
1799 }
1800 if (!data_exists_p)
1801 err = eventNotHandledErr;
1802 else
1803 err = mac_store_service_event (event);
1804 }
1805 break;
1806 }
1807
1808 if (err != noErr)
1809 err = eventNotHandledErr;
1810 return err;
1811}
1812#endif 1073#endif
1813 1074
1814
1815void 1075void
1816syms_of_macselect () 1076syms_of_macselect ()
1817{ 1077{
@@ -1870,11 +1130,7 @@ set to nil. */);
1870 DEFVAR_LISP ("mac-dnd-known-types", &Vmac_dnd_known_types, 1130 DEFVAR_LISP ("mac-dnd-known-types", &Vmac_dnd_known_types,
1871 doc: /* The types accepted by default for dropped data. 1131 doc: /* The types accepted by default for dropped data.
1872The types are chosen in the order they appear in the list. */); 1132The types are chosen in the order they appear in the list. */);
1873 Vmac_dnd_known_types = list4 (build_string ("hfs "), build_string ("utxt"), 1133 Vmac_dnd_known_types = mac_dnd_default_known_types ();
1874 build_string ("TEXT"), build_string ("TIFF"));
1875#ifdef MAC_OSX
1876 Vmac_dnd_known_types = Fcons (build_string ("furl"), Vmac_dnd_known_types);
1877#endif
1878#endif 1134#endif
1879 1135
1880#ifdef MAC_OSX 1136#ifdef MAC_OSX
diff --git a/src/macterm.h b/src/macterm.h
index 1e0ffbab263..0a448484873 100644
--- a/src/macterm.h
+++ b/src/macterm.h
@@ -376,12 +376,6 @@ typedef struct mac_output mac_output;
376/* This is the 'font_info *' which frame F has. */ 376/* This is the 'font_info *' which frame F has. */
377#define FRAME_MAC_FONT_TABLE(f) (FRAME_MAC_DISPLAY_INFO (f)->font_table) 377#define FRAME_MAC_FONT_TABLE(f) (FRAME_MAC_DISPLAY_INFO (f)->font_table)
378 378
379/* The difference in pixels between the top left corner of the
380 Emacs window (including possible window manager decorations)
381 and FRAME_MAC_WINDOW (f). */
382#define FRAME_OUTER_TO_INNER_DIFF_X(f) ((f)->x_pixels_diff)
383#define FRAME_OUTER_TO_INNER_DIFF_Y(f) ((f)->y_pixels_diff)
384
385/* Value is the smallest width of any character in any font on frame F. */ 379/* Value is the smallest width of any character in any font on frame F. */
386 380
387#define FRAME_SMALLEST_CHAR_WIDTH(F) \ 381#define FRAME_SMALLEST_CHAR_WIDTH(F) \
@@ -549,8 +543,8 @@ struct scroll_bar {
549#define MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH (11) 543#define MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH (11)
550 544
551/* Size of hourglass controls */ 545/* Size of hourglass controls */
552#define HOURGLASS_WIDTH (16) 546#define HOURGLASS_WIDTH (15)
553#define HOURGLASS_HEIGHT (16) 547#define HOURGLASS_HEIGHT (15)
554 548
555/* Some constants that are used locally. */ 549/* Some constants that are used locally. */
556/* Creator code for Emacs on Mac OS. */ 550/* Creator code for Emacs on Mac OS. */
@@ -624,6 +618,8 @@ extern int XParseGeometry P_ ((char *, int *, int *, unsigned int *,
624extern void x_set_window_size P_ ((struct frame *, int, int, int)); 618extern void x_set_window_size P_ ((struct frame *, int, int, int));
625extern void x_set_mouse_position P_ ((struct frame *, int, int)); 619extern void x_set_mouse_position P_ ((struct frame *, int, int));
626extern void x_set_mouse_pixel_position P_ ((struct frame *, int, int)); 620extern void x_set_mouse_pixel_position P_ ((struct frame *, int, int));
621extern void x_raise_frame P_ ((struct frame *));
622extern void x_lower_frame P_ ((struct frame *));
627extern void x_make_frame_visible P_ ((struct frame *)); 623extern void x_make_frame_visible P_ ((struct frame *));
628extern void x_make_frame_invisible P_ ((struct frame *)); 624extern void x_make_frame_invisible P_ ((struct frame *));
629extern void x_iconify_frame P_ ((struct frame *)); 625extern void x_iconify_frame P_ ((struct frame *));
@@ -643,29 +639,12 @@ extern GC XCreateGC P_ ((Display *, void *, unsigned long, XGCValues *));
643extern void XFreeGC P_ ((Display *, GC)); 639extern void XFreeGC P_ ((Display *, GC));
644extern void XSetForeground P_ ((Display *, GC, unsigned long)); 640extern void XSetForeground P_ ((Display *, GC, unsigned long));
645extern void XSetBackground P_ ((Display *, GC, unsigned long)); 641extern void XSetBackground P_ ((Display *, GC, unsigned long));
646extern void XSetWindowBackground P_ ((Display *, WindowRef, unsigned long));
647extern void XDrawLine P_ ((Display *, Pixmap, GC, int, int, int, int)); 642extern void XDrawLine P_ ((Display *, Pixmap, GC, int, int, int, int));
648extern void mac_clear_area P_ ((struct frame *, int, int, 643extern void mac_clear_area P_ ((struct frame *, int, int,
649 unsigned int, unsigned int)); 644 unsigned int, unsigned int));
650extern void mac_unload_font P_ ((struct mac_display_info *, XFontStruct *)); 645extern void mac_unload_font P_ ((struct mac_display_info *, XFontStruct *));
651extern int mac_font_panel_visible_p P_ ((void));
652extern OSStatus mac_show_hide_font_panel P_ ((void));
653extern OSStatus mac_set_font_info_for_selection P_ ((struct frame *, int, int));
654extern OSStatus install_window_handler P_ ((WindowRef));
655extern void remove_window_handler P_ ((WindowRef));
656extern OSStatus mac_post_mouse_moved_event P_ ((void)); 646extern OSStatus mac_post_mouse_moved_event P_ ((void));
657#if !TARGET_API_MAC_CARBON
658extern void do_apple_menu P_ ((SInt16));
659#endif
660#if USE_CG_DRAWING
661extern void mac_prepare_for_quickdraw P_ ((struct frame *));
662#endif
663extern void mac_get_window_bounds P_ ((struct frame *, Rect *, Rect *));
664extern int mac_quit_char_key_p P_ ((UInt32, UInt32)); 647extern int mac_quit_char_key_p P_ ((UInt32, UInt32));
665#if USE_MAC_TOOLBAR
666extern void update_frame_tool_bar P_ ((FRAME_PTR f));
667extern void free_frame_tool_bar P_ ((FRAME_PTR f));
668#endif
669 648
670#define FONT_TYPE_FOR_UNIBYTE(font, ch) 0 649#define FONT_TYPE_FOR_UNIBYTE(font, ch) 0
671#define FONT_TYPE_FOR_MULTIBYTE(font, ch) 0 650#define FONT_TYPE_FOR_MULTIBYTE(font, ch) 0
@@ -673,6 +652,7 @@ extern void free_frame_tool_bar P_ ((FRAME_PTR f));
673/* Defined in macselect.c */ 652/* Defined in macselect.c */
674 653
675extern void x_clear_frame_selections P_ ((struct frame *)); 654extern void x_clear_frame_selections P_ ((struct frame *));
655EXFUN (Fx_selection_owner_p, 1);
676 656
677/* Defined in macfns.c */ 657/* Defined in macfns.c */
678 658
@@ -687,11 +667,6 @@ extern void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object))
687extern void mac_update_title_bar P_ ((struct frame *, int)); 667extern void mac_update_title_bar P_ ((struct frame *, int));
688extern Lisp_Object x_get_focus_frame P_ ((struct frame *)); 668extern Lisp_Object x_get_focus_frame P_ ((struct frame *));
689 669
690/* Defined in macmenu.c */
691
692extern void x_activate_menubar P_ ((struct frame *));
693extern void free_frame_menubar P_ ((struct frame *));
694
695/* Defined in mac.c. */ 670/* Defined in mac.c. */
696 671
697extern void mac_clear_font_name_table P_ ((void)); 672extern void mac_clear_font_name_table P_ ((void));
@@ -723,5 +698,86 @@ extern Lisp_Object xrm_get_resource P_ ((XrmDatabase, const char *,
723extern XrmDatabase xrm_get_preference_database P_ ((const char *)); 698extern XrmDatabase xrm_get_preference_database P_ ((const char *));
724EXFUN (Fmac_get_preference, 4); 699EXFUN (Fmac_get_preference, 4);
725 700
701/* Defined in mactoolbox.c. */
702
703extern void mac_alert_sound_play P_ ((void));
704extern OSStatus install_application_handler P_ ((void));
705extern void mac_get_window_bounds P_ ((struct frame *, Rect *, Rect *));
706extern Rect *mac_get_frame_bounds P_ ((struct frame *, Rect *));
707extern void mac_get_frame_mouse P_ ((struct frame *, Point *));
708extern void mac_convert_frame_point_to_global P_ ((struct frame *, int *,
709 int *));
710#if TARGET_API_MAC_CARBON
711extern void mac_update_proxy_icon P_ ((struct frame *));
712#endif
713extern void mac_set_frame_window_background P_ ((struct frame *,
714 unsigned long));
715extern void mac_update_begin P_ ((struct frame *));
716extern void mac_update_end P_ ((struct frame *));
717extern void mac_frame_up_to_date P_ ((struct frame *));
718extern void x_flush P_ ((struct frame *));
719extern void mac_create_frame_window P_ ((struct frame *, int));
720extern void mac_dispose_frame_window P_ ((struct frame *));
721#if USE_CG_DRAWING
722extern CGContextRef mac_begin_cg_clip P_ ((struct frame *, GC));
723extern void mac_end_cg_clip P_ ((struct frame *));
724#endif
725extern void mac_begin_clip P_ ((struct frame *, GC));
726extern void mac_end_clip P_ ((struct frame *, GC));
727extern void mac_create_scroll_bar P_ ((struct scroll_bar *, const Rect *,
728 Boolean));
729extern void mac_dispose_scroll_bar P_ ((struct scroll_bar *));
730extern void mac_set_scroll_bar_bounds P_ ((struct scroll_bar *, const Rect *));
731extern void mac_redraw_scroll_bar P_ ((struct scroll_bar *));
732#ifdef USE_TOOLKIT_SCROLL_BARS
733extern void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
734 int, int, int));
735#else
736extern void x_scroll_bar_set_handle P_ ((scroll_bar *, int, int, int));
737#endif
738#if USE_MAC_FONT_PANEL
739extern int mac_font_panel_visible_p P_ ((void));
740extern OSStatus mac_show_hide_font_panel P_ ((void));
741extern OSStatus mac_set_font_info_for_selection P_ ((struct frame *, int, int));
742#endif
743#ifdef MAC_OSX
744extern Boolean mac_run_loop_run_once P_ ((EventTimeout));
745#endif
746#if USE_MAC_TOOLBAR
747extern void update_frame_tool_bar P_ ((FRAME_PTR f));
748extern void free_frame_tool_bar P_ ((FRAME_PTR f));
749#endif
750#if TARGET_API_MAC_CARBON
751extern void mac_show_hourglass P_ ((struct frame *));
752extern void mac_hide_hourglass P_ ((struct frame *));
753extern void mac_reposition_hourglass P_ ((struct frame *));
754extern Lisp_Object mac_file_dialog P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
755 Lisp_Object, Lisp_Object));
756#endif
757extern void x_activate_menubar P_ ((struct frame *));
758extern void free_frame_menubar P_ ((struct frame *));
759extern void mac_fill_menubar P_ ((widget_value *, int));
760extern void create_and_show_popup_menu P_ ((FRAME_PTR, widget_value *,
761 int, int, int));
762#if TARGET_API_MAC_CARBON
763extern void create_and_show_dialog P_ ((FRAME_PTR, widget_value *));
764#else
765extern int mac_dialog P_ ((widget_value *));
766#endif
767extern OSStatus mac_get_selection_from_symbol P_ ((Lisp_Object, int,
768 Selection *));
769extern int mac_valid_selection_target_p P_ ((Lisp_Object));
770extern OSStatus mac_clear_selection P_ ((Selection *));
771extern Lisp_Object mac_get_selection_ownership_info P_ ((Selection));
772extern int mac_valid_selection_value_p P_ ((Lisp_Object, Lisp_Object));
773extern OSStatus mac_put_selection_value P_ ((Selection, Lisp_Object,
774 Lisp_Object));
775extern int mac_selection_has_target_p P_ ((Selection, Lisp_Object));
776extern Lisp_Object mac_get_selection_value P_ ((Selection, Lisp_Object));
777extern Lisp_Object mac_get_selection_target_list P_ ((Selection));
778#if TARGET_API_MAC_CARBON
779extern Lisp_Object mac_dnd_default_known_types P_ ((void));
780#endif
781
726/* arch-tag: 6b4ca125-5bef-476d-8ee8-31ed808b7e79 782/* arch-tag: 6b4ca125-5bef-476d-8ee8-31ed808b7e79
727 (do not change this comment) */ 783 (do not change this comment) */
diff --git a/src/mactoolbox.c b/src/mactoolbox.c
new file mode 100644
index 00000000000..6b4d22049a9
--- /dev/null
+++ b/src/mactoolbox.c
@@ -0,0 +1,6211 @@
1/* Functions for GUI implemented with (HI)Toolbox on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA. */
21
22#include <config.h>
23
24#include <stdio.h>
25
26#include "lisp.h"
27#include "blockinput.h"
28
29#include "macterm.h"
30
31#if !TARGET_API_MAC_CARBON
32#include <Quickdraw.h>
33#include <ToolUtils.h>
34#include <Sound.h>
35#include <Events.h>
36#include <Script.h>
37#include <Resources.h>
38#include <Fonts.h>
39#include <TextUtils.h>
40#include <LowMem.h>
41#include <Controls.h>
42#include <Windows.h>
43#include <Displays.h>
44#if defined (__MRC__) || (__MSL__ >= 0x6000)
45#include <ControlDefinitions.h>
46#endif
47
48#if __profile__
49#include <profiler.h>
50#endif
51#endif /* not TARGET_API_MAC_CARBON */
52
53#include "charset.h"
54#include "coding.h"
55#include "frame.h"
56#include "dispextern.h"
57#include "fontset.h"
58#include "termhooks.h"
59#include "buffer.h"
60#include "window.h"
61#include "keyboard.h"
62
63#include <sys/param.h>
64
65#ifndef MAC_OSX
66#include <alloca.h>
67#endif
68
69
70/************************************************************************
71 General
72 ************************************************************************/
73
74/* The difference in pixels between the top left corner of the
75 Emacs window (including possible window manager decorations)
76 and FRAME_MAC_WINDOW (f). */
77#define FRAME_OUTER_TO_INNER_DIFF_X(f) ((f)->x_pixels_diff)
78#define FRAME_OUTER_TO_INNER_DIFF_Y(f) ((f)->y_pixels_diff)
79
80#define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP)
81
82void
83mac_alert_sound_play ()
84{
85#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
86 AlertSoundPlay ();
87#else
88 SysBeep (1);
89#endif
90}
91
92
93/************************************************************************
94 Application
95 ************************************************************************/
96
97extern struct frame *mac_focus_frame P_ ((struct mac_display_info *));
98extern void do_keystroke P_ ((EventKind, unsigned char, UInt32, UInt32,
99 unsigned long, struct input_event *));
100extern UInt32 mac_mapped_modifiers P_ ((UInt32, UInt32));
101#if TARGET_API_MAC_CARBON
102extern int mac_to_emacs_modifiers P_ ((UInt32, UInt32));
103#else
104extern int mac_to_emacs_modifiers P_ ((EventModifiers, EventModifiers));
105#endif
106
107#if TARGET_API_MAC_CARBON
108/* Points to the variable `inev' in the function XTread_socket. It is
109 used for passing an input event to the function back from
110 Carbon/Apple event handlers. */
111static struct input_event *read_socket_inev = NULL;
112
113extern const unsigned char keycode_to_xkeysym_table[];
114extern EMACS_INT extra_keyboard_modifiers;
115
116extern Lisp_Object Qhi_command;
117#if USE_MAC_TSM
118static TSMDocumentID tsm_document_id;
119extern Lisp_Object Qtext_input;
120extern Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
121extern Lisp_Object Vmac_ts_active_input_overlay;
122extern Lisp_Object Qbefore_string;
123extern Lisp_Object Vmac_ts_script_language_on_focus;
124extern Lisp_Object saved_ts_script_language_on_focus;
125#endif
126
127static int mac_event_to_emacs_modifiers P_ ((EventRef));
128static OSStatus install_menu_target_item_handler P_ ((void));
129#ifdef MAC_OSX
130static OSStatus install_service_handler P_ ((void));
131#endif
132
133extern OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
134 Lisp_Object,
135 Lisp_Object,
136 EventRef, UInt32,
137 const EventParamName *,
138 const EventParamType *));
139
140#if USE_MAC_TSM
141extern OSStatus mac_restore_keyboard_input_source P_ ((void));
142extern void mac_save_keyboard_input_source P_ ((void));
143
144static OSStatus
145mac_tsm_resume ()
146{
147 OSStatus err;
148
149 err = ActivateTSMDocument (tsm_document_id);
150 if (err == noErr)
151 err = mac_restore_keyboard_input_source ();
152
153 return err;
154}
155
156static OSStatus
157mac_tsm_suspend ()
158{
159 OSStatus err;
160
161 mac_save_keyboard_input_source ();
162 err = DeactivateTSMDocument (tsm_document_id);
163
164 return err;
165}
166
167static void
168init_tsm ()
169{
170#ifdef MAC_OSX
171 static InterfaceTypeList types = {kUnicodeDocument};
172#else
173 static InterfaceTypeList types = {kTextService};
174#endif
175
176 NewTSMDocument (sizeof (types) / sizeof (types[0]), types,
177 &tsm_document_id, 0);
178}
179#endif /* USE_MAC_TSM */
180
181static pascal OSStatus
182mac_handle_keyboard_event (next_handler, event, data)
183 EventHandlerCallRef next_handler;
184 EventRef event;
185 void *data;
186{
187 OSStatus err, result = eventNotHandledErr;
188 UInt32 event_kind, key_code, modifiers;
189 unsigned char char_code;
190
191 event_kind = GetEventKind (event);
192 switch (event_kind)
193 {
194 case kEventRawKeyDown:
195 case kEventRawKeyRepeat:
196 case kEventRawKeyUp:
197 /* When using Carbon Events, we need to pass raw keyboard events
198 to the TSM ourselves. If TSM handles it, it will pass back
199 noErr, otherwise it will pass back "eventNotHandledErr" and
200 we can process it normally. */
201 result = CallNextEventHandler (next_handler, event);
202 if (result != eventNotHandledErr)
203 break;
204
205 if (read_socket_inev == NULL)
206 break;
207
208#if USE_MAC_TSM
209 if (read_socket_inev->kind != NO_EVENT)
210 {
211 result = noErr;
212 break;
213 }
214#endif
215
216 if (event_kind == kEventRawKeyUp)
217 break;
218
219 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
220 typeChar, NULL,
221 sizeof (char), NULL, &char_code);
222 if (err != noErr)
223 break;
224
225 err = GetEventParameter (event, kEventParamKeyCode,
226 typeUInt32, NULL,
227 sizeof (UInt32), NULL, &key_code);
228 if (err != noErr)
229 break;
230
231 err = GetEventParameter (event, kEventParamKeyModifiers,
232 typeUInt32, NULL,
233 sizeof (UInt32), NULL, &modifiers);
234 if (err != noErr)
235 break;
236
237 do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey),
238 char_code, key_code, modifiers,
239 ((unsigned long)
240 (GetEventTime (event) / kEventDurationMillisecond)),
241 read_socket_inev);
242 result = noErr;
243 break;
244
245 default:
246 abort ();
247 }
248
249 return result;
250}
251
252static pascal OSStatus
253mac_handle_command_event (next_handler, event, data)
254 EventHandlerCallRef next_handler;
255 EventRef event;
256 void *data;
257{
258 OSStatus err, result = eventNotHandledErr;
259 HICommand command;
260 static const EventParamName names[] =
261 {kEventParamDirectObject, kEventParamKeyModifiers};
262 static const EventParamType types[] =
263 {typeHICommand, typeUInt32};
264 int num_params = sizeof (names) / sizeof (names[0]);
265
266 err = GetEventParameter (event, kEventParamDirectObject, typeHICommand,
267 NULL, sizeof (HICommand), NULL, &command);
268 if (err != noErr)
269 return eventNotHandledErr;
270
271 switch (GetEventKind (event))
272 {
273 case kEventCommandProcess:
274 result = CallNextEventHandler (next_handler, event);
275 if (result != eventNotHandledErr)
276 break;
277
278 err = GetEventParameter (event, kEventParamDirectObject,
279 typeHICommand, NULL,
280 sizeof (HICommand), NULL, &command);
281
282 if (err != noErr || command.commandID == 0)
283 break;
284
285 /* A HI command event is mapped to an Apple event whose event
286 class symbol is `hi-command' and event ID is its command
287 ID. */
288 err = mac_store_event_ref_as_apple_event (0, command.commandID,
289 Qhi_command, Qnil,
290 event, num_params,
291 names, types);
292 if (err == noErr)
293 result = noErr;
294 break;
295
296 default:
297 abort ();
298 }
299
300 return result;
301}
302
303static pascal OSStatus
304mac_handle_mouse_event (next_handler, event, data)
305 EventHandlerCallRef next_handler;
306 EventRef event;
307 void *data;
308{
309 OSStatus err, result = eventNotHandledErr;
310
311 switch (GetEventKind (event))
312 {
313 case kEventMouseWheelMoved:
314 {
315 WindowRef wp;
316 struct frame *f;
317 EventMouseWheelAxis axis;
318 SInt32 delta;
319 Point point;
320
321 result = CallNextEventHandler (next_handler, event);
322 if (result != eventNotHandledErr || read_socket_inev == NULL)
323 break;
324
325 f = mac_focus_frame (&one_mac_display_info);
326
327 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
328 NULL, sizeof (WindowRef), NULL, &wp);
329 if (err != noErr
330 || wp != FRAME_MAC_WINDOW (f))
331 break;
332
333 err = GetEventParameter (event, kEventParamMouseWheelAxis,
334 typeMouseWheelAxis, NULL,
335 sizeof (EventMouseWheelAxis), NULL, &axis);
336 if (err != noErr || axis != kEventMouseWheelAxisY)
337 break;
338
339 err = GetEventParameter (event, kEventParamMouseLocation,
340 typeQDPoint, NULL, sizeof (Point),
341 NULL, &point);
342 if (err != noErr)
343 break;
344
345 point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
346 point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
347 if (point.h < 0 || point.v < 0
348 || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1),
349 f->tool_bar_window))
350 break;
351
352 err = GetEventParameter (event, kEventParamMouseWheelDelta,
353 typeSInt32, NULL, sizeof (SInt32),
354 NULL, &delta);
355 if (err != noErr)
356 break;
357
358 read_socket_inev->kind = WHEEL_EVENT;
359 read_socket_inev->code = 0;
360 read_socket_inev->modifiers =
361 (mac_event_to_emacs_modifiers (event)
362 | ((delta < 0) ? down_modifier : up_modifier));
363 XSETINT (read_socket_inev->x, point.h);
364 XSETINT (read_socket_inev->y, point.v);
365 XSETFRAME (read_socket_inev->frame_or_window, f);
366
367 result = noErr;
368 }
369 break;
370
371 default:
372 abort ();
373 }
374
375 return result;
376}
377
378#if USE_MAC_TSM
379static pascal OSStatus
380mac_handle_text_input_event (next_handler, event, data)
381 EventHandlerCallRef next_handler;
382 EventRef event;
383 void *data;
384{
385 OSStatus err, result;
386 Lisp_Object id_key = Qnil;
387 int num_params;
388 const EventParamName *names;
389 const EventParamType *types;
390 static UInt32 seqno_uaia = 0;
391 static const EventParamName names_uaia[] =
392 {kEventParamTextInputSendComponentInstance,
393 kEventParamTextInputSendRefCon,
394 kEventParamTextInputSendSLRec,
395 kEventParamTextInputSendFixLen,
396 kEventParamTextInputSendText,
397 kEventParamTextInputSendUpdateRng,
398 kEventParamTextInputSendHiliteRng,
399 kEventParamTextInputSendClauseRng,
400 kEventParamTextInputSendPinRng,
401 kEventParamTextInputSendTextServiceEncoding,
402 kEventParamTextInputSendTextServiceMacEncoding,
403 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER};
404 static const EventParamType types_uaia[] =
405 {typeComponentInstance,
406 typeLongInteger,
407 typeIntlWritingCode,
408 typeLongInteger,
409#ifdef MAC_OSX
410 typeUnicodeText,
411#else
412 typeChar,
413#endif
414 typeTextRangeArray,
415 typeTextRangeArray,
416 typeOffsetArray,
417 typeTextRange,
418 typeUInt32,
419 typeUInt32,
420 typeUInt32};
421 static const EventParamName names_ufke[] =
422 {kEventParamTextInputSendComponentInstance,
423 kEventParamTextInputSendRefCon,
424 kEventParamTextInputSendSLRec,
425 kEventParamTextInputSendText};
426 static const EventParamType types_ufke[] =
427 {typeComponentInstance,
428 typeLongInteger,
429 typeIntlWritingCode,
430 typeUnicodeText};
431
432 result = CallNextEventHandler (next_handler, event);
433 if (result != eventNotHandledErr)
434 return result;
435
436 switch (GetEventKind (event))
437 {
438 case kEventTextInputUpdateActiveInputArea:
439 id_key = Qupdate_active_input_area;
440 num_params = sizeof (names_uaia) / sizeof (names_uaia[0]);
441 names = names_uaia;
442 types = types_uaia;
443 SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER,
444 typeUInt32, sizeof (UInt32), &seqno_uaia);
445 seqno_uaia++;
446 result = noErr;
447 break;
448
449 case kEventTextInputUnicodeForKeyEvent:
450 {
451 EventRef kbd_event;
452 UInt32 actual_size, modifiers, key_code;
453
454 err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent,
455 typeEventRef, NULL, sizeof (EventRef), NULL,
456 &kbd_event);
457 if (err == noErr)
458 err = GetEventParameter (kbd_event, kEventParamKeyModifiers,
459 typeUInt32, NULL,
460 sizeof (UInt32), NULL, &modifiers);
461 if (err == noErr)
462 err = GetEventParameter (kbd_event, kEventParamKeyCode,
463 typeUInt32, NULL, sizeof (UInt32),
464 NULL, &key_code);
465 if (err == noErr && mac_mapped_modifiers (modifiers, key_code))
466 /* There're mapped modifier keys. Process it in
467 do_keystroke. */
468 break;
469 if (err == noErr)
470 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
471 typeUnicodeText, NULL, 0, &actual_size,
472 NULL);
473 if (err == noErr && actual_size == sizeof (UniChar))
474 {
475 UniChar code;
476
477 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
478 typeUnicodeText, NULL,
479 sizeof (UniChar), NULL, &code);
480 if (err == noErr && code < 0x80)
481 {
482 /* ASCII character. Process it in do_keystroke. */
483 if (read_socket_inev && code >= 0x20 && code <= 0x7e
484 && !(key_code <= 0x7f
485 && keycode_to_xkeysym_table [key_code]))
486 {
487 struct frame *f = mac_focus_frame (&one_mac_display_info);
488
489 read_socket_inev->kind = ASCII_KEYSTROKE_EVENT;
490 read_socket_inev->code = code;
491 read_socket_inev->modifiers =
492 mac_to_emacs_modifiers (modifiers, 0);
493 read_socket_inev->modifiers |=
494 (extra_keyboard_modifiers
495 & (meta_modifier | alt_modifier
496 | hyper_modifier | super_modifier));
497 XSETFRAME (read_socket_inev->frame_or_window, f);
498 }
499 break;
500 }
501 }
502 if (err == noErr)
503 {
504 /* Non-ASCII keystrokes without mapped modifiers are
505 processed at the Lisp level. */
506 id_key = Qunicode_for_key_event;
507 num_params = sizeof (names_ufke) / sizeof (names_ufke[0]);
508 names = names_ufke;
509 types = types_ufke;
510 result = noErr;
511 }
512 }
513 break;
514
515 case kEventTextInputOffsetToPos:
516 {
517 struct frame *f;
518 struct window *w;
519 Point p;
520
521 if (!OVERLAYP (Vmac_ts_active_input_overlay))
522 break;
523
524 /* Strictly speaking, this is not always correct because
525 previous events may change some states about display. */
526 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
527 {
528 /* Active input area is displayed around the current point. */
529 f = SELECTED_FRAME ();
530 w = XWINDOW (f->selected_window);
531 }
532 else if (WINDOWP (echo_area_window))
533 {
534 /* Active input area is displayed in the echo area. */
535 w = XWINDOW (echo_area_window);
536 f = WINDOW_XFRAME (w);
537 }
538 else
539 break;
540
541 p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
542 + WINDOW_LEFT_FRINGE_WIDTH (w)
543 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
544 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
545 + FONT_BASE (FRAME_FONT (f))
546 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
547 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
548 typeQDPoint, sizeof (typeQDPoint), &p);
549 if (err == noErr)
550 result = noErr;
551 }
552 break;
553
554 default:
555 abort ();
556 }
557
558 if (!NILP (id_key))
559 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
560 event, num_params,
561 names, types);
562 return result;
563}
564#endif
565
566OSStatus
567install_application_handler ()
568{
569 OSStatus err = noErr;
570
571 if (err == noErr)
572 {
573 static const EventTypeSpec specs[] =
574 {{kEventClassKeyboard, kEventRawKeyDown},
575 {kEventClassKeyboard, kEventRawKeyRepeat},
576 {kEventClassKeyboard, kEventRawKeyUp}};
577
578 err = InstallApplicationEventHandler (NewEventHandlerUPP
579 (mac_handle_keyboard_event),
580 GetEventTypeCount (specs),
581 specs, NULL, NULL);
582 }
583
584 if (err == noErr)
585 {
586 static const EventTypeSpec specs[] =
587 {{kEventClassCommand, kEventCommandProcess}};
588
589 err = InstallApplicationEventHandler (NewEventHandlerUPP
590 (mac_handle_command_event),
591 GetEventTypeCount (specs),
592 specs, NULL, NULL);
593 }
594
595 if (err == noErr)
596 {
597 static const EventTypeSpec specs[] =
598 {{kEventClassMouse, kEventMouseWheelMoved}};
599
600 err = InstallApplicationEventHandler (NewEventHandlerUPP
601 (mac_handle_mouse_event),
602 GetEventTypeCount (specs),
603 specs, NULL, NULL);
604 }
605
606#if USE_MAC_TSM
607 if (err == noErr)
608 {
609 static const EventTypeSpec spec[] =
610 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
611 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
612 {kEventClassTextInput, kEventTextInputOffsetToPos}};
613
614 err = InstallApplicationEventHandler (NewEventHandlerUPP
615 (mac_handle_text_input_event),
616 GetEventTypeCount (spec),
617 spec, NULL, NULL);
618 }
619#endif
620
621 if (err == noErr)
622 err = install_menu_target_item_handler ();
623
624#ifdef MAC_OSX
625 if (err == noErr)
626 err = install_service_handler ();
627#endif
628
629 return err;
630}
631#endif /* TARGET_API_MAC_CARBON */
632
633
634/************************************************************************
635 Windows
636 ************************************************************************/
637
638#define DEFAULT_NUM_COLS 80
639
640#define MIN_DOC_SIZE 64
641#define MAX_DOC_SIZE 32767
642
643/* Drag and Drop */
644static OSErr install_drag_handler P_ ((WindowRef));
645static void remove_drag_handler P_ ((WindowRef));
646
647#if USE_CG_DRAWING
648static void mac_prepare_for_quickdraw P_ ((struct frame *));
649#endif
650
651extern void mac_handle_visibility_change P_ ((struct frame *));
652extern void mac_handle_origin_change P_ ((struct frame *));
653extern void mac_handle_size_change P_ ((struct frame *, int, int));
654
655#if TARGET_API_MAC_CARBON
656#ifdef MAC_OSX
657extern Lisp_Object Qwindow;
658extern Lisp_Object Qtoolbar_switch_mode;
659#endif
660#endif
661
662static void
663do_window_update (WindowRef win)
664{
665 struct frame *f = mac_window_to_frame (win);
666
667 BeginUpdate (win);
668
669 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
670 below. */
671 if (win != tip_window)
672 {
673 if (f->async_visible == 0)
674 {
675 /* Update events may occur when a frame gets iconified. */
676#if 0
677 f->async_visible = 1;
678 f->async_iconified = 0;
679 SET_FRAME_GARBAGED (f);
680#endif
681 }
682 else
683 {
684 Rect r;
685#if TARGET_API_MAC_CARBON
686 RgnHandle region = NewRgn ();
687
688 GetPortVisibleRegion (GetWindowPort (win), region);
689 GetRegionBounds (region, &r);
690 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
691#if USE_CG_DRAWING
692 mac_prepare_for_quickdraw (f);
693#endif
694 UpdateControls (win, region);
695 DisposeRgn (region);
696#else
697 r = (*win->visRgn)->rgnBBox;
698 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
699 UpdateControls (win, win->visRgn);
700#endif
701 }
702 }
703
704 EndUpdate (win);
705}
706
707static int
708is_emacs_window (WindowRef win)
709{
710 Lisp_Object tail, frame;
711
712 if (!win)
713 return 0;
714
715 FOR_EACH_FRAME (tail, frame)
716 if (FRAME_MAC_P (XFRAME (frame)))
717 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
718 return 1;
719
720 return 0;
721}
722
723/* Handle drags in size box. Based on code contributed by Ben
724 Mesander and IM - Window Manager A. */
725
726static void
727do_grow_window (w, e)
728 WindowRef w;
729 const EventRecord *e;
730{
731 Rect limit_rect;
732 int rows, columns, width, height;
733 struct frame *f = mac_window_to_frame (w);
734 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
735 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
736#if TARGET_API_MAC_CARBON
737 Rect new_rect;
738#else
739 long grow_size;
740#endif
741
742 if (size_hints->flags & PMinSize)
743 {
744 min_width = size_hints->min_width;
745 min_height = size_hints->min_height;
746 }
747 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
748
749#if TARGET_API_MAC_CARBON
750 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
751 return;
752 height = new_rect.bottom - new_rect.top;
753 width = new_rect.right - new_rect.left;
754#else
755 grow_size = GrowWindow (w, e->where, &limit_rect);
756 /* see if it really changed size */
757 if (grow_size == 0)
758 return;
759 height = HiWord (grow_size);
760 width = LoWord (grow_size);
761#endif
762
763 if (width != FRAME_PIXEL_WIDTH (f)
764 || height != FRAME_PIXEL_HEIGHT (f))
765 {
766 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
767 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
768
769 x_set_window_size (f, 0, columns, rows);
770 }
771}
772
773#if TARGET_API_MAC_CARBON
774static Point
775mac_get_ideal_size (f)
776 struct frame *f;
777{
778 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
779 WindowRef w = FRAME_MAC_WINDOW (f);
780 Point ideal_size;
781 Rect standard_rect;
782 int height, width, columns, rows;
783
784 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
785 ideal_size.v = dpyinfo->height;
786 IsWindowInStandardState (w, &ideal_size, &standard_rect);
787 /* Adjust the standard size according to character boundaries. */
788 width = standard_rect.right - standard_rect.left;
789 height = standard_rect.bottom - standard_rect.top;
790 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
791 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
792 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
793 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
794
795 return ideal_size;
796}
797
798static pascal OSStatus
799mac_handle_window_event (next_handler, event, data)
800 EventHandlerCallRef next_handler;
801 EventRef event;
802 void *data;
803{
804 WindowRef wp;
805 OSStatus err, result = eventNotHandledErr;
806 struct frame *f;
807 UInt32 attributes;
808 XSizeHints *size_hints;
809
810 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
811 NULL, sizeof (WindowRef), NULL, &wp);
812 if (err != noErr)
813 return eventNotHandledErr;
814
815 f = mac_window_to_frame (wp);
816 switch (GetEventKind (event))
817 {
818 /* -- window refresh events -- */
819
820 case kEventWindowUpdate:
821 result = CallNextEventHandler (next_handler, event);
822 if (result != eventNotHandledErr)
823 break;
824
825 do_window_update (wp);
826 result = noErr;
827 break;
828
829 /* -- window state change events -- */
830
831 case kEventWindowShowing:
832 size_hints = FRAME_SIZE_HINTS (f);
833 if (!(size_hints->flags & (USPosition | PPosition)))
834 {
835 struct frame *sf = SELECTED_FRAME ();
836
837 if (!(FRAME_MAC_P (sf) && sf->async_visible))
838 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
839 else
840 {
841 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
842#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
843 kWindowCascadeStartAtParentWindowScreen
844#else
845 kWindowCascadeOnParentWindowScreen
846#endif
847 );
848#if USE_MAC_TOOLBAR
849 /* This is a workaround. RepositionWindow fails to put
850 a window at the cascading position when its parent
851 window has a Carbon HIToolbar. */
852 if ((f->left_pos == sf->left_pos
853 && f->top_pos == sf->top_pos)
854 || (f->left_pos == sf->left_pos + 10 * 2
855 && f->top_pos == sf->top_pos + 32 * 2))
856 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
857#endif
858 }
859 result = noErr;
860 }
861 break;
862
863 case kEventWindowHiding:
864 /* Before unmapping the window, update the WM_SIZE_HINTS
865 property to claim that the current position of the window is
866 user-specified, rather than program-specified, so that when
867 the window is mapped again, it will be placed at the same
868 location, without forcing the user to position it by hand
869 again (they have already done that once for this window.) */
870 x_wm_set_size_hint (f, (long) 0, 1);
871 result = noErr;
872 break;
873
874 case kEventWindowShown:
875 case kEventWindowHidden:
876 case kEventWindowCollapsed:
877 case kEventWindowExpanded:
878 mac_handle_visibility_change (f);
879 result = noErr;
880 break;
881
882 case kEventWindowBoundsChanging:
883 result = CallNextEventHandler (next_handler, event);
884 if (result != eventNotHandledErr)
885 break;
886
887 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
888 NULL, sizeof (UInt32), NULL, &attributes);
889 if (err != noErr)
890 break;
891
892 size_hints = FRAME_SIZE_HINTS (f);
893 if ((attributes & kWindowBoundsChangeUserResize)
894 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
895 == (PResizeInc | PBaseSize | PMinSize)))
896 {
897 Rect bounds;
898 int width, height;
899
900 err = GetEventParameter (event, kEventParamCurrentBounds,
901 typeQDRectangle, NULL, sizeof (Rect),
902 NULL, &bounds);
903 if (err != noErr)
904 break;
905
906 width = bounds.right - bounds.left;
907 height = bounds.bottom - bounds.top;
908
909 if (width < size_hints->min_width)
910 width = size_hints->min_width;
911 else
912 width = size_hints->base_width
913 + (int) ((width - size_hints->base_width)
914 / (float) size_hints->width_inc + .5)
915 * size_hints->width_inc;
916
917 if (height < size_hints->min_height)
918 height = size_hints->min_height;
919 else
920 height = size_hints->base_height
921 + (int) ((height - size_hints->base_height)
922 / (float) size_hints->height_inc + .5)
923 * size_hints->height_inc;
924
925 bounds.right = bounds.left + width;
926 bounds.bottom = bounds.top + height;
927 SetEventParameter (event, kEventParamCurrentBounds,
928 typeQDRectangle, sizeof (Rect), &bounds);
929 result = noErr;
930 }
931 break;
932
933 case kEventWindowBoundsChanged:
934 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
935 NULL, sizeof (UInt32), NULL, &attributes);
936 if (err != noErr)
937 break;
938
939 if (attributes & kWindowBoundsChangeSizeChanged)
940 {
941 Rect bounds;
942
943 err = GetEventParameter (event, kEventParamCurrentBounds,
944 typeQDRectangle, NULL, sizeof (Rect),
945 NULL, &bounds);
946 if (err == noErr)
947 {
948 int width, height;
949
950 width = bounds.right - bounds.left;
951 height = bounds.bottom - bounds.top;
952 mac_handle_size_change (f, width, height);
953 mac_wakeup_from_rne ();
954 }
955 }
956
957 if (attributes & kWindowBoundsChangeOriginChanged)
958 mac_handle_origin_change (f);
959
960 result = noErr;
961 break;
962
963 /* -- window action events -- */
964
965 case kEventWindowClose:
966 {
967 struct input_event buf;
968
969 EVENT_INIT (buf);
970 buf.kind = DELETE_WINDOW_EVENT;
971 XSETFRAME (buf.frame_or_window, f);
972 buf.arg = Qnil;
973 kbd_buffer_store_event (&buf);
974 }
975 result = noErr;
976 break;
977
978 case kEventWindowGetIdealSize:
979 result = CallNextEventHandler (next_handler, event);
980 if (result != eventNotHandledErr)
981 break;
982
983 {
984 Point ideal_size = mac_get_ideal_size (f);
985
986 err = SetEventParameter (event, kEventParamDimensions,
987 typeQDPoint, sizeof (Point), &ideal_size);
988 if (err == noErr)
989 result = noErr;
990 }
991 break;
992
993#ifdef MAC_OSX
994 case kEventWindowToolbarSwitchMode:
995 {
996 static const EventParamName names[] = {kEventParamDirectObject,
997 kEventParamWindowMouseLocation,
998 kEventParamKeyModifiers,
999 kEventParamMouseButton,
1000 kEventParamClickCount,
1001 kEventParamMouseChord};
1002 static const EventParamType types[] = {typeWindowRef,
1003 typeQDPoint,
1004 typeUInt32,
1005 typeMouseButton,
1006 typeUInt32,
1007 typeUInt32};
1008 int num_params = sizeof (names) / sizeof (names[0]);
1009
1010 err = mac_store_event_ref_as_apple_event (0, 0,
1011 Qwindow,
1012 Qtoolbar_switch_mode,
1013 event, num_params,
1014 names, types);
1015 }
1016 if (err == noErr)
1017 result = noErr;
1018 break;
1019#endif
1020
1021#if USE_MAC_TSM
1022 /* -- window focus events -- */
1023
1024 case kEventWindowFocusAcquired:
1025 err = mac_tsm_resume ();
1026 if (err == noErr)
1027 result = noErr;
1028 break;
1029
1030 case kEventWindowFocusRelinquish:
1031 err = mac_tsm_suspend ();
1032 if (err == noErr)
1033 result = noErr;
1034 break;
1035#endif
1036
1037 default:
1038 abort ();
1039 }
1040
1041 return result;
1042}
1043#endif
1044
1045/* Handle clicks in zoom box. Calculation of "standard state" based
1046 on code in IM - Window Manager A and code contributed by Ben
1047 Mesander. The standard state of an Emacs window is 80-characters
1048 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
1049
1050static void
1051do_zoom_window (WindowRef w, int zoom_in_or_out)
1052{
1053 Rect zoom_rect, port_rect;
1054 int width, height;
1055 struct frame *f = mac_window_to_frame (w);
1056#if TARGET_API_MAC_CARBON
1057 Point ideal_size = mac_get_ideal_size (f);
1058
1059 GetWindowBounds (w, kWindowContentRgn, &port_rect);
1060 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
1061 && port_rect.left == zoom_rect.left
1062 && port_rect.top == zoom_rect.top)
1063 zoom_in_or_out = inZoomIn;
1064 else
1065 zoom_in_or_out = inZoomOut;
1066
1067#ifdef MAC_OS8
1068 mac_clear_area (f, 0, 0, port_rect.right - port_rect.left,
1069 port_rect.bottom - port_rect.top);
1070#endif
1071 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
1072#else /* not TARGET_API_MAC_CARBON */
1073 GrafPtr save_port;
1074 Point top_left;
1075 int w_title_height, rows;
1076 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
1077
1078 GetPort (&save_port);
1079
1080 SetPortWindowPort (w);
1081
1082 /* Clear window to avoid flicker. */
1083 EraseRect (&(w->portRect));
1084 if (zoom_in_or_out == inZoomOut)
1085 {
1086 SetPt (&top_left, w->portRect.left, w->portRect.top);
1087 LocalToGlobal (&top_left);
1088
1089 /* calculate height of window's title bar */
1090 w_title_height = top_left.v - 1
1091 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
1092
1093 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
1094 zoom_rect = qd.screenBits.bounds;
1095 zoom_rect.top += w_title_height;
1096 InsetRect (&zoom_rect, 8, 4); /* not too tight */
1097
1098 zoom_rect.right = zoom_rect.left
1099 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
1100
1101 /* Adjust the standard size according to character boundaries. */
1102 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
1103 zoom_rect.bottom =
1104 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1105
1106 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
1107 = zoom_rect;
1108 }
1109
1110 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
1111
1112 SetPort (save_port);
1113#endif /* not TARGET_API_MAC_CARBON */
1114
1115#if !TARGET_API_MAC_CARBON
1116 /* retrieve window size and update application values */
1117 port_rect = w->portRect;
1118 height = port_rect.bottom - port_rect.top;
1119 width = port_rect.right - port_rect.left;
1120
1121 mac_handle_size_change (f, width, height);
1122 mac_handle_origin_change (f);
1123#endif
1124}
1125
1126static OSStatus
1127install_window_handler (window)
1128 WindowRef window;
1129{
1130 OSStatus err = noErr;
1131
1132#if TARGET_API_MAC_CARBON
1133 if (err == noErr)
1134 {
1135 static const EventTypeSpec specs[] =
1136 {
1137 /* -- window refresh events -- */
1138 {kEventClassWindow, kEventWindowUpdate},
1139 /* -- window state change events -- */
1140 {kEventClassWindow, kEventWindowShowing},
1141 {kEventClassWindow, kEventWindowHiding},
1142 {kEventClassWindow, kEventWindowShown},
1143 {kEventClassWindow, kEventWindowHidden},
1144 {kEventClassWindow, kEventWindowCollapsed},
1145 {kEventClassWindow, kEventWindowExpanded},
1146 {kEventClassWindow, kEventWindowBoundsChanging},
1147 {kEventClassWindow, kEventWindowBoundsChanged},
1148 /* -- window action events -- */
1149 {kEventClassWindow, kEventWindowClose},
1150 {kEventClassWindow, kEventWindowGetIdealSize},
1151#ifdef MAC_OSX
1152 {kEventClassWindow, kEventWindowToolbarSwitchMode},
1153#endif
1154#if USE_MAC_TSM
1155 /* -- window focus events -- */
1156 {kEventClassWindow, kEventWindowFocusAcquired},
1157 {kEventClassWindow, kEventWindowFocusRelinquish},
1158#endif
1159 };
1160 static EventHandlerUPP handle_window_eventUPP = NULL;
1161
1162 if (handle_window_eventUPP == NULL)
1163 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
1164
1165 err = InstallWindowEventHandler (window, handle_window_eventUPP,
1166 GetEventTypeCount (specs),
1167 specs, NULL, NULL);
1168 }
1169#endif
1170
1171 if (err == noErr)
1172 err = install_drag_handler (window);
1173
1174 return err;
1175}
1176
1177static void
1178remove_window_handler (window)
1179 WindowRef window;
1180{
1181 remove_drag_handler (window);
1182}
1183
1184void
1185mac_get_window_bounds (f, inner, outer)
1186 struct frame *f;
1187 Rect *inner, *outer;
1188{
1189#if TARGET_API_MAC_CARBON
1190 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
1191 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
1192#else /* not TARGET_API_MAC_CARBON */
1193 RgnHandle region = NewRgn ();
1194
1195 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
1196 *inner = (*region)->rgnBBox;
1197 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
1198 *outer = (*region)->rgnBBox;
1199 DisposeRgn (region);
1200#endif /* not TARGET_API_MAC_CARBON */
1201}
1202
1203Rect *
1204mac_get_frame_bounds (f, r)
1205 struct frame *f;
1206 Rect *r;
1207{
1208#if TARGET_API_MAC_CARBON
1209 return GetWindowPortBounds (FRAME_MAC_WINDOW (f), r);
1210#else
1211 *r = FRAME_MAC_WINDOW (f)->portRect;
1212
1213 return r;
1214#endif
1215}
1216
1217void
1218mac_get_frame_mouse (f, point)
1219 struct frame *f;
1220 Point *point;
1221{
1222#if TARGET_API_MAC_CARBON
1223 GetGlobalMouse (point);
1224 point->h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1225 point->v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1226#else
1227 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1228 GetMouse (point);
1229#endif
1230}
1231
1232void
1233mac_convert_frame_point_to_global (f, x, y)
1234 struct frame *f;
1235 int *x, *y;
1236{
1237 *x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1238 *y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1239}
1240
1241#if TARGET_API_MAC_CARBON
1242void
1243mac_update_proxy_icon (f)
1244 struct frame *f;
1245{
1246 OSStatus err;
1247 Lisp_Object file_name =
1248 XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer)->filename;
1249 Window w = FRAME_MAC_WINDOW (f);
1250 AliasHandle alias = NULL;
1251
1252 err = GetWindowProxyAlias (w, &alias);
1253 if (err == errWindowDoesNotHaveProxy && !STRINGP (file_name))
1254 return;
1255
1256 if (STRINGP (file_name))
1257 {
1258 AEDesc desc;
1259#ifdef MAC_OSX
1260 FSRef fref, fref_proxy;
1261#else
1262 FSSpec fss, fss_proxy;
1263#endif
1264 Boolean changed;
1265 Lisp_Object encoded_file_name = ENCODE_FILE (file_name);
1266
1267#ifdef MAC_OSX
1268 err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name),
1269 SBYTES (encoded_file_name), typeFSRef, &desc);
1270#else
1271 SetPortWindowPort (w);
1272 err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name),
1273 SBYTES (encoded_file_name), typeFSS, &desc);
1274#endif
1275 if (err == noErr)
1276 {
1277#ifdef MAC_OSX
1278 err = AEGetDescData (&desc, &fref, sizeof (FSRef));
1279#else
1280 err = AEGetDescData (&desc, &fss, sizeof (FSSpec));
1281#endif
1282 AEDisposeDesc (&desc);
1283 }
1284 if (err == noErr)
1285 {
1286 if (alias)
1287 {
1288 /* (FS)ResolveAlias never sets `changed' to true if
1289 `alias' is minimal. */
1290#ifdef MAC_OSX
1291 err = FSResolveAlias (NULL, alias, &fref_proxy, &changed);
1292 if (err == noErr)
1293 err = FSCompareFSRefs (&fref, &fref_proxy);
1294#else
1295 err = ResolveAlias (NULL, alias, &fss_proxy, &changed);
1296 if (err == noErr)
1297 err = !(fss.vRefNum == fss_proxy.vRefNum
1298 && fss.parID == fss_proxy.parID
1299 && EqualString (fss.name, fss_proxy.name,
1300 false, true));
1301#endif
1302 }
1303 if (err != noErr || alias == NULL)
1304 {
1305 if (alias)
1306 DisposeHandle ((Handle) alias);
1307#ifdef MAC_OSX
1308 err = FSNewAliasMinimal (&fref, &alias);
1309#else
1310 err = NewAliasMinimal (&fss, &alias);
1311#endif
1312 changed = true;
1313 }
1314 }
1315 if (err == noErr)
1316 if (changed)
1317 err = SetWindowProxyAlias (w, alias);
1318 }
1319
1320 if (alias)
1321 DisposeHandle ((Handle) alias);
1322
1323 if (err != noErr || !STRINGP (file_name))
1324 RemoveWindowProxy (w);
1325}
1326#endif
1327
1328/* Mac replacement for XSetWindowBackground. */
1329
1330void
1331mac_set_frame_window_background (f, color)
1332 struct frame *f;
1333 unsigned long color;
1334{
1335 WindowRef w = FRAME_MAC_WINDOW (f);
1336#if !TARGET_API_MAC_CARBON
1337 AuxWinHandle aw_handle;
1338 CTabHandle ctab_handle;
1339 ColorSpecPtr ct_table;
1340 short ct_size;
1341#endif
1342 RGBColor bg_color;
1343
1344 bg_color.red = RED16_FROM_ULONG (color);
1345 bg_color.green = GREEN16_FROM_ULONG (color);
1346 bg_color.blue = BLUE16_FROM_ULONG (color);
1347
1348#if TARGET_API_MAC_CARBON
1349 SetWindowContentColor (w, &bg_color);
1350#else
1351 if (GetAuxWin (w, &aw_handle))
1352 {
1353 ctab_handle = (*aw_handle)->awCTable;
1354 HandToHand ((Handle *) &ctab_handle);
1355 ct_table = (*ctab_handle)->ctTable;
1356 ct_size = (*ctab_handle)->ctSize;
1357 while (ct_size > -1)
1358 {
1359 if (ct_table->value == 0)
1360 {
1361 ct_table->rgb = bg_color;
1362 CTabChanged (ctab_handle);
1363 SetWinColor (w, (WCTabHandle) ctab_handle);
1364 }
1365 ct_size--;
1366 }
1367 }
1368#endif
1369}
1370
1371/* Flush display of frame F, or of all frames if F is null. */
1372
1373void
1374x_flush (f)
1375 struct frame *f;
1376{
1377#if TARGET_API_MAC_CARBON
1378 BLOCK_INPUT;
1379#if USE_CG_DRAWING
1380 mac_prepare_for_quickdraw (f);
1381#endif
1382 if (f)
1383 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
1384 else
1385 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
1386 UNBLOCK_INPUT;
1387#endif
1388}
1389
1390#if USE_CG_DRAWING
1391void
1392mac_flush_display_optional (f)
1393 struct frame *f;
1394{
1395 BLOCK_INPUT;
1396 mac_prepare_for_quickdraw (f);
1397 UNBLOCK_INPUT;
1398}
1399#endif
1400
1401void
1402mac_update_begin (f)
1403 struct frame *f;
1404{
1405#if TARGET_API_MAC_CARBON
1406 /* During update of a frame, availability of input events is
1407 periodically checked with ReceiveNextEvent if
1408 redisplay-dont-pause is nil. That normally flushes window buffer
1409 changes for every check, and thus screen update looks waving even
1410 if no input is available. So we disable screen updates during
1411 update of a frame. */
1412 DisableScreenUpdates ();
1413#endif
1414}
1415
1416void
1417mac_update_end (f)
1418 struct frame *f;
1419{
1420#if TARGET_API_MAC_CARBON
1421 EnableScreenUpdates ();
1422#endif
1423}
1424
1425void
1426mac_frame_up_to_date (f)
1427 struct frame *f;
1428{
1429 /* Nothing to do. */
1430}
1431
1432void
1433mac_create_frame_window (f, tooltip_p)
1434 struct frame *f;
1435 int tooltip_p;
1436{
1437 Rect r;
1438#if TARGET_API_MAC_CARBON
1439 WindowClass window_class;
1440 WindowAttributes attributes;
1441#else
1442 short proc_id;
1443 WindowRef behind;
1444 Boolean go_away_flag;
1445#endif
1446
1447 if (!tooltip_p)
1448 {
1449 SetRect (&r, f->left_pos, f->top_pos,
1450 f->left_pos + FRAME_PIXEL_WIDTH (f),
1451 f->top_pos + FRAME_PIXEL_HEIGHT (f));
1452#if TARGET_API_MAC_CARBON
1453 window_class = kDocumentWindowClass;
1454 attributes = (kWindowStandardDocumentAttributes
1455#ifdef MAC_OSX
1456 | kWindowToolbarButtonAttribute
1457#endif
1458 );
1459#else
1460 proc_id = zoomDocProc;
1461 behind = (WindowRef) -1;
1462 go_away_flag = true;
1463#endif
1464 }
1465 else
1466 {
1467 SetRect (&r, 0, 0, 1, 1);
1468#if TARGET_API_MAC_CARBON
1469 window_class = kHelpWindowClass;
1470 attributes = (kWindowNoUpdatesAttribute
1471 | kWindowNoActivatesAttribute
1472#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1473 | kWindowIgnoreClicksAttribute
1474#endif
1475 );
1476#else
1477 proc_id = plainDBox;
1478 behind = NULL;
1479 go_away_flag = false;
1480#endif
1481 }
1482
1483#if TARGET_API_MAC_CARBON
1484 CreateNewWindow (window_class, attributes, &r, &FRAME_MAC_WINDOW (f));
1485 if (FRAME_MAC_WINDOW (f))
1486 {
1487 SetWRefCon (FRAME_MAC_WINDOW (f), (long) f->output_data.mac);
1488 if (!tooltip_p)
1489 if (install_window_handler (FRAME_MAC_WINDOW (f)) != noErr)
1490 {
1491 DisposeWindow (FRAME_MAC_WINDOW (f));
1492 FRAME_MAC_WINDOW (f) = NULL;
1493 }
1494 }
1495#else /* !TARGET_API_MAC_CARBON */
1496 FRAME_MAC_WINDOW (f)
1497 = NewCWindow (NULL, &r, "\p", false, proc_id, behind, go_away_flag,
1498 (long) f->output_data.mac);
1499#endif /* !TARGET_API_MAC_CARBON */
1500 /* so that update events can find this mac_output struct */
1501 f->output_data.mac->mFP = f; /* point back to emacs frame */
1502
1503#ifndef MAC_OSX
1504 if (!tooltip_p)
1505 if (FRAME_MAC_WINDOW (f))
1506 {
1507 ControlRef root_control;
1508
1509 if (CreateRootControl (FRAME_MAC_WINDOW (f), &root_control) != noErr)
1510 {
1511 DisposeWindow (FRAME_MAC_WINDOW (f));
1512 FRAME_MAC_WINDOW (f) = NULL;
1513 }
1514 }
1515#endif
1516}
1517
1518/* Dispose of the Mac window of the frame F. */
1519
1520void
1521mac_dispose_frame_window (f)
1522 struct frame *f;
1523{
1524 WindowRef window = FRAME_MAC_WINDOW (f);
1525
1526 if (window != tip_window)
1527 remove_window_handler (window);
1528
1529#if USE_CG_DRAWING
1530 mac_prepare_for_quickdraw (f);
1531#endif
1532 DisposeWindow (window);
1533}
1534
1535
1536/************************************************************************
1537 View and Drawing
1538 ************************************************************************/
1539
1540#if USE_CG_DRAWING
1541#define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
1542
1543CGContextRef
1544mac_begin_cg_clip (f, gc)
1545 struct frame *f;
1546 GC gc;
1547{
1548 CGContextRef context = FRAME_CG_CONTEXT (f);
1549
1550 if (!context)
1551 {
1552 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1553 FRAME_CG_CONTEXT (f) = context;
1554 }
1555
1556 CGContextSaveGState (context);
1557 CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f));
1558 CGContextScaleCTM (context, 1, -1);
1559 if (gc && gc->n_clip_rects)
1560 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
1561
1562 return context;
1563}
1564
1565void
1566mac_end_cg_clip (f)
1567 struct frame *f;
1568{
1569 CGContextRestoreGState (FRAME_CG_CONTEXT (f));
1570}
1571
1572static void
1573mac_prepare_for_quickdraw (f)
1574 struct frame *f;
1575{
1576 if (f == NULL)
1577 {
1578 Lisp_Object rest, frame;
1579 FOR_EACH_FRAME (rest, frame)
1580 if (FRAME_MAC_P (XFRAME (frame)))
1581 mac_prepare_for_quickdraw (XFRAME (frame));
1582 }
1583 else
1584 {
1585 CGContextRef context = FRAME_CG_CONTEXT (f);
1586
1587 if (context)
1588 {
1589 CGContextSynchronize (context);
1590 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)),
1591 &FRAME_CG_CONTEXT (f));
1592 }
1593 }
1594}
1595#endif
1596
1597static RgnHandle saved_port_clip_region = NULL;
1598
1599void
1600mac_begin_clip (f, gc)
1601 struct frame *f;
1602 GC gc;
1603{
1604 static RgnHandle new_region = NULL;
1605
1606 if (saved_port_clip_region == NULL)
1607 saved_port_clip_region = NewRgn ();
1608 if (new_region == NULL)
1609 new_region = NewRgn ();
1610
1611#if USE_CG_DRAWING
1612 mac_prepare_for_quickdraw (f);
1613#endif
1614 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1615
1616 if (gc && gc->n_clip_rects)
1617 {
1618 GetClip (saved_port_clip_region);
1619 SectRgn (saved_port_clip_region, gc->clip_region, new_region);
1620 SetClip (new_region);
1621 }
1622}
1623
1624void
1625mac_end_clip (f, gc)
1626 struct frame *f;
1627 GC gc;
1628{
1629 if (gc && gc->n_clip_rects)
1630 SetClip (saved_port_clip_region);
1631}
1632
1633#if TARGET_API_MAC_CARBON
1634/* Mac replacement for XCopyArea: used only for scrolling. */
1635
1636void
1637mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1638 struct frame *f;
1639 GC gc;
1640 int src_x, src_y;
1641 unsigned int width, height;
1642 int dest_x, dest_y;
1643{
1644 Rect src_r;
1645 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
1646
1647 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1648#if USE_CG_DRAWING
1649 mac_prepare_for_quickdraw (f);
1650#endif
1651 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1652 &src_r, dest_x - src_x, dest_y - src_y,
1653 kScrollWindowNoOptions, dummy);
1654 DisposeRgn (dummy);
1655}
1656#endif
1657
1658
1659/************************************************************************
1660 Scroll bars
1661 ************************************************************************/
1662
1663extern struct scroll_bar *tracked_scroll_bar;
1664extern Lisp_Object last_mouse_scroll_bar;
1665extern Time last_mouse_movement_time;
1666
1667static void x_scroll_bar_handle_click P_ ((struct scroll_bar *,
1668 ControlPartCode,
1669 const EventRecord *,
1670 struct input_event *));
1671#ifndef USE_TOOLKIT_SCROLL_BARS
1672static void x_scroll_bar_note_movement P_ ((struct scroll_bar *, int, Time));
1673#else /* USE_TOOLKIT_SCROLL_BARS */
1674static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
1675 ControlPartCode, Point,
1676 struct input_event *));
1677static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
1678 struct input_event *));
1679static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *,
1680 Point, struct input_event *));
1681static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
1682static OSStatus install_scroll_bar_timer P_ ((void));
1683static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
1684static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
1685static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
1686 struct input_event *));
1687static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode,
1688 Rect *));
1689static void update_scroll_bar_track_info P_ ((struct scroll_bar *));
1690
1691/* Last scroll bar part sent in x_scroll_bar_handle_*. */
1692
1693static int last_scroll_bar_part;
1694
1695static EventLoopTimerRef scroll_bar_timer;
1696
1697static int scroll_bar_timer_event_posted_p;
1698
1699#define SCROLL_BAR_FIRST_DELAY 0.5
1700#define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
1701
1702static pascal void
1703scroll_bar_timer_callback (timer, data)
1704 EventLoopTimerRef timer;
1705 void *data;
1706{
1707 OSStatus err;
1708
1709 err = mac_post_mouse_moved_event ();
1710 if (err == noErr)
1711 scroll_bar_timer_event_posted_p = 1;
1712}
1713
1714static OSStatus
1715install_scroll_bar_timer ()
1716{
1717 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
1718
1719 if (scroll_bar_timer_callbackUPP == NULL)
1720 scroll_bar_timer_callbackUPP =
1721 NewEventLoopTimerUPP (scroll_bar_timer_callback);
1722
1723 if (scroll_bar_timer == NULL)
1724 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
1725 kEventDurationForever as delays. */
1726 return
1727 InstallEventLoopTimer (GetCurrentEventLoop (),
1728 kEventDurationForever, kEventDurationForever,
1729 scroll_bar_timer_callbackUPP, NULL,
1730 &scroll_bar_timer);
1731}
1732
1733static OSStatus
1734set_scroll_bar_timer (delay)
1735 EventTimerInterval delay;
1736{
1737 if (scroll_bar_timer == NULL)
1738 install_scroll_bar_timer ();
1739
1740 scroll_bar_timer_event_posted_p = 0;
1741
1742 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
1743}
1744
1745static int
1746control_part_code_to_scroll_bar_part (part_code)
1747 ControlPartCode part_code;
1748{
1749 switch (part_code)
1750 {
1751 case kControlUpButtonPart: return scroll_bar_up_arrow;
1752 case kControlDownButtonPart: return scroll_bar_down_arrow;
1753 case kControlPageUpPart: return scroll_bar_above_handle;
1754 case kControlPageDownPart: return scroll_bar_below_handle;
1755 case kControlIndicatorPart: return scroll_bar_handle;
1756 }
1757
1758 return -1;
1759}
1760
1761static void
1762construct_scroll_bar_click (bar, part, bufp)
1763 struct scroll_bar *bar;
1764 int part;
1765 struct input_event *bufp;
1766{
1767 bufp->kind = SCROLL_BAR_CLICK_EVENT;
1768 bufp->frame_or_window = bar->window;
1769 bufp->arg = Qnil;
1770 bufp->part = part;
1771 bufp->code = 0;
1772 XSETINT (bufp->x, 0);
1773 XSETINT (bufp->y, 0);
1774 bufp->modifiers = 0;
1775}
1776
1777static OSStatus
1778get_control_part_bounds (ch, part_code, rect)
1779 ControlRef ch;
1780 ControlPartCode part_code;
1781 Rect *rect;
1782{
1783 RgnHandle region = NewRgn ();
1784 OSStatus err;
1785
1786 err = GetControlRegion (ch, part_code, region);
1787 if (err == noErr)
1788 GetRegionBounds (region, rect);
1789 DisposeRgn (region);
1790
1791 return err;
1792}
1793
1794static void
1795x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp)
1796 struct scroll_bar *bar;
1797 ControlPartCode part_code;
1798 Point mouse_pos;
1799 struct input_event *bufp;
1800{
1801 int part = control_part_code_to_scroll_bar_part (part_code);
1802
1803 if (part < 0)
1804 return;
1805
1806 if (part != scroll_bar_handle)
1807 {
1808 construct_scroll_bar_click (bar, part, bufp);
1809 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
1810 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
1811 bar->dragging = Qnil;
1812 }
1813 else
1814 {
1815 Rect r;
1816
1817 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
1818 kControlIndicatorPart, &r);
1819 XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1);
1820 }
1821
1822 last_scroll_bar_part = part;
1823 tracked_scroll_bar = bar;
1824}
1825
1826static void
1827x_scroll_bar_handle_release (bar, bufp)
1828 struct scroll_bar *bar;
1829 struct input_event *bufp;
1830{
1831 if (last_scroll_bar_part != scroll_bar_handle
1832 || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0))
1833 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
1834
1835 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
1836 set_scroll_bar_timer (kEventDurationForever);
1837
1838 last_scroll_bar_part = -1;
1839 bar->dragging = Qnil;
1840 tracked_scroll_bar = NULL;
1841}
1842
1843static void
1844x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
1845 WindowRef win;
1846 struct scroll_bar *bar;
1847 Point mouse_pos;
1848 struct input_event *bufp;
1849{
1850 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
1851
1852 if (last_scroll_bar_part == scroll_bar_handle)
1853 {
1854 int top, top_range;
1855 Rect r;
1856
1857 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
1858 kControlIndicatorPart, &r);
1859
1860 if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0)
1861 XSETINT (bar->dragging, - (XINT (bar->dragging) + 1));
1862
1863 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
1864 top_range = XINT (bar->track_height) - XINT (bar->min_handle);
1865
1866 if (top < 0)
1867 top = 0;
1868 if (top > top_range)
1869 top = top_range;
1870
1871 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
1872 XSETINT (bufp->x, top);
1873 XSETINT (bufp->y, top_range);
1874 }
1875 else
1876 {
1877 ControlPartCode part_code;
1878 int unhilite_p = 0, part;
1879
1880 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
1881 unhilite_p = 1;
1882 else
1883 {
1884 part = control_part_code_to_scroll_bar_part (part_code);
1885
1886 switch (last_scroll_bar_part)
1887 {
1888 case scroll_bar_above_handle:
1889 case scroll_bar_below_handle:
1890 if (part != scroll_bar_above_handle
1891 && part != scroll_bar_below_handle)
1892 unhilite_p = 1;
1893 break;
1894
1895 case scroll_bar_up_arrow:
1896 case scroll_bar_down_arrow:
1897 if (part != scroll_bar_up_arrow
1898 && part != scroll_bar_down_arrow)
1899 unhilite_p = 1;
1900 break;
1901 }
1902 }
1903
1904 if (unhilite_p)
1905 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
1906 else if (part != last_scroll_bar_part
1907 || scroll_bar_timer_event_posted_p)
1908 {
1909 construct_scroll_bar_click (bar, part, bufp);
1910 last_scroll_bar_part = part;
1911 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
1912 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
1913 }
1914 }
1915}
1916
1917/* Update BAR->track_top, BAR->track_height, and BAR->min_handle for
1918 the scroll bar BAR. This function should be called when the bounds
1919 of the scroll bar is changed. */
1920
1921static void
1922update_scroll_bar_track_info (bar)
1923 struct scroll_bar *bar;
1924{
1925 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
1926 Rect r0, r1;
1927
1928 GetControlBounds (ch, &r0);
1929
1930 if (r0.right - r0.left >= r0.bottom - r0.top
1931#ifdef MAC_OSX
1932 || r0.right - r0.left < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
1933#endif
1934 )
1935 {
1936 XSETINT (bar->track_top, 0);
1937 XSETINT (bar->track_height, 0);
1938 XSETINT (bar->min_handle, 0);
1939 }
1940 else
1941 {
1942 BLOCK_INPUT;
1943
1944 SetControl32BitMinimum (ch, 0);
1945 SetControl32BitMaximum (ch, 1 << 30);
1946 SetControlViewSize (ch, 1);
1947
1948 /* Move the scroll bar thumb to the top. */
1949 SetControl32BitValue (ch, 0);
1950 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
1951
1952 /* Move the scroll bar thumb to the bottom. */
1953 SetControl32BitValue (ch, 1 << 30);
1954 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
1955
1956 UnionRect (&r0, &r1, &r0);
1957 XSETINT (bar->track_top, r0.top);
1958 XSETINT (bar->track_height, r0.bottom - r0.top);
1959 XSETINT (bar->min_handle, r1.bottom - r1.top);
1960
1961 /* Don't show the scroll bar if its height is not enough to
1962 display the scroll bar thumb. */
1963 if (r0.bottom - r0.top > 0)
1964 ShowControl (ch);
1965
1966 UNBLOCK_INPUT;
1967 }
1968}
1969
1970/* Set the thumb size and position of scroll bar BAR. We are currently
1971 displaying PORTION out of a whole WHOLE, and our position POSITION. */
1972
1973void
1974x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
1975 struct scroll_bar *bar;
1976 int portion, position, whole;
1977{
1978 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
1979 int value, viewsize, maximum;
1980
1981 if (XINT (bar->track_height) == 0)
1982 return;
1983
1984 if (whole <= portion)
1985 value = 0, viewsize = 1, maximum = 0;
1986 else
1987 {
1988 float scale;
1989
1990 maximum = XINT (bar->track_height) - XINT (bar->min_handle);
1991 scale = (float) maximum / (whole - portion);
1992 value = position * scale + 0.5f;
1993 viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle);
1994 }
1995
1996 BLOCK_INPUT;
1997
1998 if (GetControlViewSize (ch) != viewsize
1999 || GetControl32BitValue (ch) != value
2000 || GetControl32BitMaximum (ch) != maximum)
2001 {
2002 /* Temporarily hide the scroll bar to avoid multiple redraws. */
2003 SetControlVisibility (ch, false, false);
2004
2005 SetControl32BitMaximum (ch, maximum);
2006 SetControl32BitValue (ch, value);
2007 SetControlViewSize (ch, viewsize);
2008
2009 SetControlVisibility (ch, true, true);
2010 }
2011
2012 UNBLOCK_INPUT;
2013}
2014
2015#endif /* USE_TOOLKIT_SCROLL_BARS */
2016
2017/* Create a scroll bar control for BAR. BOUNDS and VISIBLE specifies
2018 the initial geometry and visibility, respectively. The created
2019 control is stored in some members of BAR. */
2020
2021void
2022mac_create_scroll_bar (bar, bounds, visible)
2023 struct scroll_bar *bar;
2024 const Rect *bounds;
2025 Boolean visible;
2026{
2027 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2028 ControlRef ch;
2029
2030#if USE_CG_DRAWING
2031 mac_prepare_for_quickdraw (f);
2032#endif
2033 ch = NewControl (FRAME_MAC_WINDOW (f), bounds, "\p", visible, 0, 0, 0,
2034#if TARGET_API_MAC_CARBON
2035 kControlScrollBarProc,
2036#else
2037 scrollBarProc,
2038#endif
2039 (SInt32) bar);
2040 SET_SCROLL_BAR_CONTROL_REF (bar, ch);
2041
2042 XSETINT (bar->start, 0);
2043 XSETINT (bar->end, 0);
2044 bar->dragging = Qnil;
2045
2046#ifdef USE_TOOLKIT_SCROLL_BARS
2047 update_scroll_bar_track_info (bar);
2048#endif
2049}
2050
2051/* Dispose of the scroll bar control stored in some members of
2052 BAR. */
2053
2054void
2055mac_dispose_scroll_bar (bar)
2056 struct scroll_bar *bar;
2057{
2058#if USE_CG_DRAWING
2059 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2060
2061 mac_prepare_for_quickdraw (f);
2062#endif
2063 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
2064}
2065
2066/* Set bounds of the scroll bar BAR to BOUNDS. */
2067
2068void
2069mac_set_scroll_bar_bounds (bar, bounds)
2070 struct scroll_bar *bar;
2071 const Rect *bounds;
2072{
2073 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2074 SInt16 width, height;
2075#if USE_CG_DRAWING
2076 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2077
2078 mac_prepare_for_quickdraw (f);
2079#endif
2080
2081 width = bounds->right - bounds->left;
2082 height = bounds->bottom - bounds->top;
2083 HideControl (ch);
2084 MoveControl (ch, bounds->left, bounds->top);
2085 SizeControl (ch, width, height);
2086#ifdef USE_TOOLKIT_SCROLL_BARS
2087 update_scroll_bar_track_info (bar);
2088#else
2089 if (width < height)
2090 ShowControl (ch);
2091#endif
2092}
2093
2094/* Draw the scroll bar BAR. */
2095
2096void
2097mac_redraw_scroll_bar (bar)
2098 struct scroll_bar *bar;
2099{
2100#if USE_CG_DRAWING
2101 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2102
2103 mac_prepare_for_quickdraw (f);
2104#endif
2105 Draw1Control (SCROLL_BAR_CONTROL_REF (bar));
2106}
2107
2108/* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2109 is set to something other than NO_EVENT, it is enqueued.
2110
2111 This may be called from a signal handler, so we have to ignore GC
2112 mark bits. */
2113
2114static void
2115x_scroll_bar_handle_click (bar, part_code, er, bufp)
2116 struct scroll_bar *bar;
2117 ControlPartCode part_code;
2118 const EventRecord *er;
2119 struct input_event *bufp;
2120{
2121 int win_y, top_range;
2122
2123 if (! GC_WINDOWP (bar->window))
2124 abort ();
2125
2126 bufp->kind = SCROLL_BAR_CLICK_EVENT;
2127 bufp->frame_or_window = bar->window;
2128 bufp->arg = Qnil;
2129
2130 bar->dragging = Qnil;
2131
2132 switch (part_code)
2133 {
2134 case kControlUpButtonPart:
2135 bufp->part = scroll_bar_up_arrow;
2136 break;
2137 case kControlDownButtonPart:
2138 bufp->part = scroll_bar_down_arrow;
2139 break;
2140 case kControlPageUpPart:
2141 bufp->part = scroll_bar_above_handle;
2142 break;
2143 case kControlPageDownPart:
2144 bufp->part = scroll_bar_below_handle;
2145 break;
2146#if TARGET_API_MAC_CARBON
2147 default:
2148#else
2149 case kControlIndicatorPart:
2150#endif
2151 if (er->what == mouseDown)
2152 bar->dragging = make_number (0);
2153 XSETVECTOR (last_mouse_scroll_bar, bar);
2154 bufp->part = scroll_bar_handle;
2155 break;
2156 }
2157
2158 win_y = XINT (bufp->y) - XINT (bar->top);
2159 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
2160
2161 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2162
2163 win_y -= 24;
2164
2165 if (! NILP (bar->dragging))
2166 win_y -= XINT (bar->dragging);
2167
2168 if (win_y < 0)
2169 win_y = 0;
2170 if (win_y > top_range)
2171 win_y = top_range;
2172
2173 XSETINT (bufp->x, win_y);
2174 XSETINT (bufp->y, top_range);
2175}
2176
2177/* Return information to the user about the current position of the mouse
2178 on the scroll bar. */
2179
2180void
2181x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
2182 FRAME_PTR *fp;
2183 Lisp_Object *bar_window;
2184 enum scroll_bar_part *part;
2185 Lisp_Object *x, *y;
2186 unsigned long *time;
2187{
2188 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
2189 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2190#if TARGET_API_MAC_CARBON
2191 WindowRef wp = GetControlOwner (ch);
2192#else
2193 WindowRef wp = (*ch)->contrlOwner;
2194#endif
2195 Point mouse_pos;
2196 struct frame *f = mac_window_to_frame (wp);
2197 int win_y, top_range;
2198
2199#if TARGET_API_MAC_CARBON
2200 GetGlobalMouse (&mouse_pos);
2201 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
2202 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
2203#else
2204 SetPortWindowPort (wp);
2205 GetMouse (&mouse_pos);
2206#endif
2207
2208 win_y = mouse_pos.v - XINT (bar->top);
2209 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
2210
2211 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2212
2213 win_y -= 24;
2214
2215 if (! NILP (bar->dragging))
2216 win_y -= XINT (bar->dragging);
2217
2218 if (win_y < 0)
2219 win_y = 0;
2220 if (win_y > top_range)
2221 win_y = top_range;
2222
2223 *fp = f;
2224 *bar_window = bar->window;
2225
2226 if (! NILP (bar->dragging))
2227 *part = scroll_bar_handle;
2228 else if (win_y < XINT (bar->start))
2229 *part = scroll_bar_above_handle;
2230 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2231 *part = scroll_bar_handle;
2232 else
2233 *part = scroll_bar_below_handle;
2234
2235 XSETINT (*x, win_y);
2236 XSETINT (*y, top_range);
2237
2238 f->mouse_moved = 0;
2239 last_mouse_scroll_bar = Qnil;
2240
2241 *time = last_mouse_movement_time;
2242}
2243
2244#ifndef USE_TOOLKIT_SCROLL_BARS
2245/* Draw BAR's handle in the proper position.
2246
2247 If the handle is already drawn from START to END, don't bother
2248 redrawing it, unless REBUILD is non-zero; in that case, always
2249 redraw it. (REBUILD is handy for drawing the handle after expose
2250 events.)
2251
2252 Normally, we want to constrain the start and end of the handle to
2253 fit inside its rectangle, but if the user is dragging the scroll
2254 bar handle, we want to let them drag it down all the way, so that
2255 the bar's top is as far down as it goes; otherwise, there's no way
2256 to move to the very end of the buffer. */
2257
2258void
2259x_scroll_bar_set_handle (bar, start, end, rebuild)
2260 struct scroll_bar *bar;
2261 int start, end;
2262 int rebuild;
2263{
2264 int dragging = ! NILP (bar->dragging);
2265 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2266 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2267 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
2268 int length = end - start;
2269
2270 /* If the display is already accurate, do nothing. */
2271 if (! rebuild
2272 && start == XINT (bar->start)
2273 && end == XINT (bar->end))
2274 return;
2275
2276 BLOCK_INPUT;
2277
2278 /* Make sure the values are reasonable, and try to preserve the
2279 distance between start and end. */
2280 if (start < 0)
2281 start = 0;
2282 else if (start > top_range)
2283 start = top_range;
2284 end = start + length;
2285
2286 if (end < start)
2287 end = start;
2288 else if (end > top_range && ! dragging)
2289 end = top_range;
2290
2291 /* Store the adjusted setting in the scroll bar. */
2292 XSETINT (bar->start, start);
2293 XSETINT (bar->end, end);
2294
2295 /* Clip the end position, just for display. */
2296 if (end > top_range)
2297 end = top_range;
2298
2299 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
2300 top positions, to make sure the handle is always at least that
2301 many pixels tall. */
2302 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
2303
2304 SetControlMinimum (ch, 0);
2305 /* Don't inadvertently activate deactivated scroll bars */
2306 if (GetControlMaximum (ch) != -1)
2307 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
2308 - (end - start));
2309 SetControlValue (ch, start);
2310#if TARGET_API_MAC_CARBON
2311 SetControlViewSize (ch, end - start);
2312#endif
2313
2314 UNBLOCK_INPUT;
2315}
2316
2317/* Handle some mouse motion while someone is dragging the scroll bar.
2318
2319 This may be called from a signal handler, so we have to ignore GC
2320 mark bits. */
2321
2322static void
2323x_scroll_bar_note_movement (bar, y_pos, t)
2324 struct scroll_bar *bar;
2325 int y_pos;
2326 Time t;
2327{
2328 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
2329
2330 last_mouse_movement_time = t;
2331
2332 f->mouse_moved = 1;
2333 XSETVECTOR (last_mouse_scroll_bar, bar);
2334
2335 /* If we're dragging the bar, display it. */
2336 if (! GC_NILP (bar->dragging))
2337 {
2338 /* Where should the handle be now? */
2339 int new_start = y_pos - 24;
2340
2341 if (new_start != XINT (bar->start))
2342 {
2343 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2344
2345 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2346 }
2347 }
2348}
2349#endif /* !USE_TOOLKIT_SCROLL_BARS */
2350
2351
2352/***********************************************************************
2353 Tool-bars
2354 ***********************************************************************/
2355
2356#if USE_MAC_TOOLBAR
2357/* In identifiers such as function/variable names, Emacs tool bar is
2358 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
2359
2360#define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
2361#define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
2362
2363#define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
2364#define TOOLBAR_ITEM_COMMAND_ID_P(id) \
2365 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2366#define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
2367 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2368#define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
2369 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2370
2371static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
2372 EventRef, void *));
2373
2374extern Rect last_mouse_glyph;
2375
2376extern void mac_move_window_with_gravity P_ ((struct frame *, int,
2377 short, short));
2378extern void mac_get_window_origin_with_gravity P_ ((struct frame *, int,
2379 short *, short *));
2380extern CGImageRef mac_image_spec_to_cg_image P_ ((struct frame *,
2381 Lisp_Object));
2382
2383static OSStatus
2384mac_handle_toolbar_event (next_handler, event, data)
2385 EventHandlerCallRef next_handler;
2386 EventRef event;
2387 void *data;
2388{
2389 OSStatus result = eventNotHandledErr;
2390
2391 switch (GetEventKind (event))
2392 {
2393 case kEventToolbarGetDefaultIdentifiers:
2394 result = noErr;
2395 break;
2396
2397 case kEventToolbarGetAllowedIdentifiers:
2398 {
2399 CFMutableArrayRef array;
2400
2401 GetEventParameter (event, kEventParamMutableArray,
2402 typeCFMutableArrayRef, NULL,
2403 sizeof (CFMutableArrayRef), NULL, &array);
2404 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
2405 result = noErr;
2406 }
2407 break;
2408
2409 case kEventToolbarCreateItemWithIdentifier:
2410 {
2411 CFStringRef identifier;
2412 HIToolbarItemRef item = NULL;
2413
2414 GetEventParameter (event, kEventParamToolbarItemIdentifier,
2415 typeCFStringRef, NULL,
2416 sizeof (CFStringRef), NULL, &identifier);
2417
2418 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
2419 == kCFCompareEqualTo)
2420 HIToolbarItemCreate (identifier,
2421 kHIToolbarItemAllowDuplicates
2422 | kHIToolbarItemCantBeRemoved, &item);
2423
2424 if (item)
2425 {
2426 SetEventParameter (event, kEventParamToolbarItem,
2427 typeHIToolbarItemRef,
2428 sizeof (HIToolbarItemRef), &item);
2429 result = noErr;
2430 }
2431 }
2432 break;
2433
2434 default:
2435 abort ();
2436 }
2437
2438 return result;
2439}
2440
2441/* Create a tool bar for frame F. */
2442
2443static OSStatus
2444mac_create_frame_tool_bar (f)
2445 FRAME_PTR f;
2446{
2447 OSStatus err;
2448 HIToolbarRef toolbar;
2449
2450 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
2451 &toolbar);
2452 if (err == noErr)
2453 {
2454 static const EventTypeSpec specs[] =
2455 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
2456 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
2457 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
2458
2459 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
2460 mac_handle_toolbar_event,
2461 GetEventTypeCount (specs), specs,
2462 f, NULL);
2463 }
2464
2465 if (err == noErr)
2466 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
2467 if (err == noErr)
2468 {
2469 static const EventTypeSpec specs[] =
2470 {{kEventClassCommand, kEventCommandProcess}};
2471
2472 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
2473 mac_handle_toolbar_command_event,
2474 GetEventTypeCount (specs),
2475 specs, f, NULL);
2476 }
2477 if (err == noErr)
2478 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
2479
2480 if (toolbar)
2481 CFRelease (toolbar);
2482
2483 return err;
2484}
2485
2486/* Update the tool bar for frame F. Add new buttons and remove old. */
2487
2488void
2489update_frame_tool_bar (f)
2490 FRAME_PTR f;
2491{
2492 HIToolbarRef toolbar = NULL;
2493 short left, top;
2494 CFArrayRef old_items = NULL;
2495 CFIndex old_count;
2496 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
2497 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2498
2499 BLOCK_INPUT;
2500
2501 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
2502 if (toolbar == NULL)
2503 {
2504 mac_create_frame_tool_bar (f);
2505 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
2506 if (toolbar == NULL)
2507 goto out;
2508 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
2509 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
2510 }
2511
2512 HIToolbarCopyItems (toolbar, &old_items);
2513 if (old_items == NULL)
2514 goto out;
2515
2516 old_count = CFArrayGetCount (old_items);
2517 pos = 0;
2518 for (i = 0; i < f->n_tool_bar_items; ++i)
2519 {
2520#define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
2521
2522 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
2523 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
2524 int idx;
2525 Lisp_Object image;
2526 CGImageRef cg_image;
2527 CFStringRef label;
2528 HIToolbarItemRef item;
2529
2530 /* If image is a vector, choose the image according to the
2531 button state. */
2532 image = PROP (TOOL_BAR_ITEM_IMAGES);
2533 if (VECTORP (image))
2534 {
2535 if (enabled_p)
2536 idx = (selected_p
2537 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
2538 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
2539 else
2540 idx = (selected_p
2541 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
2542 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
2543
2544 xassert (ASIZE (image) >= idx);
2545 image = AREF (image, idx);
2546 }
2547 else
2548 idx = -1;
2549
2550 cg_image = mac_image_spec_to_cg_image (f, image);
2551 /* Ignore invalid image specifications. */
2552 if (cg_image == NULL)
2553 continue;
2554
2555 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
2556 if (label == NULL)
2557 label = CFSTR ("");
2558
2559 if (pos < old_count)
2560 {
2561 CGImageRef old_cg_image = NULL;
2562 CFStringRef old_label = NULL;
2563 Boolean old_enabled_p;
2564
2565 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
2566
2567 HIToolbarItemCopyImage (item, &old_cg_image);
2568 if (cg_image != old_cg_image)
2569 HIToolbarItemSetImage (item, cg_image);
2570 CGImageRelease (old_cg_image);
2571
2572 HIToolbarItemCopyLabel (item, &old_label);
2573 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
2574 HIToolbarItemSetLabel (item, label);
2575 CFRelease (old_label);
2576
2577 old_enabled_p = HIToolbarItemIsEnabled (item);
2578 if ((enabled_p || idx >= 0) != old_enabled_p)
2579 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
2580 }
2581 else
2582 {
2583 item = NULL;
2584 HIToolbarCreateItemWithIdentifier (toolbar,
2585 TOOLBAR_ICON_ITEM_IDENTIFIER,
2586 NULL, &item);
2587 if (item)
2588 {
2589 HIToolbarItemSetImage (item, cg_image);
2590 HIToolbarItemSetLabel (item, label);
2591 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
2592 HIToolbarAppendItem (toolbar, item);
2593 CFRelease (item);
2594 }
2595 }
2596
2597 CFRelease (label);
2598 if (item)
2599 {
2600 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
2601 pos++;
2602 }
2603 }
2604
2605 CFRelease (old_items);
2606
2607 while (pos < old_count)
2608 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
2609
2610 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
2611 !win_gravity && f == mac_focus_frame (dpyinfo));
2612 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
2613 toolbar visibility change. */
2614 mac_handle_origin_change (f);
2615 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
2616 {
2617 mac_move_window_with_gravity (f, win_gravity, left, top);
2618 /* If the title bar is completely outside the screen, adjust the
2619 position. */
2620 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
2621 kWindowConstrainMoveRegardlessOfFit
2622 | kWindowConstrainAllowPartial, NULL, NULL);
2623 f->output_data.mac->toolbar_win_gravity = 0;
2624 }
2625
2626 out:
2627 UNBLOCK_INPUT;
2628}
2629
2630/* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
2631 doesn't deallocate the resources. */
2632
2633void
2634free_frame_tool_bar (f)
2635 FRAME_PTR f;
2636{
2637 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
2638 {
2639 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2640
2641 BLOCK_INPUT;
2642 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
2643 (NILP (find_symbol_value
2644 (intern ("frame-notice-user-settings")))
2645 && f == mac_focus_frame (dpyinfo)));
2646 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
2647 on toolbar visibility change. */
2648 mac_handle_origin_change (f);
2649 UNBLOCK_INPUT;
2650 }
2651}
2652
2653/* Report a mouse movement over toolbar to the mainstream Emacs
2654 code. */
2655
2656static void
2657mac_tool_bar_note_mouse_movement (f, event)
2658 struct frame *f;
2659 EventRef event;
2660{
2661 OSStatus err;
2662 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2663 int mouse_down_p;
2664 WindowRef window;
2665 WindowPartCode part_code;
2666 HIViewRef item_view;
2667 UInt32 command_id;
2668
2669 mouse_down_p = (dpyinfo->grabbed
2670 && f == last_mouse_frame
2671 && FRAME_LIVE_P (f));
2672 if (mouse_down_p)
2673 return;
2674
2675 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef, NULL,
2676 sizeof (WindowRef), NULL, &window);
2677 if (err != noErr || window != FRAME_MAC_WINDOW (f))
2678 return;
2679
2680 err = GetEventParameter (event, kEventParamWindowPartCode,
2681 typeWindowPartCode, NULL,
2682 sizeof (WindowPartCode), NULL, &part_code);
2683 if (err != noErr || part_code != inStructure)
2684 return;
2685
2686 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window), event, &item_view);
2687 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
2688 toolbar item view seems to have the same command ID with that of
2689 the toolbar item. */
2690 if (err == noErr)
2691 err = GetControlCommandID (item_view, &command_id);
2692 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
2693 {
2694 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
2695
2696 if (i < f->n_tool_bar_items)
2697 {
2698 HIRect bounds;
2699 HIViewRef content_view;
2700
2701 err = HIViewGetBounds (item_view, &bounds);
2702 if (err == noErr)
2703 err = HIViewFindByID (HIViewGetRoot (window),
2704 kHIViewWindowContentID, &content_view);
2705 if (err == noErr)
2706 err = HIViewConvertRect (&bounds, item_view, content_view);
2707 if (err == noErr)
2708 SetRect (&last_mouse_glyph,
2709 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
2710 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
2711
2712 help_echo_object = help_echo_window = Qnil;
2713 help_echo_pos = -1;
2714 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
2715 if (NILP (help_echo_string))
2716 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
2717 }
2718 }
2719}
2720
2721static OSStatus
2722mac_handle_toolbar_command_event (next_handler, event, data)
2723 EventHandlerCallRef next_handler;
2724 EventRef event;
2725 void *data;
2726{
2727 OSStatus err, result = eventNotHandledErr;
2728 struct frame *f = (struct frame *) data;
2729 HICommand command;
2730
2731 err = GetEventParameter (event, kEventParamDirectObject,
2732 typeHICommand, NULL,
2733 sizeof (HICommand), NULL, &command);
2734 if (err != noErr)
2735 return result;
2736
2737 switch (GetEventKind (event))
2738 {
2739 case kEventCommandProcess:
2740 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
2741 result = CallNextEventHandler (next_handler, event);
2742 else
2743 {
2744 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
2745
2746 if (i < f->n_tool_bar_items
2747 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
2748 {
2749 Lisp_Object frame;
2750 struct input_event buf;
2751
2752 EVENT_INIT (buf);
2753
2754 XSETFRAME (frame, f);
2755 buf.kind = TOOL_BAR_EVENT;
2756 buf.frame_or_window = frame;
2757 buf.arg = frame;
2758 kbd_buffer_store_event (&buf);
2759
2760 buf.kind = TOOL_BAR_EVENT;
2761 buf.frame_or_window = frame;
2762 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
2763 buf.modifiers = mac_event_to_emacs_modifiers (event);
2764 kbd_buffer_store_event (&buf);
2765
2766 result = noErr;
2767 }
2768 }
2769 break;
2770
2771 default:
2772 abort ();
2773 }
2774#undef PROP
2775
2776 return result;
2777}
2778#endif /* USE_MAC_TOOLBAR */
2779
2780
2781/***********************************************************************
2782 Font Panel
2783 ***********************************************************************/
2784
2785#if USE_MAC_FONT_PANEL
2786/* Whether Font Panel has been shown before. The first call to font
2787 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
2788 slow. This variable is used for deferring such a call as much as
2789 possible. */
2790static int font_panel_shown_p = 0;
2791
2792extern Lisp_Object Qpanel_closed, Qselection;
2793extern Lisp_Object Qfont;
2794
2795/* Whether the font panel is currently visible. */
2796
2797int
2798mac_font_panel_visible_p ()
2799{
2800 return font_panel_shown_p && FPIsFontPanelVisible ();
2801}
2802
2803static pascal OSStatus
2804mac_handle_font_event (next_handler, event, data)
2805 EventHandlerCallRef next_handler;
2806 EventRef event;
2807 void *data;
2808{
2809 OSStatus result, err;
2810 Lisp_Object id_key;
2811 int num_params;
2812 const EventParamName *names;
2813 const EventParamType *types;
2814 static const EventParamName names_sel[] = {kEventParamATSUFontID,
2815 kEventParamATSUFontSize,
2816 kEventParamFMFontFamily,
2817 kEventParamFMFontStyle,
2818 kEventParamFMFontSize,
2819 kEventParamFontColor};
2820 static const EventParamType types_sel[] = {typeATSUFontID,
2821 typeATSUSize,
2822 typeFMFontFamily,
2823 typeFMFontStyle,
2824 typeFMFontSize,
2825 typeFontColor};
2826
2827 result = CallNextEventHandler (next_handler, event);
2828 if (result != eventNotHandledErr)
2829 return result;
2830
2831 switch (GetEventKind (event))
2832 {
2833 case kEventFontPanelClosed:
2834 id_key = Qpanel_closed;
2835 num_params = 0;
2836 names = NULL;
2837 types = NULL;
2838 break;
2839
2840 case kEventFontSelection:
2841 id_key = Qselection;
2842 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
2843 names = names_sel;
2844 types = types_sel;
2845 break;
2846 }
2847
2848 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
2849 event, num_params,
2850 names, types);
2851 if (err == noErr)
2852 result = noErr;
2853
2854 return result;
2855}
2856
2857/* Toggle visiblity of the font panel. */
2858
2859OSStatus
2860mac_show_hide_font_panel ()
2861{
2862 if (!font_panel_shown_p)
2863 {
2864 OSStatus err;
2865
2866 static const EventTypeSpec specs[] =
2867 {{kEventClassFont, kEventFontPanelClosed},
2868 {kEventClassFont, kEventFontSelection}};
2869
2870 err = InstallApplicationEventHandler (mac_handle_font_event,
2871 GetEventTypeCount (specs),
2872 specs, NULL, NULL);
2873 if (err != noErr)
2874 return err;
2875
2876 font_panel_shown_p = 1;
2877 }
2878
2879 return FPShowHideFontPanel ();
2880}
2881
2882/* Set the font selected in the font panel to the one corresponding to
2883 the face FACE_ID and the charcacter C in the frame F. */
2884
2885OSStatus
2886mac_set_font_info_for_selection (f, face_id, c)
2887 struct frame *f;
2888 int face_id, c;
2889{
2890 OSStatus err;
2891 EventTargetRef target = NULL;
2892 XFontStruct *font = NULL;
2893
2894 if (!mac_font_panel_visible_p ())
2895 return noErr;
2896
2897 if (f)
2898 {
2899 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
2900
2901 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
2902 {
2903 struct face *face;
2904
2905 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
2906 face = FACE_FROM_ID (f, face_id);
2907 font = face->font;
2908 }
2909 }
2910
2911 if (font == NULL)
2912 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
2913 else
2914 {
2915 if (font->mac_fontnum != -1)
2916 {
2917 FontSelectionQDStyle qd_style;
2918
2919 qd_style.version = kFontSelectionQDStyleVersionZero;
2920 qd_style.instance.fontFamily = font->mac_fontnum;
2921 qd_style.instance.fontStyle = font->mac_fontface;
2922 qd_style.size = font->mac_fontsize;
2923 qd_style.hasColor = false;
2924
2925 err = SetFontInfoForSelection (kFontSelectionQDType,
2926 1, &qd_style, target);
2927 }
2928 else
2929 err = SetFontInfoForSelection (kFontSelectionATSUIType,
2930 1, &font->mac_style, target);
2931 }
2932
2933 return err;
2934}
2935#endif /* USE_MAC_FONT_PANEL */
2936
2937
2938/************************************************************************
2939 Event Handling
2940 ************************************************************************/
2941
2942/* Non-zero means that a HELP_EVENT has been generated since Emacs
2943 start. */
2944
2945static int any_help_event_p;
2946
2947/* Last window where we saw the mouse. Used by mouse-autoselect-window. */
2948static Lisp_Object last_window;
2949
2950static Point saved_menu_event_location;
2951
2952extern struct frame *pending_autoraise_frame;
2953
2954extern FRAME_PTR last_mouse_glyph_frame;
2955
2956#ifdef __STDC__
2957extern int volatile input_signal_count;
2958#else
2959extern int input_signal_count;
2960#endif
2961
2962extern int mac_screen_config_changed;
2963
2964extern Lisp_Object Vmac_emulate_three_button_mouse;
2965#if TARGET_API_MAC_CARBON
2966extern int mac_wheel_button_is_mouse_2;
2967extern int mac_pass_command_to_system;
2968extern int mac_pass_control_to_system;
2969#endif /* TARGET_API_MAC_CARBON */
2970extern int mac_ready_for_apple_events;
2971
2972extern void mac_focus_changed P_ ((int, struct mac_display_info *,
2973 struct frame *, struct input_event *));
2974extern int mac_get_emulated_btn P_ ((UInt32));
2975extern int note_mouse_movement P_ ((FRAME_PTR, Point *));
2976extern void mac_get_screen_info P_ ((struct mac_display_info *));
2977
2978/* The focus may have changed. Figure out if it is a real focus change,
2979 by checking both FocusIn/Out and Enter/LeaveNotify events.
2980
2981 Returns FOCUS_IN_EVENT event in *BUFP. */
2982
2983static void
2984x_detect_focus_change (dpyinfo, event, bufp)
2985 struct mac_display_info *dpyinfo;
2986 const EventRecord *event;
2987 struct input_event *bufp;
2988{
2989 struct frame *frame;
2990
2991 frame = mac_window_to_frame ((WindowRef) event->message);
2992 if (! frame)
2993 return;
2994
2995 /* On Mac, this is only called from focus events, so no switch needed. */
2996 mac_focus_changed ((event->modifiers & activeFlag),
2997 dpyinfo, frame, bufp);
2998}
2999
3000#if TARGET_API_MAC_CARBON
3001/* Obtains the event modifiers from the event EVENTREF and then calls
3002 mac_to_emacs_modifiers. */
3003
3004static int
3005mac_event_to_emacs_modifiers (EventRef eventRef)
3006{
3007 UInt32 mods = 0, class;
3008
3009 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
3010 sizeof (UInt32), NULL, &mods);
3011 class = GetEventClass (eventRef);
3012 if (!NILP (Vmac_emulate_three_button_mouse) &&
3013 (class == kEventClassMouse || class == kEventClassCommand))
3014 {
3015 mods &= ~(optionKey | cmdKey);
3016 }
3017 return mac_to_emacs_modifiers (mods, 0);
3018}
3019
3020/* Given an event REF, return the code to use for the mouse button
3021 code in the emacs input_event. */
3022
3023static int
3024mac_get_mouse_btn (EventRef ref)
3025{
3026 EventMouseButton result = kEventMouseButtonPrimary;
3027 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
3028 sizeof (EventMouseButton), NULL, &result);
3029 switch (result)
3030 {
3031 case kEventMouseButtonPrimary:
3032 if (NILP (Vmac_emulate_three_button_mouse))
3033 return 0;
3034 else {
3035 UInt32 mods = 0;
3036 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
3037 sizeof (UInt32), NULL, &mods);
3038 return mac_get_emulated_btn(mods);
3039 }
3040 case kEventMouseButtonSecondary:
3041 return mac_wheel_button_is_mouse_2 ? 2 : 1;
3042 case kEventMouseButtonTertiary:
3043 case 4: /* 4 is the number for the mouse wheel button */
3044 return mac_wheel_button_is_mouse_2 ? 1 : 2;
3045 default:
3046 return 0;
3047 }
3048}
3049
3050/* Normally, ConvertEventRefToEventRecord will correctly handle all
3051 events. However the click of the mouse wheel is not converted to a
3052 mouseDown or mouseUp event. Likewise for dead key events. This
3053 calls ConvertEventRefToEventRecord, but then checks to see if it is
3054 a mouse up/down, or a dead key Carbon event that has not been
3055 converted, and if so, converts it by hand (to be picked up in the
3056 XTread_socket loop). */
3057static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
3058{
3059 OSStatus err;
3060 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
3061 EventKind action;
3062
3063 if (result)
3064 return result;
3065
3066 switch (GetEventClass (eventRef))
3067 {
3068 case kEventClassMouse:
3069 switch (GetEventKind (eventRef))
3070 {
3071 case kEventMouseDown:
3072 eventRec->what = mouseDown;
3073 result = 1;
3074 break;
3075
3076 case kEventMouseUp:
3077 eventRec->what = mouseUp;
3078 result = 1;
3079 break;
3080
3081 default:
3082 break;
3083 }
3084 break;
3085
3086 case kEventClassKeyboard:
3087 switch (GetEventKind (eventRef))
3088 {
3089 case kEventRawKeyDown:
3090 action = keyDown;
3091 goto keystroke_common;
3092 case kEventRawKeyRepeat:
3093 action = autoKey;
3094 goto keystroke_common;
3095 case kEventRawKeyUp:
3096 action = keyUp;
3097 keystroke_common:
3098 {
3099 unsigned char char_codes;
3100 UInt32 key_code;
3101
3102 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
3103 typeChar, NULL, sizeof (char),
3104 NULL, &char_codes);
3105 if (err == noErr)
3106 err = GetEventParameter (eventRef, kEventParamKeyCode,
3107 typeUInt32, NULL, sizeof (UInt32),
3108 NULL, &key_code);
3109 if (err == noErr)
3110 {
3111 eventRec->what = action;
3112 eventRec->message = char_codes | ((key_code & 0xff) << 8);
3113 result = 1;
3114 }
3115 }
3116 break;
3117
3118 default:
3119 break;
3120 }
3121 break;
3122
3123 default:
3124 break;
3125 }
3126
3127 if (result)
3128 {
3129 /* Need where and when. */
3130 UInt32 mods = 0;
3131
3132 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
3133 NULL, sizeof (Point), NULL, &eventRec->where);
3134 /* Use two step process because new event modifiers are 32-bit
3135 and old are 16-bit. Currently, only loss is NumLock & Fn. */
3136 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
3137 NULL, sizeof (UInt32), NULL, &mods);
3138 eventRec->modifiers = mods;
3139
3140 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
3141 }
3142
3143 return result;
3144}
3145#endif /* TARGET_API_MAC_CARBON */
3146
3147#if !TARGET_API_MAC_CARBON
3148static RgnHandle mouse_region = NULL;
3149
3150Boolean
3151mac_wait_next_event (er, sleep_time, dequeue)
3152 EventRecord *er;
3153 UInt32 sleep_time;
3154 Boolean dequeue;
3155{
3156 static EventRecord er_buf = {nullEvent};
3157 UInt32 target_tick, current_tick;
3158 EventMask event_mask;
3159
3160 if (mouse_region == NULL)
3161 mouse_region = NewRgn ();
3162
3163 event_mask = everyEvent;
3164 if (!mac_ready_for_apple_events)
3165 event_mask -= highLevelEventMask;
3166
3167 current_tick = TickCount ();
3168 target_tick = current_tick + sleep_time;
3169
3170 if (er_buf.what == nullEvent)
3171 while (!WaitNextEvent (event_mask, &er_buf,
3172 target_tick - current_tick, mouse_region))
3173 {
3174 current_tick = TickCount ();
3175 if (target_tick <= current_tick)
3176 return false;
3177 }
3178
3179 *er = er_buf;
3180 if (dequeue)
3181 er_buf.what = nullEvent;
3182 return true;
3183}
3184#endif /* not TARGET_API_MAC_CARBON */
3185
3186#if TARGET_API_MAC_CARBON
3187OSStatus
3188mac_post_mouse_moved_event ()
3189{
3190 EventRef event = NULL;
3191 OSStatus err;
3192
3193 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
3194 kEventAttributeNone, &event);
3195 if (err == noErr)
3196 {
3197 Point mouse_pos;
3198
3199 GetGlobalMouse (&mouse_pos);
3200 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
3201 sizeof (Point), &mouse_pos);
3202 }
3203 if (err == noErr)
3204 {
3205 UInt32 modifiers = GetCurrentKeyModifiers ();
3206
3207 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
3208 sizeof (UInt32), &modifiers);
3209 }
3210 if (err == noErr)
3211 err = PostEventToQueue (GetCurrentEventQueue (), event,
3212 kEventPriorityStandard);
3213 if (event)
3214 ReleaseEvent (event);
3215
3216 return err;
3217}
3218#endif
3219
3220#ifdef MAC_OSX
3221/* Run the current run loop in the default mode until some input
3222 happens or TIMEOUT seconds passes unless it is negative. Return
3223 true if timeout occurs first. */
3224
3225Boolean
3226mac_run_loop_run_once (timeout)
3227 EventTimeout timeout;
3228{
3229#if USE_CG_DRAWING
3230 mac_prepare_for_quickdraw (NULL);
3231#endif
3232 return (CFRunLoopRunInMode (kCFRunLoopDefaultMode,
3233 timeout >= 0 ? timeout : 100000, true)
3234 == kCFRunLoopRunTimedOut);
3235}
3236#endif
3237
3238/* Emacs calls this whenever it wants to read an input event from the
3239 user. */
3240
3241int
3242XTread_socket (sd, expected, hold_quit)
3243 int sd, expected;
3244 struct input_event *hold_quit;
3245{
3246 struct input_event inev;
3247 int count = 0;
3248#if TARGET_API_MAC_CARBON
3249 EventRef eventRef;
3250 EventTargetRef toolbox_dispatcher;
3251#endif
3252 EventRecord er;
3253 struct mac_display_info *dpyinfo = &one_mac_display_info;
3254
3255 if (interrupt_input_blocked)
3256 {
3257 interrupt_input_pending = 1;
3258 return -1;
3259 }
3260
3261 interrupt_input_pending = 0;
3262 BLOCK_INPUT;
3263
3264 /* So people can tell when we have read the available input. */
3265 input_signal_count++;
3266
3267 ++handling_signal;
3268
3269#if TARGET_API_MAC_CARBON
3270 toolbox_dispatcher = GetEventDispatcherTarget ();
3271
3272 while (
3273#if USE_CG_DRAWING
3274 mac_prepare_for_quickdraw (NULL),
3275#endif
3276 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
3277 kEventRemoveFromQueue, &eventRef))
3278#else /* !TARGET_API_MAC_CARBON */
3279 while (mac_wait_next_event (&er, 0, true))
3280#endif /* !TARGET_API_MAC_CARBON */
3281 {
3282 int do_help = 0;
3283 struct frame *f;
3284 unsigned long timestamp;
3285
3286 EVENT_INIT (inev);
3287 inev.kind = NO_EVENT;
3288 inev.arg = Qnil;
3289
3290#if TARGET_API_MAC_CARBON
3291 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
3292
3293 if (!mac_convert_event_ref (eventRef, &er))
3294 goto OTHER;
3295#else /* !TARGET_API_MAC_CARBON */
3296 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
3297#endif /* !TARGET_API_MAC_CARBON */
3298
3299 switch (er.what)
3300 {
3301 case mouseDown:
3302 case mouseUp:
3303 {
3304 WindowRef window_ptr;
3305 ControlPartCode part_code;
3306 int tool_bar_p = 0;
3307
3308#if TARGET_API_MAC_CARBON
3309 OSStatus err;
3310
3311 /* This is needed to send mouse events like aqua window
3312 buttons to the correct handler. */
3313 read_socket_inev = &inev;
3314 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
3315 read_socket_inev = NULL;
3316 if (err != eventNotHandledErr)
3317 break;
3318#endif
3319 last_mouse_glyph_frame = 0;
3320
3321 if (dpyinfo->grabbed && last_mouse_frame
3322 && FRAME_LIVE_P (last_mouse_frame))
3323 {
3324 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
3325 part_code = inContent;
3326 }
3327 else
3328 {
3329 part_code = FindWindow (er.where, &window_ptr);
3330 if (tip_window && window_ptr == tip_window)
3331 {
3332 HideWindow (tip_window);
3333 part_code = FindWindow (er.where, &window_ptr);
3334 }
3335 }
3336
3337 if (er.what != mouseDown
3338 && (part_code != inContent || dpyinfo->grabbed == 0))
3339 break;
3340
3341 switch (part_code)
3342 {
3343 case inMenuBar:
3344 f = mac_focus_frame (dpyinfo);
3345 saved_menu_event_location = er.where;
3346 inev.kind = MENU_BAR_ACTIVATE_EVENT;
3347 XSETFRAME (inev.frame_or_window, f);
3348 break;
3349
3350 case inContent:
3351 if (
3352#if TARGET_API_MAC_CARBON
3353 FrontNonFloatingWindow ()
3354#else
3355 FrontWindow ()
3356#endif
3357 != window_ptr
3358 || (mac_window_to_frame (window_ptr)
3359 != dpyinfo->x_focus_frame))
3360 SelectWindow (window_ptr);
3361 else
3362 {
3363 ControlPartCode control_part_code;
3364 ControlRef ch;
3365 Point mouse_loc;
3366#ifdef MAC_OSX
3367 ControlKind control_kind;
3368#endif
3369
3370 f = mac_window_to_frame (window_ptr);
3371 /* convert to local coordinates of new window */
3372 mouse_loc.h = (er.where.h
3373 - (f->left_pos
3374 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
3375 mouse_loc.v = (er.where.v
3376 - (f->top_pos
3377 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
3378#if TARGET_API_MAC_CARBON
3379 ch = FindControlUnderMouse (mouse_loc, window_ptr,
3380 &control_part_code);
3381#ifdef MAC_OSX
3382 if (ch)
3383 GetControlKind (ch, &control_kind);
3384#endif
3385#else
3386 control_part_code = FindControl (mouse_loc, window_ptr,
3387 &ch);
3388#endif
3389
3390#if TARGET_API_MAC_CARBON
3391 inev.code = mac_get_mouse_btn (eventRef);
3392 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
3393#else
3394 inev.code = mac_get_emulated_btn (er.modifiers);
3395 inev.modifiers = mac_to_emacs_modifiers (er.modifiers, 0);
3396#endif
3397 XSETINT (inev.x, mouse_loc.h);
3398 XSETINT (inev.y, mouse_loc.v);
3399
3400 if ((dpyinfo->grabbed && tracked_scroll_bar)
3401 || (ch != 0
3402#ifndef USE_TOOLKIT_SCROLL_BARS
3403 /* control_part_code becomes kControlNoPart if
3404 a progress indicator is clicked. */
3405 && control_part_code != kControlNoPart
3406#else /* USE_TOOLKIT_SCROLL_BARS */
3407#ifdef MAC_OSX
3408 && control_kind.kind == kControlKindScrollBar
3409#endif /* MAC_OSX */
3410#endif /* USE_TOOLKIT_SCROLL_BARS */
3411 ))
3412 {
3413 struct scroll_bar *bar;
3414
3415 if (dpyinfo->grabbed && tracked_scroll_bar)
3416 {
3417 bar = tracked_scroll_bar;
3418#ifndef USE_TOOLKIT_SCROLL_BARS
3419 control_part_code = kControlIndicatorPart;
3420#endif
3421 }
3422 else
3423 bar = (struct scroll_bar *) GetControlReference (ch);
3424#ifdef USE_TOOLKIT_SCROLL_BARS
3425 /* Make the "Ctrl-Mouse-2 splits window" work
3426 for toolkit scroll bars. */
3427 if (inev.modifiers & ctrl_modifier)
3428 x_scroll_bar_handle_click (bar, control_part_code,
3429 &er, &inev);
3430 else if (er.what == mouseDown)
3431 x_scroll_bar_handle_press (bar, control_part_code,
3432 mouse_loc, &inev);
3433 else
3434 x_scroll_bar_handle_release (bar, &inev);
3435#else /* not USE_TOOLKIT_SCROLL_BARS */
3436 x_scroll_bar_handle_click (bar, control_part_code,
3437 &er, &inev);
3438 if (er.what == mouseDown
3439 && control_part_code == kControlIndicatorPart)
3440 tracked_scroll_bar = bar;
3441 else
3442 tracked_scroll_bar = NULL;
3443#endif /* not USE_TOOLKIT_SCROLL_BARS */
3444 }
3445 else
3446 {
3447 Lisp_Object window;
3448 int x = mouse_loc.h;
3449 int y = mouse_loc.v;
3450
3451 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
3452 if (EQ (window, f->tool_bar_window))
3453 {
3454 if (er.what == mouseDown)
3455 handle_tool_bar_click (f, x, y, 1, 0);
3456 else
3457 handle_tool_bar_click (f, x, y, 0,
3458 inev.modifiers);
3459 tool_bar_p = 1;
3460 }
3461 else
3462 {
3463 XSETFRAME (inev.frame_or_window, f);
3464 inev.kind = MOUSE_CLICK_EVENT;
3465 }
3466 }
3467
3468 if (er.what == mouseDown)
3469 {
3470 dpyinfo->grabbed |= (1 << inev.code);
3471 last_mouse_frame = f;
3472
3473 if (!tool_bar_p)
3474 last_tool_bar_item = -1;
3475 }
3476 else
3477 {
3478 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
3479 /* If a button is released though it was not
3480 previously pressed, that would be because
3481 of multi-button emulation. */
3482 dpyinfo->grabbed = 0;
3483 else
3484 dpyinfo->grabbed &= ~(1 << inev.code);
3485 }
3486
3487 /* Ignore any mouse motion that happened before
3488 this event; any subsequent mouse-movement Emacs
3489 events should reflect only motion after the
3490 ButtonPress. */
3491 if (f != 0)
3492 f->mouse_moved = 0;
3493
3494#ifdef USE_TOOLKIT_SCROLL_BARS
3495 if (inev.kind == MOUSE_CLICK_EVENT
3496 || (inev.kind == SCROLL_BAR_CLICK_EVENT
3497 && (inev.modifiers & ctrl_modifier)))
3498#endif
3499 switch (er.what)
3500 {
3501 case mouseDown:
3502 inev.modifiers |= down_modifier;
3503 break;
3504 case mouseUp:
3505 inev.modifiers |= up_modifier;
3506 break;
3507 }
3508 }
3509 break;
3510
3511 case inDrag:
3512#if TARGET_API_MAC_CARBON
3513 case inProxyIcon:
3514 if (IsWindowPathSelectClick (window_ptr, &er))
3515 {
3516 WindowPathSelect (window_ptr, NULL, NULL);
3517 break;
3518 }
3519 if (part_code == inProxyIcon
3520 && (TrackWindowProxyDrag (window_ptr, er.where)
3521 != errUserWantsToDragWindow))
3522 break;
3523 DragWindow (window_ptr, er.where, NULL);
3524#else /* not TARGET_API_MAC_CARBON */
3525 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
3526 /* Update the frame parameters. */
3527 {
3528 struct frame *f = mac_window_to_frame (window_ptr);
3529
3530 if (f && !f->async_iconified)
3531 mac_handle_origin_change (f);
3532 }
3533#endif /* not TARGET_API_MAC_CARBON */
3534 break;
3535
3536 case inGoAway:
3537 if (TrackGoAway (window_ptr, er.where))
3538 {
3539 inev.kind = DELETE_WINDOW_EVENT;
3540 XSETFRAME (inev.frame_or_window,
3541 mac_window_to_frame (window_ptr));
3542 }
3543 break;
3544
3545 /* window resize handling added --ben */
3546 case inGrow:
3547 do_grow_window (window_ptr, &er);
3548 break;
3549
3550 /* window zoom handling added --ben */
3551 case inZoomIn:
3552 case inZoomOut:
3553 if (TrackBox (window_ptr, er.where, part_code))
3554 do_zoom_window (window_ptr, part_code);
3555 break;
3556
3557#if USE_MAC_TOOLBAR
3558 case inStructure:
3559 {
3560 OSStatus err;
3561 HIViewRef ch;
3562
3563 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
3564 eventRef, &ch);
3565 /* This doesn't work on Mac OS X 10.2. */
3566 if (err == noErr)
3567 HIViewClick (ch, eventRef);
3568 }
3569 break;
3570#endif /* USE_MAC_TOOLBAR */
3571
3572 default:
3573 break;
3574 }
3575 }
3576 break;
3577
3578#if !TARGET_API_MAC_CARBON
3579 case updateEvt:
3580 do_window_update ((WindowRef) er.message);
3581 break;
3582#endif
3583
3584 case osEvt:
3585#if TARGET_API_MAC_CARBON
3586 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
3587 != eventNotHandledErr)
3588 break;
3589#endif
3590 switch ((er.message >> 24) & 0x000000FF)
3591 {
3592#if USE_MAC_TSM
3593 case suspendResumeMessage:
3594 if (er.message & resumeFlag)
3595 mac_tsm_resume ();
3596 else
3597 mac_tsm_suspend ();
3598 break;
3599#endif
3600
3601 case mouseMovedMessage:
3602#if !TARGET_API_MAC_CARBON
3603 SetRectRgn (mouse_region, er.where.h, er.where.v,
3604 er.where.h + 1, er.where.v + 1);
3605#endif
3606 previous_help_echo_string = help_echo_string;
3607 help_echo_string = Qnil;
3608
3609 if (dpyinfo->grabbed && last_mouse_frame
3610 && FRAME_LIVE_P (last_mouse_frame))
3611 f = last_mouse_frame;
3612 else
3613 f = dpyinfo->x_focus_frame;
3614
3615 if (dpyinfo->mouse_face_hidden)
3616 {
3617 dpyinfo->mouse_face_hidden = 0;
3618 clear_mouse_face (dpyinfo);
3619 }
3620
3621 if (f)
3622 {
3623 WindowRef wp = FRAME_MAC_WINDOW (f);
3624 Point mouse_pos;
3625
3626 mouse_pos.h = (er.where.h
3627 - (f->left_pos
3628 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
3629 mouse_pos.v = (er.where.v
3630 - (f->top_pos
3631 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
3632 if (dpyinfo->grabbed && tracked_scroll_bar)
3633#ifdef USE_TOOLKIT_SCROLL_BARS
3634 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
3635 mouse_pos, &inev);
3636#else /* not USE_TOOLKIT_SCROLL_BARS */
3637 x_scroll_bar_note_movement (tracked_scroll_bar,
3638 mouse_pos.v
3639 - XINT (tracked_scroll_bar->top),
3640 er.when * (1000 / 60));
3641#endif /* not USE_TOOLKIT_SCROLL_BARS */
3642 else
3643 {
3644 /* Generate SELECT_WINDOW_EVENTs when needed. */
3645 if (!NILP (Vmouse_autoselect_window))
3646 {
3647 Lisp_Object window;
3648
3649 window = window_from_coordinates (f,
3650 mouse_pos.h,
3651 mouse_pos.v,
3652 0, 0, 0, 0);
3653
3654 /* Window will be selected only when it is
3655 not selected now and last mouse movement
3656 event was not in it. Minibuffer window
3657 will be selected only when it is active. */
3658 if (WINDOWP (window)
3659 && !EQ (window, last_window)
3660 && !EQ (window, selected_window)
3661 /* For click-to-focus window managers
3662 create event iff we don't leave the
3663 selected frame. */
3664 && (focus_follows_mouse
3665 || (EQ (XWINDOW (window)->frame,
3666 XWINDOW (selected_window)->frame))))
3667 {
3668 inev.kind = SELECT_WINDOW_EVENT;
3669 inev.frame_or_window = window;
3670 }
3671
3672 last_window=window;
3673 }
3674 if (!note_mouse_movement (f, &mouse_pos))
3675 help_echo_string = previous_help_echo_string;
3676#if USE_MAC_TOOLBAR
3677 else
3678 mac_tool_bar_note_mouse_movement (f, eventRef);
3679#endif
3680 }
3681 }
3682
3683 /* If the contents of the global variable
3684 help_echo_string has changed, generate a
3685 HELP_EVENT. */
3686 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
3687 do_help = 1;
3688 break;
3689 }
3690 break;
3691
3692 case activateEvt:
3693 {
3694 WindowRef window_ptr = (WindowRef) er.message;
3695 OSErr err;
3696 ControlRef root_control;
3697
3698 if (window_ptr == tip_window)
3699 {
3700 HideWindow (tip_window);
3701 break;
3702 }
3703
3704 if (!is_emacs_window (window_ptr))
3705 goto OTHER;
3706
3707 f = mac_window_to_frame (window_ptr);
3708
3709 if ((er.modifiers & activeFlag) != 0)
3710 {
3711 /* A window has been activated */
3712 Point mouse_loc;
3713
3714 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
3715 if (err == noErr)
3716 ActivateControl (root_control);
3717
3718 x_detect_focus_change (dpyinfo, &er, &inev);
3719
3720 mouse_loc.h = (er.where.h
3721 - (f->left_pos
3722 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
3723 mouse_loc.v = (er.where.v
3724 - (f->top_pos
3725 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
3726 /* Window-activated event counts as mouse movement,
3727 so update things that depend on mouse position. */
3728 note_mouse_movement (f, &mouse_loc);
3729 }
3730 else
3731 {
3732 /* A window has been deactivated */
3733 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
3734 if (err == noErr)
3735 DeactivateControl (root_control);
3736
3737#ifdef USE_TOOLKIT_SCROLL_BARS
3738 if (dpyinfo->grabbed && tracked_scroll_bar)
3739 {
3740 struct input_event event;
3741
3742 EVENT_INIT (event);
3743 event.kind = NO_EVENT;
3744 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
3745 if (event.kind != NO_EVENT)
3746 {
3747 event.timestamp = timestamp;
3748 kbd_buffer_store_event_hold (&event, hold_quit);
3749 count++;
3750 }
3751 }
3752#endif
3753 dpyinfo->grabbed = 0;
3754
3755 x_detect_focus_change (dpyinfo, &er, &inev);
3756
3757 if (f == dpyinfo->mouse_face_mouse_frame)
3758 {
3759 /* If we move outside the frame, then we're
3760 certainly no longer on any text in the
3761 frame. */
3762 clear_mouse_face (dpyinfo);
3763 dpyinfo->mouse_face_mouse_frame = 0;
3764 }
3765
3766 /* Generate a nil HELP_EVENT to cancel a help-echo.
3767 Do it only if there's something to cancel.
3768 Otherwise, the startup message is cleared when the
3769 mouse leaves the frame. */
3770 if (any_help_event_p)
3771 do_help = -1;
3772 }
3773 }
3774 break;
3775
3776 case keyDown:
3777 case keyUp:
3778 case autoKey:
3779 ObscureCursor ();
3780
3781 f = mac_focus_frame (dpyinfo);
3782 XSETFRAME (inev.frame_or_window, f);
3783
3784 /* If mouse-highlight is an integer, input clears out mouse
3785 highlighting. */
3786 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
3787 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
3788 {
3789 clear_mouse_face (dpyinfo);
3790 dpyinfo->mouse_face_hidden = 1;
3791 }
3792
3793 {
3794 UInt32 modifiers = er.modifiers, mapped_modifiers;
3795 UInt32 key_code = (er.message & keyCodeMask) >> 8;
3796
3797#ifdef MAC_OSX
3798 GetEventParameter (eventRef, kEventParamKeyModifiers,
3799 typeUInt32, NULL,
3800 sizeof (UInt32), NULL, &modifiers);
3801#endif
3802 mapped_modifiers = mac_mapped_modifiers (modifiers, key_code);
3803
3804#if TARGET_API_MAC_CARBON
3805 if (!(mapped_modifiers
3806 & ~(mac_pass_command_to_system ? cmdKey : 0)
3807 & ~(mac_pass_control_to_system ? controlKey : 0)))
3808 goto OTHER;
3809 else
3810#endif
3811 if (er.what != keyUp)
3812 do_keystroke (er.what, er.message & charCodeMask,
3813 key_code, modifiers, timestamp, &inev);
3814 }
3815 break;
3816
3817 case kHighLevelEvent:
3818 AEProcessAppleEvent (&er);
3819 break;
3820
3821 default:
3822 OTHER:
3823#if TARGET_API_MAC_CARBON
3824 {
3825 OSStatus err;
3826
3827 read_socket_inev = &inev;
3828 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
3829 read_socket_inev = NULL;
3830 }
3831#endif
3832 break;
3833 }
3834#if TARGET_API_MAC_CARBON
3835 ReleaseEvent (eventRef);
3836#endif
3837
3838 if (inev.kind != NO_EVENT)
3839 {
3840 inev.timestamp = timestamp;
3841 kbd_buffer_store_event_hold (&inev, hold_quit);
3842 count++;
3843 }
3844
3845 if (do_help
3846 && !(hold_quit && hold_quit->kind != NO_EVENT))
3847 {
3848 Lisp_Object frame;
3849
3850 if (f)
3851 XSETFRAME (frame, f);
3852 else
3853 frame = Qnil;
3854
3855 if (do_help > 0)
3856 {
3857 any_help_event_p = 1;
3858 gen_help_event (help_echo_string, frame, help_echo_window,
3859 help_echo_object, help_echo_pos);
3860 }
3861 else
3862 {
3863 help_echo_string = Qnil;
3864 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
3865 }
3866 count++;
3867 }
3868 }
3869
3870 /* If the focus was just given to an autoraising frame,
3871 raise it now. */
3872 /* ??? This ought to be able to handle more than one such frame. */
3873 if (pending_autoraise_frame)
3874 {
3875 x_raise_frame (pending_autoraise_frame);
3876 pending_autoraise_frame = 0;
3877 }
3878
3879 if (mac_screen_config_changed)
3880 {
3881 mac_get_screen_info (dpyinfo);
3882 mac_screen_config_changed = 0;
3883 }
3884
3885#if !TARGET_API_MAC_CARBON
3886 /* Check which frames are still visible. We do this here because
3887 there doesn't seem to be any direct notification from the Window
3888 Manager that the visibility of a window has changed (at least,
3889 not in all cases). */
3890 {
3891 Lisp_Object tail, frame;
3892
3893 FOR_EACH_FRAME (tail, frame)
3894 {
3895 struct frame *f = XFRAME (frame);
3896
3897 /* The tooltip has been drawn already. Avoid the
3898 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
3899 if (EQ (frame, tip_frame))
3900 continue;
3901
3902 if (FRAME_MAC_P (f))
3903 mac_handle_visibility_change (f);
3904 }
3905 }
3906#endif
3907
3908 --handling_signal;
3909 UNBLOCK_INPUT;
3910 return count;
3911}
3912
3913
3914/***********************************************************************
3915 Busy cursor
3916 ***********************************************************************/
3917
3918#if TARGET_API_MAC_CARBON
3919/* Show the spinning progress indicator for the frame F. Create it if
3920 it doesn't exist yet. */
3921
3922void
3923mac_show_hourglass (f)
3924 struct frame *f;
3925{
3926#if USE_CG_DRAWING
3927 mac_prepare_for_quickdraw (f);
3928#endif
3929 if (!f->output_data.mac->hourglass_control)
3930 {
3931 Window w = FRAME_MAC_WINDOW (f);
3932 Rect r;
3933 ControlRef c;
3934
3935 GetWindowPortBounds (w, &r);
3936 r.left = r.right - HOURGLASS_WIDTH;
3937 r.bottom = r.top + HOURGLASS_HEIGHT;
3938 if (CreateChasingArrowsControl (w, &r, &c) == noErr)
3939 f->output_data.mac->hourglass_control = c;
3940 }
3941
3942 if (f->output_data.mac->hourglass_control)
3943 ShowControl (f->output_data.mac->hourglass_control);
3944}
3945
3946/* Hide the spinning progress indicator for the frame F. Do nothing
3947 it doesn't exist yet. */
3948
3949void
3950mac_hide_hourglass (f)
3951 struct frame *f;
3952{
3953 if (f->output_data.mac->hourglass_control)
3954 {
3955#if USE_CG_DRAWING
3956 mac_prepare_for_quickdraw (f);
3957#endif
3958 HideControl (f->output_data.mac->hourglass_control);
3959 }
3960}
3961
3962/* Reposition the spinning progress indicator for the frame F. Do
3963 nothing it doesn't exist yet. */
3964
3965void
3966mac_reposition_hourglass (f)
3967 struct frame *f;
3968{
3969 if (f->output_data.mac->hourglass_control)
3970 {
3971#if USE_CG_DRAWING
3972 mac_prepare_for_quickdraw (f);
3973#endif
3974 MoveControl (f->output_data.mac->hourglass_control,
3975 FRAME_PIXEL_WIDTH (f) - HOURGLASS_WIDTH, 0);
3976 }
3977}
3978#endif /* TARGET_API_MAC_CARBON */
3979
3980
3981/***********************************************************************
3982 File selection dialog
3983 ***********************************************************************/
3984
3985#if TARGET_API_MAC_CARBON
3986extern Lisp_Object Qfile_name_history;
3987
3988static pascal void mac_nav_event_callback P_ ((NavEventCallbackMessage,
3989 NavCBRecPtr, void *));
3990
3991/* The actual implementation of Fx_file_dialog. */
3992
3993Lisp_Object
3994mac_file_dialog (prompt, dir, default_filename, mustmatch, only_dir_p)
3995 Lisp_Object prompt, dir, default_filename, mustmatch, only_dir_p;
3996{
3997 Lisp_Object file = Qnil;
3998 int count = SPECPDL_INDEX ();
3999 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
4000 char filename[MAXPATHLEN];
4001 static NavEventUPP mac_nav_event_callbackUPP = NULL;
4002
4003 check_mac ();
4004
4005 GCPRO6 (prompt, dir, default_filename, mustmatch, file, only_dir_p);
4006 CHECK_STRING (prompt);
4007 CHECK_STRING (dir);
4008
4009 /* Create the dialog with PROMPT as title, using DIR as initial
4010 directory and using "*" as pattern. */
4011 dir = Fexpand_file_name (dir, Qnil);
4012
4013 {
4014 OSStatus status;
4015 NavDialogCreationOptions options;
4016 NavDialogRef dialogRef;
4017 NavTypeListHandle fileTypes = NULL;
4018 NavUserAction userAction;
4019 CFStringRef message=NULL, saveName = NULL;
4020
4021 BLOCK_INPUT;
4022 /* No need for a callback function because we are modal */
4023 NavGetDefaultDialogCreationOptions(&options);
4024 options.modality = kWindowModalityAppModal;
4025 options.location.h = options.location.v = -1;
4026 options.optionFlags = kNavDefaultNavDlogOptions;
4027 options.optionFlags |= kNavAllFilesInPopup; /* All files allowed */
4028 options.optionFlags |= kNavSelectAllReadableItem;
4029 options.optionFlags &= ~kNavAllowMultipleFiles;
4030 if (!NILP(prompt))
4031 {
4032 message = cfstring_create_with_string (prompt);
4033 options.message = message;
4034 }
4035 /* Don't set the application, let it use default.
4036 options.clientName = CFSTR ("Emacs");
4037 */
4038
4039 if (mac_nav_event_callbackUPP == NULL)
4040 mac_nav_event_callbackUPP = NewNavEventUPP (mac_nav_event_callback);
4041
4042 if (!NILP (only_dir_p))
4043 status = NavCreateChooseFolderDialog(&options, mac_nav_event_callbackUPP,
4044 NULL, NULL, &dialogRef);
4045 else if (NILP (mustmatch))
4046 {
4047 /* This is a save dialog */
4048 options.optionFlags |= kNavDontConfirmReplacement;
4049 options.actionButtonLabel = CFSTR ("Ok");
4050 options.windowTitle = CFSTR ("Enter name");
4051
4052 if (STRINGP (default_filename))
4053 {
4054 Lisp_Object utf8 = ENCODE_UTF_8 (default_filename);
4055 char *begPtr = SDATA(utf8);
4056 char *filePtr = begPtr + SBYTES(utf8);
4057 while (filePtr != begPtr && !IS_DIRECTORY_SEP(filePtr[-1]))
4058 filePtr--;
4059 saveName = cfstring_create_with_utf8_cstring (filePtr);
4060 options.saveFileName = saveName;
4061 options.optionFlags |= kNavSelectDefaultLocation;
4062 }
4063 status = NavCreatePutFileDialog(&options,
4064 'TEXT', kNavGenericSignature,
4065 mac_nav_event_callbackUPP, NULL,
4066 &dialogRef);
4067 }
4068 else
4069 {
4070 /* This is an open dialog*/
4071 status = NavCreateChooseFileDialog(&options, fileTypes,
4072 mac_nav_event_callbackUPP, NULL,
4073 NULL, NULL, &dialogRef);
4074 }
4075
4076 /* Set the default location and continue*/
4077 if (status == noErr)
4078 {
4079 Lisp_Object encoded_dir = ENCODE_FILE (dir);
4080 AEDesc defLocAed;
4081
4082 status = AECreateDesc (TYPE_FILE_NAME, SDATA (encoded_dir),
4083 SBYTES (encoded_dir), &defLocAed);
4084 if (status == noErr)
4085 {
4086 NavCustomControl(dialogRef, kNavCtlSetLocation, (void*) &defLocAed);
4087 AEDisposeDesc(&defLocAed);
4088 }
4089 status = NavDialogRun(dialogRef);
4090 }
4091
4092 if (saveName) CFRelease(saveName);
4093 if (message) CFRelease(message);
4094
4095 if (status == noErr) {
4096 userAction = NavDialogGetUserAction(dialogRef);
4097 switch (userAction)
4098 {
4099 case kNavUserActionNone:
4100 case kNavUserActionCancel:
4101 break; /* Treat cancel like C-g */
4102 case kNavUserActionOpen:
4103 case kNavUserActionChoose:
4104 case kNavUserActionSaveAs:
4105 {
4106 NavReplyRecord reply;
4107 Size len;
4108
4109 status = NavDialogGetReply(dialogRef, &reply);
4110 if (status != noErr)
4111 break;
4112 status = AEGetNthPtr (&reply.selection, 1, TYPE_FILE_NAME,
4113 NULL, NULL, filename,
4114 sizeof (filename) - 1, &len);
4115 if (status == noErr)
4116 {
4117 len = min (len, sizeof (filename) - 1);
4118 filename[len] = '\0';
4119 if (reply.saveFileName)
4120 {
4121 /* If it was a saved file, we need to add the file name */
4122 if (len && len < sizeof (filename) - 1
4123 && filename[len-1] != '/')
4124 filename[len++] = '/';
4125 CFStringGetCString(reply.saveFileName, filename+len,
4126 sizeof (filename) - len,
4127#ifdef MAC_OSX
4128 kCFStringEncodingUTF8
4129#else
4130 CFStringGetSystemEncoding ()
4131#endif
4132 );
4133 }
4134 file = DECODE_FILE (make_unibyte_string (filename,
4135 strlen (filename)));
4136 }
4137 NavDisposeReply(&reply);
4138 }
4139 break;
4140 }
4141 NavDialogDispose(dialogRef);
4142 UNBLOCK_INPUT;
4143 }
4144 else {
4145 UNBLOCK_INPUT;
4146 /* Fall back on minibuffer if there was a problem */
4147 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
4148 dir, mustmatch, dir, Qfile_name_history,
4149 default_filename, Qnil);
4150 }
4151 }
4152
4153 UNGCPRO;
4154
4155 /* Make "Cancel" equivalent to C-g. */
4156 if (NILP (file))
4157 Fsignal (Qquit, Qnil);
4158
4159 return unbind_to (count, file);
4160}
4161
4162/* Need to register some event callback function for enabling drag and
4163 drop in Navigation Service dialogs. */
4164static pascal void
4165mac_nav_event_callback (selector, parms, data)
4166 NavEventCallbackMessage selector;
4167 NavCBRecPtr parms;
4168 void *data;
4169{
4170}
4171#endif
4172
4173
4174/************************************************************************
4175 Menu
4176 ************************************************************************/
4177
4178#if !TARGET_API_MAC_CARBON
4179#include <MacTypes.h>
4180#include <Menus.h>
4181#include <Quickdraw.h>
4182#include <ToolUtils.h>
4183#include <Fonts.h>
4184#include <Controls.h>
4185#include <Windows.h>
4186#include <Events.h>
4187#if defined (__MRC__) || (__MSL__ >= 0x6000)
4188#include <ControlDefinitions.h>
4189#endif
4190#endif /* not TARGET_API_MAC_CARBON */
4191
4192extern int menu_item_selection;
4193extern int popup_activated_flag;
4194extern int name_is_separator P_ ((const char *));
4195extern void find_and_call_menu_selection P_ ((FRAME_PTR, int, Lisp_Object,
4196 void *));
4197extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
4198
4199enum mac_menu_kind { /* Menu ID range */
4200 MAC_MENU_APPLE, /* 0 (Reserved by Apple) */
4201 MAC_MENU_MENU_BAR, /* 1 .. 233 */
4202 MAC_MENU_M_APPLE, /* 234 (== M_APPLE) */
4203 MAC_MENU_POPUP, /* 235 */
4204 MAC_MENU_DRIVER, /* 236 .. 255 (Reserved) */
4205 MAC_MENU_MENU_BAR_SUB, /* 256 .. 16383 */
4206 MAC_MENU_POPUP_SUB, /* 16384 .. 32767 */
4207 MAC_MENU_END /* 32768 */
4208};
4209
4210static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
4211
4212static int fill_menu P_ ((MenuRef, widget_value *, enum mac_menu_kind, int));
4213static void dispose_menus P_ ((enum mac_menu_kind, int));
4214
4215#if !TARGET_API_MAC_CARBON
4216static void
4217do_apple_menu (SInt16 menu_item)
4218{
4219 Str255 item_name;
4220 SInt16 da_driver_refnum;
4221
4222 if (menu_item == I_ABOUT)
4223 NoteAlert (ABOUT_ALERT_ID, NULL);
4224 else
4225 {
4226 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
4227 da_driver_refnum = OpenDeskAcc (item_name);
4228 }
4229}
4230#endif /* !TARGET_API_MAC_CARBON */
4231
4232/* Activate the menu bar of frame F.
4233 This is called from keyboard.c when it gets the
4234 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
4235
4236 To activate the menu bar, we use the button-press event location
4237 that was saved in saved_menu_event_location.
4238
4239 But first we recompute the menu bar contents (the whole tree).
4240
4241 The reason for saving the button event until here, instead of
4242 passing it to the toolkit right away, is that we can safely
4243 execute Lisp code. */
4244
4245void
4246x_activate_menubar (f)
4247 FRAME_PTR f;
4248{
4249 SInt32 menu_choice;
4250 SInt16 menu_id, menu_item;
4251 extern Point saved_menu_event_location;
4252
4253 set_frame_menubar (f, 0, 1);
4254 BLOCK_INPUT;
4255
4256 popup_activated_flag = 1;
4257 menu_choice = MenuSelect (saved_menu_event_location);
4258 popup_activated_flag = 0;
4259 menu_id = HiWord (menu_choice);
4260 menu_item = LoWord (menu_choice);
4261
4262#if !TARGET_API_MAC_CARBON
4263 if (menu_id == min_menu_id[MAC_MENU_M_APPLE])
4264 do_apple_menu (menu_item);
4265 else
4266#endif
4267 if (menu_id)
4268 {
4269 MenuRef menu = GetMenuRef (menu_id);
4270
4271 if (menu)
4272 {
4273 UInt32 refcon;
4274
4275 GetMenuItemRefCon (menu, menu_item, &refcon);
4276 find_and_call_menu_selection (f, f->menu_bar_items_used,
4277 f->menu_bar_vector, (void *) refcon);
4278 }
4279 }
4280
4281 HiliteMenu (0);
4282
4283 UNBLOCK_INPUT;
4284}
4285
4286#if TARGET_API_MAC_CARBON
4287extern Lisp_Object Vshow_help_function;
4288
4289static Lisp_Object
4290restore_show_help_function (old_show_help_function)
4291 Lisp_Object old_show_help_function;
4292{
4293 Vshow_help_function = old_show_help_function;
4294
4295 return Qnil;
4296}
4297
4298static pascal OSStatus
4299menu_target_item_handler (next_handler, event, data)
4300 EventHandlerCallRef next_handler;
4301 EventRef event;
4302 void *data;
4303{
4304 OSStatus err;
4305 MenuRef menu;
4306 MenuItemIndex menu_item;
4307 Lisp_Object help;
4308 GrafPtr port;
4309 int specpdl_count = SPECPDL_INDEX ();
4310
4311 /* Don't be bothered with the overflowed toolbar items menu. */
4312 if (!popup_activated ())
4313 return eventNotHandledErr;
4314
4315 err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef,
4316 NULL, sizeof (MenuRef), NULL, &menu);
4317 if (err == noErr)
4318 err = GetEventParameter (event, kEventParamMenuItemIndex,
4319 typeMenuItemIndex, NULL,
4320 sizeof (MenuItemIndex), NULL, &menu_item);
4321 if (err == noErr)
4322 err = GetMenuItemProperty (menu, menu_item,
4323 MAC_EMACS_CREATOR_CODE, 'help',
4324 sizeof (Lisp_Object), NULL, &help);
4325 if (err != noErr)
4326 help = Qnil;
4327
4328 /* Temporarily bind Vshow_help_function to Qnil because we don't
4329 want tooltips during menu tracking. */
4330 record_unwind_protect (restore_show_help_function, Vshow_help_function);
4331 Vshow_help_function = Qnil;
4332 GetPort (&port);
4333 show_help_echo (help, Qnil, Qnil, Qnil, 1);
4334 SetPort (port);
4335 unbind_to (specpdl_count, Qnil);
4336
4337 return err == noErr ? noErr : eventNotHandledErr;
4338}
4339
4340/* Showing help echo string during menu tracking. */
4341
4342static OSStatus
4343install_menu_target_item_handler ()
4344{
4345 static const EventTypeSpec specs[] =
4346 {{kEventClassMenu, kEventMenuTargetItem}};
4347
4348 return InstallApplicationEventHandler (NewEventHandlerUPP
4349 (menu_target_item_handler),
4350 GetEventTypeCount (specs),
4351 specs, NULL, NULL);
4352}
4353#endif /* TARGET_API_MAC_CARBON */
4354
4355/* Event handler function that pops down a menu on C-g. We can only pop
4356 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
4357
4358#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4359static pascal OSStatus
4360menu_quit_handler (nextHandler, theEvent, userData)
4361 EventHandlerCallRef nextHandler;
4362 EventRef theEvent;
4363 void* userData;
4364{
4365 OSStatus err;
4366 UInt32 keyCode;
4367 UInt32 keyModifiers;
4368
4369 err = GetEventParameter (theEvent, kEventParamKeyCode,
4370 typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
4371
4372 if (err == noErr)
4373 err = GetEventParameter (theEvent, kEventParamKeyModifiers,
4374 typeUInt32, NULL, sizeof(UInt32),
4375 NULL, &keyModifiers);
4376
4377 if (err == noErr && mac_quit_char_key_p (keyModifiers, keyCode))
4378 {
4379 MenuRef menu = userData != 0
4380 ? (MenuRef)userData : AcquireRootMenu ();
4381
4382 CancelMenuTracking (menu, true, 0);
4383 if (!userData) ReleaseMenu (menu);
4384 return noErr;
4385 }
4386
4387 return CallNextEventHandler (nextHandler, theEvent);
4388}
4389#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4390
4391/* Add event handler to all menus that belong to KIND so we can detect
4392 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
4393 when C-g is detected. NULL means the menu bar. If
4394 CancelMenuTracking isn't available, do nothing. */
4395
4396static void
4397install_menu_quit_handler (kind, root_menu)
4398 enum mac_menu_kind kind;
4399 MenuRef root_menu;
4400{
4401#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4402 static const EventTypeSpec typesList[] =
4403 {{kEventClassKeyboard, kEventRawKeyDown}};
4404 int id;
4405
4406#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
4407 if (CancelMenuTracking == NULL)
4408 return;
4409#endif
4410 for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++)
4411 {
4412 MenuRef menu = GetMenuRef (id);
4413
4414 if (menu == NULL)
4415 break;
4416 InstallMenuEventHandler (menu, menu_quit_handler,
4417 GetEventTypeCount (typesList),
4418 typesList, root_menu, NULL);
4419 }
4420#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4421}
4422
4423static Lisp_Object
4424pop_down_menu (arg)
4425 Lisp_Object arg;
4426{
4427 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
4428 FRAME_PTR f = p->pointer;
4429 MenuRef menu = GetMenuRef (min_menu_id[MAC_MENU_POPUP]);
4430
4431 BLOCK_INPUT;
4432
4433 /* Must reset this manually because the button release event is not
4434 passed to Emacs event loop. */
4435 FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0;
4436
4437 /* delete all menus */
4438 dispose_menus (MAC_MENU_POPUP_SUB, 0);
4439 DeleteMenu (min_menu_id[MAC_MENU_POPUP]);
4440 DisposeMenu (menu);
4441
4442 UNBLOCK_INPUT;
4443
4444 return Qnil;
4445}
4446
4447/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop
4448 until the menu pops down. Return the selection. */
4449
4450void
4451create_and_show_popup_menu (f, first_wv, x, y, for_click)
4452 FRAME_PTR f;
4453 widget_value *first_wv;
4454 int x;
4455 int y;
4456 int for_click;
4457{
4458 int result = 0;
4459 MenuRef menu = NewMenu (min_menu_id[MAC_MENU_POPUP], "\p");
4460 int menu_item_choice;
4461 int specpdl_count = SPECPDL_INDEX ();
4462
4463 InsertMenu (menu, -1);
4464 fill_menu (menu, first_wv->contents, MAC_MENU_POPUP_SUB,
4465 min_menu_id[MAC_MENU_POPUP_SUB]);
4466
4467 /* Add event handler so we can detect C-g. */
4468 install_menu_quit_handler (MAC_MENU_POPUP, menu);
4469 install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu);
4470
4471 record_unwind_protect (pop_down_menu, make_save_value (f, 0));
4472
4473 /* Adjust coordinates to be root-window-relative. */
4474 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
4475 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
4476
4477 /* Display the menu. */
4478 popup_activated_flag = 1;
4479 menu_item_choice = PopUpMenuSelect (menu, y, x, 0);
4480 popup_activated_flag = 0;
4481
4482 /* Get the refcon to find the correct item */
4483 if (menu_item_choice)
4484 {
4485 MenuRef sel_menu = GetMenuRef (HiWord (menu_item_choice));
4486
4487 if (sel_menu)
4488 GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice),
4489 (UInt32 *) &result);
4490 }
4491
4492 unbind_to (specpdl_count, Qnil);
4493
4494 menu_item_selection = result;
4495}
4496
4497static void
4498add_menu_item (menu, pos, wv)
4499 MenuRef menu;
4500 int pos;
4501 widget_value *wv;
4502{
4503#if TARGET_API_MAC_CARBON
4504 CFStringRef item_name;
4505#else
4506 Str255 item_name;
4507#endif
4508
4509 if (name_is_separator (wv->name))
4510 AppendMenu (menu, "\p-");
4511 else
4512 {
4513 AppendMenu (menu, "\pX");
4514
4515#if TARGET_API_MAC_CARBON
4516 item_name = cfstring_create_with_utf8_cstring (wv->name);
4517
4518 if (wv->key != NULL)
4519 {
4520 CFStringRef name, key;
4521
4522 name = item_name;
4523 key = cfstring_create_with_utf8_cstring (wv->key);
4524 item_name = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@ %@"),
4525 name, key);
4526 CFRelease (name);
4527 CFRelease (key);
4528 }
4529
4530 SetMenuItemTextWithCFString (menu, pos, item_name);
4531 CFRelease (item_name);
4532
4533 if (wv->enabled)
4534 EnableMenuItem (menu, pos);
4535 else
4536 DisableMenuItem (menu, pos);
4537
4538 if (STRINGP (wv->help))
4539 SetMenuItemProperty (menu, pos, MAC_EMACS_CREATOR_CODE, 'help',
4540 sizeof (Lisp_Object), &wv->help);
4541#else /* ! TARGET_API_MAC_CARBON */
4542 item_name[sizeof (item_name) - 1] = '\0';
4543 strncpy (item_name, wv->name, sizeof (item_name) - 1);
4544 if (wv->key != NULL)
4545 {
4546 int len = strlen (item_name);
4547
4548 strncpy (item_name + len, " ", sizeof (item_name) - 1 - len);
4549 len = strlen (item_name);
4550 strncpy (item_name + len, wv->key, sizeof (item_name) - 1 - len);
4551 }
4552 c2pstr (item_name);
4553 SetMenuItemText (menu, pos, item_name);
4554
4555 if (wv->enabled)
4556 EnableItem (menu, pos);
4557 else
4558 DisableItem (menu, pos);
4559#endif /* ! TARGET_API_MAC_CARBON */
4560
4561 /* Draw radio buttons and tickboxes. */
4562 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE
4563 || wv->button_type == BUTTON_TYPE_RADIO))
4564 SetItemMark (menu, pos, checkMark);
4565 else
4566 SetItemMark (menu, pos, noMark);
4567
4568 SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
4569 }
4570}
4571
4572/* Construct native Mac OS menu based on widget_value tree. */
4573
4574static int
4575fill_menu (menu, wv, kind, submenu_id)
4576 MenuRef menu;
4577 widget_value *wv;
4578 enum mac_menu_kind kind;
4579 int submenu_id;
4580{
4581 int pos;
4582
4583 for (pos = 1; wv != NULL; wv = wv->next, pos++)
4584 {
4585 add_menu_item (menu, pos, wv);
4586 if (wv->contents && submenu_id < min_menu_id[kind + 1])
4587 {
4588 MenuRef submenu = NewMenu (submenu_id, "\pX");
4589
4590 InsertMenu (submenu, -1);
4591#if TARGET_API_MAC_CARBON
4592 SetMenuItemHierarchicalMenu (menu, pos, submenu);
4593#else
4594 SetMenuItemHierarchicalID (menu, pos, submenu_id);
4595#endif
4596 submenu_id = fill_menu (submenu, wv->contents, kind, submenu_id + 1);
4597 }
4598 }
4599
4600 return submenu_id;
4601}
4602
4603/* Fill menu bar with the items defined by WV. If DEEP_P, consider
4604 the entire menu trees we supply, rather than just the menu bar item
4605 names. */
4606
4607void
4608mac_fill_menubar (wv, deep_p)
4609 widget_value *wv;
4610 int deep_p;
4611{
4612 int id, submenu_id;
4613#if !TARGET_API_MAC_CARBON
4614 int title_changed_p = 0;
4615#endif
4616
4617 /* Clean up the menu bar when filled by the entire menu trees. */
4618 if (deep_p)
4619 {
4620 dispose_menus (MAC_MENU_MENU_BAR, 0);
4621 dispose_menus (MAC_MENU_MENU_BAR_SUB, 0);
4622#if !TARGET_API_MAC_CARBON
4623 title_changed_p = 1;
4624#endif
4625 }
4626
4627 /* Fill menu bar titles and submenus. Reuse the existing menu bar
4628 titles as much as possible to minimize redraw (if !deep_p). */
4629 submenu_id = min_menu_id[MAC_MENU_MENU_BAR_SUB];
4630 for (id = min_menu_id[MAC_MENU_MENU_BAR];
4631 wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1];
4632 wv = wv->next, id++)
4633 {
4634 OSStatus err = noErr;
4635 MenuRef menu;
4636#if TARGET_API_MAC_CARBON
4637 CFStringRef title;
4638
4639 title = CFStringCreateWithCString (NULL, wv->name,
4640 kCFStringEncodingMacRoman);
4641#else
4642 Str255 title;
4643
4644 strncpy (title, wv->name, 255);
4645 title[255] = '\0';
4646 c2pstr (title);
4647#endif
4648
4649 menu = GetMenuRef (id);
4650 if (menu)
4651 {
4652#if TARGET_API_MAC_CARBON
4653 CFStringRef old_title;
4654
4655 err = CopyMenuTitleAsCFString (menu, &old_title);
4656 if (err == noErr)
4657 {
4658 if (CFStringCompare (title, old_title, 0) != kCFCompareEqualTo)
4659 {
4660#ifdef MAC_OSX
4661 if (id + 1 == min_menu_id[MAC_MENU_MENU_BAR + 1]
4662 || GetMenuRef (id + 1) == NULL)
4663 {
4664 /* This is a workaround for Mac OS X 10.5 where
4665 just calling SetMenuTitleWithCFString fails
4666 to change the title of the last (Help) menu
4667 in the menu bar. */
4668 DeleteMenu (id);
4669 DisposeMenu (menu);
4670 menu = NULL;
4671 }
4672 else
4673#endif /* MAC_OSX */
4674 err = SetMenuTitleWithCFString (menu, title);
4675 }
4676 CFRelease (old_title);
4677 }
4678 else
4679 err = SetMenuTitleWithCFString (menu, title);
4680#else /* !TARGET_API_MAC_CARBON */
4681 if (!EqualString (title, (*menu)->menuData, false, false))
4682 {
4683 DeleteMenu (id);
4684 DisposeMenu (menu);
4685 menu = NewMenu (id, title);
4686 InsertMenu (menu, GetMenuRef (id + 1) ? id + 1 : 0);
4687 title_changed_p = 1;
4688 }
4689#endif /* !TARGET_API_MAC_CARBON */
4690 }
4691
4692 if (!menu)
4693 {
4694#if TARGET_API_MAC_CARBON
4695 err = CreateNewMenu (id, 0, &menu);
4696 if (err == noErr)
4697 err = SetMenuTitleWithCFString (menu, title);
4698#else
4699 menu = NewMenu (id, title);
4700#endif
4701 if (err == noErr)
4702 {
4703 InsertMenu (menu, 0);
4704#if !TARGET_API_MAC_CARBON
4705 title_changed_p = 1;
4706#endif
4707 }
4708 }
4709#if TARGET_API_MAC_CARBON
4710 CFRelease (title);
4711#endif
4712
4713 if (err == noErr)
4714 if (wv->contents)
4715 submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
4716 submenu_id);
4717 }
4718
4719 if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuRef (id))
4720 {
4721 dispose_menus (MAC_MENU_MENU_BAR, id);
4722#if !TARGET_API_MAC_CARBON
4723 title_changed_p = 1;
4724#endif
4725 }
4726
4727#if !TARGET_API_MAC_CARBON
4728 if (title_changed_p)
4729 InvalMenuBar ();
4730#endif
4731
4732 /* Add event handler so we can detect C-g. */
4733 install_menu_quit_handler (MAC_MENU_MENU_BAR, NULL);
4734 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB, NULL);
4735}
4736
4737/* Dispose of menus that belong to KIND, and remove them from the menu
4738 list. ID is the lower bound of menu IDs that will be processed. */
4739
4740static void
4741dispose_menus (kind, id)
4742 enum mac_menu_kind kind;
4743 int id;
4744{
4745 for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++)
4746 {
4747 MenuRef menu = GetMenuRef (id);
4748
4749 if (menu == NULL)
4750 break;
4751 DeleteMenu (id);
4752 DisposeMenu (menu);
4753 }
4754}
4755
4756static void
4757init_menu_bar ()
4758{
4759#ifdef MAC_OSX
4760 OSStatus err;
4761 MenuRef menu;
4762 MenuItemIndex menu_index;
4763
4764 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
4765 &menu, &menu_index);
4766 if (err == noErr)
4767 SetMenuItemCommandKey (menu, menu_index, false, 0);
4768 EnableMenuCommand (NULL, kHICommandPreferences);
4769 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
4770 &menu, &menu_index);
4771 if (err == noErr)
4772 {
4773 SetMenuItemCommandKey (menu, menu_index, false, 0);
4774 InsertMenuItemTextWithCFString (menu, NULL,
4775 0, kMenuItemAttrSeparator, 0);
4776 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
4777 0, 0, kHICommandAbout);
4778 }
4779#else /* !MAC_OSX */
4780#if TARGET_API_MAC_CARBON
4781 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
4782#endif
4783#endif
4784}
4785
4786
4787/***********************************************************************
4788 Popup Dialog
4789 ***********************************************************************/
4790
4791#if TARGET_API_MAC_CARBON
4792#define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
4793#define DIALOG_BUTTON_COMMAND_ID_P(id) \
4794 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
4795#define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
4796 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
4797#define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
4798 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
4799
4800extern EMACS_TIME timer_check P_ ((int));
4801static int quit_dialog_event_loop;
4802
4803static pascal OSStatus
4804mac_handle_dialog_event (next_handler, event, data)
4805 EventHandlerCallRef next_handler;
4806 EventRef event;
4807 void *data;
4808{
4809 OSStatus err, result = eventNotHandledErr;
4810 WindowRef window = (WindowRef) data;
4811
4812 switch (GetEventClass (event))
4813 {
4814 case kEventClassCommand:
4815 {
4816 HICommand command;
4817
4818 err = GetEventParameter (event, kEventParamDirectObject,
4819 typeHICommand, NULL, sizeof (HICommand),
4820 NULL, &command);
4821 if (err == noErr)
4822 if (DIALOG_BUTTON_COMMAND_ID_P (command.commandID))
4823 {
4824 SetWRefCon (window, command.commandID);
4825 quit_dialog_event_loop = 1;
4826 break;
4827 }
4828
4829 result = CallNextEventHandler (next_handler, event);
4830 }
4831 break;
4832
4833 case kEventClassKeyboard:
4834 {
4835 OSStatus result;
4836 char char_code;
4837
4838 result = CallNextEventHandler (next_handler, event);
4839 if (result != eventNotHandledErr)
4840 break;
4841
4842 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
4843 typeChar, NULL, sizeof (char),
4844 NULL, &char_code);
4845 if (err == noErr)
4846 switch (char_code)
4847 {
4848 case kEscapeCharCode:
4849 quit_dialog_event_loop = 1;
4850 break;
4851
4852 default:
4853 {
4854 UInt32 modifiers, key_code;
4855
4856 err = GetEventParameter (event, kEventParamKeyModifiers,
4857 typeUInt32, NULL, sizeof (UInt32),
4858 NULL, &modifiers);
4859 if (err == noErr)
4860 err = GetEventParameter (event, kEventParamKeyCode,
4861 typeUInt32, NULL, sizeof (UInt32),
4862 NULL, &key_code);
4863 if (err == noErr)
4864 if (mac_quit_char_key_p (modifiers, key_code))
4865 quit_dialog_event_loop = 1;
4866 }
4867 break;
4868 }
4869 }
4870 break;
4871
4872 default:
4873 abort ();
4874 }
4875
4876 if (quit_dialog_event_loop)
4877 {
4878 err = QuitEventLoop (GetCurrentEventLoop ());
4879 if (err == noErr)
4880 result = noErr;
4881 }
4882
4883 return result;
4884}
4885
4886static OSStatus
4887install_dialog_event_handler (window)
4888 WindowRef window;
4889{
4890 static const EventTypeSpec specs[] =
4891 {{kEventClassCommand, kEventCommandProcess},
4892 {kEventClassKeyboard, kEventRawKeyDown}};
4893 static EventHandlerUPP handle_dialog_eventUPP = NULL;
4894
4895 if (handle_dialog_eventUPP == NULL)
4896 handle_dialog_eventUPP = NewEventHandlerUPP (mac_handle_dialog_event);
4897 return InstallWindowEventHandler (window, handle_dialog_eventUPP,
4898 GetEventTypeCount (specs), specs,
4899 window, NULL);
4900}
4901
4902static Lisp_Object
4903pop_down_dialog (arg)
4904 Lisp_Object arg;
4905{
4906 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
4907 WindowRef window = p->pointer;
4908
4909 BLOCK_INPUT;
4910
4911 if (popup_activated_flag)
4912 EndAppModalStateForWindow (window);
4913 DisposeWindow (window);
4914 popup_activated_flag = 0;
4915
4916 UNBLOCK_INPUT;
4917
4918 return Qnil;
4919}
4920
4921/* Pop up the dialog for frame F defined by FIRST_WV and loop until the
4922 dialog pops down.
4923 menu_item_selection will be set to the selection. */
4924
4925void
4926create_and_show_dialog (f, first_wv)
4927 FRAME_PTR f;
4928 widget_value *first_wv;
4929{
4930 OSStatus err;
4931 char *dialog_name, *message;
4932 int nb_buttons, first_group_count, i, result = 0;
4933 widget_value *wv;
4934 short buttons_height, text_height, inner_width, inner_height;
4935 Rect empty_rect, *rects;
4936 WindowRef window = NULL;
4937 ControlRef *buttons, default_button = NULL, text;
4938 int specpdl_count = SPECPDL_INDEX ();
4939
4940 dialog_name = first_wv->name;
4941 nb_buttons = dialog_name[1] - '0';
4942 first_group_count = nb_buttons - (dialog_name[4] - '0');
4943
4944 wv = first_wv->contents;
4945 message = wv->value;
4946
4947 wv = wv->next;
4948 SetRect (&empty_rect, 0, 0, 0, 0);
4949
4950 /* Create dialog window. */
4951 err = CreateNewWindow (kMovableModalWindowClass,
4952 kWindowStandardHandlerAttribute,
4953 &empty_rect, &window);
4954 if (err == noErr)
4955 {
4956 record_unwind_protect (pop_down_dialog, make_save_value (window, 0));
4957 err = SetThemeWindowBackground (window, kThemeBrushMovableModalBackground,
4958 true);
4959 }
4960 if (err == noErr)
4961 err = SetWindowTitleWithCFString (window, (dialog_name[0] == 'Q'
4962 ? CFSTR ("Question")
4963 : CFSTR ("Information")));
4964
4965 /* Create button controls and measure their optimal bounds. */
4966 if (err == noErr)
4967 {
4968 buttons = alloca (sizeof (ControlRef) * nb_buttons);
4969 rects = alloca (sizeof (Rect) * nb_buttons);
4970 for (i = 0; i < nb_buttons; i++)
4971 {
4972 CFStringRef label = cfstring_create_with_utf8_cstring (wv->value);
4973
4974 if (label == NULL)
4975 err = memFullErr;
4976 else
4977 {
4978 err = CreatePushButtonControl (window, &empty_rect,
4979 label, &buttons[i]);
4980 CFRelease (label);
4981 }
4982 if (err == noErr)
4983 {
4984 if (!wv->enabled)
4985 {
4986#ifdef MAC_OSX
4987 err = DisableControl (buttons[i]);
4988#else
4989 err = DeactivateControl (buttons[i]);
4990#endif
4991 }
4992 else if (default_button == NULL)
4993 default_button = buttons[i];
4994 }
4995 if (err == noErr)
4996 {
4997 SInt16 unused;
4998
4999 rects[i] = empty_rect;
5000 err = GetBestControlRect (buttons[i], &rects[i], &unused);
5001 }
5002 if (err == noErr)
5003 {
5004 UInt32 command_id;
5005
5006 OffsetRect (&rects[i], -rects[i].left, -rects[i].top);
5007 if (rects[i].right < DIALOG_BUTTON_MIN_WIDTH)
5008 rects[i].right = DIALOG_BUTTON_MIN_WIDTH;
5009 else if (rects[i].right > DIALOG_MAX_INNER_WIDTH)
5010 rects[i].right = DIALOG_MAX_INNER_WIDTH;
5011
5012 command_id = DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv->call_data);
5013 err = SetControlCommandID (buttons[i], command_id);
5014 }
5015 if (err != noErr)
5016 break;
5017 wv = wv->next;
5018 }
5019 }
5020
5021 /* Layout buttons. rects[i] is set relative to the bottom-right
5022 corner of the inner box. */
5023 if (err == noErr)
5024 {
5025 short bottom, right, max_height, left_align_shift;
5026
5027 inner_width = DIALOG_MIN_INNER_WIDTH;
5028 bottom = right = max_height = 0;
5029 for (i = 0; i < nb_buttons; i++)
5030 {
5031 if (right - rects[i].right < - inner_width)
5032 {
5033 if (i != first_group_count
5034 && right - rects[i].right >= - DIALOG_MAX_INNER_WIDTH)
5035 inner_width = - (right - rects[i].right);
5036 else
5037 {
5038 bottom -= max_height + DIALOG_BUTTON_BUTTON_VERTICAL_SPACE;
5039 right = max_height = 0;
5040 }
5041 }
5042 if (max_height < rects[i].bottom)
5043 max_height = rects[i].bottom;
5044 OffsetRect (&rects[i], right - rects[i].right,
5045 bottom - rects[i].bottom);
5046 right = rects[i].left - DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
5047 if (i == first_group_count - 1)
5048 right -= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
5049 }
5050 buttons_height = - (bottom - max_height);
5051
5052 left_align_shift = - (inner_width + rects[nb_buttons - 1].left);
5053 for (i = nb_buttons - 1; i >= first_group_count; i--)
5054 {
5055 if (bottom != rects[i].bottom)
5056 {
5057 left_align_shift = - (inner_width + rects[i].left);
5058 bottom = rects[i].bottom;
5059 }
5060 OffsetRect (&rects[i], left_align_shift, 0);
5061 }
5062 }
5063
5064 /* Create a static text control and measure its bounds. */
5065 if (err == noErr)
5066 {
5067 CFStringRef message_string;
5068 Rect bounds;
5069
5070 message_string = cfstring_create_with_utf8_cstring (message);
5071 if (message_string == NULL)
5072 err = memFullErr;
5073 else
5074 {
5075 ControlFontStyleRec text_style;
5076
5077 text_style.flags = 0;
5078 SetRect (&bounds, 0, 0, inner_width, 0);
5079 err = CreateStaticTextControl (window, &bounds, message_string,
5080 &text_style, &text);
5081 CFRelease (message_string);
5082 }
5083 if (err == noErr)
5084 {
5085 SInt16 unused;
5086
5087 bounds = empty_rect;
5088 err = GetBestControlRect (text, &bounds, &unused);
5089 }
5090 if (err == noErr)
5091 {
5092 text_height = bounds.bottom - bounds.top;
5093 if (text_height < DIALOG_TEXT_MIN_HEIGHT)
5094 text_height = DIALOG_TEXT_MIN_HEIGHT;
5095 }
5096 }
5097
5098 /* Place buttons. */
5099 if (err == noErr)
5100 {
5101 inner_height = (text_height + DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
5102 + buttons_height);
5103
5104 for (i = 0; i < nb_buttons; i++)
5105 {
5106 OffsetRect (&rects[i], DIALOG_LEFT_MARGIN + inner_width,
5107 DIALOG_TOP_MARGIN + inner_height);
5108 SetControlBounds (buttons[i], &rects[i]);
5109 }
5110 }
5111
5112 /* Place text. */
5113 if (err == noErr)
5114 {
5115 Rect bounds;
5116
5117 SetRect (&bounds, DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN,
5118 DIALOG_LEFT_MARGIN + inner_width,
5119 DIALOG_TOP_MARGIN + text_height);
5120 SetControlBounds (text, &bounds);
5121 }
5122
5123 /* Create the application icon at the upper-left corner. */
5124 if (err == noErr)
5125 {
5126 ControlButtonContentInfo content;
5127 ControlRef icon;
5128 static const ProcessSerialNumber psn = {0, kCurrentProcess};
5129#ifdef MAC_OSX
5130 FSRef app_location;
5131#else
5132 ProcessInfoRec pinfo;
5133 FSSpec app_spec;
5134#endif
5135 SInt16 unused;
5136
5137 content.contentType = kControlContentIconRef;
5138#ifdef MAC_OSX
5139 err = GetProcessBundleLocation (&psn, &app_location);
5140 if (err == noErr)
5141 err = GetIconRefFromFileInfo (&app_location, 0, NULL, 0, NULL,
5142 kIconServicesNormalUsageFlag,
5143 &content.u.iconRef, &unused);
5144#else
5145 bzero (&pinfo, sizeof (ProcessInfoRec));
5146 pinfo.processInfoLength = sizeof (ProcessInfoRec);
5147 pinfo.processAppSpec = &app_spec;
5148 err = GetProcessInformation (&psn, &pinfo);
5149 if (err == noErr)
5150 err = GetIconRefFromFile (&app_spec, &content.u.iconRef, &unused);
5151#endif
5152 if (err == noErr)
5153 {
5154 Rect bounds;
5155
5156 SetRect (&bounds, DIALOG_ICON_LEFT_MARGIN, DIALOG_ICON_TOP_MARGIN,
5157 DIALOG_ICON_LEFT_MARGIN + DIALOG_ICON_WIDTH,
5158 DIALOG_ICON_TOP_MARGIN + DIALOG_ICON_HEIGHT);
5159 err = CreateIconControl (window, &bounds, &content, true, &icon);
5160 ReleaseIconRef (content.u.iconRef);
5161 }
5162 }
5163
5164 /* Show the dialog window and run event loop. */
5165 if (err == noErr)
5166 if (default_button)
5167 err = SetWindowDefaultButton (window, default_button);
5168 if (err == noErr)
5169 err = install_dialog_event_handler (window);
5170 if (err == noErr)
5171 {
5172 SizeWindow (window,
5173 DIALOG_LEFT_MARGIN + inner_width + DIALOG_RIGHT_MARGIN,
5174 DIALOG_TOP_MARGIN + inner_height + DIALOG_BOTTOM_MARGIN,
5175 true);
5176 err = RepositionWindow (window, FRAME_MAC_WINDOW (f),
5177 kWindowAlertPositionOnParentWindow);
5178 }
5179 if (err == noErr)
5180 {
5181 SetWRefCon (window, 0);
5182 ShowWindow (window);
5183 BringToFront (window);
5184 popup_activated_flag = 1;
5185 err = BeginAppModalStateForWindow (window);
5186 }
5187 if (err == noErr)
5188 {
5189 EventTargetRef toolbox_dispatcher = GetEventDispatcherTarget ();
5190
5191 quit_dialog_event_loop = 0;
5192 while (1)
5193 {
5194 EMACS_TIME next_time = timer_check (1);
5195 long secs = EMACS_SECS (next_time);
5196 long usecs = EMACS_USECS (next_time);
5197 EventTimeout timeout;
5198 EventRef event;
5199
5200 if (secs < 0 || (secs == 0 && usecs == 0))
5201 {
5202 /* Sometimes timer_check returns -1 (no timers) even if
5203 there are timers. So do a timeout anyway. */
5204 secs = 1;
5205 usecs = 0;
5206 }
5207
5208 timeout = (secs * kEventDurationSecond
5209 + usecs * kEventDurationMicrosecond);
5210 err = ReceiveNextEvent (0, NULL, timeout, kEventRemoveFromQueue,
5211 &event);
5212 if (err == noErr)
5213 {
5214 SendEventToEventTarget (event, toolbox_dispatcher);
5215 ReleaseEvent (event);
5216 }
5217#if 0 /* defined (MAC_OSX) */
5218 else if (err != eventLoopTimedOutErr)
5219 {
5220 if (err == eventLoopQuitErr)
5221 err = noErr;
5222 break;
5223 }
5224#else
5225 /* The return value of ReceiveNextEvent seems to be
5226 unreliable. Use our own global variable instead. */
5227 if (quit_dialog_event_loop)
5228 {
5229 err = noErr;
5230 break;
5231 }
5232#endif
5233 }
5234 }
5235 if (err == noErr)
5236 {
5237 UInt32 command_id = GetWRefCon (window);
5238
5239 if (DIALOG_BUTTON_COMMAND_ID_P (command_id))
5240 result = DIALOG_BUTTON_COMMAND_ID_VALUE (command_id);
5241 }
5242
5243 unbind_to (specpdl_count, Qnil);
5244
5245 menu_item_selection = result;
5246}
5247#else /* not TARGET_API_MAC_CARBON */
5248#define DIALOG_WINDOW_RESOURCE 130
5249
5250int
5251mac_dialog (widget_value *wv)
5252{
5253 char *dialog_name;
5254 char *prompt;
5255 char **button_labels;
5256 UInt32 *ref_cons;
5257 int nb_buttons;
5258 int left_count;
5259 int i;
5260 int dialog_width;
5261 Rect rect;
5262 WindowRef window_ptr;
5263 ControlRef ch;
5264 int left;
5265 EventRecord event_record;
5266 SInt16 part_code;
5267 int control_part_code;
5268 Point mouse;
5269
5270 dialog_name = wv->name;
5271 nb_buttons = dialog_name[1] - '0';
5272 left_count = nb_buttons - (dialog_name[4] - '0');
5273 button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
5274 ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons);
5275
5276 wv = wv->contents;
5277 prompt = (char *) alloca (strlen (wv->value) + 1);
5278 strcpy (prompt, wv->value);
5279 c2pstr (prompt);
5280
5281 wv = wv->next;
5282 for (i = 0; i < nb_buttons; i++)
5283 {
5284 button_labels[i] = wv->value;
5285 button_labels[i] = (char *) alloca (strlen (wv->value) + 1);
5286 strcpy (button_labels[i], wv->value);
5287 c2pstr (button_labels[i]);
5288 ref_cons[i] = (UInt32) wv->call_data;
5289 wv = wv->next;
5290 }
5291
5292 window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowRef) -1);
5293
5294 SetPortWindowPort (window_ptr);
5295
5296 TextFont (0);
5297 /* Left and right margins in the dialog are 13 pixels each.*/
5298 dialog_width = 14;
5299 /* Calculate width of dialog box: 8 pixels on each side of the text
5300 label in each button, 12 pixels between buttons. */
5301 for (i = 0; i < nb_buttons; i++)
5302 dialog_width += StringWidth (button_labels[i]) + 16 + 12;
5303
5304 if (left_count != 0 && nb_buttons - left_count != 0)
5305 dialog_width += 12;
5306
5307 dialog_width = max (dialog_width, StringWidth (prompt) + 26);
5308
5309 SizeWindow (window_ptr, dialog_width, 78, 0);
5310 ShowWindow (window_ptr);
5311
5312 SetPortWindowPort (window_ptr);
5313
5314 TextFont (0);
5315
5316 MoveTo (13, 29);
5317 DrawString (prompt);
5318
5319 left = 13;
5320 for (i = 0; i < nb_buttons; i++)
5321 {
5322 int button_width = StringWidth (button_labels[i]) + 16;
5323 SetRect (&rect, left, 45, left + button_width, 65);
5324 ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0,
5325 kControlPushButtonProc, ref_cons[i]);
5326 left += button_width + 12;
5327 if (i == left_count - 1)
5328 left += 12;
5329 }
5330
5331 i = 0;
5332 while (!i)
5333 {
5334 if (WaitNextEvent (mDownMask, &event_record, 10, NULL))
5335 if (event_record.what == mouseDown)
5336 {
5337 part_code = FindWindow (event_record.where, &window_ptr);
5338 if (part_code == inContent)
5339 {
5340 mouse = event_record.where;
5341 GlobalToLocal (&mouse);
5342 control_part_code = FindControl (mouse, window_ptr, &ch);
5343 if (control_part_code == kControlButtonPart)
5344 if (TrackControl (ch, mouse, NULL))
5345 i = GetControlReference (ch);
5346 }
5347 }
5348 }
5349
5350 DisposeWindow (window_ptr);
5351
5352 return i;
5353}
5354#endif /* not TARGET_API_MAC_CARBON */
5355
5356
5357/***********************************************************************
5358 Selection support
5359***********************************************************************/
5360
5361#if !TARGET_API_MAC_CARBON
5362#include <Scrap.h>
5363#include <Endian.h>
5364#endif
5365
5366extern Lisp_Object Vselection_converter_alist;
5367extern Lisp_Object Qmac_scrap_name, Qmac_ostype;
5368
5369static ScrapFlavorType get_flavor_type_from_symbol P_ ((Lisp_Object,
5370 Selection));
5371
5372/* Get a reference to the selection corresponding to the symbol SYM.
5373 The reference is set to *SEL, and it becomes NULL if there's no
5374 corresponding selection. Clear the selection if CLEAR_P is
5375 non-zero. */
5376
5377OSStatus
5378mac_get_selection_from_symbol (sym, clear_p, sel)
5379 Lisp_Object sym;
5380 int clear_p;
5381 Selection *sel;
5382{
5383 OSStatus err = noErr;
5384 Lisp_Object str = Fget (sym, Qmac_scrap_name);
5385
5386 if (!STRINGP (str))
5387 *sel = NULL;
5388 else
5389 {
5390#if TARGET_API_MAC_CARBON
5391#ifdef MAC_OSX
5392 CFStringRef scrap_name = cfstring_create_with_string (str);
5393 OptionBits options = (clear_p ? kScrapClearNamedScrap
5394 : kScrapGetNamedScrap);
5395
5396 err = GetScrapByName (scrap_name, options, sel);
5397 CFRelease (scrap_name);
5398#else /* !MAC_OSX */
5399 if (clear_p)
5400 err = ClearCurrentScrap ();
5401 if (err == noErr)
5402 err = GetCurrentScrap (sel);
5403#endif /* !MAC_OSX */
5404#else /* !TARGET_API_MAC_CARBON */
5405 if (clear_p)
5406 err = ZeroScrap ();
5407 if (err == noErr)
5408 *sel = 1;
5409#endif /* !TARGET_API_MAC_CARBON */
5410 }
5411
5412 return err;
5413}
5414
5415/* Get a scrap flavor type from the symbol SYM. Return 0 if no
5416 corresponding flavor type. If SEL is non-zero, the return value is
5417 non-zero only when the SEL has the flavor type. */
5418
5419static ScrapFlavorType
5420get_flavor_type_from_symbol (sym, sel)
5421 Lisp_Object sym;
5422 Selection sel;
5423{
5424 Lisp_Object str = Fget (sym, Qmac_ostype);
5425 ScrapFlavorType flavor_type;
5426
5427 if (STRINGP (str) && SBYTES (str) == 4)
5428 flavor_type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
5429 else
5430 flavor_type = 0;
5431
5432 if (flavor_type && sel)
5433 {
5434#if TARGET_API_MAC_CARBON
5435 OSStatus err;
5436 ScrapFlavorFlags flags;
5437
5438 err = GetScrapFlavorFlags (sel, flavor_type, &flags);
5439 if (err != noErr)
5440 flavor_type = 0;
5441#else /* !TARGET_API_MAC_CARBON */
5442 SInt32 size, offset;
5443
5444 size = GetScrap (NULL, flavor_type, &offset);
5445 if (size < 0)
5446 flavor_type = 0;
5447#endif /* !TARGET_API_MAC_CARBON */
5448 }
5449
5450 return flavor_type;
5451}
5452
5453/* Check if the symbol SYM has a corresponding selection target type. */
5454
5455int
5456mac_valid_selection_target_p (sym)
5457 Lisp_Object sym;
5458{
5459 return get_flavor_type_from_symbol (sym, 0) != 0;
5460}
5461
5462/* Clear the selection whose reference is *SEL. */
5463
5464OSStatus
5465mac_clear_selection (sel)
5466 Selection *sel;
5467{
5468#if TARGET_API_MAC_CARBON
5469#ifdef MAC_OSX
5470 return ClearScrap (sel);
5471#else
5472 OSStatus err;
5473
5474 err = ClearCurrentScrap ();
5475 if (err == noErr)
5476 err = GetCurrentScrap (sel);
5477 return err;
5478#endif
5479#else /* !TARGET_API_MAC_CARBON */
5480 return ZeroScrap ();
5481#endif /* !TARGET_API_MAC_CARBON */
5482}
5483
5484/* Get ownership information for SEL. Emacs can detect a change of
5485 the ownership by comparing saved and current values of the
5486 ownership information. */
5487
5488Lisp_Object
5489mac_get_selection_ownership_info (sel)
5490 Selection sel;
5491{
5492#if TARGET_API_MAC_CARBON
5493 return long_to_cons ((unsigned long) sel);
5494#else /* !TARGET_API_MAC_CARBON */
5495 ScrapStuffPtr scrap_info = InfoScrap ();
5496
5497 return make_number (scrap_info->scrapCount);
5498#endif /* !TARGET_API_MAC_CARBON */
5499}
5500
5501/* Return non-zero if VALUE is a valid selection value for TARGET. */
5502
5503int
5504mac_valid_selection_value_p (value, target)
5505 Lisp_Object value, target;
5506{
5507 return STRINGP (value);
5508}
5509
5510/* Put Lisp object VALUE to the selection SEL. The target type is
5511 specified by TARGET. */
5512
5513OSStatus
5514mac_put_selection_value (sel, target, value)
5515 Selection sel;
5516 Lisp_Object target, value;
5517{
5518 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, 0);
5519
5520 if (flavor_type == 0 || !STRINGP (value))
5521 return noTypeErr;
5522
5523#if TARGET_API_MAC_CARBON
5524 return PutScrapFlavor (sel, flavor_type, kScrapFlavorMaskNone,
5525 SBYTES (value), SDATA (value));
5526#else /* !TARGET_API_MAC_CARBON */
5527 return PutScrap (SBYTES (value), flavor_type, SDATA (value));
5528#endif /* !TARGET_API_MAC_CARBON */
5529}
5530
5531/* Check if data for the target type TARGET is available in SEL. */
5532
5533int
5534mac_selection_has_target_p (sel, target)
5535 Selection sel;
5536 Lisp_Object target;
5537{
5538 return get_flavor_type_from_symbol (target, sel) != 0;
5539}
5540
5541/* Get data for the target type TARGET from SEL and create a Lisp
5542 string. Return nil if failed to get data. */
5543
5544Lisp_Object
5545mac_get_selection_value (sel, target)
5546 Selection sel;
5547 Lisp_Object target;
5548{
5549 OSStatus err;
5550 Lisp_Object result = Qnil;
5551 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, sel);
5552#if TARGET_API_MAC_CARBON
5553 Size size;
5554
5555 if (flavor_type)
5556 {
5557 err = GetScrapFlavorSize (sel, flavor_type, &size);
5558 if (err == noErr)
5559 {
5560 do
5561 {
5562 result = make_uninit_string (size);
5563 err = GetScrapFlavorData (sel, flavor_type,
5564 &size, SDATA (result));
5565 if (err != noErr)
5566 result = Qnil;
5567 else if (size < SBYTES (result))
5568 result = make_unibyte_string (SDATA (result), size);
5569 }
5570 while (STRINGP (result) && size > SBYTES (result));
5571 }
5572 }
5573#else
5574 Handle handle;
5575 SInt32 size, offset;
5576
5577 if (flavor_type)
5578 size = GetScrap (NULL, flavor_type, &offset);
5579 if (size >= 0)
5580 {
5581 handle = NewHandle (size);
5582 HLock (handle);
5583 size = GetScrap (handle, flavor_type, &offset);
5584 if (size >= 0)
5585 result = make_unibyte_string (*handle, size);
5586 DisposeHandle (handle);
5587 }
5588#endif
5589
5590 return result;
5591}
5592
5593/* Get the list of target types in SEL. The return value is a list of
5594 target type symbols possibly followed by scrap flavor type
5595 strings. */
5596
5597Lisp_Object
5598mac_get_selection_target_list (sel)
5599 Selection sel;
5600{
5601 Lisp_Object result = Qnil, rest, target;
5602#if TARGET_API_MAC_CARBON
5603 OSStatus err;
5604 UInt32 count, i, type;
5605 ScrapFlavorInfo *flavor_info = NULL;
5606 Lisp_Object strings = Qnil;
5607
5608 err = GetScrapFlavorCount (sel, &count);
5609 if (err == noErr)
5610 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
5611 err = GetScrapFlavorInfoList (sel, &count, flavor_info);
5612 if (err != noErr)
5613 {
5614 xfree (flavor_info);
5615 flavor_info = NULL;
5616 }
5617 if (flavor_info == NULL)
5618 count = 0;
5619#endif
5620 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
5621 {
5622 ScrapFlavorType flavor_type = 0;
5623
5624 if (CONSP (XCAR (rest))
5625 && (target = XCAR (XCAR (rest)),
5626 SYMBOLP (target))
5627 && (flavor_type = get_flavor_type_from_symbol (target, sel)))
5628 {
5629 result = Fcons (target, result);
5630#if TARGET_API_MAC_CARBON
5631 for (i = 0; i < count; i++)
5632 if (flavor_info[i].flavorType == flavor_type)
5633 {
5634 flavor_info[i].flavorType = 0;
5635 break;
5636 }
5637#endif
5638 }
5639 }
5640#if TARGET_API_MAC_CARBON
5641 if (flavor_info)
5642 {
5643 for (i = 0; i < count; i++)
5644 if (flavor_info[i].flavorType)
5645 {
5646 type = EndianU32_NtoB (flavor_info[i].flavorType);
5647 strings = Fcons (make_unibyte_string ((char *) &type, 4), strings);
5648 }
5649 result = nconc2 (result, strings);
5650 xfree (flavor_info);
5651 }
5652#endif
5653
5654 return result;
5655}
5656
5657
5658/***********************************************************************
5659 Apple event support
5660***********************************************************************/
5661
5662extern pascal OSErr mac_handle_apple_event P_ ((const AppleEvent *,
5663 AppleEvent *, SInt32));
5664extern void cleanup_all_suspended_apple_events P_ ((void));
5665
5666void
5667init_apple_event_handler ()
5668{
5669 OSErr err;
5670 long result;
5671
5672 /* Make sure we have Apple events before starting. */
5673 err = Gestalt (gestaltAppleEventsAttr, &result);
5674 if (err != noErr)
5675 abort ();
5676
5677 if (!(result & (1 << gestaltAppleEventsPresent)))
5678 abort ();
5679
5680 err = AEInstallEventHandler (typeWildCard, typeWildCard,
5681#if TARGET_API_MAC_CARBON
5682 NewAEEventHandlerUPP (mac_handle_apple_event),
5683#else
5684 NewAEEventHandlerProc (mac_handle_apple_event),
5685#endif
5686 0L, false);
5687 if (err != noErr)
5688 abort ();
5689
5690 atexit (cleanup_all_suspended_apple_events);
5691}
5692
5693
5694/***********************************************************************
5695 Drag and drop support
5696***********************************************************************/
5697
5698#if TARGET_API_MAC_CARBON
5699extern Lisp_Object Vmac_dnd_known_types;
5700
5701static pascal OSErr mac_do_track_drag P_ ((DragTrackingMessage, WindowRef,
5702 void *, DragRef));
5703static pascal OSErr mac_do_receive_drag P_ ((WindowRef, void *, DragRef));
5704static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL;
5705static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL;
5706
5707static void
5708mac_store_drag_event (window, mouse_pos, modifiers, desc)
5709 WindowRef window;
5710 Point mouse_pos;
5711 SInt16 modifiers;
5712 const AEDesc *desc;
5713{
5714 struct input_event buf;
5715
5716 EVENT_INIT (buf);
5717
5718 buf.kind = DRAG_N_DROP_EVENT;
5719 buf.modifiers = mac_to_emacs_modifiers (modifiers, 0);
5720 buf.timestamp = TickCount () * (1000 / 60);
5721 XSETINT (buf.x, mouse_pos.h);
5722 XSETINT (buf.y, mouse_pos.v);
5723 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
5724 buf.arg = mac_aedesc_to_lisp (desc);
5725 kbd_buffer_store_event (&buf);
5726}
5727
5728static pascal OSErr
5729mac_do_track_drag (message, window, refcon, drag)
5730 DragTrackingMessage message;
5731 WindowRef window;
5732 void *refcon;
5733 DragRef drag;
5734{
5735 OSErr err = noErr;
5736 static int can_accept;
5737 UInt16 num_items, index;
5738
5739 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
5740 return dragNotAcceptedErr;
5741
5742 switch (message)
5743 {
5744 case kDragTrackingEnterHandler:
5745 err = CountDragItems (drag, &num_items);
5746 if (err != noErr)
5747 break;
5748 can_accept = 0;
5749 for (index = 1; index <= num_items; index++)
5750 {
5751 ItemReference item;
5752 FlavorFlags flags;
5753 Lisp_Object rest;
5754
5755 err = GetDragItemReferenceNumber (drag, index, &item);
5756 if (err != noErr)
5757 continue;
5758 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
5759 {
5760 Lisp_Object str;
5761 FlavorType type;
5762
5763 str = XCAR (rest);
5764 if (!(STRINGP (str) && SBYTES (str) == 4))
5765 continue;
5766 type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
5767
5768 err = GetFlavorFlags (drag, item, type, &flags);
5769 if (err == noErr)
5770 {
5771 can_accept = 1;
5772 break;
5773 }
5774 }
5775 }
5776 break;
5777
5778 case kDragTrackingEnterWindow:
5779 if (can_accept)
5780 {
5781 RgnHandle hilite_rgn = NewRgn ();
5782
5783 if (hilite_rgn)
5784 {
5785 Rect r;
5786
5787 GetWindowPortBounds (window, &r);
5788 OffsetRect (&r, -r.left, -r.top);
5789 RectRgn (hilite_rgn, &r);
5790 ShowDragHilite (drag, hilite_rgn, true);
5791 DisposeRgn (hilite_rgn);
5792 }
5793 SetThemeCursor (kThemeCopyArrowCursor);
5794 }
5795 break;
5796
5797 case kDragTrackingInWindow:
5798 break;
5799
5800 case kDragTrackingLeaveWindow:
5801 if (can_accept)
5802 {
5803 HideDragHilite (drag);
5804 SetThemeCursor (kThemeArrowCursor);
5805 }
5806 break;
5807
5808 case kDragTrackingLeaveHandler:
5809 break;
5810 }
5811
5812 if (err != noErr)
5813 return dragNotAcceptedErr;
5814 return noErr;
5815}
5816
5817static pascal OSErr
5818mac_do_receive_drag (window, refcon, drag)
5819 WindowRef window;
5820 void *refcon;
5821 DragRef drag;
5822{
5823 OSErr err;
5824 int num_types, i;
5825 Lisp_Object rest, str;
5826 FlavorType *types;
5827 AppleEvent apple_event;
5828 Point mouse_pos;
5829 SInt16 modifiers;
5830
5831 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
5832 return dragNotAcceptedErr;
5833
5834 num_types = 0;
5835 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
5836 {
5837 str = XCAR (rest);
5838 if (STRINGP (str) && SBYTES (str) == 4)
5839 num_types++;
5840 }
5841
5842 types = xmalloc (sizeof (FlavorType) * num_types);
5843 i = 0;
5844 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
5845 {
5846 str = XCAR (rest);
5847 if (STRINGP (str) && SBYTES (str) == 4)
5848 types[i++] = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
5849 }
5850
5851 err = create_apple_event_from_drag_ref (drag, num_types, types,
5852 &apple_event);
5853 xfree (types);
5854
5855 if (err == noErr)
5856 err = GetDragMouse (drag, &mouse_pos, NULL);
5857 if (err == noErr)
5858 {
5859 GlobalToLocal (&mouse_pos);
5860 err = GetDragModifiers (drag, NULL, NULL, &modifiers);
5861 }
5862 if (err == noErr)
5863 {
5864 UInt32 key_modifiers = modifiers;
5865
5866 err = AEPutParamPtr (&apple_event, kEventParamKeyModifiers,
5867 typeUInt32, &key_modifiers, sizeof (UInt32));
5868 }
5869
5870 if (err == noErr)
5871 {
5872 mac_store_drag_event (window, mouse_pos, 0, &apple_event);
5873 AEDisposeDesc (&apple_event);
5874 mac_wakeup_from_rne ();
5875 return noErr;
5876 }
5877 else
5878 return dragNotAcceptedErr;
5879}
5880#endif /* TARGET_API_MAC_CARBON */
5881
5882static OSErr
5883install_drag_handler (window)
5884 WindowRef window;
5885{
5886 OSErr err = noErr;
5887
5888#if TARGET_API_MAC_CARBON
5889 if (mac_do_track_dragUPP == NULL)
5890 mac_do_track_dragUPP = NewDragTrackingHandlerUPP (mac_do_track_drag);
5891 if (mac_do_receive_dragUPP == NULL)
5892 mac_do_receive_dragUPP = NewDragReceiveHandlerUPP (mac_do_receive_drag);
5893
5894 err = InstallTrackingHandler (mac_do_track_dragUPP, window, NULL);
5895 if (err == noErr)
5896 err = InstallReceiveHandler (mac_do_receive_dragUPP, window, NULL);
5897#endif
5898
5899 return err;
5900}
5901
5902static void
5903remove_drag_handler (window)
5904 WindowRef window;
5905{
5906#if TARGET_API_MAC_CARBON
5907 if (mac_do_track_dragUPP)
5908 RemoveTrackingHandler (mac_do_track_dragUPP, window);
5909 if (mac_do_receive_dragUPP)
5910 RemoveReceiveHandler (mac_do_receive_dragUPP, window);
5911#endif
5912}
5913
5914#if TARGET_API_MAC_CARBON
5915/* Return default value for mac-dnd-known-types. */
5916
5917Lisp_Object
5918mac_dnd_default_known_types ()
5919{
5920 Lisp_Object result = list4 (build_string ("hfs "), build_string ("utxt"),
5921 build_string ("TEXT"), build_string ("TIFF"));
5922
5923#ifdef MAC_OSX
5924 result = Fcons (build_string ("furl"), result);
5925#endif
5926
5927 return result;
5928}
5929#endif
5930
5931
5932/***********************************************************************
5933 Services menu support
5934***********************************************************************/
5935
5936#ifdef MAC_OSX
5937extern Lisp_Object Qservice, Qpaste, Qperform;
5938extern Lisp_Object Vmac_service_selection;
5939
5940static OSStatus
5941mac_store_service_event (event)
5942 EventRef event;
5943{
5944 OSStatus err;
5945 Lisp_Object id_key;
5946 int num_params;
5947 const EventParamName *names;
5948 const EventParamType *types;
5949 static const EventParamName names_pfm[] =
5950 {kEventParamServiceMessageName, kEventParamServiceUserData};
5951 static const EventParamType types_pfm[] =
5952 {typeCFStringRef, typeCFStringRef};
5953
5954 switch (GetEventKind (event))
5955 {
5956 case kEventServicePaste:
5957 id_key = Qpaste;
5958 num_params = 0;
5959 names = NULL;
5960 types = NULL;
5961 break;
5962
5963 case kEventServicePerform:
5964 id_key = Qperform;
5965 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
5966 names = names_pfm;
5967 types = types_pfm;
5968 break;
5969
5970 default:
5971 abort ();
5972 }
5973
5974 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
5975 event, num_params,
5976 names, types);
5977
5978 return err;
5979}
5980
5981static OSStatus
5982copy_scrap_flavor_data (from_scrap, to_scrap, flavor_type)
5983 ScrapRef from_scrap, to_scrap;
5984 ScrapFlavorType flavor_type;
5985{
5986 OSStatus err;
5987 Size size, size_allocated;
5988 char *buf = NULL;
5989
5990 err = GetScrapFlavorSize (from_scrap, flavor_type, &size);
5991 if (err == noErr)
5992 buf = xmalloc (size);
5993 while (buf)
5994 {
5995 size_allocated = size;
5996 err = GetScrapFlavorData (from_scrap, flavor_type, &size, buf);
5997 if (err != noErr)
5998 {
5999 xfree (buf);
6000 buf = NULL;
6001 }
6002 else if (size_allocated < size)
6003 buf = xrealloc (buf, size);
6004 else
6005 break;
6006 }
6007 if (err == noErr)
6008 {
6009 if (buf == NULL)
6010 err = memFullErr;
6011 else
6012 {
6013 err = PutScrapFlavor (to_scrap, flavor_type, kScrapFlavorMaskNone,
6014 size, buf);
6015 xfree (buf);
6016 }
6017 }
6018
6019 return err;
6020}
6021
6022static OSStatus
6023mac_handle_service_event (call_ref, event, data)
6024 EventHandlerCallRef call_ref;
6025 EventRef event;
6026 void *data;
6027{
6028 OSStatus err = noErr;
6029 ScrapRef cur_scrap, specific_scrap;
6030 UInt32 event_kind = GetEventKind (event);
6031 CFMutableArrayRef copy_types, paste_types;
6032 CFStringRef type;
6033 Lisp_Object rest;
6034 ScrapFlavorType flavor_type;
6035
6036 /* Check if Vmac_service_selection is a valid selection that has a
6037 corresponding scrap. */
6038 if (!SYMBOLP (Vmac_service_selection))
6039 err = eventNotHandledErr;
6040 else
6041 err = mac_get_selection_from_symbol (Vmac_service_selection, 0, &cur_scrap);
6042 if (!(err == noErr && cur_scrap))
6043 return eventNotHandledErr;
6044
6045 switch (event_kind)
6046 {
6047 case kEventServiceGetTypes:
6048 /* Set paste types. */
6049 err = GetEventParameter (event, kEventParamServicePasteTypes,
6050 typeCFMutableArrayRef, NULL,
6051 sizeof (CFMutableArrayRef), NULL,
6052 &paste_types);
6053 if (err != noErr)
6054 break;
6055
6056 for (rest = Vselection_converter_alist; CONSP (rest);
6057 rest = XCDR (rest))
6058 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
6059 && (flavor_type =
6060 get_flavor_type_from_symbol (XCAR (XCAR (rest)), 0)))
6061 {
6062 type = CreateTypeStringWithOSType (flavor_type);
6063 if (type)
6064 {
6065 CFArrayAppendValue (paste_types, type);
6066 CFRelease (type);
6067 }
6068 }
6069
6070 /* Set copy types. */
6071 err = GetEventParameter (event, kEventParamServiceCopyTypes,
6072 typeCFMutableArrayRef, NULL,
6073 sizeof (CFMutableArrayRef), NULL,
6074 &copy_types);
6075 if (err != noErr)
6076 break;
6077
6078 if (NILP (Fx_selection_owner_p (Vmac_service_selection)))
6079 break;
6080 else
6081 goto copy_all_flavors;
6082
6083 case kEventServiceCopy:
6084 err = GetEventParameter (event, kEventParamScrapRef,
6085 typeScrapRef, NULL,
6086 sizeof (ScrapRef), NULL, &specific_scrap);
6087 if (err != noErr
6088 || NILP (Fx_selection_owner_p (Vmac_service_selection)))
6089 {
6090 err = eventNotHandledErr;
6091 break;
6092 }
6093
6094 copy_all_flavors:
6095 {
6096 UInt32 count, i;
6097 ScrapFlavorInfo *flavor_info = NULL;
6098 ScrapFlavorFlags flags;
6099
6100 err = GetScrapFlavorCount (cur_scrap, &count);
6101 if (err == noErr)
6102 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
6103 err = GetScrapFlavorInfoList (cur_scrap, &count, flavor_info);
6104 if (err != noErr)
6105 {
6106 xfree (flavor_info);
6107 flavor_info = NULL;
6108 }
6109 if (flavor_info == NULL)
6110 break;
6111
6112 for (i = 0; i < count; i++)
6113 {
6114 flavor_type = flavor_info[i].flavorType;
6115 err = GetScrapFlavorFlags (cur_scrap, flavor_type, &flags);
6116 if (err == noErr && !(flags & kScrapFlavorMaskSenderOnly))
6117 {
6118 if (event_kind == kEventServiceCopy)
6119 err = copy_scrap_flavor_data (cur_scrap, specific_scrap,
6120 flavor_type);
6121 else /* event_kind == kEventServiceGetTypes */
6122 {
6123 type = CreateTypeStringWithOSType (flavor_type);
6124 if (type)
6125 {
6126 CFArrayAppendValue (copy_types, type);
6127 CFRelease (type);
6128 }
6129 }
6130 }
6131 }
6132 xfree (flavor_info);
6133 }
6134 break;
6135
6136 case kEventServicePaste:
6137 case kEventServicePerform:
6138 {
6139 int data_exists_p = 0;
6140
6141 err = GetEventParameter (event, kEventParamScrapRef, typeScrapRef,
6142 NULL, sizeof (ScrapRef), NULL,
6143 &specific_scrap);
6144 if (err == noErr)
6145 err = mac_clear_selection (&cur_scrap);
6146 if (err == noErr)
6147 for (rest = Vselection_converter_alist; CONSP (rest);
6148 rest = XCDR (rest))
6149 {
6150 if (! (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))))
6151 continue;
6152 flavor_type = get_flavor_type_from_symbol (XCAR (XCAR (rest)),
6153 specific_scrap);
6154 if (flavor_type == 0)
6155 continue;
6156 err = copy_scrap_flavor_data (specific_scrap, cur_scrap,
6157 flavor_type);
6158 if (err == noErr)
6159 data_exists_p = 1;
6160 }
6161 if (!data_exists_p)
6162 err = eventNotHandledErr;
6163 else
6164 err = mac_store_service_event (event);
6165 }
6166 break;
6167 }
6168
6169 if (err != noErr)
6170 err = eventNotHandledErr;
6171 return err;
6172}
6173
6174static OSStatus
6175install_service_handler ()
6176{
6177 static const EventTypeSpec specs[] =
6178 {{kEventClassService, kEventServiceGetTypes},
6179 {kEventClassService, kEventServiceCopy},
6180 {kEventClassService, kEventServicePaste},
6181 {kEventClassService, kEventServicePerform}};
6182
6183 return InstallApplicationEventHandler (NewEventHandlerUPP
6184 (mac_handle_service_event),
6185 GetEventTypeCount (specs),
6186 specs, NULL, NULL);
6187}
6188#endif /* MAC_OSX */
6189
6190
6191/***********************************************************************
6192 Initialization
6193 ***********************************************************************/
6194
6195void
6196mac_toolbox_initialize ()
6197{
6198 any_help_event_p = 0;
6199
6200 init_menu_bar ();
6201
6202#ifdef MAC_OSX
6203 init_apple_event_handler ();
6204#endif
6205#if USE_MAC_TSM
6206 init_tsm ();
6207#endif
6208}
6209
6210/* arch-tag: 71a597a8-6e9f-47b0-8b89-5a5ae3e16516
6211 (do not change this comment) */