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)
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. */
27 #include "blockinput.h"
31 #if !TARGET_API_MAC_CARBON
32 #include <Quickdraw.h>
33 #include <ToolUtils.h>
37 #include <Resources.h>
39 #include <TextUtils.h>
44 #if defined (__MRC__) || (__MSL__ >= 0x6000)
45 #include <ControlDefinitions.h>
51 #endif /* not TARGET_API_MAC_CARBON */
56 #include "dispextern.h"
58 #include "termhooks.h"
63 #include <sys/param.h>
70 /************************************************************************
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)
83 mac_alert_sound_play ()
85 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
93 /************************************************************************
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
));
104 extern int mac_to_emacs_modifiers
P_ ((EventModifiers
, EventModifiers
));
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
;
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
;
125 static int mac_event_to_emacs_modifiers
P_ ((EventRef
));
126 static OSStatus install_menu_target_item_handler
P_ ((void));
128 static OSStatus install_service_handler
P_ ((void));
131 extern OSStatus mac_store_event_ref_as_apple_event
P_ ((AEEventClass
, AEEventID
,
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
*));
147 extern OSStatus mac_restore_keyboard_input_source
P_ ((void));
148 extern void mac_save_keyboard_input_source
P_ ((void));
155 err
= ActivateTSMDocument (tsm_document_id
);
157 err
= mac_restore_keyboard_input_source ();
167 mac_save_keyboard_input_source ();
168 err
= DeactivateTSMDocument (tsm_document_id
);
177 static InterfaceTypeList types
= {kUnicodeDocument
};
179 static InterfaceTypeList types
= {kTextService
};
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
;
193 OSStatus err
, result
= eventNotHandledErr
;
194 UInt32 event_kind
, key_code
, modifiers
;
195 unsigned char char_code
;
197 event_kind
= GetEventKind (event
);
200 case kEventRawKeyDown
:
201 case kEventRawKeyRepeat
:
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
)
211 if (read_socket_inev
== NULL
)
215 if (read_socket_inev
->kind
!= NO_EVENT
)
222 if (event_kind
== kEventRawKeyUp
)
225 err
= GetEventParameter (event
, kEventParamKeyMacCharCodes
,
227 sizeof (char), NULL
, &char_code
);
231 err
= GetEventParameter (event
, kEventParamKeyCode
,
233 sizeof (UInt32
), NULL
, &key_code
);
237 err
= GetEventParameter (event
, kEventParamKeyModifiers
,
239 sizeof (UInt32
), NULL
, &modifiers
);
243 do_keystroke ((event_kind
== kEventRawKeyDown
? keyDown
: autoKey
),
244 char_code
, key_code
, modifiers
,
246 (GetEventTime (event
) / kEventDurationMillisecond
)),
258 static pascal OSStatus
259 mac_handle_command_event (next_handler
, event
, data
)
260 EventHandlerCallRef next_handler
;
264 OSStatus err
, result
= eventNotHandledErr
;
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
);
275 return eventNotHandledErr
;
277 switch (GetEventKind (event
))
279 case kEventCommandProcess
:
280 result
= CallNextEventHandler (next_handler
, event
);
281 if (result
!= eventNotHandledErr
)
284 err
= GetEventParameter (event
, kEventParamDirectObject
,
286 sizeof (HICommand
), NULL
, &command
);
288 if (err
!= noErr
|| command
.commandID
== 0)
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
294 err
= mac_store_event_ref_as_apple_event (0, command
.commandID
,
309 static pascal OSStatus
310 mac_handle_mouse_event (next_handler
, event
, data
)
311 EventHandlerCallRef next_handler
;
315 OSStatus err
, result
= eventNotHandledErr
;
317 switch (GetEventKind (event
))
319 case kEventMouseWheelMoved
:
323 EventMouseWheelAxis axis
;
327 result
= CallNextEventHandler (next_handler
, event
);
328 if (result
!= eventNotHandledErr
|| read_socket_inev
== NULL
)
331 f
= mac_focus_frame (&one_mac_display_info
);
333 err
= GetEventParameter (event
, kEventParamWindowRef
, typeWindowRef
,
334 NULL
, sizeof (WindowRef
), NULL
, &wp
);
336 || wp
!= FRAME_MAC_WINDOW (f
))
339 err
= GetEventParameter (event
, kEventParamMouseWheelAxis
,
340 typeMouseWheelAxis
, NULL
,
341 sizeof (EventMouseWheelAxis
), NULL
, &axis
);
342 if (err
!= noErr
|| axis
!= kEventMouseWheelAxisY
)
345 err
= GetEventParameter (event
, kEventParamMouseLocation
,
346 typeQDPoint
, NULL
, sizeof (Point
),
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),
358 err
= GetEventParameter (event
, kEventParamMouseWheelDelta
,
359 typeSInt32
, NULL
, sizeof (SInt32
),
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
);
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
;
395 OSStatus err
, result
;
396 Lisp_Object id_key
= Qnil
;
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
,
431 static const EventParamName names_ufke
[] =
432 {kEventParamTextInputSendComponentInstance
,
433 kEventParamTextInputSendRefCon
,
434 kEventParamTextInputSendSLRec
,
435 kEventParamTextInputSendText
};
436 static const EventParamType types_ufke
[] =
437 {typeComponentInstance
,
442 result
= CallNextEventHandler (next_handler
, event
);
443 if (result
!= eventNotHandledErr
)
446 switch (GetEventKind (event
))
448 case kEventTextInputUpdateActiveInputArea
:
449 id_key
= Qupdate_active_input_area
;
450 num_params
= sizeof (names_uaia
) / sizeof (names_uaia
[0]);
453 SetEventParameter (event
, EVENT_PARAM_TEXT_INPUT_SEQUENCE_NUMBER
,
454 typeUInt32
, sizeof (UInt32
), &seqno_uaia
);
459 case kEventTextInputUnicodeForKeyEvent
:
462 UInt32 actual_size
, modifiers
, key_code
;
464 err
= GetEventParameter (event
, kEventParamTextInputSendKeyboardEvent
,
465 typeEventRef
, NULL
, sizeof (EventRef
), NULL
,
468 err
= GetEventParameter (kbd_event
, kEventParamKeyModifiers
,
470 sizeof (UInt32
), NULL
, &modifiers
);
472 err
= GetEventParameter (kbd_event
, kEventParamKeyCode
,
473 typeUInt32
, NULL
, sizeof (UInt32
),
475 if (err
== noErr
&& mac_mapped_modifiers (modifiers
, key_code
))
476 /* There're mapped modifier keys. Process it in
480 err
= GetEventParameter (kbd_event
, kEventParamKeyUnicodes
,
481 typeUnicodeText
, NULL
, 0, &actual_size
,
483 if (err
== noErr
&& actual_size
== sizeof (UniChar
))
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
);
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]);
525 case kEventTextInputOffsetToPos
:
532 err
= GetEventParameter (event
, kEventParamTextInputSendTextOffset
,
533 typeLongInteger
, NULL
, sizeof (long), NULL
,
538 if (STRINGP (Vmac_ts_active_input_buf
)
539 && SBYTES (Vmac_ts_active_input_buf
) != 0)
541 if (!OVERLAYP (Vmac_ts_active_input_overlay
))
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
);
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
));
576 int hpos
, vpos
, x
, y
;
577 struct glyph_row
*row
;
581 f
= mac_focus_frame (&one_mac_display_info
);
582 w
= XWINDOW (f
->selected_window
);
583 b
= XBUFFER (w
->buffer
);
585 /* Are we in a window whose display is up to date?
586 And verify the buffer's text has not changed. */
587 if (!(EQ (w
->window_end_valid
, w
->buffer
)
588 && XINT (w
->last_modified
) == BUF_MODIFF (b
)
589 && XINT (w
->last_overlay_modified
) == BUF_OVERLAY_MODIFF (b
)))
592 mac_get_selected_range (w
, &sel_range
);
593 charpos
= (BUF_BEGV (b
) + sel_range
.location
594 + byte_offset
/ (long) sizeof (UniChar
));
596 if (!fast_find_position (w
, charpos
, &hpos
, &vpos
, &x
, &y
, Qnil
))
598 result
= errOffsetInvalid
;
602 row
= MATRIX_ROW (w
->current_matrix
, vpos
);
603 glyph
= row
->glyphs
[TEXT_AREA
] + hpos
;
604 if (glyph
->type
!= CHAR_GLYPH
|| glyph
->glyph_not_available_p
)
607 p
.h
= (WINDOW_TEXT_TO_FRAME_PIXEL_X (w
, x
)
608 + f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
));
609 p
.v
= (WINDOW_TO_FRAME_PIXEL_Y (w
, y
)
610 + row
->visible_height
611 + f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
));
613 face
= FACE_FROM_ID (f
, glyph
->face_id
);
614 if (face
&& face
->font
)
616 XFontStruct
*font
= face
->font
;
617 Fixed point_size
= Long2Fix (font
->mac_fontsize
);
618 short height
= row
->visible_height
;
619 short ascent
= row
->ascent
;
621 SetEventParameter (event
,
622 kEventParamTextInputReplyPointSize
,
623 typeFixed
, sizeof (Fixed
), &point_size
);
624 SetEventParameter (event
,
625 kEventParamTextInputReplyLineHeight
,
626 typeShortInteger
, sizeof (short), &height
);
627 SetEventParameter (event
,
628 kEventParamTextInputReplyLineAscent
,
629 typeShortInteger
, sizeof (short), &ascent
);
630 if (font
->mac_fontnum
!= -1)
636 err1
= FMGetFontFromFontFamilyInstance (font
->mac_fontnum
,
640 SetEventParameter (event
, kEventParamTextInputReplyFMFont
,
641 typeUInt32
, sizeof (UInt32
), &fm_font
);
644 long qd_font
= font
->mac_fontnum
;
646 SetEventParameter (event
, kEventParamTextInputReplyFont
,
647 typeLongInteger
, sizeof (long),
651 else if (font
->mac_style
)
656 err1
= ATSUGetAttribute (font
->mac_style
, kATSUFontTag
,
657 sizeof (ATSUFontID
), &font_id
,
660 SetEventParameter (event
, kEventParamTextInputReplyFMFont
,
661 typeUInt32
, sizeof (UInt32
), &font_id
);
669 err
= SetEventParameter (event
, kEventParamTextInputReplyPoint
,
670 typeQDPoint
, sizeof (Point
), &p
);
677 case kEventTextInputPosToOffset
:
680 Boolean leading_edge_p
= true;
684 enum window_part part
;
685 long region_class
= kTSMOutsideOfBody
, byte_offset
= 0;
687 err
= GetEventParameter (event
, kEventParamTextInputSendCurrentPoint
,
688 typeQDPoint
, NULL
, sizeof (Point
), NULL
,
693 GetEventParameter (event
, kEventParamTextInputReplyLeadingEdge
,
694 typeBoolean
, NULL
, sizeof (Boolean
), NULL
,
697 f
= mac_focus_frame (&one_mac_display_info
);
698 x
= point
.h
- (f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
));
699 y
= point
.v
- (f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
));
700 window
= window_from_coordinates (f
, x
, y
, &part
, 0, 0, 1);
701 if (WINDOWP (window
) && EQ (window
, f
->selected_window
))
706 /* Convert to window-relative pixel coordinates. */
707 w
= XWINDOW (window
);
708 frame_to_window_pixel_xy (w
, &x
, &y
);
710 /* Are we in a window whose display is up to date?
711 And verify the buffer's text has not changed. */
712 b
= XBUFFER (w
->buffer
);
714 && EQ (w
->window_end_valid
, w
->buffer
)
715 && XINT (w
->last_modified
) == BUF_MODIFF (b
)
716 && XINT (w
->last_overlay_modified
) == BUF_OVERLAY_MODIFF (b
))
718 int hpos
, vpos
, area
;
721 /* Find the glyph under X/Y. */
722 glyph
= x_y_to_hpos_vpos (w
, x
, y
, &hpos
, &vpos
, 0, 0, &area
);
724 if (glyph
!= NULL
&& area
== TEXT_AREA
)
726 byte_offset
= ((glyph
->charpos
- BUF_BEGV (b
))
728 region_class
= kTSMInsideOfBody
;
733 err
= SetEventParameter (event
, kEventParamTextInputReplyRegionClass
,
734 typeLongInteger
, sizeof (long),
737 err
= SetEventParameter (event
, kEventParamTextInputReplyTextOffset
,
738 typeLongInteger
, sizeof (long),
745 case kEventTextInputGetSelectedText
:
747 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
748 struct window
*w
= XWINDOW (f
->selected_window
);
749 struct buffer
*b
= XBUFFER (w
->buffer
);
752 UniChar
*characters
, c
;
754 if (poll_suppress_count
== 0 && !NILP (Vinhibit_quit
))
755 /* Don't try to get buffer contents as the gap might be
759 mac_get_selected_range (w
, &sel_range
);
760 if (sel_range
.length
== 0)
762 Boolean leading_edge_p
;
764 err
= GetEventParameter (event
,
765 kEventParamTextInputReplyLeadingEdge
,
766 typeBoolean
, NULL
, sizeof (Boolean
), NULL
,
771 start
= BUF_BEGV (b
) + sel_range
.location
;
777 if (start
< BUF_BEGV (b
) || end
> BUF_ZV (b
))
782 start
= BUF_BEGV (b
) + sel_range
.location
;
783 end
= start
+ sel_range
.length
;
784 characters
= xmalloc (sel_range
.length
* sizeof (UniChar
));
787 if (mac_store_buffer_text_to_unicode_chars (b
, start
, end
, characters
))
788 err
= SetEventParameter (event
, kEventParamTextInputReplyText
,
790 sel_range
.length
* sizeof (UniChar
),
792 if (characters
!= &c
)
806 err
= mac_store_event_ref_as_apple_event (0, 0, Qtext_input
, id_key
,
812 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
813 static pascal OSStatus
814 mac_handle_document_access_event (next_handler
, event
, data
)
815 EventHandlerCallRef next_handler
;
819 OSStatus err
, result
;
820 struct frame
*f
= mac_focus_frame (&one_mac_display_info
);
822 result
= CallNextEventHandler (next_handler
, event
);
823 if (result
!= eventNotHandledErr
)
826 switch (GetEventKind (event
))
828 case kEventTSMDocumentAccessGetLength
:
830 CFIndex count
= mac_ax_number_of_characters (f
);
832 err
= SetEventParameter (event
, kEventParamTSMDocAccessCharacterCount
,
833 typeCFIndex
, sizeof (CFIndex
), &count
);
839 case kEventTSMDocumentAccessGetSelectedRange
:
843 mac_ax_selected_text_range (f
, &sel_range
);
844 err
= SetEventParameter (event
,
845 kEventParamTSMDocAccessReplyCharacterRange
,
846 typeCFRange
, sizeof (CFRange
), &sel_range
);
852 case kEventTSMDocumentAccessGetCharacters
:
854 struct buffer
*b
= XBUFFER (XWINDOW (f
->selected_window
)->buffer
);
859 if (poll_suppress_count
== 0 && !NILP (Vinhibit_quit
))
860 /* Don't try to get buffer contents as the gap might be
864 err
= GetEventParameter (event
,
865 kEventParamTSMDocAccessSendCharacterRange
,
866 typeCFRange
, NULL
, sizeof (CFRange
), NULL
,
869 err
= GetEventParameter (event
,
870 kEventParamTSMDocAccessSendCharactersPtr
,
871 typePtr
, NULL
, sizeof (Ptr
), NULL
,
876 start
= BUF_BEGV (b
) + range
.location
;
877 end
= start
+ range
.length
;
878 if (mac_store_buffer_text_to_unicode_chars (b
, start
, end
,
879 (UniChar
*) characters
))
894 install_application_handler ()
896 OSStatus err
= noErr
;
900 static const EventTypeSpec specs
[] =
901 {{kEventClassKeyboard
, kEventRawKeyDown
},
902 {kEventClassKeyboard
, kEventRawKeyRepeat
},
903 {kEventClassKeyboard
, kEventRawKeyUp
}};
905 err
= InstallApplicationEventHandler (NewEventHandlerUPP
906 (mac_handle_keyboard_event
),
907 GetEventTypeCount (specs
),
913 static const EventTypeSpec specs
[] =
914 {{kEventClassCommand
, kEventCommandProcess
}};
916 err
= InstallApplicationEventHandler (NewEventHandlerUPP
917 (mac_handle_command_event
),
918 GetEventTypeCount (specs
),
924 static const EventTypeSpec specs
[] =
925 {{kEventClassMouse
, kEventMouseWheelMoved
}};
927 err
= InstallApplicationEventHandler (NewEventHandlerUPP
928 (mac_handle_mouse_event
),
929 GetEventTypeCount (specs
),
936 static const EventTypeSpec specs
[] =
937 {{kEventClassTextInput
, kEventTextInputUpdateActiveInputArea
},
938 {kEventClassTextInput
, kEventTextInputUnicodeForKeyEvent
},
939 {kEventClassTextInput
, kEventTextInputOffsetToPos
},
941 {kEventClassTextInput
, kEventTextInputPosToOffset
},
942 {kEventClassTextInput
, kEventTextInputGetSelectedText
}
946 err
= InstallApplicationEventHandler (NewEventHandlerUPP
947 (mac_handle_text_input_event
),
948 GetEventTypeCount (specs
),
952 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
955 static const EventTypeSpec specs
[] =
956 {{kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetLength
},
957 {kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetSelectedRange
},
958 {kEventClassTSMDocumentAccess
, kEventTSMDocumentAccessGetCharacters
}};
960 err
= InstallApplicationEventHandler (mac_handle_document_access_event
,
961 GetEventTypeCount (specs
),
968 err
= install_menu_target_item_handler ();
972 err
= install_service_handler ();
977 #endif /* TARGET_API_MAC_CARBON */
980 /************************************************************************
982 ************************************************************************/
984 #define DEFAULT_NUM_COLS 80
986 #define MIN_DOC_SIZE 64
987 #define MAX_DOC_SIZE 32767
990 static OSErr install_drag_handler
P_ ((WindowRef
));
991 static void remove_drag_handler
P_ ((WindowRef
));
994 static void mac_prepare_for_quickdraw
P_ ((struct frame
*));
997 extern void mac_handle_visibility_change
P_ ((struct frame
*));
998 extern void mac_handle_origin_change
P_ ((struct frame
*));
999 extern void mac_handle_size_change
P_ ((struct frame
*, int, int));
1001 #if TARGET_API_MAC_CARBON
1003 extern Lisp_Object Qwindow
;
1004 extern Lisp_Object Qtoolbar_switch_mode
;
1009 do_window_update (WindowRef win
)
1011 struct frame
*f
= mac_window_to_frame (win
);
1015 /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED
1017 if (win
!= tip_window
)
1019 if (f
->async_visible
== 0)
1021 /* Update events may occur when a frame gets iconified. */
1023 f
->async_visible
= 1;
1024 f
->async_iconified
= 0;
1025 SET_FRAME_GARBAGED (f
);
1031 #if TARGET_API_MAC_CARBON
1032 RgnHandle region
= NewRgn ();
1034 GetPortVisibleRegion (GetWindowPort (win
), region
);
1035 GetRegionBounds (region
, &r
);
1036 expose_frame (f
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);
1038 mac_prepare_for_quickdraw (f
);
1040 UpdateControls (win
, region
);
1041 DisposeRgn (region
);
1043 r
= (*win
->visRgn
)->rgnBBox
;
1044 expose_frame (f
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
);
1045 UpdateControls (win
, win
->visRgn
);
1054 is_emacs_window (WindowRef win
)
1056 Lisp_Object tail
, frame
;
1061 FOR_EACH_FRAME (tail
, frame
)
1062 if (FRAME_MAC_P (XFRAME (frame
)))
1063 if (FRAME_MAC_WINDOW (XFRAME (frame
)) == win
)
1069 /* Handle drags in size box. Based on code contributed by Ben
1070 Mesander and IM - Window Manager A. */
1073 do_grow_window (w
, e
)
1075 const EventRecord
*e
;
1078 int rows
, columns
, width
, height
;
1079 struct frame
*f
= mac_window_to_frame (w
);
1080 XSizeHints
*size_hints
= FRAME_SIZE_HINTS (f
);
1081 int min_width
= MIN_DOC_SIZE
, min_height
= MIN_DOC_SIZE
;
1082 #if TARGET_API_MAC_CARBON
1088 if (size_hints
->flags
& PMinSize
)
1090 min_width
= size_hints
->min_width
;
1091 min_height
= size_hints
->min_height
;
1093 SetRect (&limit_rect
, min_width
, min_height
, MAX_DOC_SIZE
, MAX_DOC_SIZE
);
1095 #if TARGET_API_MAC_CARBON
1096 if (!ResizeWindow (w
, e
->where
, &limit_rect
, &new_rect
))
1098 height
= new_rect
.bottom
- new_rect
.top
;
1099 width
= new_rect
.right
- new_rect
.left
;
1101 grow_size
= GrowWindow (w
, e
->where
, &limit_rect
);
1102 /* see if it really changed size */
1105 height
= HiWord (grow_size
);
1106 width
= LoWord (grow_size
);
1109 if (width
!= FRAME_PIXEL_WIDTH (f
)
1110 || height
!= FRAME_PIXEL_HEIGHT (f
))
1112 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, height
);
1113 columns
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, width
);
1115 x_set_window_size (f
, 0, columns
, rows
);
1119 #if TARGET_API_MAC_CARBON
1121 mac_get_ideal_size (f
)
1124 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
1125 WindowRef w
= FRAME_MAC_WINDOW (f
);
1128 int height
, width
, columns
, rows
;
1130 ideal_size
.h
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, DEFAULT_NUM_COLS
);
1131 ideal_size
.v
= dpyinfo
->height
;
1132 IsWindowInStandardState (w
, &ideal_size
, &standard_rect
);
1133 /* Adjust the standard size according to character boundaries. */
1134 width
= standard_rect
.right
- standard_rect
.left
;
1135 height
= standard_rect
.bottom
- standard_rect
.top
;
1136 columns
= FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f
, width
);
1137 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, height
);
1138 ideal_size
.h
= FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, columns
);
1139 ideal_size
.v
= FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, rows
);
1144 static pascal OSStatus
1145 mac_handle_window_event (next_handler
, event
, data
)
1146 EventHandlerCallRef next_handler
;
1151 OSStatus err
, result
= eventNotHandledErr
;
1154 XSizeHints
*size_hints
;
1156 err
= GetEventParameter (event
, kEventParamDirectObject
, typeWindowRef
,
1157 NULL
, sizeof (WindowRef
), NULL
, &wp
);
1159 return eventNotHandledErr
;
1161 f
= mac_window_to_frame (wp
);
1162 switch (GetEventKind (event
))
1164 /* -- window refresh events -- */
1166 case kEventWindowUpdate
:
1167 result
= CallNextEventHandler (next_handler
, event
);
1168 if (result
!= eventNotHandledErr
)
1171 do_window_update (wp
);
1175 /* -- window state change events -- */
1177 case kEventWindowShowing
:
1178 size_hints
= FRAME_SIZE_HINTS (f
);
1179 if (!(size_hints
->flags
& (USPosition
| PPosition
)))
1181 struct frame
*sf
= SELECTED_FRAME ();
1183 if (!(FRAME_MAC_P (sf
) && sf
->async_visible
))
1184 RepositionWindow (wp
, NULL
, kWindowCenterOnMainScreen
);
1187 RepositionWindow (wp
, FRAME_MAC_WINDOW (sf
),
1188 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1189 kWindowCascadeStartAtParentWindowScreen
1191 kWindowCascadeOnParentWindowScreen
1195 /* This is a workaround. RepositionWindow fails to put
1196 a window at the cascading position when its parent
1197 window has a Carbon HIToolbar. */
1198 if ((f
->left_pos
== sf
->left_pos
1199 && f
->top_pos
== sf
->top_pos
)
1200 || (f
->left_pos
== sf
->left_pos
+ 10 * 2
1201 && f
->top_pos
== sf
->top_pos
+ 32 * 2))
1202 MoveWindowStructure (wp
, sf
->left_pos
+ 10, sf
->top_pos
+ 32);
1209 case kEventWindowHiding
:
1210 /* Before unmapping the window, update the WM_SIZE_HINTS
1211 property to claim that the current position of the window is
1212 user-specified, rather than program-specified, so that when
1213 the window is mapped again, it will be placed at the same
1214 location, without forcing the user to position it by hand
1215 again (they have already done that once for this window.) */
1216 x_wm_set_size_hint (f
, (long) 0, 1);
1220 case kEventWindowShown
:
1221 case kEventWindowHidden
:
1222 case kEventWindowCollapsed
:
1223 case kEventWindowExpanded
:
1224 mac_handle_visibility_change (f
);
1228 case kEventWindowBoundsChanging
:
1229 result
= CallNextEventHandler (next_handler
, event
);
1230 if (result
!= eventNotHandledErr
)
1233 err
= GetEventParameter (event
, kEventParamAttributes
, typeUInt32
,
1234 NULL
, sizeof (UInt32
), NULL
, &attributes
);
1238 size_hints
= FRAME_SIZE_HINTS (f
);
1239 if ((attributes
& kWindowBoundsChangeUserResize
)
1240 && ((size_hints
->flags
& (PResizeInc
| PBaseSize
| PMinSize
))
1241 == (PResizeInc
| PBaseSize
| PMinSize
)))
1246 err
= GetEventParameter (event
, kEventParamCurrentBounds
,
1247 typeQDRectangle
, NULL
, sizeof (Rect
),
1252 width
= bounds
.right
- bounds
.left
;
1253 height
= bounds
.bottom
- bounds
.top
;
1255 if (width
< size_hints
->min_width
)
1256 width
= size_hints
->min_width
;
1258 width
= size_hints
->base_width
1259 + (int) ((width
- size_hints
->base_width
)
1260 / (float) size_hints
->width_inc
+ .5)
1261 * size_hints
->width_inc
;
1263 if (height
< size_hints
->min_height
)
1264 height
= size_hints
->min_height
;
1266 height
= size_hints
->base_height
1267 + (int) ((height
- size_hints
->base_height
)
1268 / (float) size_hints
->height_inc
+ .5)
1269 * size_hints
->height_inc
;
1271 bounds
.right
= bounds
.left
+ width
;
1272 bounds
.bottom
= bounds
.top
+ height
;
1273 SetEventParameter (event
, kEventParamCurrentBounds
,
1274 typeQDRectangle
, sizeof (Rect
), &bounds
);
1279 case kEventWindowBoundsChanged
:
1280 err
= GetEventParameter (event
, kEventParamAttributes
, typeUInt32
,
1281 NULL
, sizeof (UInt32
), NULL
, &attributes
);
1285 if (attributes
& kWindowBoundsChangeSizeChanged
)
1289 err
= GetEventParameter (event
, kEventParamCurrentBounds
,
1290 typeQDRectangle
, NULL
, sizeof (Rect
),
1296 width
= bounds
.right
- bounds
.left
;
1297 height
= bounds
.bottom
- bounds
.top
;
1298 mac_handle_size_change (f
, width
, height
);
1299 mac_wakeup_from_rne ();
1303 if (attributes
& kWindowBoundsChangeOriginChanged
)
1304 mac_handle_origin_change (f
);
1309 /* -- window action events -- */
1311 case kEventWindowClose
:
1313 struct input_event buf
;
1316 buf
.kind
= DELETE_WINDOW_EVENT
;
1317 XSETFRAME (buf
.frame_or_window
, f
);
1319 kbd_buffer_store_event (&buf
);
1324 case kEventWindowGetIdealSize
:
1325 result
= CallNextEventHandler (next_handler
, event
);
1326 if (result
!= eventNotHandledErr
)
1330 Point ideal_size
= mac_get_ideal_size (f
);
1332 err
= SetEventParameter (event
, kEventParamDimensions
,
1333 typeQDPoint
, sizeof (Point
), &ideal_size
);
1340 case kEventWindowToolbarSwitchMode
:
1342 static const EventParamName names
[] = {kEventParamDirectObject
,
1343 kEventParamWindowMouseLocation
,
1344 kEventParamKeyModifiers
,
1345 kEventParamMouseButton
,
1346 kEventParamClickCount
,
1347 kEventParamMouseChord
};
1348 static const EventParamType types
[] = {typeWindowRef
,
1354 int num_params
= sizeof (names
) / sizeof (names
[0]);
1356 err
= mac_store_event_ref_as_apple_event (0, 0,
1358 Qtoolbar_switch_mode
,
1368 /* -- window focus events -- */
1370 case kEventWindowFocusAcquired
:
1371 err
= mac_tsm_resume ();
1376 case kEventWindowFocusRelinquish
:
1377 err
= mac_tsm_suspend ();
1391 /* Handle clicks in zoom box. Calculation of "standard state" based
1392 on code in IM - Window Manager A and code contributed by Ben
1393 Mesander. The standard state of an Emacs window is 80-characters
1394 wide (DEFAULT_NUM_COLS) and as tall as will fit on the screen. */
1397 do_zoom_window (WindowRef w
, int zoom_in_or_out
)
1399 Rect zoom_rect
, port_rect
;
1401 struct frame
*f
= mac_window_to_frame (w
);
1402 #if TARGET_API_MAC_CARBON
1403 Point ideal_size
= mac_get_ideal_size (f
);
1405 GetWindowBounds (w
, kWindowContentRgn
, &port_rect
);
1406 if (IsWindowInStandardState (w
, &ideal_size
, &zoom_rect
)
1407 && port_rect
.left
== zoom_rect
.left
1408 && port_rect
.top
== zoom_rect
.top
)
1409 zoom_in_or_out
= inZoomIn
;
1411 zoom_in_or_out
= inZoomOut
;
1414 mac_clear_area (f
, 0, 0, port_rect
.right
- port_rect
.left
,
1415 port_rect
.bottom
- port_rect
.top
);
1417 ZoomWindowIdeal (w
, zoom_in_or_out
, &ideal_size
);
1418 #else /* not TARGET_API_MAC_CARBON */
1421 int w_title_height
, rows
;
1422 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
1424 GetPort (&save_port
);
1426 SetPortWindowPort (w
);
1428 /* Clear window to avoid flicker. */
1429 EraseRect (&(w
->portRect
));
1430 if (zoom_in_or_out
== inZoomOut
)
1432 SetPt (&top_left
, w
->portRect
.left
, w
->portRect
.top
);
1433 LocalToGlobal (&top_left
);
1435 /* calculate height of window's title bar */
1436 w_title_height
= top_left
.v
- 1
1437 - (**((WindowPeek
) w
)->strucRgn
).rgnBBox
.top
+ GetMBarHeight ();
1439 /* get maximum height of window into zoom_rect.bottom - zoom_rect.top */
1440 zoom_rect
= qd
.screenBits
.bounds
;
1441 zoom_rect
.top
+= w_title_height
;
1442 InsetRect (&zoom_rect
, 8, 4); /* not too tight */
1444 zoom_rect
.right
= zoom_rect
.left
1445 + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f
, DEFAULT_NUM_COLS
);
1447 /* Adjust the standard size according to character boundaries. */
1448 rows
= FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f
, zoom_rect
.bottom
- zoom_rect
.top
);
1450 zoom_rect
.top
+ FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f
, rows
);
1452 (**((WStateDataHandle
) ((WindowPeek
) w
)->dataHandle
)).stdState
1456 ZoomWindow (w
, zoom_in_or_out
, f
== mac_focus_frame (dpyinfo
));
1458 SetPort (save_port
);
1459 #endif /* not TARGET_API_MAC_CARBON */
1461 #if !TARGET_API_MAC_CARBON
1462 /* retrieve window size and update application values */
1463 port_rect
= w
->portRect
;
1464 height
= port_rect
.bottom
- port_rect
.top
;
1465 width
= port_rect
.right
- port_rect
.left
;
1467 mac_handle_size_change (f
, width
, height
);
1468 mac_handle_origin_change (f
);
1473 install_window_handler (window
)
1476 OSStatus err
= noErr
;
1478 #if TARGET_API_MAC_CARBON
1481 static const EventTypeSpec specs
[] =
1483 /* -- window refresh events -- */
1484 {kEventClassWindow
, kEventWindowUpdate
},
1485 /* -- window state change events -- */
1486 {kEventClassWindow
, kEventWindowShowing
},
1487 {kEventClassWindow
, kEventWindowHiding
},
1488 {kEventClassWindow
, kEventWindowShown
},
1489 {kEventClassWindow
, kEventWindowHidden
},
1490 {kEventClassWindow
, kEventWindowCollapsed
},
1491 {kEventClassWindow
, kEventWindowExpanded
},
1492 {kEventClassWindow
, kEventWindowBoundsChanging
},
1493 {kEventClassWindow
, kEventWindowBoundsChanged
},
1494 /* -- window action events -- */
1495 {kEventClassWindow
, kEventWindowClose
},
1496 {kEventClassWindow
, kEventWindowGetIdealSize
},
1498 {kEventClassWindow
, kEventWindowToolbarSwitchMode
},
1501 /* -- window focus events -- */
1502 {kEventClassWindow
, kEventWindowFocusAcquired
},
1503 {kEventClassWindow
, kEventWindowFocusRelinquish
},
1506 static EventHandlerUPP handle_window_eventUPP
= NULL
;
1508 if (handle_window_eventUPP
== NULL
)
1509 handle_window_eventUPP
= NewEventHandlerUPP (mac_handle_window_event
);
1511 err
= InstallWindowEventHandler (window
, handle_window_eventUPP
,
1512 GetEventTypeCount (specs
),
1518 err
= install_drag_handler (window
);
1524 remove_window_handler (window
)
1527 remove_drag_handler (window
);
1531 mac_get_window_bounds (f
, inner
, outer
)
1533 Rect
*inner
, *outer
;
1535 #if TARGET_API_MAC_CARBON
1536 GetWindowBounds (FRAME_MAC_WINDOW (f
), kWindowContentRgn
, inner
);
1537 GetWindowBounds (FRAME_MAC_WINDOW (f
), kWindowStructureRgn
, outer
);
1538 #else /* not TARGET_API_MAC_CARBON */
1539 RgnHandle region
= NewRgn ();
1541 GetWindowRegion (FRAME_MAC_WINDOW (f
), kWindowContentRgn
, region
);
1542 *inner
= (*region
)->rgnBBox
;
1543 GetWindowRegion (FRAME_MAC_WINDOW (f
), kWindowStructureRgn
, region
);
1544 *outer
= (*region
)->rgnBBox
;
1545 DisposeRgn (region
);
1546 #endif /* not TARGET_API_MAC_CARBON */
1550 mac_get_frame_bounds (f
, r
)
1554 #if TARGET_API_MAC_CARBON
1555 return GetWindowPortBounds (FRAME_MAC_WINDOW (f
), r
);
1557 *r
= FRAME_MAC_WINDOW (f
)->portRect
;
1564 mac_get_frame_mouse (f
, point
)
1568 #if TARGET_API_MAC_CARBON
1569 GetGlobalMouse (point
);
1570 point
->h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1571 point
->v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1573 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1579 mac_convert_frame_point_to_global (f
, x
, y
)
1583 *x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
1584 *y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
1587 #if TARGET_API_MAC_CARBON
1589 mac_update_proxy_icon (f
)
1593 Lisp_Object file_name
=
1594 XBUFFER (XWINDOW (FRAME_SELECTED_WINDOW (f
))->buffer
)->filename
;
1595 Window w
= FRAME_MAC_WINDOW (f
);
1596 AliasHandle alias
= NULL
;
1598 err
= GetWindowProxyAlias (w
, &alias
);
1599 if (err
== errWindowDoesNotHaveProxy
&& !STRINGP (file_name
))
1602 if (STRINGP (file_name
))
1606 FSRef fref
, fref_proxy
;
1608 FSSpec fss
, fss_proxy
;
1611 Lisp_Object encoded_file_name
= ENCODE_FILE (file_name
);
1614 err
= AECoercePtr (TYPE_FILE_NAME
, SDATA (encoded_file_name
),
1615 SBYTES (encoded_file_name
), typeFSRef
, &desc
);
1617 SetPortWindowPort (w
);
1618 err
= AECoercePtr (TYPE_FILE_NAME
, SDATA (encoded_file_name
),
1619 SBYTES (encoded_file_name
), typeFSS
, &desc
);
1624 err
= AEGetDescData (&desc
, &fref
, sizeof (FSRef
));
1626 err
= AEGetDescData (&desc
, &fss
, sizeof (FSSpec
));
1628 AEDisposeDesc (&desc
);
1634 /* (FS)ResolveAlias never sets `changed' to true if
1635 `alias' is minimal. */
1637 err
= FSResolveAlias (NULL
, alias
, &fref_proxy
, &changed
);
1639 err
= FSCompareFSRefs (&fref
, &fref_proxy
);
1641 err
= ResolveAlias (NULL
, alias
, &fss_proxy
, &changed
);
1643 err
= !(fss
.vRefNum
== fss_proxy
.vRefNum
1644 && fss
.parID
== fss_proxy
.parID
1645 && EqualString (fss
.name
, fss_proxy
.name
,
1649 if (err
!= noErr
|| alias
== NULL
)
1652 DisposeHandle ((Handle
) alias
);
1654 err
= FSNewAliasMinimal (&fref
, &alias
);
1656 err
= NewAliasMinimal (&fss
, &alias
);
1663 err
= SetWindowProxyAlias (w
, alias
);
1667 DisposeHandle ((Handle
) alias
);
1669 if (err
!= noErr
|| !STRINGP (file_name
))
1670 RemoveWindowProxy (w
);
1674 /* Mac replacement for XSetWindowBackground. */
1677 mac_set_frame_window_background (f
, color
)
1679 unsigned long color
;
1681 WindowRef w
= FRAME_MAC_WINDOW (f
);
1682 #if !TARGET_API_MAC_CARBON
1683 AuxWinHandle aw_handle
;
1684 CTabHandle ctab_handle
;
1685 ColorSpecPtr ct_table
;
1690 bg_color
.red
= RED16_FROM_ULONG (color
);
1691 bg_color
.green
= GREEN16_FROM_ULONG (color
);
1692 bg_color
.blue
= BLUE16_FROM_ULONG (color
);
1694 #if TARGET_API_MAC_CARBON
1695 SetWindowContentColor (w
, &bg_color
);
1697 if (GetAuxWin (w
, &aw_handle
))
1699 ctab_handle
= (*aw_handle
)->awCTable
;
1700 HandToHand ((Handle
*) &ctab_handle
);
1701 ct_table
= (*ctab_handle
)->ctTable
;
1702 ct_size
= (*ctab_handle
)->ctSize
;
1703 while (ct_size
> -1)
1705 if (ct_table
->value
== 0)
1707 ct_table
->rgb
= bg_color
;
1708 CTabChanged (ctab_handle
);
1709 SetWinColor (w
, (WCTabHandle
) ctab_handle
);
1717 /* Flush display of frame F, or of all frames if F is null. */
1723 #if TARGET_API_MAC_CARBON
1726 mac_prepare_for_quickdraw (f
);
1729 QDFlushPortBuffer (GetWindowPort (FRAME_MAC_WINDOW (f
)), NULL
);
1731 QDFlushPortBuffer (GetQDGlobalsThePort (), NULL
);
1738 mac_flush_display_optional (f
)
1742 mac_prepare_for_quickdraw (f
);
1748 mac_update_begin (f
)
1751 #if TARGET_API_MAC_CARBON
1752 /* During update of a frame, availability of input events is
1753 periodically checked with ReceiveNextEvent if
1754 redisplay-dont-pause is nil. That normally flushes window buffer
1755 changes for every check, and thus screen update looks waving even
1756 if no input is available. So we disable screen updates during
1757 update of a frame. */
1758 DisableScreenUpdates ();
1766 #if TARGET_API_MAC_CARBON
1767 EnableScreenUpdates ();
1772 mac_frame_up_to_date (f
)
1775 /* Nothing to do. */
1779 mac_create_frame_window (f
, tooltip_p
)
1784 #if TARGET_API_MAC_CARBON
1785 WindowClass window_class
;
1786 WindowAttributes attributes
;
1790 Boolean go_away_flag
;
1795 SetRect (&r
, f
->left_pos
, f
->top_pos
,
1796 f
->left_pos
+ FRAME_PIXEL_WIDTH (f
),
1797 f
->top_pos
+ FRAME_PIXEL_HEIGHT (f
));
1798 #if TARGET_API_MAC_CARBON
1799 window_class
= kDocumentWindowClass
;
1800 attributes
= (kWindowStandardDocumentAttributes
1802 | kWindowToolbarButtonAttribute
1806 proc_id
= zoomDocProc
;
1807 behind
= (WindowRef
) -1;
1808 go_away_flag
= true;
1813 SetRect (&r
, 0, 0, 1, 1);
1814 #if TARGET_API_MAC_CARBON
1815 window_class
= kHelpWindowClass
;
1816 attributes
= (kWindowNoUpdatesAttribute
1817 | kWindowNoActivatesAttribute
1818 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1020
1819 | kWindowIgnoreClicksAttribute
1823 proc_id
= plainDBox
;
1825 go_away_flag
= false;
1829 #if TARGET_API_MAC_CARBON
1830 CreateNewWindow (window_class
, attributes
, &r
, &FRAME_MAC_WINDOW (f
));
1831 if (FRAME_MAC_WINDOW (f
))
1833 SetWRefCon (FRAME_MAC_WINDOW (f
), (long) f
->output_data
.mac
);
1835 if (install_window_handler (FRAME_MAC_WINDOW (f
)) != noErr
)
1837 DisposeWindow (FRAME_MAC_WINDOW (f
));
1838 FRAME_MAC_WINDOW (f
) = NULL
;
1841 #else /* !TARGET_API_MAC_CARBON */
1842 FRAME_MAC_WINDOW (f
)
1843 = NewCWindow (NULL
, &r
, "\p", false, proc_id
, behind
, go_away_flag
,
1844 (long) f
->output_data
.mac
);
1845 #endif /* !TARGET_API_MAC_CARBON */
1846 /* so that update events can find this mac_output struct */
1847 f
->output_data
.mac
->mFP
= f
; /* point back to emacs frame */
1851 if (FRAME_MAC_WINDOW (f
))
1853 ControlRef root_control
;
1855 if (CreateRootControl (FRAME_MAC_WINDOW (f
), &root_control
) != noErr
)
1857 DisposeWindow (FRAME_MAC_WINDOW (f
));
1858 FRAME_MAC_WINDOW (f
) = NULL
;
1864 /* Dispose of the Mac window of the frame F. */
1867 mac_dispose_frame_window (f
)
1870 WindowRef window
= FRAME_MAC_WINDOW (f
);
1872 if (window
!= tip_window
)
1873 remove_window_handler (window
);
1876 mac_prepare_for_quickdraw (f
);
1878 DisposeWindow (window
);
1882 /************************************************************************
1884 ************************************************************************/
1887 #define FRAME_CG_CONTEXT(f) ((f)->output_data.mac->cg_context)
1890 mac_begin_cg_clip (f
, gc
)
1894 CGContextRef context
= FRAME_CG_CONTEXT (f
);
1898 QDBeginCGContext (GetWindowPort (FRAME_MAC_WINDOW (f
)), &context
);
1899 FRAME_CG_CONTEXT (f
) = context
;
1902 CGContextSaveGState (context
);
1903 CGContextTranslateCTM (context
, 0, FRAME_PIXEL_HEIGHT (f
));
1904 CGContextScaleCTM (context
, 1, -1);
1905 if (gc
&& gc
->n_clip_rects
)
1906 CGContextClipToRects (context
, gc
->clip_rects
, gc
->n_clip_rects
);
1915 CGContextRestoreGState (FRAME_CG_CONTEXT (f
));
1919 mac_prepare_for_quickdraw (f
)
1924 Lisp_Object rest
, frame
;
1925 FOR_EACH_FRAME (rest
, frame
)
1926 if (FRAME_MAC_P (XFRAME (frame
)))
1927 mac_prepare_for_quickdraw (XFRAME (frame
));
1931 CGContextRef context
= FRAME_CG_CONTEXT (f
);
1935 CGContextSynchronize (context
);
1936 QDEndCGContext (GetWindowPort (FRAME_MAC_WINDOW (f
)),
1937 &FRAME_CG_CONTEXT (f
));
1943 static RgnHandle saved_port_clip_region
= NULL
;
1946 mac_begin_clip (f
, gc
)
1950 static RgnHandle new_region
= NULL
;
1952 if (saved_port_clip_region
== NULL
)
1953 saved_port_clip_region
= NewRgn ();
1954 if (new_region
== NULL
)
1955 new_region
= NewRgn ();
1958 mac_prepare_for_quickdraw (f
);
1960 SetPortWindowPort (FRAME_MAC_WINDOW (f
));
1962 if (gc
&& gc
->n_clip_rects
)
1964 GetClip (saved_port_clip_region
);
1965 SectRgn (saved_port_clip_region
, gc
->clip_region
, new_region
);
1966 SetClip (new_region
);
1971 mac_end_clip (f
, gc
)
1975 if (gc
&& gc
->n_clip_rects
)
1976 SetClip (saved_port_clip_region
);
1979 #if TARGET_API_MAC_CARBON
1980 /* Mac replacement for XCopyArea: used only for scrolling. */
1983 mac_scroll_area (f
, gc
, src_x
, src_y
, width
, height
, dest_x
, dest_y
)
1987 unsigned int width
, height
;
1991 RgnHandle dummy
= NewRgn (); /* For avoiding update events. */
1993 SetRect (&src_r
, src_x
, src_y
, src_x
+ width
, src_y
+ height
);
1995 mac_prepare_for_quickdraw (f
);
1997 ScrollWindowRect (FRAME_MAC_WINDOW (f
),
1998 &src_r
, dest_x
- src_x
, dest_y
- src_y
,
1999 kScrollWindowNoOptions
, dummy
);
2005 /************************************************************************
2007 ************************************************************************/
2009 extern struct scroll_bar
*tracked_scroll_bar
;
2010 extern Lisp_Object last_mouse_scroll_bar
;
2011 extern Time last_mouse_movement_time
;
2013 static void x_scroll_bar_handle_click
P_ ((struct scroll_bar
*,
2015 const EventRecord
*,
2016 struct input_event
*));
2017 #ifndef USE_TOOLKIT_SCROLL_BARS
2018 static void x_scroll_bar_note_movement
P_ ((struct scroll_bar
*, int, Time
));
2019 #else /* USE_TOOLKIT_SCROLL_BARS */
2020 static void x_scroll_bar_handle_press
P_ ((struct scroll_bar
*,
2021 ControlPartCode
, Point
,
2022 struct input_event
*));
2023 static void x_scroll_bar_handle_release
P_ ((struct scroll_bar
*,
2024 struct input_event
*));
2025 static void x_scroll_bar_handle_drag
P_ ((WindowRef
, struct scroll_bar
*,
2026 Point
, struct input_event
*));
2027 static pascal void scroll_bar_timer_callback
P_ ((EventLoopTimerRef
, void *));
2028 static OSStatus install_scroll_bar_timer
P_ ((void));
2029 static OSStatus set_scroll_bar_timer
P_ ((EventTimerInterval
));
2030 static int control_part_code_to_scroll_bar_part
P_ ((ControlPartCode
));
2031 static void construct_scroll_bar_click
P_ ((struct scroll_bar
*, int,
2032 struct input_event
*));
2033 static OSStatus get_control_part_bounds
P_ ((ControlRef
, ControlPartCode
,
2035 static void update_scroll_bar_track_info
P_ ((struct scroll_bar
*));
2037 /* Last scroll bar part sent in x_scroll_bar_handle_*. */
2039 static int last_scroll_bar_part
;
2041 static EventLoopTimerRef scroll_bar_timer
;
2043 static int scroll_bar_timer_event_posted_p
;
2045 #define SCROLL_BAR_FIRST_DELAY 0.5
2046 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
2049 scroll_bar_timer_callback (timer
, data
)
2050 EventLoopTimerRef timer
;
2055 err
= mac_post_mouse_moved_event ();
2057 scroll_bar_timer_event_posted_p
= 1;
2061 install_scroll_bar_timer ()
2063 static EventLoopTimerUPP scroll_bar_timer_callbackUPP
= NULL
;
2065 if (scroll_bar_timer_callbackUPP
== NULL
)
2066 scroll_bar_timer_callbackUPP
=
2067 NewEventLoopTimerUPP (scroll_bar_timer_callback
);
2069 if (scroll_bar_timer
== NULL
)
2070 /* Mac OS X and CarbonLib 1.5 and later allow us to specify
2071 kEventDurationForever as delays. */
2073 InstallEventLoopTimer (GetCurrentEventLoop (),
2074 kEventDurationForever
, kEventDurationForever
,
2075 scroll_bar_timer_callbackUPP
, NULL
,
2080 set_scroll_bar_timer (delay
)
2081 EventTimerInterval delay
;
2083 if (scroll_bar_timer
== NULL
)
2084 install_scroll_bar_timer ();
2086 scroll_bar_timer_event_posted_p
= 0;
2088 return SetEventLoopTimerNextFireTime (scroll_bar_timer
, delay
);
2092 control_part_code_to_scroll_bar_part (part_code
)
2093 ControlPartCode part_code
;
2097 case kControlUpButtonPart
: return scroll_bar_up_arrow
;
2098 case kControlDownButtonPart
: return scroll_bar_down_arrow
;
2099 case kControlPageUpPart
: return scroll_bar_above_handle
;
2100 case kControlPageDownPart
: return scroll_bar_below_handle
;
2101 case kControlIndicatorPart
: return scroll_bar_handle
;
2108 construct_scroll_bar_click (bar
, part
, bufp
)
2109 struct scroll_bar
*bar
;
2111 struct input_event
*bufp
;
2113 bufp
->kind
= SCROLL_BAR_CLICK_EVENT
;
2114 bufp
->frame_or_window
= bar
->window
;
2118 XSETINT (bufp
->x
, 0);
2119 XSETINT (bufp
->y
, 0);
2120 bufp
->modifiers
= 0;
2124 get_control_part_bounds (ch
, part_code
, rect
)
2126 ControlPartCode part_code
;
2129 RgnHandle region
= NewRgn ();
2132 err
= GetControlRegion (ch
, part_code
, region
);
2134 GetRegionBounds (region
, rect
);
2135 DisposeRgn (region
);
2141 x_scroll_bar_handle_press (bar
, part_code
, mouse_pos
, bufp
)
2142 struct scroll_bar
*bar
;
2143 ControlPartCode part_code
;
2145 struct input_event
*bufp
;
2147 int part
= control_part_code_to_scroll_bar_part (part_code
);
2152 if (part
!= scroll_bar_handle
)
2154 construct_scroll_bar_click (bar
, part
, bufp
);
2155 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), part_code
);
2156 set_scroll_bar_timer (SCROLL_BAR_FIRST_DELAY
);
2157 bar
->dragging
= Qnil
;
2163 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar
),
2164 kControlIndicatorPart
, &r
);
2165 XSETINT (bar
->dragging
, - (mouse_pos
.v
- r
.top
) - 1);
2168 last_scroll_bar_part
= part
;
2169 tracked_scroll_bar
= bar
;
2173 x_scroll_bar_handle_release (bar
, bufp
)
2174 struct scroll_bar
*bar
;
2175 struct input_event
*bufp
;
2177 if (last_scroll_bar_part
!= scroll_bar_handle
2178 || (INTEGERP (bar
->dragging
) && XINT (bar
->dragging
) >= 0))
2179 construct_scroll_bar_click (bar
, scroll_bar_end_scroll
, bufp
);
2181 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), 0);
2182 set_scroll_bar_timer (kEventDurationForever
);
2184 last_scroll_bar_part
= -1;
2185 bar
->dragging
= Qnil
;
2186 tracked_scroll_bar
= NULL
;
2190 x_scroll_bar_handle_drag (win
, bar
, mouse_pos
, bufp
)
2192 struct scroll_bar
*bar
;
2194 struct input_event
*bufp
;
2196 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2198 if (last_scroll_bar_part
== scroll_bar_handle
)
2203 get_control_part_bounds (SCROLL_BAR_CONTROL_REF (bar
),
2204 kControlIndicatorPart
, &r
);
2206 if (INTEGERP (bar
->dragging
) && XINT (bar
->dragging
) < 0)
2207 XSETINT (bar
->dragging
, - (XINT (bar
->dragging
) + 1));
2209 top
= mouse_pos
.v
- XINT (bar
->dragging
) - XINT (bar
->track_top
);
2210 top_range
= XINT (bar
->track_height
) - XINT (bar
->min_handle
);
2214 if (top
> top_range
)
2217 construct_scroll_bar_click (bar
, scroll_bar_handle
, bufp
);
2218 XSETINT (bufp
->x
, top
);
2219 XSETINT (bufp
->y
, top_range
);
2223 ControlPartCode part_code
;
2224 int unhilite_p
= 0, part
;
2226 if (ch
!= FindControlUnderMouse (mouse_pos
, win
, &part_code
))
2230 part
= control_part_code_to_scroll_bar_part (part_code
);
2232 switch (last_scroll_bar_part
)
2234 case scroll_bar_above_handle
:
2235 case scroll_bar_below_handle
:
2236 if (part
!= scroll_bar_above_handle
2237 && part
!= scroll_bar_below_handle
)
2241 case scroll_bar_up_arrow
:
2242 case scroll_bar_down_arrow
:
2243 if (part
!= scroll_bar_up_arrow
2244 && part
!= scroll_bar_down_arrow
)
2251 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), 0);
2252 else if (part
!= last_scroll_bar_part
2253 || scroll_bar_timer_event_posted_p
)
2255 construct_scroll_bar_click (bar
, part
, bufp
);
2256 last_scroll_bar_part
= part
;
2257 HiliteControl (SCROLL_BAR_CONTROL_REF (bar
), part_code
);
2258 set_scroll_bar_timer (SCROLL_BAR_CONTINUOUS_DELAY
);
2263 /* Update BAR->track_top, BAR->track_height, and BAR->min_handle for
2264 the scroll bar BAR. This function should be called when the bounds
2265 of the scroll bar is changed. */
2268 update_scroll_bar_track_info (bar
)
2269 struct scroll_bar
*bar
;
2271 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2274 GetControlBounds (ch
, &r0
);
2276 if (r0
.right
- r0
.left
>= r0
.bottom
- r0
.top
2278 || r0
.right
- r0
.left
< MAC_AQUA_SMALL_VERTICAL_SCROLL_BAR_WIDTH
2282 XSETINT (bar
->track_top
, 0);
2283 XSETINT (bar
->track_height
, 0);
2284 XSETINT (bar
->min_handle
, 0);
2290 SetControl32BitMinimum (ch
, 0);
2291 SetControl32BitMaximum (ch
, 1 << 30);
2292 SetControlViewSize (ch
, 1);
2294 /* Move the scroll bar thumb to the top. */
2295 SetControl32BitValue (ch
, 0);
2296 get_control_part_bounds (ch
, kControlIndicatorPart
, &r0
);
2298 /* Move the scroll bar thumb to the bottom. */
2299 SetControl32BitValue (ch
, 1 << 30);
2300 get_control_part_bounds (ch
, kControlIndicatorPart
, &r1
);
2302 UnionRect (&r0
, &r1
, &r0
);
2303 XSETINT (bar
->track_top
, r0
.top
);
2304 XSETINT (bar
->track_height
, r0
.bottom
- r0
.top
);
2305 XSETINT (bar
->min_handle
, r1
.bottom
- r1
.top
);
2307 /* Don't show the scroll bar if its height is not enough to
2308 display the scroll bar thumb. */
2309 if (r0
.bottom
- r0
.top
> 0)
2316 /* Set the thumb size and position of scroll bar BAR. We are currently
2317 displaying PORTION out of a whole WHOLE, and our position POSITION. */
2320 x_set_toolkit_scroll_bar_thumb (bar
, portion
, position
, whole
)
2321 struct scroll_bar
*bar
;
2322 int portion
, position
, whole
;
2324 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2325 int value
, viewsize
, maximum
;
2327 if (XINT (bar
->track_height
) == 0)
2330 if (whole
<= portion
)
2331 value
= 0, viewsize
= 1, maximum
= 0;
2336 maximum
= XINT (bar
->track_height
) - XINT (bar
->min_handle
);
2337 scale
= (float) maximum
/ (whole
- portion
);
2338 value
= position
* scale
+ 0.5f
;
2339 viewsize
= (int) (portion
* scale
+ 0.5f
) + XINT (bar
->min_handle
);
2344 if (GetControlViewSize (ch
) != viewsize
2345 || GetControl32BitValue (ch
) != value
2346 || GetControl32BitMaximum (ch
) != maximum
)
2348 /* Temporarily hide the scroll bar to avoid multiple redraws. */
2349 SetControlVisibility (ch
, false, false);
2351 SetControl32BitMaximum (ch
, maximum
);
2352 SetControl32BitValue (ch
, value
);
2353 SetControlViewSize (ch
, viewsize
);
2355 SetControlVisibility (ch
, true, true);
2361 #endif /* USE_TOOLKIT_SCROLL_BARS */
2363 /* Create a scroll bar control for BAR. BOUNDS and VISIBLE specifies
2364 the initial geometry and visibility, respectively. The created
2365 control is stored in some members of BAR. */
2368 mac_create_scroll_bar (bar
, bounds
, visible
)
2369 struct scroll_bar
*bar
;
2373 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2377 mac_prepare_for_quickdraw (f
);
2379 ch
= NewControl (FRAME_MAC_WINDOW (f
), bounds
, "\p", visible
, 0, 0, 0,
2380 #if TARGET_API_MAC_CARBON
2381 kControlScrollBarProc
,
2386 SET_SCROLL_BAR_CONTROL_REF (bar
, ch
);
2388 XSETINT (bar
->start
, 0);
2389 XSETINT (bar
->end
, 0);
2390 bar
->dragging
= Qnil
;
2392 #ifdef USE_TOOLKIT_SCROLL_BARS
2393 update_scroll_bar_track_info (bar
);
2397 /* Dispose of the scroll bar control stored in some members of
2401 mac_dispose_scroll_bar (bar
)
2402 struct scroll_bar
*bar
;
2405 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2407 mac_prepare_for_quickdraw (f
);
2409 DisposeControl (SCROLL_BAR_CONTROL_REF (bar
));
2412 /* Set bounds of the scroll bar BAR to BOUNDS. */
2415 mac_set_scroll_bar_bounds (bar
, bounds
)
2416 struct scroll_bar
*bar
;
2419 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2420 SInt16 width
, height
;
2422 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2424 mac_prepare_for_quickdraw (f
);
2427 width
= bounds
->right
- bounds
->left
;
2428 height
= bounds
->bottom
- bounds
->top
;
2430 MoveControl (ch
, bounds
->left
, bounds
->top
);
2431 SizeControl (ch
, width
, height
);
2432 #ifdef USE_TOOLKIT_SCROLL_BARS
2433 update_scroll_bar_track_info (bar
);
2440 /* Draw the scroll bar BAR. */
2443 mac_redraw_scroll_bar (bar
)
2444 struct scroll_bar
*bar
;
2447 struct frame
*f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2449 mac_prepare_for_quickdraw (f
);
2451 Draw1Control (SCROLL_BAR_CONTROL_REF (bar
));
2454 /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
2455 is set to something other than NO_EVENT, it is enqueued.
2457 This may be called from a signal handler, so we have to ignore GC
2461 x_scroll_bar_handle_click (bar
, part_code
, er
, bufp
)
2462 struct scroll_bar
*bar
;
2463 ControlPartCode part_code
;
2464 const EventRecord
*er
;
2465 struct input_event
*bufp
;
2467 int win_y
, top_range
;
2469 if (! GC_WINDOWP (bar
->window
))
2472 bufp
->kind
= SCROLL_BAR_CLICK_EVENT
;
2473 bufp
->frame_or_window
= bar
->window
;
2476 bar
->dragging
= Qnil
;
2480 case kControlUpButtonPart
:
2481 bufp
->part
= scroll_bar_up_arrow
;
2483 case kControlDownButtonPart
:
2484 bufp
->part
= scroll_bar_down_arrow
;
2486 case kControlPageUpPart
:
2487 bufp
->part
= scroll_bar_above_handle
;
2489 case kControlPageDownPart
:
2490 bufp
->part
= scroll_bar_below_handle
;
2492 #if TARGET_API_MAC_CARBON
2495 case kControlIndicatorPart
:
2497 if (er
->what
== mouseDown
)
2498 bar
->dragging
= make_number (0);
2499 XSETVECTOR (last_mouse_scroll_bar
, bar
);
2500 bufp
->part
= scroll_bar_handle
;
2504 win_y
= XINT (bufp
->y
) - XINT (bar
->top
);
2505 top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (0/*dummy*/, XINT (bar
->height
));
2507 win_y
-= VERTICAL_SCROLL_BAR_TOP_BORDER
;
2511 if (! NILP (bar
->dragging
))
2512 win_y
-= XINT (bar
->dragging
);
2516 if (win_y
> top_range
)
2519 XSETINT (bufp
->x
, win_y
);
2520 XSETINT (bufp
->y
, top_range
);
2523 /* Return information to the user about the current position of the mouse
2524 on the scroll bar. */
2527 x_scroll_bar_report_motion (fp
, bar_window
, part
, x
, y
, time
)
2529 Lisp_Object
*bar_window
;
2530 enum scroll_bar_part
*part
;
2532 unsigned long *time
;
2534 struct scroll_bar
*bar
= XSCROLL_BAR (last_mouse_scroll_bar
);
2535 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2536 #if TARGET_API_MAC_CARBON
2537 WindowRef wp
= GetControlOwner (ch
);
2539 WindowRef wp
= (*ch
)->contrlOwner
;
2542 struct frame
*f
= mac_window_to_frame (wp
);
2543 int win_y
, top_range
;
2545 #if TARGET_API_MAC_CARBON
2546 GetGlobalMouse (&mouse_pos
);
2547 mouse_pos
.h
-= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
2548 mouse_pos
.v
-= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
2550 SetPortWindowPort (wp
);
2551 GetMouse (&mouse_pos
);
2554 win_y
= mouse_pos
.v
- XINT (bar
->top
);
2555 top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (f
, XINT (bar
->height
));
2557 win_y
-= VERTICAL_SCROLL_BAR_TOP_BORDER
;
2561 if (! NILP (bar
->dragging
))
2562 win_y
-= XINT (bar
->dragging
);
2566 if (win_y
> top_range
)
2570 *bar_window
= bar
->window
;
2572 if (! NILP (bar
->dragging
))
2573 *part
= scroll_bar_handle
;
2574 else if (win_y
< XINT (bar
->start
))
2575 *part
= scroll_bar_above_handle
;
2576 else if (win_y
< XINT (bar
->end
) + VERTICAL_SCROLL_BAR_MIN_HANDLE
)
2577 *part
= scroll_bar_handle
;
2579 *part
= scroll_bar_below_handle
;
2581 XSETINT (*x
, win_y
);
2582 XSETINT (*y
, top_range
);
2585 last_mouse_scroll_bar
= Qnil
;
2587 *time
= last_mouse_movement_time
;
2590 #ifndef USE_TOOLKIT_SCROLL_BARS
2591 /* Draw BAR's handle in the proper position.
2593 If the handle is already drawn from START to END, don't bother
2594 redrawing it, unless REBUILD is non-zero; in that case, always
2595 redraw it. (REBUILD is handy for drawing the handle after expose
2598 Normally, we want to constrain the start and end of the handle to
2599 fit inside its rectangle, but if the user is dragging the scroll
2600 bar handle, we want to let them drag it down all the way, so that
2601 the bar's top is as far down as it goes; otherwise, there's no way
2602 to move to the very end of the buffer. */
2605 x_scroll_bar_set_handle (bar
, start
, end
, rebuild
)
2606 struct scroll_bar
*bar
;
2610 int dragging
= ! NILP (bar
->dragging
);
2611 ControlRef ch
= SCROLL_BAR_CONTROL_REF (bar
);
2612 FRAME_PTR f
= XFRAME (WINDOW_FRAME (XWINDOW (bar
->window
)));
2613 int top_range
= VERTICAL_SCROLL_BAR_TOP_RANGE (f
, XINT (bar
->height
));
2614 int length
= end
- start
;
2616 /* If the display is already accurate, do nothing. */
2618 && start
== XINT (bar
->start
)
2619 && end
== XINT (bar
->end
))
2624 /* Make sure the values are reasonable, and try to preserve the
2625 distance between start and end. */
2628 else if (start
> top_range
)
2630 end
= start
+ length
;
2634 else if (end
> top_range
&& ! dragging
)
2637 /* Store the adjusted setting in the scroll bar. */
2638 XSETINT (bar
->start
, start
);
2639 XSETINT (bar
->end
, end
);
2641 /* Clip the end position, just for display. */
2642 if (end
> top_range
)
2645 /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels below
2646 top positions, to make sure the handle is always at least that
2647 many pixels tall. */
2648 end
+= VERTICAL_SCROLL_BAR_MIN_HANDLE
;
2650 SetControlMinimum (ch
, 0);
2651 /* Don't inadvertently activate deactivated scroll bars */
2652 if (GetControlMaximum (ch
) != -1)
2653 SetControlMaximum (ch
, top_range
+ VERTICAL_SCROLL_BAR_MIN_HANDLE
2655 SetControlValue (ch
, start
);
2656 #if TARGET_API_MAC_CARBON
2657 SetControlViewSize (ch
, end
- start
);
2663 /* Handle some mouse motion while someone is dragging the scroll bar.
2665 This may be called from a signal handler, so we have to ignore GC
2669 x_scroll_bar_note_movement (bar
, y_pos
, t
)
2670 struct scroll_bar
*bar
;
2674 FRAME_PTR f
= XFRAME (XWINDOW (bar
->window
)->frame
);
2676 last_mouse_movement_time
= t
;
2679 XSETVECTOR (last_mouse_scroll_bar
, bar
);
2681 /* If we're dragging the bar, display it. */
2682 if (! GC_NILP (bar
->dragging
))
2684 /* Where should the handle be now? */
2685 int new_start
= y_pos
- 24;
2687 if (new_start
!= XINT (bar
->start
))
2689 int new_end
= new_start
+ (XINT (bar
->end
) - XINT (bar
->start
));
2691 x_scroll_bar_set_handle (bar
, new_start
, new_end
, 0);
2695 #endif /* !USE_TOOLKIT_SCROLL_BARS */
2698 /***********************************************************************
2700 ***********************************************************************/
2703 /* In identifiers such as function/variable names, Emacs tool bar is
2704 referred to as `tool_bar', and Carbon HIToolbar as `toolbar'. */
2706 #define TOOLBAR_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar"))
2707 #define TOOLBAR_ICON_ITEM_IDENTIFIER (CFSTR ("org.gnu.Emacs.toolbar.icon"))
2709 #define TOOLBAR_ITEM_COMMAND_ID_OFFSET 'Tb\0\0'
2710 #define TOOLBAR_ITEM_COMMAND_ID_P(id) \
2711 (((id) & ~0xffff) == TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2712 #define TOOLBAR_ITEM_COMMAND_ID_VALUE(id) \
2713 ((id) - TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2714 #define TOOLBAR_ITEM_MAKE_COMMAND_ID(value) \
2715 ((value) + TOOLBAR_ITEM_COMMAND_ID_OFFSET)
2717 static OSStatus mac_handle_toolbar_command_event
P_ ((EventHandlerCallRef
,
2720 extern Rect last_mouse_glyph
;
2722 extern void mac_move_window_with_gravity
P_ ((struct frame
*, int,
2724 extern void mac_get_window_origin_with_gravity
P_ ((struct frame
*, int,
2726 extern CGImageRef mac_image_spec_to_cg_image
P_ ((struct frame
*,
2730 mac_handle_toolbar_event (next_handler
, event
, data
)
2731 EventHandlerCallRef next_handler
;
2735 OSStatus result
= eventNotHandledErr
;
2737 switch (GetEventKind (event
))
2739 case kEventToolbarGetDefaultIdentifiers
:
2743 case kEventToolbarGetAllowedIdentifiers
:
2745 CFMutableArrayRef array
;
2747 GetEventParameter (event
, kEventParamMutableArray
,
2748 typeCFMutableArrayRef
, NULL
,
2749 sizeof (CFMutableArrayRef
), NULL
, &array
);
2750 CFArrayAppendValue (array
, TOOLBAR_ICON_ITEM_IDENTIFIER
);
2755 case kEventToolbarCreateItemWithIdentifier
:
2757 CFStringRef identifier
;
2758 HIToolbarItemRef item
= NULL
;
2760 GetEventParameter (event
, kEventParamToolbarItemIdentifier
,
2761 typeCFStringRef
, NULL
,
2762 sizeof (CFStringRef
), NULL
, &identifier
);
2764 if (CFStringCompare (identifier
, TOOLBAR_ICON_ITEM_IDENTIFIER
, 0)
2765 == kCFCompareEqualTo
)
2766 HIToolbarItemCreate (identifier
,
2767 kHIToolbarItemAllowDuplicates
2768 | kHIToolbarItemCantBeRemoved
, &item
);
2772 SetEventParameter (event
, kEventParamToolbarItem
,
2773 typeHIToolbarItemRef
,
2774 sizeof (HIToolbarItemRef
), &item
);
2787 /* Create a tool bar for frame F. */
2790 mac_create_frame_tool_bar (f
)
2794 HIToolbarRef toolbar
;
2796 err
= HIToolbarCreate (TOOLBAR_IDENTIFIER
, kHIToolbarNoAttributes
,
2800 static const EventTypeSpec specs
[] =
2801 {{kEventClassToolbar
, kEventToolbarGetDefaultIdentifiers
},
2802 {kEventClassToolbar
, kEventToolbarGetAllowedIdentifiers
},
2803 {kEventClassToolbar
, kEventToolbarCreateItemWithIdentifier
}};
2805 err
= InstallEventHandler (HIObjectGetEventTarget (toolbar
),
2806 mac_handle_toolbar_event
,
2807 GetEventTypeCount (specs
), specs
,
2812 err
= HIToolbarSetDisplayMode (toolbar
, kHIToolbarDisplayModeIconOnly
);
2815 static const EventTypeSpec specs
[] =
2816 {{kEventClassCommand
, kEventCommandProcess
}};
2818 err
= InstallWindowEventHandler (FRAME_MAC_WINDOW (f
),
2819 mac_handle_toolbar_command_event
,
2820 GetEventTypeCount (specs
),
2824 err
= SetWindowToolbar (FRAME_MAC_WINDOW (f
), toolbar
);
2827 CFRelease (toolbar
);
2832 /* Update the tool bar for frame F. Add new buttons and remove old. */
2835 update_frame_tool_bar (f
)
2838 HIToolbarRef toolbar
= NULL
;
2840 CFArrayRef old_items
= NULL
;
2842 int i
, pos
, win_gravity
= f
->output_data
.mac
->toolbar_win_gravity
;
2843 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2847 GetWindowToolbar (FRAME_MAC_WINDOW (f
), &toolbar
);
2848 if (toolbar
== NULL
)
2850 mac_create_frame_tool_bar (f
);
2851 GetWindowToolbar (FRAME_MAC_WINDOW (f
), &toolbar
);
2852 if (toolbar
== NULL
)
2854 if (win_gravity
>= NorthWestGravity
&& win_gravity
<= SouthEastGravity
)
2855 mac_get_window_origin_with_gravity (f
, win_gravity
, &left
, &top
);
2858 HIToolbarCopyItems (toolbar
, &old_items
);
2859 if (old_items
== NULL
)
2862 old_count
= CFArrayGetCount (old_items
);
2864 for (i
= 0; i
< f
->n_tool_bar_items
; ++i
)
2866 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
2868 int enabled_p
= !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P
));
2869 int selected_p
= !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P
));
2872 CGImageRef cg_image
;
2874 HIToolbarItemRef item
;
2876 /* If image is a vector, choose the image according to the
2878 image
= PROP (TOOL_BAR_ITEM_IMAGES
);
2879 if (VECTORP (image
))
2883 ? TOOL_BAR_IMAGE_ENABLED_SELECTED
2884 : TOOL_BAR_IMAGE_ENABLED_DESELECTED
);
2887 ? TOOL_BAR_IMAGE_DISABLED_SELECTED
2888 : TOOL_BAR_IMAGE_DISABLED_DESELECTED
);
2890 xassert (ASIZE (image
) >= idx
);
2891 image
= AREF (image
, idx
);
2896 cg_image
= mac_image_spec_to_cg_image (f
, image
);
2897 /* Ignore invalid image specifications. */
2898 if (cg_image
== NULL
)
2901 label
= cfstring_create_with_string (PROP (TOOL_BAR_ITEM_CAPTION
));
2905 if (pos
< old_count
)
2907 CGImageRef old_cg_image
= NULL
;
2908 CFStringRef old_label
= NULL
;
2909 Boolean old_enabled_p
;
2911 item
= (HIToolbarItemRef
) CFArrayGetValueAtIndex (old_items
, pos
);
2913 HIToolbarItemCopyImage (item
, &old_cg_image
);
2914 if (cg_image
!= old_cg_image
)
2915 HIToolbarItemSetImage (item
, cg_image
);
2916 CGImageRelease (old_cg_image
);
2918 HIToolbarItemCopyLabel (item
, &old_label
);
2919 if (CFStringCompare (label
, old_label
, 0) != kCFCompareEqualTo
)
2920 HIToolbarItemSetLabel (item
, label
);
2921 CFRelease (old_label
);
2923 old_enabled_p
= HIToolbarItemIsEnabled (item
);
2924 if ((enabled_p
|| idx
>= 0) != old_enabled_p
)
2925 HIToolbarItemSetEnabled (item
, (enabled_p
|| idx
>= 0));
2930 HIToolbarCreateItemWithIdentifier (toolbar
,
2931 TOOLBAR_ICON_ITEM_IDENTIFIER
,
2935 HIToolbarItemSetImage (item
, cg_image
);
2936 HIToolbarItemSetLabel (item
, label
);
2937 HIToolbarItemSetEnabled (item
, (enabled_p
|| idx
>= 0));
2938 HIToolbarAppendItem (toolbar
, item
);
2946 HIToolbarItemSetCommandID (item
, TOOLBAR_ITEM_MAKE_COMMAND_ID (i
));
2951 CFRelease (old_items
);
2953 while (pos
< old_count
)
2954 HIToolbarRemoveItemAtIndex (toolbar
, --old_count
);
2956 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f
), true,
2957 !win_gravity
&& f
== mac_focus_frame (dpyinfo
));
2958 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events on
2959 toolbar visibility change. */
2960 mac_handle_origin_change (f
);
2961 if (win_gravity
>= NorthWestGravity
&& win_gravity
<= SouthEastGravity
)
2963 mac_move_window_with_gravity (f
, win_gravity
, left
, top
);
2964 /* If the title bar is completely outside the screen, adjust the
2966 ConstrainWindowToScreen (FRAME_MAC_WINDOW (f
), kWindowTitleBarRgn
,
2967 kWindowConstrainMoveRegardlessOfFit
2968 | kWindowConstrainAllowPartial
, NULL
, NULL
);
2969 f
->output_data
.mac
->toolbar_win_gravity
= 0;
2976 /* Hide the tool bar on frame F. Unlike the counterpart on GTK+, it
2977 doesn't deallocate the resources. */
2980 free_frame_tool_bar (f
)
2983 if (IsWindowToolbarVisible (FRAME_MAC_WINDOW (f
)))
2985 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
2988 ShowHideWindowToolbar (FRAME_MAC_WINDOW (f
), false,
2989 (NILP (find_symbol_value
2990 (intern ("frame-notice-user-settings")))
2991 && f
== mac_focus_frame (dpyinfo
)));
2992 /* Mac OS X 10.3 does not issue kEventWindowBoundsChanged events
2993 on toolbar visibility change. */
2994 mac_handle_origin_change (f
);
2999 /* Report a mouse movement over toolbar to the mainstream Emacs
3003 mac_tool_bar_note_mouse_movement (f
, event
)
3008 struct mac_display_info
*dpyinfo
= FRAME_MAC_DISPLAY_INFO (f
);
3011 WindowPartCode part_code
;
3012 HIViewRef item_view
;
3015 mouse_down_p
= (dpyinfo
->grabbed
3016 && f
== last_mouse_frame
3017 && FRAME_LIVE_P (f
));
3021 err
= GetEventParameter (event
, kEventParamWindowRef
, typeWindowRef
, NULL
,
3022 sizeof (WindowRef
), NULL
, &window
);
3023 if (err
!= noErr
|| window
!= FRAME_MAC_WINDOW (f
))
3026 err
= GetEventParameter (event
, kEventParamWindowPartCode
,
3027 typeWindowPartCode
, NULL
,
3028 sizeof (WindowPartCode
), NULL
, &part_code
);
3029 if (err
!= noErr
|| part_code
!= inStructure
)
3032 err
= HIViewGetViewForMouseEvent (HIViewGetRoot (window
), event
, &item_view
);
3033 /* This doesn't work on Mac OS X 10.2. On Mac OS X 10.3 and 10.4, a
3034 toolbar item view seems to have the same command ID with that of
3035 the toolbar item. */
3037 err
= GetControlCommandID (item_view
, &command_id
);
3038 if (err
== noErr
&& TOOLBAR_ITEM_COMMAND_ID_P (command_id
))
3040 int i
= TOOLBAR_ITEM_COMMAND_ID_VALUE (command_id
);
3042 if (i
< f
->n_tool_bar_items
)
3045 HIViewRef content_view
;
3047 err
= HIViewGetBounds (item_view
, &bounds
);
3049 err
= HIViewFindByID (HIViewGetRoot (window
),
3050 kHIViewWindowContentID
, &content_view
);
3052 err
= HIViewConvertRect (&bounds
, item_view
, content_view
);
3054 SetRect (&last_mouse_glyph
,
3055 CGRectGetMinX (bounds
), CGRectGetMinY (bounds
),
3056 CGRectGetMaxX (bounds
), CGRectGetMaxY (bounds
));
3058 help_echo_object
= help_echo_window
= Qnil
;
3060 help_echo_string
= PROP (TOOL_BAR_ITEM_HELP
);
3061 if (NILP (help_echo_string
))
3062 help_echo_string
= PROP (TOOL_BAR_ITEM_CAPTION
);
3068 mac_handle_toolbar_command_event (next_handler
, event
, data
)
3069 EventHandlerCallRef next_handler
;
3073 OSStatus err
, result
= eventNotHandledErr
;
3074 struct frame
*f
= (struct frame
*) data
;
3077 err
= GetEventParameter (event
, kEventParamDirectObject
,
3078 typeHICommand
, NULL
,
3079 sizeof (HICommand
), NULL
, &command
);
3083 switch (GetEventKind (event
))
3085 case kEventCommandProcess
:
3086 if (!TOOLBAR_ITEM_COMMAND_ID_P (command
.commandID
))
3087 result
= CallNextEventHandler (next_handler
, event
);
3090 int i
= TOOLBAR_ITEM_COMMAND_ID_VALUE (command
.commandID
);
3092 if (i
< f
->n_tool_bar_items
3093 && !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P
)))
3096 struct input_event buf
;
3100 XSETFRAME (frame
, f
);
3101 buf
.kind
= TOOL_BAR_EVENT
;
3102 buf
.frame_or_window
= frame
;
3104 kbd_buffer_store_event (&buf
);
3106 buf
.kind
= TOOL_BAR_EVENT
;
3107 buf
.frame_or_window
= frame
;
3108 buf
.arg
= PROP (TOOL_BAR_ITEM_KEY
);
3109 buf
.modifiers
= mac_event_to_emacs_modifiers (event
);
3110 kbd_buffer_store_event (&buf
);
3124 #endif /* USE_MAC_TOOLBAR */
3127 /***********************************************************************
3129 ***********************************************************************/
3131 #if USE_MAC_FONT_PANEL
3132 /* Whether Font Panel has been shown before. The first call to font
3133 panel functions (FPIsFontPanelVisible, SetFontInfoForSelection) is
3134 slow. This variable is used for deferring such a call as much as
3136 static int font_panel_shown_p
= 0;
3138 extern Lisp_Object Qpanel_closed
, Qselection
;
3139 extern Lisp_Object Qfont
;
3141 /* Whether the font panel is currently visible. */
3144 mac_font_panel_visible_p ()
3146 return font_panel_shown_p
&& FPIsFontPanelVisible ();
3149 static pascal OSStatus
3150 mac_handle_font_event (next_handler
, event
, data
)
3151 EventHandlerCallRef next_handler
;
3155 OSStatus result
, err
;
3158 const EventParamName
*names
;
3159 const EventParamType
*types
;
3160 static const EventParamName names_sel
[] = {kEventParamATSUFontID
,
3161 kEventParamATSUFontSize
,
3162 kEventParamFMFontFamily
,
3163 kEventParamFMFontStyle
,
3164 kEventParamFMFontSize
,
3165 kEventParamFontColor
};
3166 static const EventParamType types_sel
[] = {typeATSUFontID
,
3173 result
= CallNextEventHandler (next_handler
, event
);
3174 if (result
!= eventNotHandledErr
)
3177 switch (GetEventKind (event
))
3179 case kEventFontPanelClosed
:
3180 id_key
= Qpanel_closed
;
3186 case kEventFontSelection
:
3187 id_key
= Qselection
;
3188 num_params
= sizeof (names_sel
) / sizeof (names_sel
[0]);
3194 err
= mac_store_event_ref_as_apple_event (0, 0, Qfont
, id_key
,
3203 /* Toggle visiblity of the font panel. */
3206 mac_show_hide_font_panel ()
3208 if (!font_panel_shown_p
)
3212 static const EventTypeSpec specs
[] =
3213 {{kEventClassFont
, kEventFontPanelClosed
},
3214 {kEventClassFont
, kEventFontSelection
}};
3216 err
= InstallApplicationEventHandler (mac_handle_font_event
,
3217 GetEventTypeCount (specs
),
3222 font_panel_shown_p
= 1;
3225 return FPShowHideFontPanel ();
3228 /* Set the font selected in the font panel to the one corresponding to
3229 the face FACE_ID and the charcacter C in the frame F. */
3232 mac_set_font_info_for_selection (f
, face_id
, c
)
3237 EventTargetRef target
= NULL
;
3238 XFontStruct
*font
= NULL
;
3240 if (!mac_font_panel_visible_p ())
3245 target
= GetWindowEventTarget (FRAME_MAC_WINDOW (f
));
3247 if (FRAME_FACE_CACHE (f
) && CHAR_VALID_P (c
, 0))
3251 face_id
= FACE_FOR_CHAR (f
, FACE_FROM_ID (f
, face_id
), c
);
3252 face
= FACE_FROM_ID (f
, face_id
);
3258 err
= SetFontInfoForSelection (kFontSelectionATSUIType
, 0, NULL
, target
);
3261 if (font
->mac_fontnum
!= -1)
3263 FontSelectionQDStyle qd_style
;
3265 qd_style
.version
= kFontSelectionQDStyleVersionZero
;
3266 qd_style
.instance
.fontFamily
= font
->mac_fontnum
;
3267 qd_style
.instance
.fontStyle
= font
->mac_fontface
;
3268 qd_style
.size
= font
->mac_fontsize
;
3269 qd_style
.hasColor
= false;
3271 err
= SetFontInfoForSelection (kFontSelectionQDType
,
3272 1, &qd_style
, target
);
3275 err
= SetFontInfoForSelection (kFontSelectionATSUIType
,
3276 1, &font
->mac_style
, target
);
3281 #endif /* USE_MAC_FONT_PANEL */
3284 /************************************************************************
3286 ************************************************************************/
3288 /* Non-zero means that a HELP_EVENT has been generated since Emacs
3291 static int any_help_event_p
;
3293 /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
3294 static Lisp_Object last_window
;
3296 static Point saved_menu_event_location
;
3298 extern struct frame
*pending_autoraise_frame
;
3300 extern FRAME_PTR last_mouse_glyph_frame
;
3303 extern int volatile input_signal_count
;
3305 extern int input_signal_count
;
3308 extern int mac_screen_config_changed
;
3310 extern Lisp_Object Vmac_emulate_three_button_mouse
;
3311 #if TARGET_API_MAC_CARBON
3312 extern int mac_wheel_button_is_mouse_2
;
3313 extern int mac_pass_command_to_system
;
3314 extern int mac_pass_control_to_system
;
3315 #endif /* TARGET_API_MAC_CARBON */
3316 extern int mac_ready_for_apple_events
;
3318 extern void mac_focus_changed
P_ ((int, struct mac_display_info
*,
3319 struct frame
*, struct input_event
*));
3320 extern int mac_get_emulated_btn
P_ ((UInt32
));
3321 extern int note_mouse_movement
P_ ((FRAME_PTR
, Point
*));
3322 extern void mac_get_screen_info
P_ ((struct mac_display_info
*));
3324 /* The focus may have changed. Figure out if it is a real focus change,
3325 by checking both FocusIn/Out and Enter/LeaveNotify events.
3327 Returns FOCUS_IN_EVENT event in *BUFP. */
3330 x_detect_focus_change (dpyinfo
, event
, bufp
)
3331 struct mac_display_info
*dpyinfo
;
3332 const EventRecord
*event
;
3333 struct input_event
*bufp
;
3335 struct frame
*frame
;
3337 frame
= mac_window_to_frame ((WindowRef
) event
->message
);
3341 /* On Mac, this is only called from focus events, so no switch needed. */
3342 mac_focus_changed ((event
->modifiers
& activeFlag
),
3343 dpyinfo
, frame
, bufp
);
3346 #if TARGET_API_MAC_CARBON
3347 /* Obtains the event modifiers from the event EVENTREF and then calls
3348 mac_to_emacs_modifiers. */
3351 mac_event_to_emacs_modifiers (EventRef eventRef
)
3353 UInt32 mods
= 0, class;
3355 GetEventParameter (eventRef
, kEventParamKeyModifiers
, typeUInt32
, NULL
,
3356 sizeof (UInt32
), NULL
, &mods
);
3357 class = GetEventClass (eventRef
);
3358 if (!NILP (Vmac_emulate_three_button_mouse
)
3359 && (class == kEventClassMouse
|| class == kEventClassCommand
))
3361 mods
&= ~(optionKey
| cmdKey
);
3363 return mac_to_emacs_modifiers (mods
, 0);
3366 /* Given an event REF, return the code to use for the mouse button
3367 code in the emacs input_event. */
3370 mac_get_mouse_btn (EventRef ref
)
3372 EventMouseButton result
= kEventMouseButtonPrimary
;
3373 GetEventParameter (ref
, kEventParamMouseButton
, typeMouseButton
, NULL
,
3374 sizeof (EventMouseButton
), NULL
, &result
);
3377 case kEventMouseButtonPrimary
:
3378 if (NILP (Vmac_emulate_three_button_mouse
))
3382 GetEventParameter (ref
, kEventParamKeyModifiers
, typeUInt32
, NULL
,
3383 sizeof (UInt32
), NULL
, &mods
);
3384 return mac_get_emulated_btn(mods
);
3386 case kEventMouseButtonSecondary
:
3387 return mac_wheel_button_is_mouse_2
? 2 : 1;
3388 case kEventMouseButtonTertiary
:
3389 case 4: /* 4 is the number for the mouse wheel button */
3390 return mac_wheel_button_is_mouse_2
? 1 : 2;
3396 /* Normally, ConvertEventRefToEventRecord will correctly handle all
3397 events. However the click of the mouse wheel is not converted to a
3398 mouseDown or mouseUp event. Likewise for dead key events. This
3399 calls ConvertEventRefToEventRecord, but then checks to see if it is
3400 a mouse up/down, or a dead key Carbon event that has not been
3401 converted, and if so, converts it by hand (to be picked up in the
3402 XTread_socket loop). */
3403 static Boolean
mac_convert_event_ref (EventRef eventRef
, EventRecord
*eventRec
)
3406 Boolean result
= ConvertEventRefToEventRecord (eventRef
, eventRec
);
3412 switch (GetEventClass (eventRef
))
3414 case kEventClassMouse
:
3415 switch (GetEventKind (eventRef
))
3417 case kEventMouseDown
:
3418 eventRec
->what
= mouseDown
;
3423 eventRec
->what
= mouseUp
;
3432 case kEventClassKeyboard
:
3433 switch (GetEventKind (eventRef
))
3435 case kEventRawKeyDown
:
3437 goto keystroke_common
;
3438 case kEventRawKeyRepeat
:
3440 goto keystroke_common
;
3441 case kEventRawKeyUp
:
3445 unsigned char char_codes
;
3448 err
= GetEventParameter (eventRef
, kEventParamKeyMacCharCodes
,
3449 typeChar
, NULL
, sizeof (char),
3452 err
= GetEventParameter (eventRef
, kEventParamKeyCode
,
3453 typeUInt32
, NULL
, sizeof (UInt32
),
3457 eventRec
->what
= action
;
3458 eventRec
->message
= char_codes
| ((key_code
& 0xff) << 8);
3475 /* Need where and when. */
3478 GetEventParameter (eventRef
, kEventParamMouseLocation
, typeQDPoint
,
3479 NULL
, sizeof (Point
), NULL
, &eventRec
->where
);
3480 /* Use two step process because new event modifiers are 32-bit
3481 and old are 16-bit. Currently, only loss is NumLock & Fn. */
3482 GetEventParameter (eventRef
, kEventParamKeyModifiers
, typeUInt32
,
3483 NULL
, sizeof (UInt32
), NULL
, &mods
);
3484 eventRec
->modifiers
= mods
;
3486 eventRec
->when
= EventTimeToTicks (GetEventTime (eventRef
));
3491 #endif /* TARGET_API_MAC_CARBON */
3493 #if !TARGET_API_MAC_CARBON
3494 static RgnHandle mouse_region
= NULL
;
3497 mac_wait_next_event (er
, sleep_time
, dequeue
)
3502 static EventRecord er_buf
= {nullEvent
};
3503 UInt32 target_tick
, current_tick
;
3504 EventMask event_mask
;
3506 if (mouse_region
== NULL
)
3507 mouse_region
= NewRgn ();
3509 event_mask
= everyEvent
;
3510 if (!mac_ready_for_apple_events
)
3511 event_mask
-= highLevelEventMask
;
3513 current_tick
= TickCount ();
3514 target_tick
= current_tick
+ sleep_time
;
3516 if (er_buf
.what
== nullEvent
)
3517 while (!WaitNextEvent (event_mask
, &er_buf
,
3518 target_tick
- current_tick
, mouse_region
))
3520 current_tick
= TickCount ();
3521 if (target_tick
<= current_tick
)
3527 er_buf
.what
= nullEvent
;
3530 #endif /* not TARGET_API_MAC_CARBON */
3532 #if TARGET_API_MAC_CARBON
3534 mac_post_mouse_moved_event ()
3536 EventRef event
= NULL
;
3539 err
= CreateEvent (NULL
, kEventClassMouse
, kEventMouseMoved
, 0,
3540 kEventAttributeNone
, &event
);
3545 GetGlobalMouse (&mouse_pos
);
3546 err
= SetEventParameter (event
, kEventParamMouseLocation
, typeQDPoint
,
3547 sizeof (Point
), &mouse_pos
);
3551 UInt32 modifiers
= GetCurrentKeyModifiers ();
3553 err
= SetEventParameter (event
, kEventParamKeyModifiers
, typeUInt32
,
3554 sizeof (UInt32
), &modifiers
);
3557 err
= PostEventToQueue (GetCurrentEventQueue (), event
,
3558 kEventPriorityStandard
);
3560 ReleaseEvent (event
);
3567 /* Run the current run loop in the default mode until some input
3568 happens or TIMEOUT seconds passes unless it is negative. Return
3569 true if timeout occurs first. */
3572 mac_run_loop_run_once (timeout
)
3573 EventTimeout timeout
;
3576 mac_prepare_for_quickdraw (NULL
);
3578 return (CFRunLoopRunInMode (kCFRunLoopDefaultMode
,
3579 timeout
>= 0 ? timeout
: 100000, true)
3580 == kCFRunLoopRunTimedOut
);
3584 /* Emacs calls this whenever it wants to read an input event from the
3588 XTread_socket (sd
, expected
, hold_quit
)
3590 struct input_event
*hold_quit
;
3592 struct input_event inev
;
3594 #if TARGET_API_MAC_CARBON
3596 EventTargetRef toolbox_dispatcher
;
3599 struct mac_display_info
*dpyinfo
= &one_mac_display_info
;
3601 if (interrupt_input_blocked
)
3603 interrupt_input_pending
= 1;
3607 interrupt_input_pending
= 0;
3610 /* So people can tell when we have read the available input. */
3611 input_signal_count
++;
3615 #if TARGET_API_MAC_CARBON
3616 toolbox_dispatcher
= GetEventDispatcherTarget ();
3620 mac_prepare_for_quickdraw (NULL
),
3622 !ReceiveNextEvent (0, NULL
, kEventDurationNoWait
,
3623 kEventRemoveFromQueue
, &eventRef
))
3624 #else /* !TARGET_API_MAC_CARBON */
3625 while (mac_wait_next_event (&er
, 0, true))
3626 #endif /* !TARGET_API_MAC_CARBON */
3630 unsigned long timestamp
;
3633 inev
.kind
= NO_EVENT
;
3636 #if TARGET_API_MAC_CARBON
3637 timestamp
= GetEventTime (eventRef
) / kEventDurationMillisecond
;
3639 if (!mac_convert_event_ref (eventRef
, &er
))
3641 #else /* !TARGET_API_MAC_CARBON */
3642 timestamp
= er
.when
* (1000 / 60); /* ticks to milliseconds */
3643 #endif /* !TARGET_API_MAC_CARBON */
3650 WindowRef window_ptr
;
3651 ControlPartCode part_code
;
3654 #if TARGET_API_MAC_CARBON
3657 /* This is needed to send mouse events like aqua window
3658 buttons to the correct handler. */
3659 read_socket_inev
= &inev
;
3660 err
= SendEventToEventTarget (eventRef
, toolbox_dispatcher
);
3661 read_socket_inev
= NULL
;
3662 if (err
!= eventNotHandledErr
)
3665 last_mouse_glyph_frame
= 0;
3667 if (dpyinfo
->grabbed
&& last_mouse_frame
3668 && FRAME_LIVE_P (last_mouse_frame
))
3670 window_ptr
= FRAME_MAC_WINDOW (last_mouse_frame
);
3671 part_code
= inContent
;
3675 part_code
= FindWindow (er
.where
, &window_ptr
);
3676 if (tip_window
&& window_ptr
== tip_window
)
3678 HideWindow (tip_window
);
3679 part_code
= FindWindow (er
.where
, &window_ptr
);
3683 if (er
.what
!= mouseDown
3684 && (part_code
!= inContent
|| dpyinfo
->grabbed
== 0))
3690 f
= mac_focus_frame (dpyinfo
);
3691 saved_menu_event_location
= er
.where
;
3692 inev
.kind
= MENU_BAR_ACTIVATE_EVENT
;
3693 XSETFRAME (inev
.frame_or_window
, f
);
3698 #if TARGET_API_MAC_CARBON
3699 FrontNonFloatingWindow ()
3704 || (mac_window_to_frame (window_ptr
)
3705 != dpyinfo
->x_focus_frame
))
3706 SelectWindow (window_ptr
);
3709 ControlPartCode control_part_code
;
3713 ControlKind control_kind
;
3716 f
= mac_window_to_frame (window_ptr
);
3717 /* convert to local coordinates of new window */
3718 mouse_loc
.h
= (er
.where
.h
3720 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
3721 mouse_loc
.v
= (er
.where
.v
3723 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
3724 #if TARGET_API_MAC_CARBON
3725 ch
= FindControlUnderMouse (mouse_loc
, window_ptr
,
3726 &control_part_code
);
3729 GetControlKind (ch
, &control_kind
);
3732 control_part_code
= FindControl (mouse_loc
, window_ptr
,
3736 #if TARGET_API_MAC_CARBON
3737 inev
.code
= mac_get_mouse_btn (eventRef
);
3738 inev
.modifiers
= mac_event_to_emacs_modifiers (eventRef
);
3740 inev
.code
= mac_get_emulated_btn (er
.modifiers
);
3741 inev
.modifiers
= mac_to_emacs_modifiers (er
.modifiers
, 0);
3743 XSETINT (inev
.x
, mouse_loc
.h
);
3744 XSETINT (inev
.y
, mouse_loc
.v
);
3746 if ((dpyinfo
->grabbed
&& tracked_scroll_bar
)
3748 #ifndef USE_TOOLKIT_SCROLL_BARS
3749 /* control_part_code becomes kControlNoPart if
3750 a progress indicator is clicked. */
3751 && control_part_code
!= kControlNoPart
3752 #else /* USE_TOOLKIT_SCROLL_BARS */
3754 && control_kind
.kind
== kControlKindScrollBar
3755 #endif /* MAC_OSX */
3756 #endif /* USE_TOOLKIT_SCROLL_BARS */
3759 struct scroll_bar
*bar
;
3761 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
3763 bar
= tracked_scroll_bar
;
3764 #ifndef USE_TOOLKIT_SCROLL_BARS
3765 control_part_code
= kControlIndicatorPart
;
3769 bar
= (struct scroll_bar
*) GetControlReference (ch
);
3770 #ifdef USE_TOOLKIT_SCROLL_BARS
3771 /* Make the "Ctrl-Mouse-2 splits window" work
3772 for toolkit scroll bars. */
3773 if (inev
.modifiers
& ctrl_modifier
)
3774 x_scroll_bar_handle_click (bar
, control_part_code
,
3776 else if (er
.what
== mouseDown
)
3777 x_scroll_bar_handle_press (bar
, control_part_code
,
3780 x_scroll_bar_handle_release (bar
, &inev
);
3781 #else /* not USE_TOOLKIT_SCROLL_BARS */
3782 x_scroll_bar_handle_click (bar
, control_part_code
,
3784 if (er
.what
== mouseDown
3785 && control_part_code
== kControlIndicatorPart
)
3786 tracked_scroll_bar
= bar
;
3788 tracked_scroll_bar
= NULL
;
3789 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3794 int x
= mouse_loc
.h
;
3795 int y
= mouse_loc
.v
;
3797 window
= window_from_coordinates (f
, x
, y
, 0, 0, 0, 1);
3798 if (EQ (window
, f
->tool_bar_window
))
3800 if (er
.what
== mouseDown
)
3801 handle_tool_bar_click (f
, x
, y
, 1, 0);
3803 handle_tool_bar_click (f
, x
, y
, 0,
3809 XSETFRAME (inev
.frame_or_window
, f
);
3810 inev
.kind
= MOUSE_CLICK_EVENT
;
3814 if (er
.what
== mouseDown
)
3816 dpyinfo
->grabbed
|= (1 << inev
.code
);
3817 last_mouse_frame
= f
;
3820 last_tool_bar_item
= -1;
3824 if ((dpyinfo
->grabbed
& (1 << inev
.code
)) == 0)
3825 /* If a button is released though it was not
3826 previously pressed, that would be because
3827 of multi-button emulation. */
3828 dpyinfo
->grabbed
= 0;
3830 dpyinfo
->grabbed
&= ~(1 << inev
.code
);
3833 /* Ignore any mouse motion that happened before
3834 this event; any subsequent mouse-movement Emacs
3835 events should reflect only motion after the
3840 #ifdef USE_TOOLKIT_SCROLL_BARS
3841 if (inev
.kind
== MOUSE_CLICK_EVENT
3842 || (inev
.kind
== SCROLL_BAR_CLICK_EVENT
3843 && (inev
.modifiers
& ctrl_modifier
)))
3848 inev
.modifiers
|= down_modifier
;
3851 inev
.modifiers
|= up_modifier
;
3858 #if TARGET_API_MAC_CARBON
3860 if (IsWindowPathSelectClick (window_ptr
, &er
))
3862 WindowPathSelect (window_ptr
, NULL
, NULL
);
3865 if (part_code
== inProxyIcon
3866 && (TrackWindowProxyDrag (window_ptr
, er
.where
)
3867 != errUserWantsToDragWindow
))
3869 DragWindow (window_ptr
, er
.where
, NULL
);
3870 #else /* not TARGET_API_MAC_CARBON */
3871 DragWindow (window_ptr
, er
.where
, &qd
.screenBits
.bounds
);
3872 /* Update the frame parameters. */
3874 struct frame
*f
= mac_window_to_frame (window_ptr
);
3876 if (f
&& !f
->async_iconified
)
3877 mac_handle_origin_change (f
);
3879 #endif /* not TARGET_API_MAC_CARBON */
3883 if (TrackGoAway (window_ptr
, er
.where
))
3885 inev
.kind
= DELETE_WINDOW_EVENT
;
3886 XSETFRAME (inev
.frame_or_window
,
3887 mac_window_to_frame (window_ptr
));
3891 /* window resize handling added --ben */
3893 do_grow_window (window_ptr
, &er
);
3896 /* window zoom handling added --ben */
3899 if (TrackBox (window_ptr
, er
.where
, part_code
))
3900 do_zoom_window (window_ptr
, part_code
);
3909 if (FrontNonFloatingWindow () != window_ptr
)
3910 SelectWindow (window_ptr
);
3912 err
= HIViewGetViewForMouseEvent (HIViewGetRoot (window_ptr
),
3914 /* This doesn't work on Mac OS X 10.2. */
3916 HIViewClick (ch
, eventRef
);
3919 #endif /* USE_MAC_TOOLBAR */
3927 #if !TARGET_API_MAC_CARBON
3929 do_window_update ((WindowRef
) er
.message
);
3934 #if TARGET_API_MAC_CARBON
3935 if (SendEventToEventTarget (eventRef
, toolbox_dispatcher
)
3936 != eventNotHandledErr
)
3939 switch ((er
.message
>> 24) & 0x000000FF)
3942 case suspendResumeMessage
:
3943 if (er
.message
& resumeFlag
)
3950 case mouseMovedMessage
:
3951 #if !TARGET_API_MAC_CARBON
3952 SetRectRgn (mouse_region
, er
.where
.h
, er
.where
.v
,
3953 er
.where
.h
+ 1, er
.where
.v
+ 1);
3955 previous_help_echo_string
= help_echo_string
;
3956 help_echo_string
= Qnil
;
3958 if (dpyinfo
->grabbed
&& last_mouse_frame
3959 && FRAME_LIVE_P (last_mouse_frame
))
3960 f
= last_mouse_frame
;
3962 f
= dpyinfo
->x_focus_frame
;
3964 if (dpyinfo
->mouse_face_hidden
)
3966 dpyinfo
->mouse_face_hidden
= 0;
3967 clear_mouse_face (dpyinfo
);
3972 WindowRef wp
= FRAME_MAC_WINDOW (f
);
3975 mouse_pos
.h
= (er
.where
.h
3977 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
3978 mouse_pos
.v
= (er
.where
.v
3980 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
3981 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
3982 #ifdef USE_TOOLKIT_SCROLL_BARS
3983 x_scroll_bar_handle_drag (wp
, tracked_scroll_bar
,
3985 #else /* not USE_TOOLKIT_SCROLL_BARS */
3986 x_scroll_bar_note_movement (tracked_scroll_bar
,
3988 - XINT (tracked_scroll_bar
->top
),
3989 er
.when
* (1000 / 60));
3990 #endif /* not USE_TOOLKIT_SCROLL_BARS */
3993 /* Generate SELECT_WINDOW_EVENTs when needed. */
3994 if (!NILP (Vmouse_autoselect_window
))
3998 window
= window_from_coordinates (f
,
4003 /* Window will be selected only when it is
4004 not selected now and last mouse movement
4005 event was not in it. Minibuffer window
4006 will be selected only when it is active. */
4007 if (WINDOWP (window
)
4008 && !EQ (window
, last_window
)
4009 && !EQ (window
, selected_window
)
4010 /* For click-to-focus window managers
4011 create event iff we don't leave the
4013 && (focus_follows_mouse
4014 || (EQ (XWINDOW (window
)->frame
,
4015 XWINDOW (selected_window
)->frame
))))
4017 inev
.kind
= SELECT_WINDOW_EVENT
;
4018 inev
.frame_or_window
= window
;
4023 if (!note_mouse_movement (f
, &mouse_pos
))
4024 help_echo_string
= previous_help_echo_string
;
4027 mac_tool_bar_note_mouse_movement (f
, eventRef
);
4032 /* If the contents of the global variable
4033 help_echo_string has changed, generate a
4035 if (!NILP (help_echo_string
) || !NILP (previous_help_echo_string
))
4043 WindowRef window_ptr
= (WindowRef
) er
.message
;
4045 ControlRef root_control
;
4047 if (window_ptr
== tip_window
)
4049 HideWindow (tip_window
);
4053 if (!is_emacs_window (window_ptr
))
4056 f
= mac_window_to_frame (window_ptr
);
4058 if ((er
.modifiers
& activeFlag
) != 0)
4060 /* A window has been activated */
4063 err
= GetRootControl (FRAME_MAC_WINDOW (f
), &root_control
);
4065 ActivateControl (root_control
);
4067 x_detect_focus_change (dpyinfo
, &er
, &inev
);
4069 mouse_loc
.h
= (er
.where
.h
4071 + FRAME_OUTER_TO_INNER_DIFF_X (f
)));
4072 mouse_loc
.v
= (er
.where
.v
4074 + FRAME_OUTER_TO_INNER_DIFF_Y (f
)));
4075 /* Window-activated event counts as mouse movement,
4076 so update things that depend on mouse position. */
4077 note_mouse_movement (f
, &mouse_loc
);
4081 /* A window has been deactivated */
4082 err
= GetRootControl (FRAME_MAC_WINDOW (f
), &root_control
);
4084 DeactivateControl (root_control
);
4086 #ifdef USE_TOOLKIT_SCROLL_BARS
4087 if (dpyinfo
->grabbed
&& tracked_scroll_bar
)
4089 struct input_event event
;
4092 event
.kind
= NO_EVENT
;
4093 x_scroll_bar_handle_release (tracked_scroll_bar
, &event
);
4094 if (event
.kind
!= NO_EVENT
)
4096 event
.timestamp
= timestamp
;
4097 kbd_buffer_store_event_hold (&event
, hold_quit
);
4102 dpyinfo
->grabbed
= 0;
4104 x_detect_focus_change (dpyinfo
, &er
, &inev
);
4106 if (f
== dpyinfo
->mouse_face_mouse_frame
)
4108 /* If we move outside the frame, then we're
4109 certainly no longer on any text in the
4111 clear_mouse_face (dpyinfo
);
4112 dpyinfo
->mouse_face_mouse_frame
= 0;
4115 /* Generate a nil HELP_EVENT to cancel a help-echo.
4116 Do it only if there's something to cancel.
4117 Otherwise, the startup message is cleared when the
4118 mouse leaves the frame. */
4119 if (any_help_event_p
)
4130 f
= mac_focus_frame (dpyinfo
);
4131 XSETFRAME (inev
.frame_or_window
, f
);
4133 /* If mouse-highlight is an integer, input clears out mouse
4135 if (!dpyinfo
->mouse_face_hidden
&& INTEGERP (Vmouse_highlight
)
4136 && !EQ (f
->tool_bar_window
, dpyinfo
->mouse_face_window
))
4138 clear_mouse_face (dpyinfo
);
4139 dpyinfo
->mouse_face_hidden
= 1;
4143 UInt32 modifiers
= er
.modifiers
, mapped_modifiers
;
4144 UInt32 key_code
= (er
.message
& keyCodeMask
) >> 8;
4147 GetEventParameter (eventRef
, kEventParamKeyModifiers
,
4149 sizeof (UInt32
), NULL
, &modifiers
);
4151 mapped_modifiers
= mac_mapped_modifiers (modifiers
, key_code
);
4153 #if TARGET_API_MAC_CARBON
4154 if (!(mapped_modifiers
4155 & ~(mac_pass_command_to_system
? cmdKey
: 0)
4156 & ~(mac_pass_control_to_system
? controlKey
: 0)))
4160 if (er
.what
!= keyUp
)
4161 do_keystroke (er
.what
, er
.message
& charCodeMask
,
4162 key_code
, modifiers
, timestamp
, &inev
);
4166 case kHighLevelEvent
:
4167 AEProcessAppleEvent (&er
);
4172 #if TARGET_API_MAC_CARBON
4176 read_socket_inev
= &inev
;
4177 err
= SendEventToEventTarget (eventRef
, toolbox_dispatcher
);
4178 read_socket_inev
= NULL
;
4183 #if TARGET_API_MAC_CARBON
4184 ReleaseEvent (eventRef
);
4187 if (inev
.kind
!= NO_EVENT
)
4189 inev
.timestamp
= timestamp
;
4190 kbd_buffer_store_event_hold (&inev
, hold_quit
);
4195 && !(hold_quit
&& hold_quit
->kind
!= NO_EVENT
))
4200 XSETFRAME (frame
, f
);
4206 any_help_event_p
= 1;
4207 gen_help_event (help_echo_string
, frame
, help_echo_window
,
4208 help_echo_object
, help_echo_pos
);
4212 help_echo_string
= Qnil
;
4213 gen_help_event (Qnil
, frame
, Qnil
, Qnil
, 0);
4219 /* If the focus was just given to an autoraising frame,
4221 /* ??? This ought to be able to handle more than one such frame. */
4222 if (pending_autoraise_frame
)
4224 x_raise_frame (pending_autoraise_frame
);
4225 pending_autoraise_frame
= 0;
4228 if (mac_screen_config_changed
)
4230 mac_get_screen_info (dpyinfo
);
4231 mac_screen_config_changed
= 0;
4234 #if !TARGET_API_MAC_CARBON
4235 /* Check which frames are still visible. We do this here because
4236 there doesn't seem to be any direct notification from the Window
4237 Manager that the visibility of a window has changed (at least,
4238 not in all cases). */
4240 Lisp_Object tail
, frame
;
4242 FOR_EACH_FRAME (tail
, frame
)
4244 struct frame
*f
= XFRAME (frame
);
4246 /* The tooltip has been drawn already. Avoid the
4247 SET_FRAME_GARBAGED in mac_handle_visibility_change. */
4248 if (EQ (frame
, tip_frame
))
4251 if (FRAME_MAC_P (f
))
4252 mac_handle_visibility_change (f
);
4263 /***********************************************************************
4265 ***********************************************************************/
4267 #if TARGET_API_MAC_CARBON
4268 /* Show the spinning progress indicator for the frame F. Create it if
4269 it doesn't exist yet. */
4272 mac_show_hourglass (f
)
4276 mac_prepare_for_quickdraw (f
);
4278 if (!f
->output_data
.mac
->hourglass_control
)
4280 Window w
= FRAME_MAC_WINDOW (f
);
4284 GetWindowPortBounds (w
, &r
);
4285 r
.left
= r
.right
- HOURGLASS_WIDTH
;
4286 r
.bottom
= r
.top
+ HOURGLASS_HEIGHT
;
4287 if (CreateChasingArrowsControl (w
, &r
, &c
) == noErr
)
4288 f
->output_data
.mac
->hourglass_control
= c
;
4291 if (f
->output_data
.mac
->hourglass_control
)
4292 ShowControl (f
->output_data
.mac
->hourglass_control
);
4295 /* Hide the spinning progress indicator for the frame F. Do nothing
4296 it doesn't exist yet. */
4299 mac_hide_hourglass (f
)
4302 if (f
->output_data
.mac
->hourglass_control
)
4305 mac_prepare_for_quickdraw (f
);
4307 HideControl (f
->output_data
.mac
->hourglass_control
);
4311 /* Reposition the spinning progress indicator for the frame F. Do
4312 nothing it doesn't exist yet. */
4315 mac_reposition_hourglass (f
)
4318 if (f
->output_data
.mac
->hourglass_control
)
4321 mac_prepare_for_quickdraw (f
);
4323 MoveControl (f
->output_data
.mac
->hourglass_control
,
4324 FRAME_PIXEL_WIDTH (f
) - HOURGLASS_WIDTH
, 0);
4327 #endif /* TARGET_API_MAC_CARBON */
4330 /***********************************************************************
4331 File selection dialog
4332 ***********************************************************************/
4334 #if TARGET_API_MAC_CARBON
4335 extern Lisp_Object Qfile_name_history
;
4337 static pascal void mac_nav_event_callback
P_ ((NavEventCallbackMessage
,
4338 NavCBRecPtr
, void *));
4340 /* The actual implementation of Fx_file_dialog. */
4343 mac_file_dialog (prompt
, dir
, default_filename
, mustmatch
, only_dir_p
)
4344 Lisp_Object prompt
, dir
, default_filename
, mustmatch
, only_dir_p
;
4346 Lisp_Object file
= Qnil
;
4347 int count
= SPECPDL_INDEX ();
4348 struct gcpro gcpro1
, gcpro2
, gcpro3
, gcpro4
, gcpro5
, gcpro6
;
4349 char filename
[MAXPATHLEN
];
4350 static NavEventUPP mac_nav_event_callbackUPP
= NULL
;
4354 GCPRO6 (prompt
, dir
, default_filename
, mustmatch
, file
, only_dir_p
);
4355 CHECK_STRING (prompt
);
4358 /* Create the dialog with PROMPT as title, using DIR as initial
4359 directory and using "*" as pattern. */
4360 dir
= Fexpand_file_name (dir
, Qnil
);
4364 NavDialogCreationOptions options
;
4365 NavDialogRef dialogRef
;
4366 NavTypeListHandle fileTypes
= NULL
;
4367 NavUserAction userAction
;
4368 CFStringRef message
=NULL
, saveName
= NULL
;
4371 /* No need for a callback function because we are modal */
4372 NavGetDefaultDialogCreationOptions(&options
);
4373 options
.modality
= kWindowModalityAppModal
;
4374 options
.location
.h
= options
.location
.v
= -1;
4375 options
.optionFlags
= kNavDefaultNavDlogOptions
;
4376 options
.optionFlags
|= kNavAllFilesInPopup
; /* All files allowed */
4377 options
.optionFlags
|= kNavSelectAllReadableItem
;
4378 options
.optionFlags
&= ~kNavAllowMultipleFiles
;
4381 message
= cfstring_create_with_string (prompt
);
4382 options
.message
= message
;
4384 /* Don't set the application, let it use default.
4385 options.clientName = CFSTR ("Emacs");
4388 if (mac_nav_event_callbackUPP
== NULL
)
4389 mac_nav_event_callbackUPP
= NewNavEventUPP (mac_nav_event_callback
);
4391 if (!NILP (only_dir_p
))
4392 status
= NavCreateChooseFolderDialog(&options
, mac_nav_event_callbackUPP
,
4393 NULL
, NULL
, &dialogRef
);
4394 else if (NILP (mustmatch
))
4396 /* This is a save dialog */
4397 options
.optionFlags
|= kNavDontConfirmReplacement
;
4398 options
.actionButtonLabel
= CFSTR ("Ok");
4399 options
.windowTitle
= CFSTR ("Enter name");
4401 if (STRINGP (default_filename
))
4403 Lisp_Object utf8
= ENCODE_UTF_8 (default_filename
);
4404 char *begPtr
= SDATA(utf8
);
4405 char *filePtr
= begPtr
+ SBYTES(utf8
);
4406 while (filePtr
!= begPtr
&& !IS_DIRECTORY_SEP(filePtr
[-1]))
4408 saveName
= cfstring_create_with_utf8_cstring (filePtr
);
4409 options
.saveFileName
= saveName
;
4410 options
.optionFlags
|= kNavSelectDefaultLocation
;
4412 status
= NavCreatePutFileDialog(&options
,
4413 'TEXT', kNavGenericSignature
,
4414 mac_nav_event_callbackUPP
, NULL
,
4419 /* This is an open dialog*/
4420 status
= NavCreateChooseFileDialog(&options
, fileTypes
,
4421 mac_nav_event_callbackUPP
, NULL
,
4422 NULL
, NULL
, &dialogRef
);
4425 /* Set the default location and continue*/
4426 if (status
== noErr
)
4428 Lisp_Object encoded_dir
= ENCODE_FILE (dir
);
4431 status
= AECreateDesc (TYPE_FILE_NAME
, SDATA (encoded_dir
),
4432 SBYTES (encoded_dir
), &defLocAed
);
4433 if (status
== noErr
)
4435 NavCustomControl(dialogRef
, kNavCtlSetLocation
, (void*) &defLocAed
);
4436 AEDisposeDesc(&defLocAed
);
4438 status
= NavDialogRun(dialogRef
);
4441 if (saveName
) CFRelease(saveName
);
4442 if (message
) CFRelease(message
);
4444 if (status
== noErr
) {
4445 userAction
= NavDialogGetUserAction(dialogRef
);
4448 case kNavUserActionNone
:
4449 case kNavUserActionCancel
:
4450 break; /* Treat cancel like C-g */
4451 case kNavUserActionOpen
:
4452 case kNavUserActionChoose
:
4453 case kNavUserActionSaveAs
:
4455 NavReplyRecord reply
;
4458 status
= NavDialogGetReply(dialogRef
, &reply
);
4459 if (status
!= noErr
)
4461 status
= AEGetNthPtr (&reply
.selection
, 1, TYPE_FILE_NAME
,
4462 NULL
, NULL
, filename
,
4463 sizeof (filename
) - 1, &len
);
4464 if (status
== noErr
)
4466 len
= min (len
, sizeof (filename
) - 1);
4467 filename
[len
] = '\0';
4468 if (reply
.saveFileName
)
4470 /* If it was a saved file, we need to add the file name */
4471 if (len
&& len
< sizeof (filename
) - 1
4472 && filename
[len
-1] != '/')
4473 filename
[len
++] = '/';
4474 CFStringGetCString(reply
.saveFileName
, filename
+len
,
4475 sizeof (filename
) - len
,
4477 kCFStringEncodingUTF8
4479 CFStringGetSystemEncoding ()
4483 file
= DECODE_FILE (make_unibyte_string (filename
,
4484 strlen (filename
)));
4486 NavDisposeReply(&reply
);
4490 NavDialogDispose(dialogRef
);
4495 /* Fall back on minibuffer if there was a problem */
4496 file
= Fcompleting_read (prompt
, intern ("read-file-name-internal"),
4497 dir
, mustmatch
, dir
, Qfile_name_history
,
4498 default_filename
, Qnil
);
4504 /* Make "Cancel" equivalent to C-g. */
4506 Fsignal (Qquit
, Qnil
);
4508 return unbind_to (count
, file
);
4511 /* Need to register some event callback function for enabling drag and
4512 drop in Navigation Service dialogs. */
4514 mac_nav_event_callback (selector
, parms
, data
)
4515 NavEventCallbackMessage selector
;
4523 /************************************************************************
4525 ************************************************************************/
4527 #if !TARGET_API_MAC_CARBON
4528 #include <MacTypes.h>
4530 #include <Quickdraw.h>
4531 #include <ToolUtils.h>
4533 #include <Controls.h>
4534 #include <Windows.h>
4536 #if defined (__MRC__) || (__MSL__ >= 0x6000)
4537 #include <ControlDefinitions.h>
4539 #endif /* not TARGET_API_MAC_CARBON */
4541 extern int menu_item_selection
;
4542 extern int popup_activated_flag
;
4543 extern int name_is_separator
P_ ((const char *));
4544 extern void find_and_call_menu_selection
P_ ((FRAME_PTR
, int, Lisp_Object
,
4546 extern void set_frame_menubar
P_ ((FRAME_PTR
, int, int));
4548 enum mac_menu_kind
{ /* Menu ID range */
4549 MAC_MENU_APPLE
, /* 0 (Reserved by Apple) */
4550 MAC_MENU_MENU_BAR
, /* 1 .. 233 */
4551 MAC_MENU_M_APPLE
, /* 234 (== M_APPLE) */
4552 MAC_MENU_POPUP
, /* 235 */
4553 MAC_MENU_DRIVER
, /* 236 .. 255 (Reserved) */
4554 MAC_MENU_MENU_BAR_SUB
, /* 256 .. 16383 */
4555 MAC_MENU_POPUP_SUB
, /* 16384 .. 32767 */
4556 MAC_MENU_END
/* 32768 */
4559 static const int min_menu_id
[] = {0, 1, 234, 235, 236, 256, 16384, 32768};
4561 static int fill_menu
P_ ((MenuRef
, widget_value
*, enum mac_menu_kind
, int));
4562 static void dispose_menus
P_ ((enum mac_menu_kind
, int));
4564 #if !TARGET_API_MAC_CARBON
4566 do_apple_menu (SInt16 menu_item
)
4569 SInt16 da_driver_refnum
;
4571 if (menu_item
== I_ABOUT
)
4572 NoteAlert (ABOUT_ALERT_ID
, NULL
);
4575 GetMenuItemText (GetMenuRef (M_APPLE
), menu_item
, item_name
);
4576 da_driver_refnum
= OpenDeskAcc (item_name
);
4579 #endif /* !TARGET_API_MAC_CARBON */
4581 /* Activate the menu bar of frame F.
4582 This is called from keyboard.c when it gets the
4583 MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue.
4585 To activate the menu bar, we use the button-press event location
4586 that was saved in saved_menu_event_location.
4588 But first we recompute the menu bar contents (the whole tree).
4590 The reason for saving the button event until here, instead of
4591 passing it to the toolkit right away, is that we can safely
4592 execute Lisp code. */
4595 x_activate_menubar (f
)
4599 SInt16 menu_id
, menu_item
;
4601 set_frame_menubar (f
, 0, 1);
4604 popup_activated_flag
= 1;
4605 menu_choice
= MenuSelect (saved_menu_event_location
);
4606 popup_activated_flag
= 0;
4607 menu_id
= HiWord (menu_choice
);
4608 menu_item
= LoWord (menu_choice
);
4610 #if !TARGET_API_MAC_CARBON
4611 if (menu_id
== min_menu_id
[MAC_MENU_M_APPLE
])
4612 do_apple_menu (menu_item
);
4617 MenuRef menu
= GetMenuRef (menu_id
);
4623 GetMenuItemRefCon (menu
, menu_item
, &refcon
);
4624 find_and_call_menu_selection (f
, f
->menu_bar_items_used
,
4625 f
->menu_bar_vector
, (void *) refcon
);
4634 #if TARGET_API_MAC_CARBON
4635 extern Lisp_Object Vshow_help_function
;
4638 restore_show_help_function (old_show_help_function
)
4639 Lisp_Object old_show_help_function
;
4641 Vshow_help_function
= old_show_help_function
;
4646 static pascal OSStatus
4647 menu_target_item_handler (next_handler
, event
, data
)
4648 EventHandlerCallRef next_handler
;
4654 MenuItemIndex menu_item
;
4657 int specpdl_count
= SPECPDL_INDEX ();
4659 /* Don't be bothered with the overflowed toolbar items menu. */
4660 if (!popup_activated ())
4661 return eventNotHandledErr
;
4663 err
= GetEventParameter (event
, kEventParamDirectObject
, typeMenuRef
,
4664 NULL
, sizeof (MenuRef
), NULL
, &menu
);
4666 err
= GetEventParameter (event
, kEventParamMenuItemIndex
,
4667 typeMenuItemIndex
, NULL
,
4668 sizeof (MenuItemIndex
), NULL
, &menu_item
);
4670 err
= GetMenuItemProperty (menu
, menu_item
,
4671 MAC_EMACS_CREATOR_CODE
, 'help',
4672 sizeof (Lisp_Object
), NULL
, &help
);
4676 /* Temporarily bind Vshow_help_function to Qnil because we don't
4677 want tooltips during menu tracking. */
4678 record_unwind_protect (restore_show_help_function
, Vshow_help_function
);
4679 Vshow_help_function
= Qnil
;
4681 show_help_echo (help
, Qnil
, Qnil
, Qnil
, 1);
4683 unbind_to (specpdl_count
, Qnil
);
4685 return err
== noErr
? noErr
: eventNotHandledErr
;
4688 /* Showing help echo string during menu tracking. */
4691 install_menu_target_item_handler ()
4693 static const EventTypeSpec specs
[] =
4694 {{kEventClassMenu
, kEventMenuTargetItem
}};
4696 return InstallApplicationEventHandler (NewEventHandlerUPP
4697 (menu_target_item_handler
),
4698 GetEventTypeCount (specs
),
4701 #endif /* TARGET_API_MAC_CARBON */
4703 /* Event handler function that pops down a menu on C-g. We can only pop
4704 down menus if CancelMenuTracking is present (OSX 10.3 or later). */
4706 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4707 static pascal OSStatus
4708 menu_quit_handler (nextHandler
, theEvent
, userData
)
4709 EventHandlerCallRef nextHandler
;
4715 UInt32 keyModifiers
;
4717 err
= GetEventParameter (theEvent
, kEventParamKeyCode
,
4718 typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
4721 err
= GetEventParameter (theEvent
, kEventParamKeyModifiers
,
4722 typeUInt32
, NULL
, sizeof(UInt32
),
4723 NULL
, &keyModifiers
);
4725 if (err
== noErr
&& mac_quit_char_key_p (keyModifiers
, keyCode
))
4727 MenuRef menu
= userData
!= 0
4728 ? (MenuRef
)userData
: AcquireRootMenu ();
4730 CancelMenuTracking (menu
, true, 0);
4731 if (!userData
) ReleaseMenu (menu
);
4735 return CallNextEventHandler (nextHandler
, theEvent
);
4737 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4739 /* Add event handler to all menus that belong to KIND so we can detect
4740 C-g. ROOT_MENU is the root menu of the tracking session to dismiss
4741 when C-g is detected. NULL means the menu bar. If
4742 CancelMenuTracking isn't available, do nothing. */
4745 install_menu_quit_handler (kind
, root_menu
)
4746 enum mac_menu_kind kind
;
4749 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
4750 static const EventTypeSpec typesList
[] =
4751 {{kEventClassKeyboard
, kEventRawKeyDown
}};
4754 #if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
4755 if (CancelMenuTracking
== NULL
)
4758 for (id
= min_menu_id
[kind
]; id
< min_menu_id
[kind
+ 1]; id
++)
4760 MenuRef menu
= GetMenuRef (id
);
4764 InstallMenuEventHandler (menu
, menu_quit_handler
,
4765 GetEventTypeCount (typesList
),
4766 typesList
, root_menu
, NULL
);
4768 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1030 */
4775 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
4776 FRAME_PTR f
= p
->pointer
;
4777 MenuRef menu
= GetMenuRef (min_menu_id
[MAC_MENU_POPUP
]);
4781 /* Must reset this manually because the button release event is not
4782 passed to Emacs event loop. */
4783 FRAME_MAC_DISPLAY_INFO (f
)->grabbed
= 0;
4785 /* delete all menus */
4786 dispose_menus (MAC_MENU_POPUP_SUB
, 0);
4787 DeleteMenu (min_menu_id
[MAC_MENU_POPUP
]);
4795 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop
4796 until the menu pops down. Return the selection. */
4799 create_and_show_popup_menu (f
, first_wv
, x
, y
, for_click
)
4801 widget_value
*first_wv
;
4807 MenuRef menu
= NewMenu (min_menu_id
[MAC_MENU_POPUP
], "\p");
4808 int menu_item_choice
;
4809 int specpdl_count
= SPECPDL_INDEX ();
4811 InsertMenu (menu
, -1);
4812 fill_menu (menu
, first_wv
->contents
, MAC_MENU_POPUP_SUB
,
4813 min_menu_id
[MAC_MENU_POPUP_SUB
]);
4815 /* Add event handler so we can detect C-g. */
4816 install_menu_quit_handler (MAC_MENU_POPUP
, menu
);
4817 install_menu_quit_handler (MAC_MENU_POPUP_SUB
, menu
);
4819 record_unwind_protect (pop_down_menu
, make_save_value (f
, 0));
4821 /* Adjust coordinates to be root-window-relative. */
4822 x
+= f
->left_pos
+ FRAME_OUTER_TO_INNER_DIFF_X (f
);
4823 y
+= f
->top_pos
+ FRAME_OUTER_TO_INNER_DIFF_Y (f
);
4825 /* Display the menu. */
4826 popup_activated_flag
= 1;
4827 menu_item_choice
= PopUpMenuSelect (menu
, y
, x
, 0);
4828 popup_activated_flag
= 0;
4830 /* Get the refcon to find the correct item */
4831 if (menu_item_choice
)
4833 MenuRef sel_menu
= GetMenuRef (HiWord (menu_item_choice
));
4836 GetMenuItemRefCon (sel_menu
, LoWord (menu_item_choice
),
4837 (UInt32
*) &result
);
4840 unbind_to (specpdl_count
, Qnil
);
4842 menu_item_selection
= result
;
4846 add_menu_item (menu
, pos
, wv
)
4851 #if TARGET_API_MAC_CARBON
4852 CFStringRef item_name
;
4857 if (name_is_separator (wv
->name
))
4858 AppendMenu (menu
, "\p-");
4861 AppendMenu (menu
, "\pX");
4863 #if TARGET_API_MAC_CARBON
4864 item_name
= cfstring_create_with_utf8_cstring (wv
->name
);
4866 if (wv
->key
!= NULL
)
4868 CFStringRef name
, key
;
4871 key
= cfstring_create_with_utf8_cstring (wv
->key
);
4872 item_name
= CFStringCreateWithFormat (NULL
, NULL
, CFSTR ("%@ %@"),
4878 SetMenuItemTextWithCFString (menu
, pos
, item_name
);
4879 CFRelease (item_name
);
4882 EnableMenuItem (menu
, pos
);
4884 DisableMenuItem (menu
, pos
);
4886 if (STRINGP (wv
->help
))
4887 SetMenuItemProperty (menu
, pos
, MAC_EMACS_CREATOR_CODE
, 'help',
4888 sizeof (Lisp_Object
), &wv
->help
);
4889 #else /* ! TARGET_API_MAC_CARBON */
4890 item_name
[sizeof (item_name
) - 1] = '\0';
4891 strncpy (item_name
, wv
->name
, sizeof (item_name
) - 1);
4892 if (wv
->key
!= NULL
)
4894 int len
= strlen (item_name
);
4896 strncpy (item_name
+ len
, " ", sizeof (item_name
) - 1 - len
);
4897 len
= strlen (item_name
);
4898 strncpy (item_name
+ len
, wv
->key
, sizeof (item_name
) - 1 - len
);
4901 SetMenuItemText (menu
, pos
, item_name
);
4904 EnableItem (menu
, pos
);
4906 DisableItem (menu
, pos
);
4907 #endif /* ! TARGET_API_MAC_CARBON */
4909 /* Draw radio buttons and tickboxes. */
4910 if (wv
->selected
&& (wv
->button_type
== BUTTON_TYPE_TOGGLE
4911 || wv
->button_type
== BUTTON_TYPE_RADIO
))
4912 SetItemMark (menu
, pos
, checkMark
);
4914 SetItemMark (menu
, pos
, noMark
);
4916 SetMenuItemRefCon (menu
, pos
, (UInt32
) wv
->call_data
);
4920 /* Construct native Mac OS menu based on widget_value tree. */
4923 fill_menu (menu
, wv
, kind
, submenu_id
)
4926 enum mac_menu_kind kind
;
4931 for (pos
= 1; wv
!= NULL
; wv
= wv
->next
, pos
++)
4933 add_menu_item (menu
, pos
, wv
);
4934 if (wv
->contents
&& submenu_id
< min_menu_id
[kind
+ 1])
4936 MenuRef submenu
= NewMenu (submenu_id
, "\pX");
4938 InsertMenu (submenu
, -1);
4939 #if TARGET_API_MAC_CARBON
4940 SetMenuItemHierarchicalMenu (menu
, pos
, submenu
);
4942 SetMenuItemHierarchicalID (menu
, pos
, submenu_id
);
4944 submenu_id
= fill_menu (submenu
, wv
->contents
, kind
, submenu_id
+ 1);
4951 /* Fill menu bar with the items defined by WV. If DEEP_P, consider
4952 the entire menu trees we supply, rather than just the menu bar item
4956 mac_fill_menubar (wv
, deep_p
)
4961 #if !TARGET_API_MAC_CARBON
4962 int title_changed_p
= 0;
4965 /* Clean up the menu bar when filled by the entire menu trees. */
4968 dispose_menus (MAC_MENU_MENU_BAR
, 0);
4969 dispose_menus (MAC_MENU_MENU_BAR_SUB
, 0);
4970 #if !TARGET_API_MAC_CARBON
4971 title_changed_p
= 1;
4975 /* Fill menu bar titles and submenus. Reuse the existing menu bar
4976 titles as much as possible to minimize redraw (if !deep_p). */
4977 submenu_id
= min_menu_id
[MAC_MENU_MENU_BAR_SUB
];
4978 for (id
= min_menu_id
[MAC_MENU_MENU_BAR
];
4979 wv
!= NULL
&& id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1];
4980 wv
= wv
->next
, id
++)
4982 OSStatus err
= noErr
;
4984 #if TARGET_API_MAC_CARBON
4987 title
= CFStringCreateWithCString (NULL
, wv
->name
,
4988 kCFStringEncodingMacRoman
);
4992 strncpy (title
, wv
->name
, 255);
4997 menu
= GetMenuRef (id
);
5000 #if TARGET_API_MAC_CARBON
5001 CFStringRef old_title
;
5003 err
= CopyMenuTitleAsCFString (menu
, &old_title
);
5006 if (CFStringCompare (title
, old_title
, 0) != kCFCompareEqualTo
)
5009 if (id
+ 1 == min_menu_id
[MAC_MENU_MENU_BAR
+ 1]
5010 || GetMenuRef (id
+ 1) == NULL
)
5012 /* This is a workaround for Mac OS X 10.5 where
5013 just calling SetMenuTitleWithCFString fails
5014 to change the title of the last (Help) menu
5021 #endif /* MAC_OSX */
5022 err
= SetMenuTitleWithCFString (menu
, title
);
5024 CFRelease (old_title
);
5027 err
= SetMenuTitleWithCFString (menu
, title
);
5028 #else /* !TARGET_API_MAC_CARBON */
5029 if (!EqualString (title
, (*menu
)->menuData
, false, false))
5033 menu
= NewMenu (id
, title
);
5034 InsertMenu (menu
, GetMenuRef (id
+ 1) ? id
+ 1 : 0);
5035 title_changed_p
= 1;
5037 #endif /* !TARGET_API_MAC_CARBON */
5042 #if TARGET_API_MAC_CARBON
5043 err
= CreateNewMenu (id
, 0, &menu
);
5045 err
= SetMenuTitleWithCFString (menu
, title
);
5047 menu
= NewMenu (id
, title
);
5051 InsertMenu (menu
, 0);
5052 #if !TARGET_API_MAC_CARBON
5053 title_changed_p
= 1;
5057 #if TARGET_API_MAC_CARBON
5063 submenu_id
= fill_menu (menu
, wv
->contents
, MAC_MENU_MENU_BAR_SUB
,
5067 if (id
< min_menu_id
[MAC_MENU_MENU_BAR
+ 1] && GetMenuRef (id
))
5069 dispose_menus (MAC_MENU_MENU_BAR
, id
);
5070 #if !TARGET_API_MAC_CARBON
5071 title_changed_p
= 1;
5075 #if !TARGET_API_MAC_CARBON
5076 if (title_changed_p
)
5080 /* Add event handler so we can detect C-g. */
5081 install_menu_quit_handler (MAC_MENU_MENU_BAR
, NULL
);
5082 install_menu_quit_handler (MAC_MENU_MENU_BAR_SUB
, NULL
);
5085 /* Dispose of menus that belong to KIND, and remove them from the menu
5086 list. ID is the lower bound of menu IDs that will be processed. */
5089 dispose_menus (kind
, id
)
5090 enum mac_menu_kind kind
;
5093 for (id
= max (id
, min_menu_id
[kind
]); id
< min_menu_id
[kind
+ 1]; id
++)
5095 MenuRef menu
= GetMenuRef (id
);
5110 MenuItemIndex menu_index
;
5112 err
= GetIndMenuItemWithCommandID (NULL
, kHICommandQuit
, 1,
5113 &menu
, &menu_index
);
5115 SetMenuItemCommandKey (menu
, menu_index
, false, 0);
5116 EnableMenuCommand (NULL
, kHICommandPreferences
);
5117 err
= GetIndMenuItemWithCommandID (NULL
, kHICommandPreferences
, 1,
5118 &menu
, &menu_index
);
5121 SetMenuItemCommandKey (menu
, menu_index
, false, 0);
5122 InsertMenuItemTextWithCFString (menu
, NULL
,
5123 0, kMenuItemAttrSeparator
, 0);
5124 InsertMenuItemTextWithCFString (menu
, CFSTR ("About Emacs"),
5125 0, 0, kHICommandAbout
);
5127 #else /* !MAC_OSX */
5128 #if TARGET_API_MAC_CARBON
5129 SetMenuItemCommandID (GetMenuRef (M_APPLE
), I_ABOUT
, kHICommandAbout
);
5135 /***********************************************************************
5137 ***********************************************************************/
5139 #if TARGET_API_MAC_CARBON
5140 #define DIALOG_BUTTON_COMMAND_ID_OFFSET 'Bt\0\0'
5141 #define DIALOG_BUTTON_COMMAND_ID_P(id) \
5142 (((id) & ~0xffff) == DIALOG_BUTTON_COMMAND_ID_OFFSET)
5143 #define DIALOG_BUTTON_COMMAND_ID_VALUE(id) \
5144 ((id) - DIALOG_BUTTON_COMMAND_ID_OFFSET)
5145 #define DIALOG_BUTTON_MAKE_COMMAND_ID(value) \
5146 ((value) + DIALOG_BUTTON_COMMAND_ID_OFFSET)
5148 extern EMACS_TIME timer_check
P_ ((int));
5149 static int quit_dialog_event_loop
;
5151 static pascal OSStatus
5152 mac_handle_dialog_event (next_handler
, event
, data
)
5153 EventHandlerCallRef next_handler
;
5157 OSStatus err
, result
= eventNotHandledErr
;
5158 WindowRef window
= (WindowRef
) data
;
5160 switch (GetEventClass (event
))
5162 case kEventClassCommand
:
5166 err
= GetEventParameter (event
, kEventParamDirectObject
,
5167 typeHICommand
, NULL
, sizeof (HICommand
),
5170 if (DIALOG_BUTTON_COMMAND_ID_P (command
.commandID
))
5172 SetWRefCon (window
, command
.commandID
);
5173 quit_dialog_event_loop
= 1;
5177 result
= CallNextEventHandler (next_handler
, event
);
5181 case kEventClassKeyboard
:
5186 result
= CallNextEventHandler (next_handler
, event
);
5187 if (result
!= eventNotHandledErr
)
5190 err
= GetEventParameter (event
, kEventParamKeyMacCharCodes
,
5191 typeChar
, NULL
, sizeof (char),
5196 case kEscapeCharCode
:
5197 quit_dialog_event_loop
= 1;
5202 UInt32 modifiers
, key_code
;
5204 err
= GetEventParameter (event
, kEventParamKeyModifiers
,
5205 typeUInt32
, NULL
, sizeof (UInt32
),
5208 err
= GetEventParameter (event
, kEventParamKeyCode
,
5209 typeUInt32
, NULL
, sizeof (UInt32
),
5212 if (mac_quit_char_key_p (modifiers
, key_code
))
5213 quit_dialog_event_loop
= 1;
5224 if (quit_dialog_event_loop
)
5226 err
= QuitEventLoop (GetCurrentEventLoop ());
5235 install_dialog_event_handler (window
)
5238 static const EventTypeSpec specs
[] =
5239 {{kEventClassCommand
, kEventCommandProcess
},
5240 {kEventClassKeyboard
, kEventRawKeyDown
}};
5241 static EventHandlerUPP handle_dialog_eventUPP
= NULL
;
5243 if (handle_dialog_eventUPP
== NULL
)
5244 handle_dialog_eventUPP
= NewEventHandlerUPP (mac_handle_dialog_event
);
5245 return InstallWindowEventHandler (window
, handle_dialog_eventUPP
,
5246 GetEventTypeCount (specs
), specs
,
5251 pop_down_dialog (arg
)
5254 struct Lisp_Save_Value
*p
= XSAVE_VALUE (arg
);
5255 WindowRef window
= p
->pointer
;
5259 if (popup_activated_flag
)
5260 EndAppModalStateForWindow (window
);
5261 DisposeWindow (window
);
5262 popup_activated_flag
= 0;
5269 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
5271 menu_item_selection will be set to the selection. */
5274 create_and_show_dialog (f
, first_wv
)
5276 widget_value
*first_wv
;
5279 char *dialog_name
, *message
;
5280 int nb_buttons
, first_group_count
, i
, result
= 0;
5282 short buttons_height
, text_height
, inner_width
, inner_height
;
5283 Rect empty_rect
, *rects
;
5284 WindowRef window
= NULL
;
5285 ControlRef
*buttons
, default_button
= NULL
, text
;
5286 int specpdl_count
= SPECPDL_INDEX ();
5288 dialog_name
= first_wv
->name
;
5289 nb_buttons
= dialog_name
[1] - '0';
5290 first_group_count
= nb_buttons
- (dialog_name
[4] - '0');
5292 wv
= first_wv
->contents
;
5293 message
= wv
->value
;
5296 SetRect (&empty_rect
, 0, 0, 0, 0);
5298 /* Create dialog window. */
5299 err
= CreateNewWindow (kMovableModalWindowClass
,
5300 kWindowStandardHandlerAttribute
,
5301 &empty_rect
, &window
);
5304 record_unwind_protect (pop_down_dialog
, make_save_value (window
, 0));
5305 err
= SetThemeWindowBackground (window
, kThemeBrushMovableModalBackground
,
5309 err
= SetWindowTitleWithCFString (window
, (dialog_name
[0] == 'Q'
5310 ? CFSTR ("Question")
5311 : CFSTR ("Information")));
5313 /* Create button controls and measure their optimal bounds. */
5316 buttons
= alloca (sizeof (ControlRef
) * nb_buttons
);
5317 rects
= alloca (sizeof (Rect
) * nb_buttons
);
5318 for (i
= 0; i
< nb_buttons
; i
++)
5320 CFStringRef label
= cfstring_create_with_utf8_cstring (wv
->value
);
5326 err
= CreatePushButtonControl (window
, &empty_rect
,
5327 label
, &buttons
[i
]);
5335 err
= DisableControl (buttons
[i
]);
5337 err
= DeactivateControl (buttons
[i
]);
5340 else if (default_button
== NULL
)
5341 default_button
= buttons
[i
];
5347 rects
[i
] = empty_rect
;
5348 err
= GetBestControlRect (buttons
[i
], &rects
[i
], &unused
);
5354 OffsetRect (&rects
[i
], -rects
[i
].left
, -rects
[i
].top
);
5355 if (rects
[i
].right
< DIALOG_BUTTON_MIN_WIDTH
)
5356 rects
[i
].right
= DIALOG_BUTTON_MIN_WIDTH
;
5357 else if (rects
[i
].right
> DIALOG_MAX_INNER_WIDTH
)
5358 rects
[i
].right
= DIALOG_MAX_INNER_WIDTH
;
5360 command_id
= DIALOG_BUTTON_MAKE_COMMAND_ID ((int) wv
->call_data
);
5361 err
= SetControlCommandID (buttons
[i
], command_id
);
5369 /* Layout buttons. rects[i] is set relative to the bottom-right
5370 corner of the inner box. */
5373 short bottom
, right
, max_height
, left_align_shift
;
5375 inner_width
= DIALOG_MIN_INNER_WIDTH
;
5376 bottom
= right
= max_height
= 0;
5377 for (i
= 0; i
< nb_buttons
; i
++)
5379 if (right
- rects
[i
].right
< - inner_width
)
5381 if (i
!= first_group_count
5382 && right
- rects
[i
].right
>= - DIALOG_MAX_INNER_WIDTH
)
5383 inner_width
= - (right
- rects
[i
].right
);
5386 bottom
-= max_height
+ DIALOG_BUTTON_BUTTON_VERTICAL_SPACE
;
5387 right
= max_height
= 0;
5390 if (max_height
< rects
[i
].bottom
)
5391 max_height
= rects
[i
].bottom
;
5392 OffsetRect (&rects
[i
], right
- rects
[i
].right
,
5393 bottom
- rects
[i
].bottom
);
5394 right
= rects
[i
].left
- DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
5395 if (i
== first_group_count
- 1)
5396 right
-= DIALOG_BUTTON_BUTTON_HORIZONTAL_SPACE
;
5398 buttons_height
= - (bottom
- max_height
);
5400 left_align_shift
= - (inner_width
+ rects
[nb_buttons
- 1].left
);
5401 for (i
= nb_buttons
- 1; i
>= first_group_count
; i
--)
5403 if (bottom
!= rects
[i
].bottom
)
5405 left_align_shift
= - (inner_width
+ rects
[i
].left
);
5406 bottom
= rects
[i
].bottom
;
5408 OffsetRect (&rects
[i
], left_align_shift
, 0);
5412 /* Create a static text control and measure its bounds. */
5415 CFStringRef message_string
;
5418 message_string
= cfstring_create_with_utf8_cstring (message
);
5419 if (message_string
== NULL
)
5423 ControlFontStyleRec text_style
;
5425 text_style
.flags
= 0;
5426 SetRect (&bounds
, 0, 0, inner_width
, 0);
5427 err
= CreateStaticTextControl (window
, &bounds
, message_string
,
5428 &text_style
, &text
);
5429 CFRelease (message_string
);
5435 bounds
= empty_rect
;
5436 err
= GetBestControlRect (text
, &bounds
, &unused
);
5440 text_height
= bounds
.bottom
- bounds
.top
;
5441 if (text_height
< DIALOG_TEXT_MIN_HEIGHT
)
5442 text_height
= DIALOG_TEXT_MIN_HEIGHT
;
5446 /* Place buttons. */
5449 inner_height
= (text_height
+ DIALOG_TEXT_BUTTONS_VERTICAL_SPACE
5452 for (i
= 0; i
< nb_buttons
; i
++)
5454 OffsetRect (&rects
[i
], DIALOG_LEFT_MARGIN
+ inner_width
,
5455 DIALOG_TOP_MARGIN
+ inner_height
);
5456 SetControlBounds (buttons
[i
], &rects
[i
]);
5465 SetRect (&bounds
, DIALOG_LEFT_MARGIN
, DIALOG_TOP_MARGIN
,
5466 DIALOG_LEFT_MARGIN
+ inner_width
,
5467 DIALOG_TOP_MARGIN
+ text_height
);
5468 SetControlBounds (text
, &bounds
);
5471 /* Create the application icon at the upper-left corner. */
5474 ControlButtonContentInfo content
;
5476 static const ProcessSerialNumber psn
= {0, kCurrentProcess
};
5480 ProcessInfoRec pinfo
;
5485 content
.contentType
= kControlContentIconRef
;
5487 err
= GetProcessBundleLocation (&psn
, &app_location
);
5489 err
= GetIconRefFromFileInfo (&app_location
, 0, NULL
, 0, NULL
,
5490 kIconServicesNormalUsageFlag
,
5491 &content
.u
.iconRef
, &unused
);
5493 bzero (&pinfo
, sizeof (ProcessInfoRec
));
5494 pinfo
.processInfoLength
= sizeof (ProcessInfoRec
);
5495 pinfo
.processAppSpec
= &app_spec
;
5496 err
= GetProcessInformation (&psn
, &pinfo
);
5498 err
= GetIconRefFromFile (&app_spec
, &content
.u
.iconRef
, &unused
);
5504 SetRect (&bounds
, DIALOG_ICON_LEFT_MARGIN
, DIALOG_ICON_TOP_MARGIN
,
5505 DIALOG_ICON_LEFT_MARGIN
+ DIALOG_ICON_WIDTH
,
5506 DIALOG_ICON_TOP_MARGIN
+ DIALOG_ICON_HEIGHT
);
5507 err
= CreateIconControl (window
, &bounds
, &content
, true, &icon
);
5508 ReleaseIconRef (content
.u
.iconRef
);
5512 /* Show the dialog window and run event loop. */
5515 err
= SetWindowDefaultButton (window
, default_button
);
5517 err
= install_dialog_event_handler (window
);
5521 DIALOG_LEFT_MARGIN
+ inner_width
+ DIALOG_RIGHT_MARGIN
,
5522 DIALOG_TOP_MARGIN
+ inner_height
+ DIALOG_BOTTOM_MARGIN
,
5524 err
= RepositionWindow (window
, FRAME_MAC_WINDOW (f
),
5525 kWindowAlertPositionOnParentWindow
);
5529 SetWRefCon (window
, 0);
5530 ShowWindow (window
);
5531 BringToFront (window
);
5532 popup_activated_flag
= 1;
5533 err
= BeginAppModalStateForWindow (window
);
5537 EventTargetRef toolbox_dispatcher
= GetEventDispatcherTarget ();
5539 quit_dialog_event_loop
= 0;
5542 EMACS_TIME next_time
= timer_check (1);
5543 long secs
= EMACS_SECS (next_time
);
5544 long usecs
= EMACS_USECS (next_time
);
5545 EventTimeout timeout
;
5548 if (secs
< 0 || (secs
== 0 && usecs
== 0))
5550 /* Sometimes timer_check returns -1 (no timers) even if
5551 there are timers. So do a timeout anyway. */
5556 timeout
= (secs
* kEventDurationSecond
5557 + usecs
* kEventDurationMicrosecond
);
5558 err
= ReceiveNextEvent (0, NULL
, timeout
, kEventRemoveFromQueue
,
5562 SendEventToEventTarget (event
, toolbox_dispatcher
);
5563 ReleaseEvent (event
);
5565 #if 0 /* defined (MAC_OSX) */
5566 else if (err
!= eventLoopTimedOutErr
)
5568 if (err
== eventLoopQuitErr
)
5573 /* The return value of ReceiveNextEvent seems to be
5574 unreliable. Use our own global variable instead. */
5575 if (quit_dialog_event_loop
)
5585 UInt32 command_id
= GetWRefCon (window
);
5587 if (DIALOG_BUTTON_COMMAND_ID_P (command_id
))
5588 result
= DIALOG_BUTTON_COMMAND_ID_VALUE (command_id
);
5591 unbind_to (specpdl_count
, Qnil
);
5593 menu_item_selection
= result
;
5595 #else /* not TARGET_API_MAC_CARBON */
5596 #define DIALOG_WINDOW_RESOURCE 130
5599 mac_dialog (widget_value
*wv
)
5603 char **button_labels
;
5610 WindowRef window_ptr
;
5613 EventRecord event_record
;
5615 int control_part_code
;
5618 dialog_name
= wv
->name
;
5619 nb_buttons
= dialog_name
[1] - '0';
5620 left_count
= nb_buttons
- (dialog_name
[4] - '0');
5621 button_labels
= (char **) alloca (sizeof (char *) * nb_buttons
);
5622 ref_cons
= (UInt32
*) alloca (sizeof (UInt32
) * nb_buttons
);
5625 prompt
= (char *) alloca (strlen (wv
->value
) + 1);
5626 strcpy (prompt
, wv
->value
);
5630 for (i
= 0; i
< nb_buttons
; i
++)
5632 button_labels
[i
] = wv
->value
;
5633 button_labels
[i
] = (char *) alloca (strlen (wv
->value
) + 1);
5634 strcpy (button_labels
[i
], wv
->value
);
5635 c2pstr (button_labels
[i
]);
5636 ref_cons
[i
] = (UInt32
) wv
->call_data
;
5640 window_ptr
= GetNewCWindow (DIALOG_WINDOW_RESOURCE
, NULL
, (WindowRef
) -1);
5642 SetPortWindowPort (window_ptr
);
5645 /* Left and right margins in the dialog are 13 pixels each.*/
5647 /* Calculate width of dialog box: 8 pixels on each side of the text
5648 label in each button, 12 pixels between buttons. */
5649 for (i
= 0; i
< nb_buttons
; i
++)
5650 dialog_width
+= StringWidth (button_labels
[i
]) + 16 + 12;
5652 if (left_count
!= 0 && nb_buttons
- left_count
!= 0)
5655 dialog_width
= max (dialog_width
, StringWidth (prompt
) + 26);
5657 SizeWindow (window_ptr
, dialog_width
, 78, 0);
5658 ShowWindow (window_ptr
);
5660 SetPortWindowPort (window_ptr
);
5665 DrawString (prompt
);
5668 for (i
= 0; i
< nb_buttons
; i
++)
5670 int button_width
= StringWidth (button_labels
[i
]) + 16;
5671 SetRect (&rect
, left
, 45, left
+ button_width
, 65);
5672 ch
= NewControl (window_ptr
, &rect
, button_labels
[i
], 1, 0, 0, 0,
5673 kControlPushButtonProc
, ref_cons
[i
]);
5674 left
+= button_width
+ 12;
5675 if (i
== left_count
- 1)
5682 if (WaitNextEvent (mDownMask
, &event_record
, 10, NULL
))
5683 if (event_record
.what
== mouseDown
)
5685 part_code
= FindWindow (event_record
.where
, &window_ptr
);
5686 if (part_code
== inContent
)
5688 mouse
= event_record
.where
;
5689 GlobalToLocal (&mouse
);
5690 control_part_code
= FindControl (mouse
, window_ptr
, &ch
);
5691 if (control_part_code
== kControlButtonPart
)
5692 if (TrackControl (ch
, mouse
, NULL
))
5693 i
= GetControlReference (ch
);
5698 DisposeWindow (window_ptr
);
5702 #endif /* not TARGET_API_MAC_CARBON */
5705 /***********************************************************************
5707 ***********************************************************************/
5709 #if !TARGET_API_MAC_CARBON
5714 extern Lisp_Object Vselection_converter_alist
;
5715 extern Lisp_Object Qmac_scrap_name
, Qmac_ostype
;
5717 static ScrapFlavorType get_flavor_type_from_symbol
P_ ((Lisp_Object
,
5720 /* Get a reference to the selection corresponding to the symbol SYM.
5721 The reference is set to *SEL, and it becomes NULL if there's no
5722 corresponding selection. Clear the selection if CLEAR_P is
5726 mac_get_selection_from_symbol (sym
, clear_p
, sel
)
5731 OSStatus err
= noErr
;
5732 Lisp_Object str
= Fget (sym
, Qmac_scrap_name
);
5738 #if TARGET_API_MAC_CARBON
5740 CFStringRef scrap_name
= cfstring_create_with_string (str
);
5741 OptionBits options
= (clear_p
? kScrapClearNamedScrap
5742 : kScrapGetNamedScrap
);
5744 err
= GetScrapByName (scrap_name
, options
, sel
);
5745 CFRelease (scrap_name
);
5746 #else /* !MAC_OSX */
5748 err
= ClearCurrentScrap ();
5750 err
= GetCurrentScrap (sel
);
5751 #endif /* !MAC_OSX */
5752 #else /* !TARGET_API_MAC_CARBON */
5757 #endif /* !TARGET_API_MAC_CARBON */
5763 /* Get a scrap flavor type from the symbol SYM. Return 0 if no
5764 corresponding flavor type. If SEL is non-zero, the return value is
5765 non-zero only when the SEL has the flavor type. */
5767 static ScrapFlavorType
5768 get_flavor_type_from_symbol (sym
, sel
)
5772 Lisp_Object str
= Fget (sym
, Qmac_ostype
);
5773 ScrapFlavorType flavor_type
;
5775 if (STRINGP (str
) && SBYTES (str
) == 4)
5776 flavor_type
= EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
5780 if (flavor_type
&& sel
)
5782 #if TARGET_API_MAC_CARBON
5784 ScrapFlavorFlags flags
;
5786 err
= GetScrapFlavorFlags (sel
, flavor_type
, &flags
);
5789 #else /* !TARGET_API_MAC_CARBON */
5790 SInt32 size
, offset
;
5792 size
= GetScrap (NULL
, flavor_type
, &offset
);
5795 #endif /* !TARGET_API_MAC_CARBON */
5801 /* Check if the symbol SYM has a corresponding selection target type. */
5804 mac_valid_selection_target_p (sym
)
5807 return get_flavor_type_from_symbol (sym
, 0) != 0;
5810 /* Clear the selection whose reference is *SEL. */
5813 mac_clear_selection (sel
)
5816 #if TARGET_API_MAC_CARBON
5818 return ClearScrap (sel
);
5822 err
= ClearCurrentScrap ();
5824 err
= GetCurrentScrap (sel
);
5827 #else /* !TARGET_API_MAC_CARBON */
5828 return ZeroScrap ();
5829 #endif /* !TARGET_API_MAC_CARBON */
5832 /* Get ownership information for SEL. Emacs can detect a change of
5833 the ownership by comparing saved and current values of the
5834 ownership information. */
5837 mac_get_selection_ownership_info (sel
)
5840 #if TARGET_API_MAC_CARBON
5841 return long_to_cons ((unsigned long) sel
);
5842 #else /* !TARGET_API_MAC_CARBON */
5843 ScrapStuffPtr scrap_info
= InfoScrap ();
5845 return make_number (scrap_info
->scrapCount
);
5846 #endif /* !TARGET_API_MAC_CARBON */
5849 /* Return non-zero if VALUE is a valid selection value for TARGET. */
5852 mac_valid_selection_value_p (value
, target
)
5853 Lisp_Object value
, target
;
5855 return STRINGP (value
);
5858 /* Put Lisp object VALUE to the selection SEL. The target type is
5859 specified by TARGET. */
5862 mac_put_selection_value (sel
, target
, value
)
5864 Lisp_Object target
, value
;
5866 ScrapFlavorType flavor_type
= get_flavor_type_from_symbol (target
, 0);
5868 if (flavor_type
== 0 || !STRINGP (value
))
5871 #if TARGET_API_MAC_CARBON
5872 return PutScrapFlavor (sel
, flavor_type
, kScrapFlavorMaskNone
,
5873 SBYTES (value
), SDATA (value
));
5874 #else /* !TARGET_API_MAC_CARBON */
5875 return PutScrap (SBYTES (value
), flavor_type
, SDATA (value
));
5876 #endif /* !TARGET_API_MAC_CARBON */
5879 /* Check if data for the target type TARGET is available in SEL. */
5882 mac_selection_has_target_p (sel
, target
)
5886 return get_flavor_type_from_symbol (target
, sel
) != 0;
5889 /* Get data for the target type TARGET from SEL and create a Lisp
5890 string. Return nil if failed to get data. */
5893 mac_get_selection_value (sel
, target
)
5898 Lisp_Object result
= Qnil
;
5899 ScrapFlavorType flavor_type
= get_flavor_type_from_symbol (target
, sel
);
5900 #if TARGET_API_MAC_CARBON
5905 err
= GetScrapFlavorSize (sel
, flavor_type
, &size
);
5910 result
= make_uninit_string (size
);
5911 err
= GetScrapFlavorData (sel
, flavor_type
,
5912 &size
, SDATA (result
));
5915 else if (size
< SBYTES (result
))
5916 result
= make_unibyte_string (SDATA (result
), size
);
5918 while (STRINGP (result
) && size
> SBYTES (result
));
5923 SInt32 size
, offset
;
5926 size
= GetScrap (NULL
, flavor_type
, &offset
);
5929 handle
= NewHandle (size
);
5931 size
= GetScrap (handle
, flavor_type
, &offset
);
5933 result
= make_unibyte_string (*handle
, size
);
5934 DisposeHandle (handle
);
5941 /* Get the list of target types in SEL. The return value is a list of
5942 target type symbols possibly followed by scrap flavor type
5946 mac_get_selection_target_list (sel
)
5949 Lisp_Object result
= Qnil
, rest
, target
;
5950 #if TARGET_API_MAC_CARBON
5952 UInt32 count
, i
, type
;
5953 ScrapFlavorInfo
*flavor_info
= NULL
;
5954 Lisp_Object strings
= Qnil
;
5956 err
= GetScrapFlavorCount (sel
, &count
);
5958 flavor_info
= xmalloc (sizeof (ScrapFlavorInfo
) * count
);
5959 err
= GetScrapFlavorInfoList (sel
, &count
, flavor_info
);
5962 xfree (flavor_info
);
5965 if (flavor_info
== NULL
)
5968 for (rest
= Vselection_converter_alist
; CONSP (rest
); rest
= XCDR (rest
))
5970 ScrapFlavorType flavor_type
= 0;
5972 if (CONSP (XCAR (rest
))
5973 && (target
= XCAR (XCAR (rest
)),
5975 && (flavor_type
= get_flavor_type_from_symbol (target
, sel
)))
5977 result
= Fcons (target
, result
);
5978 #if TARGET_API_MAC_CARBON
5979 for (i
= 0; i
< count
; i
++)
5980 if (flavor_info
[i
].flavorType
== flavor_type
)
5982 flavor_info
[i
].flavorType
= 0;
5988 #if TARGET_API_MAC_CARBON
5991 for (i
= 0; i
< count
; i
++)
5992 if (flavor_info
[i
].flavorType
)
5994 type
= EndianU32_NtoB (flavor_info
[i
].flavorType
);
5995 strings
= Fcons (make_unibyte_string ((char *) &type
, 4), strings
);
5997 result
= nconc2 (result
, strings
);
5998 xfree (flavor_info
);
6006 /***********************************************************************
6008 ***********************************************************************/
6010 extern pascal OSErr mac_handle_apple_event
P_ ((const AppleEvent
*,
6011 AppleEvent
*, SInt32
));
6012 extern void cleanup_all_suspended_apple_events
P_ ((void));
6015 init_apple_event_handler ()
6020 /* Make sure we have Apple events before starting. */
6021 err
= Gestalt (gestaltAppleEventsAttr
, &result
);
6025 if (!(result
& (1 << gestaltAppleEventsPresent
)))
6028 err
= AEInstallEventHandler (typeWildCard
, typeWildCard
,
6029 #if TARGET_API_MAC_CARBON
6030 NewAEEventHandlerUPP (mac_handle_apple_event
),
6032 NewAEEventHandlerProc (mac_handle_apple_event
),
6038 atexit (cleanup_all_suspended_apple_events
);
6042 /***********************************************************************
6043 Drag and drop support
6044 ***********************************************************************/
6046 #if TARGET_API_MAC_CARBON
6047 extern Lisp_Object Vmac_dnd_known_types
;
6049 static pascal OSErr mac_do_track_drag
P_ ((DragTrackingMessage
, WindowRef
,
6051 static pascal OSErr mac_do_receive_drag
P_ ((WindowRef
, void *, DragRef
));
6052 static DragTrackingHandlerUPP mac_do_track_dragUPP
= NULL
;
6053 static DragReceiveHandlerUPP mac_do_receive_dragUPP
= NULL
;
6056 create_apple_event_from_drag_ref (drag
, num_types
, types
, result
)
6059 const FlavorType
*types
;
6068 err
= CountDragItems (drag
, &num_items
);
6071 err
= AECreateList (NULL
, 0, false, &items
);
6075 for (index
= 1; index
<= num_items
; index
++)
6078 DescType desc_type
= typeNull
;
6081 err
= GetDragItemReferenceNumber (drag
, index
, &item
);
6086 for (i
= 0; i
< num_types
; i
++)
6088 err
= GetFlavorDataSize (drag
, item
, types
[i
], &size
);
6091 buf
= xrealloc (buf
, size
);
6092 err
= GetFlavorData (drag
, item
, types
[i
], buf
, &size
, 0);
6096 desc_type
= types
[i
];
6101 err
= AEPutPtr (&items
, index
, desc_type
,
6102 desc_type
!= typeNull
? buf
: NULL
,
6103 desc_type
!= typeNull
? size
: 0);
6112 err
= create_apple_event (0, 0, result
); /* Dummy class and ID. */
6114 err
= AEPutParamDesc (result
, keyDirectObject
, &items
);
6116 AEDisposeDesc (result
);
6119 AEDisposeDesc (&items
);
6125 mac_store_drag_event (window
, mouse_pos
, modifiers
, desc
)
6131 struct input_event buf
;
6135 buf
.kind
= DRAG_N_DROP_EVENT
;
6136 buf
.modifiers
= mac_to_emacs_modifiers (modifiers
, 0);
6137 buf
.timestamp
= TickCount () * (1000 / 60);
6138 XSETINT (buf
.x
, mouse_pos
.h
);
6139 XSETINT (buf
.y
, mouse_pos
.v
);
6140 XSETFRAME (buf
.frame_or_window
, mac_window_to_frame (window
));
6141 buf
.arg
= mac_aedesc_to_lisp (desc
);
6142 kbd_buffer_store_event (&buf
);
6146 mac_do_track_drag (message
, window
, refcon
, drag
)
6147 DragTrackingMessage message
;
6153 static int can_accept
;
6154 UInt16 num_items
, index
;
6156 if (GetFrontWindowOfClass (kMovableModalWindowClass
, false))
6157 return dragNotAcceptedErr
;
6161 case kDragTrackingEnterHandler
:
6162 err
= CountDragItems (drag
, &num_items
);
6166 for (index
= 1; index
<= num_items
; index
++)
6172 err
= GetDragItemReferenceNumber (drag
, index
, &item
);
6175 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6181 if (!(STRINGP (str
) && SBYTES (str
) == 4))
6183 type
= EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
6185 err
= GetFlavorFlags (drag
, item
, type
, &flags
);
6195 case kDragTrackingEnterWindow
:
6198 RgnHandle hilite_rgn
= NewRgn ();
6204 GetWindowPortBounds (window
, &r
);
6205 OffsetRect (&r
, -r
.left
, -r
.top
);
6206 RectRgn (hilite_rgn
, &r
);
6207 ShowDragHilite (drag
, hilite_rgn
, true);
6208 DisposeRgn (hilite_rgn
);
6210 SetThemeCursor (kThemeCopyArrowCursor
);
6214 case kDragTrackingInWindow
:
6217 case kDragTrackingLeaveWindow
:
6220 HideDragHilite (drag
);
6221 SetThemeCursor (kThemeArrowCursor
);
6225 case kDragTrackingLeaveHandler
:
6230 return dragNotAcceptedErr
;
6235 mac_do_receive_drag (window
, refcon
, drag
)
6242 Lisp_Object rest
, str
;
6244 AppleEvent apple_event
;
6248 if (GetFrontWindowOfClass (kMovableModalWindowClass
, false))
6249 return dragNotAcceptedErr
;
6252 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6255 if (STRINGP (str
) && SBYTES (str
) == 4)
6259 types
= xmalloc (sizeof (FlavorType
) * num_types
);
6261 for (rest
= Vmac_dnd_known_types
; CONSP (rest
); rest
= XCDR (rest
))
6264 if (STRINGP (str
) && SBYTES (str
) == 4)
6265 types
[i
++] = EndianU32_BtoN (*((UInt32
*) SDATA (str
)));
6268 err
= create_apple_event_from_drag_ref (drag
, num_types
, types
,
6273 err
= GetDragMouse (drag
, &mouse_pos
, NULL
);
6276 GlobalToLocal (&mouse_pos
);
6277 err
= GetDragModifiers (drag
, NULL
, NULL
, &modifiers
);
6281 UInt32 key_modifiers
= modifiers
;
6283 err
= AEPutParamPtr (&apple_event
, kEventParamKeyModifiers
,
6284 typeUInt32
, &key_modifiers
, sizeof (UInt32
));
6289 mac_store_drag_event (window
, mouse_pos
, 0, &apple_event
);
6290 AEDisposeDesc (&apple_event
);
6291 mac_wakeup_from_rne ();
6295 return dragNotAcceptedErr
;
6297 #endif /* TARGET_API_MAC_CARBON */
6300 install_drag_handler (window
)
6305 #if TARGET_API_MAC_CARBON
6306 if (mac_do_track_dragUPP
== NULL
)
6307 mac_do_track_dragUPP
= NewDragTrackingHandlerUPP (mac_do_track_drag
);
6308 if (mac_do_receive_dragUPP
== NULL
)
6309 mac_do_receive_dragUPP
= NewDragReceiveHandlerUPP (mac_do_receive_drag
);
6311 err
= InstallTrackingHandler (mac_do_track_dragUPP
, window
, NULL
);
6313 err
= InstallReceiveHandler (mac_do_receive_dragUPP
, window
, NULL
);
6320 remove_drag_handler (window
)
6323 #if TARGET_API_MAC_CARBON
6324 if (mac_do_track_dragUPP
)
6325 RemoveTrackingHandler (mac_do_track_dragUPP
, window
);
6326 if (mac_do_receive_dragUPP
)
6327 RemoveReceiveHandler (mac_do_receive_dragUPP
, window
);
6331 #if TARGET_API_MAC_CARBON
6332 /* Return default value for mac-dnd-known-types. */
6335 mac_dnd_default_known_types ()
6337 Lisp_Object result
= list4 (build_string ("hfs "), build_string ("utxt"),
6338 build_string ("TEXT"), build_string ("TIFF"));
6341 result
= Fcons (build_string ("furl"), result
);
6349 /***********************************************************************
6350 Services menu support
6351 ***********************************************************************/
6354 extern Lisp_Object Qservice
, Qpaste
, Qperform
;
6355 extern Lisp_Object Vmac_service_selection
;
6358 mac_store_service_event (event
)
6364 const EventParamName
*names
;
6365 const EventParamType
*types
;
6366 static const EventParamName names_pfm
[] =
6367 {kEventParamServiceMessageName
, kEventParamServiceUserData
};
6368 static const EventParamType types_pfm
[] =
6369 {typeCFStringRef
, typeCFStringRef
};
6371 switch (GetEventKind (event
))
6373 case kEventServicePaste
:
6380 case kEventServicePerform
:
6382 num_params
= sizeof (names_pfm
) / sizeof (names_pfm
[0]);
6391 err
= mac_store_event_ref_as_apple_event (0, 0, Qservice
, id_key
,
6399 copy_scrap_flavor_data (from_scrap
, to_scrap
, flavor_type
)
6400 ScrapRef from_scrap
, to_scrap
;
6401 ScrapFlavorType flavor_type
;
6404 Size size
, size_allocated
;
6407 err
= GetScrapFlavorSize (from_scrap
, flavor_type
, &size
);
6409 buf
= xmalloc (size
);
6412 size_allocated
= size
;
6413 err
= GetScrapFlavorData (from_scrap
, flavor_type
, &size
, buf
);
6419 else if (size_allocated
< size
)
6420 buf
= xrealloc (buf
, size
);
6430 err
= PutScrapFlavor (to_scrap
, flavor_type
, kScrapFlavorMaskNone
,
6440 mac_handle_service_event (call_ref
, event
, data
)
6441 EventHandlerCallRef call_ref
;
6445 OSStatus err
= noErr
;
6446 ScrapRef cur_scrap
, specific_scrap
;
6447 UInt32 event_kind
= GetEventKind (event
);
6448 CFMutableArrayRef copy_types
, paste_types
;
6451 ScrapFlavorType flavor_type
;
6453 /* Check if Vmac_service_selection is a valid selection that has a
6454 corresponding scrap. */
6455 if (!SYMBOLP (Vmac_service_selection
))
6456 err
= eventNotHandledErr
;
6458 err
= mac_get_selection_from_symbol (Vmac_service_selection
, 0, &cur_scrap
);
6459 if (!(err
== noErr
&& cur_scrap
))
6460 return eventNotHandledErr
;
6464 case kEventServiceGetTypes
:
6465 /* Set paste types. */
6466 err
= GetEventParameter (event
, kEventParamServicePasteTypes
,
6467 typeCFMutableArrayRef
, NULL
,
6468 sizeof (CFMutableArrayRef
), NULL
,
6473 for (rest
= Vselection_converter_alist
; CONSP (rest
);
6475 if (CONSP (XCAR (rest
)) && SYMBOLP (XCAR (XCAR (rest
)))
6477 get_flavor_type_from_symbol (XCAR (XCAR (rest
)), 0)))
6479 type
= CreateTypeStringWithOSType (flavor_type
);
6482 CFArrayAppendValue (paste_types
, type
);
6487 /* Set copy types. */
6488 err
= GetEventParameter (event
, kEventParamServiceCopyTypes
,
6489 typeCFMutableArrayRef
, NULL
,
6490 sizeof (CFMutableArrayRef
), NULL
,
6495 if (NILP (Fx_selection_owner_p (Vmac_service_selection
)))
6498 goto copy_all_flavors
;
6500 case kEventServiceCopy
:
6501 err
= GetEventParameter (event
, kEventParamScrapRef
,
6503 sizeof (ScrapRef
), NULL
, &specific_scrap
);
6505 || NILP (Fx_selection_owner_p (Vmac_service_selection
)))
6507 err
= eventNotHandledErr
;
6514 ScrapFlavorInfo
*flavor_info
= NULL
;
6515 ScrapFlavorFlags flags
;
6517 err
= GetScrapFlavorCount (cur_scrap
, &count
);
6519 flavor_info
= xmalloc (sizeof (ScrapFlavorInfo
) * count
);
6520 err
= GetScrapFlavorInfoList (cur_scrap
, &count
, flavor_info
);
6523 xfree (flavor_info
);
6526 if (flavor_info
== NULL
)
6529 for (i
= 0; i
< count
; i
++)
6531 flavor_type
= flavor_info
[i
].flavorType
;
6532 err
= GetScrapFlavorFlags (cur_scrap
, flavor_type
, &flags
);
6533 if (err
== noErr
&& !(flags
& kScrapFlavorMaskSenderOnly
))
6535 if (event_kind
== kEventServiceCopy
)
6536 err
= copy_scrap_flavor_data (cur_scrap
, specific_scrap
,
6538 else /* event_kind == kEventServiceGetTypes */
6540 type
= CreateTypeStringWithOSType (flavor_type
);
6543 CFArrayAppendValue (copy_types
, type
);
6549 xfree (flavor_info
);
6553 case kEventServicePaste
:
6554 case kEventServicePerform
:
6556 int data_exists_p
= 0;
6558 err
= GetEventParameter (event
, kEventParamScrapRef
, typeScrapRef
,
6559 NULL
, sizeof (ScrapRef
), NULL
,
6562 err
= mac_clear_selection (&cur_scrap
);
6564 for (rest
= Vselection_converter_alist
; CONSP (rest
);
6567 if (! (CONSP (XCAR (rest
)) && SYMBOLP (XCAR (XCAR (rest
)))))
6569 flavor_type
= get_flavor_type_from_symbol (XCAR (XCAR (rest
)),
6571 if (flavor_type
== 0)
6573 err
= copy_scrap_flavor_data (specific_scrap
, cur_scrap
,
6579 err
= eventNotHandledErr
;
6581 err
= mac_store_service_event (event
);
6587 err
= eventNotHandledErr
;
6592 install_service_handler ()
6594 static const EventTypeSpec specs
[] =
6595 {{kEventClassService
, kEventServiceGetTypes
},
6596 {kEventClassService
, kEventServiceCopy
},
6597 {kEventClassService
, kEventServicePaste
},
6598 {kEventClassService
, kEventServicePerform
}};
6600 return InstallApplicationEventHandler (NewEventHandlerUPP
6601 (mac_handle_service_event
),
6602 GetEventTypeCount (specs
),
6605 #endif /* MAC_OSX */
6608 /***********************************************************************
6610 ***********************************************************************/
6613 mac_toolbox_initialize ()
6615 any_help_event_p
= 0;
6620 init_apple_event_handler ();
6627 /* arch-tag: 71a597a8-6e9f-47b0-8b89-5a5ae3e16516
6628 (do not change this comment) */