(tags-query-replace): Set arg `map' of `perform-replace'
[emacs.git] / src / mactoolbox.c
blobc6e5f8bcf8a0eb5d5be6c6efbe876dc95906f42a
1 /* Functions for GUI implemented with (HI)Toolbox on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
3 2008 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 #include <config.h>
22 #include <stdio.h>
24 #include "lisp.h"
25 #include "blockinput.h"
27 #include "macterm.h"
29 #if !TARGET_API_MAC_CARBON
30 #include <Quickdraw.h>
31 #include <ToolUtils.h>
32 #include <Sound.h>
33 #include <Events.h>
34 #include <Script.h>
35 #include <Resources.h>
36 #include <Fonts.h>
37 #include <TextUtils.h>
38 #include <LowMem.h>
39 #include <Controls.h>
40 #include <Windows.h>
41 #include <Displays.h>
42 #if defined (__MRC__) || (__MSL__ >= 0x6000)
43 #include <ControlDefinitions.h>
44 #endif
46 #if __profile__
47 #include <profiler.h>
48 #endif
49 #endif /* not TARGET_API_MAC_CARBON */
51 #include "charset.h"
52 #include "coding.h"
53 #include "frame.h"
54 #include "dispextern.h"
55 #include "fontset.h"
56 #include "termhooks.h"
57 #include "buffer.h"
58 #include "window.h"
59 #include "keyboard.h"
61 #include <sys/param.h>
63 #ifndef MAC_OSX
64 #include <alloca.h>
65 #endif
68 /************************************************************************
69 General
70 ************************************************************************/
72 /* The difference in pixels between the top left corner of the
73 Emacs window (including possible window manager decorations)
74 and FRAME_MAC_WINDOW (f). */
75 #define FRAME_OUTER_TO_INNER_DIFF_X(f) ((f)->x_pixels_diff)
76 #define FRAME_OUTER_TO_INNER_DIFF_Y(f) ((f)->y_pixels_diff)
78 #define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP)
80 void
81 mac_alert_sound_play ()
83 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
84 AlertSoundPlay ();
85 #else
86 SysBeep (1);
87 #endif
91 /************************************************************************
92 Application
93 ************************************************************************/
95 extern struct frame *mac_focus_frame P_ ((struct mac_display_info *));
96 extern void do_keystroke P_ ((EventKind, unsigned char, UInt32, UInt32,
97 unsigned long, struct input_event *));
98 extern UInt32 mac_mapped_modifiers P_ ((UInt32, UInt32));
99 #if TARGET_API_MAC_CARBON
100 extern int mac_to_emacs_modifiers P_ ((UInt32, UInt32));
101 #else
102 extern int mac_to_emacs_modifiers P_ ((EventModifiers, EventModifiers));
103 #endif
105 #if TARGET_API_MAC_CARBON
106 /* Points to the variable `inev' in the function XTread_socket. It is
107 used for passing an input event to the function back from
108 Carbon/Apple event handlers. */
109 static struct input_event *read_socket_inev = NULL;
111 extern const unsigned char keycode_to_xkeysym_table[];
112 extern EMACS_INT extra_keyboard_modifiers;
114 extern Lisp_Object Qhi_command;
115 #if USE_MAC_TSM
116 static TSMDocumentID tsm_document_id;
117 extern Lisp_Object Qtext_input;
118 extern Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
119 extern Lisp_Object Vmac_ts_active_input_overlay, Vmac_ts_active_input_buf;
120 extern Lisp_Object Qbefore_string;
121 #endif
123 static int mac_event_to_emacs_modifiers P_ ((EventRef));
124 static OSStatus install_menu_target_item_handler P_ ((void));
125 #ifdef MAC_OSX
126 static OSStatus install_service_handler P_ ((void));
127 #endif
129 extern OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
130 Lisp_Object,
131 Lisp_Object,
132 EventRef, UInt32,
133 const EventParamName *,
134 const EventParamType *));
135 extern int fast_find_position P_ ((struct window *, int, int *, int *,
136 int *, int *, Lisp_Object));
137 extern struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
138 int *, int *, int *, int *, int *));
139 extern void mac_ax_selected_text_range P_ ((struct frame *, CFRange *));
140 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
141 extern unsigned int mac_ax_number_of_characters P_ ((struct frame *));
142 #endif
144 #if USE_MAC_TSM
145 extern OSStatus mac_restore_keyboard_input_source P_ ((void));
146 extern void mac_save_keyboard_input_source P_ ((void));
148 static OSStatus
149 mac_tsm_resume ()
151 OSStatus err;
153 err = ActivateTSMDocument (tsm_document_id);
154 if (err == noErr)
155 err = mac_restore_keyboard_input_source ();
157 return err;
160 static OSStatus
161 mac_tsm_suspend ()
163 OSStatus err;
165 mac_save_keyboard_input_source ();
166 err = DeactivateTSMDocument (tsm_document_id);
168 return err;
171 static void
172 init_tsm ()
174 #ifdef MAC_OSX
175 static InterfaceTypeList types = {kUnicodeDocument};
176 #else
177 static InterfaceTypeList types = {kTextService};
178 #endif
180 NewTSMDocument (sizeof (types) / sizeof (types[0]), types,
181 &tsm_document_id, 0);
183 #endif /* USE_MAC_TSM */
185 static pascal OSStatus
186 mac_handle_keyboard_event (next_handler, event, data)
187 EventHandlerCallRef next_handler;
188 EventRef event;
189 void *data;
191 OSStatus err, result = eventNotHandledErr;
192 UInt32 event_kind, key_code, modifiers;
193 unsigned char char_code;
195 event_kind = GetEventKind (event);
196 switch (event_kind)
198 case kEventRawKeyDown:
199 case kEventRawKeyRepeat:
200 case kEventRawKeyUp:
201 /* When using Carbon Events, we need to pass raw keyboard events
202 to the TSM ourselves. If TSM handles it, it will pass back
203 noErr, otherwise it will pass back "eventNotHandledErr" and
204 we can process it normally. */
205 result = CallNextEventHandler (next_handler, event);
206 if (result != eventNotHandledErr)
207 break;
209 if (read_socket_inev == NULL)
210 break;
212 #if USE_MAC_TSM
213 if (read_socket_inev->kind != NO_EVENT)
215 result = noErr;
216 break;
218 #endif
220 if (event_kind == kEventRawKeyUp)
221 break;
223 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
224 typeChar, NULL,
225 sizeof (char), NULL, &char_code);
226 if (err != noErr)
227 break;
229 err = GetEventParameter (event, kEventParamKeyCode,
230 typeUInt32, NULL,
231 sizeof (UInt32), NULL, &key_code);
232 if (err != noErr)
233 break;
235 err = GetEventParameter (event, kEventParamKeyModifiers,
236 typeUInt32, NULL,
237 sizeof (UInt32), NULL, &modifiers);
238 if (err != noErr)
239 break;
241 do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey),
242 char_code, key_code, modifiers,
243 ((unsigned long)
244 (GetEventTime (event) / kEventDurationMillisecond)),
245 read_socket_inev);
246 result = noErr;
247 break;
249 default:
250 abort ();
253 return result;
256 static pascal OSStatus
257 mac_handle_command_event (next_handler, event, data)
258 EventHandlerCallRef next_handler;
259 EventRef event;
260 void *data;
262 OSStatus err, result = eventNotHandledErr;
263 HICommand command;
264 static const EventParamName names[] =
265 {kEventParamDirectObject, kEventParamKeyModifiers};
266 static const EventParamType types[] =
267 {typeHICommand, typeUInt32};
268 int num_params = sizeof (names) / sizeof (names[0]);
270 err = GetEventParameter (event, kEventParamDirectObject, typeHICommand,
271 NULL, sizeof (HICommand), NULL, &command);
272 if (err != noErr)
273 return eventNotHandledErr;
275 switch (GetEventKind (event))
277 case kEventCommandProcess:
278 result = CallNextEventHandler (next_handler, event);
279 if (result != eventNotHandledErr)
280 break;
282 err = GetEventParameter (event, kEventParamDirectObject,
283 typeHICommand, NULL,
284 sizeof (HICommand), NULL, &command);
286 if (err != noErr || command.commandID == 0)
287 break;
289 /* A HI command event is mapped to an Apple event whose event
290 class symbol is `hi-command' and event ID is its command
291 ID. */
292 err = mac_store_event_ref_as_apple_event (0, command.commandID,
293 Qhi_command, Qnil,
294 event, num_params,
295 names, types);
296 if (err == noErr)
297 result = noErr;
298 break;
300 default:
301 abort ();
304 return result;
307 static pascal OSStatus
308 mac_handle_mouse_event (next_handler, event, data)
309 EventHandlerCallRef next_handler;
310 EventRef event;
311 void *data;
313 OSStatus err, result = eventNotHandledErr;
315 switch (GetEventKind (event))
317 case kEventMouseWheelMoved:
319 WindowRef wp;
320 struct frame *f;
321 EventMouseWheelAxis axis;
322 SInt32 delta;
323 Point point;
325 result = CallNextEventHandler (next_handler, event);
326 if (result != eventNotHandledErr || read_socket_inev == NULL)
327 break;
329 f = mac_focus_frame (&one_mac_display_info);
331 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
332 NULL, sizeof (WindowRef), NULL, &wp);
333 if (err != noErr
334 || wp != FRAME_MAC_WINDOW (f))
335 break;
337 err = GetEventParameter (event, kEventParamMouseWheelAxis,
338 typeMouseWheelAxis, NULL,
339 sizeof (EventMouseWheelAxis), NULL, &axis);
340 if (err != noErr || axis != kEventMouseWheelAxisY)
341 break;
343 err = GetEventParameter (event, kEventParamMouseLocation,
344 typeQDPoint, NULL, sizeof (Point),
345 NULL, &point);
346 if (err != noErr)
347 break;
349 point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
350 point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
351 if (point.h < 0 || point.v < 0
352 || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1),
353 f->tool_bar_window))
354 break;
356 err = GetEventParameter (event, kEventParamMouseWheelDelta,
357 typeSInt32, NULL, sizeof (SInt32),
358 NULL, &delta);
359 if (err != noErr)
360 break;
362 read_socket_inev->kind = WHEEL_EVENT;
363 read_socket_inev->code = 0;
364 read_socket_inev->modifiers =
365 (mac_event_to_emacs_modifiers (event)
366 | ((delta < 0) ? down_modifier : up_modifier));
367 XSETINT (read_socket_inev->x, point.h);
368 XSETINT (read_socket_inev->y, point.v);
369 XSETFRAME (read_socket_inev->frame_or_window, f);
371 result = noErr;
373 break;
375 default:
376 abort ();
379 return result;
382 #if USE_MAC_TSM
383 extern void mac_get_selected_range P_ ((struct window *, CFRange *));
384 extern int mac_store_buffer_text_to_unicode_chars P_ ((struct buffer *,
385 int, int, UniChar *));
387 static pascal OSStatus
388 mac_handle_text_input_event (next_handler, event, data)
389 EventHandlerCallRef next_handler;
390 EventRef event;
391 void *data;
393 OSStatus err, result;
394 Lisp_Object id_key = Qnil;
395 int num_params;
396 const EventParamName *names;
397 const EventParamType *types;
398 static UInt32 seqno_uaia = 0;
399 static const EventParamName names_uaia[] =
400 {kEventParamTextInputSendComponentInstance,
401 kEventParamTextInputSendRefCon,
402 kEventParamTextInputSendSLRec,
403 kEventParamTextInputSendFixLen,
404 kEventParamTextInputSendText,
405 kEventParamTextInputSendUpdateRng,
406 kEventParamTextInputSendHiliteRng,
407 kEventParamTextInputSendClauseRng,
408 kEventParamTextInputSendPinRng,
409 kEventParamTextInputSendTextServiceEncoding,
410 kEventParamTextInputSendTextServiceMacEncoding,
411 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER};
412 static const EventParamType types_uaia[] =
413 {typeComponentInstance,
414 typeLongInteger,
415 typeIntlWritingCode,
416 typeLongInteger,
417 #ifdef MAC_OSX
418 typeUnicodeText,
419 #else
420 typeChar,
421 #endif
422 typeTextRangeArray,
423 typeTextRangeArray,
424 typeOffsetArray,
425 typeTextRange,
426 typeUInt32,
427 typeUInt32,
428 typeUInt32};
429 static const EventParamName names_ufke[] =
430 {kEventParamTextInputSendComponentInstance,
431 kEventParamTextInputSendRefCon,
432 kEventParamTextInputSendSLRec,
433 kEventParamTextInputSendText};
434 static const EventParamType types_ufke[] =
435 {typeComponentInstance,
436 typeLongInteger,
437 typeIntlWritingCode,
438 typeUnicodeText};
440 result = CallNextEventHandler (next_handler, event);
441 if (result != eventNotHandledErr)
442 return result;
444 switch (GetEventKind (event))
446 case kEventTextInputUpdateActiveInputArea:
447 id_key = Qupdate_active_input_area;
448 num_params = sizeof (names_uaia) / sizeof (names_uaia[0]);
449 names = names_uaia;
450 types = types_uaia;
451 SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER,
452 typeUInt32, sizeof (UInt32), &seqno_uaia);
453 seqno_uaia++;
454 result = noErr;
455 break;
457 case kEventTextInputUnicodeForKeyEvent:
459 EventRef kbd_event;
460 UInt32 actual_size, modifiers, key_code;
462 err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent,
463 typeEventRef, NULL, sizeof (EventRef), NULL,
464 &kbd_event);
465 if (err == noErr)
466 err = GetEventParameter (kbd_event, kEventParamKeyModifiers,
467 typeUInt32, NULL,
468 sizeof (UInt32), NULL, &modifiers);
469 if (err == noErr)
470 err = GetEventParameter (kbd_event, kEventParamKeyCode,
471 typeUInt32, NULL, sizeof (UInt32),
472 NULL, &key_code);
473 if (err == noErr && mac_mapped_modifiers (modifiers, key_code))
474 /* There're mapped modifier keys. Process it in
475 do_keystroke. */
476 break;
477 if (err == noErr)
478 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
479 typeUnicodeText, NULL, 0, &actual_size,
480 NULL);
481 if (err == noErr && actual_size == sizeof (UniChar))
483 UniChar code;
485 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
486 typeUnicodeText, NULL,
487 sizeof (UniChar), NULL, &code);
488 if (err == noErr && code < 0x80)
490 /* ASCII character. Process it in do_keystroke. */
491 if (read_socket_inev && code >= 0x20 && code <= 0x7e
492 && !(key_code <= 0x7f
493 && keycode_to_xkeysym_table [key_code]))
495 struct frame *f = mac_focus_frame (&one_mac_display_info);
497 read_socket_inev->kind = ASCII_KEYSTROKE_EVENT;
498 read_socket_inev->code = code;
499 read_socket_inev->modifiers =
500 mac_to_emacs_modifiers (modifiers, 0);
501 read_socket_inev->modifiers |=
502 (extra_keyboard_modifiers
503 & (meta_modifier | alt_modifier
504 | hyper_modifier | super_modifier));
505 XSETFRAME (read_socket_inev->frame_or_window, f);
507 break;
510 if (err == noErr)
512 /* Non-ASCII keystrokes without mapped modifiers are
513 processed at the Lisp level. */
514 id_key = Qunicode_for_key_event;
515 num_params = sizeof (names_ufke) / sizeof (names_ufke[0]);
516 names = names_ufke;
517 types = types_ufke;
518 result = noErr;
521 break;
523 case kEventTextInputOffsetToPos:
525 long byte_offset;
526 struct frame *f;
527 struct window *w;
528 Point p;
530 err = GetEventParameter (event, kEventParamTextInputSendTextOffset,
531 typeLongInteger, NULL, sizeof (long), NULL,
532 &byte_offset);
533 if (err != noErr)
534 break;
536 if (STRINGP (Vmac_ts_active_input_buf)
537 && SBYTES (Vmac_ts_active_input_buf) != 0)
539 if (!OVERLAYP (Vmac_ts_active_input_overlay))
540 break;
542 /* Strictly speaking, this is not always correct because
543 previous events may change some states about display. */
544 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
546 /* Active input area is displayed around the current point. */
547 f = SELECTED_FRAME ();
548 w = XWINDOW (f->selected_window);
550 else if (WINDOWP (echo_area_window))
552 /* Active input area is displayed in the echo area. */
553 w = XWINDOW (echo_area_window);
554 f = WINDOW_XFRAME (w);
556 else
557 break;
559 p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
560 + WINDOW_LEFT_FRINGE_WIDTH (w)
561 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
562 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
563 + FONT_BASE (FRAME_FONT (f))
564 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
566 else
568 #ifndef MAC_OSX
569 break;
570 #else /* MAC_OSX */
571 CFRange sel_range;
572 int charpos;
573 int hpos, vpos, x, y;
574 struct glyph_row *row;
575 struct glyph *glyph;
576 struct face *face;
578 f = mac_focus_frame (&one_mac_display_info);
579 w = XWINDOW (f->selected_window);
580 mac_get_selected_range (w, &sel_range);
581 charpos = (BUF_BEGV (XBUFFER (w->buffer)) + sel_range.location
582 + byte_offset / (long) sizeof (UniChar));
584 if (!fast_find_position (w, charpos, &hpos, &vpos, &x, &y, Qnil))
586 result = errOffsetInvalid;
587 break;
590 row = MATRIX_ROW (w->current_matrix, vpos);
591 glyph = row->glyphs[TEXT_AREA] + hpos;
592 if (glyph->type != CHAR_GLYPH || glyph->glyph_not_available_p)
593 break;
595 p.h = (WINDOW_TEXT_TO_FRAME_PIXEL_X (w, x)
596 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
597 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, y)
598 + row->visible_height
599 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
601 face = FACE_FROM_ID (f, glyph->face_id);
602 if (face && face->font)
604 XFontStruct *font = face->font;
605 Fixed point_size = Long2Fix (font->mac_fontsize);
606 short height = row->visible_height;
607 short ascent = row->ascent;
609 SetEventParameter (event,
610 kEventParamTextInputReplyPointSize,
611 typeFixed, sizeof (Fixed), &point_size);
612 SetEventParameter (event,
613 kEventParamTextInputReplyLineHeight,
614 typeShortInteger, sizeof (short), &height);
615 SetEventParameter (event,
616 kEventParamTextInputReplyLineAscent,
617 typeShortInteger, sizeof (short), &ascent);
618 if (font->mac_fontnum != -1)
620 OSStatus err1;
621 FMFont fm_font;
622 FMFontStyle style;
624 err1 = FMGetFontFromFontFamilyInstance (font->mac_fontnum,
625 font->mac_fontface,
626 &fm_font, &style);
627 if (err1 == noErr)
628 SetEventParameter (event, kEventParamTextInputReplyFMFont,
629 typeUInt32, sizeof (UInt32), &fm_font);
630 else
632 long qd_font = font->mac_fontnum;
634 SetEventParameter (event, kEventParamTextInputReplyFont,
635 typeLongInteger, sizeof (long),
636 &qd_font);
639 else if (font->mac_style)
641 OSStatus err1;
642 ATSUFontID font_id;
644 err1 = ATSUGetAttribute (font->mac_style, kATSUFontTag,
645 sizeof (ATSUFontID), &font_id,
646 NULL);
647 if (err1 == noErr)
648 SetEventParameter (event, kEventParamTextInputReplyFMFont,
649 typeUInt32, sizeof (UInt32), &font_id);
651 else
652 abort ();
654 #endif /* MAC_OSX */
657 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
658 typeQDPoint, sizeof (Point), &p);
659 if (err == noErr)
660 result = noErr;
662 break;
664 #ifdef MAC_OSX
665 case kEventTextInputPosToOffset:
667 Point point;
668 Boolean leading_edge_p = true;
669 struct frame *f;
670 int x, y;
671 Lisp_Object window;
672 enum window_part part;
673 long region_class = kTSMOutsideOfBody, byte_offset = 0;
675 err = GetEventParameter (event, kEventParamTextInputSendCurrentPoint,
676 typeQDPoint, NULL, sizeof (Point), NULL,
677 &point);
678 if (err != noErr)
679 break;
681 GetEventParameter (event, kEventParamTextInputReplyLeadingEdge,
682 typeBoolean, NULL, sizeof (Boolean), NULL,
683 &leading_edge_p);
685 f = mac_focus_frame (&one_mac_display_info);
686 x = point.h - (f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
687 y = point.v - (f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
688 window = window_from_coordinates (f, x, y, &part, 0, 0, 1);
689 if (WINDOWP (window) && EQ (window, f->selected_window))
691 struct window *w;
692 struct buffer *b;
694 /* Convert to window-relative pixel coordinates. */
695 w = XWINDOW (window);
696 frame_to_window_pixel_xy (w, &x, &y);
698 /* Are we in a window whose display is up to date?
699 And verify the buffer's text has not changed. */
700 b = XBUFFER (w->buffer);
701 if (part == ON_TEXT
702 && EQ (w->window_end_valid, w->buffer)
703 && XINT (w->last_modified) == BUF_MODIFF (b)
704 && XINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
706 int hpos, vpos, area;
707 struct glyph *glyph;
709 /* Find the glyph under X/Y. */
710 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, 0, 0, &area);
712 if (glyph != NULL && area == TEXT_AREA)
714 byte_offset = ((glyph->charpos - BUF_BEGV (b))
715 * sizeof (UniChar));
716 region_class = kTSMInsideOfBody;
721 err = SetEventParameter (event, kEventParamTextInputReplyRegionClass,
722 typeLongInteger, sizeof (long),
723 &region_class);
724 if (err == noErr)
725 err = SetEventParameter (event, kEventParamTextInputReplyTextOffset,
726 typeLongInteger, sizeof (long),
727 &byte_offset);
728 if (err == noErr)
729 result = noErr;
731 break;
733 case kEventTextInputGetSelectedText:
735 struct frame *f = mac_focus_frame (&one_mac_display_info);
736 struct window *w = XWINDOW (f->selected_window);
737 struct buffer *b = XBUFFER (w->buffer);
738 CFRange sel_range;
739 int start, end;
740 UniChar *characters, c;
742 if (poll_suppress_count == 0 && !NILP (Vinhibit_quit))
743 /* Don't try to get buffer contents as the gap might be
744 being altered. */
745 break;
747 mac_get_selected_range (w, &sel_range);
748 if (sel_range.length == 0)
750 Boolean leading_edge_p;
752 err = GetEventParameter (event,
753 kEventParamTextInputReplyLeadingEdge,
754 typeBoolean, NULL, sizeof (Boolean), NULL,
755 &leading_edge_p);
756 if (err != noErr)
757 break;
759 start = BUF_BEGV (b) + sel_range.location;
760 if (!leading_edge_p)
761 start--;
762 end = start + 1;
763 characters = &c;
765 if (start < BUF_BEGV (b) || end > BUF_ZV (b))
766 break;
768 else
770 start = BUF_BEGV (b) + sel_range.location;
771 end = start + sel_range.length;
772 characters = xmalloc (sel_range.length * sizeof (UniChar));
775 if (mac_store_buffer_text_to_unicode_chars (b, start, end, characters))
776 err = SetEventParameter (event, kEventParamTextInputReplyText,
777 typeUnicodeText,
778 sel_range.length * sizeof (UniChar),
779 characters);
780 if (characters != &c)
781 xfree (characters);
783 if (err == noErr)
784 result = noErr;
786 break;
787 #endif /* MAC_OSX */
789 default:
790 abort ();
793 if (!NILP (id_key))
794 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
795 event, num_params,
796 names, types);
797 return result;
800 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
801 static pascal OSStatus
802 mac_handle_document_access_event (next_handler, event, data)
803 EventHandlerCallRef next_handler;
804 EventRef event;
805 void *data;
807 OSStatus err, result;
808 struct frame *f = mac_focus_frame (&one_mac_display_info);
810 result = CallNextEventHandler (next_handler, event);
811 if (result != eventNotHandledErr)
812 return result;
814 switch (GetEventKind (event))
816 case kEventTSMDocumentAccessGetLength:
818 CFIndex count = mac_ax_number_of_characters (f);
820 err = SetEventParameter (event, kEventParamTSMDocAccessCharacterCount,
821 typeCFIndex, sizeof (CFIndex), &count);
822 if (err == noErr)
823 result = noErr;
825 break;
827 case kEventTSMDocumentAccessGetSelectedRange:
829 CFRange sel_range;
831 mac_ax_selected_text_range (f, &sel_range);
832 err = SetEventParameter (event,
833 kEventParamTSMDocAccessReplyCharacterRange,
834 typeCFRange, sizeof (CFRange), &sel_range);
835 if (err == noErr)
836 result = noErr;
838 break;
840 case kEventTSMDocumentAccessGetCharacters:
842 struct buffer *b = XBUFFER (XWINDOW (f->selected_window)->buffer);
843 CFRange range;
844 Ptr characters;
845 int start, end;
847 if (poll_suppress_count == 0 && !NILP (Vinhibit_quit))
848 /* Don't try to get buffer contents as the gap might be
849 being altered. */
850 break;
852 err = GetEventParameter (event,
853 kEventParamTSMDocAccessSendCharacterRange,
854 typeCFRange, NULL, sizeof (CFRange), NULL,
855 &range);
856 if (err == noErr)
857 err = GetEventParameter (event,
858 kEventParamTSMDocAccessSendCharactersPtr,
859 typePtr, NULL, sizeof (Ptr), NULL,
860 &characters);
861 if (err != noErr)
862 break;
864 start = BUF_BEGV (b) + range.location;
865 end = start + range.length;
866 if (mac_store_buffer_text_to_unicode_chars (b, start, end,
867 (UniChar *) characters))
868 result = noErr;
870 break;
872 default:
873 abort ();
876 return result;
878 #endif
879 #endif
881 OSStatus
882 install_application_handler ()
884 OSStatus err = noErr;
886 if (err == noErr)
888 static const EventTypeSpec specs[] =
889 {{kEventClassKeyboard, kEventRawKeyDown},
890 {kEventClassKeyboard, kEventRawKeyRepeat},
891 {kEventClassKeyboard, kEventRawKeyUp}};
893 err = InstallApplicationEventHandler (NewEventHandlerUPP
894 (mac_handle_keyboard_event),
895 GetEventTypeCount (specs),
896 specs, NULL, NULL);
899 if (err == noErr)
901 static const EventTypeSpec specs[] =
902 {{kEventClassCommand, kEventCommandProcess}};
904 err = InstallApplicationEventHandler (NewEventHandlerUPP
905 (mac_handle_command_event),
906 GetEventTypeCount (specs),
907 specs, NULL, NULL);
910 if (err == noErr)
912 static const EventTypeSpec specs[] =
913 {{kEventClassMouse, kEventMouseWheelMoved}};
915 err = InstallApplicationEventHandler (NewEventHandlerUPP
916 (mac_handle_mouse_event),
917 GetEventTypeCount (specs),
918 specs, NULL, NULL);
921 #if USE_MAC_TSM
922 if (err == noErr)
924 static const EventTypeSpec specs[] =
925 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
926 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
927 {kEventClassTextInput, kEventTextInputOffsetToPos},
928 #ifdef MAC_OSX
929 {kEventClassTextInput, kEventTextInputPosToOffset},
930 {kEventClassTextInput, kEventTextInputGetSelectedText}
931 #endif
934 err = InstallApplicationEventHandler (NewEventHandlerUPP
935 (mac_handle_text_input_event),
936 GetEventTypeCount (specs),
937 specs, NULL, NULL);
940 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
941 if (err == noErr)
943 static const EventTypeSpec specs[] =
944 {{kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength},
945 {kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange},
946 {kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters}};
948 err = InstallApplicationEventHandler (mac_handle_document_access_event,
949 GetEventTypeCount (specs),
950 specs, NULL, NULL);
952 #endif
953 #endif
955 if (err == noErr)
956 err = install_menu_target_item_handler ();
958 #ifdef MAC_OSX
959 if (err == noErr)
960 err = install_service_handler ();
961 #endif
963 return err;
965 #endif /* TARGET_API_MAC_CARBON */
968 /************************************************************************
969 Windows
970 ************************************************************************/
972 #define DEFAULT_NUM_COLS 80
974 #define MIN_DOC_SIZE 64
975 #define MAX_DOC_SIZE 32767
977 /* Drag and Drop */
978 static OSErr install_drag_handler P_ ((WindowRef));
979 static void remove_drag_handler P_ ((WindowRef));
981 #if USE_CG_DRAWING
982 static void mac_prepare_for_quickdraw P_ ((struct frame *));
983 #endif
985 extern void mac_handle_visibility_change P_ ((struct frame *));
986 extern void mac_handle_origin_change P_ ((struct frame *));
987 extern void mac_handle_size_change P_ ((struct frame *, int, int));
989 #if TARGET_API_MAC_CARBON
990 #ifdef MAC_OSX
991 extern Lisp_Object Qwindow;
992 extern Lisp_Object Qtoolbar_switch_mode;
993 #endif
994 #endif
996 static void
997 do_window_update (WindowRef win)
999 struct frame *f = mac_window_to_frame (win);
1001 BeginUpdate (win);
1003 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
1004 below. */
1005 if (win != tip_window)
1007 if (f->async_visible == 0)
1009 /* Update events may occur when a frame gets iconified. */
1010 #if 0
1011 f->async_visible = 1;
1012 f->async_iconified = 0;
1013 SET_FRAME_GARBAGED (f);
1014 #endif
1016 else
1018 Rect r;
1019 #if TARGET_API_MAC_CARBON
1020 RgnHandle region = NewRgn ();
1022 GetPortVisibleRegion (GetWindowPort (win), region);
1023 GetRegionBounds (region, &r);
1024 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
1025 #if USE_CG_DRAWING
1026 mac_prepare_for_quickdraw (f);
1027 #endif
1028 UpdateControls (win, region);
1029 DisposeRgn (region);
1030 #else
1031 r = (*win->visRgn)->rgnBBox;
1032 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
1033 UpdateControls (win, win->visRgn);
1034 #endif
1038 EndUpdate (win);
1041 static int
1042 is_emacs_window (WindowRef win)
1044 Lisp_Object tail, frame;
1046 if (!win)
1047 return 0;
1049 FOR_EACH_FRAME (tail, frame)
1050 if (FRAME_MAC_P (XFRAME (frame)))
1051 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
1052 return 1;
1054 return 0;
1057 /* Handle drags in size box. Based on code contributed by Ben
1058 Mesander and IM - Window Manager A. */
1060 static void
1061 do_grow_window (w, e)
1062 WindowRef w;
1063 const EventRecord *e;
1065 Rect limit_rect;
1066 int rows, columns, width, height;
1067 struct frame *f = mac_window_to_frame (w);
1068 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
1069 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
1070 #if TARGET_API_MAC_CARBON
1071 Rect new_rect;
1072 #else
1073 long grow_size;
1074 #endif
1076 if (size_hints->flags & PMinSize)
1078 min_width = size_hints->min_width;
1079 min_height = size_hints->min_height;
1081 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
1083 #if TARGET_API_MAC_CARBON
1084 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
1085 return;
1086 height = new_rect.bottom - new_rect.top;
1087 width = new_rect.right - new_rect.left;
1088 #else
1089 grow_size = GrowWindow (w, e->where, &limit_rect);
1090 /* see if it really changed size */
1091 if (grow_size == 0)
1092 return;
1093 height = HiWord (grow_size);
1094 width = LoWord (grow_size);
1095 #endif
1097 if (width != FRAME_PIXEL_WIDTH (f)
1098 || height != FRAME_PIXEL_HEIGHT (f))
1100 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
1101 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
1103 x_set_window_size (f, 0, columns, rows);
1107 #if TARGET_API_MAC_CARBON
1108 static Point
1109 mac_get_ideal_size (f)
1110 struct frame *f;
1112 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
1113 WindowRef w = FRAME_MAC_WINDOW (f);
1114 Point ideal_size;
1115 Rect standard_rect;
1116 int height, width, columns, rows;
1118 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
1119 ideal_size.v = dpyinfo->height;
1120 IsWindowInStandardState (w, &ideal_size, &standard_rect);
1121 /* Adjust the standard size according to character boundaries. */
1122 width = standard_rect.right - standard_rect.left;
1123 height = standard_rect.bottom - standard_rect.top;
1124 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
1125 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
1126 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
1127 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1129 return ideal_size;
1132 static pascal OSStatus
1133 mac_handle_window_event (next_handler, event, data)
1134 EventHandlerCallRef next_handler;
1135 EventRef event;
1136 void *data;
1138 WindowRef wp;
1139 OSStatus err, result = eventNotHandledErr;
1140 struct frame *f;
1141 UInt32 attributes;
1142 XSizeHints *size_hints;
1144 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
1145 NULL, sizeof (WindowRef), NULL, &wp);
1146 if (err != noErr)
1147 return eventNotHandledErr;
1149 f = mac_window_to_frame (wp);
1150 switch (GetEventKind (event))
1152 /* -- window refresh events -- */
1154 case kEventWindowUpdate:
1155 result = CallNextEventHandler (next_handler, event);
1156 if (result != eventNotHandledErr)
1157 break;
1159 do_window_update (wp);
1160 result = noErr;
1161 break;
1163 /* -- window state change events -- */
1165 case kEventWindowShowing:
1166 size_hints = FRAME_SIZE_HINTS (f);
1167 if (!(size_hints->flags & (USPosition | PPosition)))
1169 struct frame *sf = SELECTED_FRAME ();
1171 if (!(FRAME_MAC_P (sf) && sf->async_visible))
1172 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
1173 else
1175 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
1176 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1177 kWindowCascadeStartAtParentWindowScreen
1178 #else
1179 kWindowCascadeOnParentWindowScreen
1180 #endif
1182 #if USE_MAC_TOOLBAR
1183 /* This is a workaround. RepositionWindow fails to put
1184 a window at the cascading position when its parent
1185 window has a Carbon HIToolbar. */
1186 if ((f->left_pos == sf->left_pos
1187 && f->top_pos == sf->top_pos)
1188 || (f->left_pos == sf->left_pos + 10 * 2
1189 && f->top_pos == sf->top_pos + 32 * 2))
1190 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
1191 #endif
1193 result = noErr;
1195 break;
1197 case kEventWindowHiding:
1198 /* Before unmapping the window, update the WM_SIZE_HINTS
1199 property to claim that the current position of the window is
1200 user-specified, rather than program-specified, so that when
1201 the window is mapped again, it will be placed at the same
1202 location, without forcing the user to position it by hand
1203 again (they have already done that once for this window.) */
1204 x_wm_set_size_hint (f, (long) 0, 1);
1205 result = noErr;
1206 break;
1208 case kEventWindowShown:
1209 case kEventWindowHidden:
1210 case kEventWindowCollapsed:
1211 case kEventWindowExpanded:
1212 mac_handle_visibility_change (f);
1213 result = noErr;
1214 break;
1216 case kEventWindowBoundsChanging:
1217 result = CallNextEventHandler (next_handler, event);
1218 if (result != eventNotHandledErr)
1219 break;
1221 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
1222 NULL, sizeof (UInt32), NULL, &attributes);
1223 if (err != noErr)
1224 break;
1226 size_hints = FRAME_SIZE_HINTS (f);
1227 if ((attributes & kWindowBoundsChangeUserResize)
1228 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
1229 == (PResizeInc | PBaseSize | PMinSize)))
1231 Rect bounds;
1232 int width, height;
1234 err = GetEventParameter (event, kEventParamCurrentBounds,
1235 typeQDRectangle, NULL, sizeof (Rect),
1236 NULL, &bounds);
1237 if (err != noErr)
1238 break;
1240 width = bounds.right - bounds.left;
1241 height = bounds.bottom - bounds.top;
1243 if (width < size_hints->min_width)
1244 width = size_hints->min_width;
1245 else
1246 width = size_hints->base_width
1247 + (int) ((width - size_hints->base_width)
1248 / (float) size_hints->width_inc + .5)
1249 * size_hints->width_inc;
1251 if (height < size_hints->min_height)
1252 height = size_hints->min_height;
1253 else
1254 height = size_hints->base_height
1255 + (int) ((height - size_hints->base_height)
1256 / (float) size_hints->height_inc + .5)
1257 * size_hints->height_inc;
1259 bounds.right = bounds.left + width;
1260 bounds.bottom = bounds.top + height;
1261 SetEventParameter (event, kEventParamCurrentBounds,
1262 typeQDRectangle, sizeof (Rect), &bounds);
1263 result = noErr;
1265 break;
1267 case kEventWindowBoundsChanged:
1268 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
1269 NULL, sizeof (UInt32), NULL, &attributes);
1270 if (err != noErr)
1271 break;
1273 if (attributes & kWindowBoundsChangeSizeChanged)
1275 Rect bounds;
1277 err = GetEventParameter (event, kEventParamCurrentBounds,
1278 typeQDRectangle, NULL, sizeof (Rect),
1279 NULL, &bounds);
1280 if (err == noErr)
1282 int width, height;
1284 width = bounds.right - bounds.left;
1285 height = bounds.bottom - bounds.top;
1286 mac_handle_size_change (f, width, height);
1287 mac_wakeup_from_rne ();
1291 if (attributes & kWindowBoundsChangeOriginChanged)
1292 mac_handle_origin_change (f);
1294 result = noErr;
1295 break;
1297 /* -- window action events -- */
1299 case kEventWindowClose:
1301 struct input_event buf;
1303 EVENT_INIT (buf);
1304 buf.kind = DELETE_WINDOW_EVENT;
1305 XSETFRAME (buf.frame_or_window, f);
1306 buf.arg = Qnil;
1307 kbd_buffer_store_event (&buf);
1309 result = noErr;
1310 break;
1312 case kEventWindowGetIdealSize:
1313 result = CallNextEventHandler (next_handler, event);
1314 if (result != eventNotHandledErr)
1315 break;
1318 Point ideal_size = mac_get_ideal_size (f);
1320 err = SetEventParameter (event, kEventParamDimensions,
1321 typeQDPoint, sizeof (Point), &ideal_size);
1322 if (err == noErr)
1323 result = noErr;
1325 break;
1327 #ifdef MAC_OSX
1328 case kEventWindowToolbarSwitchMode:
1330 static const EventParamName names[] = {kEventParamDirectObject,
1331 kEventParamWindowMouseLocation,
1332 kEventParamKeyModifiers,
1333 kEventParamMouseButton,
1334 kEventParamClickCount,
1335 kEventParamMouseChord};
1336 static const EventParamType types[] = {typeWindowRef,
1337 typeQDPoint,
1338 typeUInt32,
1339 typeMouseButton,
1340 typeUInt32,
1341 typeUInt32};
1342 int num_params = sizeof (names) / sizeof (names[0]);
1344 err = mac_store_event_ref_as_apple_event (0, 0,
1345 Qwindow,
1346 Qtoolbar_switch_mode,
1347 event, num_params,
1348 names, types);
1350 if (err == noErr)
1351 result = noErr;
1352 break;
1353 #endif
1355 #if USE_MAC_TSM
1356 /* -- window focus events -- */
1358 case kEventWindowFocusAcquired:
1359 err = mac_tsm_resume ();
1360 if (err == noErr)
1361 result = noErr;
1362 break;
1364 case kEventWindowFocusRelinquish:
1365 err = mac_tsm_suspend ();
1366 if (err == noErr)
1367 result = noErr;
1368 break;
1369 #endif
1371 default:
1372 abort ();
1375 return result;
1377 #endif
1379 /* Handle clicks in zoom box. Calculation of "standard state" based
1380 on code in IM - Window Manager A and code contributed by Ben
1381 Mesander. The standard state of an Emacs window is 80-characters
1382 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
1384 static void
1385 do_zoom_window (WindowRef w, int zoom_in_or_out)
1387 Rect zoom_rect, port_rect;
1388 int width, height;
1389 struct frame *f = mac_window_to_frame (w);
1390 #if TARGET_API_MAC_CARBON
1391 Point ideal_size = mac_get_ideal_size (f);
1393 GetWindowBounds (w, kWindowContentRgn, &port_rect);
1394 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
1395 && port_rect.left == zoom_rect.left
1396 && port_rect.top == zoom_rect.top)
1397 zoom_in_or_out = inZoomIn;
1398 else
1399 zoom_in_or_out = inZoomOut;
1401 #ifdef MAC_OS8
1402 mac_clear_area (f, 0, 0, port_rect.right - port_rect.left,
1403 port_rect.bottom - port_rect.top);
1404 #endif
1405 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
1406 #else /* not TARGET_API_MAC_CARBON */
1407 GrafPtr save_port;
1408 Point top_left;
1409 int w_title_height, rows;
1410 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
1412 GetPort (&save_port);
1414 SetPortWindowPort (w);
1416 /* Clear window to avoid flicker. */
1417 EraseRect (&(w->portRect));
1418 if (zoom_in_or_out == inZoomOut)
1420 SetPt (&top_left, w->portRect.left, w->portRect.top);
1421 LocalToGlobal (&top_left);
1423 /* calculate height of window's title bar */
1424 w_title_height = top_left.v - 1
1425 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
1427 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
1428 zoom_rect = qd.screenBits.bounds;
1429 zoom_rect.top += w_title_height;
1430 InsetRect (&zoom_rect, 8, 4); /* not too tight */
1432 zoom_rect.right = zoom_rect.left
1433 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
1435 /* Adjust the standard size according to character boundaries. */
1436 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
1437 zoom_rect.bottom =
1438 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1440 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
1441 = zoom_rect;
1444 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
1446 SetPort (save_port);
1447 #endif /* not TARGET_API_MAC_CARBON */
1449 #if !TARGET_API_MAC_CARBON
1450 /* retrieve window size and update application values */
1451 port_rect = w->portRect;
1452 height = port_rect.bottom - port_rect.top;
1453 width = port_rect.right - port_rect.left;
1455 mac_handle_size_change (f, width, height);
1456 mac_handle_origin_change (f);
1457 #endif
1460 static OSStatus
1461 install_window_handler (window)
1462 WindowRef window;
1464 OSStatus err = noErr;
1466 #if TARGET_API_MAC_CARBON
1467 if (err == noErr)
1469 static const EventTypeSpec specs[] =
1471 /* -- window refresh events -- */
1472 {kEventClassWindow, kEventWindowUpdate},
1473 /* -- window state change events -- */
1474 {kEventClassWindow, kEventWindowShowing},
1475 {kEventClassWindow, kEventWindowHiding},
1476 {kEventClassWindow, kEventWindowShown},
1477 {kEventClassWindow, kEventWindowHidden},
1478 {kEventClassWindow, kEventWindowCollapsed},
1479 {kEventClassWindow, kEventWindowExpanded},
1480 {kEventClassWindow, kEventWindowBoundsChanging},
1481 {kEventClassWindow, kEventWindowBoundsChanged},
1482 /* -- window action events -- */
1483 {kEventClassWindow, kEventWindowClose},
1484 {kEventClassWindow, kEventWindowGetIdealSize},
1485 #ifdef MAC_OSX
1486 {kEventClassWindow, kEventWindowToolbarSwitchMode},
1487 #endif
1488 #if USE_MAC_TSM
1489 /* -- window focus events -- */
1490 {kEventClassWindow, kEventWindowFocusAcquired},
1491 {kEventClassWindow, kEventWindowFocusRelinquish},
1492 #endif
1494 static EventHandlerUPP handle_window_eventUPP = NULL;
1496 if (handle_window_eventUPP == NULL)
1497 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
1499 err = InstallWindowEventHandler (window, handle_window_eventUPP,
1500 GetEventTypeCount (specs),
1501 specs, NULL, NULL);
1503 #endif
1505 if (err == noErr)
1506 err = install_drag_handler (window);
1508 return err;
1511 static void
1512 remove_window_handler (window)
1513 WindowRef window;
1515 remove_drag_handler (window);
1518 void
1519 mac_get_window_bounds (f, inner, outer)
1520 struct frame *f;
1521 Rect *inner, *outer;
1523 #if TARGET_API_MAC_CARBON
1524 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
1525 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
1526 #else /* not TARGET_API_MAC_CARBON */
1527 RgnHandle region = NewRgn ();
1529 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
1530 *inner = (*region)->rgnBBox;
1531 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
1532 *outer = (*region)->rgnBBox;
1533 DisposeRgn (region);
1534 #endif /* not TARGET_API_MAC_CARBON */
1537 Rect *
1538 mac_get_frame_bounds (f, r)
1539 struct frame *f;
1540 Rect *r;
1542 #if TARGET_API_MAC_CARBON
1543 return GetWindowPortBounds (FRAME_MAC_WINDOW (f), r);
1544 #else
1545 *r = FRAME_MAC_WINDOW (f)->portRect;
1547 return r;
1548 #endif
1551 void
1552 mac_get_frame_mouse (f, point)
1553 struct frame *f;
1554 Point *point;
1556 #if TARGET_API_MAC_CARBON
1557 GetGlobalMouse (point);
1558 point->h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1559 point->v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1560 #else
1561 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1562 GetMouse (point);
1563 #endif
1566 void
1567 mac_convert_frame_point_to_global (f, x, y)
1568 struct frame *f;
1569 int *x, *y;
1571 *x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1572 *y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1575 #if TARGET_API_MAC_CARBON
1576 void
1577 mac_update_proxy_icon (f)
1578 struct frame *f;
1580 OSStatus err;
1581 Lisp_Object file_name =
1582 XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer)->filename;
1583 Window w = FRAME_MAC_WINDOW (f);
1584 AliasHandle alias = NULL;
1586 err = GetWindowProxyAlias (w, &alias);
1587 if (err == errWindowDoesNotHaveProxy && !STRINGP (file_name))
1588 return;
1590 if (STRINGP (file_name))
1592 AEDesc desc;
1593 #ifdef MAC_OSX
1594 FSRef fref, fref_proxy;
1595 #else
1596 FSSpec fss, fss_proxy;
1597 #endif
1598 Boolean changed;
1599 Lisp_Object encoded_file_name = ENCODE_FILE (file_name);
1601 #ifdef MAC_OSX
1602 err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name),
1603 SBYTES (encoded_file_name), typeFSRef, &desc);
1604 #else
1605 SetPortWindowPort (w);
1606 err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name),
1607 SBYTES (encoded_file_name), typeFSS, &desc);
1608 #endif
1609 if (err == noErr)
1611 #ifdef MAC_OSX
1612 err = AEGetDescData (&desc, &fref, sizeof (FSRef));
1613 #else
1614 err = AEGetDescData (&desc, &fss, sizeof (FSSpec));
1615 #endif
1616 AEDisposeDesc (&desc);
1618 if (err == noErr)
1620 if (alias)
1622 /* (FS)ResolveAlias never sets `changed' to true if
1623 `alias' is minimal. */
1624 #ifdef MAC_OSX
1625 err = FSResolveAlias (NULL, alias, &fref_proxy, &changed);
1626 if (err == noErr)
1627 err = FSCompareFSRefs (&fref, &fref_proxy);
1628 #else
1629 err = ResolveAlias (NULL, alias, &fss_proxy, &changed);
1630 if (err == noErr)
1631 err = !(fss.vRefNum == fss_proxy.vRefNum
1632 && fss.parID == fss_proxy.parID
1633 && EqualString (fss.name, fss_proxy.name,
1634 false, true));
1635 #endif
1637 if (err != noErr || alias == NULL)
1639 if (alias)
1640 DisposeHandle ((Handle) alias);
1641 #ifdef MAC_OSX
1642 err = FSNewAliasMinimal (&fref, &alias);
1643 #else
1644 err = NewAliasMinimal (&fss, &alias);
1645 #endif
1646 changed = true;
1649 if (err == noErr)
1650 if (changed)
1651 err = SetWindowProxyAlias (w, alias);
1654 if (alias)
1655 DisposeHandle ((Handle) alias);
1657 if (err != noErr || !STRINGP (file_name))
1658 RemoveWindowProxy (w);
1660 #endif
1662 /* Mac replacement for XSetWindowBackground. */
1664 void
1665 mac_set_frame_window_background (f, color)
1666 struct frame *f;
1667 unsigned long color;
1669 WindowRef w = FRAME_MAC_WINDOW (f);
1670 #if !TARGET_API_MAC_CARBON
1671 AuxWinHandle aw_handle;
1672 CTabHandle ctab_handle;
1673 ColorSpecPtr ct_table;
1674 short ct_size;
1675 #endif
1676 RGBColor bg_color;
1678 bg_color.red = RED16_FROM_ULONG (color);
1679 bg_color.green = GREEN16_FROM_ULONG (color);
1680 bg_color.blue = BLUE16_FROM_ULONG (color);
1682 #if TARGET_API_MAC_CARBON
1683 SetWindowContentColor (w, &bg_color);
1684 #else
1685 if (GetAuxWin (w, &aw_handle))
1687 ctab_handle = (*aw_handle)->awCTable;
1688 HandToHand ((Handle *) &ctab_handle);
1689 ct_table = (*ctab_handle)->ctTable;
1690 ct_size = (*ctab_handle)->ctSize;
1691 while (ct_size > -1)
1693 if (ct_table->value == 0)
1695 ct_table->rgb = bg_color;
1696 CTabChanged (ctab_handle);
1697 SetWinColor (w, (WCTabHandle) ctab_handle);
1699 ct_size--;
1702 #endif
1705 /* Flush display of frame F, or of all frames if F is null. */
1707 void
1708 x_flush (f)
1709 struct frame *f;
1711 #if TARGET_API_MAC_CARBON
1712 BLOCK_INPUT;
1713 #if USE_CG_DRAWING
1714 mac_prepare_for_quickdraw (f);
1715 #endif
1716 if (f)
1717 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
1718 else
1719 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
1720 UNBLOCK_INPUT;
1721 #endif
1724 #if USE_CG_DRAWING
1725 void
1726 mac_flush_display_optional (f)
1727 struct frame *f;
1729 BLOCK_INPUT;
1730 mac_prepare_for_quickdraw (f);
1731 UNBLOCK_INPUT;
1733 #endif
1735 void
1736 mac_update_begin (f)
1737 struct frame *f;
1739 #if TARGET_API_MAC_CARBON
1740 /* During update of a frame, availability of input events is
1741 periodically checked with ReceiveNextEvent if
1742 redisplay-dont-pause is nil. That normally flushes window buffer
1743 changes for every check, and thus screen update looks waving even
1744 if no input is available. So we disable screen updates during
1745 update of a frame. */
1746 DisableScreenUpdates ();
1747 #endif
1750 void
1751 mac_update_end (f)
1752 struct frame *f;
1754 #if TARGET_API_MAC_CARBON
1755 EnableScreenUpdates ();
1756 #endif
1759 void
1760 mac_frame_up_to_date (f)
1761 struct frame *f;
1763 /* Nothing to do. */
1766 void
1767 mac_create_frame_window (f, tooltip_p)
1768 struct frame *f;
1769 int tooltip_p;
1771 Rect r;
1772 #if TARGET_API_MAC_CARBON
1773 WindowClass window_class;
1774 WindowAttributes attributes;
1775 #else
1776 short proc_id;
1777 WindowRef behind;
1778 Boolean go_away_flag;
1779 #endif
1781 if (!tooltip_p)
1783 SetRect (&r, f->left_pos, f->top_pos,
1784 f->left_pos + FRAME_PIXEL_WIDTH (f),
1785 f->top_pos + FRAME_PIXEL_HEIGHT (f));
1786 #if TARGET_API_MAC_CARBON
1787 window_class = kDocumentWindowClass;
1788 attributes = (kWindowStandardDocumentAttributes
1789 #ifdef MAC_OSX
1790 | kWindowToolbarButtonAttribute
1791 #endif
1793 #else
1794 proc_id = zoomDocProc;
1795 behind = (WindowRef) -1;
1796 go_away_flag = true;
1797 #endif
1799 else
1801 SetRect (&r, 0, 0, 1, 1);
1802 #if TARGET_API_MAC_CARBON
1803 window_class = kHelpWindowClass;
1804 attributes = (kWindowNoUpdatesAttribute
1805 | kWindowNoActivatesAttribute
1806 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1807 | kWindowIgnoreClicksAttribute
1808 #endif
1810 #else
1811 proc_id = plainDBox;
1812 behind = NULL;
1813 go_away_flag = false;
1814 #endif
1817 #if TARGET_API_MAC_CARBON
1818 CreateNewWindow (window_class, attributes, &r, &FRAME_MAC_WINDOW (f));
1819 if (FRAME_MAC_WINDOW (f))
1821 SetWRefCon (FRAME_MAC_WINDOW (f), (long) f->output_data.mac);
1822 if (!tooltip_p)
1823 if (install_window_handler (FRAME_MAC_WINDOW (f)) != noErr)
1825 DisposeWindow (FRAME_MAC_WINDOW (f));
1826 FRAME_MAC_WINDOW (f) = NULL;
1829 #else /* !TARGET_API_MAC_CARBON */
1830 FRAME_MAC_WINDOW (f)
1831 = NewCWindow (NULL, &r, "\p", false, proc_id, behind, go_away_flag,
1832 (long) f->output_data.mac);
1833 #endif /* !TARGET_API_MAC_CARBON */
1834 /* so that update events can find this mac_output struct */
1835 f->output_data.mac->mFP = f; /* point back to emacs frame */
1837 #ifndef MAC_OSX
1838 if (!tooltip_p)
1839 if (FRAME_MAC_WINDOW (f))
1841 ControlRef root_control;
1843 if (CreateRootControl (FRAME_MAC_WINDOW (f), &root_control) != noErr)
1845 DisposeWindow (FRAME_MAC_WINDOW (f));
1846 FRAME_MAC_WINDOW (f) = NULL;
1849 #endif
1852 /* Dispose of the Mac window of the frame F. */
1854 void
1855 mac_dispose_frame_window (f)
1856 struct frame *f;
1858 WindowRef window = FRAME_MAC_WINDOW (f);
1860 if (window != tip_window)
1861 remove_window_handler (window);
1863 #if USE_CG_DRAWING
1864 mac_prepare_for_quickdraw (f);
1865 #endif
1866 DisposeWindow (window);
1870 /************************************************************************
1871 View and Drawing
1872 ************************************************************************/
1874 #if USE_CG_DRAWING
1875 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
1877 CGContextRef
1878 mac_begin_cg_clip (f, gc)
1879 struct frame *f;
1880 GC gc;
1882 CGContextRef context = FRAME_CG_CONTEXT (f);
1884 if (!context)
1886 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1887 FRAME_CG_CONTEXT (f) = context;
1890 CGContextSaveGState (context);
1891 CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f));
1892 CGContextScaleCTM (context, 1, -1);
1893 if (gc && gc->n_clip_rects)
1894 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
1896 return context;
1899 void
1900 mac_end_cg_clip (f)
1901 struct frame *f;
1903 CGContextRestoreGState (FRAME_CG_CONTEXT (f));
1906 static void
1907 mac_prepare_for_quickdraw (f)
1908 struct frame *f;
1910 if (f == NULL)
1912 Lisp_Object rest, frame;
1913 FOR_EACH_FRAME (rest, frame)
1914 if (FRAME_MAC_P (XFRAME (frame)))
1915 mac_prepare_for_quickdraw (XFRAME (frame));
1917 else
1919 CGContextRef context = FRAME_CG_CONTEXT (f);
1921 if (context)
1923 CGContextSynchronize (context);
1924 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)),
1925 &FRAME_CG_CONTEXT (f));
1929 #endif
1931 static RgnHandle saved_port_clip_region = NULL;
1933 void
1934 mac_begin_clip (f, gc)
1935 struct frame *f;
1936 GC gc;
1938 static RgnHandle new_region = NULL;
1940 if (saved_port_clip_region == NULL)
1941 saved_port_clip_region = NewRgn ();
1942 if (new_region == NULL)
1943 new_region = NewRgn ();
1945 #if USE_CG_DRAWING
1946 mac_prepare_for_quickdraw (f);
1947 #endif
1948 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1950 if (gc && gc->n_clip_rects)
1952 GetClip (saved_port_clip_region);
1953 SectRgn (saved_port_clip_region, gc->clip_region, new_region);
1954 SetClip (new_region);
1958 void
1959 mac_end_clip (f, gc)
1960 struct frame *f;
1961 GC gc;
1963 if (gc && gc->n_clip_rects)
1964 SetClip (saved_port_clip_region);
1967 #if TARGET_API_MAC_CARBON
1968 /* Mac replacement for XCopyArea: used only for scrolling. */
1970 void
1971 mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1972 struct frame *f;
1973 GC gc;
1974 int src_x, src_y;
1975 unsigned int width, height;
1976 int dest_x, dest_y;
1978 Rect src_r;
1979 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
1981 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1982 #if USE_CG_DRAWING
1983 mac_prepare_for_quickdraw (f);
1984 #endif
1985 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1986 &src_r, dest_x - src_x, dest_y - src_y,
1987 kScrollWindowNoOptions, dummy);
1988 DisposeRgn (dummy);
1990 #endif
1993 /************************************************************************
1994 Scroll bars
1995 ************************************************************************/
1997 extern struct scroll_bar *tracked_scroll_bar;
1998 extern Lisp_Object last_mouse_scroll_bar;
1999 extern Time last_mouse_movement_time;
2001 static void x_scroll_bar_handle_click P_ ((struct scroll_bar *,
2002 ControlPartCode,
2003 const EventRecord *,
2004 struct input_event *));
2005 #ifndef USE_TOOLKIT_SCROLL_BARS
2006 static void x_scroll_bar_note_movement P_ ((struct scroll_bar *, int, Time));
2007 #else /* USE_TOOLKIT_SCROLL_BARS */
2008 static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
2009 ControlPartCode, Point,
2010 struct input_event *));
2011 static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
2012 struct input_event *));
2013 static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *,
2014 Point, struct input_event *));
2015 static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
2016 static OSStatus install_scroll_bar_timer P_ ((void));
2017 static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
2018 static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
2019 static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
2020 struct input_event *));
2021 static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode,
2022 Rect *));
2023 static void update_scroll_bar_track_info P_ ((struct scroll_bar *));
2025 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
2027 static int last_scroll_bar_part;
2029 static EventLoopTimerRef scroll_bar_timer;
2031 static int scroll_bar_timer_event_posted_p;
2033 #define SCROLL_BAR_FIRST_DELAY 0.5
2034 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
2036 static pascal void
2037 scroll_bar_timer_callback (timer, data)
2038 EventLoopTimerRef timer;
2039 void *data;
2041 OSStatus err;
2043 err = mac_post_mouse_moved_event ();
2044 if (err == noErr)
2045 scroll_bar_timer_event_posted_p = 1;
2048 static OSStatus
2049 install_scroll_bar_timer ()
2051 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
2053 if (scroll_bar_timer_callbackUPP == NULL)
2054 scroll_bar_timer_callbackUPP =
2055 NewEventLoopTimerUPP (scroll_bar_timer_callback);
2057 if (scroll_bar_timer == NULL)
2058 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
2059 kEventDurationForever as delays. */
2060 return
2061 InstallEventLoopTimer (GetCurrentEventLoop (),
2062 kEventDurationForever, kEventDurationForever,
2063 scroll_bar_timer_callbackUPP, NULL,
2064 &scroll_bar_timer);
2067 static OSStatus
2068 set_scroll_bar_timer (delay)
2069 EventTimerInterval delay;
2071 if (scroll_bar_timer == NULL)
2072 install_scroll_bar_timer ();
2074 scroll_bar_timer_event_posted_p = 0;
2076 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
2079 static int
2080 control_part_code_to_scroll_bar_part (part_code)
2081 ControlPartCode part_code;
2083 switch (part_code)
2085 case kControlUpButtonPart: return scroll_bar_up_arrow;
2086 case kControlDownButtonPart: return scroll_bar_down_arrow;
2087 case kControlPageUpPart: return scroll_bar_above_handle;
2088 case kControlPageDownPart: return scroll_bar_below_handle;
2089 case kControlIndicatorPart: return scroll_bar_handle;
2092 return -1;
2095 static void
2096 construct_scroll_bar_click (bar, part, bufp)
2097 struct scroll_bar *bar;
2098 int part;
2099 struct input_event *bufp;
2101 bufp->kind = SCROLL_BAR_CLICK_EVENT;
2102 bufp->frame_or_window = bar->window;
2103 bufp->arg = Qnil;
2104 bufp->part = part;
2105 bufp->code = 0;
2106 XSETINT (bufp->x, 0);
2107 XSETINT (bufp->y, 0);
2108 bufp->modifiers = 0;
2111 static OSStatus
2112 get_control_part_bounds (ch, part_code, rect)
2113 ControlRef ch;
2114 ControlPartCode part_code;
2115 Rect *rect;
2117 RgnHandle region = NewRgn ();
2118 OSStatus err;
2120 err = GetControlRegion (ch, part_code, region);
2121 if (err == noErr)
2122 GetRegionBounds (region, rect);
2123 DisposeRgn (region);
2125 return err;
2128 static void
2129 x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp)
2130 struct scroll_bar *bar;
2131 ControlPartCode part_code;
2132 Point mouse_pos;
2133 struct input_event *bufp;
2135 int part = control_part_code_to_scroll_bar_part (part_code);
2137 if (part < 0)
2138 return;
2140 if (part != scroll_bar_handle)
2142 construct_scroll_bar_click (bar, part, bufp);
2143 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
2144 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
2145 bar->dragging = Qnil;
2147 else
2149 Rect r;
2151 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
2152 kControlIndicatorPart, &r);
2153 XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1);
2156 last_scroll_bar_part = part;
2157 tracked_scroll_bar = bar;
2160 static void
2161 x_scroll_bar_handle_release (bar, bufp)
2162 struct scroll_bar *bar;
2163 struct input_event *bufp;
2165 if (last_scroll_bar_part != scroll_bar_handle
2166 || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0))
2167 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
2169 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
2170 set_scroll_bar_timer (kEventDurationForever);
2172 last_scroll_bar_part = -1;
2173 bar->dragging = Qnil;
2174 tracked_scroll_bar = NULL;
2177 static void
2178 x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
2179 WindowRef win;
2180 struct scroll_bar *bar;
2181 Point mouse_pos;
2182 struct input_event *bufp;
2184 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2186 if (last_scroll_bar_part == scroll_bar_handle)
2188 int top, top_range;
2189 Rect r;
2191 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
2192 kControlIndicatorPart, &r);
2194 if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0)
2195 XSETINT (bar->dragging, - (XINT (bar->dragging) + 1));
2197 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
2198 top_range = XINT (bar->track_height) - XINT (bar->min_handle);
2200 if (top < 0)
2201 top = 0;
2202 if (top > top_range)
2203 top = top_range;
2205 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
2206 XSETINT (bufp->x, top);
2207 XSETINT (bufp->y, top_range);
2209 else
2211 ControlPartCode part_code;
2212 int unhilite_p = 0, part;
2214 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
2215 unhilite_p = 1;
2216 else
2218 part = control_part_code_to_scroll_bar_part (part_code);
2220 switch (last_scroll_bar_part)
2222 case scroll_bar_above_handle:
2223 case scroll_bar_below_handle:
2224 if (part != scroll_bar_above_handle
2225 && part != scroll_bar_below_handle)
2226 unhilite_p = 1;
2227 break;
2229 case scroll_bar_up_arrow:
2230 case scroll_bar_down_arrow:
2231 if (part != scroll_bar_up_arrow
2232 && part != scroll_bar_down_arrow)
2233 unhilite_p = 1;
2234 break;
2238 if (unhilite_p)
2239 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
2240 else if (part != last_scroll_bar_part
2241 || scroll_bar_timer_event_posted_p)
2243 construct_scroll_bar_click (bar, part, bufp);
2244 last_scroll_bar_part = part;
2245 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
2246 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
2251 /* Update BAR->track_top, BAR->track_height, and BAR->min_handle for
2252 the scroll bar BAR. This function should be called when the bounds
2253 of the scroll bar is changed. */
2255 static void
2256 update_scroll_bar_track_info (bar)
2257 struct scroll_bar *bar;
2259 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2260 Rect r0, r1;
2262 GetControlBounds (ch, &r0);
2264 if (r0.right - r0.left >= r0.bottom - r0.top
2265 #ifdef MAC_OSX
2266 || r0.right - r0.left < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
2267 #endif
2270 XSETINT (bar->track_top, 0);
2271 XSETINT (bar->track_height, 0);
2272 XSETINT (bar->min_handle, 0);
2274 else
2276 BLOCK_INPUT;
2278 SetControl32BitMinimum (ch, 0);
2279 SetControl32BitMaximum (ch, 1 << 30);
2280 SetControlViewSize (ch, 1);
2282 /* Move the scroll bar thumb to the top. */
2283 SetControl32BitValue (ch, 0);
2284 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
2286 /* Move the scroll bar thumb to the bottom. */
2287 SetControl32BitValue (ch, 1 << 30);
2288 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
2290 UnionRect (&r0, &r1, &r0);
2291 XSETINT (bar->track_top, r0.top);
2292 XSETINT (bar->track_height, r0.bottom - r0.top);
2293 XSETINT (bar->min_handle, r1.bottom - r1.top);
2295 /* Don't show the scroll bar if its height is not enough to
2296 display the scroll bar thumb. */
2297 if (r0.bottom - r0.top > 0)
2298 ShowControl (ch);
2300 UNBLOCK_INPUT;
2304 /* Set the thumb size and position of scroll bar BAR. We are currently
2305 displaying PORTION out of a whole WHOLE, and our position POSITION. */
2307 void
2308 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
2309 struct scroll_bar *bar;
2310 int portion, position, whole;
2312 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2313 int value, viewsize, maximum;
2315 if (XINT (bar->track_height) == 0)
2316 return;
2318 if (whole <= portion)
2319 value = 0, viewsize = 1, maximum = 0;
2320 else
2322 float scale;
2324 maximum = XINT (bar->track_height) - XINT (bar->min_handle);
2325 scale = (float) maximum / (whole - portion);
2326 value = position * scale + 0.5f;
2327 viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle);
2330 BLOCK_INPUT;
2332 if (GetControlViewSize (ch) != viewsize
2333 || GetControl32BitValue (ch) != value
2334 || GetControl32BitMaximum (ch) != maximum)
2336 /* Temporarily hide the scroll bar to avoid multiple redraws. */
2337 SetControlVisibility (ch, false, false);
2339 SetControl32BitMaximum (ch, maximum);
2340 SetControl32BitValue (ch, value);
2341 SetControlViewSize (ch, viewsize);
2343 SetControlVisibility (ch, true, true);
2346 UNBLOCK_INPUT;
2349 #endif /* USE_TOOLKIT_SCROLL_BARS */
2351 /* Create a scroll bar control for BAR. BOUNDS and VISIBLE specifies
2352 the initial geometry and visibility, respectively. The created
2353 control is stored in some members of BAR. */
2355 void
2356 mac_create_scroll_bar (bar, bounds, visible)
2357 struct scroll_bar *bar;
2358 const Rect *bounds;
2359 Boolean visible;
2361 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2362 ControlRef ch;
2364 #if USE_CG_DRAWING
2365 mac_prepare_for_quickdraw (f);
2366 #endif
2367 ch = NewControl (FRAME_MAC_WINDOW (f), bounds, "\p", visible, 0, 0, 0,
2368 #if TARGET_API_MAC_CARBON
2369 kControlScrollBarProc,
2370 #else
2371 scrollBarProc,
2372 #endif
2373 (SInt32) bar);
2374 SET_SCROLL_BAR_CONTROL_REF (bar, ch);
2376 XSETINT (bar->start, 0);
2377 XSETINT (bar->end, 0);
2378 bar->dragging = Qnil;
2380 #ifdef USE_TOOLKIT_SCROLL_BARS
2381 update_scroll_bar_track_info (bar);
2382 #endif
2385 /* Dispose of the scroll bar control stored in some members of
2386 BAR. */
2388 void
2389 mac_dispose_scroll_bar (bar)
2390 struct scroll_bar *bar;
2392 #if USE_CG_DRAWING
2393 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2395 mac_prepare_for_quickdraw (f);
2396 #endif
2397 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
2400 /* Set bounds of the scroll bar BAR to BOUNDS. */
2402 void
2403 mac_set_scroll_bar_bounds (bar, bounds)
2404 struct scroll_bar *bar;
2405 const Rect *bounds;
2407 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2408 SInt16 width, height;
2409 #if USE_CG_DRAWING
2410 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2412 mac_prepare_for_quickdraw (f);
2413 #endif
2415 width = bounds->right - bounds->left;
2416 height = bounds->bottom - bounds->top;
2417 HideControl (ch);
2418 MoveControl (ch, bounds->left, bounds->top);
2419 SizeControl (ch, width, height);
2420 #ifdef USE_TOOLKIT_SCROLL_BARS
2421 update_scroll_bar_track_info (bar);
2422 #else
2423 if (width < height)
2424 ShowControl (ch);
2425 #endif
2428 /* Draw the scroll bar BAR. */
2430 void
2431 mac_redraw_scroll_bar (bar)
2432 struct scroll_bar *bar;
2434 #if USE_CG_DRAWING
2435 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2437 mac_prepare_for_quickdraw (f);
2438 #endif
2439 Draw1Control (SCROLL_BAR_CONTROL_REF (bar));
2442 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2443 is set to something other than NO_EVENT, it is enqueued.
2445 This may be called from a signal handler, so we have to ignore GC
2446 mark bits. */
2448 static void
2449 x_scroll_bar_handle_click (bar, part_code, er, bufp)
2450 struct scroll_bar *bar;
2451 ControlPartCode part_code;
2452 const EventRecord *er;
2453 struct input_event *bufp;
2455 int win_y, top_range;
2457 if (! GC_WINDOWP (bar->window))
2458 abort ();
2460 bufp->kind = SCROLL_BAR_CLICK_EVENT;
2461 bufp->frame_or_window = bar->window;
2462 bufp->arg = Qnil;
2464 bar->dragging = Qnil;
2466 switch (part_code)
2468 case kControlUpButtonPart:
2469 bufp->part = scroll_bar_up_arrow;
2470 break;
2471 case kControlDownButtonPart:
2472 bufp->part = scroll_bar_down_arrow;
2473 break;
2474 case kControlPageUpPart:
2475 bufp->part = scroll_bar_above_handle;
2476 break;
2477 case kControlPageDownPart:
2478 bufp->part = scroll_bar_below_handle;
2479 break;
2480 #if TARGET_API_MAC_CARBON
2481 default:
2482 #else
2483 case kControlIndicatorPart:
2484 #endif
2485 if (er->what == mouseDown)
2486 bar->dragging = make_number (0);
2487 XSETVECTOR (last_mouse_scroll_bar, bar);
2488 bufp->part = scroll_bar_handle;
2489 break;
2492 win_y = XINT (bufp->y) - XINT (bar->top);
2493 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
2495 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2497 win_y -= 24;
2499 if (! NILP (bar->dragging))
2500 win_y -= XINT (bar->dragging);
2502 if (win_y < 0)
2503 win_y = 0;
2504 if (win_y > top_range)
2505 win_y = top_range;
2507 XSETINT (bufp->x, win_y);
2508 XSETINT (bufp->y, top_range);
2511 /* Return information to the user about the current position of the mouse
2512 on the scroll bar. */
2514 void
2515 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
2516 FRAME_PTR *fp;
2517 Lisp_Object *bar_window;
2518 enum scroll_bar_part *part;
2519 Lisp_Object *x, *y;
2520 unsigned long *time;
2522 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
2523 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2524 #if TARGET_API_MAC_CARBON
2525 WindowRef wp = GetControlOwner (ch);
2526 #else
2527 WindowRef wp = (*ch)->contrlOwner;
2528 #endif
2529 Point mouse_pos;
2530 struct frame *f = mac_window_to_frame (wp);
2531 int win_y, top_range;
2533 #if TARGET_API_MAC_CARBON
2534 GetGlobalMouse (&mouse_pos);
2535 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
2536 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
2537 #else
2538 SetPortWindowPort (wp);
2539 GetMouse (&mouse_pos);
2540 #endif
2542 win_y = mouse_pos.v - XINT (bar->top);
2543 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
2545 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2547 win_y -= 24;
2549 if (! NILP (bar->dragging))
2550 win_y -= XINT (bar->dragging);
2552 if (win_y < 0)
2553 win_y = 0;
2554 if (win_y > top_range)
2555 win_y = top_range;
2557 *fp = f;
2558 *bar_window = bar->window;
2560 if (! NILP (bar->dragging))
2561 *part = scroll_bar_handle;
2562 else if (win_y < XINT (bar->start))
2563 *part = scroll_bar_above_handle;
2564 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2565 *part = scroll_bar_handle;
2566 else
2567 *part = scroll_bar_below_handle;
2569 XSETINT (*x, win_y);
2570 XSETINT (*y, top_range);
2572 f->mouse_moved = 0;
2573 last_mouse_scroll_bar = Qnil;
2575 *time = last_mouse_movement_time;
2578 #ifndef USE_TOOLKIT_SCROLL_BARS
2579 /* Draw BAR's handle in the proper position.
2581 If the handle is already drawn from START to END, don't bother
2582 redrawing it, unless REBUILD is non-zero; in that case, always
2583 redraw it. (REBUILD is handy for drawing the handle after expose
2584 events.)
2586 Normally, we want to constrain the start and end of the handle to
2587 fit inside its rectangle, but if the user is dragging the scroll
2588 bar handle, we want to let them drag it down all the way, so that
2589 the bar's top is as far down as it goes; otherwise, there's no way
2590 to move to the very end of the buffer. */
2592 void
2593 x_scroll_bar_set_handle (bar, start, end, rebuild)
2594 struct scroll_bar *bar;
2595 int start, end;
2596 int rebuild;
2598 int dragging = ! NILP (bar->dragging);
2599 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2600 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2601 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
2602 int length = end - start;
2604 /* If the display is already accurate, do nothing. */
2605 if (! rebuild
2606 && start == XINT (bar->start)
2607 && end == XINT (bar->end))
2608 return;
2610 BLOCK_INPUT;
2612 /* Make sure the values are reasonable, and try to preserve the
2613 distance between start and end. */
2614 if (start < 0)
2615 start = 0;
2616 else if (start > top_range)
2617 start = top_range;
2618 end = start + length;
2620 if (end < start)
2621 end = start;
2622 else if (end > top_range && ! dragging)
2623 end = top_range;
2625 /* Store the adjusted setting in the scroll bar. */
2626 XSETINT (bar->start, start);
2627 XSETINT (bar->end, end);
2629 /* Clip the end position, just for display. */
2630 if (end > top_range)
2631 end = top_range;
2633 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
2634 top positions, to make sure the handle is always at least that
2635 many pixels tall. */
2636 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
2638 SetControlMinimum (ch, 0);
2639 /* Don't inadvertently activate deactivated scroll bars */
2640 if (GetControlMaximum (ch) != -1)
2641 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
2642 - (end - start));
2643 SetControlValue (ch, start);
2644 #if TARGET_API_MAC_CARBON
2645 SetControlViewSize (ch, end - start);
2646 #endif
2648 UNBLOCK_INPUT;
2651 /* Handle some mouse motion while someone is dragging the scroll bar.
2653 This may be called from a signal handler, so we have to ignore GC
2654 mark bits. */
2656 static void
2657 x_scroll_bar_note_movement (bar, y_pos, t)
2658 struct scroll_bar *bar;
2659 int y_pos;
2660 Time t;
2662 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
2664 last_mouse_movement_time = t;
2666 f->mouse_moved = 1;
2667 XSETVECTOR (last_mouse_scroll_bar, bar);
2669 /* If we're dragging the bar, display it. */
2670 if (! GC_NILP (bar->dragging))
2672 /* Where should the handle be now? */
2673 int new_start = y_pos - 24;
2675 if (new_start != XINT (bar->start))
2677 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2679 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2683 #endif /* !USE_TOOLKIT_SCROLL_BARS */
2686 /***********************************************************************
2687 Tool-bars
2688 ***********************************************************************/
2690 #if USE_MAC_TOOLBAR
2691 /* In identifiers such as function/variable names, Emacs tool bar is
2692 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
2694 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
2695 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
2697 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
2698 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
2699 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2700 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
2701 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2702 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
2703 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2705 static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
2706 EventRef, void *));
2708 extern Rect last_mouse_glyph;
2710 extern void mac_move_window_with_gravity P_ ((struct frame *, int,
2711 short, short));
2712 extern void mac_get_window_origin_with_gravity P_ ((struct frame *, int,
2713 short *, short *));
2714 extern CGImageRef mac_image_spec_to_cg_image P_ ((struct frame *,
2715 Lisp_Object));
2717 static OSStatus
2718 mac_handle_toolbar_event (next_handler, event, data)
2719 EventHandlerCallRef next_handler;
2720 EventRef event;
2721 void *data;
2723 OSStatus result = eventNotHandledErr;
2725 switch (GetEventKind (event))
2727 case kEventToolbarGetDefaultIdentifiers:
2728 result = noErr;
2729 break;
2731 case kEventToolbarGetAllowedIdentifiers:
2733 CFMutableArrayRef array;
2735 GetEventParameter (event, kEventParamMutableArray,
2736 typeCFMutableArrayRef, NULL,
2737 sizeof (CFMutableArrayRef), NULL, &array);
2738 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
2739 result = noErr;
2741 break;
2743 case kEventToolbarCreateItemWithIdentifier:
2745 CFStringRef identifier;
2746 HIToolbarItemRef item = NULL;
2748 GetEventParameter (event, kEventParamToolbarItemIdentifier,
2749 typeCFStringRef, NULL,
2750 sizeof (CFStringRef), NULL, &identifier);
2752 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
2753 == kCFCompareEqualTo)
2754 HIToolbarItemCreate (identifier,
2755 kHIToolbarItemAllowDuplicates
2756 | kHIToolbarItemCantBeRemoved, &item);
2758 if (item)
2760 SetEventParameter (event, kEventParamToolbarItem,
2761 typeHIToolbarItemRef,
2762 sizeof (HIToolbarItemRef), &item);
2763 result = noErr;
2766 break;
2768 default:
2769 abort ();
2772 return result;
2775 /* Create a tool bar for frame F. */
2777 static OSStatus
2778 mac_create_frame_tool_bar (f)
2779 FRAME_PTR f;
2781 OSStatus err;
2782 HIToolbarRef toolbar;
2784 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
2785 &toolbar);
2786 if (err == noErr)
2788 static const EventTypeSpec specs[] =
2789 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
2790 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
2791 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
2793 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
2794 mac_handle_toolbar_event,
2795 GetEventTypeCount (specs), specs,
2796 f, NULL);
2799 if (err == noErr)
2800 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
2801 if (err == noErr)
2803 static const EventTypeSpec specs[] =
2804 {{kEventClassCommand, kEventCommandProcess}};
2806 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
2807 mac_handle_toolbar_command_event,
2808 GetEventTypeCount (specs),
2809 specs, f, NULL);
2811 if (err == noErr)
2812 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
2814 if (toolbar)
2815 CFRelease (toolbar);
2817 return err;
2820 /* Update the tool bar for frame F. Add new buttons and remove old. */
2822 void
2823 update_frame_tool_bar (f)
2824 FRAME_PTR f;
2826 HIToolbarRef toolbar = NULL;
2827 short left, top;
2828 CFArrayRef old_items = NULL;
2829 CFIndex old_count;
2830 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
2831 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2833 BLOCK_INPUT;
2835 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
2836 if (toolbar == NULL)
2838 mac_create_frame_tool_bar (f);
2839 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
2840 if (toolbar == NULL)
2841 goto out;
2842 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
2843 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
2846 HIToolbarCopyItems (toolbar, &old_items);
2847 if (old_items == NULL)
2848 goto out;
2850 old_count = CFArrayGetCount (old_items);
2851 pos = 0;
2852 for (i = 0; i < f->n_tool_bar_items; ++i)
2854 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
2856 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
2857 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
2858 int idx;
2859 Lisp_Object image;
2860 CGImageRef cg_image;
2861 CFStringRef label;
2862 HIToolbarItemRef item;
2864 /* If image is a vector, choose the image according to the
2865 button state. */
2866 image = PROP (TOOL_BAR_ITEM_IMAGES);
2867 if (VECTORP (image))
2869 if (enabled_p)
2870 idx = (selected_p
2871 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
2872 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
2873 else
2874 idx = (selected_p
2875 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
2876 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
2878 xassert (ASIZE (image) >= idx);
2879 image = AREF (image, idx);
2881 else
2882 idx = -1;
2884 cg_image = mac_image_spec_to_cg_image (f, image);
2885 /* Ignore invalid image specifications. */
2886 if (cg_image == NULL)
2887 continue;
2889 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
2890 if (label == NULL)
2891 label = CFSTR ("");
2893 if (pos < old_count)
2895 CGImageRef old_cg_image = NULL;
2896 CFStringRef old_label = NULL;
2897 Boolean old_enabled_p;
2899 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
2901 HIToolbarItemCopyImage (item, &old_cg_image);
2902 if (cg_image != old_cg_image)
2903 HIToolbarItemSetImage (item, cg_image);
2904 CGImageRelease (old_cg_image);
2906 HIToolbarItemCopyLabel (item, &old_label);
2907 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
2908 HIToolbarItemSetLabel (item, label);
2909 CFRelease (old_label);
2911 old_enabled_p = HIToolbarItemIsEnabled (item);
2912 if ((enabled_p || idx >= 0) != old_enabled_p)
2913 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
2915 else
2917 item = NULL;
2918 HIToolbarCreateItemWithIdentifier (toolbar,
2919 TOOLBAR_ICON_ITEM_IDENTIFIER,
2920 NULL, &item);
2921 if (item)
2923 HIToolbarItemSetImage (item, cg_image);
2924 HIToolbarItemSetLabel (item, label);
2925 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
2926 HIToolbarAppendItem (toolbar, item);
2927 CFRelease (item);
2931 CFRelease (label);
2932 if (item)
2934 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
2935 pos++;
2939 CFRelease (old_items);
2941 while (pos < old_count)
2942 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
2944 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
2945 !win_gravity && f == mac_focus_frame (dpyinfo));
2946 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
2947 toolbar visibility change. */
2948 mac_handle_origin_change (f);
2949 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
2951 mac_move_window_with_gravity (f, win_gravity, left, top);
2952 /* If the title bar is completely outside the screen, adjust the
2953 position. */
2954 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
2955 kWindowConstrainMoveRegardlessOfFit
2956 | kWindowConstrainAllowPartial, NULL, NULL);
2957 f->output_data.mac->toolbar_win_gravity = 0;
2960 out:
2961 UNBLOCK_INPUT;
2964 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
2965 doesn't deallocate the resources. */
2967 void
2968 free_frame_tool_bar (f)
2969 FRAME_PTR f;
2971 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
2973 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2975 BLOCK_INPUT;
2976 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
2977 (NILP (find_symbol_value
2978 (intern ("frame-notice-user-settings")))
2979 && f == mac_focus_frame (dpyinfo)));
2980 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
2981 on toolbar visibility change. */
2982 mac_handle_origin_change (f);
2983 UNBLOCK_INPUT;
2987 /* Report a mouse movement over toolbar to the mainstream Emacs
2988 code. */
2990 static void
2991 mac_tool_bar_note_mouse_movement (f, event)
2992 struct frame *f;
2993 EventRef event;
2995 OSStatus err;
2996 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2997 int mouse_down_p;
2998 WindowRef window;
2999 WindowPartCode part_code;
3000 HIViewRef item_view;
3001 UInt32 command_id;
3003 mouse_down_p = (dpyinfo->grabbed
3004 && f == last_mouse_frame
3005 && FRAME_LIVE_P (f));
3006 if (mouse_down_p)
3007 return;
3009 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef, NULL,
3010 sizeof (WindowRef), NULL, &window);
3011 if (err != noErr || window != FRAME_MAC_WINDOW (f))
3012 return;
3014 err = GetEventParameter (event, kEventParamWindowPartCode,
3015 typeWindowPartCode, NULL,
3016 sizeof (WindowPartCode), NULL, &part_code);
3017 if (err != noErr || part_code != inStructure)
3018 return;
3020 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window), event, &item_view);
3021 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
3022 toolbar item view seems to have the same command ID with that of
3023 the toolbar item. */
3024 if (err == noErr)
3025 err = GetControlCommandID (item_view, &command_id);
3026 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
3028 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
3030 if (i < f->n_tool_bar_items)
3032 HIRect bounds;
3033 HIViewRef content_view;
3035 err = HIViewGetBounds (item_view, &bounds);
3036 if (err == noErr)
3037 err = HIViewFindByID (HIViewGetRoot (window),
3038 kHIViewWindowContentID, &content_view);
3039 if (err == noErr)
3040 err = HIViewConvertRect (&bounds, item_view, content_view);
3041 if (err == noErr)
3042 SetRect (&last_mouse_glyph,
3043 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
3044 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
3046 help_echo_object = help_echo_window = Qnil;
3047 help_echo_pos = -1;
3048 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
3049 if (NILP (help_echo_string))
3050 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
3055 static OSStatus
3056 mac_handle_toolbar_command_event (next_handler, event, data)
3057 EventHandlerCallRef next_handler;
3058 EventRef event;
3059 void *data;
3061 OSStatus err, result = eventNotHandledErr;
3062 struct frame *f = (struct frame *) data;
3063 HICommand command;
3065 err = GetEventParameter (event, kEventParamDirectObject,
3066 typeHICommand, NULL,
3067 sizeof (HICommand), NULL, &command);
3068 if (err != noErr)
3069 return result;
3071 switch (GetEventKind (event))
3073 case kEventCommandProcess:
3074 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
3075 result = CallNextEventHandler (next_handler, event);
3076 else
3078 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
3080 if (i < f->n_tool_bar_items
3081 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
3083 Lisp_Object frame;
3084 struct input_event buf;
3086 EVENT_INIT (buf);
3088 XSETFRAME (frame, f);
3089 buf.kind = TOOL_BAR_EVENT;
3090 buf.frame_or_window = frame;
3091 buf.arg = frame;
3092 kbd_buffer_store_event (&buf);
3094 buf.kind = TOOL_BAR_EVENT;
3095 buf.frame_or_window = frame;
3096 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
3097 buf.modifiers = mac_event_to_emacs_modifiers (event);
3098 kbd_buffer_store_event (&buf);
3100 result = noErr;
3103 break;
3105 default:
3106 abort ();
3108 #undef PROP
3110 return result;
3112 #endif /* USE_MAC_TOOLBAR */
3115 /***********************************************************************
3116 Font Panel
3117 ***********************************************************************/
3119 #if USE_MAC_FONT_PANEL
3120 /* Whether Font Panel has been shown before. The first call to font
3121 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
3122 slow. This variable is used for deferring such a call as much as
3123 possible. */
3124 static int font_panel_shown_p = 0;
3126 extern Lisp_Object Qpanel_closed, Qselection;
3127 extern Lisp_Object Qfont;
3129 /* Whether the font panel is currently visible. */
3132 mac_font_panel_visible_p ()
3134 return font_panel_shown_p && FPIsFontPanelVisible ();
3137 static pascal OSStatus
3138 mac_handle_font_event (next_handler, event, data)
3139 EventHandlerCallRef next_handler;
3140 EventRef event;
3141 void *data;
3143 OSStatus result, err;
3144 Lisp_Object id_key;
3145 int num_params;
3146 const EventParamName *names;
3147 const EventParamType *types;
3148 static const EventParamName names_sel[] = {kEventParamATSUFontID,
3149 kEventParamATSUFontSize,
3150 kEventParamFMFontFamily,
3151 kEventParamFMFontStyle,
3152 kEventParamFMFontSize,
3153 kEventParamFontColor};
3154 static const EventParamType types_sel[] = {typeATSUFontID,
3155 typeATSUSize,
3156 typeFMFontFamily,
3157 typeFMFontStyle,
3158 typeFMFontSize,
3159 typeFontColor};
3161 result = CallNextEventHandler (next_handler, event);
3162 if (result != eventNotHandledErr)
3163 return result;
3165 switch (GetEventKind (event))
3167 case kEventFontPanelClosed:
3168 id_key = Qpanel_closed;
3169 num_params = 0;
3170 names = NULL;
3171 types = NULL;
3172 break;
3174 case kEventFontSelection:
3175 id_key = Qselection;
3176 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
3177 names = names_sel;
3178 types = types_sel;
3179 break;
3182 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
3183 event, num_params,
3184 names, types);
3185 if (err == noErr)
3186 result = noErr;
3188 return result;
3191 /* Toggle visiblity of the font panel. */
3193 OSStatus
3194 mac_show_hide_font_panel ()
3196 if (!font_panel_shown_p)
3198 OSStatus err;
3200 static const EventTypeSpec specs[] =
3201 {{kEventClassFont, kEventFontPanelClosed},
3202 {kEventClassFont, kEventFontSelection}};
3204 err = InstallApplicationEventHandler (mac_handle_font_event,
3205 GetEventTypeCount (specs),
3206 specs, NULL, NULL);
3207 if (err != noErr)
3208 return err;
3210 font_panel_shown_p = 1;
3213 return FPShowHideFontPanel ();
3216 /* Set the font selected in the font panel to the one corresponding to
3217 the face FACE_ID and the charcacter C in the frame F. */
3219 OSStatus
3220 mac_set_font_info_for_selection (f, face_id, c)
3221 struct frame *f;
3222 int face_id, c;
3224 OSStatus err;
3225 EventTargetRef target = NULL;
3226 XFontStruct *font = NULL;
3228 if (!mac_font_panel_visible_p ())
3229 return noErr;
3231 if (f)
3233 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
3235 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
3237 struct face *face;
3239 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
3240 face = FACE_FROM_ID (f, face_id);
3241 font = face->font;
3245 if (font == NULL)
3246 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
3247 else
3249 if (font->mac_fontnum != -1)
3251 FontSelectionQDStyle qd_style;
3253 qd_style.version = kFontSelectionQDStyleVersionZero;
3254 qd_style.instance.fontFamily = font->mac_fontnum;
3255 qd_style.instance.fontStyle = font->mac_fontface;
3256 qd_style.size = font->mac_fontsize;
3257 qd_style.hasColor = false;
3259 err = SetFontInfoForSelection (kFontSelectionQDType,
3260 1, &qd_style, target);
3262 else
3263 err = SetFontInfoForSelection (kFontSelectionATSUIType,
3264 1, &font->mac_style, target);
3267 return err;
3269 #endif /* USE_MAC_FONT_PANEL */
3272 /************************************************************************
3273 Event Handling
3274 ************************************************************************/
3276 /* Non-zero means that a HELP_EVENT has been generated since Emacs
3277 start. */
3279 static int any_help_event_p;
3281 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
3282 static Lisp_Object last_window;
3284 static Point saved_menu_event_location;
3286 extern struct frame *pending_autoraise_frame;
3288 extern FRAME_PTR last_mouse_glyph_frame;
3290 #ifdef __STDC__
3291 extern int volatile input_signal_count;
3292 #else
3293 extern int input_signal_count;
3294 #endif
3296 extern int mac_screen_config_changed;
3298 extern Lisp_Object Vmac_emulate_three_button_mouse;
3299 #if TARGET_API_MAC_CARBON
3300 extern int mac_wheel_button_is_mouse_2;
3301 extern int mac_pass_command_to_system;
3302 extern int mac_pass_control_to_system;
3303 #endif /* TARGET_API_MAC_CARBON */
3304 extern int mac_ready_for_apple_events;
3306 extern void mac_focus_changed P_ ((int, struct mac_display_info *,
3307 struct frame *, struct input_event *));
3308 extern int mac_get_emulated_btn P_ ((UInt32));
3309 extern int note_mouse_movement P_ ((FRAME_PTR, Point *));
3310 extern void mac_get_screen_info P_ ((struct mac_display_info *));
3312 /* The focus may have changed. Figure out if it is a real focus change,
3313 by checking both FocusIn/Out and Enter/LeaveNotify events.
3315 Returns FOCUS_IN_EVENT event in *BUFP. */
3317 static void
3318 x_detect_focus_change (dpyinfo, event, bufp)
3319 struct mac_display_info *dpyinfo;
3320 const EventRecord *event;
3321 struct input_event *bufp;
3323 struct frame *frame;
3325 frame = mac_window_to_frame ((WindowRef) event->message);
3326 if (! frame)
3327 return;
3329 /* On Mac, this is only called from focus events, so no switch needed. */
3330 mac_focus_changed ((event->modifiers & activeFlag),
3331 dpyinfo, frame, bufp);
3334 #if TARGET_API_MAC_CARBON
3335 /* Obtains the event modifiers from the event EVENTREF and then calls
3336 mac_to_emacs_modifiers. */
3338 static int
3339 mac_event_to_emacs_modifiers (EventRef eventRef)
3341 UInt32 mods = 0, class;
3343 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
3344 sizeof (UInt32), NULL, &mods);
3345 class = GetEventClass (eventRef);
3346 if (!NILP (Vmac_emulate_three_button_mouse)
3347 && (class == kEventClassMouse || class == kEventClassCommand))
3349 mods &= ~(optionKey | cmdKey);
3351 return mac_to_emacs_modifiers (mods, 0);
3354 /* Given an event REF, return the code to use for the mouse button
3355 code in the emacs input_event. */
3357 static int
3358 mac_get_mouse_btn (EventRef ref)
3360 EventMouseButton result = kEventMouseButtonPrimary;
3361 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
3362 sizeof (EventMouseButton), NULL, &result);
3363 switch (result)
3365 case kEventMouseButtonPrimary:
3366 if (NILP (Vmac_emulate_three_button_mouse))
3367 return 0;
3368 else {
3369 UInt32 mods = 0;
3370 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
3371 sizeof (UInt32), NULL, &mods);
3372 return mac_get_emulated_btn(mods);
3374 case kEventMouseButtonSecondary:
3375 return mac_wheel_button_is_mouse_2 ? 2 : 1;
3376 case kEventMouseButtonTertiary:
3377 case 4: /* 4 is the number for the mouse wheel button */
3378 return mac_wheel_button_is_mouse_2 ? 1 : 2;
3379 default:
3380 return 0;
3384 /* Normally, ConvertEventRefToEventRecord will correctly handle all
3385 events. However the click of the mouse wheel is not converted to a
3386 mouseDown or mouseUp event. Likewise for dead key events. This
3387 calls ConvertEventRefToEventRecord, but then checks to see if it is
3388 a mouse up/down, or a dead key Carbon event that has not been
3389 converted, and if so, converts it by hand (to be picked up in the
3390 XTread_socket loop). */
3391 static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
3393 OSStatus err;
3394 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
3395 EventKind action;
3397 if (result)
3398 return result;
3400 switch (GetEventClass (eventRef))
3402 case kEventClassMouse:
3403 switch (GetEventKind (eventRef))
3405 case kEventMouseDown:
3406 eventRec->what = mouseDown;
3407 result = 1;
3408 break;
3410 case kEventMouseUp:
3411 eventRec->what = mouseUp;
3412 result = 1;
3413 break;
3415 default:
3416 break;
3418 break;
3420 case kEventClassKeyboard:
3421 switch (GetEventKind (eventRef))
3423 case kEventRawKeyDown:
3424 action = keyDown;
3425 goto keystroke_common;
3426 case kEventRawKeyRepeat:
3427 action = autoKey;
3428 goto keystroke_common;
3429 case kEventRawKeyUp:
3430 action = keyUp;
3431 keystroke_common:
3433 unsigned char char_codes;
3434 UInt32 key_code;
3436 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
3437 typeChar, NULL, sizeof (char),
3438 NULL, &char_codes);
3439 if (err == noErr)
3440 err = GetEventParameter (eventRef, kEventParamKeyCode,
3441 typeUInt32, NULL, sizeof (UInt32),
3442 NULL, &key_code);
3443 if (err == noErr)
3445 eventRec->what = action;
3446 eventRec->message = char_codes | ((key_code & 0xff) << 8);
3447 result = 1;
3450 break;
3452 default:
3453 break;
3455 break;
3457 default:
3458 break;
3461 if (result)
3463 /* Need where and when. */
3464 UInt32 mods = 0;
3466 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
3467 NULL, sizeof (Point), NULL, &eventRec->where);
3468 /* Use two step process because new event modifiers are 32-bit
3469 and old are 16-bit. Currently, only loss is NumLock & Fn. */
3470 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
3471 NULL, sizeof (UInt32), NULL, &mods);
3472 eventRec->modifiers = mods;
3474 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
3477 return result;
3479 #endif /* TARGET_API_MAC_CARBON */
3481 #if !TARGET_API_MAC_CARBON
3482 static RgnHandle mouse_region = NULL;
3484 Boolean
3485 mac_wait_next_event (er, sleep_time, dequeue)
3486 EventRecord *er;
3487 UInt32 sleep_time;
3488 Boolean dequeue;
3490 static EventRecord er_buf = {nullEvent};
3491 UInt32 target_tick, current_tick;
3492 EventMask event_mask;
3494 if (mouse_region == NULL)
3495 mouse_region = NewRgn ();
3497 event_mask = everyEvent;
3498 if (!mac_ready_for_apple_events)
3499 event_mask -= highLevelEventMask;
3501 current_tick = TickCount ();
3502 target_tick = current_tick + sleep_time;
3504 if (er_buf.what == nullEvent)
3505 while (!WaitNextEvent (event_mask, &er_buf,
3506 target_tick - current_tick, mouse_region))
3508 current_tick = TickCount ();
3509 if (target_tick <= current_tick)
3510 return false;
3513 *er = er_buf;
3514 if (dequeue)
3515 er_buf.what = nullEvent;
3516 return true;
3518 #endif /* not TARGET_API_MAC_CARBON */
3520 #if TARGET_API_MAC_CARBON
3521 OSStatus
3522 mac_post_mouse_moved_event ()
3524 EventRef event = NULL;
3525 OSStatus err;
3527 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
3528 kEventAttributeNone, &event);
3529 if (err == noErr)
3531 Point mouse_pos;
3533 GetGlobalMouse (&mouse_pos);
3534 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
3535 sizeof (Point), &mouse_pos);
3537 if (err == noErr)
3539 UInt32 modifiers = GetCurrentKeyModifiers ();
3541 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
3542 sizeof (UInt32), &modifiers);
3544 if (err == noErr)
3545 err = PostEventToQueue (GetCurrentEventQueue (), event,
3546 kEventPriorityStandard);
3547 if (event)
3548 ReleaseEvent (event);
3550 return err;
3552 #endif
3554 #ifdef MAC_OSX
3555 /* Run the current run loop in the default mode until some input
3556 happens or TIMEOUT seconds passes unless it is negative. Return
3557 true if timeout occurs first. */
3559 Boolean
3560 mac_run_loop_run_once (timeout)
3561 EventTimeout timeout;
3563 #if USE_CG_DRAWING
3564 mac_prepare_for_quickdraw (NULL);
3565 #endif
3566 return (CFRunLoopRunInMode (kCFRunLoopDefaultMode,
3567 timeout >= 0 ? timeout : 100000, true)
3568 == kCFRunLoopRunTimedOut);
3570 #endif
3572 /* Emacs calls this whenever it wants to read an input event from the
3573 user. */
3576 XTread_socket (sd, expected, hold_quit)
3577 int sd, expected;
3578 struct input_event *hold_quit;
3580 struct input_event inev;
3581 int count = 0;
3582 #if TARGET_API_MAC_CARBON
3583 EventRef eventRef;
3584 EventTargetRef toolbox_dispatcher;
3585 #endif
3586 EventRecord er;
3587 struct mac_display_info *dpyinfo = &one_mac_display_info;
3589 if (interrupt_input_blocked)
3591 interrupt_input_pending = 1;
3592 return -1;
3595 interrupt_input_pending = 0;
3596 BLOCK_INPUT;
3598 /* So people can tell when we have read the available input. */
3599 input_signal_count++;
3601 ++handling_signal;
3603 #if TARGET_API_MAC_CARBON
3604 toolbox_dispatcher = GetEventDispatcherTarget ();
3606 while (
3607 #if USE_CG_DRAWING
3608 mac_prepare_for_quickdraw (NULL),
3609 #endif
3610 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
3611 kEventRemoveFromQueue, &eventRef))
3612 #else /* !TARGET_API_MAC_CARBON */
3613 while (mac_wait_next_event (&er, 0, true))
3614 #endif /* !TARGET_API_MAC_CARBON */
3616 int do_help = 0;
3617 struct frame *f;
3618 unsigned long timestamp;
3620 EVENT_INIT (inev);
3621 inev.kind = NO_EVENT;
3622 inev.arg = Qnil;
3624 #if TARGET_API_MAC_CARBON
3625 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
3627 if (!mac_convert_event_ref (eventRef, &er))
3628 goto OTHER;
3629 #else /* !TARGET_API_MAC_CARBON */
3630 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
3631 #endif /* !TARGET_API_MAC_CARBON */
3633 switch (er.what)
3635 case mouseDown:
3636 case mouseUp:
3638 WindowRef window_ptr;
3639 ControlPartCode part_code;
3640 int tool_bar_p = 0;
3642 #if TARGET_API_MAC_CARBON
3643 OSStatus err;
3645 /* This is needed to send mouse events like aqua window
3646 buttons to the correct handler. */
3647 read_socket_inev = &inev;
3648 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
3649 read_socket_inev = NULL;
3650 if (err != eventNotHandledErr)
3651 break;
3652 #endif
3653 last_mouse_glyph_frame = 0;
3655 if (dpyinfo->grabbed && last_mouse_frame
3656 && FRAME_LIVE_P (last_mouse_frame))
3658 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
3659 part_code = inContent;
3661 else
3663 part_code = FindWindow (er.where, &window_ptr);
3664 if (tip_window && window_ptr == tip_window)
3666 HideWindow (tip_window);
3667 part_code = FindWindow (er.where, &window_ptr);
3671 if (er.what != mouseDown
3672 && (part_code != inContent || dpyinfo->grabbed == 0))
3673 break;
3675 switch (part_code)
3677 case inMenuBar:
3678 f = mac_focus_frame (dpyinfo);
3679 saved_menu_event_location = er.where;
3680 inev.kind = MENU_BAR_ACTIVATE_EVENT;
3681 XSETFRAME (inev.frame_or_window, f);
3682 break;
3684 case inContent:
3685 if (
3686 #if TARGET_API_MAC_CARBON
3687 FrontNonFloatingWindow ()
3688 #else
3689 FrontWindow ()
3690 #endif
3691 != window_ptr
3692 || (mac_window_to_frame (window_ptr)
3693 != dpyinfo->x_focus_frame))
3694 SelectWindow (window_ptr);
3695 else
3697 ControlPartCode control_part_code;
3698 ControlRef ch;
3699 Point mouse_loc;
3700 #ifdef MAC_OSX
3701 ControlKind control_kind;
3702 #endif
3704 f = mac_window_to_frame (window_ptr);
3705 /* convert to local coordinates of new window */
3706 mouse_loc.h = (er.where.h
3707 - (f->left_pos
3708 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
3709 mouse_loc.v = (er.where.v
3710 - (f->top_pos
3711 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
3712 #if TARGET_API_MAC_CARBON
3713 ch = FindControlUnderMouse (mouse_loc, window_ptr,
3714 &control_part_code);
3715 #ifdef MAC_OSX
3716 if (ch)
3717 GetControlKind (ch, &control_kind);
3718 #endif
3719 #else
3720 control_part_code = FindControl (mouse_loc, window_ptr,
3721 &ch);
3722 #endif
3724 #if TARGET_API_MAC_CARBON
3725 inev.code = mac_get_mouse_btn (eventRef);
3726 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
3727 #else
3728 inev.code = mac_get_emulated_btn (er.modifiers);
3729 inev.modifiers = mac_to_emacs_modifiers (er.modifiers, 0);
3730 #endif
3731 XSETINT (inev.x, mouse_loc.h);
3732 XSETINT (inev.y, mouse_loc.v);
3734 if ((dpyinfo->grabbed && tracked_scroll_bar)
3735 || (ch != 0
3736 #ifndef USE_TOOLKIT_SCROLL_BARS
3737 /* control_part_code becomes kControlNoPart if
3738 a progress indicator is clicked. */
3739 && control_part_code != kControlNoPart
3740 #else /* USE_TOOLKIT_SCROLL_BARS */
3741 #ifdef MAC_OSX
3742 && control_kind.kind == kControlKindScrollBar
3743 #endif /* MAC_OSX */
3744 #endif /* USE_TOOLKIT_SCROLL_BARS */
3747 struct scroll_bar *bar;
3749 if (dpyinfo->grabbed && tracked_scroll_bar)
3751 bar = tracked_scroll_bar;
3752 #ifndef USE_TOOLKIT_SCROLL_BARS
3753 control_part_code = kControlIndicatorPart;
3754 #endif
3756 else
3757 bar = (struct scroll_bar *) GetControlReference (ch);
3758 #ifdef USE_TOOLKIT_SCROLL_BARS
3759 /* Make the "Ctrl-Mouse-2 splits window" work
3760 for toolkit scroll bars. */
3761 if (inev.modifiers & ctrl_modifier)
3762 x_scroll_bar_handle_click (bar, control_part_code,
3763 &er, &inev);
3764 else if (er.what == mouseDown)
3765 x_scroll_bar_handle_press (bar, control_part_code,
3766 mouse_loc, &inev);
3767 else
3768 x_scroll_bar_handle_release (bar, &inev);
3769 #else /* not USE_TOOLKIT_SCROLL_BARS */
3770 x_scroll_bar_handle_click (bar, control_part_code,
3771 &er, &inev);
3772 if (er.what == mouseDown
3773 && control_part_code == kControlIndicatorPart)
3774 tracked_scroll_bar = bar;
3775 else
3776 tracked_scroll_bar = NULL;
3777 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3779 else
3781 Lisp_Object window;
3782 int x = mouse_loc.h;
3783 int y = mouse_loc.v;
3785 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
3786 if (EQ (window, f->tool_bar_window))
3788 if (er.what == mouseDown)
3789 handle_tool_bar_click (f, x, y, 1, 0);
3790 else
3791 handle_tool_bar_click (f, x, y, 0,
3792 inev.modifiers);
3793 tool_bar_p = 1;
3795 else
3797 XSETFRAME (inev.frame_or_window, f);
3798 inev.kind = MOUSE_CLICK_EVENT;
3802 if (er.what == mouseDown)
3804 dpyinfo->grabbed |= (1 << inev.code);
3805 last_mouse_frame = f;
3807 if (!tool_bar_p)
3808 last_tool_bar_item = -1;
3810 else
3812 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
3813 /* If a button is released though it was not
3814 previously pressed, that would be because
3815 of multi-button emulation. */
3816 dpyinfo->grabbed = 0;
3817 else
3818 dpyinfo->grabbed &= ~(1 << inev.code);
3821 /* Ignore any mouse motion that happened before
3822 this event; any subsequent mouse-movement Emacs
3823 events should reflect only motion after the
3824 ButtonPress. */
3825 if (f != 0)
3826 f->mouse_moved = 0;
3828 #ifdef USE_TOOLKIT_SCROLL_BARS
3829 if (inev.kind == MOUSE_CLICK_EVENT
3830 || (inev.kind == SCROLL_BAR_CLICK_EVENT
3831 && (inev.modifiers & ctrl_modifier)))
3832 #endif
3833 switch (er.what)
3835 case mouseDown:
3836 inev.modifiers |= down_modifier;
3837 break;
3838 case mouseUp:
3839 inev.modifiers |= up_modifier;
3840 break;
3843 break;
3845 case inDrag:
3846 #if TARGET_API_MAC_CARBON
3847 case inProxyIcon:
3848 if (IsWindowPathSelectClick (window_ptr, &er))
3850 WindowPathSelect (window_ptr, NULL, NULL);
3851 break;
3853 if (part_code == inProxyIcon
3854 && (TrackWindowProxyDrag (window_ptr, er.where)
3855 != errUserWantsToDragWindow))
3856 break;
3857 DragWindow (window_ptr, er.where, NULL);
3858 #else /* not TARGET_API_MAC_CARBON */
3859 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
3860 /* Update the frame parameters. */
3862 struct frame *f = mac_window_to_frame (window_ptr);
3864 if (f && !f->async_iconified)
3865 mac_handle_origin_change (f);
3867 #endif /* not TARGET_API_MAC_CARBON */
3868 break;
3870 case inGoAway:
3871 if (TrackGoAway (window_ptr, er.where))
3873 inev.kind = DELETE_WINDOW_EVENT;
3874 XSETFRAME (inev.frame_or_window,
3875 mac_window_to_frame (window_ptr));
3877 break;
3879 /* window resize handling added --ben */
3880 case inGrow:
3881 do_grow_window (window_ptr, &er);
3882 break;
3884 /* window zoom handling added --ben */
3885 case inZoomIn:
3886 case inZoomOut:
3887 if (TrackBox (window_ptr, er.where, part_code))
3888 do_zoom_window (window_ptr, part_code);
3889 break;
3891 #if USE_MAC_TOOLBAR
3892 case inStructure:
3894 OSStatus err;
3895 HIViewRef ch;
3897 if (FrontNonFloatingWindow () != window_ptr)
3898 SelectWindow (window_ptr);
3900 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
3901 eventRef, &ch);
3902 /* This doesn't work on Mac OS X 10.2. */
3903 if (err == noErr)
3904 HIViewClick (ch, eventRef);
3906 break;
3907 #endif /* USE_MAC_TOOLBAR */
3909 default:
3910 break;
3913 break;
3915 #if !TARGET_API_MAC_CARBON
3916 case updateEvt:
3917 do_window_update ((WindowRef) er.message);
3918 break;
3919 #endif
3921 case osEvt:
3922 #if TARGET_API_MAC_CARBON
3923 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
3924 != eventNotHandledErr)
3925 break;
3926 #endif
3927 switch ((er.message >> 24) & 0x000000FF)
3929 #if USE_MAC_TSM
3930 case suspendResumeMessage:
3931 if (er.message & resumeFlag)
3932 mac_tsm_resume ();
3933 else
3934 mac_tsm_suspend ();
3935 break;
3936 #endif
3938 case mouseMovedMessage:
3939 #if !TARGET_API_MAC_CARBON
3940 SetRectRgn (mouse_region, er.where.h, er.where.v,
3941 er.where.h + 1, er.where.v + 1);
3942 #endif
3943 previous_help_echo_string = help_echo_string;
3944 help_echo_string = Qnil;
3946 if (dpyinfo->grabbed && last_mouse_frame
3947 && FRAME_LIVE_P (last_mouse_frame))
3948 f = last_mouse_frame;
3949 else
3950 f = dpyinfo->x_focus_frame;
3952 if (dpyinfo->mouse_face_hidden)
3954 dpyinfo->mouse_face_hidden = 0;
3955 clear_mouse_face (dpyinfo);
3958 if (f)
3960 WindowRef wp = FRAME_MAC_WINDOW (f);
3961 Point mouse_pos;
3963 mouse_pos.h = (er.where.h
3964 - (f->left_pos
3965 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
3966 mouse_pos.v = (er.where.v
3967 - (f->top_pos
3968 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
3969 if (dpyinfo->grabbed && tracked_scroll_bar)
3970 #ifdef USE_TOOLKIT_SCROLL_BARS
3971 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
3972 mouse_pos, &inev);
3973 #else /* not USE_TOOLKIT_SCROLL_BARS */
3974 x_scroll_bar_note_movement (tracked_scroll_bar,
3975 mouse_pos.v
3976 - XINT (tracked_scroll_bar->top),
3977 er.when * (1000 / 60));
3978 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3979 else
3981 /* Generate SELECT_WINDOW_EVENTs when needed. */
3982 if (!NILP (Vmouse_autoselect_window))
3984 Lisp_Object window;
3986 window = window_from_coordinates (f,
3987 mouse_pos.h,
3988 mouse_pos.v,
3989 0, 0, 0, 0);
3991 /* Window will be selected only when it is
3992 not selected now and last mouse movement
3993 event was not in it. Minibuffer window
3994 will be selected only when it is active. */
3995 if (WINDOWP (window)
3996 && !EQ (window, last_window)
3997 && !EQ (window, selected_window)
3998 /* For click-to-focus window managers
3999 create event iff we don't leave the
4000 selected frame. */
4001 && (focus_follows_mouse
4002 || (EQ (XWINDOW (window)->frame,
4003 XWINDOW (selected_window)->frame))))
4005 inev.kind = SELECT_WINDOW_EVENT;
4006 inev.frame_or_window = window;
4009 last_window=window;
4011 if (!note_mouse_movement (f, &mouse_pos))
4012 help_echo_string = previous_help_echo_string;
4013 #if USE_MAC_TOOLBAR
4014 else
4015 mac_tool_bar_note_mouse_movement (f, eventRef);
4016 #endif
4020 /* If the contents of the global variable
4021 help_echo_string has changed, generate a
4022 HELP_EVENT. */
4023 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
4024 do_help = 1;
4025 break;
4027 break;
4029 case activateEvt:
4031 WindowRef window_ptr = (WindowRef) er.message;
4032 OSErr err;
4033 ControlRef root_control;
4035 if (window_ptr == tip_window)
4037 HideWindow (tip_window);
4038 break;
4041 if (!is_emacs_window (window_ptr))
4042 goto OTHER;
4044 f = mac_window_to_frame (window_ptr);
4046 if ((er.modifiers & activeFlag) != 0)
4048 /* A window has been activated */
4049 Point mouse_loc;
4051 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
4052 if (err == noErr)
4053 ActivateControl (root_control);
4055 x_detect_focus_change (dpyinfo, &er, &inev);
4057 mouse_loc.h = (er.where.h
4058 - (f->left_pos
4059 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
4060 mouse_loc.v = (er.where.v
4061 - (f->top_pos
4062 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
4063 /* Window-activated event counts as mouse movement,
4064 so update things that depend on mouse position. */
4065 note_mouse_movement (f, &mouse_loc);
4067 else
4069 /* A window has been deactivated */
4070 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
4071 if (err == noErr)
4072 DeactivateControl (root_control);
4074 #ifdef USE_TOOLKIT_SCROLL_BARS
4075 if (dpyinfo->grabbed && tracked_scroll_bar)
4077 struct input_event event;
4079 EVENT_INIT (event);
4080 event.kind = NO_EVENT;
4081 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
4082 if (event.kind != NO_EVENT)
4084 event.timestamp = timestamp;
4085 kbd_buffer_store_event_hold (&event, hold_quit);
4086 count++;
4089 #endif
4090 dpyinfo->grabbed = 0;
4092 x_detect_focus_change (dpyinfo, &er, &inev);
4094 if (f == dpyinfo->mouse_face_mouse_frame)
4096 /* If we move outside the frame, then we're
4097 certainly no longer on any text in the
4098 frame. */
4099 clear_mouse_face (dpyinfo);
4100 dpyinfo->mouse_face_mouse_frame = 0;
4103 /* Generate a nil HELP_EVENT to cancel a help-echo.
4104 Do it only if there's something to cancel.
4105 Otherwise, the startup message is cleared when the
4106 mouse leaves the frame. */
4107 if (any_help_event_p)
4108 do_help = -1;
4111 break;
4113 case keyDown:
4114 case keyUp:
4115 case autoKey:
4116 ObscureCursor ();
4118 f = mac_focus_frame (dpyinfo);
4119 XSETFRAME (inev.frame_or_window, f);
4121 /* If mouse-highlight is an integer, input clears out mouse
4122 highlighting. */
4123 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
4124 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
4126 clear_mouse_face (dpyinfo);
4127 dpyinfo->mouse_face_hidden = 1;
4131 UInt32 modifiers = er.modifiers, mapped_modifiers;
4132 UInt32 key_code = (er.message & keyCodeMask) >> 8;
4134 #ifdef MAC_OSX
4135 GetEventParameter (eventRef, kEventParamKeyModifiers,
4136 typeUInt32, NULL,
4137 sizeof (UInt32), NULL, &modifiers);
4138 #endif
4139 mapped_modifiers = mac_mapped_modifiers (modifiers, key_code);
4141 #if TARGET_API_MAC_CARBON
4142 if (!(mapped_modifiers
4143 & ~(mac_pass_command_to_system ? cmdKey : 0)
4144 & ~(mac_pass_control_to_system ? controlKey : 0)))
4145 goto OTHER;
4146 else
4147 #endif
4148 if (er.what != keyUp)
4149 do_keystroke (er.what, er.message & charCodeMask,
4150 key_code, modifiers, timestamp, &inev);
4152 break;
4154 case kHighLevelEvent:
4155 AEProcessAppleEvent (&er);
4156 break;
4158 default:
4159 OTHER:
4160 #if TARGET_API_MAC_CARBON
4162 OSStatus err;
4164 read_socket_inev = &inev;
4165 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
4166 read_socket_inev = NULL;
4168 #endif
4169 break;
4171 #if TARGET_API_MAC_CARBON
4172 ReleaseEvent (eventRef);
4173 #endif
4175 if (inev.kind != NO_EVENT)
4177 inev.timestamp = timestamp;
4178 kbd_buffer_store_event_hold (&inev, hold_quit);
4179 count++;
4182 if (do_help
4183 && !(hold_quit && hold_quit->kind != NO_EVENT))
4185 Lisp_Object frame;
4187 if (f)
4188 XSETFRAME (frame, f);
4189 else
4190 frame = Qnil;
4192 if (do_help > 0)
4194 any_help_event_p = 1;
4195 gen_help_event (help_echo_string, frame, help_echo_window,
4196 help_echo_object, help_echo_pos);
4198 else
4200 help_echo_string = Qnil;
4201 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
4203 count++;
4207 /* If the focus was just given to an autoraising frame,
4208 raise it now. */
4209 /* ??? This ought to be able to handle more than one such frame. */
4210 if (pending_autoraise_frame)
4212 x_raise_frame (pending_autoraise_frame);
4213 pending_autoraise_frame = 0;
4216 if (mac_screen_config_changed)
4218 mac_get_screen_info (dpyinfo);
4219 mac_screen_config_changed = 0;
4222 #if !TARGET_API_MAC_CARBON
4223 /* Check which frames are still visible. We do this here because
4224 there doesn't seem to be any direct notification from the Window
4225 Manager that the visibility of a window has changed (at least,
4226 not in all cases). */
4228 Lisp_Object tail, frame;
4230 FOR_EACH_FRAME (tail, frame)
4232 struct frame *f = XFRAME (frame);
4234 /* The tooltip has been drawn already. Avoid the
4235 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
4236 if (EQ (frame, tip_frame))
4237 continue;
4239 if (FRAME_MAC_P (f))
4240 mac_handle_visibility_change (f);
4243 #endif
4245 --handling_signal;
4246 UNBLOCK_INPUT;
4247 return count;
4251 /***********************************************************************
4252 Busy cursor
4253 ***********************************************************************/
4255 #if TARGET_API_MAC_CARBON
4256 /* Show the spinning progress indicator for the frame F. Create it if
4257 it doesn't exist yet. */
4259 void
4260 mac_show_hourglass (f)
4261 struct frame *f;
4263 #if USE_CG_DRAWING
4264 mac_prepare_for_quickdraw (f);
4265 #endif
4266 if (!f->output_data.mac->hourglass_control)
4268 Window w = FRAME_MAC_WINDOW (f);
4269 Rect r;
4270 ControlRef c;
4272 GetWindowPortBounds (w, &r);
4273 r.left = r.right - HOURGLASS_WIDTH;
4274 r.bottom = r.top + HOURGLASS_HEIGHT;
4275 if (CreateChasingArrowsControl (w, &r, &c) == noErr)
4276 f->output_data.mac->hourglass_control = c;
4279 if (f->output_data.mac->hourglass_control)
4280 ShowControl (f->output_data.mac->hourglass_control);
4283 /* Hide the spinning progress indicator for the frame F. Do nothing
4284 it doesn't exist yet. */
4286 void
4287 mac_hide_hourglass (f)
4288 struct frame *f;
4290 if (f->output_data.mac->hourglass_control)
4292 #if USE_CG_DRAWING
4293 mac_prepare_for_quickdraw (f);
4294 #endif
4295 HideControl (f->output_data.mac->hourglass_control);
4299 /* Reposition the spinning progress indicator for the frame F. Do
4300 nothing it doesn't exist yet. */
4302 void
4303 mac_reposition_hourglass (f)
4304 struct frame *f;
4306 if (f->output_data.mac->hourglass_control)
4308 #if USE_CG_DRAWING
4309 mac_prepare_for_quickdraw (f);
4310 #endif
4311 MoveControl (f->output_data.mac->hourglass_control,
4312 FRAME_PIXEL_WIDTH (f) - HOURGLASS_WIDTH, 0);
4315 #endif /* TARGET_API_MAC_CARBON */
4318 /***********************************************************************
4319 File selection dialog
4320 ***********************************************************************/
4322 #if TARGET_API_MAC_CARBON
4323 extern Lisp_Object Qfile_name_history;
4325 static pascal void mac_nav_event_callback P_ ((NavEventCallbackMessage,
4326 NavCBRecPtr, void *));
4328 /* The actual implementation of Fx_file_dialog. */
4330 Lisp_Object
4331 mac_file_dialog (prompt, dir, default_filename, mustmatch, only_dir_p)
4332 Lisp_Object prompt, dir, default_filename, mustmatch, only_dir_p;
4334 Lisp_Object file = Qnil;
4335 int count = SPECPDL_INDEX ();
4336 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
4337 char filename[MAXPATHLEN];
4338 static NavEventUPP mac_nav_event_callbackUPP = NULL;
4340 check_mac ();
4342 GCPRO6 (prompt, dir, default_filename, mustmatch, file, only_dir_p);
4343 CHECK_STRING (prompt);
4344 CHECK_STRING (dir);
4346 /* Create the dialog with PROMPT as title, using DIR as initial
4347 directory and using "*" as pattern. */
4348 dir = Fexpand_file_name (dir, Qnil);
4351 OSStatus status;
4352 NavDialogCreationOptions options;
4353 NavDialogRef dialogRef;
4354 NavTypeListHandle fileTypes = NULL;
4355 NavUserAction userAction;
4356 CFStringRef message=NULL, saveName = NULL;
4358 BLOCK_INPUT;
4359 /* No need for a callback function because we are modal */
4360 NavGetDefaultDialogCreationOptions(&options);
4361 options.modality = kWindowModalityAppModal;
4362 options.location.h = options.location.v = -1;
4363 options.optionFlags = kNavDefaultNavDlogOptions;
4364 options.optionFlags |= kNavAllFilesInPopup; /* All files allowed */
4365 options.optionFlags |= kNavSelectAllReadableItem;
4366 options.optionFlags &= ~kNavAllowMultipleFiles;
4367 if (!NILP(prompt))
4369 message = cfstring_create_with_string (prompt);
4370 options.message = message;
4372 /* Don't set the application, let it use default.
4373 options.clientName = CFSTR ("Emacs");
4376 if (mac_nav_event_callbackUPP == NULL)
4377 mac_nav_event_callbackUPP = NewNavEventUPP (mac_nav_event_callback);
4379 if (!NILP (only_dir_p))
4380 status = NavCreateChooseFolderDialog(&options, mac_nav_event_callbackUPP,
4381 NULL, NULL, &dialogRef);
4382 else if (NILP (mustmatch))
4384 /* This is a save dialog */
4385 options.optionFlags |= kNavDontConfirmReplacement;
4386 options.actionButtonLabel = CFSTR ("Ok");
4387 options.windowTitle = CFSTR ("Enter name");
4389 if (STRINGP (default_filename))
4391 Lisp_Object utf8 = ENCODE_UTF_8 (default_filename);
4392 char *begPtr = SDATA(utf8);
4393 char *filePtr = begPtr + SBYTES(utf8);
4394 while (filePtr != begPtr && !IS_DIRECTORY_SEP(filePtr[-1]))
4395 filePtr--;
4396 saveName = cfstring_create_with_utf8_cstring (filePtr);
4397 options.saveFileName = saveName;
4398 options.optionFlags |= kNavSelectDefaultLocation;
4400 status = NavCreatePutFileDialog(&options,
4401 'TEXT', kNavGenericSignature,
4402 mac_nav_event_callbackUPP, NULL,
4403 &dialogRef);
4405 else
4407 /* This is an open dialog*/
4408 status = NavCreateChooseFileDialog(&options, fileTypes,
4409 mac_nav_event_callbackUPP, NULL,
4410 NULL, NULL, &dialogRef);
4413 /* Set the default location and continue*/
4414 if (status == noErr)
4416 Lisp_Object encoded_dir = ENCODE_FILE (dir);
4417 AEDesc defLocAed;
4419 status = AECreateDesc (TYPE_FILE_NAME, SDATA (encoded_dir),
4420 SBYTES (encoded_dir), &defLocAed);
4421 if (status == noErr)
4423 NavCustomControl(dialogRef, kNavCtlSetLocation, (void*) &defLocAed);
4424 AEDisposeDesc(&defLocAed);
4426 status = NavDialogRun(dialogRef);
4429 if (saveName) CFRelease(saveName);
4430 if (message) CFRelease(message);
4432 if (status == noErr) {
4433 userAction = NavDialogGetUserAction(dialogRef);
4434 switch (userAction)
4436 case kNavUserActionNone:
4437 case kNavUserActionCancel:
4438 break; /* Treat cancel like C-g */
4439 case kNavUserActionOpen:
4440 case kNavUserActionChoose:
4441 case kNavUserActionSaveAs:
4443 NavReplyRecord reply;
4444 Size len;
4446 status = NavDialogGetReply(dialogRef, &reply);
4447 if (status != noErr)
4448 break;
4449 status = AEGetNthPtr (&reply.selection, 1, TYPE_FILE_NAME,
4450 NULL, NULL, filename,
4451 sizeof (filename) - 1, &len);
4452 if (status == noErr)
4454 len = min (len, sizeof (filename) - 1);
4455 filename[len] = '\0';
4456 if (reply.saveFileName)
4458 /* If it was a saved file, we need to add the file name */
4459 if (len && len < sizeof (filename) - 1
4460 && filename[len-1] != '/')
4461 filename[len++] = '/';
4462 CFStringGetCString(reply.saveFileName, filename+len,
4463 sizeof (filename) - len,
4464 #ifdef MAC_OSX
4465 kCFStringEncodingUTF8
4466 #else
4467 CFStringGetSystemEncoding ()
4468 #endif
4471 file = DECODE_FILE (make_unibyte_string (filename,
4472 strlen (filename)));
4474 NavDisposeReply(&reply);
4476 break;
4478 NavDialogDispose(dialogRef);
4479 UNBLOCK_INPUT;
4481 else {
4482 UNBLOCK_INPUT;
4483 /* Fall back on minibuffer if there was a problem */
4484 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
4485 dir, mustmatch, dir, Qfile_name_history,
4486 default_filename, Qnil);
4490 UNGCPRO;
4492 /* Make "Cancel" equivalent to C-g. */
4493 if (NILP (file))
4494 Fsignal (Qquit, Qnil);
4496 return unbind_to (count, file);
4499 /* Need to register some event callback function for enabling drag and
4500 drop in Navigation Service dialogs. */
4501 static pascal void
4502 mac_nav_event_callback (selector, parms, data)
4503 NavEventCallbackMessage selector;
4504 NavCBRecPtr parms;
4505 void *data;
4508 #endif
4511 /************************************************************************
4512 Menu
4513 ************************************************************************/
4515 #if !TARGET_API_MAC_CARBON
4516 #include <MacTypes.h>
4517 #include <Menus.h>
4518 #include <Quickdraw.h>
4519 #include <ToolUtils.h>
4520 #include <Fonts.h>
4521 #include <Controls.h>
4522 #include <Windows.h>
4523 #include <Events.h>
4524 #if defined (__MRC__) || (__MSL__ >= 0x6000)
4525 #include <ControlDefinitions.h>
4526 #endif
4527 #endif /* not TARGET_API_MAC_CARBON */
4529 extern int menu_item_selection;
4530 extern int popup_activated_flag;
4531 extern int name_is_separator P_ ((const char *));
4532 extern void find_and_call_menu_selection P_ ((FRAME_PTR, int, Lisp_Object,
4533 void *));
4534 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
4536 enum mac_menu_kind { /* Menu ID range */
4537 MAC_MENU_APPLE, /* 0 (Reserved by Apple) */
4538 MAC_MENU_MENU_BAR, /* 1 .. 233 */
4539 MAC_MENU_M_APPLE, /* 234 (== M_APPLE) */
4540 MAC_MENU_POPUP, /* 235 */
4541 MAC_MENU_DRIVER, /* 236 .. 255 (Reserved) */
4542 MAC_MENU_MENU_BAR_SUB, /* 256 .. 16383 */
4543 MAC_MENU_POPUP_SUB, /* 16384 .. 32767 */
4544 MAC_MENU_END /* 32768 */
4547 static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
4549 static int fill_menu P_ ((MenuRef, widget_value *, enum mac_menu_kind, int));
4550 static void dispose_menus P_ ((enum mac_menu_kind, int));
4552 #if !TARGET_API_MAC_CARBON
4553 static void
4554 do_apple_menu (SInt16 menu_item)
4556 Str255 item_name;
4557 SInt16 da_driver_refnum;
4559 if (menu_item == I_ABOUT)
4560 NoteAlert (ABOUT_ALERT_ID, NULL);
4561 else
4563 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
4564 da_driver_refnum = OpenDeskAcc (item_name);
4567 #endif /* !TARGET_API_MAC_CARBON */
4569 /* Activate the menu bar of frame F.
4570 This is called from keyboard.c when it gets the
4571 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
4573 To activate the menu bar, we use the button-press event location
4574 that was saved in saved_menu_event_location.
4576 But first we recompute the menu bar contents (the whole tree).
4578 The reason for saving the button event until here, instead of
4579 passing it to the toolkit right away, is that we can safely
4580 execute Lisp code. */
4582 void
4583 x_activate_menubar (f)
4584 FRAME_PTR f;
4586 SInt32 menu_choice;
4587 SInt16 menu_id, menu_item;
4589 set_frame_menubar (f, 0, 1);
4590 BLOCK_INPUT;
4592 popup_activated_flag = 1;
4593 menu_choice = MenuSelect (saved_menu_event_location);
4594 popup_activated_flag = 0;
4595 menu_id = HiWord (menu_choice);
4596 menu_item = LoWord (menu_choice);
4598 #if !TARGET_API_MAC_CARBON
4599 if (menu_id == min_menu_id[MAC_MENU_M_APPLE])
4600 do_apple_menu (menu_item);
4601 else
4602 #endif
4603 if (menu_id)
4605 MenuRef menu = GetMenuRef (menu_id);
4607 if (menu)
4609 UInt32 refcon;
4611 GetMenuItemRefCon (menu, menu_item, &refcon);
4612 find_and_call_menu_selection (f, f->menu_bar_items_used,
4613 f->menu_bar_vector, (void *) refcon);
4617 HiliteMenu (0);
4619 UNBLOCK_INPUT;
4622 #if TARGET_API_MAC_CARBON
4623 extern Lisp_Object Vshow_help_function;
4625 static Lisp_Object
4626 restore_show_help_function (old_show_help_function)
4627 Lisp_Object old_show_help_function;
4629 Vshow_help_function = old_show_help_function;
4631 return Qnil;
4634 static pascal OSStatus
4635 menu_target_item_handler (next_handler, event, data)
4636 EventHandlerCallRef next_handler;
4637 EventRef event;
4638 void *data;
4640 OSStatus err;
4641 MenuRef menu;
4642 MenuItemIndex menu_item;
4643 Lisp_Object help;
4644 GrafPtr port;
4645 int specpdl_count = SPECPDL_INDEX ();
4647 /* Don't be bothered with the overflowed toolbar items menu. */
4648 if (!popup_activated ())
4649 return eventNotHandledErr;
4651 err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef,
4652 NULL, sizeof (MenuRef), NULL, &menu);
4653 if (err == noErr)
4654 err = GetEventParameter (event, kEventParamMenuItemIndex,
4655 typeMenuItemIndex, NULL,
4656 sizeof (MenuItemIndex), NULL, &menu_item);
4657 if (err == noErr)
4658 err = GetMenuItemProperty (menu, menu_item,
4659 MAC_EMACS_CREATOR_CODE, 'help',
4660 sizeof (Lisp_Object), NULL, &help);
4661 if (err != noErr)
4662 help = Qnil;
4664 /* Temporarily bind Vshow_help_function to Qnil because we don't
4665 want tooltips during menu tracking. */
4666 record_unwind_protect (restore_show_help_function, Vshow_help_function);
4667 Vshow_help_function = Qnil;
4668 GetPort (&port);
4669 show_help_echo (help, Qnil, Qnil, Qnil, 1);
4670 SetPort (port);
4671 unbind_to (specpdl_count, Qnil);
4673 return err == noErr ? noErr : eventNotHandledErr;
4676 /* Showing help echo string during menu tracking. */
4678 static OSStatus
4679 install_menu_target_item_handler ()
4681 static const EventTypeSpec specs[] =
4682 {{kEventClassMenu, kEventMenuTargetItem}};
4684 return InstallApplicationEventHandler (NewEventHandlerUPP
4685 (menu_target_item_handler),
4686 GetEventTypeCount (specs),
4687 specs, NULL, NULL);
4689 #endif /* TARGET_API_MAC_CARBON */
4691 /* Event handler function that pops down a menu on C-g. We can only pop
4692 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
4694 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4695 static pascal OSStatus
4696 menu_quit_handler (nextHandler, theEvent, userData)
4697 EventHandlerCallRef nextHandler;
4698 EventRef theEvent;
4699 void* userData;
4701 OSStatus err;
4702 UInt32 keyCode;
4703 UInt32 keyModifiers;
4705 err = GetEventParameter (theEvent, kEventParamKeyCode,
4706 typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
4708 if (err == noErr)
4709 err = GetEventParameter (theEvent, kEventParamKeyModifiers,
4710 typeUInt32, NULL, sizeof(UInt32),
4711 NULL, &keyModifiers);
4713 if (err == noErr && mac_quit_char_key_p (keyModifiers, keyCode))
4715 MenuRef menu = userData != 0
4716 ? (MenuRef)userData : AcquireRootMenu ();
4718 CancelMenuTracking (menu, true, 0);
4719 if (!userData) ReleaseMenu (menu);
4720 return noErr;
4723 return CallNextEventHandler (nextHandler, theEvent);
4725 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4727 /* Add event handler to all menus that belong to KIND so we can detect
4728 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
4729 when C-g is detected. NULL means the menu bar. If
4730 CancelMenuTracking isn't available, do nothing. */
4732 static void
4733 install_menu_quit_handler (kind, root_menu)
4734 enum mac_menu_kind kind;
4735 MenuRef root_menu;
4737 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4738 static const EventTypeSpec typesList[] =
4739 {{kEventClassKeyboard, kEventRawKeyDown}};
4740 int id;
4742 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
4743 if (CancelMenuTracking == NULL)
4744 return;
4745 #endif
4746 for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++)
4748 MenuRef menu = GetMenuRef (id);
4750 if (menu == NULL)
4751 break;
4752 InstallMenuEventHandler (menu, menu_quit_handler,
4753 GetEventTypeCount (typesList),
4754 typesList, root_menu, NULL);
4756 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4759 static Lisp_Object
4760 pop_down_menu (arg)
4761 Lisp_Object arg;
4763 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
4764 FRAME_PTR f = p->pointer;
4765 MenuRef menu = GetMenuRef (min_menu_id[MAC_MENU_POPUP]);
4767 BLOCK_INPUT;
4769 /* Must reset this manually because the button release event is not
4770 passed to Emacs event loop. */
4771 FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0;
4773 /* delete all menus */
4774 dispose_menus (MAC_MENU_POPUP_SUB, 0);
4775 DeleteMenu (min_menu_id[MAC_MENU_POPUP]);
4776 DisposeMenu (menu);
4778 UNBLOCK_INPUT;
4780 return Qnil;
4783 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop
4784 until the menu pops down. Return the selection. */
4786 void
4787 create_and_show_popup_menu (f, first_wv, x, y, for_click)
4788 FRAME_PTR f;
4789 widget_value *first_wv;
4790 int x;
4791 int y;
4792 int for_click;
4794 int result = 0;
4795 MenuRef menu = NewMenu (min_menu_id[MAC_MENU_POPUP], "\p");
4796 int menu_item_choice;
4797 int specpdl_count = SPECPDL_INDEX ();
4799 InsertMenu (menu, -1);
4800 fill_menu (menu, first_wv->contents, MAC_MENU_POPUP_SUB,
4801 min_menu_id[MAC_MENU_POPUP_SUB]);
4803 /* Add event handler so we can detect C-g. */
4804 install_menu_quit_handler (MAC_MENU_POPUP, menu);
4805 install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu);
4807 record_unwind_protect (pop_down_menu, make_save_value (f, 0));
4809 /* Adjust coordinates to be root-window-relative. */
4810 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
4811 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
4813 /* Display the menu. */
4814 popup_activated_flag = 1;
4815 menu_item_choice = PopUpMenuSelect (menu, y, x, 0);
4816 popup_activated_flag = 0;
4818 /* Get the refcon to find the correct item */
4819 if (menu_item_choice)
4821 MenuRef sel_menu = GetMenuRef (HiWord (menu_item_choice));
4823 if (sel_menu)
4824 GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice),
4825 (UInt32 *) &result);
4828 unbind_to (specpdl_count, Qnil);
4830 menu_item_selection = result;
4833 static void
4834 add_menu_item (menu, pos, wv)
4835 MenuRef menu;
4836 int pos;
4837 widget_value *wv;
4839 #if TARGET_API_MAC_CARBON
4840 CFStringRef item_name;
4841 #else
4842 Str255 item_name;
4843 #endif
4845 if (name_is_separator (wv->name))
4846 AppendMenu (menu, "\p-");
4847 else
4849 AppendMenu (menu, "\pX");
4851 #if TARGET_API_MAC_CARBON
4852 item_name = cfstring_create_with_utf8_cstring (wv->name);
4854 if (wv->key != NULL)
4856 CFStringRef name, key;
4858 name = item_name;
4859 key = cfstring_create_with_utf8_cstring (wv->key);
4860 item_name = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@ %@"),
4861 name, key);
4862 CFRelease (name);
4863 CFRelease (key);
4866 SetMenuItemTextWithCFString (menu, pos, item_name);
4867 CFRelease (item_name);
4869 if (wv->enabled)
4870 EnableMenuItem (menu, pos);
4871 else
4872 DisableMenuItem (menu, pos);
4874 if (STRINGP (wv->help))
4875 SetMenuItemProperty (menu, pos, MAC_EMACS_CREATOR_CODE, 'help',
4876 sizeof (Lisp_Object), &wv->help);
4877 #else /* ! TARGET_API_MAC_CARBON */
4878 item_name[sizeof (item_name) - 1] = '\0';
4879 strncpy (item_name, wv->name, sizeof (item_name) - 1);
4880 if (wv->key != NULL)
4882 int len = strlen (item_name);
4884 strncpy (item_name + len, " ", sizeof (item_name) - 1 - len);
4885 len = strlen (item_name);
4886 strncpy (item_name + len, wv->key, sizeof (item_name) - 1 - len);
4888 c2pstr (item_name);
4889 SetMenuItemText (menu, pos, item_name);
4891 if (wv->enabled)
4892 EnableItem (menu, pos);
4893 else
4894 DisableItem (menu, pos);
4895 #endif /* ! TARGET_API_MAC_CARBON */
4897 /* Draw radio buttons and tickboxes. */
4898 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE
4899 || wv->button_type == BUTTON_TYPE_RADIO))
4900 SetItemMark (menu, pos, checkMark);
4901 else
4902 SetItemMark (menu, pos, noMark);
4904 SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
4908 /* Construct native Mac OS menu based on widget_value tree. */
4910 static int
4911 fill_menu (menu, wv, kind, submenu_id)
4912 MenuRef menu;
4913 widget_value *wv;
4914 enum mac_menu_kind kind;
4915 int submenu_id;
4917 int pos;
4919 for (pos = 1; wv != NULL; wv = wv->next, pos++)
4921 add_menu_item (menu, pos, wv);
4922 if (wv->contents && submenu_id < min_menu_id[kind + 1])
4924 MenuRef submenu = NewMenu (submenu_id, "\pX");
4926 InsertMenu (submenu, -1);
4927 #if TARGET_API_MAC_CARBON
4928 SetMenuItemHierarchicalMenu (menu, pos, submenu);
4929 #else
4930 SetMenuItemHierarchicalID (menu, pos, submenu_id);
4931 #endif
4932 submenu_id = fill_menu (submenu, wv->contents, kind, submenu_id + 1);
4936 return submenu_id;
4939 /* Fill menu bar with the items defined by WV. If DEEP_P, consider
4940 the entire menu trees we supply, rather than just the menu bar item
4941 names. */
4943 void
4944 mac_fill_menubar (wv, deep_p)
4945 widget_value *wv;
4946 int deep_p;
4948 int id, submenu_id;
4949 #if !TARGET_API_MAC_CARBON
4950 int title_changed_p = 0;
4951 #endif
4953 /* Clean up the menu bar when filled by the entire menu trees. */
4954 if (deep_p)
4956 dispose_menus (MAC_MENU_MENU_BAR, 0);
4957 dispose_menus (MAC_MENU_MENU_BAR_SUB, 0);
4958 #if !TARGET_API_MAC_CARBON
4959 title_changed_p = 1;
4960 #endif
4963 /* Fill menu bar titles and submenus. Reuse the existing menu bar
4964 titles as much as possible to minimize redraw (if !deep_p). */
4965 submenu_id = min_menu_id[MAC_MENU_MENU_BAR_SUB];
4966 for (id = min_menu_id[MAC_MENU_MENU_BAR];
4967 wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1];
4968 wv = wv->next, id++)
4970 OSStatus err = noErr;
4971 MenuRef menu;
4972 #if TARGET_API_MAC_CARBON
4973 CFStringRef title;
4975 title = CFStringCreateWithCString (NULL, wv->name,
4976 kCFStringEncodingMacRoman);
4977 #else
4978 Str255 title;
4980 strncpy (title, wv->name, 255);
4981 title[255] = '\0';
4982 c2pstr (title);
4983 #endif
4985 menu = GetMenuRef (id);
4986 if (menu)
4988 #if TARGET_API_MAC_CARBON
4989 CFStringRef old_title;
4991 err = CopyMenuTitleAsCFString (menu, &old_title);
4992 if (err == noErr)
4994 if (CFStringCompare (title, old_title, 0) != kCFCompareEqualTo)
4996 #ifdef MAC_OSX
4997 if (id + 1 == min_menu_id[MAC_MENU_MENU_BAR + 1]
4998 || GetMenuRef (id + 1) == NULL)
5000 /* This is a workaround for Mac OS X 10.5 where
5001 just calling SetMenuTitleWithCFString fails
5002 to change the title of the last (Help) menu
5003 in the menu bar. */
5004 DeleteMenu (id);
5005 DisposeMenu (menu);
5006 menu = NULL;
5008 else
5009 #endif /* MAC_OSX */
5010 err = SetMenuTitleWithCFString (menu, title);
5012 CFRelease (old_title);
5014 else
5015 err = SetMenuTitleWithCFString (menu, title);
5016 #else /* !TARGET_API_MAC_CARBON */
5017 if (!EqualString (title, (*menu)->menuData, false, false))
5019 DeleteMenu (id);
5020 DisposeMenu (menu);
5021 menu = NewMenu (id, title);
5022 InsertMenu (menu, GetMenuRef (id + 1) ? id + 1 : 0);
5023 title_changed_p = 1;
5025 #endif /* !TARGET_API_MAC_CARBON */
5028 if (!menu)
5030 #if TARGET_API_MAC_CARBON
5031 err = CreateNewMenu (id, 0, &menu);
5032 if (err == noErr)
5033 err = SetMenuTitleWithCFString (menu, title);
5034 #else
5035 menu = NewMenu (id, title);
5036 #endif
5037 if (err == noErr)
5039 InsertMenu (menu, 0);
5040 #if !TARGET_API_MAC_CARBON
5041 title_changed_p = 1;
5042 #endif
5045 #if TARGET_API_MAC_CARBON
5046 CFRelease (title);
5047 #endif
5049 if (err == noErr)
5050 if (wv->contents)
5051 submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
5052 submenu_id);
5055 if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuRef (id))
5057 dispose_menus (MAC_MENU_MENU_BAR, id);
5058 #if !TARGET_API_MAC_CARBON
5059 title_changed_p = 1;
5060 #endif
5063 #if !TARGET_API_MAC_CARBON
5064 if (title_changed_p)
5065 InvalMenuBar ();
5066 #endif
5068 /* Add event handler so we can detect C-g. */
5069 install_menu_quit_handler (MAC_MENU_MENU_BAR, NULL);
5070 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB, NULL);
5073 /* Dispose of menus that belong to KIND, and remove them from the menu
5074 list. ID is the lower bound of menu IDs that will be processed. */
5076 static void
5077 dispose_menus (kind, id)
5078 enum mac_menu_kind kind;
5079 int id;
5081 for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++)
5083 MenuRef menu = GetMenuRef (id);
5085 if (menu == NULL)
5086 break;
5087 DeleteMenu (id);
5088 DisposeMenu (menu);
5092 static void
5093 init_menu_bar ()
5095 #ifdef MAC_OSX
5096 OSStatus err;
5097 MenuRef menu;
5098 MenuItemIndex menu_index;
5100 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
5101 &menu, &menu_index);
5102 if (err == noErr)
5103 SetMenuItemCommandKey (menu, menu_index, false, 0);
5104 EnableMenuCommand (NULL, kHICommandPreferences);
5105 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
5106 &menu, &menu_index);
5107 if (err == noErr)
5109 SetMenuItemCommandKey (menu, menu_index, false, 0);
5110 InsertMenuItemTextWithCFString (menu, NULL,
5111 0, kMenuItemAttrSeparator, 0);
5112 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
5113 0, 0, kHICommandAbout);
5115 #else /* !MAC_OSX */
5116 #if TARGET_API_MAC_CARBON
5117 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
5118 #endif
5119 #endif
5123 /***********************************************************************
5124 Popup Dialog
5125 ***********************************************************************/
5127 #if TARGET_API_MAC_CARBON
5128 #define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
5129 #define DIALOG_BUTTON_COMMAND_ID_P(id) \
5130 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
5131 #define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
5132 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
5133 #define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
5134 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
5136 extern EMACS_TIME timer_check P_ ((int));
5137 static int quit_dialog_event_loop;
5139 static pascal OSStatus
5140 mac_handle_dialog_event (next_handler, event, data)
5141 EventHandlerCallRef next_handler;
5142 EventRef event;
5143 void *data;
5145 OSStatus err, result = eventNotHandledErr;
5146 WindowRef window = (WindowRef) data;
5148 switch (GetEventClass (event))
5150 case kEventClassCommand:
5152 HICommand command;
5154 err = GetEventParameter (event, kEventParamDirectObject,
5155 typeHICommand, NULL, sizeof (HICommand),
5156 NULL, &command);
5157 if (err == noErr)
5158 if (DIALOG_BUTTON_COMMAND_ID_P (command.commandID))
5160 SetWRefCon (window, command.commandID);
5161 quit_dialog_event_loop = 1;
5162 break;
5165 result = CallNextEventHandler (next_handler, event);
5167 break;
5169 case kEventClassKeyboard:
5171 OSStatus result;
5172 char char_code;
5174 result = CallNextEventHandler (next_handler, event);
5175 if (result != eventNotHandledErr)
5176 break;
5178 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
5179 typeChar, NULL, sizeof (char),
5180 NULL, &char_code);
5181 if (err == noErr)
5182 switch (char_code)
5184 case kEscapeCharCode:
5185 quit_dialog_event_loop = 1;
5186 break;
5188 default:
5190 UInt32 modifiers, key_code;
5192 err = GetEventParameter (event, kEventParamKeyModifiers,
5193 typeUInt32, NULL, sizeof (UInt32),
5194 NULL, &modifiers);
5195 if (err == noErr)
5196 err = GetEventParameter (event, kEventParamKeyCode,
5197 typeUInt32, NULL, sizeof (UInt32),
5198 NULL, &key_code);
5199 if (err == noErr)
5200 if (mac_quit_char_key_p (modifiers, key_code))
5201 quit_dialog_event_loop = 1;
5203 break;
5206 break;
5208 default:
5209 abort ();
5212 if (quit_dialog_event_loop)
5214 err = QuitEventLoop (GetCurrentEventLoop ());
5215 if (err == noErr)
5216 result = noErr;
5219 return result;
5222 static OSStatus
5223 install_dialog_event_handler (window)
5224 WindowRef window;
5226 static const EventTypeSpec specs[] =
5227 {{kEventClassCommand, kEventCommandProcess},
5228 {kEventClassKeyboard, kEventRawKeyDown}};
5229 static EventHandlerUPP handle_dialog_eventUPP = NULL;
5231 if (handle_dialog_eventUPP == NULL)
5232 handle_dialog_eventUPP = NewEventHandlerUPP (mac_handle_dialog_event);
5233 return InstallWindowEventHandler (window, handle_dialog_eventUPP,
5234 GetEventTypeCount (specs), specs,
5235 window, NULL);
5238 static Lisp_Object
5239 pop_down_dialog (arg)
5240 Lisp_Object arg;
5242 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
5243 WindowRef window = p->pointer;
5245 BLOCK_INPUT;
5247 if (popup_activated_flag)
5248 EndAppModalStateForWindow (window);
5249 DisposeWindow (window);
5250 popup_activated_flag = 0;
5252 UNBLOCK_INPUT;
5254 return Qnil;
5257 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
5258 dialog pops down.
5259 menu_item_selection will be set to the selection. */
5261 void
5262 create_and_show_dialog (f, first_wv)
5263 FRAME_PTR f;
5264 widget_value *first_wv;
5266 OSStatus err;
5267 char *dialog_name, *message;
5268 int nb_buttons, first_group_count, i, result = 0;
5269 widget_value *wv;
5270 short buttons_height, text_height, inner_width, inner_height;
5271 Rect empty_rect, *rects;
5272 WindowRef window = NULL;
5273 ControlRef *buttons, default_button = NULL, text;
5274 int specpdl_count = SPECPDL_INDEX ();
5276 dialog_name = first_wv->name;
5277 nb_buttons = dialog_name[1] - '0';
5278 first_group_count = nb_buttons - (dialog_name[4] - '0');
5280 wv = first_wv->contents;
5281 message = wv->value;
5283 wv = wv->next;
5284 SetRect (&empty_rect, 0, 0, 0, 0);
5286 /* Create dialog window. */
5287 err = CreateNewWindow (kMovableModalWindowClass,
5288 kWindowStandardHandlerAttribute,
5289 &empty_rect, &window);
5290 if (err == noErr)
5292 record_unwind_protect (pop_down_dialog, make_save_value (window, 0));
5293 err = SetThemeWindowBackground (window, kThemeBrushMovableModalBackground,
5294 true);
5296 if (err == noErr)
5297 err = SetWindowTitleWithCFString (window, (dialog_name[0] == 'Q'
5298 ? CFSTR ("Question")
5299 : CFSTR ("Information")));
5301 /* Create button controls and measure their optimal bounds. */
5302 if (err == noErr)
5304 buttons = alloca (sizeof (ControlRef) * nb_buttons);
5305 rects = alloca (sizeof (Rect) * nb_buttons);
5306 for (i = 0; i < nb_buttons; i++)
5308 CFStringRef label = cfstring_create_with_utf8_cstring (wv->value);
5310 if (label == NULL)
5311 err = memFullErr;
5312 else
5314 err = CreatePushButtonControl (window, &empty_rect,
5315 label, &buttons[i]);
5316 CFRelease (label);
5318 if (err == noErr)
5320 if (!wv->enabled)
5322 #ifdef MAC_OSX
5323 err = DisableControl (buttons[i]);
5324 #else
5325 err = DeactivateControl (buttons[i]);
5326 #endif
5328 else if (default_button == NULL)
5329 default_button = buttons[i];
5331 if (err == noErr)
5333 SInt16 unused;
5335 rects[i] = empty_rect;
5336 err = GetBestControlRect (buttons[i], &rects[i], &unused);
5338 if (err == noErr)
5340 UInt32 command_id;
5342 OffsetRect (&rects[i], -rects[i].left, -rects[i].top);
5343 if (rects[i].right < DIALOG_BUTTON_MIN_WIDTH)
5344 rects[i].right = DIALOG_BUTTON_MIN_WIDTH;
5345 else if (rects[i].right > DIALOG_MAX_INNER_WIDTH)
5346 rects[i].right = DIALOG_MAX_INNER_WIDTH;
5348 command_id = DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv->call_data);
5349 err = SetControlCommandID (buttons[i], command_id);
5351 if (err != noErr)
5352 break;
5353 wv = wv->next;
5357 /* Layout buttons. rects[i] is set relative to the bottom-right
5358 corner of the inner box. */
5359 if (err == noErr)
5361 short bottom, right, max_height, left_align_shift;
5363 inner_width = DIALOG_MIN_INNER_WIDTH;
5364 bottom = right = max_height = 0;
5365 for (i = 0; i < nb_buttons; i++)
5367 if (right - rects[i].right < - inner_width)
5369 if (i != first_group_count
5370 && right - rects[i].right >= - DIALOG_MAX_INNER_WIDTH)
5371 inner_width = - (right - rects[i].right);
5372 else
5374 bottom -= max_height + DIALOG_BUTTON_BUTTON_VERTICAL_SPACE;
5375 right = max_height = 0;
5378 if (max_height < rects[i].bottom)
5379 max_height = rects[i].bottom;
5380 OffsetRect (&rects[i], right - rects[i].right,
5381 bottom - rects[i].bottom);
5382 right = rects[i].left - DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
5383 if (i == first_group_count - 1)
5384 right -= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
5386 buttons_height = - (bottom - max_height);
5388 left_align_shift = - (inner_width + rects[nb_buttons - 1].left);
5389 for (i = nb_buttons - 1; i >= first_group_count; i--)
5391 if (bottom != rects[i].bottom)
5393 left_align_shift = - (inner_width + rects[i].left);
5394 bottom = rects[i].bottom;
5396 OffsetRect (&rects[i], left_align_shift, 0);
5400 /* Create a static text control and measure its bounds. */
5401 if (err == noErr)
5403 CFStringRef message_string;
5404 Rect bounds;
5406 message_string = cfstring_create_with_utf8_cstring (message);
5407 if (message_string == NULL)
5408 err = memFullErr;
5409 else
5411 ControlFontStyleRec text_style;
5413 text_style.flags = 0;
5414 SetRect (&bounds, 0, 0, inner_width, 0);
5415 err = CreateStaticTextControl (window, &bounds, message_string,
5416 &text_style, &text);
5417 CFRelease (message_string);
5419 if (err == noErr)
5421 SInt16 unused;
5423 bounds = empty_rect;
5424 err = GetBestControlRect (text, &bounds, &unused);
5426 if (err == noErr)
5428 text_height = bounds.bottom - bounds.top;
5429 if (text_height < DIALOG_TEXT_MIN_HEIGHT)
5430 text_height = DIALOG_TEXT_MIN_HEIGHT;
5434 /* Place buttons. */
5435 if (err == noErr)
5437 inner_height = (text_height + DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
5438 + buttons_height);
5440 for (i = 0; i < nb_buttons; i++)
5442 OffsetRect (&rects[i], DIALOG_LEFT_MARGIN + inner_width,
5443 DIALOG_TOP_MARGIN + inner_height);
5444 SetControlBounds (buttons[i], &rects[i]);
5448 /* Place text. */
5449 if (err == noErr)
5451 Rect bounds;
5453 SetRect (&bounds, DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN,
5454 DIALOG_LEFT_MARGIN + inner_width,
5455 DIALOG_TOP_MARGIN + text_height);
5456 SetControlBounds (text, &bounds);
5459 /* Create the application icon at the upper-left corner. */
5460 if (err == noErr)
5462 ControlButtonContentInfo content;
5463 ControlRef icon;
5464 static const ProcessSerialNumber psn = {0, kCurrentProcess};
5465 #ifdef MAC_OSX
5466 FSRef app_location;
5467 #else
5468 ProcessInfoRec pinfo;
5469 FSSpec app_spec;
5470 #endif
5471 SInt16 unused;
5473 content.contentType = kControlContentIconRef;
5474 #ifdef MAC_OSX
5475 err = GetProcessBundleLocation (&psn, &app_location);
5476 if (err == noErr)
5477 err = GetIconRefFromFileInfo (&app_location, 0, NULL, 0, NULL,
5478 kIconServicesNormalUsageFlag,
5479 &content.u.iconRef, &unused);
5480 #else
5481 bzero (&pinfo, sizeof (ProcessInfoRec));
5482 pinfo.processInfoLength = sizeof (ProcessInfoRec);
5483 pinfo.processAppSpec = &app_spec;
5484 err = GetProcessInformation (&psn, &pinfo);
5485 if (err == noErr)
5486 err = GetIconRefFromFile (&app_spec, &content.u.iconRef, &unused);
5487 #endif
5488 if (err == noErr)
5490 Rect bounds;
5492 SetRect (&bounds, DIALOG_ICON_LEFT_MARGIN, DIALOG_ICON_TOP_MARGIN,
5493 DIALOG_ICON_LEFT_MARGIN + DIALOG_ICON_WIDTH,
5494 DIALOG_ICON_TOP_MARGIN + DIALOG_ICON_HEIGHT);
5495 err = CreateIconControl (window, &bounds, &content, true, &icon);
5496 ReleaseIconRef (content.u.iconRef);
5500 /* Show the dialog window and run event loop. */
5501 if (err == noErr)
5502 if (default_button)
5503 err = SetWindowDefaultButton (window, default_button);
5504 if (err == noErr)
5505 err = install_dialog_event_handler (window);
5506 if (err == noErr)
5508 SizeWindow (window,
5509 DIALOG_LEFT_MARGIN + inner_width + DIALOG_RIGHT_MARGIN,
5510 DIALOG_TOP_MARGIN + inner_height + DIALOG_BOTTOM_MARGIN,
5511 true);
5512 err = RepositionWindow (window, FRAME_MAC_WINDOW (f),
5513 kWindowAlertPositionOnParentWindow);
5515 if (err == noErr)
5517 SetWRefCon (window, 0);
5518 ShowWindow (window);
5519 BringToFront (window);
5520 popup_activated_flag = 1;
5521 err = BeginAppModalStateForWindow (window);
5523 if (err == noErr)
5525 EventTargetRef toolbox_dispatcher = GetEventDispatcherTarget ();
5527 quit_dialog_event_loop = 0;
5528 while (1)
5530 EMACS_TIME next_time = timer_check (1);
5531 long secs = EMACS_SECS (next_time);
5532 long usecs = EMACS_USECS (next_time);
5533 EventTimeout timeout;
5534 EventRef event;
5536 if (secs < 0 || (secs == 0 && usecs == 0))
5538 /* Sometimes timer_check returns -1 (no timers) even if
5539 there are timers. So do a timeout anyway. */
5540 secs = 1;
5541 usecs = 0;
5544 timeout = (secs * kEventDurationSecond
5545 + usecs * kEventDurationMicrosecond);
5546 err = ReceiveNextEvent (0, NULL, timeout, kEventRemoveFromQueue,
5547 &event);
5548 if (err == noErr)
5550 SendEventToEventTarget (event, toolbox_dispatcher);
5551 ReleaseEvent (event);
5553 #if 0 /* defined (MAC_OSX) */
5554 else if (err != eventLoopTimedOutErr)
5556 if (err == eventLoopQuitErr)
5557 err = noErr;
5558 break;
5560 #else
5561 /* The return value of ReceiveNextEvent seems to be
5562 unreliable. Use our own global variable instead. */
5563 if (quit_dialog_event_loop)
5565 err = noErr;
5566 break;
5568 #endif
5571 if (err == noErr)
5573 UInt32 command_id = GetWRefCon (window);
5575 if (DIALOG_BUTTON_COMMAND_ID_P (command_id))
5576 result = DIALOG_BUTTON_COMMAND_ID_VALUE (command_id);
5579 unbind_to (specpdl_count, Qnil);
5581 menu_item_selection = result;
5583 #else /* not TARGET_API_MAC_CARBON */
5584 #define DIALOG_WINDOW_RESOURCE 130
5587 mac_dialog (widget_value *wv)
5589 char *dialog_name;
5590 char *prompt;
5591 char **button_labels;
5592 UInt32 *ref_cons;
5593 int nb_buttons;
5594 int left_count;
5595 int i;
5596 int dialog_width;
5597 Rect rect;
5598 WindowRef window_ptr;
5599 ControlRef ch;
5600 int left;
5601 EventRecord event_record;
5602 SInt16 part_code;
5603 int control_part_code;
5604 Point mouse;
5606 dialog_name = wv->name;
5607 nb_buttons = dialog_name[1] - '0';
5608 left_count = nb_buttons - (dialog_name[4] - '0');
5609 button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
5610 ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons);
5612 wv = wv->contents;
5613 prompt = (char *) alloca (strlen (wv->value) + 1);
5614 strcpy (prompt, wv->value);
5615 c2pstr (prompt);
5617 wv = wv->next;
5618 for (i = 0; i < nb_buttons; i++)
5620 button_labels[i] = wv->value;
5621 button_labels[i] = (char *) alloca (strlen (wv->value) + 1);
5622 strcpy (button_labels[i], wv->value);
5623 c2pstr (button_labels[i]);
5624 ref_cons[i] = (UInt32) wv->call_data;
5625 wv = wv->next;
5628 window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowRef) -1);
5630 SetPortWindowPort (window_ptr);
5632 TextFont (0);
5633 /* Left and right margins in the dialog are 13 pixels each.*/
5634 dialog_width = 14;
5635 /* Calculate width of dialog box: 8 pixels on each side of the text
5636 label in each button, 12 pixels between buttons. */
5637 for (i = 0; i < nb_buttons; i++)
5638 dialog_width += StringWidth (button_labels[i]) + 16 + 12;
5640 if (left_count != 0 && nb_buttons - left_count != 0)
5641 dialog_width += 12;
5643 dialog_width = max (dialog_width, StringWidth (prompt) + 26);
5645 SizeWindow (window_ptr, dialog_width, 78, 0);
5646 ShowWindow (window_ptr);
5648 SetPortWindowPort (window_ptr);
5650 TextFont (0);
5652 MoveTo (13, 29);
5653 DrawString (prompt);
5655 left = 13;
5656 for (i = 0; i < nb_buttons; i++)
5658 int button_width = StringWidth (button_labels[i]) + 16;
5659 SetRect (&rect, left, 45, left + button_width, 65);
5660 ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0,
5661 kControlPushButtonProc, ref_cons[i]);
5662 left += button_width + 12;
5663 if (i == left_count - 1)
5664 left += 12;
5667 i = 0;
5668 while (!i)
5670 if (WaitNextEvent (mDownMask, &event_record, 10, NULL))
5671 if (event_record.what == mouseDown)
5673 part_code = FindWindow (event_record.where, &window_ptr);
5674 if (part_code == inContent)
5676 mouse = event_record.where;
5677 GlobalToLocal (&mouse);
5678 control_part_code = FindControl (mouse, window_ptr, &ch);
5679 if (control_part_code == kControlButtonPart)
5680 if (TrackControl (ch, mouse, NULL))
5681 i = GetControlReference (ch);
5686 DisposeWindow (window_ptr);
5688 return i;
5690 #endif /* not TARGET_API_MAC_CARBON */
5693 /***********************************************************************
5694 Selection support
5695 ***********************************************************************/
5697 #if !TARGET_API_MAC_CARBON
5698 #include <Scrap.h>
5699 #include <Endian.h>
5700 #endif
5702 extern Lisp_Object Vselection_converter_alist;
5703 extern Lisp_Object Qmac_scrap_name, Qmac_ostype;
5705 static ScrapFlavorType get_flavor_type_from_symbol P_ ((Lisp_Object,
5706 Selection));
5708 /* Get a reference to the selection corresponding to the symbol SYM.
5709 The reference is set to *SEL, and it becomes NULL if there's no
5710 corresponding selection. Clear the selection if CLEAR_P is
5711 non-zero. */
5713 OSStatus
5714 mac_get_selection_from_symbol (sym, clear_p, sel)
5715 Lisp_Object sym;
5716 int clear_p;
5717 Selection *sel;
5719 OSStatus err = noErr;
5720 Lisp_Object str = Fget (sym, Qmac_scrap_name);
5722 if (!STRINGP (str))
5723 *sel = NULL;
5724 else
5726 #if TARGET_API_MAC_CARBON
5727 #ifdef MAC_OSX
5728 CFStringRef scrap_name = cfstring_create_with_string (str);
5729 OptionBits options = (clear_p ? kScrapClearNamedScrap
5730 : kScrapGetNamedScrap);
5732 err = GetScrapByName (scrap_name, options, sel);
5733 CFRelease (scrap_name);
5734 #else /* !MAC_OSX */
5735 if (clear_p)
5736 err = ClearCurrentScrap ();
5737 if (err == noErr)
5738 err = GetCurrentScrap (sel);
5739 #endif /* !MAC_OSX */
5740 #else /* !TARGET_API_MAC_CARBON */
5741 if (clear_p)
5742 err = ZeroScrap ();
5743 if (err == noErr)
5744 *sel = 1;
5745 #endif /* !TARGET_API_MAC_CARBON */
5748 return err;
5751 /* Get a scrap flavor type from the symbol SYM. Return 0 if no
5752 corresponding flavor type. If SEL is non-zero, the return value is
5753 non-zero only when the SEL has the flavor type. */
5755 static ScrapFlavorType
5756 get_flavor_type_from_symbol (sym, sel)
5757 Lisp_Object sym;
5758 Selection sel;
5760 Lisp_Object str = Fget (sym, Qmac_ostype);
5761 ScrapFlavorType flavor_type;
5763 if (STRINGP (str) && SBYTES (str) == 4)
5764 flavor_type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
5765 else
5766 flavor_type = 0;
5768 if (flavor_type && sel)
5770 #if TARGET_API_MAC_CARBON
5771 OSStatus err;
5772 ScrapFlavorFlags flags;
5774 err = GetScrapFlavorFlags (sel, flavor_type, &flags);
5775 if (err != noErr)
5776 flavor_type = 0;
5777 #else /* !TARGET_API_MAC_CARBON */
5778 SInt32 size, offset;
5780 size = GetScrap (NULL, flavor_type, &offset);
5781 if (size < 0)
5782 flavor_type = 0;
5783 #endif /* !TARGET_API_MAC_CARBON */
5786 return flavor_type;
5789 /* Check if the symbol SYM has a corresponding selection target type. */
5792 mac_valid_selection_target_p (sym)
5793 Lisp_Object sym;
5795 return get_flavor_type_from_symbol (sym, 0) != 0;
5798 /* Clear the selection whose reference is *SEL. */
5800 OSStatus
5801 mac_clear_selection (sel)
5802 Selection *sel;
5804 #if TARGET_API_MAC_CARBON
5805 #ifdef MAC_OSX
5806 return ClearScrap (sel);
5807 #else
5808 OSStatus err;
5810 err = ClearCurrentScrap ();
5811 if (err == noErr)
5812 err = GetCurrentScrap (sel);
5813 return err;
5814 #endif
5815 #else /* !TARGET_API_MAC_CARBON */
5816 return ZeroScrap ();
5817 #endif /* !TARGET_API_MAC_CARBON */
5820 /* Get ownership information for SEL. Emacs can detect a change of
5821 the ownership by comparing saved and current values of the
5822 ownership information. */
5824 Lisp_Object
5825 mac_get_selection_ownership_info (sel)
5826 Selection sel;
5828 #if TARGET_API_MAC_CARBON
5829 return long_to_cons ((unsigned long) sel);
5830 #else /* !TARGET_API_MAC_CARBON */
5831 ScrapStuffPtr scrap_info = InfoScrap ();
5833 return make_number (scrap_info->scrapCount);
5834 #endif /* !TARGET_API_MAC_CARBON */
5837 /* Return non-zero if VALUE is a valid selection value for TARGET. */
5840 mac_valid_selection_value_p (value, target)
5841 Lisp_Object value, target;
5843 return STRINGP (value);
5846 /* Put Lisp object VALUE to the selection SEL. The target type is
5847 specified by TARGET. */
5849 OSStatus
5850 mac_put_selection_value (sel, target, value)
5851 Selection sel;
5852 Lisp_Object target, value;
5854 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, 0);
5856 if (flavor_type == 0 || !STRINGP (value))
5857 return noTypeErr;
5859 #if TARGET_API_MAC_CARBON
5860 return PutScrapFlavor (sel, flavor_type, kScrapFlavorMaskNone,
5861 SBYTES (value), SDATA (value));
5862 #else /* !TARGET_API_MAC_CARBON */
5863 return PutScrap (SBYTES (value), flavor_type, SDATA (value));
5864 #endif /* !TARGET_API_MAC_CARBON */
5867 /* Check if data for the target type TARGET is available in SEL. */
5870 mac_selection_has_target_p (sel, target)
5871 Selection sel;
5872 Lisp_Object target;
5874 return get_flavor_type_from_symbol (target, sel) != 0;
5877 /* Get data for the target type TARGET from SEL and create a Lisp
5878 string. Return nil if failed to get data. */
5880 Lisp_Object
5881 mac_get_selection_value (sel, target)
5882 Selection sel;
5883 Lisp_Object target;
5885 OSStatus err;
5886 Lisp_Object result = Qnil;
5887 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, sel);
5888 #if TARGET_API_MAC_CARBON
5889 Size size;
5891 if (flavor_type)
5893 err = GetScrapFlavorSize (sel, flavor_type, &size);
5894 if (err == noErr)
5898 result = make_uninit_string (size);
5899 err = GetScrapFlavorData (sel, flavor_type,
5900 &size, SDATA (result));
5901 if (err != noErr)
5902 result = Qnil;
5903 else if (size < SBYTES (result))
5904 result = make_unibyte_string (SDATA (result), size);
5906 while (STRINGP (result) && size > SBYTES (result));
5909 #else
5910 Handle handle;
5911 SInt32 size, offset;
5913 if (flavor_type)
5914 size = GetScrap (NULL, flavor_type, &offset);
5915 if (size >= 0)
5917 handle = NewHandle (size);
5918 HLock (handle);
5919 size = GetScrap (handle, flavor_type, &offset);
5920 if (size >= 0)
5921 result = make_unibyte_string (*handle, size);
5922 DisposeHandle (handle);
5924 #endif
5926 return result;
5929 /* Get the list of target types in SEL. The return value is a list of
5930 target type symbols possibly followed by scrap flavor type
5931 strings. */
5933 Lisp_Object
5934 mac_get_selection_target_list (sel)
5935 Selection sel;
5937 Lisp_Object result = Qnil, rest, target;
5938 #if TARGET_API_MAC_CARBON
5939 OSStatus err;
5940 UInt32 count, i, type;
5941 ScrapFlavorInfo *flavor_info = NULL;
5942 Lisp_Object strings = Qnil;
5944 err = GetScrapFlavorCount (sel, &count);
5945 if (err == noErr)
5946 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
5947 err = GetScrapFlavorInfoList (sel, &count, flavor_info);
5948 if (err != noErr)
5950 xfree (flavor_info);
5951 flavor_info = NULL;
5953 if (flavor_info == NULL)
5954 count = 0;
5955 #endif
5956 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
5958 ScrapFlavorType flavor_type = 0;
5960 if (CONSP (XCAR (rest))
5961 && (target = XCAR (XCAR (rest)),
5962 SYMBOLP (target))
5963 && (flavor_type = get_flavor_type_from_symbol (target, sel)))
5965 result = Fcons (target, result);
5966 #if TARGET_API_MAC_CARBON
5967 for (i = 0; i < count; i++)
5968 if (flavor_info[i].flavorType == flavor_type)
5970 flavor_info[i].flavorType = 0;
5971 break;
5973 #endif
5976 #if TARGET_API_MAC_CARBON
5977 if (flavor_info)
5979 for (i = 0; i < count; i++)
5980 if (flavor_info[i].flavorType)
5982 type = EndianU32_NtoB (flavor_info[i].flavorType);
5983 strings = Fcons (make_unibyte_string ((char *) &type, 4), strings);
5985 result = nconc2 (result, strings);
5986 xfree (flavor_info);
5988 #endif
5990 return result;
5994 /***********************************************************************
5995 Apple event support
5996 ***********************************************************************/
5998 extern pascal OSErr mac_handle_apple_event P_ ((const AppleEvent *,
5999 AppleEvent *, SInt32));
6000 extern void cleanup_all_suspended_apple_events P_ ((void));
6002 void
6003 init_apple_event_handler ()
6005 OSErr err;
6006 long result;
6008 /* Make sure we have Apple events before starting. */
6009 err = Gestalt (gestaltAppleEventsAttr, &result);
6010 if (err != noErr)
6011 abort ();
6013 if (!(result & (1 << gestaltAppleEventsPresent)))
6014 abort ();
6016 err = AEInstallEventHandler (typeWildCard, typeWildCard,
6017 #if TARGET_API_MAC_CARBON
6018 NewAEEventHandlerUPP (mac_handle_apple_event),
6019 #else
6020 NewAEEventHandlerProc (mac_handle_apple_event),
6021 #endif
6022 0L, false);
6023 if (err != noErr)
6024 abort ();
6026 atexit (cleanup_all_suspended_apple_events);
6030 /***********************************************************************
6031 Drag and drop support
6032 ***********************************************************************/
6034 #if TARGET_API_MAC_CARBON
6035 extern Lisp_Object Vmac_dnd_known_types;
6037 static pascal OSErr mac_do_track_drag P_ ((DragTrackingMessage, WindowRef,
6038 void *, DragRef));
6039 static pascal OSErr mac_do_receive_drag P_ ((WindowRef, void *, DragRef));
6040 static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL;
6041 static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL;
6043 static OSErr
6044 create_apple_event_from_drag_ref (drag, num_types, types, result)
6045 DragRef drag;
6046 UInt32 num_types;
6047 const FlavorType *types;
6048 AppleEvent *result;
6050 OSErr err;
6051 UInt16 num_items;
6052 AppleEvent items;
6053 long index;
6054 char *buf = NULL;
6056 err = CountDragItems (drag, &num_items);
6057 if (err != noErr)
6058 return err;
6059 err = AECreateList (NULL, 0, false, &items);
6060 if (err != noErr)
6061 return err;
6063 for (index = 1; index <= num_items; index++)
6065 ItemReference item;
6066 DescType desc_type = typeNull;
6067 Size size;
6069 err = GetDragItemReferenceNumber (drag, index, &item);
6070 if (err == noErr)
6072 int i;
6074 for (i = 0; i < num_types; i++)
6076 err = GetFlavorDataSize (drag, item, types[i], &size);
6077 if (err == noErr)
6079 buf = xrealloc (buf, size);
6080 err = GetFlavorData (drag, item, types[i], buf, &size, 0);
6082 if (err == noErr)
6084 desc_type = types[i];
6085 break;
6089 err = AEPutPtr (&items, index, desc_type,
6090 desc_type != typeNull ? buf : NULL,
6091 desc_type != typeNull ? size : 0);
6092 if (err != noErr)
6093 break;
6095 xfree (buf);
6097 if (err == noErr)
6099 err = create_apple_event (0, 0, result); /* Dummy class and ID. */
6100 if (err == noErr)
6101 err = AEPutParamDesc (result, keyDirectObject, &items);
6102 if (err != noErr)
6103 AEDisposeDesc (result);
6106 AEDisposeDesc (&items);
6108 return err;
6111 static void
6112 mac_store_drag_event (window, mouse_pos, modifiers, desc)
6113 WindowRef window;
6114 Point mouse_pos;
6115 SInt16 modifiers;
6116 const AEDesc *desc;
6118 struct input_event buf;
6120 EVENT_INIT (buf);
6122 buf.kind = DRAG_N_DROP_EVENT;
6123 buf.modifiers = mac_to_emacs_modifiers (modifiers, 0);
6124 buf.timestamp = TickCount () * (1000 / 60);
6125 XSETINT (buf.x, mouse_pos.h);
6126 XSETINT (buf.y, mouse_pos.v);
6127 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
6128 buf.arg = mac_aedesc_to_lisp (desc);
6129 kbd_buffer_store_event (&buf);
6132 static pascal OSErr
6133 mac_do_track_drag (message, window, refcon, drag)
6134 DragTrackingMessage message;
6135 WindowRef window;
6136 void *refcon;
6137 DragRef drag;
6139 OSErr err = noErr;
6140 static int can_accept;
6141 UInt16 num_items, index;
6143 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
6144 return dragNotAcceptedErr;
6146 switch (message)
6148 case kDragTrackingEnterHandler:
6149 err = CountDragItems (drag, &num_items);
6150 if (err != noErr)
6151 break;
6152 can_accept = 0;
6153 for (index = 1; index <= num_items; index++)
6155 ItemReference item;
6156 FlavorFlags flags;
6157 Lisp_Object rest;
6159 err = GetDragItemReferenceNumber (drag, index, &item);
6160 if (err != noErr)
6161 continue;
6162 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
6164 Lisp_Object str;
6165 FlavorType type;
6167 str = XCAR (rest);
6168 if (!(STRINGP (str) && SBYTES (str) == 4))
6169 continue;
6170 type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
6172 err = GetFlavorFlags (drag, item, type, &flags);
6173 if (err == noErr)
6175 can_accept = 1;
6176 break;
6180 break;
6182 case kDragTrackingEnterWindow:
6183 if (can_accept)
6185 RgnHandle hilite_rgn = NewRgn ();
6187 if (hilite_rgn)
6189 Rect r;
6191 GetWindowPortBounds (window, &r);
6192 OffsetRect (&r, -r.left, -r.top);
6193 RectRgn (hilite_rgn, &r);
6194 ShowDragHilite (drag, hilite_rgn, true);
6195 DisposeRgn (hilite_rgn);
6197 SetThemeCursor (kThemeCopyArrowCursor);
6199 break;
6201 case kDragTrackingInWindow:
6202 break;
6204 case kDragTrackingLeaveWindow:
6205 if (can_accept)
6207 HideDragHilite (drag);
6208 SetThemeCursor (kThemeArrowCursor);
6210 break;
6212 case kDragTrackingLeaveHandler:
6213 break;
6216 if (err != noErr)
6217 return dragNotAcceptedErr;
6218 return noErr;
6221 static pascal OSErr
6222 mac_do_receive_drag (window, refcon, drag)
6223 WindowRef window;
6224 void *refcon;
6225 DragRef drag;
6227 OSErr err;
6228 int num_types, i;
6229 Lisp_Object rest, str;
6230 FlavorType *types;
6231 AppleEvent apple_event;
6232 Point mouse_pos;
6233 SInt16 modifiers;
6235 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
6236 return dragNotAcceptedErr;
6238 num_types = 0;
6239 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
6241 str = XCAR (rest);
6242 if (STRINGP (str) && SBYTES (str) == 4)
6243 num_types++;
6246 types = xmalloc (sizeof (FlavorType) * num_types);
6247 i = 0;
6248 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
6250 str = XCAR (rest);
6251 if (STRINGP (str) && SBYTES (str) == 4)
6252 types[i++] = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
6255 err = create_apple_event_from_drag_ref (drag, num_types, types,
6256 &apple_event);
6257 xfree (types);
6259 if (err == noErr)
6260 err = GetDragMouse (drag, &mouse_pos, NULL);
6261 if (err == noErr)
6263 GlobalToLocal (&mouse_pos);
6264 err = GetDragModifiers (drag, NULL, NULL, &modifiers);
6266 if (err == noErr)
6268 UInt32 key_modifiers = modifiers;
6270 err = AEPutParamPtr (&apple_event, kEventParamKeyModifiers,
6271 typeUInt32, &key_modifiers, sizeof (UInt32));
6274 if (err == noErr)
6276 mac_store_drag_event (window, mouse_pos, 0, &apple_event);
6277 AEDisposeDesc (&apple_event);
6278 mac_wakeup_from_rne ();
6279 return noErr;
6281 else
6282 return dragNotAcceptedErr;
6284 #endif /* TARGET_API_MAC_CARBON */
6286 static OSErr
6287 install_drag_handler (window)
6288 WindowRef window;
6290 OSErr err = noErr;
6292 #if TARGET_API_MAC_CARBON
6293 if (mac_do_track_dragUPP == NULL)
6294 mac_do_track_dragUPP = NewDragTrackingHandlerUPP (mac_do_track_drag);
6295 if (mac_do_receive_dragUPP == NULL)
6296 mac_do_receive_dragUPP = NewDragReceiveHandlerUPP (mac_do_receive_drag);
6298 err = InstallTrackingHandler (mac_do_track_dragUPP, window, NULL);
6299 if (err == noErr)
6300 err = InstallReceiveHandler (mac_do_receive_dragUPP, window, NULL);
6301 #endif
6303 return err;
6306 static void
6307 remove_drag_handler (window)
6308 WindowRef window;
6310 #if TARGET_API_MAC_CARBON
6311 if (mac_do_track_dragUPP)
6312 RemoveTrackingHandler (mac_do_track_dragUPP, window);
6313 if (mac_do_receive_dragUPP)
6314 RemoveReceiveHandler (mac_do_receive_dragUPP, window);
6315 #endif
6318 #if TARGET_API_MAC_CARBON
6319 /* Return default value for mac-dnd-known-types. */
6321 Lisp_Object
6322 mac_dnd_default_known_types ()
6324 Lisp_Object result = list4 (build_string ("hfs "), build_string ("utxt"),
6325 build_string ("TEXT"), build_string ("TIFF"));
6327 #ifdef MAC_OSX
6328 result = Fcons (build_string ("furl"), result);
6329 #endif
6331 return result;
6333 #endif
6336 /***********************************************************************
6337 Services menu support
6338 ***********************************************************************/
6340 #ifdef MAC_OSX
6341 extern Lisp_Object Qservice, Qpaste, Qperform;
6342 extern Lisp_Object Vmac_service_selection;
6344 static OSStatus
6345 mac_store_service_event (event)
6346 EventRef event;
6348 OSStatus err;
6349 Lisp_Object id_key;
6350 int num_params;
6351 const EventParamName *names;
6352 const EventParamType *types;
6353 static const EventParamName names_pfm[] =
6354 {kEventParamServiceMessageName, kEventParamServiceUserData};
6355 static const EventParamType types_pfm[] =
6356 {typeCFStringRef, typeCFStringRef};
6358 switch (GetEventKind (event))
6360 case kEventServicePaste:
6361 id_key = Qpaste;
6362 num_params = 0;
6363 names = NULL;
6364 types = NULL;
6365 break;
6367 case kEventServicePerform:
6368 id_key = Qperform;
6369 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
6370 names = names_pfm;
6371 types = types_pfm;
6372 break;
6374 default:
6375 abort ();
6378 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
6379 event, num_params,
6380 names, types);
6382 return err;
6385 static OSStatus
6386 copy_scrap_flavor_data (from_scrap, to_scrap, flavor_type)
6387 ScrapRef from_scrap, to_scrap;
6388 ScrapFlavorType flavor_type;
6390 OSStatus err;
6391 Size size, size_allocated;
6392 char *buf = NULL;
6394 err = GetScrapFlavorSize (from_scrap, flavor_type, &size);
6395 if (err == noErr)
6396 buf = xmalloc (size);
6397 while (buf)
6399 size_allocated = size;
6400 err = GetScrapFlavorData (from_scrap, flavor_type, &size, buf);
6401 if (err != noErr)
6403 xfree (buf);
6404 buf = NULL;
6406 else if (size_allocated < size)
6407 buf = xrealloc (buf, size);
6408 else
6409 break;
6411 if (err == noErr)
6413 if (buf == NULL)
6414 err = memFullErr;
6415 else
6417 err = PutScrapFlavor (to_scrap, flavor_type, kScrapFlavorMaskNone,
6418 size, buf);
6419 xfree (buf);
6423 return err;
6426 static OSStatus
6427 mac_handle_service_event (call_ref, event, data)
6428 EventHandlerCallRef call_ref;
6429 EventRef event;
6430 void *data;
6432 OSStatus err = noErr;
6433 ScrapRef cur_scrap, specific_scrap;
6434 UInt32 event_kind = GetEventKind (event);
6435 CFMutableArrayRef copy_types, paste_types;
6436 CFStringRef type;
6437 Lisp_Object rest;
6438 ScrapFlavorType flavor_type;
6440 /* Check if Vmac_service_selection is a valid selection that has a
6441 corresponding scrap. */
6442 if (!SYMBOLP (Vmac_service_selection))
6443 err = eventNotHandledErr;
6444 else
6445 err = mac_get_selection_from_symbol (Vmac_service_selection, 0, &cur_scrap);
6446 if (!(err == noErr && cur_scrap))
6447 return eventNotHandledErr;
6449 switch (event_kind)
6451 case kEventServiceGetTypes:
6452 /* Set paste types. */
6453 err = GetEventParameter (event, kEventParamServicePasteTypes,
6454 typeCFMutableArrayRef, NULL,
6455 sizeof (CFMutableArrayRef), NULL,
6456 &paste_types);
6457 if (err != noErr)
6458 break;
6460 for (rest = Vselection_converter_alist; CONSP (rest);
6461 rest = XCDR (rest))
6462 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
6463 && (flavor_type =
6464 get_flavor_type_from_symbol (XCAR (XCAR (rest)), 0)))
6466 type = CreateTypeStringWithOSType (flavor_type);
6467 if (type)
6469 CFArrayAppendValue (paste_types, type);
6470 CFRelease (type);
6474 /* Set copy types. */
6475 err = GetEventParameter (event, kEventParamServiceCopyTypes,
6476 typeCFMutableArrayRef, NULL,
6477 sizeof (CFMutableArrayRef), NULL,
6478 &copy_types);
6479 if (err != noErr)
6480 break;
6482 if (NILP (Fx_selection_owner_p (Vmac_service_selection)))
6483 break;
6484 else
6485 goto copy_all_flavors;
6487 case kEventServiceCopy:
6488 err = GetEventParameter (event, kEventParamScrapRef,
6489 typeScrapRef, NULL,
6490 sizeof (ScrapRef), NULL, &specific_scrap);
6491 if (err != noErr
6492 || NILP (Fx_selection_owner_p (Vmac_service_selection)))
6494 err = eventNotHandledErr;
6495 break;
6498 copy_all_flavors:
6500 UInt32 count, i;
6501 ScrapFlavorInfo *flavor_info = NULL;
6502 ScrapFlavorFlags flags;
6504 err = GetScrapFlavorCount (cur_scrap, &count);
6505 if (err == noErr)
6506 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
6507 err = GetScrapFlavorInfoList (cur_scrap, &count, flavor_info);
6508 if (err != noErr)
6510 xfree (flavor_info);
6511 flavor_info = NULL;
6513 if (flavor_info == NULL)
6514 break;
6516 for (i = 0; i < count; i++)
6518 flavor_type = flavor_info[i].flavorType;
6519 err = GetScrapFlavorFlags (cur_scrap, flavor_type, &flags);
6520 if (err == noErr && !(flags & kScrapFlavorMaskSenderOnly))
6522 if (event_kind == kEventServiceCopy)
6523 err = copy_scrap_flavor_data (cur_scrap, specific_scrap,
6524 flavor_type);
6525 else /* event_kind == kEventServiceGetTypes */
6527 type = CreateTypeStringWithOSType (flavor_type);
6528 if (type)
6530 CFArrayAppendValue (copy_types, type);
6531 CFRelease (type);
6536 xfree (flavor_info);
6538 break;
6540 case kEventServicePaste:
6541 case kEventServicePerform:
6543 int data_exists_p = 0;
6545 err = GetEventParameter (event, kEventParamScrapRef, typeScrapRef,
6546 NULL, sizeof (ScrapRef), NULL,
6547 &specific_scrap);
6548 if (err == noErr)
6549 err = mac_clear_selection (&cur_scrap);
6550 if (err == noErr)
6551 for (rest = Vselection_converter_alist; CONSP (rest);
6552 rest = XCDR (rest))
6554 if (! (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))))
6555 continue;
6556 flavor_type = get_flavor_type_from_symbol (XCAR (XCAR (rest)),
6557 specific_scrap);
6558 if (flavor_type == 0)
6559 continue;
6560 err = copy_scrap_flavor_data (specific_scrap, cur_scrap,
6561 flavor_type);
6562 if (err == noErr)
6563 data_exists_p = 1;
6565 if (!data_exists_p)
6566 err = eventNotHandledErr;
6567 else
6568 err = mac_store_service_event (event);
6570 break;
6573 if (err != noErr)
6574 err = eventNotHandledErr;
6575 return err;
6578 static OSStatus
6579 install_service_handler ()
6581 static const EventTypeSpec specs[] =
6582 {{kEventClassService, kEventServiceGetTypes},
6583 {kEventClassService, kEventServiceCopy},
6584 {kEventClassService, kEventServicePaste},
6585 {kEventClassService, kEventServicePerform}};
6587 return InstallApplicationEventHandler (NewEventHandlerUPP
6588 (mac_handle_service_event),
6589 GetEventTypeCount (specs),
6590 specs, NULL, NULL);
6592 #endif /* MAC_OSX */
6595 /***********************************************************************
6596 Initialization
6597 ***********************************************************************/
6599 void
6600 mac_toolbox_initialize ()
6602 any_help_event_p = 0;
6604 init_menu_bar ();
6606 #ifdef MAC_OSX
6607 init_apple_event_handler ();
6608 #endif
6609 #if USE_MAC_TSM
6610 init_tsm ();
6611 #endif
6614 /* arch-tag: 71a597a8-6e9f-47b0-8b89-5a5ae3e16516
6615 (do not change this comment) */