Merge from gnus--rel--5.10
[emacs.git] / src / mactoolbox.c
blob45a861354226e8feb807c1665e78cb91a81f134c
1 /* Functions for GUI implemented with (HI)Toolbox on the Mac OS.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
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, or (at your option)
10 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; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
22 #include <config.h>
24 #include <stdio.h>
26 #include "lisp.h"
27 #include "blockinput.h"
29 #include "macterm.h"
31 #if !TARGET_API_MAC_CARBON
32 #include <Quickdraw.h>
33 #include <ToolUtils.h>
34 #include <Sound.h>
35 #include <Events.h>
36 #include <Script.h>
37 #include <Resources.h>
38 #include <Fonts.h>
39 #include <TextUtils.h>
40 #include <LowMem.h>
41 #include <Controls.h>
42 #include <Windows.h>
43 #include <Displays.h>
44 #if defined (__MRC__) || (__MSL__ >= 0x6000)
45 #include <ControlDefinitions.h>
46 #endif
48 #if __profile__
49 #include <profiler.h>
50 #endif
51 #endif /* not TARGET_API_MAC_CARBON */
53 #include "charset.h"
54 #include "coding.h"
55 #include "frame.h"
56 #include "dispextern.h"
57 #include "fontset.h"
58 #include "termhooks.h"
59 #include "buffer.h"
60 #include "window.h"
61 #include "keyboard.h"
63 #include <sys/param.h>
65 #ifndef MAC_OSX
66 #include <alloca.h>
67 #endif
70 /************************************************************************
71 General
72 ************************************************************************/
74 /* The difference in pixels between the top left corner of the
75 Emacs window (including possible window manager decorations)
76 and FRAME_MAC_WINDOW (f). */
77 #define FRAME_OUTER_TO_INNER_DIFF_X(f) ((f)->x_pixels_diff)
78 #define FRAME_OUTER_TO_INNER_DIFF_Y(f) ((f)->y_pixels_diff)
80 #define mac_window_to_frame(wp) (((mac_output *) GetWRefCon (wp))->mFP)
82 void
83 mac_alert_sound_play ()
85 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
86 AlertSoundPlay ();
87 #else
88 SysBeep (1);
89 #endif
93 /************************************************************************
94 Application
95 ************************************************************************/
97 extern struct frame *mac_focus_frame P_ ((struct mac_display_info *));
98 extern void do_keystroke P_ ((EventKind, unsigned char, UInt32, UInt32,
99 unsigned long, struct input_event *));
100 extern UInt32 mac_mapped_modifiers P_ ((UInt32, UInt32));
101 #if TARGET_API_MAC_CARBON
102 extern int mac_to_emacs_modifiers P_ ((UInt32, UInt32));
103 #else
104 extern int mac_to_emacs_modifiers P_ ((EventModifiers, EventModifiers));
105 #endif
107 #if TARGET_API_MAC_CARBON
108 /* Points to the variable `inev' in the function XTread_socket. It is
109 used for passing an input event to the function back from
110 Carbon/Apple event handlers. */
111 static struct input_event *read_socket_inev = NULL;
113 extern const unsigned char keycode_to_xkeysym_table[];
114 extern EMACS_INT extra_keyboard_modifiers;
116 extern Lisp_Object Qhi_command;
117 #if USE_MAC_TSM
118 static TSMDocumentID tsm_document_id;
119 extern Lisp_Object Qtext_input;
120 extern Lisp_Object Qupdate_active_input_area, Qunicode_for_key_event;
121 extern Lisp_Object Vmac_ts_active_input_overlay, Vmac_ts_active_input_buf;
122 extern Lisp_Object Qbefore_string;
123 #endif
125 static int mac_event_to_emacs_modifiers P_ ((EventRef));
126 static OSStatus install_menu_target_item_handler P_ ((void));
127 #ifdef MAC_OSX
128 static OSStatus install_service_handler P_ ((void));
129 #endif
131 extern OSStatus mac_store_event_ref_as_apple_event P_ ((AEEventClass, AEEventID,
132 Lisp_Object,
133 Lisp_Object,
134 EventRef, UInt32,
135 const EventParamName *,
136 const EventParamType *));
137 extern int fast_find_position P_ ((struct window *, int, int *, int *,
138 int *, int *, Lisp_Object));
139 extern struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
140 int *, int *, int *, int *, int *));
141 extern void mac_ax_selected_text_range P_ ((struct frame *, CFRange *));
142 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
143 extern unsigned int mac_ax_number_of_characters P_ ((struct frame *));
144 #endif
146 #if USE_MAC_TSM
147 extern OSStatus mac_restore_keyboard_input_source P_ ((void));
148 extern void mac_save_keyboard_input_source P_ ((void));
150 static OSStatus
151 mac_tsm_resume ()
153 OSStatus err;
155 err = ActivateTSMDocument (tsm_document_id);
156 if (err == noErr)
157 err = mac_restore_keyboard_input_source ();
159 return err;
162 static OSStatus
163 mac_tsm_suspend ()
165 OSStatus err;
167 mac_save_keyboard_input_source ();
168 err = DeactivateTSMDocument (tsm_document_id);
170 return err;
173 static void
174 init_tsm ()
176 #ifdef MAC_OSX
177 static InterfaceTypeList types = {kUnicodeDocument};
178 #else
179 static InterfaceTypeList types = {kTextService};
180 #endif
182 NewTSMDocument (sizeof (types) / sizeof (types[0]), types,
183 &tsm_document_id, 0);
185 #endif /* USE_MAC_TSM */
187 static pascal OSStatus
188 mac_handle_keyboard_event (next_handler, event, data)
189 EventHandlerCallRef next_handler;
190 EventRef event;
191 void *data;
193 OSStatus err, result = eventNotHandledErr;
194 UInt32 event_kind, key_code, modifiers;
195 unsigned char char_code;
197 event_kind = GetEventKind (event);
198 switch (event_kind)
200 case kEventRawKeyDown:
201 case kEventRawKeyRepeat:
202 case kEventRawKeyUp:
203 /* When using Carbon Events, we need to pass raw keyboard events
204 to the TSM ourselves. If TSM handles it, it will pass back
205 noErr, otherwise it will pass back "eventNotHandledErr" and
206 we can process it normally. */
207 result = CallNextEventHandler (next_handler, event);
208 if (result != eventNotHandledErr)
209 break;
211 if (read_socket_inev == NULL)
212 break;
214 #if USE_MAC_TSM
215 if (read_socket_inev->kind != NO_EVENT)
217 result = noErr;
218 break;
220 #endif
222 if (event_kind == kEventRawKeyUp)
223 break;
225 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
226 typeChar, NULL,
227 sizeof (char), NULL, &char_code);
228 if (err != noErr)
229 break;
231 err = GetEventParameter (event, kEventParamKeyCode,
232 typeUInt32, NULL,
233 sizeof (UInt32), NULL, &key_code);
234 if (err != noErr)
235 break;
237 err = GetEventParameter (event, kEventParamKeyModifiers,
238 typeUInt32, NULL,
239 sizeof (UInt32), NULL, &modifiers);
240 if (err != noErr)
241 break;
243 do_keystroke ((event_kind == kEventRawKeyDown ? keyDown : autoKey),
244 char_code, key_code, modifiers,
245 ((unsigned long)
246 (GetEventTime (event) / kEventDurationMillisecond)),
247 read_socket_inev);
248 result = noErr;
249 break;
251 default:
252 abort ();
255 return result;
258 static pascal OSStatus
259 mac_handle_command_event (next_handler, event, data)
260 EventHandlerCallRef next_handler;
261 EventRef event;
262 void *data;
264 OSStatus err, result = eventNotHandledErr;
265 HICommand command;
266 static const EventParamName names[] =
267 {kEventParamDirectObject, kEventParamKeyModifiers};
268 static const EventParamType types[] =
269 {typeHICommand, typeUInt32};
270 int num_params = sizeof (names) / sizeof (names[0]);
272 err = GetEventParameter (event, kEventParamDirectObject, typeHICommand,
273 NULL, sizeof (HICommand), NULL, &command);
274 if (err != noErr)
275 return eventNotHandledErr;
277 switch (GetEventKind (event))
279 case kEventCommandProcess:
280 result = CallNextEventHandler (next_handler, event);
281 if (result != eventNotHandledErr)
282 break;
284 err = GetEventParameter (event, kEventParamDirectObject,
285 typeHICommand, NULL,
286 sizeof (HICommand), NULL, &command);
288 if (err != noErr || command.commandID == 0)
289 break;
291 /* A HI command event is mapped to an Apple event whose event
292 class symbol is `hi-command' and event ID is its command
293 ID. */
294 err = mac_store_event_ref_as_apple_event (0, command.commandID,
295 Qhi_command, Qnil,
296 event, num_params,
297 names, types);
298 if (err == noErr)
299 result = noErr;
300 break;
302 default:
303 abort ();
306 return result;
309 static pascal OSStatus
310 mac_handle_mouse_event (next_handler, event, data)
311 EventHandlerCallRef next_handler;
312 EventRef event;
313 void *data;
315 OSStatus err, result = eventNotHandledErr;
317 switch (GetEventKind (event))
319 case kEventMouseWheelMoved:
321 WindowRef wp;
322 struct frame *f;
323 EventMouseWheelAxis axis;
324 SInt32 delta;
325 Point point;
327 result = CallNextEventHandler (next_handler, event);
328 if (result != eventNotHandledErr || read_socket_inev == NULL)
329 break;
331 f = mac_focus_frame (&one_mac_display_info);
333 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef,
334 NULL, sizeof (WindowRef), NULL, &wp);
335 if (err != noErr
336 || wp != FRAME_MAC_WINDOW (f))
337 break;
339 err = GetEventParameter (event, kEventParamMouseWheelAxis,
340 typeMouseWheelAxis, NULL,
341 sizeof (EventMouseWheelAxis), NULL, &axis);
342 if (err != noErr || axis != kEventMouseWheelAxisY)
343 break;
345 err = GetEventParameter (event, kEventParamMouseLocation,
346 typeQDPoint, NULL, sizeof (Point),
347 NULL, &point);
348 if (err != noErr)
349 break;
351 point.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
352 point.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
353 if (point.h < 0 || point.v < 0
354 || EQ (window_from_coordinates (f, point.h, point.v, 0, 0, 0, 1),
355 f->tool_bar_window))
356 break;
358 err = GetEventParameter (event, kEventParamMouseWheelDelta,
359 typeSInt32, NULL, sizeof (SInt32),
360 NULL, &delta);
361 if (err != noErr)
362 break;
364 read_socket_inev->kind = WHEEL_EVENT;
365 read_socket_inev->code = 0;
366 read_socket_inev->modifiers =
367 (mac_event_to_emacs_modifiers (event)
368 | ((delta < 0) ? down_modifier : up_modifier));
369 XSETINT (read_socket_inev->x, point.h);
370 XSETINT (read_socket_inev->y, point.v);
371 XSETFRAME (read_socket_inev->frame_or_window, f);
373 result = noErr;
375 break;
377 default:
378 abort ();
381 return result;
384 #if USE_MAC_TSM
385 extern void mac_get_selected_range P_ ((struct window *, CFRange *));
386 extern int mac_store_buffer_text_to_unicode_chars P_ ((struct buffer *,
387 int, int, UniChar *));
389 static pascal OSStatus
390 mac_handle_text_input_event (next_handler, event, data)
391 EventHandlerCallRef next_handler;
392 EventRef event;
393 void *data;
395 OSStatus err, result;
396 Lisp_Object id_key = Qnil;
397 int num_params;
398 const EventParamName *names;
399 const EventParamType *types;
400 static UInt32 seqno_uaia = 0;
401 static const EventParamName names_uaia[] =
402 {kEventParamTextInputSendComponentInstance,
403 kEventParamTextInputSendRefCon,
404 kEventParamTextInputSendSLRec,
405 kEventParamTextInputSendFixLen,
406 kEventParamTextInputSendText,
407 kEventParamTextInputSendUpdateRng,
408 kEventParamTextInputSendHiliteRng,
409 kEventParamTextInputSendClauseRng,
410 kEventParamTextInputSendPinRng,
411 kEventParamTextInputSendTextServiceEncoding,
412 kEventParamTextInputSendTextServiceMacEncoding,
413 EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER};
414 static const EventParamType types_uaia[] =
415 {typeComponentInstance,
416 typeLongInteger,
417 typeIntlWritingCode,
418 typeLongInteger,
419 #ifdef MAC_OSX
420 typeUnicodeText,
421 #else
422 typeChar,
423 #endif
424 typeTextRangeArray,
425 typeTextRangeArray,
426 typeOffsetArray,
427 typeTextRange,
428 typeUInt32,
429 typeUInt32,
430 typeUInt32};
431 static const EventParamName names_ufke[] =
432 {kEventParamTextInputSendComponentInstance,
433 kEventParamTextInputSendRefCon,
434 kEventParamTextInputSendSLRec,
435 kEventParamTextInputSendText};
436 static const EventParamType types_ufke[] =
437 {typeComponentInstance,
438 typeLongInteger,
439 typeIntlWritingCode,
440 typeUnicodeText};
442 result = CallNextEventHandler (next_handler, event);
443 if (result != eventNotHandledErr)
444 return result;
446 switch (GetEventKind (event))
448 case kEventTextInputUpdateActiveInputArea:
449 id_key = Qupdate_active_input_area;
450 num_params = sizeof (names_uaia) / sizeof (names_uaia[0]);
451 names = names_uaia;
452 types = types_uaia;
453 SetEventParameter (event, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER,
454 typeUInt32, sizeof (UInt32), &seqno_uaia);
455 seqno_uaia++;
456 result = noErr;
457 break;
459 case kEventTextInputUnicodeForKeyEvent:
461 EventRef kbd_event;
462 UInt32 actual_size, modifiers, key_code;
464 err = GetEventParameter (event, kEventParamTextInputSendKeyboardEvent,
465 typeEventRef, NULL, sizeof (EventRef), NULL,
466 &kbd_event);
467 if (err == noErr)
468 err = GetEventParameter (kbd_event, kEventParamKeyModifiers,
469 typeUInt32, NULL,
470 sizeof (UInt32), NULL, &modifiers);
471 if (err == noErr)
472 err = GetEventParameter (kbd_event, kEventParamKeyCode,
473 typeUInt32, NULL, sizeof (UInt32),
474 NULL, &key_code);
475 if (err == noErr && mac_mapped_modifiers (modifiers, key_code))
476 /* There're mapped modifier keys. Process it in
477 do_keystroke. */
478 break;
479 if (err == noErr)
480 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
481 typeUnicodeText, NULL, 0, &actual_size,
482 NULL);
483 if (err == noErr && actual_size == sizeof (UniChar))
485 UniChar code;
487 err = GetEventParameter (kbd_event, kEventParamKeyUnicodes,
488 typeUnicodeText, NULL,
489 sizeof (UniChar), NULL, &code);
490 if (err == noErr && code < 0x80)
492 /* ASCII character. Process it in do_keystroke. */
493 if (read_socket_inev && code >= 0x20 && code <= 0x7e
494 && !(key_code <= 0x7f
495 && keycode_to_xkeysym_table [key_code]))
497 struct frame *f = mac_focus_frame (&one_mac_display_info);
499 read_socket_inev->kind = ASCII_KEYSTROKE_EVENT;
500 read_socket_inev->code = code;
501 read_socket_inev->modifiers =
502 mac_to_emacs_modifiers (modifiers, 0);
503 read_socket_inev->modifiers |=
504 (extra_keyboard_modifiers
505 & (meta_modifier | alt_modifier
506 | hyper_modifier | super_modifier));
507 XSETFRAME (read_socket_inev->frame_or_window, f);
509 break;
512 if (err == noErr)
514 /* Non-ASCII keystrokes without mapped modifiers are
515 processed at the Lisp level. */
516 id_key = Qunicode_for_key_event;
517 num_params = sizeof (names_ufke) / sizeof (names_ufke[0]);
518 names = names_ufke;
519 types = types_ufke;
520 result = noErr;
523 break;
525 case kEventTextInputOffsetToPos:
527 long byte_offset;
528 struct frame *f;
529 struct window *w;
530 Point p;
532 err = GetEventParameter (event, kEventParamTextInputSendTextOffset,
533 typeLongInteger, NULL, sizeof (long), NULL,
534 &byte_offset);
535 if (err != noErr)
536 break;
538 if (STRINGP (Vmac_ts_active_input_buf)
539 && SBYTES (Vmac_ts_active_input_buf) != 0)
541 if (!OVERLAYP (Vmac_ts_active_input_overlay))
542 break;
544 /* Strictly speaking, this is not always correct because
545 previous events may change some states about display. */
546 if (!NILP (Foverlay_get (Vmac_ts_active_input_overlay, Qbefore_string)))
548 /* Active input area is displayed around the current point. */
549 f = SELECTED_FRAME ();
550 w = XWINDOW (f->selected_window);
552 else if (WINDOWP (echo_area_window))
554 /* Active input area is displayed in the echo area. */
555 w = XWINDOW (echo_area_window);
556 f = WINDOW_XFRAME (w);
558 else
559 break;
561 p.h = (WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x)
562 + WINDOW_LEFT_FRINGE_WIDTH (w)
563 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
564 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y)
565 + FONT_BASE (FRAME_FONT (f))
566 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
568 else
570 #ifndef MAC_OSX
571 break;
572 #else /* MAC_OSX */
573 CFRange sel_range;
574 int charpos;
575 int hpos, vpos, x, y;
576 struct glyph_row *row;
577 struct glyph *glyph;
578 XFontStruct *font;
580 f = mac_focus_frame (&one_mac_display_info);
581 w = XWINDOW (f->selected_window);
582 mac_get_selected_range (w, &sel_range);
583 charpos = (BUF_BEGV (XBUFFER (w->buffer)) + sel_range.location
584 + byte_offset / (long) sizeof (UniChar));
586 if (!fast_find_position (w, charpos, &hpos, &vpos, &x, &y, Qnil))
588 result = errOffsetInvalid;
589 break;
592 row = MATRIX_ROW (w->current_matrix, vpos);
593 glyph = row->glyphs[TEXT_AREA] + hpos;
594 if (glyph->type != CHAR_GLYPH || glyph->glyph_not_available_p)
595 break;
597 p.h = (WINDOW_TEXT_TO_FRAME_PIXEL_X (w, x)
598 + f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
599 p.v = (WINDOW_TO_FRAME_PIXEL_Y (w, y)
600 + row->visible_height
601 + f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
603 font = FACE_FROM_ID (f, glyph->face_id)->font;
604 if (font)
606 Fixed point_size = Long2Fix (font->mac_fontsize);
607 short height = row->visible_height;
608 short ascent = row->ascent;
610 SetEventParameter (event,
611 kEventParamTextInputReplyPointSize,
612 typeFixed, sizeof (Fixed), &point_size);
613 SetEventParameter (event,
614 kEventParamTextInputReplyLineHeight,
615 typeShortInteger, sizeof (short), &height);
616 SetEventParameter (event,
617 kEventParamTextInputReplyLineAscent,
618 typeShortInteger, sizeof (short), &ascent);
619 if (font->mac_fontnum != -1)
621 OSStatus err1;
622 FMFont fm_font;
623 FMFontStyle style;
625 err1 = FMGetFontFromFontFamilyInstance (font->mac_fontnum,
626 font->mac_fontface,
627 &fm_font, &style);
628 if (err1 == noErr)
629 SetEventParameter (event, kEventParamTextInputReplyFMFont,
630 typeUInt32, sizeof (UInt32), &fm_font);
631 else
633 long qd_font = font->mac_fontnum;
635 SetEventParameter (event, kEventParamTextInputReplyFont,
636 typeLongInteger, sizeof (long),
637 &qd_font);
640 else if (font->mac_style)
642 OSStatus err1;
643 ATSUFontID font_id;
645 err1 = ATSUGetAttribute (font->mac_style, kATSUFontTag,
646 sizeof (ATSUFontID), &font_id,
647 NULL);
648 if (err1 == noErr)
649 SetEventParameter (event, kEventParamTextInputReplyFMFont,
650 typeUInt32, sizeof (UInt32), &font_id);
652 else
653 abort ();
655 #endif /* MAC_OSX */
658 err = SetEventParameter (event, kEventParamTextInputReplyPoint,
659 typeQDPoint, sizeof (Point), &p);
660 if (err == noErr)
661 result = noErr;
663 break;
665 #ifdef MAC_OSX
666 case kEventTextInputPosToOffset:
668 Point point;
669 Boolean leading_edge_p = true;
670 struct frame *f;
671 int x, y;
672 Lisp_Object window;
673 enum window_part part;
674 long region_class = kTSMOutsideOfBody, byte_offset = 0;
676 err = GetEventParameter (event, kEventParamTextInputSendCurrentPoint,
677 typeQDPoint, NULL, sizeof (Point), NULL,
678 &point);
679 if (err != noErr)
680 break;
682 GetEventParameter (event, kEventParamTextInputReplyLeadingEdge,
683 typeBoolean, NULL, sizeof (Boolean), NULL,
684 &leading_edge_p);
686 f = mac_focus_frame (&one_mac_display_info);
687 x = point.h - (f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f));
688 y = point.v - (f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f));
689 window = window_from_coordinates (f, x, y, &part, 0, 0, 1);
690 if (WINDOWP (window) && EQ (window, f->selected_window))
692 struct window *w;
693 struct buffer *b;
695 /* Convert to window-relative pixel coordinates. */
696 w = XWINDOW (window);
697 frame_to_window_pixel_xy (w, &x, &y);
699 /* Are we in a window whose display is up to date?
700 And verify the buffer's text has not changed. */
701 b = XBUFFER (w->buffer);
702 if (part == ON_TEXT
703 && EQ (w->window_end_valid, w->buffer)
704 && XINT (w->last_modified) == BUF_MODIFF (b)
705 && XINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
707 int hpos, vpos, area;
708 struct glyph *glyph;
710 /* Find the glyph under X/Y. */
711 glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, 0, 0, &area);
713 if (glyph != NULL && area == TEXT_AREA)
715 byte_offset = ((glyph->charpos - BUF_BEGV (b))
716 * sizeof (UniChar));
717 region_class = kTSMInsideOfBody;
722 err = SetEventParameter (event, kEventParamTextInputReplyRegionClass,
723 typeLongInteger, sizeof (long),
724 &region_class);
725 if (err == noErr)
726 err = SetEventParameter (event, kEventParamTextInputReplyTextOffset,
727 typeLongInteger, sizeof (long),
728 &byte_offset);
729 if (err == noErr)
730 result = noErr;
732 break;
734 case kEventTextInputGetSelectedText:
736 struct frame *f = mac_focus_frame (&one_mac_display_info);
737 struct window *w = XWINDOW (f->selected_window);
738 struct buffer *b = XBUFFER (w->buffer);
739 CFRange sel_range;
740 int start, end;
741 UniChar *characters, c;
743 if (poll_suppress_count == 0 && !NILP (Vinhibit_quit))
744 /* Don't try to get buffer contents as the gap might be
745 being altered. */
746 break;
748 mac_get_selected_range (w, &sel_range);
749 if (sel_range.length == 0)
751 Boolean leading_edge_p;
753 err = GetEventParameter (event,
754 kEventParamTextInputReplyLeadingEdge,
755 typeBoolean, NULL, sizeof (Boolean), NULL,
756 &leading_edge_p);
757 if (err != noErr)
758 break;
760 start = BUF_BEGV (b) + sel_range.location;
761 if (!leading_edge_p)
762 start--;
763 end = start + 1;
764 characters = &c;
766 if (start < BUF_BEGV (b) || end > BUF_ZV (b))
767 break;
769 else
771 start = BUF_BEGV (b) + sel_range.location;
772 end = start + sel_range.length;
773 characters = xmalloc (sel_range.length * sizeof (UniChar));
776 if (mac_store_buffer_text_to_unicode_chars (b, start, end, characters))
777 err = SetEventParameter (event, kEventParamTextInputReplyText,
778 typeUnicodeText,
779 sel_range.length * sizeof (UniChar),
780 characters);
781 if (characters != &c)
782 xfree (characters);
784 if (err == noErr)
785 result = noErr;
787 break;
788 #endif /* MAC_OSX */
790 default:
791 abort ();
794 if (!NILP (id_key))
795 err = mac_store_event_ref_as_apple_event (0, 0, Qtext_input, id_key,
796 event, num_params,
797 names, types);
798 return result;
801 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
802 static pascal OSStatus
803 mac_handle_document_access_event (next_handler, event, data)
804 EventHandlerCallRef next_handler;
805 EventRef event;
806 void *data;
808 OSStatus err, result;
809 struct frame *f = mac_focus_frame (&one_mac_display_info);
811 result = CallNextEventHandler (next_handler, event);
812 if (result != eventNotHandledErr)
813 return result;
815 switch (GetEventKind (event))
817 case kEventTSMDocumentAccessGetLength:
819 CFIndex count = mac_ax_number_of_characters (f);
821 err = SetEventParameter (event, kEventParamTSMDocAccessCharacterCount,
822 typeCFIndex, sizeof (CFIndex), &count);
823 if (err == noErr)
824 result = noErr;
826 break;
828 case kEventTSMDocumentAccessGetSelectedRange:
830 CFRange sel_range;
832 mac_ax_selected_text_range (f, &sel_range);
833 err = SetEventParameter (event,
834 kEventParamTSMDocAccessReplyCharacterRange,
835 typeCFRange, sizeof (CFRange), &sel_range);
836 if (err == noErr)
837 result = noErr;
839 break;
841 case kEventTSMDocumentAccessGetCharacters:
843 struct buffer *b = XBUFFER (XWINDOW (f->selected_window)->buffer);
844 CFRange range;
845 Ptr characters;
846 int start, end;
848 if (poll_suppress_count == 0 && !NILP (Vinhibit_quit))
849 /* Don't try to get buffer contents as the gap might be
850 being altered. */
851 break;
853 err = GetEventParameter (event,
854 kEventParamTSMDocAccessSendCharacterRange,
855 typeCFRange, NULL, sizeof (CFRange), NULL,
856 &range);
857 if (err == noErr)
858 err = GetEventParameter (event,
859 kEventParamTSMDocAccessSendCharactersPtr,
860 typePtr, NULL, sizeof (Ptr), NULL,
861 &characters);
862 if (err != noErr)
863 break;
865 start = BUF_BEGV (b) + range.location;
866 end = start + range.length;
867 if (mac_store_buffer_text_to_unicode_chars (b, start, end,
868 (UniChar *) characters))
869 result = noErr;
871 break;
873 default:
874 abort ();
877 return result;
879 #endif
880 #endif
882 OSStatus
883 install_application_handler ()
885 OSStatus err = noErr;
887 if (err == noErr)
889 static const EventTypeSpec specs[] =
890 {{kEventClassKeyboard, kEventRawKeyDown},
891 {kEventClassKeyboard, kEventRawKeyRepeat},
892 {kEventClassKeyboard, kEventRawKeyUp}};
894 err = InstallApplicationEventHandler (NewEventHandlerUPP
895 (mac_handle_keyboard_event),
896 GetEventTypeCount (specs),
897 specs, NULL, NULL);
900 if (err == noErr)
902 static const EventTypeSpec specs[] =
903 {{kEventClassCommand, kEventCommandProcess}};
905 err = InstallApplicationEventHandler (NewEventHandlerUPP
906 (mac_handle_command_event),
907 GetEventTypeCount (specs),
908 specs, NULL, NULL);
911 if (err == noErr)
913 static const EventTypeSpec specs[] =
914 {{kEventClassMouse, kEventMouseWheelMoved}};
916 err = InstallApplicationEventHandler (NewEventHandlerUPP
917 (mac_handle_mouse_event),
918 GetEventTypeCount (specs),
919 specs, NULL, NULL);
922 #if USE_MAC_TSM
923 if (err == noErr)
925 static const EventTypeSpec specs[] =
926 {{kEventClassTextInput, kEventTextInputUpdateActiveInputArea},
927 {kEventClassTextInput, kEventTextInputUnicodeForKeyEvent},
928 {kEventClassTextInput, kEventTextInputOffsetToPos},
929 #ifdef MAC_OSX
930 {kEventClassTextInput, kEventTextInputPosToOffset},
931 {kEventClassTextInput, kEventTextInputGetSelectedText}
932 #endif
935 err = InstallApplicationEventHandler (NewEventHandlerUPP
936 (mac_handle_text_input_event),
937 GetEventTypeCount (specs),
938 specs, NULL, NULL);
941 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
942 if (err == noErr)
944 static const EventTypeSpec specs[] =
945 {{kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength},
946 {kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange},
947 {kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters}};
949 err = InstallApplicationEventHandler (mac_handle_document_access_event,
950 GetEventTypeCount (specs),
951 specs, NULL, NULL);
953 #endif
954 #endif
956 if (err == noErr)
957 err = install_menu_target_item_handler ();
959 #ifdef MAC_OSX
960 if (err == noErr)
961 err = install_service_handler ();
962 #endif
964 return err;
966 #endif /* TARGET_API_MAC_CARBON */
969 /************************************************************************
970 Windows
971 ************************************************************************/
973 #define DEFAULT_NUM_COLS 80
975 #define MIN_DOC_SIZE 64
976 #define MAX_DOC_SIZE 32767
978 /* Drag and Drop */
979 static OSErr install_drag_handler P_ ((WindowRef));
980 static void remove_drag_handler P_ ((WindowRef));
982 #if USE_CG_DRAWING
983 static void mac_prepare_for_quickdraw P_ ((struct frame *));
984 #endif
986 extern void mac_handle_visibility_change P_ ((struct frame *));
987 extern void mac_handle_origin_change P_ ((struct frame *));
988 extern void mac_handle_size_change P_ ((struct frame *, int, int));
990 #if TARGET_API_MAC_CARBON
991 #ifdef MAC_OSX
992 extern Lisp_Object Qwindow;
993 extern Lisp_Object Qtoolbar_switch_mode;
994 #endif
995 #endif
997 static void
998 do_window_update (WindowRef win)
1000 struct frame *f = mac_window_to_frame (win);
1002 BeginUpdate (win);
1004 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
1005 below. */
1006 if (win != tip_window)
1008 if (f->async_visible == 0)
1010 /* Update events may occur when a frame gets iconified. */
1011 #if 0
1012 f->async_visible = 1;
1013 f->async_iconified = 0;
1014 SET_FRAME_GARBAGED (f);
1015 #endif
1017 else
1019 Rect r;
1020 #if TARGET_API_MAC_CARBON
1021 RgnHandle region = NewRgn ();
1023 GetPortVisibleRegion (GetWindowPort (win), region);
1024 GetRegionBounds (region, &r);
1025 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
1026 #if USE_CG_DRAWING
1027 mac_prepare_for_quickdraw (f);
1028 #endif
1029 UpdateControls (win, region);
1030 DisposeRgn (region);
1031 #else
1032 r = (*win->visRgn)->rgnBBox;
1033 expose_frame (f, r.left, r.top, r.right - r.left, r.bottom - r.top);
1034 UpdateControls (win, win->visRgn);
1035 #endif
1039 EndUpdate (win);
1042 static int
1043 is_emacs_window (WindowRef win)
1045 Lisp_Object tail, frame;
1047 if (!win)
1048 return 0;
1050 FOR_EACH_FRAME (tail, frame)
1051 if (FRAME_MAC_P (XFRAME (frame)))
1052 if (FRAME_MAC_WINDOW (XFRAME (frame)) == win)
1053 return 1;
1055 return 0;
1058 /* Handle drags in size box. Based on code contributed by Ben
1059 Mesander and IM - Window Manager A. */
1061 static void
1062 do_grow_window (w, e)
1063 WindowRef w;
1064 const EventRecord *e;
1066 Rect limit_rect;
1067 int rows, columns, width, height;
1068 struct frame *f = mac_window_to_frame (w);
1069 XSizeHints *size_hints = FRAME_SIZE_HINTS (f);
1070 int min_width = MIN_DOC_SIZE, min_height = MIN_DOC_SIZE;
1071 #if TARGET_API_MAC_CARBON
1072 Rect new_rect;
1073 #else
1074 long grow_size;
1075 #endif
1077 if (size_hints->flags & PMinSize)
1079 min_width = size_hints->min_width;
1080 min_height = size_hints->min_height;
1082 SetRect (&limit_rect, min_width, min_height, MAX_DOC_SIZE, MAX_DOC_SIZE);
1084 #if TARGET_API_MAC_CARBON
1085 if (!ResizeWindow (w, e->where, &limit_rect, &new_rect))
1086 return;
1087 height = new_rect.bottom - new_rect.top;
1088 width = new_rect.right - new_rect.left;
1089 #else
1090 grow_size = GrowWindow (w, e->where, &limit_rect);
1091 /* see if it really changed size */
1092 if (grow_size == 0)
1093 return;
1094 height = HiWord (grow_size);
1095 width = LoWord (grow_size);
1096 #endif
1098 if (width != FRAME_PIXEL_WIDTH (f)
1099 || height != FRAME_PIXEL_HEIGHT (f))
1101 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
1102 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
1104 x_set_window_size (f, 0, columns, rows);
1108 #if TARGET_API_MAC_CARBON
1109 static Point
1110 mac_get_ideal_size (f)
1111 struct frame *f;
1113 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
1114 WindowRef w = FRAME_MAC_WINDOW (f);
1115 Point ideal_size;
1116 Rect standard_rect;
1117 int height, width, columns, rows;
1119 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
1120 ideal_size.v = dpyinfo->height;
1121 IsWindowInStandardState (w, &ideal_size, &standard_rect);
1122 /* Adjust the standard size according to character boundaries. */
1123 width = standard_rect.right - standard_rect.left;
1124 height = standard_rect.bottom - standard_rect.top;
1125 columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width);
1126 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height);
1127 ideal_size.h = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, columns);
1128 ideal_size.v = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1130 return ideal_size;
1133 static pascal OSStatus
1134 mac_handle_window_event (next_handler, event, data)
1135 EventHandlerCallRef next_handler;
1136 EventRef event;
1137 void *data;
1139 WindowRef wp;
1140 OSStatus err, result = eventNotHandledErr;
1141 struct frame *f;
1142 UInt32 attributes;
1143 XSizeHints *size_hints;
1145 err = GetEventParameter (event, kEventParamDirectObject, typeWindowRef,
1146 NULL, sizeof (WindowRef), NULL, &wp);
1147 if (err != noErr)
1148 return eventNotHandledErr;
1150 f = mac_window_to_frame (wp);
1151 switch (GetEventKind (event))
1153 /* -- window refresh events -- */
1155 case kEventWindowUpdate:
1156 result = CallNextEventHandler (next_handler, event);
1157 if (result != eventNotHandledErr)
1158 break;
1160 do_window_update (wp);
1161 result = noErr;
1162 break;
1164 /* -- window state change events -- */
1166 case kEventWindowShowing:
1167 size_hints = FRAME_SIZE_HINTS (f);
1168 if (!(size_hints->flags & (USPosition | PPosition)))
1170 struct frame *sf = SELECTED_FRAME ();
1172 if (!(FRAME_MAC_P (sf) && sf->async_visible))
1173 RepositionWindow (wp, NULL, kWindowCenterOnMainScreen);
1174 else
1176 RepositionWindow (wp, FRAME_MAC_WINDOW (sf),
1177 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1178 kWindowCascadeStartAtParentWindowScreen
1179 #else
1180 kWindowCascadeOnParentWindowScreen
1181 #endif
1183 #if USE_MAC_TOOLBAR
1184 /* This is a workaround. RepositionWindow fails to put
1185 a window at the cascading position when its parent
1186 window has a Carbon HIToolbar. */
1187 if ((f->left_pos == sf->left_pos
1188 && f->top_pos == sf->top_pos)
1189 || (f->left_pos == sf->left_pos + 10 * 2
1190 && f->top_pos == sf->top_pos + 32 * 2))
1191 MoveWindowStructure (wp, sf->left_pos + 10, sf->top_pos + 32);
1192 #endif
1194 result = noErr;
1196 break;
1198 case kEventWindowHiding:
1199 /* Before unmapping the window, update the WM_SIZE_HINTS
1200 property to claim that the current position of the window is
1201 user-specified, rather than program-specified, so that when
1202 the window is mapped again, it will be placed at the same
1203 location, without forcing the user to position it by hand
1204 again (they have already done that once for this window.) */
1205 x_wm_set_size_hint (f, (long) 0, 1);
1206 result = noErr;
1207 break;
1209 case kEventWindowShown:
1210 case kEventWindowHidden:
1211 case kEventWindowCollapsed:
1212 case kEventWindowExpanded:
1213 mac_handle_visibility_change (f);
1214 result = noErr;
1215 break;
1217 case kEventWindowBoundsChanging:
1218 result = CallNextEventHandler (next_handler, event);
1219 if (result != eventNotHandledErr)
1220 break;
1222 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
1223 NULL, sizeof (UInt32), NULL, &attributes);
1224 if (err != noErr)
1225 break;
1227 size_hints = FRAME_SIZE_HINTS (f);
1228 if ((attributes & kWindowBoundsChangeUserResize)
1229 && ((size_hints->flags & (PResizeInc | PBaseSize | PMinSize))
1230 == (PResizeInc | PBaseSize | PMinSize)))
1232 Rect bounds;
1233 int width, height;
1235 err = GetEventParameter (event, kEventParamCurrentBounds,
1236 typeQDRectangle, NULL, sizeof (Rect),
1237 NULL, &bounds);
1238 if (err != noErr)
1239 break;
1241 width = bounds.right - bounds.left;
1242 height = bounds.bottom - bounds.top;
1244 if (width < size_hints->min_width)
1245 width = size_hints->min_width;
1246 else
1247 width = size_hints->base_width
1248 + (int) ((width - size_hints->base_width)
1249 / (float) size_hints->width_inc + .5)
1250 * size_hints->width_inc;
1252 if (height < size_hints->min_height)
1253 height = size_hints->min_height;
1254 else
1255 height = size_hints->base_height
1256 + (int) ((height - size_hints->base_height)
1257 / (float) size_hints->height_inc + .5)
1258 * size_hints->height_inc;
1260 bounds.right = bounds.left + width;
1261 bounds.bottom = bounds.top + height;
1262 SetEventParameter (event, kEventParamCurrentBounds,
1263 typeQDRectangle, sizeof (Rect), &bounds);
1264 result = noErr;
1266 break;
1268 case kEventWindowBoundsChanged:
1269 err = GetEventParameter (event, kEventParamAttributes, typeUInt32,
1270 NULL, sizeof (UInt32), NULL, &attributes);
1271 if (err != noErr)
1272 break;
1274 if (attributes & kWindowBoundsChangeSizeChanged)
1276 Rect bounds;
1278 err = GetEventParameter (event, kEventParamCurrentBounds,
1279 typeQDRectangle, NULL, sizeof (Rect),
1280 NULL, &bounds);
1281 if (err == noErr)
1283 int width, height;
1285 width = bounds.right - bounds.left;
1286 height = bounds.bottom - bounds.top;
1287 mac_handle_size_change (f, width, height);
1288 mac_wakeup_from_rne ();
1292 if (attributes & kWindowBoundsChangeOriginChanged)
1293 mac_handle_origin_change (f);
1295 result = noErr;
1296 break;
1298 /* -- window action events -- */
1300 case kEventWindowClose:
1302 struct input_event buf;
1304 EVENT_INIT (buf);
1305 buf.kind = DELETE_WINDOW_EVENT;
1306 XSETFRAME (buf.frame_or_window, f);
1307 buf.arg = Qnil;
1308 kbd_buffer_store_event (&buf);
1310 result = noErr;
1311 break;
1313 case kEventWindowGetIdealSize:
1314 result = CallNextEventHandler (next_handler, event);
1315 if (result != eventNotHandledErr)
1316 break;
1319 Point ideal_size = mac_get_ideal_size (f);
1321 err = SetEventParameter (event, kEventParamDimensions,
1322 typeQDPoint, sizeof (Point), &ideal_size);
1323 if (err == noErr)
1324 result = noErr;
1326 break;
1328 #ifdef MAC_OSX
1329 case kEventWindowToolbarSwitchMode:
1331 static const EventParamName names[] = {kEventParamDirectObject,
1332 kEventParamWindowMouseLocation,
1333 kEventParamKeyModifiers,
1334 kEventParamMouseButton,
1335 kEventParamClickCount,
1336 kEventParamMouseChord};
1337 static const EventParamType types[] = {typeWindowRef,
1338 typeQDPoint,
1339 typeUInt32,
1340 typeMouseButton,
1341 typeUInt32,
1342 typeUInt32};
1343 int num_params = sizeof (names) / sizeof (names[0]);
1345 err = mac_store_event_ref_as_apple_event (0, 0,
1346 Qwindow,
1347 Qtoolbar_switch_mode,
1348 event, num_params,
1349 names, types);
1351 if (err == noErr)
1352 result = noErr;
1353 break;
1354 #endif
1356 #if USE_MAC_TSM
1357 /* -- window focus events -- */
1359 case kEventWindowFocusAcquired:
1360 err = mac_tsm_resume ();
1361 if (err == noErr)
1362 result = noErr;
1363 break;
1365 case kEventWindowFocusRelinquish:
1366 err = mac_tsm_suspend ();
1367 if (err == noErr)
1368 result = noErr;
1369 break;
1370 #endif
1372 default:
1373 abort ();
1376 return result;
1378 #endif
1380 /* Handle clicks in zoom box. Calculation of "standard state" based
1381 on code in IM - Window Manager A and code contributed by Ben
1382 Mesander. The standard state of an Emacs window is 80-characters
1383 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
1385 static void
1386 do_zoom_window (WindowRef w, int zoom_in_or_out)
1388 Rect zoom_rect, port_rect;
1389 int width, height;
1390 struct frame *f = mac_window_to_frame (w);
1391 #if TARGET_API_MAC_CARBON
1392 Point ideal_size = mac_get_ideal_size (f);
1394 GetWindowBounds (w, kWindowContentRgn, &port_rect);
1395 if (IsWindowInStandardState (w, &ideal_size, &zoom_rect)
1396 && port_rect.left == zoom_rect.left
1397 && port_rect.top == zoom_rect.top)
1398 zoom_in_or_out = inZoomIn;
1399 else
1400 zoom_in_or_out = inZoomOut;
1402 #ifdef MAC_OS8
1403 mac_clear_area (f, 0, 0, port_rect.right - port_rect.left,
1404 port_rect.bottom - port_rect.top);
1405 #endif
1406 ZoomWindowIdeal (w, zoom_in_or_out, &ideal_size);
1407 #else /* not TARGET_API_MAC_CARBON */
1408 GrafPtr save_port;
1409 Point top_left;
1410 int w_title_height, rows;
1411 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
1413 GetPort (&save_port);
1415 SetPortWindowPort (w);
1417 /* Clear window to avoid flicker. */
1418 EraseRect (&(w->portRect));
1419 if (zoom_in_or_out == inZoomOut)
1421 SetPt (&top_left, w->portRect.left, w->portRect.top);
1422 LocalToGlobal (&top_left);
1424 /* calculate height of window's title bar */
1425 w_title_height = top_left.v - 1
1426 - (**((WindowPeek) w)->strucRgn).rgnBBox.top + GetMBarHeight ();
1428 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
1429 zoom_rect = qd.screenBits.bounds;
1430 zoom_rect.top += w_title_height;
1431 InsetRect (&zoom_rect, 8, 4); /* not too tight */
1433 zoom_rect.right = zoom_rect.left
1434 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, DEFAULT_NUM_COLS);
1436 /* Adjust the standard size according to character boundaries. */
1437 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, zoom_rect.bottom - zoom_rect.top);
1438 zoom_rect.bottom =
1439 zoom_rect.top + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1441 (**((WStateDataHandle) ((WindowPeek) w)->dataHandle)).stdState
1442 = zoom_rect;
1445 ZoomWindow (w, zoom_in_or_out, f == mac_focus_frame (dpyinfo));
1447 SetPort (save_port);
1448 #endif /* not TARGET_API_MAC_CARBON */
1450 #if !TARGET_API_MAC_CARBON
1451 /* retrieve window size and update application values */
1452 port_rect = w->portRect;
1453 height = port_rect.bottom - port_rect.top;
1454 width = port_rect.right - port_rect.left;
1456 mac_handle_size_change (f, width, height);
1457 mac_handle_origin_change (f);
1458 #endif
1461 static OSStatus
1462 install_window_handler (window)
1463 WindowRef window;
1465 OSStatus err = noErr;
1467 #if TARGET_API_MAC_CARBON
1468 if (err == noErr)
1470 static const EventTypeSpec specs[] =
1472 /* -- window refresh events -- */
1473 {kEventClassWindow, kEventWindowUpdate},
1474 /* -- window state change events -- */
1475 {kEventClassWindow, kEventWindowShowing},
1476 {kEventClassWindow, kEventWindowHiding},
1477 {kEventClassWindow, kEventWindowShown},
1478 {kEventClassWindow, kEventWindowHidden},
1479 {kEventClassWindow, kEventWindowCollapsed},
1480 {kEventClassWindow, kEventWindowExpanded},
1481 {kEventClassWindow, kEventWindowBoundsChanging},
1482 {kEventClassWindow, kEventWindowBoundsChanged},
1483 /* -- window action events -- */
1484 {kEventClassWindow, kEventWindowClose},
1485 {kEventClassWindow, kEventWindowGetIdealSize},
1486 #ifdef MAC_OSX
1487 {kEventClassWindow, kEventWindowToolbarSwitchMode},
1488 #endif
1489 #if USE_MAC_TSM
1490 /* -- window focus events -- */
1491 {kEventClassWindow, kEventWindowFocusAcquired},
1492 {kEventClassWindow, kEventWindowFocusRelinquish},
1493 #endif
1495 static EventHandlerUPP handle_window_eventUPP = NULL;
1497 if (handle_window_eventUPP == NULL)
1498 handle_window_eventUPP = NewEventHandlerUPP (mac_handle_window_event);
1500 err = InstallWindowEventHandler (window, handle_window_eventUPP,
1501 GetEventTypeCount (specs),
1502 specs, NULL, NULL);
1504 #endif
1506 if (err == noErr)
1507 err = install_drag_handler (window);
1509 return err;
1512 static void
1513 remove_window_handler (window)
1514 WindowRef window;
1516 remove_drag_handler (window);
1519 void
1520 mac_get_window_bounds (f, inner, outer)
1521 struct frame *f;
1522 Rect *inner, *outer;
1524 #if TARGET_API_MAC_CARBON
1525 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowContentRgn, inner);
1526 GetWindowBounds (FRAME_MAC_WINDOW (f), kWindowStructureRgn, outer);
1527 #else /* not TARGET_API_MAC_CARBON */
1528 RgnHandle region = NewRgn ();
1530 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowContentRgn, region);
1531 *inner = (*region)->rgnBBox;
1532 GetWindowRegion (FRAME_MAC_WINDOW (f), kWindowStructureRgn, region);
1533 *outer = (*region)->rgnBBox;
1534 DisposeRgn (region);
1535 #endif /* not TARGET_API_MAC_CARBON */
1538 Rect *
1539 mac_get_frame_bounds (f, r)
1540 struct frame *f;
1541 Rect *r;
1543 #if TARGET_API_MAC_CARBON
1544 return GetWindowPortBounds (FRAME_MAC_WINDOW (f), r);
1545 #else
1546 *r = FRAME_MAC_WINDOW (f)->portRect;
1548 return r;
1549 #endif
1552 void
1553 mac_get_frame_mouse (f, point)
1554 struct frame *f;
1555 Point *point;
1557 #if TARGET_API_MAC_CARBON
1558 GetGlobalMouse (point);
1559 point->h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1560 point->v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1561 #else
1562 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1563 GetMouse (point);
1564 #endif
1567 void
1568 mac_convert_frame_point_to_global (f, x, y)
1569 struct frame *f;
1570 int *x, *y;
1572 *x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
1573 *y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
1576 #if TARGET_API_MAC_CARBON
1577 void
1578 mac_update_proxy_icon (f)
1579 struct frame *f;
1581 OSStatus err;
1582 Lisp_Object file_name =
1583 XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer)->filename;
1584 Window w = FRAME_MAC_WINDOW (f);
1585 AliasHandle alias = NULL;
1587 err = GetWindowProxyAlias (w, &alias);
1588 if (err == errWindowDoesNotHaveProxy && !STRINGP (file_name))
1589 return;
1591 if (STRINGP (file_name))
1593 AEDesc desc;
1594 #ifdef MAC_OSX
1595 FSRef fref, fref_proxy;
1596 #else
1597 FSSpec fss, fss_proxy;
1598 #endif
1599 Boolean changed;
1600 Lisp_Object encoded_file_name = ENCODE_FILE (file_name);
1602 #ifdef MAC_OSX
1603 err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name),
1604 SBYTES (encoded_file_name), typeFSRef, &desc);
1605 #else
1606 SetPortWindowPort (w);
1607 err = AECoercePtr (TYPE_FILE_NAME, SDATA (encoded_file_name),
1608 SBYTES (encoded_file_name), typeFSS, &desc);
1609 #endif
1610 if (err == noErr)
1612 #ifdef MAC_OSX
1613 err = AEGetDescData (&desc, &fref, sizeof (FSRef));
1614 #else
1615 err = AEGetDescData (&desc, &fss, sizeof (FSSpec));
1616 #endif
1617 AEDisposeDesc (&desc);
1619 if (err == noErr)
1621 if (alias)
1623 /* (FS)ResolveAlias never sets `changed' to true if
1624 `alias' is minimal. */
1625 #ifdef MAC_OSX
1626 err = FSResolveAlias (NULL, alias, &fref_proxy, &changed);
1627 if (err == noErr)
1628 err = FSCompareFSRefs (&fref, &fref_proxy);
1629 #else
1630 err = ResolveAlias (NULL, alias, &fss_proxy, &changed);
1631 if (err == noErr)
1632 err = !(fss.vRefNum == fss_proxy.vRefNum
1633 && fss.parID == fss_proxy.parID
1634 && EqualString (fss.name, fss_proxy.name,
1635 false, true));
1636 #endif
1638 if (err != noErr || alias == NULL)
1640 if (alias)
1641 DisposeHandle ((Handle) alias);
1642 #ifdef MAC_OSX
1643 err = FSNewAliasMinimal (&fref, &alias);
1644 #else
1645 err = NewAliasMinimal (&fss, &alias);
1646 #endif
1647 changed = true;
1650 if (err == noErr)
1651 if (changed)
1652 err = SetWindowProxyAlias (w, alias);
1655 if (alias)
1656 DisposeHandle ((Handle) alias);
1658 if (err != noErr || !STRINGP (file_name))
1659 RemoveWindowProxy (w);
1661 #endif
1663 /* Mac replacement for XSetWindowBackground. */
1665 void
1666 mac_set_frame_window_background (f, color)
1667 struct frame *f;
1668 unsigned long color;
1670 WindowRef w = FRAME_MAC_WINDOW (f);
1671 #if !TARGET_API_MAC_CARBON
1672 AuxWinHandle aw_handle;
1673 CTabHandle ctab_handle;
1674 ColorSpecPtr ct_table;
1675 short ct_size;
1676 #endif
1677 RGBColor bg_color;
1679 bg_color.red = RED16_FROM_ULONG (color);
1680 bg_color.green = GREEN16_FROM_ULONG (color);
1681 bg_color.blue = BLUE16_FROM_ULONG (color);
1683 #if TARGET_API_MAC_CARBON
1684 SetWindowContentColor (w, &bg_color);
1685 #else
1686 if (GetAuxWin (w, &aw_handle))
1688 ctab_handle = (*aw_handle)->awCTable;
1689 HandToHand ((Handle *) &ctab_handle);
1690 ct_table = (*ctab_handle)->ctTable;
1691 ct_size = (*ctab_handle)->ctSize;
1692 while (ct_size > -1)
1694 if (ct_table->value == 0)
1696 ct_table->rgb = bg_color;
1697 CTabChanged (ctab_handle);
1698 SetWinColor (w, (WCTabHandle) ctab_handle);
1700 ct_size--;
1703 #endif
1706 /* Flush display of frame F, or of all frames if F is null. */
1708 void
1709 x_flush (f)
1710 struct frame *f;
1712 #if TARGET_API_MAC_CARBON
1713 BLOCK_INPUT;
1714 #if USE_CG_DRAWING
1715 mac_prepare_for_quickdraw (f);
1716 #endif
1717 if (f)
1718 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f)), NULL);
1719 else
1720 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL);
1721 UNBLOCK_INPUT;
1722 #endif
1725 #if USE_CG_DRAWING
1726 void
1727 mac_flush_display_optional (f)
1728 struct frame *f;
1730 BLOCK_INPUT;
1731 mac_prepare_for_quickdraw (f);
1732 UNBLOCK_INPUT;
1734 #endif
1736 void
1737 mac_update_begin (f)
1738 struct frame *f;
1740 #if TARGET_API_MAC_CARBON
1741 /* During update of a frame, availability of input events is
1742 periodically checked with ReceiveNextEvent if
1743 redisplay-dont-pause is nil. That normally flushes window buffer
1744 changes for every check, and thus screen update looks waving even
1745 if no input is available. So we disable screen updates during
1746 update of a frame. */
1747 DisableScreenUpdates ();
1748 #endif
1751 void
1752 mac_update_end (f)
1753 struct frame *f;
1755 #if TARGET_API_MAC_CARBON
1756 EnableScreenUpdates ();
1757 #endif
1760 void
1761 mac_frame_up_to_date (f)
1762 struct frame *f;
1764 /* Nothing to do. */
1767 void
1768 mac_create_frame_window (f, tooltip_p)
1769 struct frame *f;
1770 int tooltip_p;
1772 Rect r;
1773 #if TARGET_API_MAC_CARBON
1774 WindowClass window_class;
1775 WindowAttributes attributes;
1776 #else
1777 short proc_id;
1778 WindowRef behind;
1779 Boolean go_away_flag;
1780 #endif
1782 if (!tooltip_p)
1784 SetRect (&r, f->left_pos, f->top_pos,
1785 f->left_pos + FRAME_PIXEL_WIDTH (f),
1786 f->top_pos + FRAME_PIXEL_HEIGHT (f));
1787 #if TARGET_API_MAC_CARBON
1788 window_class = kDocumentWindowClass;
1789 attributes = (kWindowStandardDocumentAttributes
1790 #ifdef MAC_OSX
1791 | kWindowToolbarButtonAttribute
1792 #endif
1794 #else
1795 proc_id = zoomDocProc;
1796 behind = (WindowRef) -1;
1797 go_away_flag = true;
1798 #endif
1800 else
1802 SetRect (&r, 0, 0, 1, 1);
1803 #if TARGET_API_MAC_CARBON
1804 window_class = kHelpWindowClass;
1805 attributes = (kWindowNoUpdatesAttribute
1806 | kWindowNoActivatesAttribute
1807 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1808 | kWindowIgnoreClicksAttribute
1809 #endif
1811 #else
1812 proc_id = plainDBox;
1813 behind = NULL;
1814 go_away_flag = false;
1815 #endif
1818 #if TARGET_API_MAC_CARBON
1819 CreateNewWindow (window_class, attributes, &r, &FRAME_MAC_WINDOW (f));
1820 if (FRAME_MAC_WINDOW (f))
1822 SetWRefCon (FRAME_MAC_WINDOW (f), (long) f->output_data.mac);
1823 if (!tooltip_p)
1824 if (install_window_handler (FRAME_MAC_WINDOW (f)) != noErr)
1826 DisposeWindow (FRAME_MAC_WINDOW (f));
1827 FRAME_MAC_WINDOW (f) = NULL;
1830 #else /* !TARGET_API_MAC_CARBON */
1831 FRAME_MAC_WINDOW (f)
1832 = NewCWindow (NULL, &r, "\p", false, proc_id, behind, go_away_flag,
1833 (long) f->output_data.mac);
1834 #endif /* !TARGET_API_MAC_CARBON */
1835 /* so that update events can find this mac_output struct */
1836 f->output_data.mac->mFP = f; /* point back to emacs frame */
1838 #ifndef MAC_OSX
1839 if (!tooltip_p)
1840 if (FRAME_MAC_WINDOW (f))
1842 ControlRef root_control;
1844 if (CreateRootControl (FRAME_MAC_WINDOW (f), &root_control) != noErr)
1846 DisposeWindow (FRAME_MAC_WINDOW (f));
1847 FRAME_MAC_WINDOW (f) = NULL;
1850 #endif
1853 /* Dispose of the Mac window of the frame F. */
1855 void
1856 mac_dispose_frame_window (f)
1857 struct frame *f;
1859 WindowRef window = FRAME_MAC_WINDOW (f);
1861 if (window != tip_window)
1862 remove_window_handler (window);
1864 #if USE_CG_DRAWING
1865 mac_prepare_for_quickdraw (f);
1866 #endif
1867 DisposeWindow (window);
1871 /************************************************************************
1872 View and Drawing
1873 ************************************************************************/
1875 #if USE_CG_DRAWING
1876 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
1878 CGContextRef
1879 mac_begin_cg_clip (f, gc)
1880 struct frame *f;
1881 GC gc;
1883 CGContextRef context = FRAME_CG_CONTEXT (f);
1885 if (!context)
1887 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)), &context);
1888 FRAME_CG_CONTEXT (f) = context;
1891 CGContextSaveGState (context);
1892 CGContextTranslateCTM (context, 0, FRAME_PIXEL_HEIGHT (f));
1893 CGContextScaleCTM (context, 1, -1);
1894 if (gc && gc->n_clip_rects)
1895 CGContextClipToRects (context, gc->clip_rects, gc->n_clip_rects);
1897 return context;
1900 void
1901 mac_end_cg_clip (f)
1902 struct frame *f;
1904 CGContextRestoreGState (FRAME_CG_CONTEXT (f));
1907 static void
1908 mac_prepare_for_quickdraw (f)
1909 struct frame *f;
1911 if (f == NULL)
1913 Lisp_Object rest, frame;
1914 FOR_EACH_FRAME (rest, frame)
1915 if (FRAME_MAC_P (XFRAME (frame)))
1916 mac_prepare_for_quickdraw (XFRAME (frame));
1918 else
1920 CGContextRef context = FRAME_CG_CONTEXT (f);
1922 if (context)
1924 CGContextSynchronize (context);
1925 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f)),
1926 &FRAME_CG_CONTEXT (f));
1930 #endif
1932 static RgnHandle saved_port_clip_region = NULL;
1934 void
1935 mac_begin_clip (f, gc)
1936 struct frame *f;
1937 GC gc;
1939 static RgnHandle new_region = NULL;
1941 if (saved_port_clip_region == NULL)
1942 saved_port_clip_region = NewRgn ();
1943 if (new_region == NULL)
1944 new_region = NewRgn ();
1946 #if USE_CG_DRAWING
1947 mac_prepare_for_quickdraw (f);
1948 #endif
1949 SetPortWindowPort (FRAME_MAC_WINDOW (f));
1951 if (gc && gc->n_clip_rects)
1953 GetClip (saved_port_clip_region);
1954 SectRgn (saved_port_clip_region, gc->clip_region, new_region);
1955 SetClip (new_region);
1959 void
1960 mac_end_clip (f, gc)
1961 struct frame *f;
1962 GC gc;
1964 if (gc && gc->n_clip_rects)
1965 SetClip (saved_port_clip_region);
1968 #if TARGET_API_MAC_CARBON
1969 /* Mac replacement for XCopyArea: used only for scrolling. */
1971 void
1972 mac_scroll_area (f, gc, src_x, src_y, width, height, dest_x, dest_y)
1973 struct frame *f;
1974 GC gc;
1975 int src_x, src_y;
1976 unsigned int width, height;
1977 int dest_x, dest_y;
1979 Rect src_r;
1980 RgnHandle dummy = NewRgn (); /* For avoiding update events. */
1982 SetRect (&src_r, src_x, src_y, src_x + width, src_y + height);
1983 #if USE_CG_DRAWING
1984 mac_prepare_for_quickdraw (f);
1985 #endif
1986 ScrollWindowRect (FRAME_MAC_WINDOW (f),
1987 &src_r, dest_x - src_x, dest_y - src_y,
1988 kScrollWindowNoOptions, dummy);
1989 DisposeRgn (dummy);
1991 #endif
1994 /************************************************************************
1995 Scroll bars
1996 ************************************************************************/
1998 extern struct scroll_bar *tracked_scroll_bar;
1999 extern Lisp_Object last_mouse_scroll_bar;
2000 extern Time last_mouse_movement_time;
2002 static void x_scroll_bar_handle_click P_ ((struct scroll_bar *,
2003 ControlPartCode,
2004 const EventRecord *,
2005 struct input_event *));
2006 #ifndef USE_TOOLKIT_SCROLL_BARS
2007 static void x_scroll_bar_note_movement P_ ((struct scroll_bar *, int, Time));
2008 #else /* USE_TOOLKIT_SCROLL_BARS */
2009 static void x_scroll_bar_handle_press P_ ((struct scroll_bar *,
2010 ControlPartCode, Point,
2011 struct input_event *));
2012 static void x_scroll_bar_handle_release P_ ((struct scroll_bar *,
2013 struct input_event *));
2014 static void x_scroll_bar_handle_drag P_ ((WindowRef, struct scroll_bar *,
2015 Point, struct input_event *));
2016 static pascal void scroll_bar_timer_callback P_ ((EventLoopTimerRef, void *));
2017 static OSStatus install_scroll_bar_timer P_ ((void));
2018 static OSStatus set_scroll_bar_timer P_ ((EventTimerInterval));
2019 static int control_part_code_to_scroll_bar_part P_ ((ControlPartCode));
2020 static void construct_scroll_bar_click P_ ((struct scroll_bar *, int,
2021 struct input_event *));
2022 static OSStatus get_control_part_bounds P_ ((ControlRef, ControlPartCode,
2023 Rect *));
2024 static void update_scroll_bar_track_info P_ ((struct scroll_bar *));
2026 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
2028 static int last_scroll_bar_part;
2030 static EventLoopTimerRef scroll_bar_timer;
2032 static int scroll_bar_timer_event_posted_p;
2034 #define SCROLL_BAR_FIRST_DELAY 0.5
2035 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
2037 static pascal void
2038 scroll_bar_timer_callback (timer, data)
2039 EventLoopTimerRef timer;
2040 void *data;
2042 OSStatus err;
2044 err = mac_post_mouse_moved_event ();
2045 if (err == noErr)
2046 scroll_bar_timer_event_posted_p = 1;
2049 static OSStatus
2050 install_scroll_bar_timer ()
2052 static EventLoopTimerUPP scroll_bar_timer_callbackUPP = NULL;
2054 if (scroll_bar_timer_callbackUPP == NULL)
2055 scroll_bar_timer_callbackUPP =
2056 NewEventLoopTimerUPP (scroll_bar_timer_callback);
2058 if (scroll_bar_timer == NULL)
2059 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
2060 kEventDurationForever as delays. */
2061 return
2062 InstallEventLoopTimer (GetCurrentEventLoop (),
2063 kEventDurationForever, kEventDurationForever,
2064 scroll_bar_timer_callbackUPP, NULL,
2065 &scroll_bar_timer);
2068 static OSStatus
2069 set_scroll_bar_timer (delay)
2070 EventTimerInterval delay;
2072 if (scroll_bar_timer == NULL)
2073 install_scroll_bar_timer ();
2075 scroll_bar_timer_event_posted_p = 0;
2077 return SetEventLoopTimerNextFireTime (scroll_bar_timer, delay);
2080 static int
2081 control_part_code_to_scroll_bar_part (part_code)
2082 ControlPartCode part_code;
2084 switch (part_code)
2086 case kControlUpButtonPart: return scroll_bar_up_arrow;
2087 case kControlDownButtonPart: return scroll_bar_down_arrow;
2088 case kControlPageUpPart: return scroll_bar_above_handle;
2089 case kControlPageDownPart: return scroll_bar_below_handle;
2090 case kControlIndicatorPart: return scroll_bar_handle;
2093 return -1;
2096 static void
2097 construct_scroll_bar_click (bar, part, bufp)
2098 struct scroll_bar *bar;
2099 int part;
2100 struct input_event *bufp;
2102 bufp->kind = SCROLL_BAR_CLICK_EVENT;
2103 bufp->frame_or_window = bar->window;
2104 bufp->arg = Qnil;
2105 bufp->part = part;
2106 bufp->code = 0;
2107 XSETINT (bufp->x, 0);
2108 XSETINT (bufp->y, 0);
2109 bufp->modifiers = 0;
2112 static OSStatus
2113 get_control_part_bounds (ch, part_code, rect)
2114 ControlRef ch;
2115 ControlPartCode part_code;
2116 Rect *rect;
2118 RgnHandle region = NewRgn ();
2119 OSStatus err;
2121 err = GetControlRegion (ch, part_code, region);
2122 if (err == noErr)
2123 GetRegionBounds (region, rect);
2124 DisposeRgn (region);
2126 return err;
2129 static void
2130 x_scroll_bar_handle_press (bar, part_code, mouse_pos, bufp)
2131 struct scroll_bar *bar;
2132 ControlPartCode part_code;
2133 Point mouse_pos;
2134 struct input_event *bufp;
2136 int part = control_part_code_to_scroll_bar_part (part_code);
2138 if (part < 0)
2139 return;
2141 if (part != scroll_bar_handle)
2143 construct_scroll_bar_click (bar, part, bufp);
2144 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
2145 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY);
2146 bar->dragging = Qnil;
2148 else
2150 Rect r;
2152 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
2153 kControlIndicatorPart, &r);
2154 XSETINT (bar->dragging, - (mouse_pos.v - r.top) - 1);
2157 last_scroll_bar_part = part;
2158 tracked_scroll_bar = bar;
2161 static void
2162 x_scroll_bar_handle_release (bar, bufp)
2163 struct scroll_bar *bar;
2164 struct input_event *bufp;
2166 if (last_scroll_bar_part != scroll_bar_handle
2167 || (INTEGERP (bar->dragging) && XINT (bar->dragging) >= 0))
2168 construct_scroll_bar_click (bar, scroll_bar_end_scroll, bufp);
2170 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
2171 set_scroll_bar_timer (kEventDurationForever);
2173 last_scroll_bar_part = -1;
2174 bar->dragging = Qnil;
2175 tracked_scroll_bar = NULL;
2178 static void
2179 x_scroll_bar_handle_drag (win, bar, mouse_pos, bufp)
2180 WindowRef win;
2181 struct scroll_bar *bar;
2182 Point mouse_pos;
2183 struct input_event *bufp;
2185 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2187 if (last_scroll_bar_part == scroll_bar_handle)
2189 int top, top_range;
2190 Rect r;
2192 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar),
2193 kControlIndicatorPart, &r);
2195 if (INTEGERP (bar->dragging) && XINT (bar->dragging) < 0)
2196 XSETINT (bar->dragging, - (XINT (bar->dragging) + 1));
2198 top = mouse_pos.v - XINT (bar->dragging) - XINT (bar->track_top);
2199 top_range = XINT (bar->track_height) - XINT (bar->min_handle);
2201 if (top < 0)
2202 top = 0;
2203 if (top > top_range)
2204 top = top_range;
2206 construct_scroll_bar_click (bar, scroll_bar_handle, bufp);
2207 XSETINT (bufp->x, top);
2208 XSETINT (bufp->y, top_range);
2210 else
2212 ControlPartCode part_code;
2213 int unhilite_p = 0, part;
2215 if (ch != FindControlUnderMouse (mouse_pos, win, &part_code))
2216 unhilite_p = 1;
2217 else
2219 part = control_part_code_to_scroll_bar_part (part_code);
2221 switch (last_scroll_bar_part)
2223 case scroll_bar_above_handle:
2224 case scroll_bar_below_handle:
2225 if (part != scroll_bar_above_handle
2226 && part != scroll_bar_below_handle)
2227 unhilite_p = 1;
2228 break;
2230 case scroll_bar_up_arrow:
2231 case scroll_bar_down_arrow:
2232 if (part != scroll_bar_up_arrow
2233 && part != scroll_bar_down_arrow)
2234 unhilite_p = 1;
2235 break;
2239 if (unhilite_p)
2240 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), 0);
2241 else if (part != last_scroll_bar_part
2242 || scroll_bar_timer_event_posted_p)
2244 construct_scroll_bar_click (bar, part, bufp);
2245 last_scroll_bar_part = part;
2246 HiliteControl (SCROLL_BAR_CONTROL_REF (bar), part_code);
2247 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY);
2252 /* Update BAR->track_top, BAR->track_height, and BAR->min_handle for
2253 the scroll bar BAR. This function should be called when the bounds
2254 of the scroll bar is changed. */
2256 static void
2257 update_scroll_bar_track_info (bar)
2258 struct scroll_bar *bar;
2260 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2261 Rect r0, r1;
2263 GetControlBounds (ch, &r0);
2265 if (r0.right - r0.left >= r0.bottom - r0.top
2266 #ifdef MAC_OSX
2267 || r0.right - r0.left < MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
2268 #endif
2271 XSETINT (bar->track_top, 0);
2272 XSETINT (bar->track_height, 0);
2273 XSETINT (bar->min_handle, 0);
2275 else
2277 BLOCK_INPUT;
2279 SetControl32BitMinimum (ch, 0);
2280 SetControl32BitMaximum (ch, 1 << 30);
2281 SetControlViewSize (ch, 1);
2283 /* Move the scroll bar thumb to the top. */
2284 SetControl32BitValue (ch, 0);
2285 get_control_part_bounds (ch, kControlIndicatorPart, &r0);
2287 /* Move the scroll bar thumb to the bottom. */
2288 SetControl32BitValue (ch, 1 << 30);
2289 get_control_part_bounds (ch, kControlIndicatorPart, &r1);
2291 UnionRect (&r0, &r1, &r0);
2292 XSETINT (bar->track_top, r0.top);
2293 XSETINT (bar->track_height, r0.bottom - r0.top);
2294 XSETINT (bar->min_handle, r1.bottom - r1.top);
2296 /* Don't show the scroll bar if its height is not enough to
2297 display the scroll bar thumb. */
2298 if (r0.bottom - r0.top > 0)
2299 ShowControl (ch);
2301 UNBLOCK_INPUT;
2305 /* Set the thumb size and position of scroll bar BAR. We are currently
2306 displaying PORTION out of a whole WHOLE, and our position POSITION. */
2308 void
2309 x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
2310 struct scroll_bar *bar;
2311 int portion, position, whole;
2313 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2314 int value, viewsize, maximum;
2316 if (XINT (bar->track_height) == 0)
2317 return;
2319 if (whole <= portion)
2320 value = 0, viewsize = 1, maximum = 0;
2321 else
2323 float scale;
2325 maximum = XINT (bar->track_height) - XINT (bar->min_handle);
2326 scale = (float) maximum / (whole - portion);
2327 value = position * scale + 0.5f;
2328 viewsize = (int) (portion * scale + 0.5f) + XINT (bar->min_handle);
2331 BLOCK_INPUT;
2333 if (GetControlViewSize (ch) != viewsize
2334 || GetControl32BitValue (ch) != value
2335 || GetControl32BitMaximum (ch) != maximum)
2337 /* Temporarily hide the scroll bar to avoid multiple redraws. */
2338 SetControlVisibility (ch, false, false);
2340 SetControl32BitMaximum (ch, maximum);
2341 SetControl32BitValue (ch, value);
2342 SetControlViewSize (ch, viewsize);
2344 SetControlVisibility (ch, true, true);
2347 UNBLOCK_INPUT;
2350 #endif /* USE_TOOLKIT_SCROLL_BARS */
2352 /* Create a scroll bar control for BAR. BOUNDS and VISIBLE specifies
2353 the initial geometry and visibility, respectively. The created
2354 control is stored in some members of BAR. */
2356 void
2357 mac_create_scroll_bar (bar, bounds, visible)
2358 struct scroll_bar *bar;
2359 const Rect *bounds;
2360 Boolean visible;
2362 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2363 ControlRef ch;
2365 #if USE_CG_DRAWING
2366 mac_prepare_for_quickdraw (f);
2367 #endif
2368 ch = NewControl (FRAME_MAC_WINDOW (f), bounds, "\p", visible, 0, 0, 0,
2369 #if TARGET_API_MAC_CARBON
2370 kControlScrollBarProc,
2371 #else
2372 scrollBarProc,
2373 #endif
2374 (SInt32) bar);
2375 SET_SCROLL_BAR_CONTROL_REF (bar, ch);
2377 XSETINT (bar->start, 0);
2378 XSETINT (bar->end, 0);
2379 bar->dragging = Qnil;
2381 #ifdef USE_TOOLKIT_SCROLL_BARS
2382 update_scroll_bar_track_info (bar);
2383 #endif
2386 /* Dispose of the scroll bar control stored in some members of
2387 BAR. */
2389 void
2390 mac_dispose_scroll_bar (bar)
2391 struct scroll_bar *bar;
2393 #if USE_CG_DRAWING
2394 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2396 mac_prepare_for_quickdraw (f);
2397 #endif
2398 DisposeControl (SCROLL_BAR_CONTROL_REF (bar));
2401 /* Set bounds of the scroll bar BAR to BOUNDS. */
2403 void
2404 mac_set_scroll_bar_bounds (bar, bounds)
2405 struct scroll_bar *bar;
2406 const Rect *bounds;
2408 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2409 SInt16 width, height;
2410 #if USE_CG_DRAWING
2411 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2413 mac_prepare_for_quickdraw (f);
2414 #endif
2416 width = bounds->right - bounds->left;
2417 height = bounds->bottom - bounds->top;
2418 HideControl (ch);
2419 MoveControl (ch, bounds->left, bounds->top);
2420 SizeControl (ch, width, height);
2421 #ifdef USE_TOOLKIT_SCROLL_BARS
2422 update_scroll_bar_track_info (bar);
2423 #else
2424 if (width < height)
2425 ShowControl (ch);
2426 #endif
2429 /* Draw the scroll bar BAR. */
2431 void
2432 mac_redraw_scroll_bar (bar)
2433 struct scroll_bar *bar;
2435 #if USE_CG_DRAWING
2436 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2438 mac_prepare_for_quickdraw (f);
2439 #endif
2440 Draw1Control (SCROLL_BAR_CONTROL_REF (bar));
2443 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2444 is set to something other than NO_EVENT, it is enqueued.
2446 This may be called from a signal handler, so we have to ignore GC
2447 mark bits. */
2449 static void
2450 x_scroll_bar_handle_click (bar, part_code, er, bufp)
2451 struct scroll_bar *bar;
2452 ControlPartCode part_code;
2453 const EventRecord *er;
2454 struct input_event *bufp;
2456 int win_y, top_range;
2458 if (! GC_WINDOWP (bar->window))
2459 abort ();
2461 bufp->kind = SCROLL_BAR_CLICK_EVENT;
2462 bufp->frame_or_window = bar->window;
2463 bufp->arg = Qnil;
2465 bar->dragging = Qnil;
2467 switch (part_code)
2469 case kControlUpButtonPart:
2470 bufp->part = scroll_bar_up_arrow;
2471 break;
2472 case kControlDownButtonPart:
2473 bufp->part = scroll_bar_down_arrow;
2474 break;
2475 case kControlPageUpPart:
2476 bufp->part = scroll_bar_above_handle;
2477 break;
2478 case kControlPageDownPart:
2479 bufp->part = scroll_bar_below_handle;
2480 break;
2481 #if TARGET_API_MAC_CARBON
2482 default:
2483 #else
2484 case kControlIndicatorPart:
2485 #endif
2486 if (er->what == mouseDown)
2487 bar->dragging = make_number (0);
2488 XSETVECTOR (last_mouse_scroll_bar, bar);
2489 bufp->part = scroll_bar_handle;
2490 break;
2493 win_y = XINT (bufp->y) - XINT (bar->top);
2494 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar->height));
2496 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2498 win_y -= 24;
2500 if (! NILP (bar->dragging))
2501 win_y -= XINT (bar->dragging);
2503 if (win_y < 0)
2504 win_y = 0;
2505 if (win_y > top_range)
2506 win_y = top_range;
2508 XSETINT (bufp->x, win_y);
2509 XSETINT (bufp->y, top_range);
2512 /* Return information to the user about the current position of the mouse
2513 on the scroll bar. */
2515 void
2516 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
2517 FRAME_PTR *fp;
2518 Lisp_Object *bar_window;
2519 enum scroll_bar_part *part;
2520 Lisp_Object *x, *y;
2521 unsigned long *time;
2523 struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
2524 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2525 #if TARGET_API_MAC_CARBON
2526 WindowRef wp = GetControlOwner (ch);
2527 #else
2528 WindowRef wp = (*ch)->contrlOwner;
2529 #endif
2530 Point mouse_pos;
2531 struct frame *f = mac_window_to_frame (wp);
2532 int win_y, top_range;
2534 #if TARGET_API_MAC_CARBON
2535 GetGlobalMouse (&mouse_pos);
2536 mouse_pos.h -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
2537 mouse_pos.v -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
2538 #else
2539 SetPortWindowPort (wp);
2540 GetMouse (&mouse_pos);
2541 #endif
2543 win_y = mouse_pos.v - XINT (bar->top);
2544 top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
2546 win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
2548 win_y -= 24;
2550 if (! NILP (bar->dragging))
2551 win_y -= XINT (bar->dragging);
2553 if (win_y < 0)
2554 win_y = 0;
2555 if (win_y > top_range)
2556 win_y = top_range;
2558 *fp = f;
2559 *bar_window = bar->window;
2561 if (! NILP (bar->dragging))
2562 *part = scroll_bar_handle;
2563 else if (win_y < XINT (bar->start))
2564 *part = scroll_bar_above_handle;
2565 else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
2566 *part = scroll_bar_handle;
2567 else
2568 *part = scroll_bar_below_handle;
2570 XSETINT (*x, win_y);
2571 XSETINT (*y, top_range);
2573 f->mouse_moved = 0;
2574 last_mouse_scroll_bar = Qnil;
2576 *time = last_mouse_movement_time;
2579 #ifndef USE_TOOLKIT_SCROLL_BARS
2580 /* Draw BAR's handle in the proper position.
2582 If the handle is already drawn from START to END, don't bother
2583 redrawing it, unless REBUILD is non-zero; in that case, always
2584 redraw it. (REBUILD is handy for drawing the handle after expose
2585 events.)
2587 Normally, we want to constrain the start and end of the handle to
2588 fit inside its rectangle, but if the user is dragging the scroll
2589 bar handle, we want to let them drag it down all the way, so that
2590 the bar's top is as far down as it goes; otherwise, there's no way
2591 to move to the very end of the buffer. */
2593 void
2594 x_scroll_bar_set_handle (bar, start, end, rebuild)
2595 struct scroll_bar *bar;
2596 int start, end;
2597 int rebuild;
2599 int dragging = ! NILP (bar->dragging);
2600 ControlRef ch = SCROLL_BAR_CONTROL_REF (bar);
2601 FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
2602 int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
2603 int length = end - start;
2605 /* If the display is already accurate, do nothing. */
2606 if (! rebuild
2607 && start == XINT (bar->start)
2608 && end == XINT (bar->end))
2609 return;
2611 BLOCK_INPUT;
2613 /* Make sure the values are reasonable, and try to preserve the
2614 distance between start and end. */
2615 if (start < 0)
2616 start = 0;
2617 else if (start > top_range)
2618 start = top_range;
2619 end = start + length;
2621 if (end < start)
2622 end = start;
2623 else if (end > top_range && ! dragging)
2624 end = top_range;
2626 /* Store the adjusted setting in the scroll bar. */
2627 XSETINT (bar->start, start);
2628 XSETINT (bar->end, end);
2630 /* Clip the end position, just for display. */
2631 if (end > top_range)
2632 end = top_range;
2634 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
2635 top positions, to make sure the handle is always at least that
2636 many pixels tall. */
2637 end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
2639 SetControlMinimum (ch, 0);
2640 /* Don't inadvertently activate deactivated scroll bars */
2641 if (GetControlMaximum (ch) != -1)
2642 SetControlMaximum (ch, top_range + VERTICAL_SCROLL_BAR_MIN_HANDLE
2643 - (end - start));
2644 SetControlValue (ch, start);
2645 #if TARGET_API_MAC_CARBON
2646 SetControlViewSize (ch, end - start);
2647 #endif
2649 UNBLOCK_INPUT;
2652 /* Handle some mouse motion while someone is dragging the scroll bar.
2654 This may be called from a signal handler, so we have to ignore GC
2655 mark bits. */
2657 static void
2658 x_scroll_bar_note_movement (bar, y_pos, t)
2659 struct scroll_bar *bar;
2660 int y_pos;
2661 Time t;
2663 FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
2665 last_mouse_movement_time = t;
2667 f->mouse_moved = 1;
2668 XSETVECTOR (last_mouse_scroll_bar, bar);
2670 /* If we're dragging the bar, display it. */
2671 if (! GC_NILP (bar->dragging))
2673 /* Where should the handle be now? */
2674 int new_start = y_pos - 24;
2676 if (new_start != XINT (bar->start))
2678 int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
2680 x_scroll_bar_set_handle (bar, new_start, new_end, 0);
2684 #endif /* !USE_TOOLKIT_SCROLL_BARS */
2687 /***********************************************************************
2688 Tool-bars
2689 ***********************************************************************/
2691 #if USE_MAC_TOOLBAR
2692 /* In identifiers such as function/variable names, Emacs tool bar is
2693 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
2695 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
2696 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
2698 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
2699 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
2700 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2701 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
2702 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2703 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
2704 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2706 static OSStatus mac_handle_toolbar_command_event P_ ((EventHandlerCallRef,
2707 EventRef, void *));
2709 extern Rect last_mouse_glyph;
2711 extern void mac_move_window_with_gravity P_ ((struct frame *, int,
2712 short, short));
2713 extern void mac_get_window_origin_with_gravity P_ ((struct frame *, int,
2714 short *, short *));
2715 extern CGImageRef mac_image_spec_to_cg_image P_ ((struct frame *,
2716 Lisp_Object));
2718 static OSStatus
2719 mac_handle_toolbar_event (next_handler, event, data)
2720 EventHandlerCallRef next_handler;
2721 EventRef event;
2722 void *data;
2724 OSStatus result = eventNotHandledErr;
2726 switch (GetEventKind (event))
2728 case kEventToolbarGetDefaultIdentifiers:
2729 result = noErr;
2730 break;
2732 case kEventToolbarGetAllowedIdentifiers:
2734 CFMutableArrayRef array;
2736 GetEventParameter (event, kEventParamMutableArray,
2737 typeCFMutableArrayRef, NULL,
2738 sizeof (CFMutableArrayRef), NULL, &array);
2739 CFArrayAppendValue (array, TOOLBAR_ICON_ITEM_IDENTIFIER);
2740 result = noErr;
2742 break;
2744 case kEventToolbarCreateItemWithIdentifier:
2746 CFStringRef identifier;
2747 HIToolbarItemRef item = NULL;
2749 GetEventParameter (event, kEventParamToolbarItemIdentifier,
2750 typeCFStringRef, NULL,
2751 sizeof (CFStringRef), NULL, &identifier);
2753 if (CFStringCompare (identifier, TOOLBAR_ICON_ITEM_IDENTIFIER, 0)
2754 == kCFCompareEqualTo)
2755 HIToolbarItemCreate (identifier,
2756 kHIToolbarItemAllowDuplicates
2757 | kHIToolbarItemCantBeRemoved, &item);
2759 if (item)
2761 SetEventParameter (event, kEventParamToolbarItem,
2762 typeHIToolbarItemRef,
2763 sizeof (HIToolbarItemRef), &item);
2764 result = noErr;
2767 break;
2769 default:
2770 abort ();
2773 return result;
2776 /* Create a tool bar for frame F. */
2778 static OSStatus
2779 mac_create_frame_tool_bar (f)
2780 FRAME_PTR f;
2782 OSStatus err;
2783 HIToolbarRef toolbar;
2785 err = HIToolbarCreate (TOOLBAR_IDENTIFIER, kHIToolbarNoAttributes,
2786 &toolbar);
2787 if (err == noErr)
2789 static const EventTypeSpec specs[] =
2790 {{kEventClassToolbar, kEventToolbarGetDefaultIdentifiers},
2791 {kEventClassToolbar, kEventToolbarGetAllowedIdentifiers},
2792 {kEventClassToolbar, kEventToolbarCreateItemWithIdentifier}};
2794 err = InstallEventHandler (HIObjectGetEventTarget (toolbar),
2795 mac_handle_toolbar_event,
2796 GetEventTypeCount (specs), specs,
2797 f, NULL);
2800 if (err == noErr)
2801 err = HIToolbarSetDisplayMode (toolbar, kHIToolbarDisplayModeIconOnly);
2802 if (err == noErr)
2804 static const EventTypeSpec specs[] =
2805 {{kEventClassCommand, kEventCommandProcess}};
2807 err = InstallWindowEventHandler (FRAME_MAC_WINDOW (f),
2808 mac_handle_toolbar_command_event,
2809 GetEventTypeCount (specs),
2810 specs, f, NULL);
2812 if (err == noErr)
2813 err = SetWindowToolbar (FRAME_MAC_WINDOW (f), toolbar);
2815 if (toolbar)
2816 CFRelease (toolbar);
2818 return err;
2821 /* Update the tool bar for frame F. Add new buttons and remove old. */
2823 void
2824 update_frame_tool_bar (f)
2825 FRAME_PTR f;
2827 HIToolbarRef toolbar = NULL;
2828 short left, top;
2829 CFArrayRef old_items = NULL;
2830 CFIndex old_count;
2831 int i, pos, win_gravity = f->output_data.mac->toolbar_win_gravity;
2832 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2834 BLOCK_INPUT;
2836 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
2837 if (toolbar == NULL)
2839 mac_create_frame_tool_bar (f);
2840 GetWindowToolbar (FRAME_MAC_WINDOW (f), &toolbar);
2841 if (toolbar == NULL)
2842 goto out;
2843 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
2844 mac_get_window_origin_with_gravity (f, win_gravity, &left, &top);
2847 HIToolbarCopyItems (toolbar, &old_items);
2848 if (old_items == NULL)
2849 goto out;
2851 old_count = CFArrayGetCount (old_items);
2852 pos = 0;
2853 for (i = 0; i < f->n_tool_bar_items; ++i)
2855 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
2857 int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
2858 int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
2859 int idx;
2860 Lisp_Object image;
2861 CGImageRef cg_image;
2862 CFStringRef label;
2863 HIToolbarItemRef item;
2865 /* If image is a vector, choose the image according to the
2866 button state. */
2867 image = PROP (TOOL_BAR_ITEM_IMAGES);
2868 if (VECTORP (image))
2870 if (enabled_p)
2871 idx = (selected_p
2872 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
2873 : TOOL_BAR_IMAGE_ENABLED_DESELECTED);
2874 else
2875 idx = (selected_p
2876 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
2877 : TOOL_BAR_IMAGE_DISABLED_DESELECTED);
2879 xassert (ASIZE (image) >= idx);
2880 image = AREF (image, idx);
2882 else
2883 idx = -1;
2885 cg_image = mac_image_spec_to_cg_image (f, image);
2886 /* Ignore invalid image specifications. */
2887 if (cg_image == NULL)
2888 continue;
2890 label = cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION));
2891 if (label == NULL)
2892 label = CFSTR ("");
2894 if (pos < old_count)
2896 CGImageRef old_cg_image = NULL;
2897 CFStringRef old_label = NULL;
2898 Boolean old_enabled_p;
2900 item = (HIToolbarItemRef) CFArrayGetValueAtIndex (old_items, pos);
2902 HIToolbarItemCopyImage (item, &old_cg_image);
2903 if (cg_image != old_cg_image)
2904 HIToolbarItemSetImage (item, cg_image);
2905 CGImageRelease (old_cg_image);
2907 HIToolbarItemCopyLabel (item, &old_label);
2908 if (CFStringCompare (label, old_label, 0) != kCFCompareEqualTo)
2909 HIToolbarItemSetLabel (item, label);
2910 CFRelease (old_label);
2912 old_enabled_p = HIToolbarItemIsEnabled (item);
2913 if ((enabled_p || idx >= 0) != old_enabled_p)
2914 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
2916 else
2918 item = NULL;
2919 HIToolbarCreateItemWithIdentifier (toolbar,
2920 TOOLBAR_ICON_ITEM_IDENTIFIER,
2921 NULL, &item);
2922 if (item)
2924 HIToolbarItemSetImage (item, cg_image);
2925 HIToolbarItemSetLabel (item, label);
2926 HIToolbarItemSetEnabled (item, (enabled_p || idx >= 0));
2927 HIToolbarAppendItem (toolbar, item);
2928 CFRelease (item);
2932 CFRelease (label);
2933 if (item)
2935 HIToolbarItemSetCommandID (item, TOOLBAR_ITEM_MAKE_COMMAND_ID (i));
2936 pos++;
2940 CFRelease (old_items);
2942 while (pos < old_count)
2943 HIToolbarRemoveItemAtIndex (toolbar, --old_count);
2945 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), true,
2946 !win_gravity && f == mac_focus_frame (dpyinfo));
2947 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
2948 toolbar visibility change. */
2949 mac_handle_origin_change (f);
2950 if (win_gravity >= NorthWestGravity && win_gravity <= SouthEastGravity)
2952 mac_move_window_with_gravity (f, win_gravity, left, top);
2953 /* If the title bar is completely outside the screen, adjust the
2954 position. */
2955 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f), kWindowTitleBarRgn,
2956 kWindowConstrainMoveRegardlessOfFit
2957 | kWindowConstrainAllowPartial, NULL, NULL);
2958 f->output_data.mac->toolbar_win_gravity = 0;
2961 out:
2962 UNBLOCK_INPUT;
2965 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
2966 doesn't deallocate the resources. */
2968 void
2969 free_frame_tool_bar (f)
2970 FRAME_PTR f;
2972 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f)))
2974 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2976 BLOCK_INPUT;
2977 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f), false,
2978 (NILP (find_symbol_value
2979 (intern ("frame-notice-user-settings")))
2980 && f == mac_focus_frame (dpyinfo)));
2981 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
2982 on toolbar visibility change. */
2983 mac_handle_origin_change (f);
2984 UNBLOCK_INPUT;
2988 /* Report a mouse movement over toolbar to the mainstream Emacs
2989 code. */
2991 static void
2992 mac_tool_bar_note_mouse_movement (f, event)
2993 struct frame *f;
2994 EventRef event;
2996 OSStatus err;
2997 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
2998 int mouse_down_p;
2999 WindowRef window;
3000 WindowPartCode part_code;
3001 HIViewRef item_view;
3002 UInt32 command_id;
3004 mouse_down_p = (dpyinfo->grabbed
3005 && f == last_mouse_frame
3006 && FRAME_LIVE_P (f));
3007 if (mouse_down_p)
3008 return;
3010 err = GetEventParameter (event, kEventParamWindowRef, typeWindowRef, NULL,
3011 sizeof (WindowRef), NULL, &window);
3012 if (err != noErr || window != FRAME_MAC_WINDOW (f))
3013 return;
3015 err = GetEventParameter (event, kEventParamWindowPartCode,
3016 typeWindowPartCode, NULL,
3017 sizeof (WindowPartCode), NULL, &part_code);
3018 if (err != noErr || part_code != inStructure)
3019 return;
3021 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window), event, &item_view);
3022 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
3023 toolbar item view seems to have the same command ID with that of
3024 the toolbar item. */
3025 if (err == noErr)
3026 err = GetControlCommandID (item_view, &command_id);
3027 if (err == noErr && TOOLBAR_ITEM_COMMAND_ID_P (command_id))
3029 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id);
3031 if (i < f->n_tool_bar_items)
3033 HIRect bounds;
3034 HIViewRef content_view;
3036 err = HIViewGetBounds (item_view, &bounds);
3037 if (err == noErr)
3038 err = HIViewFindByID (HIViewGetRoot (window),
3039 kHIViewWindowContentID, &content_view);
3040 if (err == noErr)
3041 err = HIViewConvertRect (&bounds, item_view, content_view);
3042 if (err == noErr)
3043 SetRect (&last_mouse_glyph,
3044 CGRectGetMinX (bounds), CGRectGetMinY (bounds),
3045 CGRectGetMaxX (bounds), CGRectGetMaxY (bounds));
3047 help_echo_object = help_echo_window = Qnil;
3048 help_echo_pos = -1;
3049 help_echo_string = PROP (TOOL_BAR_ITEM_HELP);
3050 if (NILP (help_echo_string))
3051 help_echo_string = PROP (TOOL_BAR_ITEM_CAPTION);
3056 static OSStatus
3057 mac_handle_toolbar_command_event (next_handler, event, data)
3058 EventHandlerCallRef next_handler;
3059 EventRef event;
3060 void *data;
3062 OSStatus err, result = eventNotHandledErr;
3063 struct frame *f = (struct frame *) data;
3064 HICommand command;
3066 err = GetEventParameter (event, kEventParamDirectObject,
3067 typeHICommand, NULL,
3068 sizeof (HICommand), NULL, &command);
3069 if (err != noErr)
3070 return result;
3072 switch (GetEventKind (event))
3074 case kEventCommandProcess:
3075 if (!TOOLBAR_ITEM_COMMAND_ID_P (command.commandID))
3076 result = CallNextEventHandler (next_handler, event);
3077 else
3079 int i = TOOLBAR_ITEM_COMMAND_ID_VALUE (command.commandID);
3081 if (i < f->n_tool_bar_items
3082 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)))
3084 Lisp_Object frame;
3085 struct input_event buf;
3087 EVENT_INIT (buf);
3089 XSETFRAME (frame, f);
3090 buf.kind = TOOL_BAR_EVENT;
3091 buf.frame_or_window = frame;
3092 buf.arg = frame;
3093 kbd_buffer_store_event (&buf);
3095 buf.kind = TOOL_BAR_EVENT;
3096 buf.frame_or_window = frame;
3097 buf.arg = PROP (TOOL_BAR_ITEM_KEY);
3098 buf.modifiers = mac_event_to_emacs_modifiers (event);
3099 kbd_buffer_store_event (&buf);
3101 result = noErr;
3104 break;
3106 default:
3107 abort ();
3109 #undef PROP
3111 return result;
3113 #endif /* USE_MAC_TOOLBAR */
3116 /***********************************************************************
3117 Font Panel
3118 ***********************************************************************/
3120 #if USE_MAC_FONT_PANEL
3121 /* Whether Font Panel has been shown before. The first call to font
3122 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
3123 slow. This variable is used for deferring such a call as much as
3124 possible. */
3125 static int font_panel_shown_p = 0;
3127 extern Lisp_Object Qpanel_closed, Qselection;
3128 extern Lisp_Object Qfont;
3130 /* Whether the font panel is currently visible. */
3133 mac_font_panel_visible_p ()
3135 return font_panel_shown_p && FPIsFontPanelVisible ();
3138 static pascal OSStatus
3139 mac_handle_font_event (next_handler, event, data)
3140 EventHandlerCallRef next_handler;
3141 EventRef event;
3142 void *data;
3144 OSStatus result, err;
3145 Lisp_Object id_key;
3146 int num_params;
3147 const EventParamName *names;
3148 const EventParamType *types;
3149 static const EventParamName names_sel[] = {kEventParamATSUFontID,
3150 kEventParamATSUFontSize,
3151 kEventParamFMFontFamily,
3152 kEventParamFMFontStyle,
3153 kEventParamFMFontSize,
3154 kEventParamFontColor};
3155 static const EventParamType types_sel[] = {typeATSUFontID,
3156 typeATSUSize,
3157 typeFMFontFamily,
3158 typeFMFontStyle,
3159 typeFMFontSize,
3160 typeFontColor};
3162 result = CallNextEventHandler (next_handler, event);
3163 if (result != eventNotHandledErr)
3164 return result;
3166 switch (GetEventKind (event))
3168 case kEventFontPanelClosed:
3169 id_key = Qpanel_closed;
3170 num_params = 0;
3171 names = NULL;
3172 types = NULL;
3173 break;
3175 case kEventFontSelection:
3176 id_key = Qselection;
3177 num_params = sizeof (names_sel) / sizeof (names_sel[0]);
3178 names = names_sel;
3179 types = types_sel;
3180 break;
3183 err = mac_store_event_ref_as_apple_event (0, 0, Qfont, id_key,
3184 event, num_params,
3185 names, types);
3186 if (err == noErr)
3187 result = noErr;
3189 return result;
3192 /* Toggle visiblity of the font panel. */
3194 OSStatus
3195 mac_show_hide_font_panel ()
3197 if (!font_panel_shown_p)
3199 OSStatus err;
3201 static const EventTypeSpec specs[] =
3202 {{kEventClassFont, kEventFontPanelClosed},
3203 {kEventClassFont, kEventFontSelection}};
3205 err = InstallApplicationEventHandler (mac_handle_font_event,
3206 GetEventTypeCount (specs),
3207 specs, NULL, NULL);
3208 if (err != noErr)
3209 return err;
3211 font_panel_shown_p = 1;
3214 return FPShowHideFontPanel ();
3217 /* Set the font selected in the font panel to the one corresponding to
3218 the face FACE_ID and the charcacter C in the frame F. */
3220 OSStatus
3221 mac_set_font_info_for_selection (f, face_id, c)
3222 struct frame *f;
3223 int face_id, c;
3225 OSStatus err;
3226 EventTargetRef target = NULL;
3227 XFontStruct *font = NULL;
3229 if (!mac_font_panel_visible_p ())
3230 return noErr;
3232 if (f)
3234 target = GetWindowEventTarget (FRAME_MAC_WINDOW (f));
3236 if (FRAME_FACE_CACHE (f) && CHAR_VALID_P (c, 0))
3238 struct face *face;
3240 face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c);
3241 face = FACE_FROM_ID (f, face_id);
3242 font = face->font;
3246 if (font == NULL)
3247 err = SetFontInfoForSelection (kFontSelectionATSUIType, 0, NULL, target);
3248 else
3250 if (font->mac_fontnum != -1)
3252 FontSelectionQDStyle qd_style;
3254 qd_style.version = kFontSelectionQDStyleVersionZero;
3255 qd_style.instance.fontFamily = font->mac_fontnum;
3256 qd_style.instance.fontStyle = font->mac_fontface;
3257 qd_style.size = font->mac_fontsize;
3258 qd_style.hasColor = false;
3260 err = SetFontInfoForSelection (kFontSelectionQDType,
3261 1, &qd_style, target);
3263 else
3264 err = SetFontInfoForSelection (kFontSelectionATSUIType,
3265 1, &font->mac_style, target);
3268 return err;
3270 #endif /* USE_MAC_FONT_PANEL */
3273 /************************************************************************
3274 Event Handling
3275 ************************************************************************/
3277 /* Non-zero means that a HELP_EVENT has been generated since Emacs
3278 start. */
3280 static int any_help_event_p;
3282 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
3283 static Lisp_Object last_window;
3285 static Point saved_menu_event_location;
3287 extern struct frame *pending_autoraise_frame;
3289 extern FRAME_PTR last_mouse_glyph_frame;
3291 #ifdef __STDC__
3292 extern int volatile input_signal_count;
3293 #else
3294 extern int input_signal_count;
3295 #endif
3297 extern int mac_screen_config_changed;
3299 extern Lisp_Object Vmac_emulate_three_button_mouse;
3300 #if TARGET_API_MAC_CARBON
3301 extern int mac_wheel_button_is_mouse_2;
3302 extern int mac_pass_command_to_system;
3303 extern int mac_pass_control_to_system;
3304 #endif /* TARGET_API_MAC_CARBON */
3305 extern int mac_ready_for_apple_events;
3307 extern void mac_focus_changed P_ ((int, struct mac_display_info *,
3308 struct frame *, struct input_event *));
3309 extern int mac_get_emulated_btn P_ ((UInt32));
3310 extern int note_mouse_movement P_ ((FRAME_PTR, Point *));
3311 extern void mac_get_screen_info P_ ((struct mac_display_info *));
3313 /* The focus may have changed. Figure out if it is a real focus change,
3314 by checking both FocusIn/Out and Enter/LeaveNotify events.
3316 Returns FOCUS_IN_EVENT event in *BUFP. */
3318 static void
3319 x_detect_focus_change (dpyinfo, event, bufp)
3320 struct mac_display_info *dpyinfo;
3321 const EventRecord *event;
3322 struct input_event *bufp;
3324 struct frame *frame;
3326 frame = mac_window_to_frame ((WindowRef) event->message);
3327 if (! frame)
3328 return;
3330 /* On Mac, this is only called from focus events, so no switch needed. */
3331 mac_focus_changed ((event->modifiers & activeFlag),
3332 dpyinfo, frame, bufp);
3335 #if TARGET_API_MAC_CARBON
3336 /* Obtains the event modifiers from the event EVENTREF and then calls
3337 mac_to_emacs_modifiers. */
3339 static int
3340 mac_event_to_emacs_modifiers (EventRef eventRef)
3342 UInt32 mods = 0, class;
3344 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL,
3345 sizeof (UInt32), NULL, &mods);
3346 class = GetEventClass (eventRef);
3347 if (!NILP (Vmac_emulate_three_button_mouse)
3348 && (class == kEventClassMouse || class == kEventClassCommand))
3350 mods &= ~(optionKey | cmdKey);
3352 return mac_to_emacs_modifiers (mods, 0);
3355 /* Given an event REF, return the code to use for the mouse button
3356 code in the emacs input_event. */
3358 static int
3359 mac_get_mouse_btn (EventRef ref)
3361 EventMouseButton result = kEventMouseButtonPrimary;
3362 GetEventParameter (ref, kEventParamMouseButton, typeMouseButton, NULL,
3363 sizeof (EventMouseButton), NULL, &result);
3364 switch (result)
3366 case kEventMouseButtonPrimary:
3367 if (NILP (Vmac_emulate_three_button_mouse))
3368 return 0;
3369 else {
3370 UInt32 mods = 0;
3371 GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL,
3372 sizeof (UInt32), NULL, &mods);
3373 return mac_get_emulated_btn(mods);
3375 case kEventMouseButtonSecondary:
3376 return mac_wheel_button_is_mouse_2 ? 2 : 1;
3377 case kEventMouseButtonTertiary:
3378 case 4: /* 4 is the number for the mouse wheel button */
3379 return mac_wheel_button_is_mouse_2 ? 1 : 2;
3380 default:
3381 return 0;
3385 /* Normally, ConvertEventRefToEventRecord will correctly handle all
3386 events. However the click of the mouse wheel is not converted to a
3387 mouseDown or mouseUp event. Likewise for dead key events. This
3388 calls ConvertEventRefToEventRecord, but then checks to see if it is
3389 a mouse up/down, or a dead key Carbon event that has not been
3390 converted, and if so, converts it by hand (to be picked up in the
3391 XTread_socket loop). */
3392 static Boolean mac_convert_event_ref (EventRef eventRef, EventRecord *eventRec)
3394 OSStatus err;
3395 Boolean result = ConvertEventRefToEventRecord (eventRef, eventRec);
3396 EventKind action;
3398 if (result)
3399 return result;
3401 switch (GetEventClass (eventRef))
3403 case kEventClassMouse:
3404 switch (GetEventKind (eventRef))
3406 case kEventMouseDown:
3407 eventRec->what = mouseDown;
3408 result = 1;
3409 break;
3411 case kEventMouseUp:
3412 eventRec->what = mouseUp;
3413 result = 1;
3414 break;
3416 default:
3417 break;
3419 break;
3421 case kEventClassKeyboard:
3422 switch (GetEventKind (eventRef))
3424 case kEventRawKeyDown:
3425 action = keyDown;
3426 goto keystroke_common;
3427 case kEventRawKeyRepeat:
3428 action = autoKey;
3429 goto keystroke_common;
3430 case kEventRawKeyUp:
3431 action = keyUp;
3432 keystroke_common:
3434 unsigned char char_codes;
3435 UInt32 key_code;
3437 err = GetEventParameter (eventRef, kEventParamKeyMacCharCodes,
3438 typeChar, NULL, sizeof (char),
3439 NULL, &char_codes);
3440 if (err == noErr)
3441 err = GetEventParameter (eventRef, kEventParamKeyCode,
3442 typeUInt32, NULL, sizeof (UInt32),
3443 NULL, &key_code);
3444 if (err == noErr)
3446 eventRec->what = action;
3447 eventRec->message = char_codes | ((key_code & 0xff) << 8);
3448 result = 1;
3451 break;
3453 default:
3454 break;
3456 break;
3458 default:
3459 break;
3462 if (result)
3464 /* Need where and when. */
3465 UInt32 mods = 0;
3467 GetEventParameter (eventRef, kEventParamMouseLocation, typeQDPoint,
3468 NULL, sizeof (Point), NULL, &eventRec->where);
3469 /* Use two step process because new event modifiers are 32-bit
3470 and old are 16-bit. Currently, only loss is NumLock & Fn. */
3471 GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32,
3472 NULL, sizeof (UInt32), NULL, &mods);
3473 eventRec->modifiers = mods;
3475 eventRec->when = EventTimeToTicks (GetEventTime (eventRef));
3478 return result;
3480 #endif /* TARGET_API_MAC_CARBON */
3482 #if !TARGET_API_MAC_CARBON
3483 static RgnHandle mouse_region = NULL;
3485 Boolean
3486 mac_wait_next_event (er, sleep_time, dequeue)
3487 EventRecord *er;
3488 UInt32 sleep_time;
3489 Boolean dequeue;
3491 static EventRecord er_buf = {nullEvent};
3492 UInt32 target_tick, current_tick;
3493 EventMask event_mask;
3495 if (mouse_region == NULL)
3496 mouse_region = NewRgn ();
3498 event_mask = everyEvent;
3499 if (!mac_ready_for_apple_events)
3500 event_mask -= highLevelEventMask;
3502 current_tick = TickCount ();
3503 target_tick = current_tick + sleep_time;
3505 if (er_buf.what == nullEvent)
3506 while (!WaitNextEvent (event_mask, &er_buf,
3507 target_tick - current_tick, mouse_region))
3509 current_tick = TickCount ();
3510 if (target_tick <= current_tick)
3511 return false;
3514 *er = er_buf;
3515 if (dequeue)
3516 er_buf.what = nullEvent;
3517 return true;
3519 #endif /* not TARGET_API_MAC_CARBON */
3521 #if TARGET_API_MAC_CARBON
3522 OSStatus
3523 mac_post_mouse_moved_event ()
3525 EventRef event = NULL;
3526 OSStatus err;
3528 err = CreateEvent (NULL, kEventClassMouse, kEventMouseMoved, 0,
3529 kEventAttributeNone, &event);
3530 if (err == noErr)
3532 Point mouse_pos;
3534 GetGlobalMouse (&mouse_pos);
3535 err = SetEventParameter (event, kEventParamMouseLocation, typeQDPoint,
3536 sizeof (Point), &mouse_pos);
3538 if (err == noErr)
3540 UInt32 modifiers = GetCurrentKeyModifiers ();
3542 err = SetEventParameter (event, kEventParamKeyModifiers, typeUInt32,
3543 sizeof (UInt32), &modifiers);
3545 if (err == noErr)
3546 err = PostEventToQueue (GetCurrentEventQueue (), event,
3547 kEventPriorityStandard);
3548 if (event)
3549 ReleaseEvent (event);
3551 return err;
3553 #endif
3555 #ifdef MAC_OSX
3556 /* Run the current run loop in the default mode until some input
3557 happens or TIMEOUT seconds passes unless it is negative. Return
3558 true if timeout occurs first. */
3560 Boolean
3561 mac_run_loop_run_once (timeout)
3562 EventTimeout timeout;
3564 #if USE_CG_DRAWING
3565 mac_prepare_for_quickdraw (NULL);
3566 #endif
3567 return (CFRunLoopRunInMode (kCFRunLoopDefaultMode,
3568 timeout >= 0 ? timeout : 100000, true)
3569 == kCFRunLoopRunTimedOut);
3571 #endif
3573 /* Emacs calls this whenever it wants to read an input event from the
3574 user. */
3577 XTread_socket (sd, expected, hold_quit)
3578 int sd, expected;
3579 struct input_event *hold_quit;
3581 struct input_event inev;
3582 int count = 0;
3583 #if TARGET_API_MAC_CARBON
3584 EventRef eventRef;
3585 EventTargetRef toolbox_dispatcher;
3586 #endif
3587 EventRecord er;
3588 struct mac_display_info *dpyinfo = &one_mac_display_info;
3590 if (interrupt_input_blocked)
3592 interrupt_input_pending = 1;
3593 return -1;
3596 interrupt_input_pending = 0;
3597 BLOCK_INPUT;
3599 /* So people can tell when we have read the available input. */
3600 input_signal_count++;
3602 ++handling_signal;
3604 #if TARGET_API_MAC_CARBON
3605 toolbox_dispatcher = GetEventDispatcherTarget ();
3607 while (
3608 #if USE_CG_DRAWING
3609 mac_prepare_for_quickdraw (NULL),
3610 #endif
3611 !ReceiveNextEvent (0, NULL, kEventDurationNoWait,
3612 kEventRemoveFromQueue, &eventRef))
3613 #else /* !TARGET_API_MAC_CARBON */
3614 while (mac_wait_next_event (&er, 0, true))
3615 #endif /* !TARGET_API_MAC_CARBON */
3617 int do_help = 0;
3618 struct frame *f;
3619 unsigned long timestamp;
3621 EVENT_INIT (inev);
3622 inev.kind = NO_EVENT;
3623 inev.arg = Qnil;
3625 #if TARGET_API_MAC_CARBON
3626 timestamp = GetEventTime (eventRef) / kEventDurationMillisecond;
3628 if (!mac_convert_event_ref (eventRef, &er))
3629 goto OTHER;
3630 #else /* !TARGET_API_MAC_CARBON */
3631 timestamp = er.when * (1000 / 60); /* ticks to milliseconds */
3632 #endif /* !TARGET_API_MAC_CARBON */
3634 switch (er.what)
3636 case mouseDown:
3637 case mouseUp:
3639 WindowRef window_ptr;
3640 ControlPartCode part_code;
3641 int tool_bar_p = 0;
3643 #if TARGET_API_MAC_CARBON
3644 OSStatus err;
3646 /* This is needed to send mouse events like aqua window
3647 buttons to the correct handler. */
3648 read_socket_inev = &inev;
3649 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
3650 read_socket_inev = NULL;
3651 if (err != eventNotHandledErr)
3652 break;
3653 #endif
3654 last_mouse_glyph_frame = 0;
3656 if (dpyinfo->grabbed && last_mouse_frame
3657 && FRAME_LIVE_P (last_mouse_frame))
3659 window_ptr = FRAME_MAC_WINDOW (last_mouse_frame);
3660 part_code = inContent;
3662 else
3664 part_code = FindWindow (er.where, &window_ptr);
3665 if (tip_window && window_ptr == tip_window)
3667 HideWindow (tip_window);
3668 part_code = FindWindow (er.where, &window_ptr);
3672 if (er.what != mouseDown
3673 && (part_code != inContent || dpyinfo->grabbed == 0))
3674 break;
3676 switch (part_code)
3678 case inMenuBar:
3679 f = mac_focus_frame (dpyinfo);
3680 saved_menu_event_location = er.where;
3681 inev.kind = MENU_BAR_ACTIVATE_EVENT;
3682 XSETFRAME (inev.frame_or_window, f);
3683 break;
3685 case inContent:
3686 if (
3687 #if TARGET_API_MAC_CARBON
3688 FrontNonFloatingWindow ()
3689 #else
3690 FrontWindow ()
3691 #endif
3692 != window_ptr
3693 || (mac_window_to_frame (window_ptr)
3694 != dpyinfo->x_focus_frame))
3695 SelectWindow (window_ptr);
3696 else
3698 ControlPartCode control_part_code;
3699 ControlRef ch;
3700 Point mouse_loc;
3701 #ifdef MAC_OSX
3702 ControlKind control_kind;
3703 #endif
3705 f = mac_window_to_frame (window_ptr);
3706 /* convert to local coordinates of new window */
3707 mouse_loc.h = (er.where.h
3708 - (f->left_pos
3709 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
3710 mouse_loc.v = (er.where.v
3711 - (f->top_pos
3712 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
3713 #if TARGET_API_MAC_CARBON
3714 ch = FindControlUnderMouse (mouse_loc, window_ptr,
3715 &control_part_code);
3716 #ifdef MAC_OSX
3717 if (ch)
3718 GetControlKind (ch, &control_kind);
3719 #endif
3720 #else
3721 control_part_code = FindControl (mouse_loc, window_ptr,
3722 &ch);
3723 #endif
3725 #if TARGET_API_MAC_CARBON
3726 inev.code = mac_get_mouse_btn (eventRef);
3727 inev.modifiers = mac_event_to_emacs_modifiers (eventRef);
3728 #else
3729 inev.code = mac_get_emulated_btn (er.modifiers);
3730 inev.modifiers = mac_to_emacs_modifiers (er.modifiers, 0);
3731 #endif
3732 XSETINT (inev.x, mouse_loc.h);
3733 XSETINT (inev.y, mouse_loc.v);
3735 if ((dpyinfo->grabbed && tracked_scroll_bar)
3736 || (ch != 0
3737 #ifndef USE_TOOLKIT_SCROLL_BARS
3738 /* control_part_code becomes kControlNoPart if
3739 a progress indicator is clicked. */
3740 && control_part_code != kControlNoPart
3741 #else /* USE_TOOLKIT_SCROLL_BARS */
3742 #ifdef MAC_OSX
3743 && control_kind.kind == kControlKindScrollBar
3744 #endif /* MAC_OSX */
3745 #endif /* USE_TOOLKIT_SCROLL_BARS */
3748 struct scroll_bar *bar;
3750 if (dpyinfo->grabbed && tracked_scroll_bar)
3752 bar = tracked_scroll_bar;
3753 #ifndef USE_TOOLKIT_SCROLL_BARS
3754 control_part_code = kControlIndicatorPart;
3755 #endif
3757 else
3758 bar = (struct scroll_bar *) GetControlReference (ch);
3759 #ifdef USE_TOOLKIT_SCROLL_BARS
3760 /* Make the "Ctrl-Mouse-2 splits window" work
3761 for toolkit scroll bars. */
3762 if (inev.modifiers & ctrl_modifier)
3763 x_scroll_bar_handle_click (bar, control_part_code,
3764 &er, &inev);
3765 else if (er.what == mouseDown)
3766 x_scroll_bar_handle_press (bar, control_part_code,
3767 mouse_loc, &inev);
3768 else
3769 x_scroll_bar_handle_release (bar, &inev);
3770 #else /* not USE_TOOLKIT_SCROLL_BARS */
3771 x_scroll_bar_handle_click (bar, control_part_code,
3772 &er, &inev);
3773 if (er.what == mouseDown
3774 && control_part_code == kControlIndicatorPart)
3775 tracked_scroll_bar = bar;
3776 else
3777 tracked_scroll_bar = NULL;
3778 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3780 else
3782 Lisp_Object window;
3783 int x = mouse_loc.h;
3784 int y = mouse_loc.v;
3786 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
3787 if (EQ (window, f->tool_bar_window))
3789 if (er.what == mouseDown)
3790 handle_tool_bar_click (f, x, y, 1, 0);
3791 else
3792 handle_tool_bar_click (f, x, y, 0,
3793 inev.modifiers);
3794 tool_bar_p = 1;
3796 else
3798 XSETFRAME (inev.frame_or_window, f);
3799 inev.kind = MOUSE_CLICK_EVENT;
3803 if (er.what == mouseDown)
3805 dpyinfo->grabbed |= (1 << inev.code);
3806 last_mouse_frame = f;
3808 if (!tool_bar_p)
3809 last_tool_bar_item = -1;
3811 else
3813 if ((dpyinfo->grabbed & (1 << inev.code)) == 0)
3814 /* If a button is released though it was not
3815 previously pressed, that would be because
3816 of multi-button emulation. */
3817 dpyinfo->grabbed = 0;
3818 else
3819 dpyinfo->grabbed &= ~(1 << inev.code);
3822 /* Ignore any mouse motion that happened before
3823 this event; any subsequent mouse-movement Emacs
3824 events should reflect only motion after the
3825 ButtonPress. */
3826 if (f != 0)
3827 f->mouse_moved = 0;
3829 #ifdef USE_TOOLKIT_SCROLL_BARS
3830 if (inev.kind == MOUSE_CLICK_EVENT
3831 || (inev.kind == SCROLL_BAR_CLICK_EVENT
3832 && (inev.modifiers & ctrl_modifier)))
3833 #endif
3834 switch (er.what)
3836 case mouseDown:
3837 inev.modifiers |= down_modifier;
3838 break;
3839 case mouseUp:
3840 inev.modifiers |= up_modifier;
3841 break;
3844 break;
3846 case inDrag:
3847 #if TARGET_API_MAC_CARBON
3848 case inProxyIcon:
3849 if (IsWindowPathSelectClick (window_ptr, &er))
3851 WindowPathSelect (window_ptr, NULL, NULL);
3852 break;
3854 if (part_code == inProxyIcon
3855 && (TrackWindowProxyDrag (window_ptr, er.where)
3856 != errUserWantsToDragWindow))
3857 break;
3858 DragWindow (window_ptr, er.where, NULL);
3859 #else /* not TARGET_API_MAC_CARBON */
3860 DragWindow (window_ptr, er.where, &qd.screenBits.bounds);
3861 /* Update the frame parameters. */
3863 struct frame *f = mac_window_to_frame (window_ptr);
3865 if (f && !f->async_iconified)
3866 mac_handle_origin_change (f);
3868 #endif /* not TARGET_API_MAC_CARBON */
3869 break;
3871 case inGoAway:
3872 if (TrackGoAway (window_ptr, er.where))
3874 inev.kind = DELETE_WINDOW_EVENT;
3875 XSETFRAME (inev.frame_or_window,
3876 mac_window_to_frame (window_ptr));
3878 break;
3880 /* window resize handling added --ben */
3881 case inGrow:
3882 do_grow_window (window_ptr, &er);
3883 break;
3885 /* window zoom handling added --ben */
3886 case inZoomIn:
3887 case inZoomOut:
3888 if (TrackBox (window_ptr, er.where, part_code))
3889 do_zoom_window (window_ptr, part_code);
3890 break;
3892 #if USE_MAC_TOOLBAR
3893 case inStructure:
3895 OSStatus err;
3896 HIViewRef ch;
3898 if (FrontNonFloatingWindow () != window_ptr)
3899 SelectWindow (window_ptr);
3901 err = HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr),
3902 eventRef, &ch);
3903 /* This doesn't work on Mac OS X 10.2. */
3904 if (err == noErr)
3905 HIViewClick (ch, eventRef);
3907 break;
3908 #endif /* USE_MAC_TOOLBAR */
3910 default:
3911 break;
3914 break;
3916 #if !TARGET_API_MAC_CARBON
3917 case updateEvt:
3918 do_window_update ((WindowRef) er.message);
3919 break;
3920 #endif
3922 case osEvt:
3923 #if TARGET_API_MAC_CARBON
3924 if (SendEventToEventTarget (eventRef, toolbox_dispatcher)
3925 != eventNotHandledErr)
3926 break;
3927 #endif
3928 switch ((er.message >> 24) & 0x000000FF)
3930 #if USE_MAC_TSM
3931 case suspendResumeMessage:
3932 if (er.message & resumeFlag)
3933 mac_tsm_resume ();
3934 else
3935 mac_tsm_suspend ();
3936 break;
3937 #endif
3939 case mouseMovedMessage:
3940 #if !TARGET_API_MAC_CARBON
3941 SetRectRgn (mouse_region, er.where.h, er.where.v,
3942 er.where.h + 1, er.where.v + 1);
3943 #endif
3944 previous_help_echo_string = help_echo_string;
3945 help_echo_string = Qnil;
3947 if (dpyinfo->grabbed && last_mouse_frame
3948 && FRAME_LIVE_P (last_mouse_frame))
3949 f = last_mouse_frame;
3950 else
3951 f = dpyinfo->x_focus_frame;
3953 if (dpyinfo->mouse_face_hidden)
3955 dpyinfo->mouse_face_hidden = 0;
3956 clear_mouse_face (dpyinfo);
3959 if (f)
3961 WindowRef wp = FRAME_MAC_WINDOW (f);
3962 Point mouse_pos;
3964 mouse_pos.h = (er.where.h
3965 - (f->left_pos
3966 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
3967 mouse_pos.v = (er.where.v
3968 - (f->top_pos
3969 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
3970 if (dpyinfo->grabbed && tracked_scroll_bar)
3971 #ifdef USE_TOOLKIT_SCROLL_BARS
3972 x_scroll_bar_handle_drag (wp, tracked_scroll_bar,
3973 mouse_pos, &inev);
3974 #else /* not USE_TOOLKIT_SCROLL_BARS */
3975 x_scroll_bar_note_movement (tracked_scroll_bar,
3976 mouse_pos.v
3977 - XINT (tracked_scroll_bar->top),
3978 er.when * (1000 / 60));
3979 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3980 else
3982 /* Generate SELECT_WINDOW_EVENTs when needed. */
3983 if (!NILP (Vmouse_autoselect_window))
3985 Lisp_Object window;
3987 window = window_from_coordinates (f,
3988 mouse_pos.h,
3989 mouse_pos.v,
3990 0, 0, 0, 0);
3992 /* Window will be selected only when it is
3993 not selected now and last mouse movement
3994 event was not in it. Minibuffer window
3995 will be selected only when it is active. */
3996 if (WINDOWP (window)
3997 && !EQ (window, last_window)
3998 && !EQ (window, selected_window)
3999 /* For click-to-focus window managers
4000 create event iff we don't leave the
4001 selected frame. */
4002 && (focus_follows_mouse
4003 || (EQ (XWINDOW (window)->frame,
4004 XWINDOW (selected_window)->frame))))
4006 inev.kind = SELECT_WINDOW_EVENT;
4007 inev.frame_or_window = window;
4010 last_window=window;
4012 if (!note_mouse_movement (f, &mouse_pos))
4013 help_echo_string = previous_help_echo_string;
4014 #if USE_MAC_TOOLBAR
4015 else
4016 mac_tool_bar_note_mouse_movement (f, eventRef);
4017 #endif
4021 /* If the contents of the global variable
4022 help_echo_string has changed, generate a
4023 HELP_EVENT. */
4024 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
4025 do_help = 1;
4026 break;
4028 break;
4030 case activateEvt:
4032 WindowRef window_ptr = (WindowRef) er.message;
4033 OSErr err;
4034 ControlRef root_control;
4036 if (window_ptr == tip_window)
4038 HideWindow (tip_window);
4039 break;
4042 if (!is_emacs_window (window_ptr))
4043 goto OTHER;
4045 f = mac_window_to_frame (window_ptr);
4047 if ((er.modifiers & activeFlag) != 0)
4049 /* A window has been activated */
4050 Point mouse_loc;
4052 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
4053 if (err == noErr)
4054 ActivateControl (root_control);
4056 x_detect_focus_change (dpyinfo, &er, &inev);
4058 mouse_loc.h = (er.where.h
4059 - (f->left_pos
4060 + FRAME_OUTER_TO_INNER_DIFF_X (f)));
4061 mouse_loc.v = (er.where.v
4062 - (f->top_pos
4063 + FRAME_OUTER_TO_INNER_DIFF_Y (f)));
4064 /* Window-activated event counts as mouse movement,
4065 so update things that depend on mouse position. */
4066 note_mouse_movement (f, &mouse_loc);
4068 else
4070 /* A window has been deactivated */
4071 err = GetRootControl (FRAME_MAC_WINDOW (f), &root_control);
4072 if (err == noErr)
4073 DeactivateControl (root_control);
4075 #ifdef USE_TOOLKIT_SCROLL_BARS
4076 if (dpyinfo->grabbed && tracked_scroll_bar)
4078 struct input_event event;
4080 EVENT_INIT (event);
4081 event.kind = NO_EVENT;
4082 x_scroll_bar_handle_release (tracked_scroll_bar, &event);
4083 if (event.kind != NO_EVENT)
4085 event.timestamp = timestamp;
4086 kbd_buffer_store_event_hold (&event, hold_quit);
4087 count++;
4090 #endif
4091 dpyinfo->grabbed = 0;
4093 x_detect_focus_change (dpyinfo, &er, &inev);
4095 if (f == dpyinfo->mouse_face_mouse_frame)
4097 /* If we move outside the frame, then we're
4098 certainly no longer on any text in the
4099 frame. */
4100 clear_mouse_face (dpyinfo);
4101 dpyinfo->mouse_face_mouse_frame = 0;
4104 /* Generate a nil HELP_EVENT to cancel a help-echo.
4105 Do it only if there's something to cancel.
4106 Otherwise, the startup message is cleared when the
4107 mouse leaves the frame. */
4108 if (any_help_event_p)
4109 do_help = -1;
4112 break;
4114 case keyDown:
4115 case keyUp:
4116 case autoKey:
4117 ObscureCursor ();
4119 f = mac_focus_frame (dpyinfo);
4120 XSETFRAME (inev.frame_or_window, f);
4122 /* If mouse-highlight is an integer, input clears out mouse
4123 highlighting. */
4124 if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
4125 && !EQ (f->tool_bar_window, dpyinfo->mouse_face_window))
4127 clear_mouse_face (dpyinfo);
4128 dpyinfo->mouse_face_hidden = 1;
4132 UInt32 modifiers = er.modifiers, mapped_modifiers;
4133 UInt32 key_code = (er.message & keyCodeMask) >> 8;
4135 #ifdef MAC_OSX
4136 GetEventParameter (eventRef, kEventParamKeyModifiers,
4137 typeUInt32, NULL,
4138 sizeof (UInt32), NULL, &modifiers);
4139 #endif
4140 mapped_modifiers = mac_mapped_modifiers (modifiers, key_code);
4142 #if TARGET_API_MAC_CARBON
4143 if (!(mapped_modifiers
4144 & ~(mac_pass_command_to_system ? cmdKey : 0)
4145 & ~(mac_pass_control_to_system ? controlKey : 0)))
4146 goto OTHER;
4147 else
4148 #endif
4149 if (er.what != keyUp)
4150 do_keystroke (er.what, er.message & charCodeMask,
4151 key_code, modifiers, timestamp, &inev);
4153 break;
4155 case kHighLevelEvent:
4156 AEProcessAppleEvent (&er);
4157 break;
4159 default:
4160 OTHER:
4161 #if TARGET_API_MAC_CARBON
4163 OSStatus err;
4165 read_socket_inev = &inev;
4166 err = SendEventToEventTarget (eventRef, toolbox_dispatcher);
4167 read_socket_inev = NULL;
4169 #endif
4170 break;
4172 #if TARGET_API_MAC_CARBON
4173 ReleaseEvent (eventRef);
4174 #endif
4176 if (inev.kind != NO_EVENT)
4178 inev.timestamp = timestamp;
4179 kbd_buffer_store_event_hold (&inev, hold_quit);
4180 count++;
4183 if (do_help
4184 && !(hold_quit && hold_quit->kind != NO_EVENT))
4186 Lisp_Object frame;
4188 if (f)
4189 XSETFRAME (frame, f);
4190 else
4191 frame = Qnil;
4193 if (do_help > 0)
4195 any_help_event_p = 1;
4196 gen_help_event (help_echo_string, frame, help_echo_window,
4197 help_echo_object, help_echo_pos);
4199 else
4201 help_echo_string = Qnil;
4202 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
4204 count++;
4208 /* If the focus was just given to an autoraising frame,
4209 raise it now. */
4210 /* ??? This ought to be able to handle more than one such frame. */
4211 if (pending_autoraise_frame)
4213 x_raise_frame (pending_autoraise_frame);
4214 pending_autoraise_frame = 0;
4217 if (mac_screen_config_changed)
4219 mac_get_screen_info (dpyinfo);
4220 mac_screen_config_changed = 0;
4223 #if !TARGET_API_MAC_CARBON
4224 /* Check which frames are still visible. We do this here because
4225 there doesn't seem to be any direct notification from the Window
4226 Manager that the visibility of a window has changed (at least,
4227 not in all cases). */
4229 Lisp_Object tail, frame;
4231 FOR_EACH_FRAME (tail, frame)
4233 struct frame *f = XFRAME (frame);
4235 /* The tooltip has been drawn already. Avoid the
4236 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
4237 if (EQ (frame, tip_frame))
4238 continue;
4240 if (FRAME_MAC_P (f))
4241 mac_handle_visibility_change (f);
4244 #endif
4246 --handling_signal;
4247 UNBLOCK_INPUT;
4248 return count;
4252 /***********************************************************************
4253 Busy cursor
4254 ***********************************************************************/
4256 #if TARGET_API_MAC_CARBON
4257 /* Show the spinning progress indicator for the frame F. Create it if
4258 it doesn't exist yet. */
4260 void
4261 mac_show_hourglass (f)
4262 struct frame *f;
4264 #if USE_CG_DRAWING
4265 mac_prepare_for_quickdraw (f);
4266 #endif
4267 if (!f->output_data.mac->hourglass_control)
4269 Window w = FRAME_MAC_WINDOW (f);
4270 Rect r;
4271 ControlRef c;
4273 GetWindowPortBounds (w, &r);
4274 r.left = r.right - HOURGLASS_WIDTH;
4275 r.bottom = r.top + HOURGLASS_HEIGHT;
4276 if (CreateChasingArrowsControl (w, &r, &c) == noErr)
4277 f->output_data.mac->hourglass_control = c;
4280 if (f->output_data.mac->hourglass_control)
4281 ShowControl (f->output_data.mac->hourglass_control);
4284 /* Hide the spinning progress indicator for the frame F. Do nothing
4285 it doesn't exist yet. */
4287 void
4288 mac_hide_hourglass (f)
4289 struct frame *f;
4291 if (f->output_data.mac->hourglass_control)
4293 #if USE_CG_DRAWING
4294 mac_prepare_for_quickdraw (f);
4295 #endif
4296 HideControl (f->output_data.mac->hourglass_control);
4300 /* Reposition the spinning progress indicator for the frame F. Do
4301 nothing it doesn't exist yet. */
4303 void
4304 mac_reposition_hourglass (f)
4305 struct frame *f;
4307 if (f->output_data.mac->hourglass_control)
4309 #if USE_CG_DRAWING
4310 mac_prepare_for_quickdraw (f);
4311 #endif
4312 MoveControl (f->output_data.mac->hourglass_control,
4313 FRAME_PIXEL_WIDTH (f) - HOURGLASS_WIDTH, 0);
4316 #endif /* TARGET_API_MAC_CARBON */
4319 /***********************************************************************
4320 File selection dialog
4321 ***********************************************************************/
4323 #if TARGET_API_MAC_CARBON
4324 extern Lisp_Object Qfile_name_history;
4326 static pascal void mac_nav_event_callback P_ ((NavEventCallbackMessage,
4327 NavCBRecPtr, void *));
4329 /* The actual implementation of Fx_file_dialog. */
4331 Lisp_Object
4332 mac_file_dialog (prompt, dir, default_filename, mustmatch, only_dir_p)
4333 Lisp_Object prompt, dir, default_filename, mustmatch, only_dir_p;
4335 Lisp_Object file = Qnil;
4336 int count = SPECPDL_INDEX ();
4337 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
4338 char filename[MAXPATHLEN];
4339 static NavEventUPP mac_nav_event_callbackUPP = NULL;
4341 check_mac ();
4343 GCPRO6 (prompt, dir, default_filename, mustmatch, file, only_dir_p);
4344 CHECK_STRING (prompt);
4345 CHECK_STRING (dir);
4347 /* Create the dialog with PROMPT as title, using DIR as initial
4348 directory and using "*" as pattern. */
4349 dir = Fexpand_file_name (dir, Qnil);
4352 OSStatus status;
4353 NavDialogCreationOptions options;
4354 NavDialogRef dialogRef;
4355 NavTypeListHandle fileTypes = NULL;
4356 NavUserAction userAction;
4357 CFStringRef message=NULL, saveName = NULL;
4359 BLOCK_INPUT;
4360 /* No need for a callback function because we are modal */
4361 NavGetDefaultDialogCreationOptions(&options);
4362 options.modality = kWindowModalityAppModal;
4363 options.location.h = options.location.v = -1;
4364 options.optionFlags = kNavDefaultNavDlogOptions;
4365 options.optionFlags |= kNavAllFilesInPopup; /* All files allowed */
4366 options.optionFlags |= kNavSelectAllReadableItem;
4367 options.optionFlags &= ~kNavAllowMultipleFiles;
4368 if (!NILP(prompt))
4370 message = cfstring_create_with_string (prompt);
4371 options.message = message;
4373 /* Don't set the application, let it use default.
4374 options.clientName = CFSTR ("Emacs");
4377 if (mac_nav_event_callbackUPP == NULL)
4378 mac_nav_event_callbackUPP = NewNavEventUPP (mac_nav_event_callback);
4380 if (!NILP (only_dir_p))
4381 status = NavCreateChooseFolderDialog(&options, mac_nav_event_callbackUPP,
4382 NULL, NULL, &dialogRef);
4383 else if (NILP (mustmatch))
4385 /* This is a save dialog */
4386 options.optionFlags |= kNavDontConfirmReplacement;
4387 options.actionButtonLabel = CFSTR ("Ok");
4388 options.windowTitle = CFSTR ("Enter name");
4390 if (STRINGP (default_filename))
4392 Lisp_Object utf8 = ENCODE_UTF_8 (default_filename);
4393 char *begPtr = SDATA(utf8);
4394 char *filePtr = begPtr + SBYTES(utf8);
4395 while (filePtr != begPtr && !IS_DIRECTORY_SEP(filePtr[-1]))
4396 filePtr--;
4397 saveName = cfstring_create_with_utf8_cstring (filePtr);
4398 options.saveFileName = saveName;
4399 options.optionFlags |= kNavSelectDefaultLocation;
4401 status = NavCreatePutFileDialog(&options,
4402 'TEXT', kNavGenericSignature,
4403 mac_nav_event_callbackUPP, NULL,
4404 &dialogRef);
4406 else
4408 /* This is an open dialog*/
4409 status = NavCreateChooseFileDialog(&options, fileTypes,
4410 mac_nav_event_callbackUPP, NULL,
4411 NULL, NULL, &dialogRef);
4414 /* Set the default location and continue*/
4415 if (status == noErr)
4417 Lisp_Object encoded_dir = ENCODE_FILE (dir);
4418 AEDesc defLocAed;
4420 status = AECreateDesc (TYPE_FILE_NAME, SDATA (encoded_dir),
4421 SBYTES (encoded_dir), &defLocAed);
4422 if (status == noErr)
4424 NavCustomControl(dialogRef, kNavCtlSetLocation, (void*) &defLocAed);
4425 AEDisposeDesc(&defLocAed);
4427 status = NavDialogRun(dialogRef);
4430 if (saveName) CFRelease(saveName);
4431 if (message) CFRelease(message);
4433 if (status == noErr) {
4434 userAction = NavDialogGetUserAction(dialogRef);
4435 switch (userAction)
4437 case kNavUserActionNone:
4438 case kNavUserActionCancel:
4439 break; /* Treat cancel like C-g */
4440 case kNavUserActionOpen:
4441 case kNavUserActionChoose:
4442 case kNavUserActionSaveAs:
4444 NavReplyRecord reply;
4445 Size len;
4447 status = NavDialogGetReply(dialogRef, &reply);
4448 if (status != noErr)
4449 break;
4450 status = AEGetNthPtr (&reply.selection, 1, TYPE_FILE_NAME,
4451 NULL, NULL, filename,
4452 sizeof (filename) - 1, &len);
4453 if (status == noErr)
4455 len = min (len, sizeof (filename) - 1);
4456 filename[len] = '\0';
4457 if (reply.saveFileName)
4459 /* If it was a saved file, we need to add the file name */
4460 if (len && len < sizeof (filename) - 1
4461 && filename[len-1] != '/')
4462 filename[len++] = '/';
4463 CFStringGetCString(reply.saveFileName, filename+len,
4464 sizeof (filename) - len,
4465 #ifdef MAC_OSX
4466 kCFStringEncodingUTF8
4467 #else
4468 CFStringGetSystemEncoding ()
4469 #endif
4472 file = DECODE_FILE (make_unibyte_string (filename,
4473 strlen (filename)));
4475 NavDisposeReply(&reply);
4477 break;
4479 NavDialogDispose(dialogRef);
4480 UNBLOCK_INPUT;
4482 else {
4483 UNBLOCK_INPUT;
4484 /* Fall back on minibuffer if there was a problem */
4485 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
4486 dir, mustmatch, dir, Qfile_name_history,
4487 default_filename, Qnil);
4491 UNGCPRO;
4493 /* Make "Cancel" equivalent to C-g. */
4494 if (NILP (file))
4495 Fsignal (Qquit, Qnil);
4497 return unbind_to (count, file);
4500 /* Need to register some event callback function for enabling drag and
4501 drop in Navigation Service dialogs. */
4502 static pascal void
4503 mac_nav_event_callback (selector, parms, data)
4504 NavEventCallbackMessage selector;
4505 NavCBRecPtr parms;
4506 void *data;
4509 #endif
4512 /************************************************************************
4513 Menu
4514 ************************************************************************/
4516 #if !TARGET_API_MAC_CARBON
4517 #include <MacTypes.h>
4518 #include <Menus.h>
4519 #include <Quickdraw.h>
4520 #include <ToolUtils.h>
4521 #include <Fonts.h>
4522 #include <Controls.h>
4523 #include <Windows.h>
4524 #include <Events.h>
4525 #if defined (__MRC__) || (__MSL__ >= 0x6000)
4526 #include <ControlDefinitions.h>
4527 #endif
4528 #endif /* not TARGET_API_MAC_CARBON */
4530 extern int menu_item_selection;
4531 extern int popup_activated_flag;
4532 extern int name_is_separator P_ ((const char *));
4533 extern void find_and_call_menu_selection P_ ((FRAME_PTR, int, Lisp_Object,
4534 void *));
4535 extern void set_frame_menubar P_ ((FRAME_PTR, int, int));
4537 enum mac_menu_kind { /* Menu ID range */
4538 MAC_MENU_APPLE, /* 0 (Reserved by Apple) */
4539 MAC_MENU_MENU_BAR, /* 1 .. 233 */
4540 MAC_MENU_M_APPLE, /* 234 (== M_APPLE) */
4541 MAC_MENU_POPUP, /* 235 */
4542 MAC_MENU_DRIVER, /* 236 .. 255 (Reserved) */
4543 MAC_MENU_MENU_BAR_SUB, /* 256 .. 16383 */
4544 MAC_MENU_POPUP_SUB, /* 16384 .. 32767 */
4545 MAC_MENU_END /* 32768 */
4548 static const int min_menu_id[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
4550 static int fill_menu P_ ((MenuRef, widget_value *, enum mac_menu_kind, int));
4551 static void dispose_menus P_ ((enum mac_menu_kind, int));
4553 #if !TARGET_API_MAC_CARBON
4554 static void
4555 do_apple_menu (SInt16 menu_item)
4557 Str255 item_name;
4558 SInt16 da_driver_refnum;
4560 if (menu_item == I_ABOUT)
4561 NoteAlert (ABOUT_ALERT_ID, NULL);
4562 else
4564 GetMenuItemText (GetMenuRef (M_APPLE), menu_item, item_name);
4565 da_driver_refnum = OpenDeskAcc (item_name);
4568 #endif /* !TARGET_API_MAC_CARBON */
4570 /* Activate the menu bar of frame F.
4571 This is called from keyboard.c when it gets the
4572 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
4574 To activate the menu bar, we use the button-press event location
4575 that was saved in saved_menu_event_location.
4577 But first we recompute the menu bar contents (the whole tree).
4579 The reason for saving the button event until here, instead of
4580 passing it to the toolkit right away, is that we can safely
4581 execute Lisp code. */
4583 void
4584 x_activate_menubar (f)
4585 FRAME_PTR f;
4587 SInt32 menu_choice;
4588 SInt16 menu_id, menu_item;
4590 set_frame_menubar (f, 0, 1);
4591 BLOCK_INPUT;
4593 popup_activated_flag = 1;
4594 menu_choice = MenuSelect (saved_menu_event_location);
4595 popup_activated_flag = 0;
4596 menu_id = HiWord (menu_choice);
4597 menu_item = LoWord (menu_choice);
4599 #if !TARGET_API_MAC_CARBON
4600 if (menu_id == min_menu_id[MAC_MENU_M_APPLE])
4601 do_apple_menu (menu_item);
4602 else
4603 #endif
4604 if (menu_id)
4606 MenuRef menu = GetMenuRef (menu_id);
4608 if (menu)
4610 UInt32 refcon;
4612 GetMenuItemRefCon (menu, menu_item, &refcon);
4613 find_and_call_menu_selection (f, f->menu_bar_items_used,
4614 f->menu_bar_vector, (void *) refcon);
4618 HiliteMenu (0);
4620 UNBLOCK_INPUT;
4623 #if TARGET_API_MAC_CARBON
4624 extern Lisp_Object Vshow_help_function;
4626 static Lisp_Object
4627 restore_show_help_function (old_show_help_function)
4628 Lisp_Object old_show_help_function;
4630 Vshow_help_function = old_show_help_function;
4632 return Qnil;
4635 static pascal OSStatus
4636 menu_target_item_handler (next_handler, event, data)
4637 EventHandlerCallRef next_handler;
4638 EventRef event;
4639 void *data;
4641 OSStatus err;
4642 MenuRef menu;
4643 MenuItemIndex menu_item;
4644 Lisp_Object help;
4645 GrafPtr port;
4646 int specpdl_count = SPECPDL_INDEX ();
4648 /* Don't be bothered with the overflowed toolbar items menu. */
4649 if (!popup_activated ())
4650 return eventNotHandledErr;
4652 err = GetEventParameter (event, kEventParamDirectObject, typeMenuRef,
4653 NULL, sizeof (MenuRef), NULL, &menu);
4654 if (err == noErr)
4655 err = GetEventParameter (event, kEventParamMenuItemIndex,
4656 typeMenuItemIndex, NULL,
4657 sizeof (MenuItemIndex), NULL, &menu_item);
4658 if (err == noErr)
4659 err = GetMenuItemProperty (menu, menu_item,
4660 MAC_EMACS_CREATOR_CODE, 'help',
4661 sizeof (Lisp_Object), NULL, &help);
4662 if (err != noErr)
4663 help = Qnil;
4665 /* Temporarily bind Vshow_help_function to Qnil because we don't
4666 want tooltips during menu tracking. */
4667 record_unwind_protect (restore_show_help_function, Vshow_help_function);
4668 Vshow_help_function = Qnil;
4669 GetPort (&port);
4670 show_help_echo (help, Qnil, Qnil, Qnil, 1);
4671 SetPort (port);
4672 unbind_to (specpdl_count, Qnil);
4674 return err == noErr ? noErr : eventNotHandledErr;
4677 /* Showing help echo string during menu tracking. */
4679 static OSStatus
4680 install_menu_target_item_handler ()
4682 static const EventTypeSpec specs[] =
4683 {{kEventClassMenu, kEventMenuTargetItem}};
4685 return InstallApplicationEventHandler (NewEventHandlerUPP
4686 (menu_target_item_handler),
4687 GetEventTypeCount (specs),
4688 specs, NULL, NULL);
4690 #endif /* TARGET_API_MAC_CARBON */
4692 /* Event handler function that pops down a menu on C-g. We can only pop
4693 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
4695 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4696 static pascal OSStatus
4697 menu_quit_handler (nextHandler, theEvent, userData)
4698 EventHandlerCallRef nextHandler;
4699 EventRef theEvent;
4700 void* userData;
4702 OSStatus err;
4703 UInt32 keyCode;
4704 UInt32 keyModifiers;
4706 err = GetEventParameter (theEvent, kEventParamKeyCode,
4707 typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
4709 if (err == noErr)
4710 err = GetEventParameter (theEvent, kEventParamKeyModifiers,
4711 typeUInt32, NULL, sizeof(UInt32),
4712 NULL, &keyModifiers);
4714 if (err == noErr && mac_quit_char_key_p (keyModifiers, keyCode))
4716 MenuRef menu = userData != 0
4717 ? (MenuRef)userData : AcquireRootMenu ();
4719 CancelMenuTracking (menu, true, 0);
4720 if (!userData) ReleaseMenu (menu);
4721 return noErr;
4724 return CallNextEventHandler (nextHandler, theEvent);
4726 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4728 /* Add event handler to all menus that belong to KIND so we can detect
4729 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
4730 when C-g is detected. NULL means the menu bar. If
4731 CancelMenuTracking isn't available, do nothing. */
4733 static void
4734 install_menu_quit_handler (kind, root_menu)
4735 enum mac_menu_kind kind;
4736 MenuRef root_menu;
4738 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4739 static const EventTypeSpec typesList[] =
4740 {{kEventClassKeyboard, kEventRawKeyDown}};
4741 int id;
4743 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
4744 if (CancelMenuTracking == NULL)
4745 return;
4746 #endif
4747 for (id = min_menu_id[kind]; id < min_menu_id[kind + 1]; id++)
4749 MenuRef menu = GetMenuRef (id);
4751 if (menu == NULL)
4752 break;
4753 InstallMenuEventHandler (menu, menu_quit_handler,
4754 GetEventTypeCount (typesList),
4755 typesList, root_menu, NULL);
4757 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4760 static Lisp_Object
4761 pop_down_menu (arg)
4762 Lisp_Object arg;
4764 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
4765 FRAME_PTR f = p->pointer;
4766 MenuRef menu = GetMenuRef (min_menu_id[MAC_MENU_POPUP]);
4768 BLOCK_INPUT;
4770 /* Must reset this manually because the button release event is not
4771 passed to Emacs event loop. */
4772 FRAME_MAC_DISPLAY_INFO (f)->grabbed = 0;
4774 /* delete all menus */
4775 dispose_menus (MAC_MENU_POPUP_SUB, 0);
4776 DeleteMenu (min_menu_id[MAC_MENU_POPUP]);
4777 DisposeMenu (menu);
4779 UNBLOCK_INPUT;
4781 return Qnil;
4784 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop
4785 until the menu pops down. Return the selection. */
4787 void
4788 create_and_show_popup_menu (f, first_wv, x, y, for_click)
4789 FRAME_PTR f;
4790 widget_value *first_wv;
4791 int x;
4792 int y;
4793 int for_click;
4795 int result = 0;
4796 MenuRef menu = NewMenu (min_menu_id[MAC_MENU_POPUP], "\p");
4797 int menu_item_choice;
4798 int specpdl_count = SPECPDL_INDEX ();
4800 InsertMenu (menu, -1);
4801 fill_menu (menu, first_wv->contents, MAC_MENU_POPUP_SUB,
4802 min_menu_id[MAC_MENU_POPUP_SUB]);
4804 /* Add event handler so we can detect C-g. */
4805 install_menu_quit_handler (MAC_MENU_POPUP, menu);
4806 install_menu_quit_handler (MAC_MENU_POPUP_SUB, menu);
4808 record_unwind_protect (pop_down_menu, make_save_value (f, 0));
4810 /* Adjust coordinates to be root-window-relative. */
4811 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
4812 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
4814 /* Display the menu. */
4815 popup_activated_flag = 1;
4816 menu_item_choice = PopUpMenuSelect (menu, y, x, 0);
4817 popup_activated_flag = 0;
4819 /* Get the refcon to find the correct item */
4820 if (menu_item_choice)
4822 MenuRef sel_menu = GetMenuRef (HiWord (menu_item_choice));
4824 if (sel_menu)
4825 GetMenuItemRefCon (sel_menu, LoWord (menu_item_choice),
4826 (UInt32 *) &result);
4829 unbind_to (specpdl_count, Qnil);
4831 menu_item_selection = result;
4834 static void
4835 add_menu_item (menu, pos, wv)
4836 MenuRef menu;
4837 int pos;
4838 widget_value *wv;
4840 #if TARGET_API_MAC_CARBON
4841 CFStringRef item_name;
4842 #else
4843 Str255 item_name;
4844 #endif
4846 if (name_is_separator (wv->name))
4847 AppendMenu (menu, "\p-");
4848 else
4850 AppendMenu (menu, "\pX");
4852 #if TARGET_API_MAC_CARBON
4853 item_name = cfstring_create_with_utf8_cstring (wv->name);
4855 if (wv->key != NULL)
4857 CFStringRef name, key;
4859 name = item_name;
4860 key = cfstring_create_with_utf8_cstring (wv->key);
4861 item_name = CFStringCreateWithFormat (NULL, NULL, CFSTR ("%@ %@"),
4862 name, key);
4863 CFRelease (name);
4864 CFRelease (key);
4867 SetMenuItemTextWithCFString (menu, pos, item_name);
4868 CFRelease (item_name);
4870 if (wv->enabled)
4871 EnableMenuItem (menu, pos);
4872 else
4873 DisableMenuItem (menu, pos);
4875 if (STRINGP (wv->help))
4876 SetMenuItemProperty (menu, pos, MAC_EMACS_CREATOR_CODE, 'help',
4877 sizeof (Lisp_Object), &wv->help);
4878 #else /* ! TARGET_API_MAC_CARBON */
4879 item_name[sizeof (item_name) - 1] = '\0';
4880 strncpy (item_name, wv->name, sizeof (item_name) - 1);
4881 if (wv->key != NULL)
4883 int len = strlen (item_name);
4885 strncpy (item_name + len, " ", sizeof (item_name) - 1 - len);
4886 len = strlen (item_name);
4887 strncpy (item_name + len, wv->key, sizeof (item_name) - 1 - len);
4889 c2pstr (item_name);
4890 SetMenuItemText (menu, pos, item_name);
4892 if (wv->enabled)
4893 EnableItem (menu, pos);
4894 else
4895 DisableItem (menu, pos);
4896 #endif /* ! TARGET_API_MAC_CARBON */
4898 /* Draw radio buttons and tickboxes. */
4899 if (wv->selected && (wv->button_type == BUTTON_TYPE_TOGGLE
4900 || wv->button_type == BUTTON_TYPE_RADIO))
4901 SetItemMark (menu, pos, checkMark);
4902 else
4903 SetItemMark (menu, pos, noMark);
4905 SetMenuItemRefCon (menu, pos, (UInt32) wv->call_data);
4909 /* Construct native Mac OS menu based on widget_value tree. */
4911 static int
4912 fill_menu (menu, wv, kind, submenu_id)
4913 MenuRef menu;
4914 widget_value *wv;
4915 enum mac_menu_kind kind;
4916 int submenu_id;
4918 int pos;
4920 for (pos = 1; wv != NULL; wv = wv->next, pos++)
4922 add_menu_item (menu, pos, wv);
4923 if (wv->contents && submenu_id < min_menu_id[kind + 1])
4925 MenuRef submenu = NewMenu (submenu_id, "\pX");
4927 InsertMenu (submenu, -1);
4928 #if TARGET_API_MAC_CARBON
4929 SetMenuItemHierarchicalMenu (menu, pos, submenu);
4930 #else
4931 SetMenuItemHierarchicalID (menu, pos, submenu_id);
4932 #endif
4933 submenu_id = fill_menu (submenu, wv->contents, kind, submenu_id + 1);
4937 return submenu_id;
4940 /* Fill menu bar with the items defined by WV. If DEEP_P, consider
4941 the entire menu trees we supply, rather than just the menu bar item
4942 names. */
4944 void
4945 mac_fill_menubar (wv, deep_p)
4946 widget_value *wv;
4947 int deep_p;
4949 int id, submenu_id;
4950 #if !TARGET_API_MAC_CARBON
4951 int title_changed_p = 0;
4952 #endif
4954 /* Clean up the menu bar when filled by the entire menu trees. */
4955 if (deep_p)
4957 dispose_menus (MAC_MENU_MENU_BAR, 0);
4958 dispose_menus (MAC_MENU_MENU_BAR_SUB, 0);
4959 #if !TARGET_API_MAC_CARBON
4960 title_changed_p = 1;
4961 #endif
4964 /* Fill menu bar titles and submenus. Reuse the existing menu bar
4965 titles as much as possible to minimize redraw (if !deep_p). */
4966 submenu_id = min_menu_id[MAC_MENU_MENU_BAR_SUB];
4967 for (id = min_menu_id[MAC_MENU_MENU_BAR];
4968 wv != NULL && id < min_menu_id[MAC_MENU_MENU_BAR + 1];
4969 wv = wv->next, id++)
4971 OSStatus err = noErr;
4972 MenuRef menu;
4973 #if TARGET_API_MAC_CARBON
4974 CFStringRef title;
4976 title = CFStringCreateWithCString (NULL, wv->name,
4977 kCFStringEncodingMacRoman);
4978 #else
4979 Str255 title;
4981 strncpy (title, wv->name, 255);
4982 title[255] = '\0';
4983 c2pstr (title);
4984 #endif
4986 menu = GetMenuRef (id);
4987 if (menu)
4989 #if TARGET_API_MAC_CARBON
4990 CFStringRef old_title;
4992 err = CopyMenuTitleAsCFString (menu, &old_title);
4993 if (err == noErr)
4995 if (CFStringCompare (title, old_title, 0) != kCFCompareEqualTo)
4997 #ifdef MAC_OSX
4998 if (id + 1 == min_menu_id[MAC_MENU_MENU_BAR + 1]
4999 || GetMenuRef (id + 1) == NULL)
5001 /* This is a workaround for Mac OS X 10.5 where
5002 just calling SetMenuTitleWithCFString fails
5003 to change the title of the last (Help) menu
5004 in the menu bar. */
5005 DeleteMenu (id);
5006 DisposeMenu (menu);
5007 menu = NULL;
5009 else
5010 #endif /* MAC_OSX */
5011 err = SetMenuTitleWithCFString (menu, title);
5013 CFRelease (old_title);
5015 else
5016 err = SetMenuTitleWithCFString (menu, title);
5017 #else /* !TARGET_API_MAC_CARBON */
5018 if (!EqualString (title, (*menu)->menuData, false, false))
5020 DeleteMenu (id);
5021 DisposeMenu (menu);
5022 menu = NewMenu (id, title);
5023 InsertMenu (menu, GetMenuRef (id + 1) ? id + 1 : 0);
5024 title_changed_p = 1;
5026 #endif /* !TARGET_API_MAC_CARBON */
5029 if (!menu)
5031 #if TARGET_API_MAC_CARBON
5032 err = CreateNewMenu (id, 0, &menu);
5033 if (err == noErr)
5034 err = SetMenuTitleWithCFString (menu, title);
5035 #else
5036 menu = NewMenu (id, title);
5037 #endif
5038 if (err == noErr)
5040 InsertMenu (menu, 0);
5041 #if !TARGET_API_MAC_CARBON
5042 title_changed_p = 1;
5043 #endif
5046 #if TARGET_API_MAC_CARBON
5047 CFRelease (title);
5048 #endif
5050 if (err == noErr)
5051 if (wv->contents)
5052 submenu_id = fill_menu (menu, wv->contents, MAC_MENU_MENU_BAR_SUB,
5053 submenu_id);
5056 if (id < min_menu_id[MAC_MENU_MENU_BAR + 1] && GetMenuRef (id))
5058 dispose_menus (MAC_MENU_MENU_BAR, id);
5059 #if !TARGET_API_MAC_CARBON
5060 title_changed_p = 1;
5061 #endif
5064 #if !TARGET_API_MAC_CARBON
5065 if (title_changed_p)
5066 InvalMenuBar ();
5067 #endif
5069 /* Add event handler so we can detect C-g. */
5070 install_menu_quit_handler (MAC_MENU_MENU_BAR, NULL);
5071 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB, NULL);
5074 /* Dispose of menus that belong to KIND, and remove them from the menu
5075 list. ID is the lower bound of menu IDs that will be processed. */
5077 static void
5078 dispose_menus (kind, id)
5079 enum mac_menu_kind kind;
5080 int id;
5082 for (id = max (id, min_menu_id[kind]); id < min_menu_id[kind + 1]; id++)
5084 MenuRef menu = GetMenuRef (id);
5086 if (menu == NULL)
5087 break;
5088 DeleteMenu (id);
5089 DisposeMenu (menu);
5093 static void
5094 init_menu_bar ()
5096 #ifdef MAC_OSX
5097 OSStatus err;
5098 MenuRef menu;
5099 MenuItemIndex menu_index;
5101 err = GetIndMenuItemWithCommandID (NULL, kHICommandQuit, 1,
5102 &menu, &menu_index);
5103 if (err == noErr)
5104 SetMenuItemCommandKey (menu, menu_index, false, 0);
5105 EnableMenuCommand (NULL, kHICommandPreferences);
5106 err = GetIndMenuItemWithCommandID (NULL, kHICommandPreferences, 1,
5107 &menu, &menu_index);
5108 if (err == noErr)
5110 SetMenuItemCommandKey (menu, menu_index, false, 0);
5111 InsertMenuItemTextWithCFString (menu, NULL,
5112 0, kMenuItemAttrSeparator, 0);
5113 InsertMenuItemTextWithCFString (menu, CFSTR ("About Emacs"),
5114 0, 0, kHICommandAbout);
5116 #else /* !MAC_OSX */
5117 #if TARGET_API_MAC_CARBON
5118 SetMenuItemCommandID (GetMenuRef (M_APPLE), I_ABOUT, kHICommandAbout);
5119 #endif
5120 #endif
5124 /***********************************************************************
5125 Popup Dialog
5126 ***********************************************************************/
5128 #if TARGET_API_MAC_CARBON
5129 #define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
5130 #define DIALOG_BUTTON_COMMAND_ID_P(id) \
5131 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
5132 #define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
5133 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
5134 #define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
5135 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
5137 extern EMACS_TIME timer_check P_ ((int));
5138 static int quit_dialog_event_loop;
5140 static pascal OSStatus
5141 mac_handle_dialog_event (next_handler, event, data)
5142 EventHandlerCallRef next_handler;
5143 EventRef event;
5144 void *data;
5146 OSStatus err, result = eventNotHandledErr;
5147 WindowRef window = (WindowRef) data;
5149 switch (GetEventClass (event))
5151 case kEventClassCommand:
5153 HICommand command;
5155 err = GetEventParameter (event, kEventParamDirectObject,
5156 typeHICommand, NULL, sizeof (HICommand),
5157 NULL, &command);
5158 if (err == noErr)
5159 if (DIALOG_BUTTON_COMMAND_ID_P (command.commandID))
5161 SetWRefCon (window, command.commandID);
5162 quit_dialog_event_loop = 1;
5163 break;
5166 result = CallNextEventHandler (next_handler, event);
5168 break;
5170 case kEventClassKeyboard:
5172 OSStatus result;
5173 char char_code;
5175 result = CallNextEventHandler (next_handler, event);
5176 if (result != eventNotHandledErr)
5177 break;
5179 err = GetEventParameter (event, kEventParamKeyMacCharCodes,
5180 typeChar, NULL, sizeof (char),
5181 NULL, &char_code);
5182 if (err == noErr)
5183 switch (char_code)
5185 case kEscapeCharCode:
5186 quit_dialog_event_loop = 1;
5187 break;
5189 default:
5191 UInt32 modifiers, key_code;
5193 err = GetEventParameter (event, kEventParamKeyModifiers,
5194 typeUInt32, NULL, sizeof (UInt32),
5195 NULL, &modifiers);
5196 if (err == noErr)
5197 err = GetEventParameter (event, kEventParamKeyCode,
5198 typeUInt32, NULL, sizeof (UInt32),
5199 NULL, &key_code);
5200 if (err == noErr)
5201 if (mac_quit_char_key_p (modifiers, key_code))
5202 quit_dialog_event_loop = 1;
5204 break;
5207 break;
5209 default:
5210 abort ();
5213 if (quit_dialog_event_loop)
5215 err = QuitEventLoop (GetCurrentEventLoop ());
5216 if (err == noErr)
5217 result = noErr;
5220 return result;
5223 static OSStatus
5224 install_dialog_event_handler (window)
5225 WindowRef window;
5227 static const EventTypeSpec specs[] =
5228 {{kEventClassCommand, kEventCommandProcess},
5229 {kEventClassKeyboard, kEventRawKeyDown}};
5230 static EventHandlerUPP handle_dialog_eventUPP = NULL;
5232 if (handle_dialog_eventUPP == NULL)
5233 handle_dialog_eventUPP = NewEventHandlerUPP (mac_handle_dialog_event);
5234 return InstallWindowEventHandler (window, handle_dialog_eventUPP,
5235 GetEventTypeCount (specs), specs,
5236 window, NULL);
5239 static Lisp_Object
5240 pop_down_dialog (arg)
5241 Lisp_Object arg;
5243 struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
5244 WindowRef window = p->pointer;
5246 BLOCK_INPUT;
5248 if (popup_activated_flag)
5249 EndAppModalStateForWindow (window);
5250 DisposeWindow (window);
5251 popup_activated_flag = 0;
5253 UNBLOCK_INPUT;
5255 return Qnil;
5258 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
5259 dialog pops down.
5260 menu_item_selection will be set to the selection. */
5262 void
5263 create_and_show_dialog (f, first_wv)
5264 FRAME_PTR f;
5265 widget_value *first_wv;
5267 OSStatus err;
5268 char *dialog_name, *message;
5269 int nb_buttons, first_group_count, i, result = 0;
5270 widget_value *wv;
5271 short buttons_height, text_height, inner_width, inner_height;
5272 Rect empty_rect, *rects;
5273 WindowRef window = NULL;
5274 ControlRef *buttons, default_button = NULL, text;
5275 int specpdl_count = SPECPDL_INDEX ();
5277 dialog_name = first_wv->name;
5278 nb_buttons = dialog_name[1] - '0';
5279 first_group_count = nb_buttons - (dialog_name[4] - '0');
5281 wv = first_wv->contents;
5282 message = wv->value;
5284 wv = wv->next;
5285 SetRect (&empty_rect, 0, 0, 0, 0);
5287 /* Create dialog window. */
5288 err = CreateNewWindow (kMovableModalWindowClass,
5289 kWindowStandardHandlerAttribute,
5290 &empty_rect, &window);
5291 if (err == noErr)
5293 record_unwind_protect (pop_down_dialog, make_save_value (window, 0));
5294 err = SetThemeWindowBackground (window, kThemeBrushMovableModalBackground,
5295 true);
5297 if (err == noErr)
5298 err = SetWindowTitleWithCFString (window, (dialog_name[0] == 'Q'
5299 ? CFSTR ("Question")
5300 : CFSTR ("Information")));
5302 /* Create button controls and measure their optimal bounds. */
5303 if (err == noErr)
5305 buttons = alloca (sizeof (ControlRef) * nb_buttons);
5306 rects = alloca (sizeof (Rect) * nb_buttons);
5307 for (i = 0; i < nb_buttons; i++)
5309 CFStringRef label = cfstring_create_with_utf8_cstring (wv->value);
5311 if (label == NULL)
5312 err = memFullErr;
5313 else
5315 err = CreatePushButtonControl (window, &empty_rect,
5316 label, &buttons[i]);
5317 CFRelease (label);
5319 if (err == noErr)
5321 if (!wv->enabled)
5323 #ifdef MAC_OSX
5324 err = DisableControl (buttons[i]);
5325 #else
5326 err = DeactivateControl (buttons[i]);
5327 #endif
5329 else if (default_button == NULL)
5330 default_button = buttons[i];
5332 if (err == noErr)
5334 SInt16 unused;
5336 rects[i] = empty_rect;
5337 err = GetBestControlRect (buttons[i], &rects[i], &unused);
5339 if (err == noErr)
5341 UInt32 command_id;
5343 OffsetRect (&rects[i], -rects[i].left, -rects[i].top);
5344 if (rects[i].right < DIALOG_BUTTON_MIN_WIDTH)
5345 rects[i].right = DIALOG_BUTTON_MIN_WIDTH;
5346 else if (rects[i].right > DIALOG_MAX_INNER_WIDTH)
5347 rects[i].right = DIALOG_MAX_INNER_WIDTH;
5349 command_id = DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv->call_data);
5350 err = SetControlCommandID (buttons[i], command_id);
5352 if (err != noErr)
5353 break;
5354 wv = wv->next;
5358 /* Layout buttons. rects[i] is set relative to the bottom-right
5359 corner of the inner box. */
5360 if (err == noErr)
5362 short bottom, right, max_height, left_align_shift;
5364 inner_width = DIALOG_MIN_INNER_WIDTH;
5365 bottom = right = max_height = 0;
5366 for (i = 0; i < nb_buttons; i++)
5368 if (right - rects[i].right < - inner_width)
5370 if (i != first_group_count
5371 && right - rects[i].right >= - DIALOG_MAX_INNER_WIDTH)
5372 inner_width = - (right - rects[i].right);
5373 else
5375 bottom -= max_height + DIALOG_BUTTON_BUTTON_VERTICAL_SPACE;
5376 right = max_height = 0;
5379 if (max_height < rects[i].bottom)
5380 max_height = rects[i].bottom;
5381 OffsetRect (&rects[i], right - rects[i].right,
5382 bottom - rects[i].bottom);
5383 right = rects[i].left - DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
5384 if (i == first_group_count - 1)
5385 right -= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE;
5387 buttons_height = - (bottom - max_height);
5389 left_align_shift = - (inner_width + rects[nb_buttons - 1].left);
5390 for (i = nb_buttons - 1; i >= first_group_count; i--)
5392 if (bottom != rects[i].bottom)
5394 left_align_shift = - (inner_width + rects[i].left);
5395 bottom = rects[i].bottom;
5397 OffsetRect (&rects[i], left_align_shift, 0);
5401 /* Create a static text control and measure its bounds. */
5402 if (err == noErr)
5404 CFStringRef message_string;
5405 Rect bounds;
5407 message_string = cfstring_create_with_utf8_cstring (message);
5408 if (message_string == NULL)
5409 err = memFullErr;
5410 else
5412 ControlFontStyleRec text_style;
5414 text_style.flags = 0;
5415 SetRect (&bounds, 0, 0, inner_width, 0);
5416 err = CreateStaticTextControl (window, &bounds, message_string,
5417 &text_style, &text);
5418 CFRelease (message_string);
5420 if (err == noErr)
5422 SInt16 unused;
5424 bounds = empty_rect;
5425 err = GetBestControlRect (text, &bounds, &unused);
5427 if (err == noErr)
5429 text_height = bounds.bottom - bounds.top;
5430 if (text_height < DIALOG_TEXT_MIN_HEIGHT)
5431 text_height = DIALOG_TEXT_MIN_HEIGHT;
5435 /* Place buttons. */
5436 if (err == noErr)
5438 inner_height = (text_height + DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
5439 + buttons_height);
5441 for (i = 0; i < nb_buttons; i++)
5443 OffsetRect (&rects[i], DIALOG_LEFT_MARGIN + inner_width,
5444 DIALOG_TOP_MARGIN + inner_height);
5445 SetControlBounds (buttons[i], &rects[i]);
5449 /* Place text. */
5450 if (err == noErr)
5452 Rect bounds;
5454 SetRect (&bounds, DIALOG_LEFT_MARGIN, DIALOG_TOP_MARGIN,
5455 DIALOG_LEFT_MARGIN + inner_width,
5456 DIALOG_TOP_MARGIN + text_height);
5457 SetControlBounds (text, &bounds);
5460 /* Create the application icon at the upper-left corner. */
5461 if (err == noErr)
5463 ControlButtonContentInfo content;
5464 ControlRef icon;
5465 static const ProcessSerialNumber psn = {0, kCurrentProcess};
5466 #ifdef MAC_OSX
5467 FSRef app_location;
5468 #else
5469 ProcessInfoRec pinfo;
5470 FSSpec app_spec;
5471 #endif
5472 SInt16 unused;
5474 content.contentType = kControlContentIconRef;
5475 #ifdef MAC_OSX
5476 err = GetProcessBundleLocation (&psn, &app_location);
5477 if (err == noErr)
5478 err = GetIconRefFromFileInfo (&app_location, 0, NULL, 0, NULL,
5479 kIconServicesNormalUsageFlag,
5480 &content.u.iconRef, &unused);
5481 #else
5482 bzero (&pinfo, sizeof (ProcessInfoRec));
5483 pinfo.processInfoLength = sizeof (ProcessInfoRec);
5484 pinfo.processAppSpec = &app_spec;
5485 err = GetProcessInformation (&psn, &pinfo);
5486 if (err == noErr)
5487 err = GetIconRefFromFile (&app_spec, &content.u.iconRef, &unused);
5488 #endif
5489 if (err == noErr)
5491 Rect bounds;
5493 SetRect (&bounds, DIALOG_ICON_LEFT_MARGIN, DIALOG_ICON_TOP_MARGIN,
5494 DIALOG_ICON_LEFT_MARGIN + DIALOG_ICON_WIDTH,
5495 DIALOG_ICON_TOP_MARGIN + DIALOG_ICON_HEIGHT);
5496 err = CreateIconControl (window, &bounds, &content, true, &icon);
5497 ReleaseIconRef (content.u.iconRef);
5501 /* Show the dialog window and run event loop. */
5502 if (err == noErr)
5503 if (default_button)
5504 err = SetWindowDefaultButton (window, default_button);
5505 if (err == noErr)
5506 err = install_dialog_event_handler (window);
5507 if (err == noErr)
5509 SizeWindow (window,
5510 DIALOG_LEFT_MARGIN + inner_width + DIALOG_RIGHT_MARGIN,
5511 DIALOG_TOP_MARGIN + inner_height + DIALOG_BOTTOM_MARGIN,
5512 true);
5513 err = RepositionWindow (window, FRAME_MAC_WINDOW (f),
5514 kWindowAlertPositionOnParentWindow);
5516 if (err == noErr)
5518 SetWRefCon (window, 0);
5519 ShowWindow (window);
5520 BringToFront (window);
5521 popup_activated_flag = 1;
5522 err = BeginAppModalStateForWindow (window);
5524 if (err == noErr)
5526 EventTargetRef toolbox_dispatcher = GetEventDispatcherTarget ();
5528 quit_dialog_event_loop = 0;
5529 while (1)
5531 EMACS_TIME next_time = timer_check (1);
5532 long secs = EMACS_SECS (next_time);
5533 long usecs = EMACS_USECS (next_time);
5534 EventTimeout timeout;
5535 EventRef event;
5537 if (secs < 0 || (secs == 0 && usecs == 0))
5539 /* Sometimes timer_check returns -1 (no timers) even if
5540 there are timers. So do a timeout anyway. */
5541 secs = 1;
5542 usecs = 0;
5545 timeout = (secs * kEventDurationSecond
5546 + usecs * kEventDurationMicrosecond);
5547 err = ReceiveNextEvent (0, NULL, timeout, kEventRemoveFromQueue,
5548 &event);
5549 if (err == noErr)
5551 SendEventToEventTarget (event, toolbox_dispatcher);
5552 ReleaseEvent (event);
5554 #if 0 /* defined (MAC_OSX) */
5555 else if (err != eventLoopTimedOutErr)
5557 if (err == eventLoopQuitErr)
5558 err = noErr;
5559 break;
5561 #else
5562 /* The return value of ReceiveNextEvent seems to be
5563 unreliable. Use our own global variable instead. */
5564 if (quit_dialog_event_loop)
5566 err = noErr;
5567 break;
5569 #endif
5572 if (err == noErr)
5574 UInt32 command_id = GetWRefCon (window);
5576 if (DIALOG_BUTTON_COMMAND_ID_P (command_id))
5577 result = DIALOG_BUTTON_COMMAND_ID_VALUE (command_id);
5580 unbind_to (specpdl_count, Qnil);
5582 menu_item_selection = result;
5584 #else /* not TARGET_API_MAC_CARBON */
5585 #define DIALOG_WINDOW_RESOURCE 130
5588 mac_dialog (widget_value *wv)
5590 char *dialog_name;
5591 char *prompt;
5592 char **button_labels;
5593 UInt32 *ref_cons;
5594 int nb_buttons;
5595 int left_count;
5596 int i;
5597 int dialog_width;
5598 Rect rect;
5599 WindowRef window_ptr;
5600 ControlRef ch;
5601 int left;
5602 EventRecord event_record;
5603 SInt16 part_code;
5604 int control_part_code;
5605 Point mouse;
5607 dialog_name = wv->name;
5608 nb_buttons = dialog_name[1] - '0';
5609 left_count = nb_buttons - (dialog_name[4] - '0');
5610 button_labels = (char **) alloca (sizeof (char *) * nb_buttons);
5611 ref_cons = (UInt32 *) alloca (sizeof (UInt32) * nb_buttons);
5613 wv = wv->contents;
5614 prompt = (char *) alloca (strlen (wv->value) + 1);
5615 strcpy (prompt, wv->value);
5616 c2pstr (prompt);
5618 wv = wv->next;
5619 for (i = 0; i < nb_buttons; i++)
5621 button_labels[i] = wv->value;
5622 button_labels[i] = (char *) alloca (strlen (wv->value) + 1);
5623 strcpy (button_labels[i], wv->value);
5624 c2pstr (button_labels[i]);
5625 ref_cons[i] = (UInt32) wv->call_data;
5626 wv = wv->next;
5629 window_ptr = GetNewCWindow (DIALOG_WINDOW_RESOURCE, NULL, (WindowRef) -1);
5631 SetPortWindowPort (window_ptr);
5633 TextFont (0);
5634 /* Left and right margins in the dialog are 13 pixels each.*/
5635 dialog_width = 14;
5636 /* Calculate width of dialog box: 8 pixels on each side of the text
5637 label in each button, 12 pixels between buttons. */
5638 for (i = 0; i < nb_buttons; i++)
5639 dialog_width += StringWidth (button_labels[i]) + 16 + 12;
5641 if (left_count != 0 && nb_buttons - left_count != 0)
5642 dialog_width += 12;
5644 dialog_width = max (dialog_width, StringWidth (prompt) + 26);
5646 SizeWindow (window_ptr, dialog_width, 78, 0);
5647 ShowWindow (window_ptr);
5649 SetPortWindowPort (window_ptr);
5651 TextFont (0);
5653 MoveTo (13, 29);
5654 DrawString (prompt);
5656 left = 13;
5657 for (i = 0; i < nb_buttons; i++)
5659 int button_width = StringWidth (button_labels[i]) + 16;
5660 SetRect (&rect, left, 45, left + button_width, 65);
5661 ch = NewControl (window_ptr, &rect, button_labels[i], 1, 0, 0, 0,
5662 kControlPushButtonProc, ref_cons[i]);
5663 left += button_width + 12;
5664 if (i == left_count - 1)
5665 left += 12;
5668 i = 0;
5669 while (!i)
5671 if (WaitNextEvent (mDownMask, &event_record, 10, NULL))
5672 if (event_record.what == mouseDown)
5674 part_code = FindWindow (event_record.where, &window_ptr);
5675 if (part_code == inContent)
5677 mouse = event_record.where;
5678 GlobalToLocal (&mouse);
5679 control_part_code = FindControl (mouse, window_ptr, &ch);
5680 if (control_part_code == kControlButtonPart)
5681 if (TrackControl (ch, mouse, NULL))
5682 i = GetControlReference (ch);
5687 DisposeWindow (window_ptr);
5689 return i;
5691 #endif /* not TARGET_API_MAC_CARBON */
5694 /***********************************************************************
5695 Selection support
5696 ***********************************************************************/
5698 #if !TARGET_API_MAC_CARBON
5699 #include <Scrap.h>
5700 #include <Endian.h>
5701 #endif
5703 extern Lisp_Object Vselection_converter_alist;
5704 extern Lisp_Object Qmac_scrap_name, Qmac_ostype;
5706 static ScrapFlavorType get_flavor_type_from_symbol P_ ((Lisp_Object,
5707 Selection));
5709 /* Get a reference to the selection corresponding to the symbol SYM.
5710 The reference is set to *SEL, and it becomes NULL if there's no
5711 corresponding selection. Clear the selection if CLEAR_P is
5712 non-zero. */
5714 OSStatus
5715 mac_get_selection_from_symbol (sym, clear_p, sel)
5716 Lisp_Object sym;
5717 int clear_p;
5718 Selection *sel;
5720 OSStatus err = noErr;
5721 Lisp_Object str = Fget (sym, Qmac_scrap_name);
5723 if (!STRINGP (str))
5724 *sel = NULL;
5725 else
5727 #if TARGET_API_MAC_CARBON
5728 #ifdef MAC_OSX
5729 CFStringRef scrap_name = cfstring_create_with_string (str);
5730 OptionBits options = (clear_p ? kScrapClearNamedScrap
5731 : kScrapGetNamedScrap);
5733 err = GetScrapByName (scrap_name, options, sel);
5734 CFRelease (scrap_name);
5735 #else /* !MAC_OSX */
5736 if (clear_p)
5737 err = ClearCurrentScrap ();
5738 if (err == noErr)
5739 err = GetCurrentScrap (sel);
5740 #endif /* !MAC_OSX */
5741 #else /* !TARGET_API_MAC_CARBON */
5742 if (clear_p)
5743 err = ZeroScrap ();
5744 if (err == noErr)
5745 *sel = 1;
5746 #endif /* !TARGET_API_MAC_CARBON */
5749 return err;
5752 /* Get a scrap flavor type from the symbol SYM. Return 0 if no
5753 corresponding flavor type. If SEL is non-zero, the return value is
5754 non-zero only when the SEL has the flavor type. */
5756 static ScrapFlavorType
5757 get_flavor_type_from_symbol (sym, sel)
5758 Lisp_Object sym;
5759 Selection sel;
5761 Lisp_Object str = Fget (sym, Qmac_ostype);
5762 ScrapFlavorType flavor_type;
5764 if (STRINGP (str) && SBYTES (str) == 4)
5765 flavor_type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
5766 else
5767 flavor_type = 0;
5769 if (flavor_type && sel)
5771 #if TARGET_API_MAC_CARBON
5772 OSStatus err;
5773 ScrapFlavorFlags flags;
5775 err = GetScrapFlavorFlags (sel, flavor_type, &flags);
5776 if (err != noErr)
5777 flavor_type = 0;
5778 #else /* !TARGET_API_MAC_CARBON */
5779 SInt32 size, offset;
5781 size = GetScrap (NULL, flavor_type, &offset);
5782 if (size < 0)
5783 flavor_type = 0;
5784 #endif /* !TARGET_API_MAC_CARBON */
5787 return flavor_type;
5790 /* Check if the symbol SYM has a corresponding selection target type. */
5793 mac_valid_selection_target_p (sym)
5794 Lisp_Object sym;
5796 return get_flavor_type_from_symbol (sym, 0) != 0;
5799 /* Clear the selection whose reference is *SEL. */
5801 OSStatus
5802 mac_clear_selection (sel)
5803 Selection *sel;
5805 #if TARGET_API_MAC_CARBON
5806 #ifdef MAC_OSX
5807 return ClearScrap (sel);
5808 #else
5809 OSStatus err;
5811 err = ClearCurrentScrap ();
5812 if (err == noErr)
5813 err = GetCurrentScrap (sel);
5814 return err;
5815 #endif
5816 #else /* !TARGET_API_MAC_CARBON */
5817 return ZeroScrap ();
5818 #endif /* !TARGET_API_MAC_CARBON */
5821 /* Get ownership information for SEL. Emacs can detect a change of
5822 the ownership by comparing saved and current values of the
5823 ownership information. */
5825 Lisp_Object
5826 mac_get_selection_ownership_info (sel)
5827 Selection sel;
5829 #if TARGET_API_MAC_CARBON
5830 return long_to_cons ((unsigned long) sel);
5831 #else /* !TARGET_API_MAC_CARBON */
5832 ScrapStuffPtr scrap_info = InfoScrap ();
5834 return make_number (scrap_info->scrapCount);
5835 #endif /* !TARGET_API_MAC_CARBON */
5838 /* Return non-zero if VALUE is a valid selection value for TARGET. */
5841 mac_valid_selection_value_p (value, target)
5842 Lisp_Object value, target;
5844 return STRINGP (value);
5847 /* Put Lisp object VALUE to the selection SEL. The target type is
5848 specified by TARGET. */
5850 OSStatus
5851 mac_put_selection_value (sel, target, value)
5852 Selection sel;
5853 Lisp_Object target, value;
5855 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, 0);
5857 if (flavor_type == 0 || !STRINGP (value))
5858 return noTypeErr;
5860 #if TARGET_API_MAC_CARBON
5861 return PutScrapFlavor (sel, flavor_type, kScrapFlavorMaskNone,
5862 SBYTES (value), SDATA (value));
5863 #else /* !TARGET_API_MAC_CARBON */
5864 return PutScrap (SBYTES (value), flavor_type, SDATA (value));
5865 #endif /* !TARGET_API_MAC_CARBON */
5868 /* Check if data for the target type TARGET is available in SEL. */
5871 mac_selection_has_target_p (sel, target)
5872 Selection sel;
5873 Lisp_Object target;
5875 return get_flavor_type_from_symbol (target, sel) != 0;
5878 /* Get data for the target type TARGET from SEL and create a Lisp
5879 string. Return nil if failed to get data. */
5881 Lisp_Object
5882 mac_get_selection_value (sel, target)
5883 Selection sel;
5884 Lisp_Object target;
5886 OSStatus err;
5887 Lisp_Object result = Qnil;
5888 ScrapFlavorType flavor_type = get_flavor_type_from_symbol (target, sel);
5889 #if TARGET_API_MAC_CARBON
5890 Size size;
5892 if (flavor_type)
5894 err = GetScrapFlavorSize (sel, flavor_type, &size);
5895 if (err == noErr)
5899 result = make_uninit_string (size);
5900 err = GetScrapFlavorData (sel, flavor_type,
5901 &size, SDATA (result));
5902 if (err != noErr)
5903 result = Qnil;
5904 else if (size < SBYTES (result))
5905 result = make_unibyte_string (SDATA (result), size);
5907 while (STRINGP (result) && size > SBYTES (result));
5910 #else
5911 Handle handle;
5912 SInt32 size, offset;
5914 if (flavor_type)
5915 size = GetScrap (NULL, flavor_type, &offset);
5916 if (size >= 0)
5918 handle = NewHandle (size);
5919 HLock (handle);
5920 size = GetScrap (handle, flavor_type, &offset);
5921 if (size >= 0)
5922 result = make_unibyte_string (*handle, size);
5923 DisposeHandle (handle);
5925 #endif
5927 return result;
5930 /* Get the list of target types in SEL. The return value is a list of
5931 target type symbols possibly followed by scrap flavor type
5932 strings. */
5934 Lisp_Object
5935 mac_get_selection_target_list (sel)
5936 Selection sel;
5938 Lisp_Object result = Qnil, rest, target;
5939 #if TARGET_API_MAC_CARBON
5940 OSStatus err;
5941 UInt32 count, i, type;
5942 ScrapFlavorInfo *flavor_info = NULL;
5943 Lisp_Object strings = Qnil;
5945 err = GetScrapFlavorCount (sel, &count);
5946 if (err == noErr)
5947 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
5948 err = GetScrapFlavorInfoList (sel, &count, flavor_info);
5949 if (err != noErr)
5951 xfree (flavor_info);
5952 flavor_info = NULL;
5954 if (flavor_info == NULL)
5955 count = 0;
5956 #endif
5957 for (rest = Vselection_converter_alist; CONSP (rest); rest = XCDR (rest))
5959 ScrapFlavorType flavor_type = 0;
5961 if (CONSP (XCAR (rest))
5962 && (target = XCAR (XCAR (rest)),
5963 SYMBOLP (target))
5964 && (flavor_type = get_flavor_type_from_symbol (target, sel)))
5966 result = Fcons (target, result);
5967 #if TARGET_API_MAC_CARBON
5968 for (i = 0; i < count; i++)
5969 if (flavor_info[i].flavorType == flavor_type)
5971 flavor_info[i].flavorType = 0;
5972 break;
5974 #endif
5977 #if TARGET_API_MAC_CARBON
5978 if (flavor_info)
5980 for (i = 0; i < count; i++)
5981 if (flavor_info[i].flavorType)
5983 type = EndianU32_NtoB (flavor_info[i].flavorType);
5984 strings = Fcons (make_unibyte_string ((char *) &type, 4), strings);
5986 result = nconc2 (result, strings);
5987 xfree (flavor_info);
5989 #endif
5991 return result;
5995 /***********************************************************************
5996 Apple event support
5997 ***********************************************************************/
5999 extern pascal OSErr mac_handle_apple_event P_ ((const AppleEvent *,
6000 AppleEvent *, SInt32));
6001 extern void cleanup_all_suspended_apple_events P_ ((void));
6003 void
6004 init_apple_event_handler ()
6006 OSErr err;
6007 long result;
6009 /* Make sure we have Apple events before starting. */
6010 err = Gestalt (gestaltAppleEventsAttr, &result);
6011 if (err != noErr)
6012 abort ();
6014 if (!(result & (1 << gestaltAppleEventsPresent)))
6015 abort ();
6017 err = AEInstallEventHandler (typeWildCard, typeWildCard,
6018 #if TARGET_API_MAC_CARBON
6019 NewAEEventHandlerUPP (mac_handle_apple_event),
6020 #else
6021 NewAEEventHandlerProc (mac_handle_apple_event),
6022 #endif
6023 0L, false);
6024 if (err != noErr)
6025 abort ();
6027 atexit (cleanup_all_suspended_apple_events);
6031 /***********************************************************************
6032 Drag and drop support
6033 ***********************************************************************/
6035 #if TARGET_API_MAC_CARBON
6036 extern Lisp_Object Vmac_dnd_known_types;
6038 static pascal OSErr mac_do_track_drag P_ ((DragTrackingMessage, WindowRef,
6039 void *, DragRef));
6040 static pascal OSErr mac_do_receive_drag P_ ((WindowRef, void *, DragRef));
6041 static DragTrackingHandlerUPP mac_do_track_dragUPP = NULL;
6042 static DragReceiveHandlerUPP mac_do_receive_dragUPP = NULL;
6044 static OSErr
6045 create_apple_event_from_drag_ref (drag, num_types, types, result)
6046 DragRef drag;
6047 UInt32 num_types;
6048 const FlavorType *types;
6049 AppleEvent *result;
6051 OSErr err;
6052 UInt16 num_items;
6053 AppleEvent items;
6054 long index;
6055 char *buf = NULL;
6057 err = CountDragItems (drag, &num_items);
6058 if (err != noErr)
6059 return err;
6060 err = AECreateList (NULL, 0, false, &items);
6061 if (err != noErr)
6062 return err;
6064 for (index = 1; index <= num_items; index++)
6066 ItemReference item;
6067 DescType desc_type = typeNull;
6068 Size size;
6070 err = GetDragItemReferenceNumber (drag, index, &item);
6071 if (err == noErr)
6073 int i;
6075 for (i = 0; i < num_types; i++)
6077 err = GetFlavorDataSize (drag, item, types[i], &size);
6078 if (err == noErr)
6080 buf = xrealloc (buf, size);
6081 err = GetFlavorData (drag, item, types[i], buf, &size, 0);
6083 if (err == noErr)
6085 desc_type = types[i];
6086 break;
6090 err = AEPutPtr (&items, index, desc_type,
6091 desc_type != typeNull ? buf : NULL,
6092 desc_type != typeNull ? size : 0);
6093 if (err != noErr)
6094 break;
6096 if (buf)
6097 xfree (buf);
6099 if (err == noErr)
6101 err = create_apple_event (0, 0, result); /* Dummy class and ID. */
6102 if (err == noErr)
6103 err = AEPutParamDesc (result, keyDirectObject, &items);
6104 if (err != noErr)
6105 AEDisposeDesc (result);
6108 AEDisposeDesc (&items);
6110 return err;
6113 static void
6114 mac_store_drag_event (window, mouse_pos, modifiers, desc)
6115 WindowRef window;
6116 Point mouse_pos;
6117 SInt16 modifiers;
6118 const AEDesc *desc;
6120 struct input_event buf;
6122 EVENT_INIT (buf);
6124 buf.kind = DRAG_N_DROP_EVENT;
6125 buf.modifiers = mac_to_emacs_modifiers (modifiers, 0);
6126 buf.timestamp = TickCount () * (1000 / 60);
6127 XSETINT (buf.x, mouse_pos.h);
6128 XSETINT (buf.y, mouse_pos.v);
6129 XSETFRAME (buf.frame_or_window, mac_window_to_frame (window));
6130 buf.arg = mac_aedesc_to_lisp (desc);
6131 kbd_buffer_store_event (&buf);
6134 static pascal OSErr
6135 mac_do_track_drag (message, window, refcon, drag)
6136 DragTrackingMessage message;
6137 WindowRef window;
6138 void *refcon;
6139 DragRef drag;
6141 OSErr err = noErr;
6142 static int can_accept;
6143 UInt16 num_items, index;
6145 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
6146 return dragNotAcceptedErr;
6148 switch (message)
6150 case kDragTrackingEnterHandler:
6151 err = CountDragItems (drag, &num_items);
6152 if (err != noErr)
6153 break;
6154 can_accept = 0;
6155 for (index = 1; index <= num_items; index++)
6157 ItemReference item;
6158 FlavorFlags flags;
6159 Lisp_Object rest;
6161 err = GetDragItemReferenceNumber (drag, index, &item);
6162 if (err != noErr)
6163 continue;
6164 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
6166 Lisp_Object str;
6167 FlavorType type;
6169 str = XCAR (rest);
6170 if (!(STRINGP (str) && SBYTES (str) == 4))
6171 continue;
6172 type = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
6174 err = GetFlavorFlags (drag, item, type, &flags);
6175 if (err == noErr)
6177 can_accept = 1;
6178 break;
6182 break;
6184 case kDragTrackingEnterWindow:
6185 if (can_accept)
6187 RgnHandle hilite_rgn = NewRgn ();
6189 if (hilite_rgn)
6191 Rect r;
6193 GetWindowPortBounds (window, &r);
6194 OffsetRect (&r, -r.left, -r.top);
6195 RectRgn (hilite_rgn, &r);
6196 ShowDragHilite (drag, hilite_rgn, true);
6197 DisposeRgn (hilite_rgn);
6199 SetThemeCursor (kThemeCopyArrowCursor);
6201 break;
6203 case kDragTrackingInWindow:
6204 break;
6206 case kDragTrackingLeaveWindow:
6207 if (can_accept)
6209 HideDragHilite (drag);
6210 SetThemeCursor (kThemeArrowCursor);
6212 break;
6214 case kDragTrackingLeaveHandler:
6215 break;
6218 if (err != noErr)
6219 return dragNotAcceptedErr;
6220 return noErr;
6223 static pascal OSErr
6224 mac_do_receive_drag (window, refcon, drag)
6225 WindowRef window;
6226 void *refcon;
6227 DragRef drag;
6229 OSErr err;
6230 int num_types, i;
6231 Lisp_Object rest, str;
6232 FlavorType *types;
6233 AppleEvent apple_event;
6234 Point mouse_pos;
6235 SInt16 modifiers;
6237 if (GetFrontWindowOfClass (kMovableModalWindowClass, false))
6238 return dragNotAcceptedErr;
6240 num_types = 0;
6241 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
6243 str = XCAR (rest);
6244 if (STRINGP (str) && SBYTES (str) == 4)
6245 num_types++;
6248 types = xmalloc (sizeof (FlavorType) * num_types);
6249 i = 0;
6250 for (rest = Vmac_dnd_known_types; CONSP (rest); rest = XCDR (rest))
6252 str = XCAR (rest);
6253 if (STRINGP (str) && SBYTES (str) == 4)
6254 types[i++] = EndianU32_BtoN (*((UInt32 *) SDATA (str)));
6257 err = create_apple_event_from_drag_ref (drag, num_types, types,
6258 &apple_event);
6259 xfree (types);
6261 if (err == noErr)
6262 err = GetDragMouse (drag, &mouse_pos, NULL);
6263 if (err == noErr)
6265 GlobalToLocal (&mouse_pos);
6266 err = GetDragModifiers (drag, NULL, NULL, &modifiers);
6268 if (err == noErr)
6270 UInt32 key_modifiers = modifiers;
6272 err = AEPutParamPtr (&apple_event, kEventParamKeyModifiers,
6273 typeUInt32, &key_modifiers, sizeof (UInt32));
6276 if (err == noErr)
6278 mac_store_drag_event (window, mouse_pos, 0, &apple_event);
6279 AEDisposeDesc (&apple_event);
6280 mac_wakeup_from_rne ();
6281 return noErr;
6283 else
6284 return dragNotAcceptedErr;
6286 #endif /* TARGET_API_MAC_CARBON */
6288 static OSErr
6289 install_drag_handler (window)
6290 WindowRef window;
6292 OSErr err = noErr;
6294 #if TARGET_API_MAC_CARBON
6295 if (mac_do_track_dragUPP == NULL)
6296 mac_do_track_dragUPP = NewDragTrackingHandlerUPP (mac_do_track_drag);
6297 if (mac_do_receive_dragUPP == NULL)
6298 mac_do_receive_dragUPP = NewDragReceiveHandlerUPP (mac_do_receive_drag);
6300 err = InstallTrackingHandler (mac_do_track_dragUPP, window, NULL);
6301 if (err == noErr)
6302 err = InstallReceiveHandler (mac_do_receive_dragUPP, window, NULL);
6303 #endif
6305 return err;
6308 static void
6309 remove_drag_handler (window)
6310 WindowRef window;
6312 #if TARGET_API_MAC_CARBON
6313 if (mac_do_track_dragUPP)
6314 RemoveTrackingHandler (mac_do_track_dragUPP, window);
6315 if (mac_do_receive_dragUPP)
6316 RemoveReceiveHandler (mac_do_receive_dragUPP, window);
6317 #endif
6320 #if TARGET_API_MAC_CARBON
6321 /* Return default value for mac-dnd-known-types. */
6323 Lisp_Object
6324 mac_dnd_default_known_types ()
6326 Lisp_Object result = list4 (build_string ("hfs "), build_string ("utxt"),
6327 build_string ("TEXT"), build_string ("TIFF"));
6329 #ifdef MAC_OSX
6330 result = Fcons (build_string ("furl"), result);
6331 #endif
6333 return result;
6335 #endif
6338 /***********************************************************************
6339 Services menu support
6340 ***********************************************************************/
6342 #ifdef MAC_OSX
6343 extern Lisp_Object Qservice, Qpaste, Qperform;
6344 extern Lisp_Object Vmac_service_selection;
6346 static OSStatus
6347 mac_store_service_event (event)
6348 EventRef event;
6350 OSStatus err;
6351 Lisp_Object id_key;
6352 int num_params;
6353 const EventParamName *names;
6354 const EventParamType *types;
6355 static const EventParamName names_pfm[] =
6356 {kEventParamServiceMessageName, kEventParamServiceUserData};
6357 static const EventParamType types_pfm[] =
6358 {typeCFStringRef, typeCFStringRef};
6360 switch (GetEventKind (event))
6362 case kEventServicePaste:
6363 id_key = Qpaste;
6364 num_params = 0;
6365 names = NULL;
6366 types = NULL;
6367 break;
6369 case kEventServicePerform:
6370 id_key = Qperform;
6371 num_params = sizeof (names_pfm) / sizeof (names_pfm[0]);
6372 names = names_pfm;
6373 types = types_pfm;
6374 break;
6376 default:
6377 abort ();
6380 err = mac_store_event_ref_as_apple_event (0, 0, Qservice, id_key,
6381 event, num_params,
6382 names, types);
6384 return err;
6387 static OSStatus
6388 copy_scrap_flavor_data (from_scrap, to_scrap, flavor_type)
6389 ScrapRef from_scrap, to_scrap;
6390 ScrapFlavorType flavor_type;
6392 OSStatus err;
6393 Size size, size_allocated;
6394 char *buf = NULL;
6396 err = GetScrapFlavorSize (from_scrap, flavor_type, &size);
6397 if (err == noErr)
6398 buf = xmalloc (size);
6399 while (buf)
6401 size_allocated = size;
6402 err = GetScrapFlavorData (from_scrap, flavor_type, &size, buf);
6403 if (err != noErr)
6405 xfree (buf);
6406 buf = NULL;
6408 else if (size_allocated < size)
6409 buf = xrealloc (buf, size);
6410 else
6411 break;
6413 if (err == noErr)
6415 if (buf == NULL)
6416 err = memFullErr;
6417 else
6419 err = PutScrapFlavor (to_scrap, flavor_type, kScrapFlavorMaskNone,
6420 size, buf);
6421 xfree (buf);
6425 return err;
6428 static OSStatus
6429 mac_handle_service_event (call_ref, event, data)
6430 EventHandlerCallRef call_ref;
6431 EventRef event;
6432 void *data;
6434 OSStatus err = noErr;
6435 ScrapRef cur_scrap, specific_scrap;
6436 UInt32 event_kind = GetEventKind (event);
6437 CFMutableArrayRef copy_types, paste_types;
6438 CFStringRef type;
6439 Lisp_Object rest;
6440 ScrapFlavorType flavor_type;
6442 /* Check if Vmac_service_selection is a valid selection that has a
6443 corresponding scrap. */
6444 if (!SYMBOLP (Vmac_service_selection))
6445 err = eventNotHandledErr;
6446 else
6447 err = mac_get_selection_from_symbol (Vmac_service_selection, 0, &cur_scrap);
6448 if (!(err == noErr && cur_scrap))
6449 return eventNotHandledErr;
6451 switch (event_kind)
6453 case kEventServiceGetTypes:
6454 /* Set paste types. */
6455 err = GetEventParameter (event, kEventParamServicePasteTypes,
6456 typeCFMutableArrayRef, NULL,
6457 sizeof (CFMutableArrayRef), NULL,
6458 &paste_types);
6459 if (err != noErr)
6460 break;
6462 for (rest = Vselection_converter_alist; CONSP (rest);
6463 rest = XCDR (rest))
6464 if (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))
6465 && (flavor_type =
6466 get_flavor_type_from_symbol (XCAR (XCAR (rest)), 0)))
6468 type = CreateTypeStringWithOSType (flavor_type);
6469 if (type)
6471 CFArrayAppendValue (paste_types, type);
6472 CFRelease (type);
6476 /* Set copy types. */
6477 err = GetEventParameter (event, kEventParamServiceCopyTypes,
6478 typeCFMutableArrayRef, NULL,
6479 sizeof (CFMutableArrayRef), NULL,
6480 &copy_types);
6481 if (err != noErr)
6482 break;
6484 if (NILP (Fx_selection_owner_p (Vmac_service_selection)))
6485 break;
6486 else
6487 goto copy_all_flavors;
6489 case kEventServiceCopy:
6490 err = GetEventParameter (event, kEventParamScrapRef,
6491 typeScrapRef, NULL,
6492 sizeof (ScrapRef), NULL, &specific_scrap);
6493 if (err != noErr
6494 || NILP (Fx_selection_owner_p (Vmac_service_selection)))
6496 err = eventNotHandledErr;
6497 break;
6500 copy_all_flavors:
6502 UInt32 count, i;
6503 ScrapFlavorInfo *flavor_info = NULL;
6504 ScrapFlavorFlags flags;
6506 err = GetScrapFlavorCount (cur_scrap, &count);
6507 if (err == noErr)
6508 flavor_info = xmalloc (sizeof (ScrapFlavorInfo) * count);
6509 err = GetScrapFlavorInfoList (cur_scrap, &count, flavor_info);
6510 if (err != noErr)
6512 xfree (flavor_info);
6513 flavor_info = NULL;
6515 if (flavor_info == NULL)
6516 break;
6518 for (i = 0; i < count; i++)
6520 flavor_type = flavor_info[i].flavorType;
6521 err = GetScrapFlavorFlags (cur_scrap, flavor_type, &flags);
6522 if (err == noErr && !(flags & kScrapFlavorMaskSenderOnly))
6524 if (event_kind == kEventServiceCopy)
6525 err = copy_scrap_flavor_data (cur_scrap, specific_scrap,
6526 flavor_type);
6527 else /* event_kind == kEventServiceGetTypes */
6529 type = CreateTypeStringWithOSType (flavor_type);
6530 if (type)
6532 CFArrayAppendValue (copy_types, type);
6533 CFRelease (type);
6538 xfree (flavor_info);
6540 break;
6542 case kEventServicePaste:
6543 case kEventServicePerform:
6545 int data_exists_p = 0;
6547 err = GetEventParameter (event, kEventParamScrapRef, typeScrapRef,
6548 NULL, sizeof (ScrapRef), NULL,
6549 &specific_scrap);
6550 if (err == noErr)
6551 err = mac_clear_selection (&cur_scrap);
6552 if (err == noErr)
6553 for (rest = Vselection_converter_alist; CONSP (rest);
6554 rest = XCDR (rest))
6556 if (! (CONSP (XCAR (rest)) && SYMBOLP (XCAR (XCAR (rest)))))
6557 continue;
6558 flavor_type = get_flavor_type_from_symbol (XCAR (XCAR (rest)),
6559 specific_scrap);
6560 if (flavor_type == 0)
6561 continue;
6562 err = copy_scrap_flavor_data (specific_scrap, cur_scrap,
6563 flavor_type);
6564 if (err == noErr)
6565 data_exists_p = 1;
6567 if (!data_exists_p)
6568 err = eventNotHandledErr;
6569 else
6570 err = mac_store_service_event (event);
6572 break;
6575 if (err != noErr)
6576 err = eventNotHandledErr;
6577 return err;
6580 static OSStatus
6581 install_service_handler ()
6583 static const EventTypeSpec specs[] =
6584 {{kEventClassService, kEventServiceGetTypes},
6585 {kEventClassService, kEventServiceCopy},
6586 {kEventClassService, kEventServicePaste},
6587 {kEventClassService, kEventServicePerform}};
6589 return InstallApplicationEventHandler (NewEventHandlerUPP
6590 (mac_handle_service_event),
6591 GetEventTypeCount (specs),
6592 specs, NULL, NULL);
6594 #endif /* MAC_OSX */
6597 /***********************************************************************
6598 Initialization
6599 ***********************************************************************/
6601 void
6602 mac_toolbox_initialize ()
6604 any_help_event_p = 0;
6606 init_menu_bar ();
6608 #ifdef MAC_OSX
6609 init_apple_event_handler ();
6610 #endif
6611 #if USE_MAC_TSM
6612 init_tsm ();
6613 #endif
6616 /* arch-tag: 71a597a8-6e9f-47b0-8b89-5a5ae3e16516
6617 (do not change this comment) */