("cyrillic-translit"): Fix rules with
[emacs.git] / src / mactoolbox.c
bloba73578d520505cb61d82d0319bb9b981959de060
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 XFontStruct *font;
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 font = FACE_FROM_ID (f, glyph->face_id)->font;
602 if (font)
604 Fixed point_size = Long2Fix (font->mac_fontsize);
605 short height = row->visible_height;
606 short ascent = row->ascent;
608 SetEventParameter (event,
609 kEventParamTextInputReplyPointSize,
610 typeFixed, sizeof (Fixed), &point_size);
611 SetEventParameter (event,
612 kEventParamTextInputReplyLineHeight,
613 typeShortInteger, sizeof (short), &height);
614 SetEventParameter (event,
615 kEventParamTextInputReplyLineAscent,
616 typeShortInteger, sizeof (short), &ascent);
617 if (font->mac_fontnum != -1)
619 OSStatus err1;
620 FMFont fm_font;
621 FMFontStyle style;
623 err1 = FMGetFontFromFontFamilyInstance (font->mac_fontnum,
624 font->mac_fontface,
625 &fm_font, &style);
626 if (err1 == noErr)
627 SetEventParameter (event, kEventParamTextInputReplyFMFont,
628 typeUInt32, sizeof (UInt32), &fm_font);
629 else
631 long qd_font = font->mac_fontnum;
633 SetEventParameter (event, kEventParamTextInputReplyFont,
634 typeLongInteger, sizeof (long),
635 &qd_font);
638 else if (font->mac_style)
640 OSStatus err1;
641 ATSUFontID font_id;
643 err1 = ATSUGetAttribute (font->mac_style, kATSUFontTag,
644 sizeof (ATSUFontID), &font_id,
645 NULL);
646 if (err1 == noErr)
647 SetEventParameter (event, kEventParamTextInputReplyFMFont,
648 typeUInt32, sizeof (UInt32), &font_id);
650 else
651 abort ();
653 #endif /* MAC_OSX */
656 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
657 typeQDPoint, sizeof (Point), &p);
658 if (err == noErr)
659 result = noErr;
661 break;
663 #ifdef MAC_OSX
664 case kEventTextInputPosToOffset:
666 Point point;
667 Boolean leading_edge_p = true;
668 struct frame *f;
669 int x, y;
670 Lisp_Object window;
671 enum window_part part;
672 long region_class = kTSMOutsideOfBody, byte_offset = 0;
674 err = GetEventParameter (event, kEventParamTextInputSendCurrentPoint,
675 typeQDPoint, NULL, sizeof (Point), NULL,
676 &point);
677 if (err != noErr)
678 break;
680 GetEventParameter (event, kEventParamTextInputReplyLeadingEdge,
681 typeBoolean, NULL, sizeof (Boolean), NULL,
682 &leading_edge_p);
684 f = mac_focus_frame (&one_mac_display_info);
685 x = point.h - (f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
686 y = point.v - (f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
687 window = window_from_coordinates (f, x, y, &part, 0, 0, 1);
688 if (WINDOWP (window) && EQ (window, f->selected_window))
690 struct window *w;
691 struct buffer *b;
693 /* Convert to window-relative pixel coordinates. */
694 w = XWINDOW (window);
695 frame_to_window_pixel_xy (w, &x, &y);
697 /* Are we in a window whose display is up to date?
698 And verify the buffer's text has not changed. */
699 b = XBUFFER (w->buffer);
700 if (part == ON_TEXT
701 && EQ (w->window_end_valid, w->buffer)
702 && XINT (w->last_modified) == BUF_MODIFF (b)
703 && XINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
705 int hpos, vpos, area;
706 struct glyph *glyph;
708 /* Find the glyph under X/Y. */
709 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, 0, 0, &area);
711 if (glyph != NULL && area == TEXT_AREA)
713 byte_offset = ((glyph->charpos - BUF_BEGV (b))
714 * sizeof (UniChar));
715 region_class = kTSMInsideOfBody;
720 err = SetEventParameter (event, kEventParamTextInputReplyRegionClass,
721 typeLongInteger, sizeof (long),
722 &region_class);
723 if (err == noErr)
724 err = SetEventParameter (event, kEventParamTextInputReplyTextOffset,
725 typeLongInteger, sizeof (long),
726 &byte_offset);
727 if (err == noErr)
728 result = noErr;
730 break;
732 case kEventTextInputGetSelectedText:
734 struct frame *f = mac_focus_frame (&one_mac_display_info);
735 struct window *w = XWINDOW (f->selected_window);
736 struct buffer *b = XBUFFER (w->buffer);
737 CFRange sel_range;
738 int start, end;
739 UniChar *characters, c;
741 if (poll_suppress_count == 0 && !NILP (Vinhibit_quit))
742 /* Don't try to get buffer contents as the gap might be
743 being altered. */
744 break;
746 mac_get_selected_range (w, &sel_range);
747 if (sel_range.length == 0)
749 Boolean leading_edge_p;
751 err = GetEventParameter (event,
752 kEventParamTextInputReplyLeadingEdge,
753 typeBoolean, NULL, sizeof (Boolean), NULL,
754 &leading_edge_p);
755 if (err != noErr)
756 break;
758 start = BUF_BEGV (b) + sel_range.location;
759 if (!leading_edge_p)
760 start--;
761 end = start + 1;
762 characters = &c;
764 if (start < BUF_BEGV (b) || end > BUF_ZV (b))
765 break;
767 else
769 start = BUF_BEGV (b) + sel_range.location;
770 end = start + sel_range.length;
771 characters = xmalloc (sel_range.length * sizeof (UniChar));
774 if (mac_store_buffer_text_to_unicode_chars (b, start, end, characters))
775 err = SetEventParameter (event, kEventParamTextInputReplyText,
776 typeUnicodeText,
777 sel_range.length * sizeof (UniChar),
778 characters);
779 if (characters != &c)
780 xfree (characters);
782 if (err == noErr)
783 result = noErr;
785 break;
786 #endif /* MAC_OSX */
788 default:
789 abort ();
792 if (!NILP (id_key))
793 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
794 event, num_params,
795 names, types);
796 return result;
799 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
800 static pascal OSStatus
801 mac_handle_document_access_event (next_handler, event, data)
802 EventHandlerCallRef next_handler;
803 EventRef event;
804 void *data;
806 OSStatus err, result;
807 struct frame *f = mac_focus_frame (&one_mac_display_info);
809 result = CallNextEventHandler (next_handler, event);
810 if (result != eventNotHandledErr)
811 return result;
813 switch (GetEventKind (event))
815 case kEventTSMDocumentAccessGetLength:
817 CFIndex count = mac_ax_number_of_characters (f);
819 err = SetEventParameter (event, kEventParamTSMDocAccessCharacterCount,
820 typeCFIndex, sizeof (CFIndex), &count);
821 if (err == noErr)
822 result = noErr;
824 break;
826 case kEventTSMDocumentAccessGetSelectedRange:
828 CFRange sel_range;
830 mac_ax_selected_text_range (f, &sel_range);
831 err = SetEventParameter (event,
832 kEventParamTSMDocAccessReplyCharacterRange,
833 typeCFRange, sizeof (CFRange), &sel_range);
834 if (err == noErr)
835 result = noErr;
837 break;
839 case kEventTSMDocumentAccessGetCharacters:
841 struct buffer *b = XBUFFER (XWINDOW (f->selected_window)->buffer);
842 CFRange range;
843 Ptr characters;
844 int start, end;
846 if (poll_suppress_count == 0 && !NILP (Vinhibit_quit))
847 /* Don't try to get buffer contents as the gap might be
848 being altered. */
849 break;
851 err = GetEventParameter (event,
852 kEventParamTSMDocAccessSendCharacterRange,
853 typeCFRange, NULL, sizeof (CFRange), NULL,
854 &range);
855 if (err == noErr)
856 err = GetEventParameter (event,
857 kEventParamTSMDocAccessSendCharactersPtr,
858 typePtr, NULL, sizeof (Ptr), NULL,
859 &characters);
860 if (err != noErr)
861 break;
863 start = BUF_BEGV (b) + range.location;
864 end = start + range.length;
865 if (mac_store_buffer_text_to_unicode_chars (b, start, end,
866 (UniChar *) characters))
867 result = noErr;
869 break;
871 default:
872 abort ();
875 return result;
877 #endif
878 #endif
880 OSStatus
881 install_application_handler ()
883 OSStatus err = noErr;
885 if (err == noErr)
887 static const EventTypeSpec specs[] =
888 {{kEventClassKeyboard, kEventRawKeyDown},
889 {kEventClassKeyboard, kEventRawKeyRepeat},
890 {kEventClassKeyboard, kEventRawKeyUp}};
892 err = InstallApplicationEventHandler (NewEventHandlerUPP
893 (mac_handle_keyboard_event),
894 GetEventTypeCount (specs),
895 specs, NULL, NULL);
898 if (err == noErr)
900 static const EventTypeSpec specs[] =
901 {{kEventClassCommand, kEventCommandProcess}};
903 err = InstallApplicationEventHandler (NewEventHandlerUPP
904 (mac_handle_command_event),
905 GetEventTypeCount (specs),
906 specs, NULL, NULL);
909 if (err == noErr)
911 static const EventTypeSpec specs[] =
912 {{kEventClassMouse, kEventMouseWheelMoved}};
914 err = InstallApplicationEventHandler (NewEventHandlerUPP
915 (mac_handle_mouse_event),
916 GetEventTypeCount (specs),
917 specs, NULL, NULL);
920 #if USE_MAC_TSM
921 if (err == noErr)
923 static const EventTypeSpec specs[] =
924 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
925 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
926 {kEventClassTextInput, kEventTextInputOffsetToPos},
927 #ifdef MAC_OSX
928 {kEventClassTextInput, kEventTextInputPosToOffset},
929 {kEventClassTextInput, kEventTextInputGetSelectedText}
930 #endif
933 err = InstallApplicationEventHandler (NewEventHandlerUPP
934 (mac_handle_text_input_event),
935 GetEventTypeCount (specs),
936 specs, NULL, NULL);
939 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
940 if (err == noErr)
942 static const EventTypeSpec specs[] =
943 {{kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength},
944 {kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange},
945 {kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters}};
947 err = InstallApplicationEventHandler (mac_handle_document_access_event,
948 GetEventTypeCount (specs),
949 specs, NULL, NULL);
951 #endif
952 #endif
954 if (err == noErr)
955 err = install_menu_target_item_handler ();
957 #ifdef MAC_OSX
958 if (err == noErr)
959 err = install_service_handler ();
960 #endif
962 return err;
964 #endif /* TARGET_API_MAC_CARBON */
967 /************************************************************************
968 Windows
969 ************************************************************************/
971 #define DEFAULT_NUM_COLS 80
973 #define MIN_DOC_SIZE 64
974 #define MAX_DOC_SIZE 32767
976 /* Drag and Drop */
977 static OSErr install_drag_handler P_ ((WindowRef));
978 static void remove_drag_handler P_ ((WindowRef));
980 #if USE_CG_DRAWING
981 static void mac_prepare_for_quickdraw P_ ((struct frame *));
982 #endif
984 extern void mac_handle_visibility_change P_ ((struct frame *));
985 extern void mac_handle_origin_change P_ ((struct frame *));
986 extern void mac_handle_size_change P_ ((struct frame *, int, int));
988 #if TARGET_API_MAC_CARBON
989 #ifdef MAC_OSX
990 extern Lisp_Object Qwindow;
991 extern Lisp_Object Qtoolbar_switch_mode;
992 #endif
993 #endif
995 static void
996 do_window_update (WindowRef win)
998 struct frame *f = mac_window_to_frame (win);
1000 BeginUpdate (win);
1002 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
1003 below. */
1004 if (win != tip_window)
1006 if (f->async_visible == 0)
1008 /* Update events may occur when a frame gets iconified. */
1009 #if 0
1010 f->async_visible = 1;
1011 f->async_iconified = 0;
1012 SET_FRAME_GARBAGED (f);
1013 #endif
1015 else
1017 Rect r;
1018 #if TARGET_API_MAC_CARBON
1019 RgnHandle region = NewRgn ();
1021 GetPortVisibleRegion (GetWindowPort (win), region);
1022 GetRegionBounds (region, &r);
1023 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
1024 #if USE_CG_DRAWING
1025 mac_prepare_for_quickdraw (f);
1026 #endif
1027 UpdateControls (win, region);
1028 DisposeRgn (region);
1029 #else
1030 r = (*win->visRgn)->rgnBBox;
1031 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
1032 UpdateControls (win, win->visRgn);
1033 #endif
1037 EndUpdate (win);
1040 static int
1041 is_emacs_window (WindowRef win)
1043 Lisp_Object tail, frame;
1045 if (!win)
1046 return 0;
1048 FOR_EACH_FRAME (tail, frame)
1049 if (FRAME_MAC_P (XFRAME (frame)))
1050 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
1051 return 1;
1053 return 0;
1056 /* Handle drags in size box. Based on code contributed by Ben
1057 Mesander and IM - Window Manager A. */
1059 static void
1060 do_grow_window (w, e)
1061 WindowRef w;
1062 const EventRecord *e;
1064 Rect limit_rect;
1065 int rows, columns, width, height;
1066 struct frame *f = mac_window_to_frame (w);
1067 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
1068 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
1069 #if TARGET_API_MAC_CARBON
1070 Rect new_rect;
1071 #else
1072 long grow_size;
1073 #endif
1075 if (size_hints->flags & PMinSize)
1077 min_width = size_hints->min_width;
1078 min_height = size_hints->min_height;
1080 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
1082 #if TARGET_API_MAC_CARBON
1083 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
1084 return;
1085 height = new_rect.bottom - new_rect.top;
1086 width = new_rect.right - new_rect.left;
1087 #else
1088 grow_size = GrowWindow (w, e->where, &limit_rect);
1089 /* see if it really changed size */
1090 if (grow_size == 0)
1091 return;
1092 height = HiWord (grow_size);
1093 width = LoWord (grow_size);
1094 #endif
1096 if (width != FRAME_PIXEL_WIDTH (f)
1097 || height != FRAME_PIXEL_HEIGHT (f))
1099 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
1100 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
1102 x_set_window_size (f, 0, columns, rows);
1106 #if TARGET_API_MAC_CARBON
1107 static Point
1108 mac_get_ideal_size (f)
1109 struct frame *f;
1111 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
1112 WindowRef w = FRAME_MAC_WINDOW (f);
1113 Point ideal_size;
1114 Rect standard_rect;
1115 int height, width, columns, rows;
1117 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
1118 ideal_size.v = dpyinfo->height;
1119 IsWindowInStandardState (w, &ideal_size, &standard_rect);
1120 /* Adjust the standard size according to character boundaries. */
1121 width = standard_rect.right - standard_rect.left;
1122 height = standard_rect.bottom - standard_rect.top;
1123 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
1124 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
1125 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
1126 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1128 return ideal_size;
1131 static pascal OSStatus
1132 mac_handle_window_event (next_handler, event, data)
1133 EventHandlerCallRef next_handler;
1134 EventRef event;
1135 void *data;
1137 WindowRef wp;
1138 OSStatus err, result = eventNotHandledErr;
1139 struct frame *f;
1140 UInt32 attributes;
1141 XSizeHints *size_hints;
1143 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
1144 NULL, sizeof (WindowRef), NULL, &wp);
1145 if (err != noErr)
1146 return eventNotHandledErr;
1148 f = mac_window_to_frame (wp);
1149 switch (GetEventKind (event))
1151 /* -- window refresh events -- */
1153 case kEventWindowUpdate:
1154 result = CallNextEventHandler (next_handler, event);
1155 if (result != eventNotHandledErr)
1156 break;
1158 do_window_update (wp);
1159 result = noErr;
1160 break;
1162 /* -- window state change events -- */
1164 case kEventWindowShowing:
1165 size_hints = FRAME_SIZE_HINTS (f);
1166 if (!(size_hints->flags & (USPosition | PPosition)))
1168 struct frame *sf = SELECTED_FRAME ();
1170 if (!(FRAME_MAC_P (sf) && sf->async_visible))
1171 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
1172 else
1174 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
1175 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1176 kWindowCascadeStartAtParentWindowScreen
1177 #else
1178 kWindowCascadeOnParentWindowScreen
1179 #endif
1181 #if USE_MAC_TOOLBAR
1182 /* This is a workaround. RepositionWindow fails to put
1183 a window at the cascading position when its parent
1184 window has a Carbon HIToolbar. */
1185 if ((f->left_pos == sf->left_pos
1186 && f->top_pos == sf->top_pos)
1187 || (f->left_pos == sf->left_pos + 10 * 2
1188 && f->top_pos == sf->top_pos + 32 * 2))
1189 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
1190 #endif
1192 result = noErr;
1194 break;
1196 case kEventWindowHiding:
1197 /* Before unmapping the window, update the WM_SIZE_HINTS
1198 property to claim that the current position of the window is
1199 user-specified, rather than program-specified, so that when
1200 the window is mapped again, it will be placed at the same
1201 location, without forcing the user to position it by hand
1202 again (they have already done that once for this window.) */
1203 x_wm_set_size_hint (f, (long) 0, 1);
1204 result = noErr;
1205 break;
1207 case kEventWindowShown:
1208 case kEventWindowHidden:
1209 case kEventWindowCollapsed:
1210 case kEventWindowExpanded:
1211 mac_handle_visibility_change (f);
1212 result = noErr;
1213 break;
1215 case kEventWindowBoundsChanging:
1216 result = CallNextEventHandler (next_handler, event);
1217 if (result != eventNotHandledErr)
1218 break;
1220 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
1221 NULL, sizeof (UInt32), NULL, &attributes);
1222 if (err != noErr)
1223 break;
1225 size_hints = FRAME_SIZE_HINTS (f);
1226 if ((attributes & kWindowBoundsChangeUserResize)
1227 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
1228 == (PResizeInc | PBaseSize | PMinSize)))
1230 Rect bounds;
1231 int width, height;
1233 err = GetEventParameter (event, kEventParamCurrentBounds,
1234 typeQDRectangle, NULL, sizeof (Rect),
1235 NULL, &bounds);
1236 if (err != noErr)
1237 break;
1239 width = bounds.right - bounds.left;
1240 height = bounds.bottom - bounds.top;
1242 if (width < size_hints->min_width)
1243 width = size_hints->min_width;
1244 else
1245 width = size_hints->base_width
1246 + (int) ((width - size_hints->base_width)
1247 / (float) size_hints->width_inc + .5)
1248 * size_hints->width_inc;
1250 if (height < size_hints->min_height)
1251 height = size_hints->min_height;
1252 else
1253 height = size_hints->base_height
1254 + (int) ((height - size_hints->base_height)
1255 / (float) size_hints->height_inc + .5)
1256 * size_hints->height_inc;
1258 bounds.right = bounds.left + width;
1259 bounds.bottom = bounds.top + height;
1260 SetEventParameter (event, kEventParamCurrentBounds,
1261 typeQDRectangle, sizeof (Rect), &bounds);
1262 result = noErr;
1264 break;
1266 case kEventWindowBoundsChanged:
1267 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
1268 NULL, sizeof (UInt32), NULL, &attributes);
1269 if (err != noErr)
1270 break;
1272 if (attributes & kWindowBoundsChangeSizeChanged)
1274 Rect bounds;
1276 err = GetEventParameter (event, kEventParamCurrentBounds,
1277 typeQDRectangle, NULL, sizeof (Rect),
1278 NULL, &bounds);
1279 if (err == noErr)
1281 int width, height;
1283 width = bounds.right - bounds.left;
1284 height = bounds.bottom - bounds.top;
1285 mac_handle_size_change (f, width, height);
1286 mac_wakeup_from_rne ();
1290 if (attributes & kWindowBoundsChangeOriginChanged)
1291 mac_handle_origin_change (f);
1293 result = noErr;
1294 break;
1296 /* -- window action events -- */
1298 case kEventWindowClose:
1300 struct input_event buf;
1302 EVENT_INIT (buf);
1303 buf.kind = DELETE_WINDOW_EVENT;
1304 XSETFRAME (buf.frame_or_window, f);
1305 buf.arg = Qnil;
1306 kbd_buffer_store_event (&buf);
1308 result = noErr;
1309 break;
1311 case kEventWindowGetIdealSize:
1312 result = CallNextEventHandler (next_handler, event);
1313 if (result != eventNotHandledErr)
1314 break;
1317 Point ideal_size = mac_get_ideal_size (f);
1319 err = SetEventParameter (event, kEventParamDimensions,
1320 typeQDPoint, sizeof (Point), &ideal_size);
1321 if (err == noErr)
1322 result = noErr;
1324 break;
1326 #ifdef MAC_OSX
1327 case kEventWindowToolbarSwitchMode:
1329 static const EventParamName names[] = {kEventParamDirectObject,
1330 kEventParamWindowMouseLocation,
1331 kEventParamKeyModifiers,
1332 kEventParamMouseButton,
1333 kEventParamClickCount,
1334 kEventParamMouseChord};
1335 static const EventParamType types[] = {typeWindowRef,
1336 typeQDPoint,
1337 typeUInt32,
1338 typeMouseButton,
1339 typeUInt32,
1340 typeUInt32};
1341 int num_params = sizeof (names) / sizeof (names[0]);
1343 err = mac_store_event_ref_as_apple_event (0, 0,
1344 Qwindow,
1345 Qtoolbar_switch_mode,
1346 event, num_params,
1347 names, types);
1349 if (err == noErr)
1350 result = noErr;
1351 break;
1352 #endif
1354 #if USE_MAC_TSM
1355 /* -- window focus events -- */
1357 case kEventWindowFocusAcquired:
1358 err = mac_tsm_resume ();
1359 if (err == noErr)
1360 result = noErr;
1361 break;
1363 case kEventWindowFocusRelinquish:
1364 err = mac_tsm_suspend ();
1365 if (err == noErr)
1366 result = noErr;
1367 break;
1368 #endif
1370 default:
1371 abort ();
1374 return result;
1376 #endif
1378 /* Handle clicks in zoom box. Calculation of "standard state" based
1379 on code in IM - Window Manager A and code contributed by Ben
1380 Mesander. The standard state of an Emacs window is 80-characters
1381 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
1383 static void
1384 do_zoom_window (WindowRef w, int zoom_in_or_out)
1386 Rect zoom_rect, port_rect;
1387 int width, height;
1388 struct frame *f = mac_window_to_frame (w);
1389 #if TARGET_API_MAC_CARBON
1390 Point ideal_size = mac_get_ideal_size (f);
1392 GetWindowBounds (w, kWindowContentRgn, &port_rect);
1393 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
1394 && port_rect.left == zoom_rect.left
1395 && port_rect.top == zoom_rect.top)
1396 zoom_in_or_out = inZoomIn;
1397 else
1398 zoom_in_or_out = inZoomOut;
1400 #ifdef MAC_OS8
1401 mac_clear_area (f, 0, 0, port_rect.right - port_rect.left,
1402 port_rect.bottom - port_rect.top);
1403 #endif
1404 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
1405 #else /* not TARGET_API_MAC_CARBON */
1406 GrafPtr save_port;
1407 Point top_left;
1408 int w_title_height, rows;
1409 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
1411 GetPort (&save_port);
1413 SetPortWindowPort (w);
1415 /* Clear window to avoid flicker. */
1416 EraseRect (&(w->portRect));
1417 if (zoom_in_or_out == inZoomOut)
1419 SetPt (&top_left, w->portRect.left, w->portRect.top);
1420 LocalToGlobal (&top_left);
1422 /* calculate height of window's title bar */
1423 w_title_height = top_left.v - 1
1424 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
1426 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
1427 zoom_rect = qd.screenBits.bounds;
1428 zoom_rect.top += w_title_height;
1429 InsetRect (&zoom_rect, 8, 4); /* not too tight */
1431 zoom_rect.right = zoom_rect.left
1432 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
1434 /* Adjust the standard size according to character boundaries. */
1435 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
1436 zoom_rect.bottom =
1437 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1439 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
1440 = zoom_rect;
1443 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
1445 SetPort (save_port);
1446 #endif /* not TARGET_API_MAC_CARBON */
1448 #if !TARGET_API_MAC_CARBON
1449 /* retrieve window size and update application values */
1450 port_rect = w->portRect;
1451 height = port_rect.bottom - port_rect.top;
1452 width = port_rect.right - port_rect.left;
1454 mac_handle_size_change (f, width, height);
1455 mac_handle_origin_change (f);
1456 #endif
1459 static OSStatus
1460 install_window_handler (window)
1461 WindowRef window;
1463 OSStatus err = noErr;
1465 #if TARGET_API_MAC_CARBON
1466 if (err == noErr)
1468 static const EventTypeSpec specs[] =
1470 /* -- window refresh events -- */
1471 {kEventClassWindow, kEventWindowUpdate},
1472 /* -- window state change events -- */
1473 {kEventClassWindow, kEventWindowShowing},
1474 {kEventClassWindow, kEventWindowHiding},
1475 {kEventClassWindow, kEventWindowShown},
1476 {kEventClassWindow, kEventWindowHidden},
1477 {kEventClassWindow, kEventWindowCollapsed},
1478 {kEventClassWindow, kEventWindowExpanded},
1479 {kEventClassWindow, kEventWindowBoundsChanging},
1480 {kEventClassWindow, kEventWindowBoundsChanged},
1481 /* -- window action events -- */
1482 {kEventClassWindow, kEventWindowClose},
1483 {kEventClassWindow, kEventWindowGetIdealSize},
1484 #ifdef MAC_OSX
1485 {kEventClassWindow, kEventWindowToolbarSwitchMode},
1486 #endif
1487 #if USE_MAC_TSM
1488 /* -- window focus events -- */
1489 {kEventClassWindow, kEventWindowFocusAcquired},
1490 {kEventClassWindow, kEventWindowFocusRelinquish},
1491 #endif
1493 static EventHandlerUPP handle_window_eventUPP = NULL;
1495 if (handle_window_eventUPP == NULL)
1496 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
1498 err = InstallWindowEventHandler (window, handle_window_eventUPP,
1499 GetEventTypeCount (specs),
1500 specs, NULL, NULL);
1502 #endif
1504 if (err == noErr)
1505 err = install_drag_handler (window);
1507 return err;
1510 static void
1511 remove_window_handler (window)
1512 WindowRef window;
1514 remove_drag_handler (window);
1517 void
1518 mac_get_window_bounds (f, inner, outer)
1519 struct frame *f;
1520 Rect *inner, *outer;
1522 #if TARGET_API_MAC_CARBON
1523 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
1524 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
1525 #else /* not TARGET_API_MAC_CARBON */
1526 RgnHandle region = NewRgn ();
1528 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
1529 *inner = (*region)->rgnBBox;
1530 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
1531 *outer = (*region)->rgnBBox;
1532 DisposeRgn (region);
1533 #endif /* not TARGET_API_MAC_CARBON */
1536 Rect *
1537 mac_get_frame_bounds (f, r)
1538 struct frame *f;
1539 Rect *r;
1541 #if TARGET_API_MAC_CARBON
1542 return GetWindowPortBounds (FRAME_MAC_WINDOW (f), r);
1543 #else
1544 *r = FRAME_MAC_WINDOW (f)->portRect;
1546 return r;
1547 #endif
1550 void
1551 mac_get_frame_mouse (f, point)
1552 struct frame *f;
1553 Point *point;
1555 #if TARGET_API_MAC_CARBON
1556 GetGlobalMouse (point);
1557 point->h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1558 point->v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1559 #else
1560 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1561 GetMouse (point);
1562 #endif
1565 void
1566 mac_convert_frame_point_to_global (f, x, y)
1567 struct frame *f;
1568 int *x, *y;
1570 *x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1571 *y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1574 #if TARGET_API_MAC_CARBON
1575 void
1576 mac_update_proxy_icon (f)
1577 struct frame *f;
1579 OSStatus err;
1580 Lisp_Object file_name =
1581 XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer)->filename;
1582 Window w = FRAME_MAC_WINDOW (f);
1583 AliasHandle alias = NULL;
1585 err = GetWindowProxyAlias (w, &alias);
1586 if (err == errWindowDoesNotHaveProxy && !STRINGP (file_name))
1587 return;
1589 if (STRINGP (file_name))
1591 AEDesc desc;
1592 #ifdef MAC_OSX
1593 FSRef fref, fref_proxy;
1594 #else
1595 FSSpec fss, fss_proxy;
1596 #endif
1597 Boolean changed;
1598 Lisp_Object encoded_file_name = ENCODE_FILE (file_name);
1600 #ifdef MAC_OSX
1601 err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name),
1602 SBYTES (encoded_file_name), typeFSRef, &desc);
1603 #else
1604 SetPortWindowPort (w);
1605 err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name),
1606 SBYTES (encoded_file_name), typeFSS, &desc);
1607 #endif
1608 if (err == noErr)
1610 #ifdef MAC_OSX
1611 err = AEGetDescData (&desc, &fref, sizeof (FSRef));
1612 #else
1613 err = AEGetDescData (&desc, &fss, sizeof (FSSpec));
1614 #endif
1615 AEDisposeDesc (&desc);
1617 if (err == noErr)
1619 if (alias)
1621 /* (FS)ResolveAlias never sets `changed' to true if
1622 `alias' is minimal. */
1623 #ifdef MAC_OSX
1624 err = FSResolveAlias (NULL, alias, &fref_proxy, &changed);
1625 if (err == noErr)
1626 err = FSCompareFSRefs (&fref, &fref_proxy);
1627 #else
1628 err = ResolveAlias (NULL, alias, &fss_proxy, &changed);
1629 if (err == noErr)
1630 err = !(fss.vRefNum == fss_proxy.vRefNum
1631 && fss.parID == fss_proxy.parID
1632 && EqualString (fss.name, fss_proxy.name,
1633 false, true));
1634 #endif
1636 if (err != noErr || alias == NULL)
1638 if (alias)
1639 DisposeHandle ((Handle) alias);
1640 #ifdef MAC_OSX
1641 err = FSNewAliasMinimal (&fref, &alias);
1642 #else
1643 err = NewAliasMinimal (&fss, &alias);
1644 #endif
1645 changed = true;
1648 if (err == noErr)
1649 if (changed)
1650 err = SetWindowProxyAlias (w, alias);
1653 if (alias)
1654 DisposeHandle ((Handle) alias);
1656 if (err != noErr || !STRINGP (file_name))
1657 RemoveWindowProxy (w);
1659 #endif
1661 /* Mac replacement for XSetWindowBackground. */
1663 void
1664 mac_set_frame_window_background (f, color)
1665 struct frame *f;
1666 unsigned long color;
1668 WindowRef w = FRAME_MAC_WINDOW (f);
1669 #if !TARGET_API_MAC_CARBON
1670 AuxWinHandle aw_handle;
1671 CTabHandle ctab_handle;
1672 ColorSpecPtr ct_table;
1673 short ct_size;
1674 #endif
1675 RGBColor bg_color;
1677 bg_color.red = RED16_FROM_ULONG (color);
1678 bg_color.green = GREEN16_FROM_ULONG (color);
1679 bg_color.blue = BLUE16_FROM_ULONG (color);
1681 #if TARGET_API_MAC_CARBON
1682 SetWindowContentColor (w, &bg_color);
1683 #else
1684 if (GetAuxWin (w, &aw_handle))
1686 ctab_handle = (*aw_handle)->awCTable;
1687 HandToHand ((Handle *) &ctab_handle);
1688 ct_table = (*ctab_handle)->ctTable;
1689 ct_size = (*ctab_handle)->ctSize;
1690 while (ct_size > -1)
1692 if (ct_table->value == 0)
1694 ct_table->rgb = bg_color;
1695 CTabChanged (ctab_handle);
1696 SetWinColor (w, (WCTabHandle) ctab_handle);
1698 ct_size--;
1701 #endif
1704 /* Flush display of frame F, or of all frames if F is null. */
1706 void
1707 x_flush (f)
1708 struct frame *f;
1710 #if TARGET_API_MAC_CARBON
1711 BLOCK_INPUT;
1712 #if USE_CG_DRAWING
1713 mac_prepare_for_quickdraw (f);
1714 #endif
1715 if (f)
1716 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
1717 else
1718 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
1719 UNBLOCK_INPUT;
1720 #endif
1723 #if USE_CG_DRAWING
1724 void
1725 mac_flush_display_optional (f)
1726 struct frame *f;
1728 BLOCK_INPUT;
1729 mac_prepare_for_quickdraw (f);
1730 UNBLOCK_INPUT;
1732 #endif
1734 void
1735 mac_update_begin (f)
1736 struct frame *f;
1738 #if TARGET_API_MAC_CARBON
1739 /* During update of a frame, availability of input events is
1740 periodically checked with ReceiveNextEvent if
1741 redisplay-dont-pause is nil. That normally flushes window buffer
1742 changes for every check, and thus screen update looks waving even
1743 if no input is available. So we disable screen updates during
1744 update of a frame. */
1745 DisableScreenUpdates ();
1746 #endif
1749 void
1750 mac_update_end (f)
1751 struct frame *f;
1753 #if TARGET_API_MAC_CARBON
1754 EnableScreenUpdates ();
1755 #endif
1758 void
1759 mac_frame_up_to_date (f)
1760 struct frame *f;
1762 /* Nothing to do. */
1765 void
1766 mac_create_frame_window (f, tooltip_p)
1767 struct frame *f;
1768 int tooltip_p;
1770 Rect r;
1771 #if TARGET_API_MAC_CARBON
1772 WindowClass window_class;
1773 WindowAttributes attributes;
1774 #else
1775 short proc_id;
1776 WindowRef behind;
1777 Boolean go_away_flag;
1778 #endif
1780 if (!tooltip_p)
1782 SetRect (&r, f->left_pos, f->top_pos,
1783 f->left_pos + FRAME_PIXEL_WIDTH (f),
1784 f->top_pos + FRAME_PIXEL_HEIGHT (f));
1785 #if TARGET_API_MAC_CARBON
1786 window_class = kDocumentWindowClass;
1787 attributes = (kWindowStandardDocumentAttributes
1788 #ifdef MAC_OSX
1789 | kWindowToolbarButtonAttribute
1790 #endif
1792 #else
1793 proc_id = zoomDocProc;
1794 behind = (WindowRef) -1;
1795 go_away_flag = true;
1796 #endif
1798 else
1800 SetRect (&r, 0, 0, 1, 1);
1801 #if TARGET_API_MAC_CARBON
1802 window_class = kHelpWindowClass;
1803 attributes = (kWindowNoUpdatesAttribute
1804 | kWindowNoActivatesAttribute
1805 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1806 | kWindowIgnoreClicksAttribute
1807 #endif
1809 #else
1810 proc_id = plainDBox;
1811 behind = NULL;
1812 go_away_flag = false;
1813 #endif
1816 #if TARGET_API_MAC_CARBON
1817 CreateNewWindow (window_class, attributes, &r, &FRAME_MAC_WINDOW (f));
1818 if (FRAME_MAC_WINDOW (f))
1820 SetWRefCon (FRAME_MAC_WINDOW (f), (long) f->output_data.mac);
1821 if (!tooltip_p)
1822 if (install_window_handler (FRAME_MAC_WINDOW (f)) != noErr)
1824 DisposeWindow (FRAME_MAC_WINDOW (f));
1825 FRAME_MAC_WINDOW (f) = NULL;
1828 #else /* !TARGET_API_MAC_CARBON */
1829 FRAME_MAC_WINDOW (f)
1830 = NewCWindow (NULL, &r, "\p", false, proc_id, behind, go_away_flag,
1831 (long) f->output_data.mac);
1832 #endif /* !TARGET_API_MAC_CARBON */
1833 /* so that update events can find this mac_output struct */
1834 f->output_data.mac->mFP = f; /* point back to emacs frame */
1836 #ifndef MAC_OSX
1837 if (!tooltip_p)
1838 if (FRAME_MAC_WINDOW (f))
1840 ControlRef root_control;
1842 if (CreateRootControl (FRAME_MAC_WINDOW (f), &root_control) != noErr)
1844 DisposeWindow (FRAME_MAC_WINDOW (f));
1845 FRAME_MAC_WINDOW (f) = NULL;
1848 #endif
1851 /* Dispose of the Mac window of the frame F. */
1853 void
1854 mac_dispose_frame_window (f)
1855 struct frame *f;
1857 WindowRef window = FRAME_MAC_WINDOW (f);
1859 if (window != tip_window)
1860 remove_window_handler (window);
1862 #if USE_CG_DRAWING
1863 mac_prepare_for_quickdraw (f);
1864 #endif
1865 DisposeWindow (window);
1869 /************************************************************************
1870 View and Drawing
1871 ************************************************************************/
1873 #if USE_CG_DRAWING
1874 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
1876 CGContextRef
1877 mac_begin_cg_clip (f, gc)
1878 struct frame *f;
1879 GC gc;
1881 CGContextRef context = FRAME_CG_CONTEXT (f);
1883 if (!context)
1885 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1886 FRAME_CG_CONTEXT (f) = context;
1889 CGContextSaveGState (context);
1890 CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f));
1891 CGContextScaleCTM (context, 1, -1);
1892 if (gc && gc->n_clip_rects)
1893 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
1895 return context;
1898 void
1899 mac_end_cg_clip (f)
1900 struct frame *f;
1902 CGContextRestoreGState (FRAME_CG_CONTEXT (f));
1905 static void
1906 mac_prepare_for_quickdraw (f)
1907 struct frame *f;
1909 if (f == NULL)
1911 Lisp_Object rest, frame;
1912 FOR_EACH_FRAME (rest, frame)
1913 if (FRAME_MAC_P (XFRAME (frame)))
1914 mac_prepare_for_quickdraw (XFRAME (frame));
1916 else
1918 CGContextRef context = FRAME_CG_CONTEXT (f);
1920 if (context)
1922 CGContextSynchronize (context);
1923 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)),
1924 &FRAME_CG_CONTEXT (f));
1928 #endif
1930 static RgnHandle saved_port_clip_region = NULL;
1932 void
1933 mac_begin_clip (f, gc)
1934 struct frame *f;
1935 GC gc;
1937 static RgnHandle new_region = NULL;
1939 if (saved_port_clip_region == NULL)
1940 saved_port_clip_region = NewRgn ();
1941 if (new_region == NULL)
1942 new_region = NewRgn ();
1944 #if USE_CG_DRAWING
1945 mac_prepare_for_quickdraw (f);
1946 #endif
1947 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1949 if (gc && gc->n_clip_rects)
1951 GetClip (saved_port_clip_region);
1952 SectRgn (saved_port_clip_region, gc->clip_region, new_region);
1953 SetClip (new_region);
1957 void
1958 mac_end_clip (f, gc)
1959 struct frame *f;
1960 GC gc;
1962 if (gc && gc->n_clip_rects)
1963 SetClip (saved_port_clip_region);
1966 #if TARGET_API_MAC_CARBON
1967 /* Mac replacement for XCopyArea: used only for scrolling. */
1969 void
1970 mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1971 struct frame *f;
1972 GC gc;
1973 int src_x, src_y;
1974 unsigned int width, height;
1975 int dest_x, dest_y;
1977 Rect src_r;
1978 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
1980 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1981 #if USE_CG_DRAWING
1982 mac_prepare_for_quickdraw (f);
1983 #endif
1984 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1985 &src_r, dest_x - src_x, dest_y - src_y,
1986 kScrollWindowNoOptions, dummy);
1987 DisposeRgn (dummy);
1989 #endif
1992 /************************************************************************
1993 Scroll bars
1994 ************************************************************************/
1996 extern struct scroll_bar *tracked_scroll_bar;
1997 extern Lisp_Object last_mouse_scroll_bar;
1998 extern Time last_mouse_movement_time;
2000 static void x_scroll_bar_handle_click P_ ((struct scroll_bar *,
2001 ControlPartCode,
2002 const EventRecord *,
2003 struct input_event *));
2004 #ifndef USE_TOOLKIT_SCROLL_BARS
2005 static void x_scroll_bar_note_movement P_ ((struct scroll_bar *, int, Time));
2006 #else /* USE_TOOLKIT_SCROLL_BARS */
2007 static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
2008 ControlPartCode, Point,
2009 struct input_event *));
2010 static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
2011 struct input_event *));
2012 static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *,
2013 Point, struct input_event *));
2014 static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
2015 static OSStatus install_scroll_bar_timer P_ ((void));
2016 static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
2017 static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
2018 static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
2019 struct input_event *));
2020 static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode,
2021 Rect *));
2022 static void update_scroll_bar_track_info P_ ((struct scroll_bar *));
2024 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
2026 static int last_scroll_bar_part;
2028 static EventLoopTimerRef scroll_bar_timer;
2030 static int scroll_bar_timer_event_posted_p;
2032 #define SCROLL_BAR_FIRST_DELAY 0.5
2033 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
2035 static pascal void
2036 scroll_bar_timer_callback (timer, data)
2037 EventLoopTimerRef timer;
2038 void *data;
2040 OSStatus err;
2042 err = mac_post_mouse_moved_event ();
2043 if (err == noErr)
2044 scroll_bar_timer_event_posted_p = 1;
2047 static OSStatus
2048 install_scroll_bar_timer ()
2050 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
2052 if (scroll_bar_timer_callbackUPP == NULL)
2053 scroll_bar_timer_callbackUPP =
2054 NewEventLoopTimerUPP (scroll_bar_timer_callback);
2056 if (scroll_bar_timer == NULL)
2057 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
2058 kEventDurationForever as delays. */
2059 return
2060 InstallEventLoopTimer (GetCurrentEventLoop (),
2061 kEventDurationForever, kEventDurationForever,
2062 scroll_bar_timer_callbackUPP, NULL,
2063 &scroll_bar_timer);
2066 static OSStatus
2067 set_scroll_bar_timer (delay)
2068 EventTimerInterval delay;
2070 if (scroll_bar_timer == NULL)
2071 install_scroll_bar_timer ();
2073 scroll_bar_timer_event_posted_p = 0;
2075 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
2078 static int
2079 control_part_code_to_scroll_bar_part (part_code)
2080 ControlPartCode part_code;
2082 switch (part_code)
2084 case kControlUpButtonPart: return scroll_bar_up_arrow;
2085 case kControlDownButtonPart: return scroll_bar_down_arrow;
2086 case kControlPageUpPart: return scroll_bar_above_handle;
2087 case kControlPageDownPart: return scroll_bar_below_handle;
2088 case kControlIndicatorPart: return scroll_bar_handle;
2091 return -1;
2094 static void
2095 construct_scroll_bar_click (bar, part, bufp)
2096 struct scroll_bar *bar;
2097 int part;
2098 struct input_event *bufp;
2100 bufp->kind = SCROLL_BAR_CLICK_EVENT;
2101 bufp->frame_or_window = bar->window;
2102 bufp->arg = Qnil;
2103 bufp->part = part;
2104 bufp->code = 0;
2105 XSETINT (bufp->x, 0);
2106 XSETINT (bufp->y, 0);
2107 bufp->modifiers = 0;
2110 static OSStatus
2111 get_control_part_bounds (ch, part_code, rect)
2112 ControlRef ch;
2113 ControlPartCode part_code;
2114 Rect *rect;
2116 RgnHandle region = NewRgn ();
2117 OSStatus err;
2119 err = GetControlRegion (ch, part_code, region);
2120 if (err == noErr)
2121 GetRegionBounds (region, rect);
2122 DisposeRgn (region);
2124 return err;
2127 static void
2128 x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp)
2129 struct scroll_bar *bar;
2130 ControlPartCode part_code;
2131 Point mouse_pos;
2132 struct input_event *bufp;
2134 int part = control_part_code_to_scroll_bar_part (part_code);
2136 if (part < 0)
2137 return;
2139 if (part != scroll_bar_handle)
2141 construct_scroll_bar_click (bar, part, bufp);
2142 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
2143 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
2144 bar->dragging = Qnil;
2146 else
2148 Rect r;
2150 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
2151 kControlIndicatorPart, &r);
2152 XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1);
2155 last_scroll_bar_part = part;
2156 tracked_scroll_bar = bar;
2159 static void
2160 x_scroll_bar_handle_release (bar, bufp)
2161 struct scroll_bar *bar;
2162 struct input_event *bufp;
2164 if (last_scroll_bar_part != scroll_bar_handle
2165 || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0))
2166 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
2168 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
2169 set_scroll_bar_timer (kEventDurationForever);
2171 last_scroll_bar_part = -1;
2172 bar->dragging = Qnil;
2173 tracked_scroll_bar = NULL;
2176 static void
2177 x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
2178 WindowRef win;
2179 struct scroll_bar *bar;
2180 Point mouse_pos;
2181 struct input_event *bufp;
2183 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2185 if (last_scroll_bar_part == scroll_bar_handle)
2187 int top, top_range;
2188 Rect r;
2190 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
2191 kControlIndicatorPart, &r);
2193 if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0)
2194 XSETINT (bar->dragging, - (XINT (bar->dragging) + 1));
2196 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
2197 top_range = XINT (bar->track_height) - XINT (bar->min_handle);
2199 if (top < 0)
2200 top = 0;
2201 if (top > top_range)
2202 top = top_range;
2204 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
2205 XSETINT (bufp->x, top);
2206 XSETINT (bufp->y, top_range);
2208 else
2210 ControlPartCode part_code;
2211 int unhilite_p = 0, part;
2213 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
2214 unhilite_p = 1;
2215 else
2217 part = control_part_code_to_scroll_bar_part (part_code);
2219 switch (last_scroll_bar_part)
2221 case scroll_bar_above_handle:
2222 case scroll_bar_below_handle:
2223 if (part != scroll_bar_above_handle
2224 && part != scroll_bar_below_handle)
2225 unhilite_p = 1;
2226 break;
2228 case scroll_bar_up_arrow:
2229 case scroll_bar_down_arrow:
2230 if (part != scroll_bar_up_arrow
2231 && part != scroll_bar_down_arrow)
2232 unhilite_p = 1;
2233 break;
2237 if (unhilite_p)
2238 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
2239 else if (part != last_scroll_bar_part
2240 || scroll_bar_timer_event_posted_p)
2242 construct_scroll_bar_click (bar, part, bufp);
2243 last_scroll_bar_part = part;
2244 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
2245 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
2250 /* Update BAR->track_top, BAR->track_height, and BAR->min_handle for
2251 the scroll bar BAR. This function should be called when the bounds
2252 of the scroll bar is changed. */
2254 static void
2255 update_scroll_bar_track_info (bar)
2256 struct scroll_bar *bar;
2258 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2259 Rect r0, r1;
2261 GetControlBounds (ch, &r0);
2263 if (r0.right - r0.left >= r0.bottom - r0.top
2264 #ifdef MAC_OSX
2265 || r0.right - r0.left < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
2266 #endif
2269 XSETINT (bar->track_top, 0);
2270 XSETINT (bar->track_height, 0);
2271 XSETINT (bar->min_handle, 0);
2273 else
2275 BLOCK_INPUT;
2277 SetControl32BitMinimum (ch, 0);
2278 SetControl32BitMaximum (ch, 1 << 30);
2279 SetControlViewSize (ch, 1);
2281 /* Move the scroll bar thumb to the top. */
2282 SetControl32BitValue (ch, 0);
2283 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
2285 /* Move the scroll bar thumb to the bottom. */
2286 SetControl32BitValue (ch, 1 << 30);
2287 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
2289 UnionRect (&r0, &r1, &r0);
2290 XSETINT (bar->track_top, r0.top);
2291 XSETINT (bar->track_height, r0.bottom - r0.top);
2292 XSETINT (bar->min_handle, r1.bottom - r1.top);
2294 /* Don't show the scroll bar if its height is not enough to
2295 display the scroll bar thumb. */
2296 if (r0.bottom - r0.top > 0)
2297 ShowControl (ch);
2299 UNBLOCK_INPUT;
2303 /* Set the thumb size and position of scroll bar BAR. We are currently
2304 displaying PORTION out of a whole WHOLE, and our position POSITION. */
2306 void
2307 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
2308 struct scroll_bar *bar;
2309 int portion, position, whole;
2311 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2312 int value, viewsize, maximum;
2314 if (XINT (bar->track_height) == 0)
2315 return;
2317 if (whole <= portion)
2318 value = 0, viewsize = 1, maximum = 0;
2319 else
2321 float scale;
2323 maximum = XINT (bar->track_height) - XINT (bar->min_handle);
2324 scale = (float) maximum / (whole - portion);
2325 value = position * scale + 0.5f;
2326 viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle);
2329 BLOCK_INPUT;
2331 if (GetControlViewSize (ch) != viewsize
2332 || GetControl32BitValue (ch) != value
2333 || GetControl32BitMaximum (ch) != maximum)
2335 /* Temporarily hide the scroll bar to avoid multiple redraws. */
2336 SetControlVisibility (ch, false, false);
2338 SetControl32BitMaximum (ch, maximum);
2339 SetControl32BitValue (ch, value);
2340 SetControlViewSize (ch, viewsize);
2342 SetControlVisibility (ch, true, true);
2345 UNBLOCK_INPUT;
2348 #endif /* USE_TOOLKIT_SCROLL_BARS */
2350 /* Create a scroll bar control for BAR. BOUNDS and VISIBLE specifies
2351 the initial geometry and visibility, respectively. The created
2352 control is stored in some members of BAR. */
2354 void
2355 mac_create_scroll_bar (bar, bounds, visible)
2356 struct scroll_bar *bar;
2357 const Rect *bounds;
2358 Boolean visible;
2360 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2361 ControlRef ch;
2363 #if USE_CG_DRAWING
2364 mac_prepare_for_quickdraw (f);
2365 #endif
2366 ch = NewControl (FRAME_MAC_WINDOW (f), bounds, "\p", visible, 0, 0, 0,
2367 #if TARGET_API_MAC_CARBON
2368 kControlScrollBarProc,
2369 #else
2370 scrollBarProc,
2371 #endif
2372 (SInt32) bar);
2373 SET_SCROLL_BAR_CONTROL_REF (bar, ch);
2375 XSETINT (bar->start, 0);
2376 XSETINT (bar->end, 0);
2377 bar->dragging = Qnil;
2379 #ifdef USE_TOOLKIT_SCROLL_BARS
2380 update_scroll_bar_track_info (bar);
2381 #endif
2384 /* Dispose of the scroll bar control stored in some members of
2385 BAR. */
2387 void
2388 mac_dispose_scroll_bar (bar)
2389 struct scroll_bar *bar;
2391 #if USE_CG_DRAWING
2392 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2394 mac_prepare_for_quickdraw (f);
2395 #endif
2396 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
2399 /* Set bounds of the scroll bar BAR to BOUNDS. */
2401 void
2402 mac_set_scroll_bar_bounds (bar, bounds)
2403 struct scroll_bar *bar;
2404 const Rect *bounds;
2406 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2407 SInt16 width, height;
2408 #if USE_CG_DRAWING
2409 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2411 mac_prepare_for_quickdraw (f);
2412 #endif
2414 width = bounds->right - bounds->left;
2415 height = bounds->bottom - bounds->top;
2416 HideControl (ch);
2417 MoveControl (ch, bounds->left, bounds->top);
2418 SizeControl (ch, width, height);
2419 #ifdef USE_TOOLKIT_SCROLL_BARS
2420 update_scroll_bar_track_info (bar);
2421 #else
2422 if (width < height)
2423 ShowControl (ch);
2424 #endif
2427 /* Draw the scroll bar BAR. */
2429 void
2430 mac_redraw_scroll_bar (bar)
2431 struct scroll_bar *bar;
2433 #if USE_CG_DRAWING
2434 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2436 mac_prepare_for_quickdraw (f);
2437 #endif
2438 Draw1Control (SCROLL_BAR_CONTROL_REF (bar));
2441 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2442 is set to something other than NO_EVENT, it is enqueued.
2444 This may be called from a signal handler, so we have to ignore GC
2445 mark bits. */
2447 static void
2448 x_scroll_bar_handle_click (bar, part_code, er, bufp)
2449 struct scroll_bar *bar;
2450 ControlPartCode part_code;
2451 const EventRecord *er;
2452 struct input_event *bufp;
2454 int win_y, top_range;
2456 if (! GC_WINDOWP (bar->window))
2457 abort ();
2459 bufp->kind = SCROLL_BAR_CLICK_EVENT;
2460 bufp->frame_or_window = bar->window;
2461 bufp->arg = Qnil;
2463 bar->dragging = Qnil;
2465 switch (part_code)
2467 case kControlUpButtonPart:
2468 bufp->part = scroll_bar_up_arrow;
2469 break;
2470 case kControlDownButtonPart:
2471 bufp->part = scroll_bar_down_arrow;
2472 break;
2473 case kControlPageUpPart:
2474 bufp->part = scroll_bar_above_handle;
2475 break;
2476 case kControlPageDownPart:
2477 bufp->part = scroll_bar_below_handle;
2478 break;
2479 #if TARGET_API_MAC_CARBON
2480 default:
2481 #else
2482 case kControlIndicatorPart:
2483 #endif
2484 if (er->what == mouseDown)
2485 bar->dragging = make_number (0);
2486 XSETVECTOR (last_mouse_scroll_bar, bar);
2487 bufp->part = scroll_bar_handle;
2488 break;
2491 win_y = XINT (bufp->y) - XINT (bar->top);
2492 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
2494 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2496 win_y -= 24;
2498 if (! NILP (bar->dragging))
2499 win_y -= XINT (bar->dragging);
2501 if (win_y < 0)
2502 win_y = 0;
2503 if (win_y > top_range)
2504 win_y = top_range;
2506 XSETINT (bufp->x, win_y);
2507 XSETINT (bufp->y, top_range);
2510 /* Return information to the user about the current position of the mouse
2511 on the scroll bar. */
2513 void
2514 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
2515 FRAME_PTR *fp;
2516 Lisp_Object *bar_window;
2517 enum scroll_bar_part *part;
2518 Lisp_Object *x, *y;
2519 unsigned long *time;
2521 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
2522 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2523 #if TARGET_API_MAC_CARBON
2524 WindowRef wp = GetControlOwner (ch);
2525 #else
2526 WindowRef wp = (*ch)->contrlOwner;
2527 #endif
2528 Point mouse_pos;
2529 struct frame *f = mac_window_to_frame (wp);
2530 int win_y, top_range;
2532 #if TARGET_API_MAC_CARBON
2533 GetGlobalMouse (&mouse_pos);
2534 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
2535 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
2536 #else
2537 SetPortWindowPort (wp);
2538 GetMouse (&mouse_pos);
2539 #endif
2541 win_y = mouse_pos.v - XINT (bar->top);
2542 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
2544 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2546 win_y -= 24;
2548 if (! NILP (bar->dragging))
2549 win_y -= XINT (bar->dragging);
2551 if (win_y < 0)
2552 win_y = 0;
2553 if (win_y > top_range)
2554 win_y = top_range;
2556 *fp = f;
2557 *bar_window = bar->window;
2559 if (! NILP (bar->dragging))
2560 *part = scroll_bar_handle;
2561 else if (win_y < XINT (bar->start))
2562 *part = scroll_bar_above_handle;
2563 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2564 *part = scroll_bar_handle;
2565 else
2566 *part = scroll_bar_below_handle;
2568 XSETINT (*x, win_y);
2569 XSETINT (*y, top_range);
2571 f->mouse_moved = 0;
2572 last_mouse_scroll_bar = Qnil;
2574 *time = last_mouse_movement_time;
2577 #ifndef USE_TOOLKIT_SCROLL_BARS
2578 /* Draw BAR's handle in the proper position.
2580 If the handle is already drawn from START to END, don't bother
2581 redrawing it, unless REBUILD is non-zero; in that case, always
2582 redraw it. (REBUILD is handy for drawing the handle after expose
2583 events.)
2585 Normally, we want to constrain the start and end of the handle to
2586 fit inside its rectangle, but if the user is dragging the scroll
2587 bar handle, we want to let them drag it down all the way, so that
2588 the bar's top is as far down as it goes; otherwise, there's no way
2589 to move to the very end of the buffer. */
2591 void
2592 x_scroll_bar_set_handle (bar, start, end, rebuild)
2593 struct scroll_bar *bar;
2594 int start, end;
2595 int rebuild;
2597 int dragging = ! NILP (bar->dragging);
2598 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2599 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2600 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
2601 int length = end - start;
2603 /* If the display is already accurate, do nothing. */
2604 if (! rebuild
2605 && start == XINT (bar->start)
2606 && end == XINT (bar->end))
2607 return;
2609 BLOCK_INPUT;
2611 /* Make sure the values are reasonable, and try to preserve the
2612 distance between start and end. */
2613 if (start < 0)
2614 start = 0;
2615 else if (start > top_range)
2616 start = top_range;
2617 end = start + length;
2619 if (end < start)
2620 end = start;
2621 else if (end > top_range && ! dragging)
2622 end = top_range;
2624 /* Store the adjusted setting in the scroll bar. */
2625 XSETINT (bar->start, start);
2626 XSETINT (bar->end, end);
2628 /* Clip the end position, just for display. */
2629 if (end > top_range)
2630 end = top_range;
2632 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
2633 top positions, to make sure the handle is always at least that
2634 many pixels tall. */
2635 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
2637 SetControlMinimum (ch, 0);
2638 /* Don't inadvertently activate deactivated scroll bars */
2639 if (GetControlMaximum (ch) != -1)
2640 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
2641 - (end - start));
2642 SetControlValue (ch, start);
2643 #if TARGET_API_MAC_CARBON
2644 SetControlViewSize (ch, end - start);
2645 #endif
2647 UNBLOCK_INPUT;
2650 /* Handle some mouse motion while someone is dragging the scroll bar.
2652 This may be called from a signal handler, so we have to ignore GC
2653 mark bits. */
2655 static void
2656 x_scroll_bar_note_movement (bar, y_pos, t)
2657 struct scroll_bar *bar;
2658 int y_pos;
2659 Time t;
2661 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
2663 last_mouse_movement_time = t;
2665 f->mouse_moved = 1;
2666 XSETVECTOR (last_mouse_scroll_bar, bar);
2668 /* If we're dragging the bar, display it. */
2669 if (! GC_NILP (bar->dragging))
2671 /* Where should the handle be now? */
2672 int new_start = y_pos - 24;
2674 if (new_start != XINT (bar->start))
2676 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2678 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2682 #endif /* !USE_TOOLKIT_SCROLL_BARS */
2685 /***********************************************************************
2686 Tool-bars
2687 ***********************************************************************/
2689 #if USE_MAC_TOOLBAR
2690 /* In identifiers such as function/variable names, Emacs tool bar is
2691 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
2693 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
2694 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
2696 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
2697 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
2698 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2699 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
2700 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2701 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
2702 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2704 static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
2705 EventRef, void *));
2707 extern Rect last_mouse_glyph;
2709 extern void mac_move_window_with_gravity P_ ((struct frame *, int,
2710 short, short));
2711 extern void mac_get_window_origin_with_gravity P_ ((struct frame *, int,
2712 short *, short *));
2713 extern CGImageRef mac_image_spec_to_cg_image P_ ((struct frame *,
2714 Lisp_Object));
2716 static OSStatus
2717 mac_handle_toolbar_event (next_handler, event, data)
2718 EventHandlerCallRef next_handler;
2719 EventRef event;
2720 void *data;
2722 OSStatus result = eventNotHandledErr;
2724 switch (GetEventKind (event))
2726 case kEventToolbarGetDefaultIdentifiers:
2727 result = noErr;
2728 break;
2730 case kEventToolbarGetAllowedIdentifiers:
2732 CFMutableArrayRef array;
2734 GetEventParameter (event, kEventParamMutableArray,
2735 typeCFMutableArrayRef, NULL,
2736 sizeof (CFMutableArrayRef), NULL, &array);
2737 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
2738 result = noErr;
2740 break;
2742 case kEventToolbarCreateItemWithIdentifier:
2744 CFStringRef identifier;
2745 HIToolbarItemRef item = NULL;
2747 GetEventParameter (event, kEventParamToolbarItemIdentifier,
2748 typeCFStringRef, NULL,
2749 sizeof (CFStringRef), NULL, &identifier);
2751 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
2752 == kCFCompareEqualTo)
2753 HIToolbarItemCreate (identifier,
2754 kHIToolbarItemAllowDuplicates
2755 | kHIToolbarItemCantBeRemoved, &item);
2757 if (item)
2759 SetEventParameter (event, kEventParamToolbarItem,
2760 typeHIToolbarItemRef,
2761 sizeof (HIToolbarItemRef), &item);
2762 result = noErr;
2765 break;
2767 default:
2768 abort ();
2771 return result;
2774 /* Create a tool bar for frame F. */
2776 static OSStatus
2777 mac_create_frame_tool_bar (f)
2778 FRAME_PTR f;
2780 OSStatus err;
2781 HIToolbarRef toolbar;
2783 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
2784 &toolbar);
2785 if (err == noErr)
2787 static const EventTypeSpec specs[] =
2788 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
2789 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
2790 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
2792 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
2793 mac_handle_toolbar_event,
2794 GetEventTypeCount (specs), specs,
2795 f, NULL);
2798 if (err == noErr)
2799 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
2800 if (err == noErr)
2802 static const EventTypeSpec specs[] =
2803 {{kEventClassCommand, kEventCommandProcess}};
2805 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
2806 mac_handle_toolbar_command_event,
2807 GetEventTypeCount (specs),
2808 specs, f, NULL);
2810 if (err == noErr)
2811 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
2813 if (toolbar)
2814 CFRelease (toolbar);
2816 return err;
2819 /* Update the tool bar for frame F. Add new buttons and remove old. */
2821 void
2822 update_frame_tool_bar (f)
2823 FRAME_PTR f;
2825 HIToolbarRef toolbar = NULL;
2826 short left, top;
2827 CFArrayRef old_items = NULL;
2828 CFIndex old_count;
2829 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
2830 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2832 BLOCK_INPUT;
2834 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
2835 if (toolbar == NULL)
2837 mac_create_frame_tool_bar (f);
2838 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
2839 if (toolbar == NULL)
2840 goto out;
2841 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
2842 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
2845 HIToolbarCopyItems (toolbar, &old_items);
2846 if (old_items == NULL)
2847 goto out;
2849 old_count = CFArrayGetCount (old_items);
2850 pos = 0;
2851 for (i = 0; i < f->n_tool_bar_items; ++i)
2853 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
2855 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
2856 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
2857 int idx;
2858 Lisp_Object image;
2859 CGImageRef cg_image;
2860 CFStringRef label;
2861 HIToolbarItemRef item;
2863 /* If image is a vector, choose the image according to the
2864 button state. */
2865 image = PROP (TOOL_BAR_ITEM_IMAGES);
2866 if (VECTORP (image))
2868 if (enabled_p)
2869 idx = (selected_p
2870 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
2871 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
2872 else
2873 idx = (selected_p
2874 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
2875 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
2877 xassert (ASIZE (image) >= idx);
2878 image = AREF (image, idx);
2880 else
2881 idx = -1;
2883 cg_image = mac_image_spec_to_cg_image (f, image);
2884 /* Ignore invalid image specifications. */
2885 if (cg_image == NULL)
2886 continue;
2888 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
2889 if (label == NULL)
2890 label = CFSTR ("");
2892 if (pos < old_count)
2894 CGImageRef old_cg_image = NULL;
2895 CFStringRef old_label = NULL;
2896 Boolean old_enabled_p;
2898 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
2900 HIToolbarItemCopyImage (item, &old_cg_image);
2901 if (cg_image != old_cg_image)
2902 HIToolbarItemSetImage (item, cg_image);
2903 CGImageRelease (old_cg_image);
2905 HIToolbarItemCopyLabel (item, &old_label);
2906 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
2907 HIToolbarItemSetLabel (item, label);
2908 CFRelease (old_label);
2910 old_enabled_p = HIToolbarItemIsEnabled (item);
2911 if ((enabled_p || idx >= 0) != old_enabled_p)
2912 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
2914 else
2916 item = NULL;
2917 HIToolbarCreateItemWithIdentifier (toolbar,
2918 TOOLBAR_ICON_ITEM_IDENTIFIER,
2919 NULL, &item);
2920 if (item)
2922 HIToolbarItemSetImage (item, cg_image);
2923 HIToolbarItemSetLabel (item, label);
2924 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
2925 HIToolbarAppendItem (toolbar, item);
2926 CFRelease (item);
2930 CFRelease (label);
2931 if (item)
2933 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
2934 pos++;
2938 CFRelease (old_items);
2940 while (pos < old_count)
2941 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
2943 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
2944 !win_gravity && f == mac_focus_frame (dpyinfo));
2945 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
2946 toolbar visibility change. */
2947 mac_handle_origin_change (f);
2948 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
2950 mac_move_window_with_gravity (f, win_gravity, left, top);
2951 /* If the title bar is completely outside the screen, adjust the
2952 position. */
2953 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
2954 kWindowConstrainMoveRegardlessOfFit
2955 | kWindowConstrainAllowPartial, NULL, NULL);
2956 f->output_data.mac->toolbar_win_gravity = 0;
2959 out:
2960 UNBLOCK_INPUT;
2963 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
2964 doesn't deallocate the resources. */
2966 void
2967 free_frame_tool_bar (f)
2968 FRAME_PTR f;
2970 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
2972 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2974 BLOCK_INPUT;
2975 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
2976 (NILP (find_symbol_value
2977 (intern ("frame-notice-user-settings")))
2978 && f == mac_focus_frame (dpyinfo)));
2979 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
2980 on toolbar visibility change. */
2981 mac_handle_origin_change (f);
2982 UNBLOCK_INPUT;
2986 /* Report a mouse movement over toolbar to the mainstream Emacs
2987 code. */
2989 static void
2990 mac_tool_bar_note_mouse_movement (f, event)
2991 struct frame *f;
2992 EventRef event;
2994 OSStatus err;
2995 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2996 int mouse_down_p;
2997 WindowRef window;
2998 WindowPartCode part_code;
2999 HIViewRef item_view;
3000 UInt32 command_id;
3002 mouse_down_p = (dpyinfo->grabbed
3003 && f == last_mouse_frame
3004 && FRAME_LIVE_P (f));
3005 if (mouse_down_p)
3006 return;
3008 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef, NULL,
3009 sizeof (WindowRef), NULL, &window);
3010 if (err != noErr || window != FRAME_MAC_WINDOW (f))
3011 return;
3013 err = GetEventParameter (event, kEventParamWindowPartCode,
3014 typeWindowPartCode, NULL,
3015 sizeof (WindowPartCode), NULL, &part_code);
3016 if (err != noErr || part_code != inStructure)
3017 return;
3019 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window), event, &item_view);
3020 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
3021 toolbar item view seems to have the same command ID with that of
3022 the toolbar item. */
3023 if (err == noErr)
3024 err = GetControlCommandID (item_view, &command_id);
3025 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
3027 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
3029 if (i < f->n_tool_bar_items)
3031 HIRect bounds;
3032 HIViewRef content_view;
3034 err = HIViewGetBounds (item_view, &bounds);
3035 if (err == noErr)
3036 err = HIViewFindByID (HIViewGetRoot (window),
3037 kHIViewWindowContentID, &content_view);
3038 if (err == noErr)
3039 err = HIViewConvertRect (&bounds, item_view, content_view);
3040 if (err == noErr)
3041 SetRect (&last_mouse_glyph,
3042 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
3043 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
3045 help_echo_object = help_echo_window = Qnil;
3046 help_echo_pos = -1;
3047 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
3048 if (NILP (help_echo_string))
3049 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
3054 static OSStatus
3055 mac_handle_toolbar_command_event (next_handler, event, data)
3056 EventHandlerCallRef next_handler;
3057 EventRef event;
3058 void *data;
3060 OSStatus err, result = eventNotHandledErr;
3061 struct frame *f = (struct frame *) data;
3062 HICommand command;
3064 err = GetEventParameter (event, kEventParamDirectObject,
3065 typeHICommand, NULL,
3066 sizeof (HICommand), NULL, &command);
3067 if (err != noErr)
3068 return result;
3070 switch (GetEventKind (event))
3072 case kEventCommandProcess:
3073 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
3074 result = CallNextEventHandler (next_handler, event);
3075 else
3077 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
3079 if (i < f->n_tool_bar_items
3080 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
3082 Lisp_Object frame;
3083 struct input_event buf;
3085 EVENT_INIT (buf);
3087 XSETFRAME (frame, f);
3088 buf.kind = TOOL_BAR_EVENT;
3089 buf.frame_or_window = frame;
3090 buf.arg = frame;
3091 kbd_buffer_store_event (&buf);
3093 buf.kind = TOOL_BAR_EVENT;
3094 buf.frame_or_window = frame;
3095 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
3096 buf.modifiers = mac_event_to_emacs_modifiers (event);
3097 kbd_buffer_store_event (&buf);
3099 result = noErr;
3102 break;
3104 default:
3105 abort ();
3107 #undef PROP
3109 return result;
3111 #endif /* USE_MAC_TOOLBAR */
3114 /***********************************************************************
3115 Font Panel
3116 ***********************************************************************/
3118 #if USE_MAC_FONT_PANEL
3119 /* Whether Font Panel has been shown before. The first call to font
3120 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
3121 slow. This variable is used for deferring such a call as much as
3122 possible. */
3123 static int font_panel_shown_p = 0;
3125 extern Lisp_Object Qpanel_closed, Qselection;
3126 extern Lisp_Object Qfont;
3128 /* Whether the font panel is currently visible. */
3131 mac_font_panel_visible_p ()
3133 return font_panel_shown_p && FPIsFontPanelVisible ();
3136 static pascal OSStatus
3137 mac_handle_font_event (next_handler, event, data)
3138 EventHandlerCallRef next_handler;
3139 EventRef event;
3140 void *data;
3142 OSStatus result, err;
3143 Lisp_Object id_key;
3144 int num_params;
3145 const EventParamName *names;
3146 const EventParamType *types;
3147 static const EventParamName names_sel[] = {kEventParamATSUFontID,
3148 kEventParamATSUFontSize,
3149 kEventParamFMFontFamily,
3150 kEventParamFMFontStyle,
3151 kEventParamFMFontSize,
3152 kEventParamFontColor};
3153 static const EventParamType types_sel[] = {typeATSUFontID,
3154 typeATSUSize,
3155 typeFMFontFamily,
3156 typeFMFontStyle,
3157 typeFMFontSize,
3158 typeFontColor};
3160 result = CallNextEventHandler (next_handler, event);
3161 if (result != eventNotHandledErr)
3162 return result;
3164 switch (GetEventKind (event))
3166 case kEventFontPanelClosed:
3167 id_key = Qpanel_closed;
3168 num_params = 0;
3169 names = NULL;
3170 types = NULL;
3171 break;
3173 case kEventFontSelection:
3174 id_key = Qselection;
3175 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
3176 names = names_sel;
3177 types = types_sel;
3178 break;
3181 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
3182 event, num_params,
3183 names, types);
3184 if (err == noErr)
3185 result = noErr;
3187 return result;
3190 /* Toggle visiblity of the font panel. */
3192 OSStatus
3193 mac_show_hide_font_panel ()
3195 if (!font_panel_shown_p)
3197 OSStatus err;
3199 static const EventTypeSpec specs[] =
3200 {{kEventClassFont, kEventFontPanelClosed},
3201 {kEventClassFont, kEventFontSelection}};
3203 err = InstallApplicationEventHandler (mac_handle_font_event,
3204 GetEventTypeCount (specs),
3205 specs, NULL, NULL);
3206 if (err != noErr)
3207 return err;
3209 font_panel_shown_p = 1;
3212 return FPShowHideFontPanel ();
3215 /* Set the font selected in the font panel to the one corresponding to
3216 the face FACE_ID and the charcacter C in the frame F. */
3218 OSStatus
3219 mac_set_font_info_for_selection (f, face_id, c)
3220 struct frame *f;
3221 int face_id, c;
3223 OSStatus err;
3224 EventTargetRef target = NULL;
3225 XFontStruct *font = NULL;
3227 if (!mac_font_panel_visible_p ())
3228 return noErr;
3230 if (f)
3232 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
3234 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
3236 struct face *face;
3238 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
3239 face = FACE_FROM_ID (f, face_id);
3240 font = face->font;
3244 if (font == NULL)
3245 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
3246 else
3248 if (font->mac_fontnum != -1)
3250 FontSelectionQDStyle qd_style;
3252 qd_style.version = kFontSelectionQDStyleVersionZero;
3253 qd_style.instance.fontFamily = font->mac_fontnum;
3254 qd_style.instance.fontStyle = font->mac_fontface;
3255 qd_style.size = font->mac_fontsize;
3256 qd_style.hasColor = false;
3258 err = SetFontInfoForSelection (kFontSelectionQDType,
3259 1, &qd_style, target);
3261 else
3262 err = SetFontInfoForSelection (kFontSelectionATSUIType,
3263 1, &font->mac_style, target);
3266 return err;
3268 #endif /* USE_MAC_FONT_PANEL */
3271 /************************************************************************
3272 Event Handling
3273 ************************************************************************/
3275 /* Non-zero means that a HELP_EVENT has been generated since Emacs
3276 start. */
3278 static int any_help_event_p;
3280 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
3281 static Lisp_Object last_window;
3283 static Point saved_menu_event_location;
3285 extern struct frame *pending_autoraise_frame;
3287 extern FRAME_PTR last_mouse_glyph_frame;
3289 #ifdef __STDC__
3290 extern int volatile input_signal_count;
3291 #else
3292 extern int input_signal_count;
3293 #endif
3295 extern int mac_screen_config_changed;
3297 extern Lisp_Object Vmac_emulate_three_button_mouse;
3298 #if TARGET_API_MAC_CARBON
3299 extern int mac_wheel_button_is_mouse_2;
3300 extern int mac_pass_command_to_system;
3301 extern int mac_pass_control_to_system;
3302 #endif /* TARGET_API_MAC_CARBON */
3303 extern int mac_ready_for_apple_events;
3305 extern void mac_focus_changed P_ ((int, struct mac_display_info *,
3306 struct frame *, struct input_event *));
3307 extern int mac_get_emulated_btn P_ ((UInt32));
3308 extern int note_mouse_movement P_ ((FRAME_PTR, Point *));
3309 extern void mac_get_screen_info P_ ((struct mac_display_info *));
3311 /* The focus may have changed. Figure out if it is a real focus change,
3312 by checking both FocusIn/Out and Enter/LeaveNotify events.
3314 Returns FOCUS_IN_EVENT event in *BUFP. */
3316 static void
3317 x_detect_focus_change (dpyinfo, event, bufp)
3318 struct mac_display_info *dpyinfo;
3319 const EventRecord *event;
3320 struct input_event *bufp;
3322 struct frame *frame;
3324 frame = mac_window_to_frame ((WindowRef) event->message);
3325 if (! frame)
3326 return;
3328 /* On Mac, this is only called from focus events, so no switch needed. */
3329 mac_focus_changed ((event->modifiers & activeFlag),
3330 dpyinfo, frame, bufp);
3333 #if TARGET_API_MAC_CARBON
3334 /* Obtains the event modifiers from the event EVENTREF and then calls
3335 mac_to_emacs_modifiers. */
3337 static int
3338 mac_event_to_emacs_modifiers (EventRef eventRef)
3340 UInt32 mods = 0, class;
3342 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
3343 sizeof (UInt32), NULL, &mods);
3344 class = GetEventClass (eventRef);
3345 if (!NILP (Vmac_emulate_three_button_mouse)
3346 && (class == kEventClassMouse || class == kEventClassCommand))
3348 mods &= ~(optionKey | cmdKey);
3350 return mac_to_emacs_modifiers (mods, 0);
3353 /* Given an event REF, return the code to use for the mouse button
3354 code in the emacs input_event. */
3356 static int
3357 mac_get_mouse_btn (EventRef ref)
3359 EventMouseButton result = kEventMouseButtonPrimary;
3360 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
3361 sizeof (EventMouseButton), NULL, &result);
3362 switch (result)
3364 case kEventMouseButtonPrimary:
3365 if (NILP (Vmac_emulate_three_button_mouse))
3366 return 0;
3367 else {
3368 UInt32 mods = 0;
3369 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
3370 sizeof (UInt32), NULL, &mods);
3371 return mac_get_emulated_btn(mods);
3373 case kEventMouseButtonSecondary:
3374 return mac_wheel_button_is_mouse_2 ? 2 : 1;
3375 case kEventMouseButtonTertiary:
3376 case 4: /* 4 is the number for the mouse wheel button */
3377 return mac_wheel_button_is_mouse_2 ? 1 : 2;
3378 default:
3379 return 0;
3383 /* Normally, ConvertEventRefToEventRecord will correctly handle all
3384 events. However the click of the mouse wheel is not converted to a
3385 mouseDown or mouseUp event. Likewise for dead key events. This
3386 calls ConvertEventRefToEventRecord, but then checks to see if it is
3387 a mouse up/down, or a dead key Carbon event that has not been
3388 converted, and if so, converts it by hand (to be picked up in the
3389 XTread_socket loop). */
3390 static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
3392 OSStatus err;
3393 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
3394 EventKind action;
3396 if (result)
3397 return result;
3399 switch (GetEventClass (eventRef))
3401 case kEventClassMouse:
3402 switch (GetEventKind (eventRef))
3404 case kEventMouseDown:
3405 eventRec->what = mouseDown;
3406 result = 1;
3407 break;
3409 case kEventMouseUp:
3410 eventRec->what = mouseUp;
3411 result = 1;
3412 break;
3414 default:
3415 break;
3417 break;
3419 case kEventClassKeyboard:
3420 switch (GetEventKind (eventRef))
3422 case kEventRawKeyDown:
3423 action = keyDown;
3424 goto keystroke_common;
3425 case kEventRawKeyRepeat:
3426 action = autoKey;
3427 goto keystroke_common;
3428 case kEventRawKeyUp:
3429 action = keyUp;
3430 keystroke_common:
3432 unsigned char char_codes;
3433 UInt32 key_code;
3435 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
3436 typeChar, NULL, sizeof (char),
3437 NULL, &char_codes);
3438 if (err == noErr)
3439 err = GetEventParameter (eventRef, kEventParamKeyCode,
3440 typeUInt32, NULL, sizeof (UInt32),
3441 NULL, &key_code);
3442 if (err == noErr)
3444 eventRec->what = action;
3445 eventRec->message = char_codes | ((key_code & 0xff) << 8);
3446 result = 1;
3449 break;
3451 default:
3452 break;
3454 break;
3456 default:
3457 break;
3460 if (result)
3462 /* Need where and when. */
3463 UInt32 mods = 0;
3465 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
3466 NULL, sizeof (Point), NULL, &eventRec->where);
3467 /* Use two step process because new event modifiers are 32-bit
3468 and old are 16-bit. Currently, only loss is NumLock & Fn. */
3469 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
3470 NULL, sizeof (UInt32), NULL, &mods);
3471 eventRec->modifiers = mods;
3473 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
3476 return result;
3478 #endif /* TARGET_API_MAC_CARBON */
3480 #if !TARGET_API_MAC_CARBON
3481 static RgnHandle mouse_region = NULL;
3483 Boolean
3484 mac_wait_next_event (er, sleep_time, dequeue)
3485 EventRecord *er;
3486 UInt32 sleep_time;
3487 Boolean dequeue;
3489 static EventRecord er_buf = {nullEvent};
3490 UInt32 target_tick, current_tick;
3491 EventMask event_mask;
3493 if (mouse_region == NULL)
3494 mouse_region = NewRgn ();
3496 event_mask = everyEvent;
3497 if (!mac_ready_for_apple_events)
3498 event_mask -= highLevelEventMask;
3500 current_tick = TickCount ();
3501 target_tick = current_tick + sleep_time;
3503 if (er_buf.what == nullEvent)
3504 while (!WaitNextEvent (event_mask, &er_buf,
3505 target_tick - current_tick, mouse_region))
3507 current_tick = TickCount ();
3508 if (target_tick <= current_tick)
3509 return false;
3512 *er = er_buf;
3513 if (dequeue)
3514 er_buf.what = nullEvent;
3515 return true;
3517 #endif /* not TARGET_API_MAC_CARBON */
3519 #if TARGET_API_MAC_CARBON
3520 OSStatus
3521 mac_post_mouse_moved_event ()
3523 EventRef event = NULL;
3524 OSStatus err;
3526 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
3527 kEventAttributeNone, &event);
3528 if (err == noErr)
3530 Point mouse_pos;
3532 GetGlobalMouse (&mouse_pos);
3533 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
3534 sizeof (Point), &mouse_pos);
3536 if (err == noErr)
3538 UInt32 modifiers = GetCurrentKeyModifiers ();
3540 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
3541 sizeof (UInt32), &modifiers);
3543 if (err == noErr)
3544 err = PostEventToQueue (GetCurrentEventQueue (), event,
3545 kEventPriorityStandard);
3546 if (event)
3547 ReleaseEvent (event);
3549 return err;
3551 #endif
3553 #ifdef MAC_OSX
3554 /* Run the current run loop in the default mode until some input
3555 happens or TIMEOUT seconds passes unless it is negative. Return
3556 true if timeout occurs first. */
3558 Boolean
3559 mac_run_loop_run_once (timeout)
3560 EventTimeout timeout;
3562 #if USE_CG_DRAWING
3563 mac_prepare_for_quickdraw (NULL);
3564 #endif
3565 return (CFRunLoopRunInMode (kCFRunLoopDefaultMode,
3566 timeout >= 0 ? timeout : 100000, true)
3567 == kCFRunLoopRunTimedOut);
3569 #endif
3571 /* Emacs calls this whenever it wants to read an input event from the
3572 user. */
3575 XTread_socket (sd, expected, hold_quit)
3576 int sd, expected;
3577 struct input_event *hold_quit;
3579 struct input_event inev;
3580 int count = 0;
3581 #if TARGET_API_MAC_CARBON
3582 EventRef eventRef;
3583 EventTargetRef toolbox_dispatcher;
3584 #endif
3585 EventRecord er;
3586 struct mac_display_info *dpyinfo = &one_mac_display_info;
3588 if (interrupt_input_blocked)
3590 interrupt_input_pending = 1;
3591 return -1;
3594 interrupt_input_pending = 0;
3595 BLOCK_INPUT;
3597 /* So people can tell when we have read the available input. */
3598 input_signal_count++;
3600 ++handling_signal;
3602 #if TARGET_API_MAC_CARBON
3603 toolbox_dispatcher = GetEventDispatcherTarget ();
3605 while (
3606 #if USE_CG_DRAWING
3607 mac_prepare_for_quickdraw (NULL),
3608 #endif
3609 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
3610 kEventRemoveFromQueue, &eventRef))
3611 #else /* !TARGET_API_MAC_CARBON */
3612 while (mac_wait_next_event (&er, 0, true))
3613 #endif /* !TARGET_API_MAC_CARBON */
3615 int do_help = 0;
3616 struct frame *f;
3617 unsigned long timestamp;
3619 EVENT_INIT (inev);
3620 inev.kind = NO_EVENT;
3621 inev.arg = Qnil;
3623 #if TARGET_API_MAC_CARBON
3624 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
3626 if (!mac_convert_event_ref (eventRef, &er))
3627 goto OTHER;
3628 #else /* !TARGET_API_MAC_CARBON */
3629 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
3630 #endif /* !TARGET_API_MAC_CARBON */
3632 switch (er.what)
3634 case mouseDown:
3635 case mouseUp:
3637 WindowRef window_ptr;
3638 ControlPartCode part_code;
3639 int tool_bar_p = 0;
3641 #if TARGET_API_MAC_CARBON
3642 OSStatus err;
3644 /* This is needed to send mouse events like aqua window
3645 buttons to the correct handler. */
3646 read_socket_inev = &inev;
3647 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
3648 read_socket_inev = NULL;
3649 if (err != eventNotHandledErr)
3650 break;
3651 #endif
3652 last_mouse_glyph_frame = 0;
3654 if (dpyinfo->grabbed && last_mouse_frame
3655 && FRAME_LIVE_P (last_mouse_frame))
3657 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
3658 part_code = inContent;
3660 else
3662 part_code = FindWindow (er.where, &window_ptr);
3663 if (tip_window && window_ptr == tip_window)
3665 HideWindow (tip_window);
3666 part_code = FindWindow (er.where, &window_ptr);
3670 if (er.what != mouseDown
3671 && (part_code != inContent || dpyinfo->grabbed == 0))
3672 break;
3674 switch (part_code)
3676 case inMenuBar:
3677 f = mac_focus_frame (dpyinfo);
3678 saved_menu_event_location = er.where;
3679 inev.kind = MENU_BAR_ACTIVATE_EVENT;
3680 XSETFRAME (inev.frame_or_window, f);
3681 break;
3683 case inContent:
3684 if (
3685 #if TARGET_API_MAC_CARBON
3686 FrontNonFloatingWindow ()
3687 #else
3688 FrontWindow ()
3689 #endif
3690 != window_ptr
3691 || (mac_window_to_frame (window_ptr)
3692 != dpyinfo->x_focus_frame))
3693 SelectWindow (window_ptr);
3694 else
3696 ControlPartCode control_part_code;
3697 ControlRef ch;
3698 Point mouse_loc;
3699 #ifdef MAC_OSX
3700 ControlKind control_kind;
3701 #endif
3703 f = mac_window_to_frame (window_ptr);
3704 /* convert to local coordinates of new window */
3705 mouse_loc.h = (er.where.h
3706 - (f->left_pos
3707 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
3708 mouse_loc.v = (er.where.v
3709 - (f->top_pos
3710 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
3711 #if TARGET_API_MAC_CARBON
3712 ch = FindControlUnderMouse (mouse_loc, window_ptr,
3713 &control_part_code);
3714 #ifdef MAC_OSX
3715 if (ch)
3716 GetControlKind (ch, &control_kind);
3717 #endif
3718 #else
3719 control_part_code = FindControl (mouse_loc, window_ptr,
3720 &ch);
3721 #endif
3723 #if TARGET_API_MAC_CARBON
3724 inev.code = mac_get_mouse_btn (eventRef);
3725 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
3726 #else
3727 inev.code = mac_get_emulated_btn (er.modifiers);
3728 inev.modifiers = mac_to_emacs_modifiers (er.modifiers, 0);
3729 #endif
3730 XSETINT (inev.x, mouse_loc.h);
3731 XSETINT (inev.y, mouse_loc.v);
3733 if ((dpyinfo->grabbed && tracked_scroll_bar)
3734 || (ch != 0
3735 #ifndef USE_TOOLKIT_SCROLL_BARS
3736 /* control_part_code becomes kControlNoPart if
3737 a progress indicator is clicked. */
3738 && control_part_code != kControlNoPart
3739 #else /* USE_TOOLKIT_SCROLL_BARS */
3740 #ifdef MAC_OSX
3741 && control_kind.kind == kControlKindScrollBar
3742 #endif /* MAC_OSX */
3743 #endif /* USE_TOOLKIT_SCROLL_BARS */
3746 struct scroll_bar *bar;
3748 if (dpyinfo->grabbed && tracked_scroll_bar)
3750 bar = tracked_scroll_bar;
3751 #ifndef USE_TOOLKIT_SCROLL_BARS
3752 control_part_code = kControlIndicatorPart;
3753 #endif
3755 else
3756 bar = (struct scroll_bar *) GetControlReference (ch);
3757 #ifdef USE_TOOLKIT_SCROLL_BARS
3758 /* Make the "Ctrl-Mouse-2 splits window" work
3759 for toolkit scroll bars. */
3760 if (inev.modifiers & ctrl_modifier)
3761 x_scroll_bar_handle_click (bar, control_part_code,
3762 &er, &inev);
3763 else if (er.what == mouseDown)
3764 x_scroll_bar_handle_press (bar, control_part_code,
3765 mouse_loc, &inev);
3766 else
3767 x_scroll_bar_handle_release (bar, &inev);
3768 #else /* not USE_TOOLKIT_SCROLL_BARS */
3769 x_scroll_bar_handle_click (bar, control_part_code,
3770 &er, &inev);
3771 if (er.what == mouseDown
3772 && control_part_code == kControlIndicatorPart)
3773 tracked_scroll_bar = bar;
3774 else
3775 tracked_scroll_bar = NULL;
3776 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3778 else
3780 Lisp_Object window;
3781 int x = mouse_loc.h;
3782 int y = mouse_loc.v;
3784 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
3785 if (EQ (window, f->tool_bar_window))
3787 if (er.what == mouseDown)
3788 handle_tool_bar_click (f, x, y, 1, 0);
3789 else
3790 handle_tool_bar_click (f, x, y, 0,
3791 inev.modifiers);
3792 tool_bar_p = 1;
3794 else
3796 XSETFRAME (inev.frame_or_window, f);
3797 inev.kind = MOUSE_CLICK_EVENT;
3801 if (er.what == mouseDown)
3803 dpyinfo->grabbed |= (1 << inev.code);
3804 last_mouse_frame = f;
3806 if (!tool_bar_p)
3807 last_tool_bar_item = -1;
3809 else
3811 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
3812 /* If a button is released though it was not
3813 previously pressed, that would be because
3814 of multi-button emulation. */
3815 dpyinfo->grabbed = 0;
3816 else
3817 dpyinfo->grabbed &= ~(1 << inev.code);
3820 /* Ignore any mouse motion that happened before
3821 this event; any subsequent mouse-movement Emacs
3822 events should reflect only motion after the
3823 ButtonPress. */
3824 if (f != 0)
3825 f->mouse_moved = 0;
3827 #ifdef USE_TOOLKIT_SCROLL_BARS
3828 if (inev.kind == MOUSE_CLICK_EVENT
3829 || (inev.kind == SCROLL_BAR_CLICK_EVENT
3830 && (inev.modifiers & ctrl_modifier)))
3831 #endif
3832 switch (er.what)
3834 case mouseDown:
3835 inev.modifiers |= down_modifier;
3836 break;
3837 case mouseUp:
3838 inev.modifiers |= up_modifier;
3839 break;
3842 break;
3844 case inDrag:
3845 #if TARGET_API_MAC_CARBON
3846 case inProxyIcon:
3847 if (IsWindowPathSelectClick (window_ptr, &er))
3849 WindowPathSelect (window_ptr, NULL, NULL);
3850 break;
3852 if (part_code == inProxyIcon
3853 && (TrackWindowProxyDrag (window_ptr, er.where)
3854 != errUserWantsToDragWindow))
3855 break;
3856 DragWindow (window_ptr, er.where, NULL);
3857 #else /* not TARGET_API_MAC_CARBON */
3858 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
3859 /* Update the frame parameters. */
3861 struct frame *f = mac_window_to_frame (window_ptr);
3863 if (f && !f->async_iconified)
3864 mac_handle_origin_change (f);
3866 #endif /* not TARGET_API_MAC_CARBON */
3867 break;
3869 case inGoAway:
3870 if (TrackGoAway (window_ptr, er.where))
3872 inev.kind = DELETE_WINDOW_EVENT;
3873 XSETFRAME (inev.frame_or_window,
3874 mac_window_to_frame (window_ptr));
3876 break;
3878 /* window resize handling added --ben */
3879 case inGrow:
3880 do_grow_window (window_ptr, &er);
3881 break;
3883 /* window zoom handling added --ben */
3884 case inZoomIn:
3885 case inZoomOut:
3886 if (TrackBox (window_ptr, er.where, part_code))
3887 do_zoom_window (window_ptr, part_code);
3888 break;
3890 #if USE_MAC_TOOLBAR
3891 case inStructure:
3893 OSStatus err;
3894 HIViewRef ch;
3896 if (FrontNonFloatingWindow () != window_ptr)
3897 SelectWindow (window_ptr);
3899 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
3900 eventRef, &ch);
3901 /* This doesn't work on Mac OS X 10.2. */
3902 if (err == noErr)
3903 HIViewClick (ch, eventRef);
3905 break;
3906 #endif /* USE_MAC_TOOLBAR */
3908 default:
3909 break;
3912 break;
3914 #if !TARGET_API_MAC_CARBON
3915 case updateEvt:
3916 do_window_update ((WindowRef) er.message);
3917 break;
3918 #endif
3920 case osEvt:
3921 #if TARGET_API_MAC_CARBON
3922 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
3923 != eventNotHandledErr)
3924 break;
3925 #endif
3926 switch ((er.message >> 24) & 0x000000FF)
3928 #if USE_MAC_TSM
3929 case suspendResumeMessage:
3930 if (er.message & resumeFlag)
3931 mac_tsm_resume ();
3932 else
3933 mac_tsm_suspend ();
3934 break;
3935 #endif
3937 case mouseMovedMessage:
3938 #if !TARGET_API_MAC_CARBON
3939 SetRectRgn (mouse_region, er.where.h, er.where.v,
3940 er.where.h + 1, er.where.v + 1);
3941 #endif
3942 previous_help_echo_string = help_echo_string;
3943 help_echo_string = Qnil;
3945 if (dpyinfo->grabbed && last_mouse_frame
3946 && FRAME_LIVE_P (last_mouse_frame))
3947 f = last_mouse_frame;
3948 else
3949 f = dpyinfo->x_focus_frame;
3951 if (dpyinfo->mouse_face_hidden)
3953 dpyinfo->mouse_face_hidden = 0;
3954 clear_mouse_face (dpyinfo);
3957 if (f)
3959 WindowRef wp = FRAME_MAC_WINDOW (f);
3960 Point mouse_pos;
3962 mouse_pos.h = (er.where.h
3963 - (f->left_pos
3964 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
3965 mouse_pos.v = (er.where.v
3966 - (f->top_pos
3967 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
3968 if (dpyinfo->grabbed && tracked_scroll_bar)
3969 #ifdef USE_TOOLKIT_SCROLL_BARS
3970 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
3971 mouse_pos, &inev);
3972 #else /* not USE_TOOLKIT_SCROLL_BARS */
3973 x_scroll_bar_note_movement (tracked_scroll_bar,
3974 mouse_pos.v
3975 - XINT (tracked_scroll_bar->top),
3976 er.when * (1000 / 60));
3977 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3978 else
3980 /* Generate SELECT_WINDOW_EVENTs when needed. */
3981 if (!NILP (Vmouse_autoselect_window))
3983 Lisp_Object window;
3985 window = window_from_coordinates (f,
3986 mouse_pos.h,
3987 mouse_pos.v,
3988 0, 0, 0, 0);
3990 /* Window will be selected only when it is
3991 not selected now and last mouse movement
3992 event was not in it. Minibuffer window
3993 will be selected only when it is active. */
3994 if (WINDOWP (window)
3995 && !EQ (window, last_window)
3996 && !EQ (window, selected_window)
3997 /* For click-to-focus window managers
3998 create event iff we don't leave the
3999 selected frame. */
4000 && (focus_follows_mouse
4001 || (EQ (XWINDOW (window)->frame,
4002 XWINDOW (selected_window)->frame))))
4004 inev.kind = SELECT_WINDOW_EVENT;
4005 inev.frame_or_window = window;
4008 last_window=window;
4010 if (!note_mouse_movement (f, &mouse_pos))
4011 help_echo_string = previous_help_echo_string;
4012 #if USE_MAC_TOOLBAR
4013 else
4014 mac_tool_bar_note_mouse_movement (f, eventRef);
4015 #endif
4019 /* If the contents of the global variable
4020 help_echo_string has changed, generate a
4021 HELP_EVENT. */
4022 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
4023 do_help = 1;
4024 break;
4026 break;
4028 case activateEvt:
4030 WindowRef window_ptr = (WindowRef) er.message;
4031 OSErr err;
4032 ControlRef root_control;
4034 if (window_ptr == tip_window)
4036 HideWindow (tip_window);
4037 break;
4040 if (!is_emacs_window (window_ptr))
4041 goto OTHER;
4043 f = mac_window_to_frame (window_ptr);
4045 if ((er.modifiers & activeFlag) != 0)
4047 /* A window has been activated */
4048 Point mouse_loc;
4050 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
4051 if (err == noErr)
4052 ActivateControl (root_control);
4054 x_detect_focus_change (dpyinfo, &er, &inev);
4056 mouse_loc.h = (er.where.h
4057 - (f->left_pos
4058 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
4059 mouse_loc.v = (er.where.v
4060 - (f->top_pos
4061 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
4062 /* Window-activated event counts as mouse movement,
4063 so update things that depend on mouse position. */
4064 note_mouse_movement (f, &mouse_loc);
4066 else
4068 /* A window has been deactivated */
4069 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
4070 if (err == noErr)
4071 DeactivateControl (root_control);
4073 #ifdef USE_TOOLKIT_SCROLL_BARS
4074 if (dpyinfo->grabbed && tracked_scroll_bar)
4076 struct input_event event;
4078 EVENT_INIT (event);
4079 event.kind = NO_EVENT;
4080 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
4081 if (event.kind != NO_EVENT)
4083 event.timestamp = timestamp;
4084 kbd_buffer_store_event_hold (&event, hold_quit);
4085 count++;
4088 #endif
4089 dpyinfo->grabbed = 0;
4091 x_detect_focus_change (dpyinfo, &er, &inev);
4093 if (f == dpyinfo->mouse_face_mouse_frame)
4095 /* If we move outside the frame, then we're
4096 certainly no longer on any text in the
4097 frame. */
4098 clear_mouse_face (dpyinfo);
4099 dpyinfo->mouse_face_mouse_frame = 0;
4102 /* Generate a nil HELP_EVENT to cancel a help-echo.
4103 Do it only if there's something to cancel.
4104 Otherwise, the startup message is cleared when the
4105 mouse leaves the frame. */
4106 if (any_help_event_p)
4107 do_help = -1;
4110 break;
4112 case keyDown:
4113 case keyUp:
4114 case autoKey:
4115 ObscureCursor ();
4117 f = mac_focus_frame (dpyinfo);
4118 XSETFRAME (inev.frame_or_window, f);
4120 /* If mouse-highlight is an integer, input clears out mouse
4121 highlighting. */
4122 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
4123 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
4125 clear_mouse_face (dpyinfo);
4126 dpyinfo->mouse_face_hidden = 1;
4130 UInt32 modifiers = er.modifiers, mapped_modifiers;
4131 UInt32 key_code = (er.message & keyCodeMask) >> 8;
4133 #ifdef MAC_OSX
4134 GetEventParameter (eventRef, kEventParamKeyModifiers,
4135 typeUInt32, NULL,
4136 sizeof (UInt32), NULL, &modifiers);
4137 #endif
4138 mapped_modifiers = mac_mapped_modifiers (modifiers, key_code);
4140 #if TARGET_API_MAC_CARBON
4141 if (!(mapped_modifiers
4142 & ~(mac_pass_command_to_system ? cmdKey : 0)
4143 & ~(mac_pass_control_to_system ? controlKey : 0)))
4144 goto OTHER;
4145 else
4146 #endif
4147 if (er.what != keyUp)
4148 do_keystroke (er.what, er.message & charCodeMask,
4149 key_code, modifiers, timestamp, &inev);
4151 break;
4153 case kHighLevelEvent:
4154 AEProcessAppleEvent (&er);
4155 break;
4157 default:
4158 OTHER:
4159 #if TARGET_API_MAC_CARBON
4161 OSStatus err;
4163 read_socket_inev = &inev;
4164 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
4165 read_socket_inev = NULL;
4167 #endif
4168 break;
4170 #if TARGET_API_MAC_CARBON
4171 ReleaseEvent (eventRef);
4172 #endif
4174 if (inev.kind != NO_EVENT)
4176 inev.timestamp = timestamp;
4177 kbd_buffer_store_event_hold (&inev, hold_quit);
4178 count++;
4181 if (do_help
4182 && !(hold_quit && hold_quit->kind != NO_EVENT))
4184 Lisp_Object frame;
4186 if (f)
4187 XSETFRAME (frame, f);
4188 else
4189 frame = Qnil;
4191 if (do_help > 0)
4193 any_help_event_p = 1;
4194 gen_help_event (help_echo_string, frame, help_echo_window,
4195 help_echo_object, help_echo_pos);
4197 else
4199 help_echo_string = Qnil;
4200 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
4202 count++;
4206 /* If the focus was just given to an autoraising frame,
4207 raise it now. */
4208 /* ??? This ought to be able to handle more than one such frame. */
4209 if (pending_autoraise_frame)
4211 x_raise_frame (pending_autoraise_frame);
4212 pending_autoraise_frame = 0;
4215 if (mac_screen_config_changed)
4217 mac_get_screen_info (dpyinfo);
4218 mac_screen_config_changed = 0;
4221 #if !TARGET_API_MAC_CARBON
4222 /* Check which frames are still visible. We do this here because
4223 there doesn't seem to be any direct notification from the Window
4224 Manager that the visibility of a window has changed (at least,
4225 not in all cases). */
4227 Lisp_Object tail, frame;
4229 FOR_EACH_FRAME (tail, frame)
4231 struct frame *f = XFRAME (frame);
4233 /* The tooltip has been drawn already. Avoid the
4234 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
4235 if (EQ (frame, tip_frame))
4236 continue;
4238 if (FRAME_MAC_P (f))
4239 mac_handle_visibility_change (f);
4242 #endif
4244 --handling_signal;
4245 UNBLOCK_INPUT;
4246 return count;
4250 /***********************************************************************
4251 Busy cursor
4252 ***********************************************************************/
4254 #if TARGET_API_MAC_CARBON
4255 /* Show the spinning progress indicator for the frame F. Create it if
4256 it doesn't exist yet. */
4258 void
4259 mac_show_hourglass (f)
4260 struct frame *f;
4262 #if USE_CG_DRAWING
4263 mac_prepare_for_quickdraw (f);
4264 #endif
4265 if (!f->output_data.mac->hourglass_control)
4267 Window w = FRAME_MAC_WINDOW (f);
4268 Rect r;
4269 ControlRef c;
4271 GetWindowPortBounds (w, &r);
4272 r.left = r.right - HOURGLASS_WIDTH;
4273 r.bottom = r.top + HOURGLASS_HEIGHT;
4274 if (CreateChasingArrowsControl (w, &r, &c) == noErr)
4275 f->output_data.mac->hourglass_control = c;
4278 if (f->output_data.mac->hourglass_control)
4279 ShowControl (f->output_data.mac->hourglass_control);
4282 /* Hide the spinning progress indicator for the frame F. Do nothing
4283 it doesn't exist yet. */
4285 void
4286 mac_hide_hourglass (f)
4287 struct frame *f;
4289 if (f->output_data.mac->hourglass_control)
4291 #if USE_CG_DRAWING
4292 mac_prepare_for_quickdraw (f);
4293 #endif
4294 HideControl (f->output_data.mac->hourglass_control);
4298 /* Reposition the spinning progress indicator for the frame F. Do
4299 nothing it doesn't exist yet. */
4301 void
4302 mac_reposition_hourglass (f)
4303 struct frame *f;
4305 if (f->output_data.mac->hourglass_control)
4307 #if USE_CG_DRAWING
4308 mac_prepare_for_quickdraw (f);
4309 #endif
4310 MoveControl (f->output_data.mac->hourglass_control,
4311 FRAME_PIXEL_WIDTH (f) - HOURGLASS_WIDTH, 0);
4314 #endif /* TARGET_API_MAC_CARBON */
4317 /***********************************************************************
4318 File selection dialog
4319 ***********************************************************************/
4321 #if TARGET_API_MAC_CARBON
4322 extern Lisp_Object Qfile_name_history;
4324 static pascal void mac_nav_event_callback P_ ((NavEventCallbackMessage,
4325 NavCBRecPtr, void *));
4327 /* The actual implementation of Fx_file_dialog. */
4329 Lisp_Object
4330 mac_file_dialog (prompt, dir, default_filename, mustmatch, only_dir_p)
4331 Lisp_Object prompt, dir, default_filename, mustmatch, only_dir_p;
4333 Lisp_Object file = Qnil;
4334 int count = SPECPDL_INDEX ();
4335 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
4336 char filename[MAXPATHLEN];
4337 static NavEventUPP mac_nav_event_callbackUPP = NULL;
4339 check_mac ();
4341 GCPRO6 (prompt, dir, default_filename, mustmatch, file, only_dir_p);
4342 CHECK_STRING (prompt);
4343 CHECK_STRING (dir);
4345 /* Create the dialog with PROMPT as title, using DIR as initial
4346 directory and using "*" as pattern. */
4347 dir = Fexpand_file_name (dir, Qnil);
4350 OSStatus status;
4351 NavDialogCreationOptions options;
4352 NavDialogRef dialogRef;
4353 NavTypeListHandle fileTypes = NULL;
4354 NavUserAction userAction;
4355 CFStringRef message=NULL, saveName = NULL;
4357 BLOCK_INPUT;
4358 /* No need for a callback function because we are modal */
4359 NavGetDefaultDialogCreationOptions(&options);
4360 options.modality = kWindowModalityAppModal;
4361 options.location.h = options.location.v = -1;
4362 options.optionFlags = kNavDefaultNavDlogOptions;
4363 options.optionFlags |= kNavAllFilesInPopup; /* All files allowed */
4364 options.optionFlags |= kNavSelectAllReadableItem;
4365 options.optionFlags &= ~kNavAllowMultipleFiles;
4366 if (!NILP(prompt))
4368 message = cfstring_create_with_string (prompt);
4369 options.message = message;
4371 /* Don't set the application, let it use default.
4372 options.clientName = CFSTR ("Emacs");
4375 if (mac_nav_event_callbackUPP == NULL)
4376 mac_nav_event_callbackUPP = NewNavEventUPP (mac_nav_event_callback);
4378 if (!NILP (only_dir_p))
4379 status = NavCreateChooseFolderDialog(&options, mac_nav_event_callbackUPP,
4380 NULL, NULL, &dialogRef);
4381 else if (NILP (mustmatch))
4383 /* This is a save dialog */
4384 options.optionFlags |= kNavDontConfirmReplacement;
4385 options.actionButtonLabel = CFSTR ("Ok");
4386 options.windowTitle = CFSTR ("Enter name");
4388 if (STRINGP (default_filename))
4390 Lisp_Object utf8 = ENCODE_UTF_8 (default_filename);
4391 char *begPtr = SDATA(utf8);
4392 char *filePtr = begPtr + SBYTES(utf8);
4393 while (filePtr != begPtr && !IS_DIRECTORY_SEP(filePtr[-1]))
4394 filePtr--;
4395 saveName = cfstring_create_with_utf8_cstring (filePtr);
4396 options.saveFileName = saveName;
4397 options.optionFlags |= kNavSelectDefaultLocation;
4399 status = NavCreatePutFileDialog(&options,
4400 'TEXT', kNavGenericSignature,
4401 mac_nav_event_callbackUPP, NULL,
4402 &dialogRef);
4404 else
4406 /* This is an open dialog*/
4407 status = NavCreateChooseFileDialog(&options, fileTypes,
4408 mac_nav_event_callbackUPP, NULL,
4409 NULL, NULL, &dialogRef);
4412 /* Set the default location and continue*/
4413 if (status == noErr)
4415 Lisp_Object encoded_dir = ENCODE_FILE (dir);
4416 AEDesc defLocAed;
4418 status = AECreateDesc (TYPE_FILE_NAME, SDATA (encoded_dir),
4419 SBYTES (encoded_dir), &defLocAed);
4420 if (status == noErr)
4422 NavCustomControl(dialogRef, kNavCtlSetLocation, (void*) &defLocAed);
4423 AEDisposeDesc(&defLocAed);
4425 status = NavDialogRun(dialogRef);
4428 if (saveName) CFRelease(saveName);
4429 if (message) CFRelease(message);
4431 if (status == noErr) {
4432 userAction = NavDialogGetUserAction(dialogRef);
4433 switch (userAction)
4435 case kNavUserActionNone:
4436 case kNavUserActionCancel:
4437 break; /* Treat cancel like C-g */
4438 case kNavUserActionOpen:
4439 case kNavUserActionChoose:
4440 case kNavUserActionSaveAs:
4442 NavReplyRecord reply;
4443 Size len;
4445 status = NavDialogGetReply(dialogRef, &reply);
4446 if (status != noErr)
4447 break;
4448 status = AEGetNthPtr (&reply.selection, 1, TYPE_FILE_NAME,
4449 NULL, NULL, filename,
4450 sizeof (filename) - 1, &len);
4451 if (status == noErr)
4453 len = min (len, sizeof (filename) - 1);
4454 filename[len] = '\0';
4455 if (reply.saveFileName)
4457 /* If it was a saved file, we need to add the file name */
4458 if (len && len < sizeof (filename) - 1
4459 && filename[len-1] != '/')
4460 filename[len++] = '/';
4461 CFStringGetCString(reply.saveFileName, filename+len,
4462 sizeof (filename) - len,
4463 #ifdef MAC_OSX
4464 kCFStringEncodingUTF8
4465 #else
4466 CFStringGetSystemEncoding ()
4467 #endif
4470 file = DECODE_FILE (make_unibyte_string (filename,
4471 strlen (filename)));
4473 NavDisposeReply(&reply);
4475 break;
4477 NavDialogDispose(dialogRef);
4478 UNBLOCK_INPUT;
4480 else {
4481 UNBLOCK_INPUT;
4482 /* Fall back on minibuffer if there was a problem */
4483 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
4484 dir, mustmatch, dir, Qfile_name_history,
4485 default_filename, Qnil);
4489 UNGCPRO;
4491 /* Make "Cancel" equivalent to C-g. */
4492 if (NILP (file))
4493 Fsignal (Qquit, Qnil);
4495 return unbind_to (count, file);
4498 /* Need to register some event callback function for enabling drag and
4499 drop in Navigation Service dialogs. */
4500 static pascal void
4501 mac_nav_event_callback (selector, parms, data)
4502 NavEventCallbackMessage selector;
4503 NavCBRecPtr parms;
4504 void *data;
4507 #endif
4510 /************************************************************************
4511 Menu
4512 ************************************************************************/
4514 #if !TARGET_API_MAC_CARBON
4515 #include <MacTypes.h>
4516 #include <Menus.h>
4517 #include <Quickdraw.h>
4518 #include <ToolUtils.h>
4519 #include <Fonts.h>
4520 #include <Controls.h>
4521 #include <Windows.h>
4522 #include <Events.h>
4523 #if defined (__MRC__) || (__MSL__ >= 0x6000)
4524 #include <ControlDefinitions.h>
4525 #endif
4526 #endif /* not TARGET_API_MAC_CARBON */
4528 extern int menu_item_selection;
4529 extern int popup_activated_flag;
4530 extern int name_is_separator P_ ((const char *));
4531 extern void find_and_call_menu_selection P_ ((FRAME_PTR, int, Lisp_Object,
4532 void *));
4533 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
4535 enum mac_menu_kind { /* Menu ID range */
4536 MAC_MENU_APPLE, /* 0 (Reserved by Apple) */
4537 MAC_MENU_MENU_BAR, /* 1 .. 233 */
4538 MAC_MENU_M_APPLE, /* 234 (== M_APPLE) */
4539 MAC_MENU_POPUP, /* 235 */
4540 MAC_MENU_DRIVER, /* 236 .. 255 (Reserved) */
4541 MAC_MENU_MENU_BAR_SUB, /* 256 .. 16383 */
4542 MAC_MENU_POPUP_SUB, /* 16384 .. 32767 */
4543 MAC_MENU_END /* 32768 */
4546 static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
4548 static int fill_menu P_ ((MenuRef, widget_value *, enum mac_menu_kind, int));
4549 static void dispose_menus P_ ((enum mac_menu_kind, int));
4551 #if !TARGET_API_MAC_CARBON
4552 static void
4553 do_apple_menu (SInt16 menu_item)
4555 Str255 item_name;
4556 SInt16 da_driver_refnum;
4558 if (menu_item == I_ABOUT)
4559 NoteAlert (ABOUT_ALERT_ID, NULL);
4560 else
4562 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
4563 da_driver_refnum = OpenDeskAcc (item_name);
4566 #endif /* !TARGET_API_MAC_CARBON */
4568 /* Activate the menu bar of frame F.
4569 This is called from keyboard.c when it gets the
4570 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
4572 To activate the menu bar, we use the button-press event location
4573 that was saved in saved_menu_event_location.
4575 But first we recompute the menu bar contents (the whole tree).
4577 The reason for saving the button event until here, instead of
4578 passing it to the toolkit right away, is that we can safely
4579 execute Lisp code. */
4581 void
4582 x_activate_menubar (f)
4583 FRAME_PTR f;
4585 SInt32 menu_choice;
4586 SInt16 menu_id, menu_item;
4588 set_frame_menubar (f, 0, 1);
4589 BLOCK_INPUT;
4591 popup_activated_flag = 1;
4592 menu_choice = MenuSelect (saved_menu_event_location);
4593 popup_activated_flag = 0;
4594 menu_id = HiWord (menu_choice);
4595 menu_item = LoWord (menu_choice);
4597 #if !TARGET_API_MAC_CARBON
4598 if (menu_id == min_menu_id[MAC_MENU_M_APPLE])
4599 do_apple_menu (menu_item);
4600 else
4601 #endif
4602 if (menu_id)
4604 MenuRef menu = GetMenuRef (menu_id);
4606 if (menu)
4608 UInt32 refcon;
4610 GetMenuItemRefCon (menu, menu_item, &refcon);
4611 find_and_call_menu_selection (f, f->menu_bar_items_used,
4612 f->menu_bar_vector, (void *) refcon);
4616 HiliteMenu (0);
4618 UNBLOCK_INPUT;
4621 #if TARGET_API_MAC_CARBON
4622 extern Lisp_Object Vshow_help_function;
4624 static Lisp_Object
4625 restore_show_help_function (old_show_help_function)
4626 Lisp_Object old_show_help_function;
4628 Vshow_help_function = old_show_help_function;
4630 return Qnil;
4633 static pascal OSStatus
4634 menu_target_item_handler (next_handler, event, data)
4635 EventHandlerCallRef next_handler;
4636 EventRef event;
4637 void *data;
4639 OSStatus err;
4640 MenuRef menu;
4641 MenuItemIndex menu_item;
4642 Lisp_Object help;
4643 GrafPtr port;
4644 int specpdl_count = SPECPDL_INDEX ();
4646 /* Don't be bothered with the overflowed toolbar items menu. */
4647 if (!popup_activated ())
4648 return eventNotHandledErr;
4650 err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef,
4651 NULL, sizeof (MenuRef), NULL, &menu);
4652 if (err == noErr)
4653 err = GetEventParameter (event, kEventParamMenuItemIndex,
4654 typeMenuItemIndex, NULL,
4655 sizeof (MenuItemIndex), NULL, &menu_item);
4656 if (err == noErr)
4657 err = GetMenuItemProperty (menu, menu_item,
4658 MAC_EMACS_CREATOR_CODE, 'help',
4659 sizeof (Lisp_Object), NULL, &help);
4660 if (err != noErr)
4661 help = Qnil;
4663 /* Temporarily bind Vshow_help_function to Qnil because we don't
4664 want tooltips during menu tracking. */
4665 record_unwind_protect (restore_show_help_function, Vshow_help_function);
4666 Vshow_help_function = Qnil;
4667 GetPort (&port);
4668 show_help_echo (help, Qnil, Qnil, Qnil, 1);
4669 SetPort (port);
4670 unbind_to (specpdl_count, Qnil);
4672 return err == noErr ? noErr : eventNotHandledErr;
4675 /* Showing help echo string during menu tracking. */
4677 static OSStatus
4678 install_menu_target_item_handler ()
4680 static const EventTypeSpec specs[] =
4681 {{kEventClassMenu, kEventMenuTargetItem}};
4683 return InstallApplicationEventHandler (NewEventHandlerUPP
4684 (menu_target_item_handler),
4685 GetEventTypeCount (specs),
4686 specs, NULL, NULL);
4688 #endif /* TARGET_API_MAC_CARBON */
4690 /* Event handler function that pops down a menu on C-g. We can only pop
4691 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
4693 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4694 static pascal OSStatus
4695 menu_quit_handler (nextHandler, theEvent, userData)
4696 EventHandlerCallRef nextHandler;
4697 EventRef theEvent;
4698 void* userData;
4700 OSStatus err;
4701 UInt32 keyCode;
4702 UInt32 keyModifiers;
4704 err = GetEventParameter (theEvent, kEventParamKeyCode,
4705 typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
4707 if (err == noErr)
4708 err = GetEventParameter (theEvent, kEventParamKeyModifiers,
4709 typeUInt32, NULL, sizeof(UInt32),
4710 NULL, &keyModifiers);
4712 if (err == noErr && mac_quit_char_key_p (keyModifiers, keyCode))
4714 MenuRef menu = userData != 0
4715 ? (MenuRef)userData : AcquireRootMenu ();
4717 CancelMenuTracking (menu, true, 0);
4718 if (!userData) ReleaseMenu (menu);
4719 return noErr;
4722 return CallNextEventHandler (nextHandler, theEvent);
4724 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4726 /* Add event handler to all menus that belong to KIND so we can detect
4727 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
4728 when C-g is detected. NULL means the menu bar. If
4729 CancelMenuTracking isn't available, do nothing. */
4731 static void
4732 install_menu_quit_handler (kind, root_menu)
4733 enum mac_menu_kind kind;
4734 MenuRef root_menu;
4736 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4737 static const EventTypeSpec typesList[] =
4738 {{kEventClassKeyboard, kEventRawKeyDown}};
4739 int id;
4741 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
4742 if (CancelMenuTracking == NULL)
4743 return;
4744 #endif
4745 for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++)
4747 MenuRef menu = GetMenuRef (id);
4749 if (menu == NULL)
4750 break;
4751 InstallMenuEventHandler (menu, menu_quit_handler,
4752 GetEventTypeCount (typesList),
4753 typesList, root_menu, NULL);
4755 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4758 static Lisp_Object
4759 pop_down_menu (arg)
4760 Lisp_Object arg;
4762 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
4763 FRAME_PTR f = p->pointer;
4764 MenuRef menu = GetMenuRef (min_menu_id[MAC_MENU_POPUP]);
4766 BLOCK_INPUT;
4768 /* Must reset this manually because the button release event is not
4769 passed to Emacs event loop. */
4770 FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0;
4772 /* delete all menus */
4773 dispose_menus (MAC_MENU_POPUP_SUB, 0);
4774 DeleteMenu (min_menu_id[MAC_MENU_POPUP]);
4775 DisposeMenu (menu);
4777 UNBLOCK_INPUT;
4779 return Qnil;
4782 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop
4783 until the menu pops down. Return the selection. */
4785 void
4786 create_and_show_popup_menu (f, first_wv, x, y, for_click)
4787 FRAME_PTR f;
4788 widget_value *first_wv;
4789 int x;
4790 int y;
4791 int for_click;
4793 int result = 0;
4794 MenuRef menu = NewMenu (min_menu_id[MAC_MENU_POPUP], "\p");
4795 int menu_item_choice;
4796 int specpdl_count = SPECPDL_INDEX ();
4798 InsertMenu (menu, -1);
4799 fill_menu (menu, first_wv->contents, MAC_MENU_POPUP_SUB,
4800 min_menu_id[MAC_MENU_POPUP_SUB]);
4802 /* Add event handler so we can detect C-g. */
4803 install_menu_quit_handler (MAC_MENU_POPUP, menu);
4804 install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu);
4806 record_unwind_protect (pop_down_menu, make_save_value (f, 0));
4808 /* Adjust coordinates to be root-window-relative. */
4809 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
4810 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
4812 /* Display the menu. */
4813 popup_activated_flag = 1;
4814 menu_item_choice = PopUpMenuSelect (menu, y, x, 0);
4815 popup_activated_flag = 0;
4817 /* Get the refcon to find the correct item */
4818 if (menu_item_choice)
4820 MenuRef sel_menu = GetMenuRef (HiWord (menu_item_choice));
4822 if (sel_menu)
4823 GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice),
4824 (UInt32 *) &result);
4827 unbind_to (specpdl_count, Qnil);
4829 menu_item_selection = result;
4832 static void
4833 add_menu_item (menu, pos, wv)
4834 MenuRef menu;
4835 int pos;
4836 widget_value *wv;
4838 #if TARGET_API_MAC_CARBON
4839 CFStringRef item_name;
4840 #else
4841 Str255 item_name;
4842 #endif
4844 if (name_is_separator (wv->name))
4845 AppendMenu (menu, "\p-");
4846 else
4848 AppendMenu (menu, "\pX");
4850 #if TARGET_API_MAC_CARBON
4851 item_name = cfstring_create_with_utf8_cstring (wv->name);
4853 if (wv->key != NULL)
4855 CFStringRef name, key;
4857 name = item_name;
4858 key = cfstring_create_with_utf8_cstring (wv->key);
4859 item_name = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@ %@"),
4860 name, key);
4861 CFRelease (name);
4862 CFRelease (key);
4865 SetMenuItemTextWithCFString (menu, pos, item_name);
4866 CFRelease (item_name);
4868 if (wv->enabled)
4869 EnableMenuItem (menu, pos);
4870 else
4871 DisableMenuItem (menu, pos);
4873 if (STRINGP (wv->help))
4874 SetMenuItemProperty (menu, pos, MAC_EMACS_CREATOR_CODE, 'help',
4875 sizeof (Lisp_Object), &wv->help);
4876 #else /* ! TARGET_API_MAC_CARBON */
4877 item_name[sizeof (item_name) - 1] = '\0';
4878 strncpy (item_name, wv->name, sizeof (item_name) - 1);
4879 if (wv->key != NULL)
4881 int len = strlen (item_name);
4883 strncpy (item_name + len, " ", sizeof (item_name) - 1 - len);
4884 len = strlen (item_name);
4885 strncpy (item_name + len, wv->key, sizeof (item_name) - 1 - len);
4887 c2pstr (item_name);
4888 SetMenuItemText (menu, pos, item_name);
4890 if (wv->enabled)
4891 EnableItem (menu, pos);
4892 else
4893 DisableItem (menu, pos);
4894 #endif /* ! TARGET_API_MAC_CARBON */
4896 /* Draw radio buttons and tickboxes. */
4897 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE
4898 || wv->button_type == BUTTON_TYPE_RADIO))
4899 SetItemMark (menu, pos, checkMark);
4900 else
4901 SetItemMark (menu, pos, noMark);
4903 SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
4907 /* Construct native Mac OS menu based on widget_value tree. */
4909 static int
4910 fill_menu (menu, wv, kind, submenu_id)
4911 MenuRef menu;
4912 widget_value *wv;
4913 enum mac_menu_kind kind;
4914 int submenu_id;
4916 int pos;
4918 for (pos = 1; wv != NULL; wv = wv->next, pos++)
4920 add_menu_item (menu, pos, wv);
4921 if (wv->contents && submenu_id < min_menu_id[kind + 1])
4923 MenuRef submenu = NewMenu (submenu_id, "\pX");
4925 InsertMenu (submenu, -1);
4926 #if TARGET_API_MAC_CARBON
4927 SetMenuItemHierarchicalMenu (menu, pos, submenu);
4928 #else
4929 SetMenuItemHierarchicalID (menu, pos, submenu_id);
4930 #endif
4931 submenu_id = fill_menu (submenu, wv->contents, kind, submenu_id + 1);
4935 return submenu_id;
4938 /* Fill menu bar with the items defined by WV. If DEEP_P, consider
4939 the entire menu trees we supply, rather than just the menu bar item
4940 names. */
4942 void
4943 mac_fill_menubar (wv, deep_p)
4944 widget_value *wv;
4945 int deep_p;
4947 int id, submenu_id;
4948 #if !TARGET_API_MAC_CARBON
4949 int title_changed_p = 0;
4950 #endif
4952 /* Clean up the menu bar when filled by the entire menu trees. */
4953 if (deep_p)
4955 dispose_menus (MAC_MENU_MENU_BAR, 0);
4956 dispose_menus (MAC_MENU_MENU_BAR_SUB, 0);
4957 #if !TARGET_API_MAC_CARBON
4958 title_changed_p = 1;
4959 #endif
4962 /* Fill menu bar titles and submenus. Reuse the existing menu bar
4963 titles as much as possible to minimize redraw (if !deep_p). */
4964 submenu_id = min_menu_id[MAC_MENU_MENU_BAR_SUB];
4965 for (id = min_menu_id[MAC_MENU_MENU_BAR];
4966 wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1];
4967 wv = wv->next, id++)
4969 OSStatus err = noErr;
4970 MenuRef menu;
4971 #if TARGET_API_MAC_CARBON
4972 CFStringRef title;
4974 title = CFStringCreateWithCString (NULL, wv->name,
4975 kCFStringEncodingMacRoman);
4976 #else
4977 Str255 title;
4979 strncpy (title, wv->name, 255);
4980 title[255] = '\0';
4981 c2pstr (title);
4982 #endif
4984 menu = GetMenuRef (id);
4985 if (menu)
4987 #if TARGET_API_MAC_CARBON
4988 CFStringRef old_title;
4990 err = CopyMenuTitleAsCFString (menu, &old_title);
4991 if (err == noErr)
4993 if (CFStringCompare (title, old_title, 0) != kCFCompareEqualTo)
4995 #ifdef MAC_OSX
4996 if (id + 1 == min_menu_id[MAC_MENU_MENU_BAR + 1]
4997 || GetMenuRef (id + 1) == NULL)
4999 /* This is a workaround for Mac OS X 10.5 where
5000 just calling SetMenuTitleWithCFString fails
5001 to change the title of the last (Help) menu
5002 in the menu bar. */
5003 DeleteMenu (id);
5004 DisposeMenu (menu);
5005 menu = NULL;
5007 else
5008 #endif /* MAC_OSX */
5009 err = SetMenuTitleWithCFString (menu, title);
5011 CFRelease (old_title);
5013 else
5014 err = SetMenuTitleWithCFString (menu, title);
5015 #else /* !TARGET_API_MAC_CARBON */
5016 if (!EqualString (title, (*menu)->menuData, false, false))
5018 DeleteMenu (id);
5019 DisposeMenu (menu);
5020 menu = NewMenu (id, title);
5021 InsertMenu (menu, GetMenuRef (id + 1) ? id + 1 : 0);
5022 title_changed_p = 1;
5024 #endif /* !TARGET_API_MAC_CARBON */
5027 if (!menu)
5029 #if TARGET_API_MAC_CARBON
5030 err = CreateNewMenu (id, 0, &menu);
5031 if (err == noErr)
5032 err = SetMenuTitleWithCFString (menu, title);
5033 #else
5034 menu = NewMenu (id, title);
5035 #endif
5036 if (err == noErr)
5038 InsertMenu (menu, 0);
5039 #if !TARGET_API_MAC_CARBON
5040 title_changed_p = 1;
5041 #endif
5044 #if TARGET_API_MAC_CARBON
5045 CFRelease (title);
5046 #endif
5048 if (err == noErr)
5049 if (wv->contents)
5050 submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
5051 submenu_id);
5054 if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuRef (id))
5056 dispose_menus (MAC_MENU_MENU_BAR, id);
5057 #if !TARGET_API_MAC_CARBON
5058 title_changed_p = 1;
5059 #endif
5062 #if !TARGET_API_MAC_CARBON
5063 if (title_changed_p)
5064 InvalMenuBar ();
5065 #endif
5067 /* Add event handler so we can detect C-g. */
5068 install_menu_quit_handler (MAC_MENU_MENU_BAR, NULL);
5069 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB, NULL);
5072 /* Dispose of menus that belong to KIND, and remove them from the menu
5073 list. ID is the lower bound of menu IDs that will be processed. */
5075 static void
5076 dispose_menus (kind, id)
5077 enum mac_menu_kind kind;
5078 int id;
5080 for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++)
5082 MenuRef menu = GetMenuRef (id);
5084 if (menu == NULL)
5085 break;
5086 DeleteMenu (id);
5087 DisposeMenu (menu);
5091 static void
5092 init_menu_bar ()
5094 #ifdef MAC_OSX
5095 OSStatus err;
5096 MenuRef menu;
5097 MenuItemIndex menu_index;
5099 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
5100 &menu, &menu_index);
5101 if (err == noErr)
5102 SetMenuItemCommandKey (menu, menu_index, false, 0);
5103 EnableMenuCommand (NULL, kHICommandPreferences);
5104 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
5105 &menu, &menu_index);
5106 if (err == noErr)
5108 SetMenuItemCommandKey (menu, menu_index, false, 0);
5109 InsertMenuItemTextWithCFString (menu, NULL,
5110 0, kMenuItemAttrSeparator, 0);
5111 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
5112 0, 0, kHICommandAbout);
5114 #else /* !MAC_OSX */
5115 #if TARGET_API_MAC_CARBON
5116 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
5117 #endif
5118 #endif
5122 /***********************************************************************
5123 Popup Dialog
5124 ***********************************************************************/
5126 #if TARGET_API_MAC_CARBON
5127 #define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
5128 #define DIALOG_BUTTON_COMMAND_ID_P(id) \
5129 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
5130 #define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
5131 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
5132 #define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
5133 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
5135 extern EMACS_TIME timer_check P_ ((int));
5136 static int quit_dialog_event_loop;
5138 static pascal OSStatus
5139 mac_handle_dialog_event (next_handler, event, data)
5140 EventHandlerCallRef next_handler;
5141 EventRef event;
5142 void *data;
5144 OSStatus err, result = eventNotHandledErr;
5145 WindowRef window = (WindowRef) data;
5147 switch (GetEventClass (event))
5149 case kEventClassCommand:
5151 HICommand command;
5153 err = GetEventParameter (event, kEventParamDirectObject,
5154 typeHICommand, NULL, sizeof (HICommand),
5155 NULL, &command);
5156 if (err == noErr)
5157 if (DIALOG_BUTTON_COMMAND_ID_P (command.commandID))
5159 SetWRefCon (window, command.commandID);
5160 quit_dialog_event_loop = 1;
5161 break;
5164 result = CallNextEventHandler (next_handler, event);
5166 break;
5168 case kEventClassKeyboard:
5170 OSStatus result;
5171 char char_code;
5173 result = CallNextEventHandler (next_handler, event);
5174 if (result != eventNotHandledErr)
5175 break;
5177 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
5178 typeChar, NULL, sizeof (char),
5179 NULL, &char_code);
5180 if (err == noErr)
5181 switch (char_code)
5183 case kEscapeCharCode:
5184 quit_dialog_event_loop = 1;
5185 break;
5187 default:
5189 UInt32 modifiers, key_code;
5191 err = GetEventParameter (event, kEventParamKeyModifiers,
5192 typeUInt32, NULL, sizeof (UInt32),
5193 NULL, &modifiers);
5194 if (err == noErr)
5195 err = GetEventParameter (event, kEventParamKeyCode,
5196 typeUInt32, NULL, sizeof (UInt32),
5197 NULL, &key_code);
5198 if (err == noErr)
5199 if (mac_quit_char_key_p (modifiers, key_code))
5200 quit_dialog_event_loop = 1;
5202 break;
5205 break;
5207 default:
5208 abort ();
5211 if (quit_dialog_event_loop)
5213 err = QuitEventLoop (GetCurrentEventLoop ());
5214 if (err == noErr)
5215 result = noErr;
5218 return result;
5221 static OSStatus
5222 install_dialog_event_handler (window)
5223 WindowRef window;
5225 static const EventTypeSpec specs[] =
5226 {{kEventClassCommand, kEventCommandProcess},
5227 {kEventClassKeyboard, kEventRawKeyDown}};
5228 static EventHandlerUPP handle_dialog_eventUPP = NULL;
5230 if (handle_dialog_eventUPP == NULL)
5231 handle_dialog_eventUPP = NewEventHandlerUPP (mac_handle_dialog_event);
5232 return InstallWindowEventHandler (window, handle_dialog_eventUPP,
5233 GetEventTypeCount (specs), specs,
5234 window, NULL);
5237 static Lisp_Object
5238 pop_down_dialog (arg)
5239 Lisp_Object arg;
5241 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
5242 WindowRef window = p->pointer;
5244 BLOCK_INPUT;
5246 if (popup_activated_flag)
5247 EndAppModalStateForWindow (window);
5248 DisposeWindow (window);
5249 popup_activated_flag = 0;
5251 UNBLOCK_INPUT;
5253 return Qnil;
5256 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
5257 dialog pops down.
5258 menu_item_selection will be set to the selection. */
5260 void
5261 create_and_show_dialog (f, first_wv)
5262 FRAME_PTR f;
5263 widget_value *first_wv;
5265 OSStatus err;
5266 char *dialog_name, *message;
5267 int nb_buttons, first_group_count, i, result = 0;
5268 widget_value *wv;
5269 short buttons_height, text_height, inner_width, inner_height;
5270 Rect empty_rect, *rects;
5271 WindowRef window = NULL;
5272 ControlRef *buttons, default_button = NULL, text;
5273 int specpdl_count = SPECPDL_INDEX ();
5275 dialog_name = first_wv->name;
5276 nb_buttons = dialog_name[1] - '0';
5277 first_group_count = nb_buttons - (dialog_name[4] - '0');
5279 wv = first_wv->contents;
5280 message = wv->value;
5282 wv = wv->next;
5283 SetRect (&empty_rect, 0, 0, 0, 0);
5285 /* Create dialog window. */
5286 err = CreateNewWindow (kMovableModalWindowClass,
5287 kWindowStandardHandlerAttribute,
5288 &empty_rect, &window);
5289 if (err == noErr)
5291 record_unwind_protect (pop_down_dialog, make_save_value (window, 0));
5292 err = SetThemeWindowBackground (window, kThemeBrushMovableModalBackground,
5293 true);
5295 if (err == noErr)
5296 err = SetWindowTitleWithCFString (window, (dialog_name[0] == 'Q'
5297 ? CFSTR ("Question")
5298 : CFSTR ("Information")));
5300 /* Create button controls and measure their optimal bounds. */
5301 if (err == noErr)
5303 buttons = alloca (sizeof (ControlRef) * nb_buttons);
5304 rects = alloca (sizeof (Rect) * nb_buttons);
5305 for (i = 0; i < nb_buttons; i++)
5307 CFStringRef label = cfstring_create_with_utf8_cstring (wv->value);
5309 if (label == NULL)
5310 err = memFullErr;
5311 else
5313 err = CreatePushButtonControl (window, &empty_rect,
5314 label, &buttons[i]);
5315 CFRelease (label);
5317 if (err == noErr)
5319 if (!wv->enabled)
5321 #ifdef MAC_OSX
5322 err = DisableControl (buttons[i]);
5323 #else
5324 err = DeactivateControl (buttons[i]);
5325 #endif
5327 else if (default_button == NULL)
5328 default_button = buttons[i];
5330 if (err == noErr)
5332 SInt16 unused;
5334 rects[i] = empty_rect;
5335 err = GetBestControlRect (buttons[i], &rects[i], &unused);
5337 if (err == noErr)
5339 UInt32 command_id;
5341 OffsetRect (&rects[i], -rects[i].left, -rects[i].top);
5342 if (rects[i].right < DIALOG_BUTTON_MIN_WIDTH)
5343 rects[i].right = DIALOG_BUTTON_MIN_WIDTH;
5344 else if (rects[i].right > DIALOG_MAX_INNER_WIDTH)
5345 rects[i].right = DIALOG_MAX_INNER_WIDTH;
5347 command_id = DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv->call_data);
5348 err = SetControlCommandID (buttons[i], command_id);
5350 if (err != noErr)
5351 break;
5352 wv = wv->next;
5356 /* Layout buttons. rects[i] is set relative to the bottom-right
5357 corner of the inner box. */
5358 if (err == noErr)
5360 short bottom, right, max_height, left_align_shift;
5362 inner_width = DIALOG_MIN_INNER_WIDTH;
5363 bottom = right = max_height = 0;
5364 for (i = 0; i < nb_buttons; i++)
5366 if (right - rects[i].right < - inner_width)
5368 if (i != first_group_count
5369 && right - rects[i].right >= - DIALOG_MAX_INNER_WIDTH)
5370 inner_width = - (right - rects[i].right);
5371 else
5373 bottom -= max_height + DIALOG_BUTTON_BUTTON_VERTICAL_SPACE;
5374 right = max_height = 0;
5377 if (max_height < rects[i].bottom)
5378 max_height = rects[i].bottom;
5379 OffsetRect (&rects[i], right - rects[i].right,
5380 bottom - rects[i].bottom);
5381 right = rects[i].left - DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
5382 if (i == first_group_count - 1)
5383 right -= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
5385 buttons_height = - (bottom - max_height);
5387 left_align_shift = - (inner_width + rects[nb_buttons - 1].left);
5388 for (i = nb_buttons - 1; i >= first_group_count; i--)
5390 if (bottom != rects[i].bottom)
5392 left_align_shift = - (inner_width + rects[i].left);
5393 bottom = rects[i].bottom;
5395 OffsetRect (&rects[i], left_align_shift, 0);
5399 /* Create a static text control and measure its bounds. */
5400 if (err == noErr)
5402 CFStringRef message_string;
5403 Rect bounds;
5405 message_string = cfstring_create_with_utf8_cstring (message);
5406 if (message_string == NULL)
5407 err = memFullErr;
5408 else
5410 ControlFontStyleRec text_style;
5412 text_style.flags = 0;
5413 SetRect (&bounds, 0, 0, inner_width, 0);
5414 err = CreateStaticTextControl (window, &bounds, message_string,
5415 &text_style, &text);
5416 CFRelease (message_string);
5418 if (err == noErr)
5420 SInt16 unused;
5422 bounds = empty_rect;
5423 err = GetBestControlRect (text, &bounds, &unused);
5425 if (err == noErr)
5427 text_height = bounds.bottom - bounds.top;
5428 if (text_height < DIALOG_TEXT_MIN_HEIGHT)
5429 text_height = DIALOG_TEXT_MIN_HEIGHT;
5433 /* Place buttons. */
5434 if (err == noErr)
5436 inner_height = (text_height + DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
5437 + buttons_height);
5439 for (i = 0; i < nb_buttons; i++)
5441 OffsetRect (&rects[i], DIALOG_LEFT_MARGIN + inner_width,
5442 DIALOG_TOP_MARGIN + inner_height);
5443 SetControlBounds (buttons[i], &rects[i]);
5447 /* Place text. */
5448 if (err == noErr)
5450 Rect bounds;
5452 SetRect (&bounds, DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN,
5453 DIALOG_LEFT_MARGIN + inner_width,
5454 DIALOG_TOP_MARGIN + text_height);
5455 SetControlBounds (text, &bounds);
5458 /* Create the application icon at the upper-left corner. */
5459 if (err == noErr)
5461 ControlButtonContentInfo content;
5462 ControlRef icon;
5463 static const ProcessSerialNumber psn = {0, kCurrentProcess};
5464 #ifdef MAC_OSX
5465 FSRef app_location;
5466 #else
5467 ProcessInfoRec pinfo;
5468 FSSpec app_spec;
5469 #endif
5470 SInt16 unused;
5472 content.contentType = kControlContentIconRef;
5473 #ifdef MAC_OSX
5474 err = GetProcessBundleLocation (&psn, &app_location);
5475 if (err == noErr)
5476 err = GetIconRefFromFileInfo (&app_location, 0, NULL, 0, NULL,
5477 kIconServicesNormalUsageFlag,
5478 &content.u.iconRef, &unused);
5479 #else
5480 bzero (&pinfo, sizeof (ProcessInfoRec));
5481 pinfo.processInfoLength = sizeof (ProcessInfoRec);
5482 pinfo.processAppSpec = &app_spec;
5483 err = GetProcessInformation (&psn, &pinfo);
5484 if (err == noErr)
5485 err = GetIconRefFromFile (&app_spec, &content.u.iconRef, &unused);
5486 #endif
5487 if (err == noErr)
5489 Rect bounds;
5491 SetRect (&bounds, DIALOG_ICON_LEFT_MARGIN, DIALOG_ICON_TOP_MARGIN,
5492 DIALOG_ICON_LEFT_MARGIN + DIALOG_ICON_WIDTH,
5493 DIALOG_ICON_TOP_MARGIN + DIALOG_ICON_HEIGHT);
5494 err = CreateIconControl (window, &bounds, &content, true, &icon);
5495 ReleaseIconRef (content.u.iconRef);
5499 /* Show the dialog window and run event loop. */
5500 if (err == noErr)
5501 if (default_button)
5502 err = SetWindowDefaultButton (window, default_button);
5503 if (err == noErr)
5504 err = install_dialog_event_handler (window);
5505 if (err == noErr)
5507 SizeWindow (window,
5508 DIALOG_LEFT_MARGIN + inner_width + DIALOG_RIGHT_MARGIN,
5509 DIALOG_TOP_MARGIN + inner_height + DIALOG_BOTTOM_MARGIN,
5510 true);
5511 err = RepositionWindow (window, FRAME_MAC_WINDOW (f),
5512 kWindowAlertPositionOnParentWindow);
5514 if (err == noErr)
5516 SetWRefCon (window, 0);
5517 ShowWindow (window);
5518 BringToFront (window);
5519 popup_activated_flag = 1;
5520 err = BeginAppModalStateForWindow (window);
5522 if (err == noErr)
5524 EventTargetRef toolbox_dispatcher = GetEventDispatcherTarget ();
5526 quit_dialog_event_loop = 0;
5527 while (1)
5529 EMACS_TIME next_time = timer_check (1);
5530 long secs = EMACS_SECS (next_time);
5531 long usecs = EMACS_USECS (next_time);
5532 EventTimeout timeout;
5533 EventRef event;
5535 if (secs < 0 || (secs == 0 && usecs == 0))
5537 /* Sometimes timer_check returns -1 (no timers) even if
5538 there are timers. So do a timeout anyway. */
5539 secs = 1;
5540 usecs = 0;
5543 timeout = (secs * kEventDurationSecond
5544 + usecs * kEventDurationMicrosecond);
5545 err = ReceiveNextEvent (0, NULL, timeout, kEventRemoveFromQueue,
5546 &event);
5547 if (err == noErr)
5549 SendEventToEventTarget (event, toolbox_dispatcher);
5550 ReleaseEvent (event);
5552 #if 0 /* defined (MAC_OSX) */
5553 else if (err != eventLoopTimedOutErr)
5555 if (err == eventLoopQuitErr)
5556 err = noErr;
5557 break;
5559 #else
5560 /* The return value of ReceiveNextEvent seems to be
5561 unreliable. Use our own global variable instead. */
5562 if (quit_dialog_event_loop)
5564 err = noErr;
5565 break;
5567 #endif
5570 if (err == noErr)
5572 UInt32 command_id = GetWRefCon (window);
5574 if (DIALOG_BUTTON_COMMAND_ID_P (command_id))
5575 result = DIALOG_BUTTON_COMMAND_ID_VALUE (command_id);
5578 unbind_to (specpdl_count, Qnil);
5580 menu_item_selection = result;
5582 #else /* not TARGET_API_MAC_CARBON */
5583 #define DIALOG_WINDOW_RESOURCE 130
5586 mac_dialog (widget_value *wv)
5588 char *dialog_name;
5589 char *prompt;
5590 char **button_labels;
5591 UInt32 *ref_cons;
5592 int nb_buttons;
5593 int left_count;
5594 int i;
5595 int dialog_width;
5596 Rect rect;
5597 WindowRef window_ptr;
5598 ControlRef ch;
5599 int left;
5600 EventRecord event_record;
5601 SInt16 part_code;
5602 int control_part_code;
5603 Point mouse;
5605 dialog_name = wv->name;
5606 nb_buttons = dialog_name[1] - '0';
5607 left_count = nb_buttons - (dialog_name[4] - '0');
5608 button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
5609 ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons);
5611 wv = wv->contents;
5612 prompt = (char *) alloca (strlen (wv->value) + 1);
5613 strcpy (prompt, wv->value);
5614 c2pstr (prompt);
5616 wv = wv->next;
5617 for (i = 0; i < nb_buttons; i++)
5619 button_labels[i] = wv->value;
5620 button_labels[i] = (char *) alloca (strlen (wv->value) + 1);
5621 strcpy (button_labels[i], wv->value);
5622 c2pstr (button_labels[i]);
5623 ref_cons[i] = (UInt32) wv->call_data;
5624 wv = wv->next;
5627 window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowRef) -1);
5629 SetPortWindowPort (window_ptr);
5631 TextFont (0);
5632 /* Left and right margins in the dialog are 13 pixels each.*/
5633 dialog_width = 14;
5634 /* Calculate width of dialog box: 8 pixels on each side of the text
5635 label in each button, 12 pixels between buttons. */
5636 for (i = 0; i < nb_buttons; i++)
5637 dialog_width += StringWidth (button_labels[i]) + 16 + 12;
5639 if (left_count != 0 && nb_buttons - left_count != 0)
5640 dialog_width += 12;
5642 dialog_width = max (dialog_width, StringWidth (prompt) + 26);
5644 SizeWindow (window_ptr, dialog_width, 78, 0);
5645 ShowWindow (window_ptr);
5647 SetPortWindowPort (window_ptr);
5649 TextFont (0);
5651 MoveTo (13, 29);
5652 DrawString (prompt);
5654 left = 13;
5655 for (i = 0; i < nb_buttons; i++)
5657 int button_width = StringWidth (button_labels[i]) + 16;
5658 SetRect (&rect, left, 45, left + button_width, 65);
5659 ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0,
5660 kControlPushButtonProc, ref_cons[i]);
5661 left += button_width + 12;
5662 if (i == left_count - 1)
5663 left += 12;
5666 i = 0;
5667 while (!i)
5669 if (WaitNextEvent (mDownMask, &event_record, 10, NULL))
5670 if (event_record.what == mouseDown)
5672 part_code = FindWindow (event_record.where, &window_ptr);
5673 if (part_code == inContent)
5675 mouse = event_record.where;
5676 GlobalToLocal (&mouse);
5677 control_part_code = FindControl (mouse, window_ptr, &ch);
5678 if (control_part_code == kControlButtonPart)
5679 if (TrackControl (ch, mouse, NULL))
5680 i = GetControlReference (ch);
5685 DisposeWindow (window_ptr);
5687 return i;
5689 #endif /* not TARGET_API_MAC_CARBON */
5692 /***********************************************************************
5693 Selection support
5694 ***********************************************************************/
5696 #if !TARGET_API_MAC_CARBON
5697 #include <Scrap.h>
5698 #include <Endian.h>
5699 #endif
5701 extern Lisp_Object Vselection_converter_alist;
5702 extern Lisp_Object Qmac_scrap_name, Qmac_ostype;
5704 static ScrapFlavorType get_flavor_type_from_symbol P_ ((Lisp_Object,
5705 Selection));
5707 /* Get a reference to the selection corresponding to the symbol SYM.
5708 The reference is set to *SEL, and it becomes NULL if there's no
5709 corresponding selection. Clear the selection if CLEAR_P is
5710 non-zero. */
5712 OSStatus
5713 mac_get_selection_from_symbol (sym, clear_p, sel)
5714 Lisp_Object sym;
5715 int clear_p;
5716 Selection *sel;
5718 OSStatus err = noErr;
5719 Lisp_Object str = Fget (sym, Qmac_scrap_name);
5721 if (!STRINGP (str))
5722 *sel = NULL;
5723 else
5725 #if TARGET_API_MAC_CARBON
5726 #ifdef MAC_OSX
5727 CFStringRef scrap_name = cfstring_create_with_string (str);
5728 OptionBits options = (clear_p ? kScrapClearNamedScrap
5729 : kScrapGetNamedScrap);
5731 err = GetScrapByName (scrap_name, options, sel);
5732 CFRelease (scrap_name);
5733 #else /* !MAC_OSX */
5734 if (clear_p)
5735 err = ClearCurrentScrap ();
5736 if (err == noErr)
5737 err = GetCurrentScrap (sel);
5738 #endif /* !MAC_OSX */
5739 #else /* !TARGET_API_MAC_CARBON */
5740 if (clear_p)
5741 err = ZeroScrap ();
5742 if (err == noErr)
5743 *sel = 1;
5744 #endif /* !TARGET_API_MAC_CARBON */
5747 return err;
5750 /* Get a scrap flavor type from the symbol SYM. Return 0 if no
5751 corresponding flavor type. If SEL is non-zero, the return value is
5752 non-zero only when the SEL has the flavor type. */
5754 static ScrapFlavorType
5755 get_flavor_type_from_symbol (sym, sel)
5756 Lisp_Object sym;
5757 Selection sel;
5759 Lisp_Object str = Fget (sym, Qmac_ostype);
5760 ScrapFlavorType flavor_type;
5762 if (STRINGP (str) && SBYTES (str) == 4)
5763 flavor_type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
5764 else
5765 flavor_type = 0;
5767 if (flavor_type && sel)
5769 #if TARGET_API_MAC_CARBON
5770 OSStatus err;
5771 ScrapFlavorFlags flags;
5773 err = GetScrapFlavorFlags (sel, flavor_type, &flags);
5774 if (err != noErr)
5775 flavor_type = 0;
5776 #else /* !TARGET_API_MAC_CARBON */
5777 SInt32 size, offset;
5779 size = GetScrap (NULL, flavor_type, &offset);
5780 if (size < 0)
5781 flavor_type = 0;
5782 #endif /* !TARGET_API_MAC_CARBON */
5785 return flavor_type;
5788 /* Check if the symbol SYM has a corresponding selection target type. */
5791 mac_valid_selection_target_p (sym)
5792 Lisp_Object sym;
5794 return get_flavor_type_from_symbol (sym, 0) != 0;
5797 /* Clear the selection whose reference is *SEL. */
5799 OSStatus
5800 mac_clear_selection (sel)
5801 Selection *sel;
5803 #if TARGET_API_MAC_CARBON
5804 #ifdef MAC_OSX
5805 return ClearScrap (sel);
5806 #else
5807 OSStatus err;
5809 err = ClearCurrentScrap ();
5810 if (err == noErr)
5811 err = GetCurrentScrap (sel);
5812 return err;
5813 #endif
5814 #else /* !TARGET_API_MAC_CARBON */
5815 return ZeroScrap ();
5816 #endif /* !TARGET_API_MAC_CARBON */
5819 /* Get ownership information for SEL. Emacs can detect a change of
5820 the ownership by comparing saved and current values of the
5821 ownership information. */
5823 Lisp_Object
5824 mac_get_selection_ownership_info (sel)
5825 Selection sel;
5827 #if TARGET_API_MAC_CARBON
5828 return long_to_cons ((unsigned long) sel);
5829 #else /* !TARGET_API_MAC_CARBON */
5830 ScrapStuffPtr scrap_info = InfoScrap ();
5832 return make_number (scrap_info->scrapCount);
5833 #endif /* !TARGET_API_MAC_CARBON */
5836 /* Return non-zero if VALUE is a valid selection value for TARGET. */
5839 mac_valid_selection_value_p (value, target)
5840 Lisp_Object value, target;
5842 return STRINGP (value);
5845 /* Put Lisp object VALUE to the selection SEL. The target type is
5846 specified by TARGET. */
5848 OSStatus
5849 mac_put_selection_value (sel, target, value)
5850 Selection sel;
5851 Lisp_Object target, value;
5853 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, 0);
5855 if (flavor_type == 0 || !STRINGP (value))
5856 return noTypeErr;
5858 #if TARGET_API_MAC_CARBON
5859 return PutScrapFlavor (sel, flavor_type, kScrapFlavorMaskNone,
5860 SBYTES (value), SDATA (value));
5861 #else /* !TARGET_API_MAC_CARBON */
5862 return PutScrap (SBYTES (value), flavor_type, SDATA (value));
5863 #endif /* !TARGET_API_MAC_CARBON */
5866 /* Check if data for the target type TARGET is available in SEL. */
5869 mac_selection_has_target_p (sel, target)
5870 Selection sel;
5871 Lisp_Object target;
5873 return get_flavor_type_from_symbol (target, sel) != 0;
5876 /* Get data for the target type TARGET from SEL and create a Lisp
5877 string. Return nil if failed to get data. */
5879 Lisp_Object
5880 mac_get_selection_value (sel, target)
5881 Selection sel;
5882 Lisp_Object target;
5884 OSStatus err;
5885 Lisp_Object result = Qnil;
5886 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, sel);
5887 #if TARGET_API_MAC_CARBON
5888 Size size;
5890 if (flavor_type)
5892 err = GetScrapFlavorSize (sel, flavor_type, &size);
5893 if (err == noErr)
5897 result = make_uninit_string (size);
5898 err = GetScrapFlavorData (sel, flavor_type,
5899 &size, SDATA (result));
5900 if (err != noErr)
5901 result = Qnil;
5902 else if (size < SBYTES (result))
5903 result = make_unibyte_string (SDATA (result), size);
5905 while (STRINGP (result) && size > SBYTES (result));
5908 #else
5909 Handle handle;
5910 SInt32 size, offset;
5912 if (flavor_type)
5913 size = GetScrap (NULL, flavor_type, &offset);
5914 if (size >= 0)
5916 handle = NewHandle (size);
5917 HLock (handle);
5918 size = GetScrap (handle, flavor_type, &offset);
5919 if (size >= 0)
5920 result = make_unibyte_string (*handle, size);
5921 DisposeHandle (handle);
5923 #endif
5925 return result;
5928 /* Get the list of target types in SEL. The return value is a list of
5929 target type symbols possibly followed by scrap flavor type
5930 strings. */
5932 Lisp_Object
5933 mac_get_selection_target_list (sel)
5934 Selection sel;
5936 Lisp_Object result = Qnil, rest, target;
5937 #if TARGET_API_MAC_CARBON
5938 OSStatus err;
5939 UInt32 count, i, type;
5940 ScrapFlavorInfo *flavor_info = NULL;
5941 Lisp_Object strings = Qnil;
5943 err = GetScrapFlavorCount (sel, &count);
5944 if (err == noErr)
5945 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
5946 err = GetScrapFlavorInfoList (sel, &count, flavor_info);
5947 if (err != noErr)
5949 xfree (flavor_info);
5950 flavor_info = NULL;
5952 if (flavor_info == NULL)
5953 count = 0;
5954 #endif
5955 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
5957 ScrapFlavorType flavor_type = 0;
5959 if (CONSP (XCAR (rest))
5960 && (target = XCAR (XCAR (rest)),
5961 SYMBOLP (target))
5962 && (flavor_type = get_flavor_type_from_symbol (target, sel)))
5964 result = Fcons (target, result);
5965 #if TARGET_API_MAC_CARBON
5966 for (i = 0; i < count; i++)
5967 if (flavor_info[i].flavorType == flavor_type)
5969 flavor_info[i].flavorType = 0;
5970 break;
5972 #endif
5975 #if TARGET_API_MAC_CARBON
5976 if (flavor_info)
5978 for (i = 0; i < count; i++)
5979 if (flavor_info[i].flavorType)
5981 type = EndianU32_NtoB (flavor_info[i].flavorType);
5982 strings = Fcons (make_unibyte_string ((char *) &type, 4), strings);
5984 result = nconc2 (result, strings);
5985 xfree (flavor_info);
5987 #endif
5989 return result;
5993 /***********************************************************************
5994 Apple event support
5995 ***********************************************************************/
5997 extern pascal OSErr mac_handle_apple_event P_ ((const AppleEvent *,
5998 AppleEvent *, SInt32));
5999 extern void cleanup_all_suspended_apple_events P_ ((void));
6001 void
6002 init_apple_event_handler ()
6004 OSErr err;
6005 long result;
6007 /* Make sure we have Apple events before starting. */
6008 err = Gestalt (gestaltAppleEventsAttr, &result);
6009 if (err != noErr)
6010 abort ();
6012 if (!(result & (1 << gestaltAppleEventsPresent)))
6013 abort ();
6015 err = AEInstallEventHandler (typeWildCard, typeWildCard,
6016 #if TARGET_API_MAC_CARBON
6017 NewAEEventHandlerUPP (mac_handle_apple_event),
6018 #else
6019 NewAEEventHandlerProc (mac_handle_apple_event),
6020 #endif
6021 0L, false);
6022 if (err != noErr)
6023 abort ();
6025 atexit (cleanup_all_suspended_apple_events);
6029 /***********************************************************************
6030 Drag and drop support
6031 ***********************************************************************/
6033 #if TARGET_API_MAC_CARBON
6034 extern Lisp_Object Vmac_dnd_known_types;
6036 static pascal OSErr mac_do_track_drag P_ ((DragTrackingMessage, WindowRef,
6037 void *, DragRef));
6038 static pascal OSErr mac_do_receive_drag P_ ((WindowRef, void *, DragRef));
6039 static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL;
6040 static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL;
6042 static OSErr
6043 create_apple_event_from_drag_ref (drag, num_types, types, result)
6044 DragRef drag;
6045 UInt32 num_types;
6046 const FlavorType *types;
6047 AppleEvent *result;
6049 OSErr err;
6050 UInt16 num_items;
6051 AppleEvent items;
6052 long index;
6053 char *buf = NULL;
6055 err = CountDragItems (drag, &num_items);
6056 if (err != noErr)
6057 return err;
6058 err = AECreateList (NULL, 0, false, &items);
6059 if (err != noErr)
6060 return err;
6062 for (index = 1; index <= num_items; index++)
6064 ItemReference item;
6065 DescType desc_type = typeNull;
6066 Size size;
6068 err = GetDragItemReferenceNumber (drag, index, &item);
6069 if (err == noErr)
6071 int i;
6073 for (i = 0; i < num_types; i++)
6075 err = GetFlavorDataSize (drag, item, types[i], &size);
6076 if (err == noErr)
6078 buf = xrealloc (buf, size);
6079 err = GetFlavorData (drag, item, types[i], buf, &size, 0);
6081 if (err == noErr)
6083 desc_type = types[i];
6084 break;
6088 err = AEPutPtr (&items, index, desc_type,
6089 desc_type != typeNull ? buf : NULL,
6090 desc_type != typeNull ? size : 0);
6091 if (err != noErr)
6092 break;
6094 xfree (buf);
6096 if (err == noErr)
6098 err = create_apple_event (0, 0, result); /* Dummy class and ID. */
6099 if (err == noErr)
6100 err = AEPutParamDesc (result, keyDirectObject, &items);
6101 if (err != noErr)
6102 AEDisposeDesc (result);
6105 AEDisposeDesc (&items);
6107 return err;
6110 static void
6111 mac_store_drag_event (window, mouse_pos, modifiers, desc)
6112 WindowRef window;
6113 Point mouse_pos;
6114 SInt16 modifiers;
6115 const AEDesc *desc;
6117 struct input_event buf;
6119 EVENT_INIT (buf);
6121 buf.kind = DRAG_N_DROP_EVENT;
6122 buf.modifiers = mac_to_emacs_modifiers (modifiers, 0);
6123 buf.timestamp = TickCount () * (1000 / 60);
6124 XSETINT (buf.x, mouse_pos.h);
6125 XSETINT (buf.y, mouse_pos.v);
6126 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
6127 buf.arg = mac_aedesc_to_lisp (desc);
6128 kbd_buffer_store_event (&buf);
6131 static pascal OSErr
6132 mac_do_track_drag (message, window, refcon, drag)
6133 DragTrackingMessage message;
6134 WindowRef window;
6135 void *refcon;
6136 DragRef drag;
6138 OSErr err = noErr;
6139 static int can_accept;
6140 UInt16 num_items, index;
6142 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
6143 return dragNotAcceptedErr;
6145 switch (message)
6147 case kDragTrackingEnterHandler:
6148 err = CountDragItems (drag, &num_items);
6149 if (err != noErr)
6150 break;
6151 can_accept = 0;
6152 for (index = 1; index <= num_items; index++)
6154 ItemReference item;
6155 FlavorFlags flags;
6156 Lisp_Object rest;
6158 err = GetDragItemReferenceNumber (drag, index, &item);
6159 if (err != noErr)
6160 continue;
6161 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
6163 Lisp_Object str;
6164 FlavorType type;
6166 str = XCAR (rest);
6167 if (!(STRINGP (str) && SBYTES (str) == 4))
6168 continue;
6169 type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
6171 err = GetFlavorFlags (drag, item, type, &flags);
6172 if (err == noErr)
6174 can_accept = 1;
6175 break;
6179 break;
6181 case kDragTrackingEnterWindow:
6182 if (can_accept)
6184 RgnHandle hilite_rgn = NewRgn ();
6186 if (hilite_rgn)
6188 Rect r;
6190 GetWindowPortBounds (window, &r);
6191 OffsetRect (&r, -r.left, -r.top);
6192 RectRgn (hilite_rgn, &r);
6193 ShowDragHilite (drag, hilite_rgn, true);
6194 DisposeRgn (hilite_rgn);
6196 SetThemeCursor (kThemeCopyArrowCursor);
6198 break;
6200 case kDragTrackingInWindow:
6201 break;
6203 case kDragTrackingLeaveWindow:
6204 if (can_accept)
6206 HideDragHilite (drag);
6207 SetThemeCursor (kThemeArrowCursor);
6209 break;
6211 case kDragTrackingLeaveHandler:
6212 break;
6215 if (err != noErr)
6216 return dragNotAcceptedErr;
6217 return noErr;
6220 static pascal OSErr
6221 mac_do_receive_drag (window, refcon, drag)
6222 WindowRef window;
6223 void *refcon;
6224 DragRef drag;
6226 OSErr err;
6227 int num_types, i;
6228 Lisp_Object rest, str;
6229 FlavorType *types;
6230 AppleEvent apple_event;
6231 Point mouse_pos;
6232 SInt16 modifiers;
6234 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
6235 return dragNotAcceptedErr;
6237 num_types = 0;
6238 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
6240 str = XCAR (rest);
6241 if (STRINGP (str) && SBYTES (str) == 4)
6242 num_types++;
6245 types = xmalloc (sizeof (FlavorType) * num_types);
6246 i = 0;
6247 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
6249 str = XCAR (rest);
6250 if (STRINGP (str) && SBYTES (str) == 4)
6251 types[i++] = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
6254 err = create_apple_event_from_drag_ref (drag, num_types, types,
6255 &apple_event);
6256 xfree (types);
6258 if (err == noErr)
6259 err = GetDragMouse (drag, &mouse_pos, NULL);
6260 if (err == noErr)
6262 GlobalToLocal (&mouse_pos);
6263 err = GetDragModifiers (drag, NULL, NULL, &modifiers);
6265 if (err == noErr)
6267 UInt32 key_modifiers = modifiers;
6269 err = AEPutParamPtr (&apple_event, kEventParamKeyModifiers,
6270 typeUInt32, &key_modifiers, sizeof (UInt32));
6273 if (err == noErr)
6275 mac_store_drag_event (window, mouse_pos, 0, &apple_event);
6276 AEDisposeDesc (&apple_event);
6277 mac_wakeup_from_rne ();
6278 return noErr;
6280 else
6281 return dragNotAcceptedErr;
6283 #endif /* TARGET_API_MAC_CARBON */
6285 static OSErr
6286 install_drag_handler (window)
6287 WindowRef window;
6289 OSErr err = noErr;
6291 #if TARGET_API_MAC_CARBON
6292 if (mac_do_track_dragUPP == NULL)
6293 mac_do_track_dragUPP = NewDragTrackingHandlerUPP (mac_do_track_drag);
6294 if (mac_do_receive_dragUPP == NULL)
6295 mac_do_receive_dragUPP = NewDragReceiveHandlerUPP (mac_do_receive_drag);
6297 err = InstallTrackingHandler (mac_do_track_dragUPP, window, NULL);
6298 if (err == noErr)
6299 err = InstallReceiveHandler (mac_do_receive_dragUPP, window, NULL);
6300 #endif
6302 return err;
6305 static void
6306 remove_drag_handler (window)
6307 WindowRef window;
6309 #if TARGET_API_MAC_CARBON
6310 if (mac_do_track_dragUPP)
6311 RemoveTrackingHandler (mac_do_track_dragUPP, window);
6312 if (mac_do_receive_dragUPP)
6313 RemoveReceiveHandler (mac_do_receive_dragUPP, window);
6314 #endif
6317 #if TARGET_API_MAC_CARBON
6318 /* Return default value for mac-dnd-known-types. */
6320 Lisp_Object
6321 mac_dnd_default_known_types ()
6323 Lisp_Object result = list4 (build_string ("hfs "), build_string ("utxt"),
6324 build_string ("TEXT"), build_string ("TIFF"));
6326 #ifdef MAC_OSX
6327 result = Fcons (build_string ("furl"), result);
6328 #endif
6330 return result;
6332 #endif
6335 /***********************************************************************
6336 Services menu support
6337 ***********************************************************************/
6339 #ifdef MAC_OSX
6340 extern Lisp_Object Qservice, Qpaste, Qperform;
6341 extern Lisp_Object Vmac_service_selection;
6343 static OSStatus
6344 mac_store_service_event (event)
6345 EventRef event;
6347 OSStatus err;
6348 Lisp_Object id_key;
6349 int num_params;
6350 const EventParamName *names;
6351 const EventParamType *types;
6352 static const EventParamName names_pfm[] =
6353 {kEventParamServiceMessageName, kEventParamServiceUserData};
6354 static const EventParamType types_pfm[] =
6355 {typeCFStringRef, typeCFStringRef};
6357 switch (GetEventKind (event))
6359 case kEventServicePaste:
6360 id_key = Qpaste;
6361 num_params = 0;
6362 names = NULL;
6363 types = NULL;
6364 break;
6366 case kEventServicePerform:
6367 id_key = Qperform;
6368 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
6369 names = names_pfm;
6370 types = types_pfm;
6371 break;
6373 default:
6374 abort ();
6377 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
6378 event, num_params,
6379 names, types);
6381 return err;
6384 static OSStatus
6385 copy_scrap_flavor_data (from_scrap, to_scrap, flavor_type)
6386 ScrapRef from_scrap, to_scrap;
6387 ScrapFlavorType flavor_type;
6389 OSStatus err;
6390 Size size, size_allocated;
6391 char *buf = NULL;
6393 err = GetScrapFlavorSize (from_scrap, flavor_type, &size);
6394 if (err == noErr)
6395 buf = xmalloc (size);
6396 while (buf)
6398 size_allocated = size;
6399 err = GetScrapFlavorData (from_scrap, flavor_type, &size, buf);
6400 if (err != noErr)
6402 xfree (buf);
6403 buf = NULL;
6405 else if (size_allocated < size)
6406 buf = xrealloc (buf, size);
6407 else
6408 break;
6410 if (err == noErr)
6412 if (buf == NULL)
6413 err = memFullErr;
6414 else
6416 err = PutScrapFlavor (to_scrap, flavor_type, kScrapFlavorMaskNone,
6417 size, buf);
6418 xfree (buf);
6422 return err;
6425 static OSStatus
6426 mac_handle_service_event (call_ref, event, data)
6427 EventHandlerCallRef call_ref;
6428 EventRef event;
6429 void *data;
6431 OSStatus err = noErr;
6432 ScrapRef cur_scrap, specific_scrap;
6433 UInt32 event_kind = GetEventKind (event);
6434 CFMutableArrayRef copy_types, paste_types;
6435 CFStringRef type;
6436 Lisp_Object rest;
6437 ScrapFlavorType flavor_type;
6439 /* Check if Vmac_service_selection is a valid selection that has a
6440 corresponding scrap. */
6441 if (!SYMBOLP (Vmac_service_selection))
6442 err = eventNotHandledErr;
6443 else
6444 err = mac_get_selection_from_symbol (Vmac_service_selection, 0, &cur_scrap);
6445 if (!(err == noErr && cur_scrap))
6446 return eventNotHandledErr;
6448 switch (event_kind)
6450 case kEventServiceGetTypes:
6451 /* Set paste types. */
6452 err = GetEventParameter (event, kEventParamServicePasteTypes,
6453 typeCFMutableArrayRef, NULL,
6454 sizeof (CFMutableArrayRef), NULL,
6455 &paste_types);
6456 if (err != noErr)
6457 break;
6459 for (rest = Vselection_converter_alist; CONSP (rest);
6460 rest = XCDR (rest))
6461 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
6462 && (flavor_type =
6463 get_flavor_type_from_symbol (XCAR (XCAR (rest)), 0)))
6465 type = CreateTypeStringWithOSType (flavor_type);
6466 if (type)
6468 CFArrayAppendValue (paste_types, type);
6469 CFRelease (type);
6473 /* Set copy types. */
6474 err = GetEventParameter (event, kEventParamServiceCopyTypes,
6475 typeCFMutableArrayRef, NULL,
6476 sizeof (CFMutableArrayRef), NULL,
6477 &copy_types);
6478 if (err != noErr)
6479 break;
6481 if (NILP (Fx_selection_owner_p (Vmac_service_selection)))
6482 break;
6483 else
6484 goto copy_all_flavors;
6486 case kEventServiceCopy:
6487 err = GetEventParameter (event, kEventParamScrapRef,
6488 typeScrapRef, NULL,
6489 sizeof (ScrapRef), NULL, &specific_scrap);
6490 if (err != noErr
6491 || NILP (Fx_selection_owner_p (Vmac_service_selection)))
6493 err = eventNotHandledErr;
6494 break;
6497 copy_all_flavors:
6499 UInt32 count, i;
6500 ScrapFlavorInfo *flavor_info = NULL;
6501 ScrapFlavorFlags flags;
6503 err = GetScrapFlavorCount (cur_scrap, &count);
6504 if (err == noErr)
6505 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
6506 err = GetScrapFlavorInfoList (cur_scrap, &count, flavor_info);
6507 if (err != noErr)
6509 xfree (flavor_info);
6510 flavor_info = NULL;
6512 if (flavor_info == NULL)
6513 break;
6515 for (i = 0; i < count; i++)
6517 flavor_type = flavor_info[i].flavorType;
6518 err = GetScrapFlavorFlags (cur_scrap, flavor_type, &flags);
6519 if (err == noErr && !(flags & kScrapFlavorMaskSenderOnly))
6521 if (event_kind == kEventServiceCopy)
6522 err = copy_scrap_flavor_data (cur_scrap, specific_scrap,
6523 flavor_type);
6524 else /* event_kind == kEventServiceGetTypes */
6526 type = CreateTypeStringWithOSType (flavor_type);
6527 if (type)
6529 CFArrayAppendValue (copy_types, type);
6530 CFRelease (type);
6535 xfree (flavor_info);
6537 break;
6539 case kEventServicePaste:
6540 case kEventServicePerform:
6542 int data_exists_p = 0;
6544 err = GetEventParameter (event, kEventParamScrapRef, typeScrapRef,
6545 NULL, sizeof (ScrapRef), NULL,
6546 &specific_scrap);
6547 if (err == noErr)
6548 err = mac_clear_selection (&cur_scrap);
6549 if (err == noErr)
6550 for (rest = Vselection_converter_alist; CONSP (rest);
6551 rest = XCDR (rest))
6553 if (! (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))))
6554 continue;
6555 flavor_type = get_flavor_type_from_symbol (XCAR (XCAR (rest)),
6556 specific_scrap);
6557 if (flavor_type == 0)
6558 continue;
6559 err = copy_scrap_flavor_data (specific_scrap, cur_scrap,
6560 flavor_type);
6561 if (err == noErr)
6562 data_exists_p = 1;
6564 if (!data_exists_p)
6565 err = eventNotHandledErr;
6566 else
6567 err = mac_store_service_event (event);
6569 break;
6572 if (err != noErr)
6573 err = eventNotHandledErr;
6574 return err;
6577 static OSStatus
6578 install_service_handler ()
6580 static const EventTypeSpec specs[] =
6581 {{kEventClassService, kEventServiceGetTypes},
6582 {kEventClassService, kEventServiceCopy},
6583 {kEventClassService, kEventServicePaste},
6584 {kEventClassService, kEventServicePerform}};
6586 return InstallApplicationEventHandler (NewEventHandlerUPP
6587 (mac_handle_service_event),
6588 GetEventTypeCount (specs),
6589 specs, NULL, NULL);
6591 #endif /* MAC_OSX */
6594 /***********************************************************************
6595 Initialization
6596 ***********************************************************************/
6598 void
6599 mac_toolbox_initialize ()
6601 any_help_event_p = 0;
6603 init_menu_bar ();
6605 #ifdef MAC_OSX
6606 init_apple_event_handler ();
6607 #endif
6608 #if USE_MAC_TSM
6609 init_tsm ();
6610 #endif
6613 /* arch-tag: 71a597a8-6e9f-47b0-8b89-5a5ae3e16516
6614 (do not change this comment) */